From 75820e26481f8f94d438192e171b840068ee78ee Mon Sep 17 00:00:00 2001 From: Nicolas Favre-Felix Date: Thu, 30 Dec 2010 14:26:33 +0100 Subject: [PATCH 1/6] Starting to work on HTTP Basic Auth --- webdis.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/webdis.json b/webdis.json index 3174b4b..f56ded8 100644 --- a/webdis.json +++ b/webdis.json @@ -1,5 +1,6 @@ { "redis_host": "127.0.0.1", + "redis_port": 6379, "redis_auth": null, @@ -9,4 +10,26 @@ "disable": { "0.0.0.0/0": ["DEBUG", "FLUSHDB", "FLUSHALL"] } + + "acl": [ + + { + "basic_auth": "user:password", + "disable": ["DEBUG", "FLUSHDB", "FLUSHALL"], + "enable": ["SET"] + }, + + { + "ip": "192.168.10.0/24", + "disable": ["SET", "FLUSHDB", "FLUSHALL"], + "enable": ["*"] + }, + + { + "basic_auth": "user:password", + "ip": "192.168.10.0/24", + "disable": ["FLUSHDB", "FLUSHALL"], + "enable": ["SET", "*"] + } + ] } From 41388a519645374539d2edd7840fdb8de5297dac Mon Sep 17 00:00:00 2001 From: Nicolas Favre-Felix Date: Thu, 30 Dec 2010 17:27:35 +0100 Subject: [PATCH 2/6] Parsed ACLs. --- cmd.c | 4 +- conf.c | 134 +++++++++++++++++++++++++++++++--------------------- conf.h | 26 +++++++--- webdis.json | 2 +- 4 files changed, 103 insertions(+), 63 deletions(-) diff --git a/cmd.c b/cmd.c index a32944a..e36ebdd 100644 --- a/cmd.c +++ b/cmd.c @@ -40,7 +40,6 @@ cmd_authorized(struct conf *cfg, struct evhttp_request *rq, const char *verb, si char *always_off[] = {"MULTI", "EXEC", "WATCH", "DISCARD", "SUBSCRIBE", "PSUBSCRIBE"}; - struct disabled_command *dc; unsigned int i; char *client_ip; @@ -59,6 +58,8 @@ cmd_authorized(struct conf *cfg, struct evhttp_request *rq, const char *verb, si 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 */ @@ -73,6 +74,7 @@ cmd_authorized(struct conf *cfg, struct evhttp_request *rq, const char *verb, si } } } +#endif return 1; } diff --git a/conf.c b/conf.c index cb9cfef..03eca79 100644 --- a/conf.c +++ b/conf.c @@ -7,8 +7,8 @@ #include #include "conf.h" -static struct disabled_command * -conf_disable_commands(json_t *jtab); +static struct acl * +conf_parse_acls(json_t *jtab); struct conf * conf_read(const char *filename) { @@ -46,8 +46,8 @@ 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), "disable") == 0 && json_typeof(jtmp) == JSON_OBJECT) { - conf->disabled = conf_disable_commands(jtmp); + } else if(strcmp(json_object_iter_key(kv), "acl") == 0 && json_typeof(jtmp) == JSON_OBJECT) { + conf->perms = conf_parse_acls(jtmp); } } @@ -56,30 +56,53 @@ conf_read(const char *filename) { return conf; } +void +acl_read_commands(json_t *jlist, struct acl_commands *ac) { -struct disabled_command * -conf_disable_commands(json_t *jtab) { + unsigned int i, n, cur; - struct disabled_command *root = NULL; + /* count strings in the array */ + for(i = 0, n = 0; i < json_array_size(jlist); ++i) { + json_t *jelem = json_array_get(jlist, (size_t)i); + if(json_typeof(jelem) == JSON_STRING) { + n++; + } + } - void *kv; - for(kv = json_object_iter(jtab); kv; kv = json_object_iter_next(jtab, kv)) { + /* allocate block */ + ac->commands = calloc((size_t)n, sizeof(char*)); + ac->count = n; + + /* add all disabled commands */ + for(i = 0, cur = 0; i < json_array_size(jlist); ++i) { + json_t *jelem = json_array_get(jlist, i); + if(json_typeof(jelem) == JSON_STRING) { + size_t sz; + const char *s = json_string_value(jelem); + sz = strlen(s); + + ac->commands[cur] = calloc(1 + sz, 1); + memcpy(ac->commands[cur], s, sz); + cur++; + } + } +} - unsigned int i, cur, n; - char *p, *ip; - const char *s; - in_addr_t mask, subnet; - unsigned short mask_bits = 0; +struct acl * +conf_parse_acl(json_t *j) { - struct disabled_command *dc; - json_t *val = json_object_iter_value(kv); + json_t *jcidr, *jbasic, *jlist; + unsigned short mask_bits = 0; - if(json_typeof(val) != JSON_ARRAY) { - continue; /* TODO: report error? */ - } + struct acl *a = calloc(1, sizeof(struct acl)); + + /* parse CIDR */ + if((jcidr = json_object_get(j, "ip")) && json_typeof(jcidr) == JSON_STRING) { + const char *s; + char *p, *ip; + a->cidr.enabled = 1; - /* parse key in format "ip/mask" */ - s = json_object_iter_key(kv); + s = json_string_value(jcidr); p = strchr(s, '/'); if(!p) { ip = strdup(s); @@ -88,45 +111,48 @@ conf_disable_commands(json_t *jtab) { memcpy(ip, s, (size_t)(p - s)); mask_bits = (unsigned short)atoi(p+1); } - mask = (mask_bits == 0 ? 0 : (0xffffffff << (32 - mask_bits))); - subnet = ntohl(inet_addr(ip)) & mask; - - /* count strings in the array */ - n = 0; - for(i = 0; i < json_array_size(val); ++i) { - json_t *jelem = json_array_get(val, (size_t)i); - if(json_typeof(jelem) == JSON_STRING) { - n++; - } - } + a->cidr.mask = (mask_bits == 0 ? 0 : (0xffffffff << (32 - mask_bits))); + a->cidr.subnet = ntohl(inet_addr(ip)) & a->cidr.mask; + free(ip); + } - /* allocate block */ - dc = calloc(1, sizeof(struct disabled_command)); - dc->commands = calloc((size_t)n, sizeof(char*)); - dc->subnet = subnet; - dc->mask = mask; - dc->count = n; - dc->next = root; - root = dc; - - /* add all disabled commands */ - for(i = 0, cur = 0; i < json_array_size(val); ++i) { - json_t *jelem = json_array_get(val, i); - if(json_typeof(jelem) == JSON_STRING) { - size_t sz; - s = json_string_value(jelem); - sz = strlen(s); - - dc->commands[cur] = calloc(1 + sz, 1); - memcpy(dc->commands[cur], s, sz); - cur++; - } - } + /* parse basic_auth */ + if((jbasic = json_object_get(j, "http_basic_auth")) && json_typeof(jbasic) == JSON_STRING) { + a->http_basic_auth = strdup(json_string_value(jbasic)); + /* TODO: base64 encode */ + } + + /* parse enabled commands */ + if((jlist = json_object_get(j, "enable")) && json_typeof(jlist) == JSON_ARRAY) { + acl_read_commands(jlist, &a->enable); + } + + /* parse disabled commands */ + if((jlist = json_object_get(j, "disable")) && json_typeof(jlist) == JSON_ARRAY) { + acl_read_commands(jlist, &a->disable); + } + + return a; +} + +struct acl * +conf_parse_acls(json_t *jtab) { + + struct acl *root = NULL, *tmp = NULL; + + void *kv; + for(kv = json_object_iter(jtab); kv; kv = json_object_iter_next(jtab, kv)) { + json_t *val = json_object_iter_value(kv); + + tmp = conf_parse_acl(val); + if(root) root->next = tmp; + root = tmp; } return root; } + void conf_free(struct conf *conf) { diff --git a/conf.h b/conf.h index 917d8a2..b2169be 100644 --- a/conf.h +++ b/conf.h @@ -3,15 +3,27 @@ #include -struct disabled_command { - - in_addr_t subnet; - in_addr_t mask; - +struct acl_commands { unsigned int count; char **commands; +}; + +struct acl { + + /* CIDR subnet + mask */ + struct { + int enabled; + in_addr_t subnet; + in_addr_t mask; + } cidr; + + char *http_basic_auth; + + /* commands that have been enabled or disabled */ + struct acl_commands enable; + struct acl_commands disable; - struct disabled_command *next; + struct acl *next; }; struct conf { @@ -23,7 +35,7 @@ struct conf { char *http_host; short http_port; - struct disabled_command *disabled; + struct acl *perms; }; struct conf * diff --git a/webdis.json b/webdis.json index f56ded8..f9e4340 100644 --- a/webdis.json +++ b/webdis.json @@ -9,7 +9,7 @@ "disable": { "0.0.0.0/0": ["DEBUG", "FLUSHDB", "FLUSHALL"] - } + }, "acl": [ From 4a9918d313b114054e295837cda7c30cd9384b83 Mon Sep 17 00:00:00 2001 From: Nicolas Favre-Felix Date: Thu, 30 Dec 2010 17:45:51 +0100 Subject: [PATCH 3/6] ACL now working again. --- cmd.c | 29 ++++++++++++++++------------- conf.c | 47 ++++++++++++++++++++++++++++++++++------------- conf.h | 7 +++++-- webdis.json | 22 ++++++++++++---------- 4 files changed, 67 insertions(+), 38 deletions(-) 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"] } ] } From 37b1281f0d41afb6bd79d7d937d14c348426f891 Mon Sep 17 00:00:00 2001 From: Nicolas Favre-Felix Date: Thu, 30 Dec 2010 18:17:26 +0100 Subject: [PATCH 4/6] Base64 encode of user:password for HTTP Basic Auth. --- Makefile | 2 +- conf.c | 20 ++++++++- libb64/cencode.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++ libb64/cencode.h | 31 ++++++++++++++ webdis.json | 4 +- 5 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 libb64/cencode.c create mode 100644 libb64/cencode.h diff --git a/Makefile b/Makefile index 760bf31..981763e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ OUT=webdis HIREDIS_OBJ=hiredis/hiredis.o hiredis/sds.o hiredis/net.o hiredis/async.o JANSSON_OBJ=jansson/src/dump.o jansson/src/error.o jansson/src/hashtable.o jansson/src/load.o jansson/src/strbuffer.o jansson/src/utf.o jansson/src/value.o jansson/src/variadic.o FORMAT_OBJS=formats/json.o formats/raw.o -OBJS=webdis.o conf.o $(FORMAT_OBJS) cmd.o server.o $(HIREDIS_OBJ) $(JANSSON_OBJ) +OBJS=webdis.o conf.o $(FORMAT_OBJS) cmd.o server.o $(HIREDIS_OBJ) $(JANSSON_OBJ) libb64/cencode.o CFLAGS=-O3 -Wall -Wextra -I. -Ijansson/src LDFLAGS=-levent diff --git a/conf.c b/conf.c index c83777a..e98eda3 100644 --- a/conf.c +++ b/conf.c @@ -5,6 +5,7 @@ #include #include +#include #include "conf.h" static struct acl * @@ -118,8 +119,23 @@ conf_parse_acl(json_t *j) { /* parse basic_auth */ if((jbasic = json_object_get(j, "http_basic_auth")) && json_typeof(jbasic) == JSON_STRING) { - a->http_basic_auth = strdup(json_string_value(jbasic)); - /* TODO: base64 encode */ + + /* base64 encode */ + base64_encodestate b64; + int pos; + char *p; + const char *plain = json_string_value(jbasic); + size_t len, plain_len = strlen(plain) + 0; + len = (plain_len + 8) * 8 / 6; + a->http_basic_auth = calloc(len, 1); + + base64_init_encodestate(&b64); + pos = base64_encode_block(plain, (int)plain_len, a->http_basic_auth, &b64); /* FIXME: check return value */ + base64_encode_blockend(a->http_basic_auth + pos, &b64); + + if((p = strchr(a->http_basic_auth + pos, '\n'))) { + *p = 0; + } } /* parse enabled commands */ diff --git a/libb64/cencode.c b/libb64/cencode.c new file mode 100644 index 0000000..a8c8fee --- /dev/null +++ b/libb64/cencode.c @@ -0,0 +1,109 @@ +/* +cencoder.c - c source to a base64 encoding algorithm implementation + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#include "cencode.h" + +const int CHARS_PER_LINE = 72; + +void base64_init_encodestate(base64_encodestate* state_in) +{ + state_in->step = step_A; + state_in->result = 0; + state_in->stepcount = 0; +} + +char base64_encode_value(char value_in) +{ + static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + if (value_in > 63) return '='; + return encoding[(int)value_in]; +} + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) +{ + const char* plainchar = plaintext_in; + const char* const plaintextend = plaintext_in + length_in; + char* codechar = code_out; + char result; + char fragment; + + result = state_in->result; + + switch (state_in->step) + { + while (1) + { + case step_A: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_A; + return codechar - code_out; + } + fragment = *plainchar++; + result = (fragment & 0x0fc) >> 2; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x003) << 4; + case step_B: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_B; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0f0) >> 4; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x00f) << 2; + case step_C: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_C; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0c0) >> 6; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x03f) >> 0; + *codechar++ = base64_encode_value(result); + + ++(state_in->stepcount); + if (state_in->stepcount == CHARS_PER_LINE/4) + { + *codechar++ = '\n'; + state_in->stepcount = 0; + } + } + } + /* control should not reach here */ + return codechar - code_out; +} + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in) +{ + char* codechar = code_out; + + switch (state_in->step) + { + case step_B: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + *codechar++ = '='; + break; + case step_C: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + break; + case step_A: + break; + } + *codechar++ = '\n'; + + return codechar - code_out; +} + diff --git a/libb64/cencode.h b/libb64/cencode.h new file mode 100644 index 0000000..c1e3464 --- /dev/null +++ b/libb64/cencode.h @@ -0,0 +1,31 @@ +/* +cencode.h - c header for a base64 encoding algorithm + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#ifndef BASE64_CENCODE_H +#define BASE64_CENCODE_H + +typedef enum +{ + step_A, step_B, step_C +} base64_encodestep; + +typedef struct +{ + base64_encodestep step; + char result; + int stepcount; +} base64_encodestate; + +void base64_init_encodestate(base64_encodestate* state_in); + +char base64_encode_value(char value_in); + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in); + +#endif /* BASE64_CENCODE_H */ diff --git a/webdis.json b/webdis.json index e5cc112..10051dc 100644 --- a/webdis.json +++ b/webdis.json @@ -10,7 +10,7 @@ "acl": [ { - "basic_auth": "user:password", + "http_basic_auth": "user:password", "disabled": ["DEBUG", "FLUSHDB", "FLUSHALL"], "enabled": ["SET"] }, @@ -22,7 +22,7 @@ }, { - "basic_auth": "user:password", + "http_basic_auth": "user:password", "ip": "192.168.10.0/24", "disabled": ["FLUSHDB", "FLUSHALL"], "enabled": ["SET", "*"] From 17c0c59a103a2523a3528731c6d70ed137646531 Mon Sep 17 00:00:00 2001 From: Nicolas Favre-Felix Date: Thu, 30 Dec 2010 18:21:26 +0100 Subject: [PATCH 5/6] Small refactoring. --- cmd.c | 13 ++++++++----- conf.c | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cmd.c b/cmd.c index 0f5658b..76bf2b5 100644 --- a/cmd.c +++ b/cmd.c @@ -36,7 +36,7 @@ cmd_free(struct cmd *c) { } int -cmd_authorized(struct conf *cfg, struct evhttp_request *rq, const char *verb, size_t verb_len) { +cmd_authorized(struct cmd *cmd, struct conf *cfg, struct evhttp_request *rq) { char *always_off[] = {"MULTI", "EXEC", "WATCH", "DISCARD", "SUBSCRIBE", "PSUBSCRIBE"}; @@ -48,9 +48,12 @@ cmd_authorized(struct conf *cfg, struct evhttp_request *rq, const char *verb, si u_short client_port; in_addr_t client_addr; + const char *cmd_name = cmd->argv[0]; + size_t cmd_len = cmd->argv_len[0]; + /* some commands are always disabled, regardless of the config file. */ for(i = 0; i < sizeof(always_off) / sizeof(always_off[0]); ++i) { - if(strncasecmp(always_off[i], verb, verb_len) == 0) { + if(strncasecmp(always_off[i], cmd_name, cmd_len) == 0) { return 0; } } @@ -66,14 +69,14 @@ cmd_authorized(struct conf *cfg, struct evhttp_request *rq, const char *verb, si /* go through authorized commands */ for(i = 0; i < a->enabled.count; ++i) { - if(strncasecmp(a->enabled.commands[i], verb, verb_len) == 0) { + if(strncasecmp(a->enabled.commands[i], cmd_name, cmd_len) == 0) { authorized = 1; } } /* go through unauthorized commands */ for(i = 0; i < a->disabled.count; ++i) { - if(strncasecmp(a->disabled.commands[i], verb, verb_len) == 0) { + if(strncasecmp(a->disabled.commands[i], cmd_name, cmd_len) == 0) { authorized = 0; } } @@ -122,7 +125,7 @@ cmd_run(struct server *s, struct evhttp_request *rq, cmd->argv_len[0] = cmd_len; /* check that the client is able to run this command */ - if(!cmd_authorized(s->cfg, rq, cmd->argv[0], cmd->argv_len[0])) { + if(!cmd_authorized(cmd, s->cfg, rq)) { return -1; } diff --git a/conf.c b/conf.c index e98eda3..d42972b 100644 --- a/conf.c +++ b/conf.c @@ -133,6 +133,7 @@ conf_parse_acl(json_t *j) { pos = base64_encode_block(plain, (int)plain_len, a->http_basic_auth, &b64); /* FIXME: check return value */ base64_encode_blockend(a->http_basic_auth + pos, &b64); + /* end string with \0 rather than \n */ if((p = strchr(a->http_basic_auth + pos, '\n'))) { *p = 0; } From 23c904ac91a2a25084772a2e6c2e08026130b2b8 Mon Sep 17 00:00:00 2001 From: Nicolas Favre-Felix Date: Thu, 30 Dec 2010 18:30:09 +0100 Subject: [PATCH 6/6] Working HTTP Basic Auth. --- cmd.c | 2 +- conf.c | 17 ++++++++++++----- conf.h | 4 +++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cmd.c b/cmd.c index 76bf2b5..3c240ac 100644 --- a/cmd.c +++ b/cmd.c @@ -65,7 +65,7 @@ cmd_authorized(struct cmd *cmd, struct conf *cfg, struct evhttp_request *rq) { /* go through permissions */ for(a = cfg->perms; a; a = a->next) { - if(!acl_match(a, &client_addr)) continue; /* match client */ + if(!acl_match(a, rq, &client_addr)) continue; /* match client */ /* go through authorized commands */ for(i = 0; i < a->enabled.count; ++i) { diff --git a/conf.c b/conf.c index d42972b..62d16cb 100644 --- a/conf.c +++ b/conf.c @@ -5,6 +5,7 @@ #include #include +#include #include #include "conf.h" @@ -174,15 +175,21 @@ conf_parse_acls(json_t *jtab) { } int -acl_match(struct acl *a, in_addr_t *ip) { - - /* TODO: add HTTP Basic Auth */ +acl_match(struct acl *a, struct evhttp_request *rq, in_addr_t *ip) { + + /* check HTTP Basic Auth */ + const char *auth; + auth = evhttp_find_header(rq->input_headers, "Authorization"); + if(auth && a->http_basic_auth && strncasecmp(auth, "Basic ", 6) == 0) { /* sent auth */ + if(strcmp(auth + 6, a->http_basic_auth) != 0) { /* wrong */ + return 0; + } + } + /* CIDR check. */ 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; } diff --git a/conf.h b/conf.h index 428758f..0ae7219 100644 --- a/conf.h +++ b/conf.h @@ -3,6 +3,8 @@ #include +struct evhttp_request; + struct acl_commands { unsigned int count; char **commands; @@ -45,6 +47,6 @@ void conf_free(struct conf *conf); int -acl_match(struct acl *a, in_addr_t *ip); +acl_match(struct acl *a, struct evhttp_request *rq, in_addr_t *ip); #endif /* CONF_H */