From 640863e02dbf4f547269d1cd5115e2b148a89180 Mon Sep 17 00:00:00 2001 From: Lammert Bies Date: Sat, 10 Dec 2016 11:02:21 +0100 Subject: [PATCH] Moved check_acl to own file --- Makefile | 1 + src/httplib_check_acl.c | 68 +++++++++++++++++++++++++++++++++++ src/libhttp-private.h | 9 +++++ src/libhttp.c | 78 +++++++++++++---------------------------- 4 files changed, 102 insertions(+), 54 deletions(-) create mode 100644 src/httplib_check_acl.c diff --git a/Makefile b/Makefile index 1dae6bfd..614126fb 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,7 @@ BUILD_DIRS = $(BUILD_DIR) $(BUILD_DIR)/src $(BUILD_DIR)/resources LIB_SOURCES = src/libhttp.c \ src/httplib_accept_new_connection.c \ + src/httplib_check_acl.c \ src/httplib_check_feature.c \ src/httplib_close_connection.c \ src/httplib_close_socket_gracefully.c \ diff --git a/src/httplib_check_acl.c b/src/httplib_check_acl.c new file mode 100644 index 00000000..826dc6ee --- /dev/null +++ b/src/httplib_check_acl.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 Lammert Bies + * Copyright (c) 2013-2016 the Civetweb developers + * Copyright (c) 2004-2013 Sergey Lyubka + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + +#include "libhttp-private.h" + + + +/* + * int XX_httplib_check_acl( struct mg_context *ctx, uint32_t remote_ip ); + * + * The function XX_httplib_check_acl() is used to check of the socket address + * of a connection is allowed according to the access control list. The + * function returns -1 if the ACL is malformed, 0 if the address is not + * allowed and 1 if the address is allowed. + */ + +int XX_httplib_check_acl( struct mg_context *ctx, uint32_t remote_ip ) { + + int allowed; + int flag; + uint32_t net; + uint32_t mask; + struct vec vec; + + if (ctx) { + const char *list = ctx->config[ACCESS_CONTROL_LIST]; + + /* If any ACL is set, deny by default */ + allowed = (list == NULL) ? '+' : '-'; + + while ((list = XX_httplib_next_option(list, &vec, NULL)) != NULL) { + flag = vec.ptr[0]; + if ((flag != '+' && flag != '-') || XX_httplib_parse_net(&vec.ptr[1], &net, &mask) == 0) { + mg_cry( XX_httplib_fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__); + return -1; + } + + if (net == (remote_ip & mask)) allowed = flag; + } + + return allowed == '+'; + } + return -1; + +} /* XX_httplib_check_acl */ diff --git a/src/libhttp-private.h b/src/libhttp-private.h index 4b66953d..6993df44 100644 --- a/src/libhttp-private.h +++ b/src/libhttp-private.h @@ -817,6 +817,13 @@ struct file { #define STRUCT_FILE_INITIALIZER { (uint64_t)0, (time_t)0, (FILE *)NULL, (const char *)NULL, 0, 0 } +/* Describes a string (chunk of memory). */ +struct vec { + const char *ptr; + size_t len; +}; + + /* * Functions local to the server. These functions all begin with XX_httplib to * indicate that these are private functions. @@ -847,7 +854,9 @@ int XX_httplib_is_valid_port( unsigned long port ); int XX_httplib_join_thread( pthread_t threadid ); void * XX_httplib_load_dll( struct mg_context *ctx, const char *dll_name, struct ssl_func *sw ); void XX_httplib_log_access( const struct mg_connection *conn ); +const char * XX_httplib_next_option( const char *list, struct vec *val, struct vec *eq_val ); int XX_httplib_parse_http_message( char *buf, int len, struct mg_request_info *ri ); +int XX_httplib_parse_net( const char *spec, uint32_t *net, uint32_t *mask ); void XX_httplib_process_new_connection( struct mg_connection *conn ); void XX_httplib_produce_socket( struct mg_context *ctx, const struct socket *sp ); int XX_httplib_read_request( FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread ); diff --git a/src/libhttp.c b/src/libhttp.c index 2e4dac4d..101452ed 100644 --- a/src/libhttp.c +++ b/src/libhttp.c @@ -545,12 +545,6 @@ struct ssl_func XX_httplib_crypto_sw[] = {{"CRYPTO_num_locks", NULL}, static const char *month_names[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; #endif /* !NO_CACHING */ -/* Describes a string (chunk of memory). */ -struct vec { - const char *ptr; - size_t len; -}; - /* Config option name, config types, default value */ @@ -1346,7 +1340,7 @@ const char *mg_get_header( const struct mg_connection *conn, const char *name ) * Value is stored in val vector. If value has form "x=y", then eq_val * vector is initialized to point to the "y" part, and val vector length * is adjusted to point only to "x". */ -static const char * next_option(const char *list, struct vec *val, struct vec *eq_val) { +const char *XX_httplib_next_option( const char *list, struct vec *val, struct vec *eq_val ) { int end; @@ -1394,7 +1388,10 @@ reparse: } return list; -} + +} /* XX_httplib_next_option */ + + /* A helper function for checking if a comma separated list of values contains * the given option (case insensitvely). @@ -1407,7 +1404,7 @@ static int header_has_option(const char *header, const char *option) { assert(option != NULL); assert(option[0] != '\0'); - while ((header = next_option(header, &opt_vec, &eq_vec)) != NULL) { + while ((header = XX_httplib_next_option(header, &opt_vec, &eq_vec)) != NULL) { if (mg_strncasecmp(option, opt_vec.ptr, opt_vec.len) == 0) return 1; } @@ -3414,7 +3411,7 @@ interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */ if (truncated) goto interpret_cleanup; rewrite = conn->ctx->config[REWRITE]; - while ((rewrite = next_option(rewrite, &a, &b)) != NULL) { + while ((rewrite = XX_httplib_next_option(rewrite, &a, &b)) != NULL) { if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) { XX_httplib_snprintf(conn, &truncated, filename, filename_buf_len - 1, "%.*s%s", (int)b.len, b.ptr, uri + match_len); break; @@ -3761,7 +3758,7 @@ static void get_mime_type(struct mg_context *ctx, const char *path, struct vec * /* Scan user-defined mime types first, in case user wants to * override default mime types. */ list = ctx->config[EXTRA_MIME_TYPES]; - while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) { + while ((list = XX_httplib_next_option(list, &ext_vec, &mime_vec)) != NULL) { /* ext now points to the path suffix */ ext = path + path_len - ext_vec.len; if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) { @@ -4134,7 +4131,7 @@ static int check_authorization(struct mg_connection *conn, const char *path) { if (!conn || !conn->ctx) return 0; list = conn->ctx->config[PROTECT_URI]; - while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) { + while ((list = XX_httplib_next_option(list, &uri_vec, &filename_vec)) != NULL) { if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) { XX_httplib_snprintf(conn, &truncated, fname, sizeof(fname), "%.*s", (int)filename_vec.len, filename_vec.ptr); @@ -5379,7 +5376,7 @@ static int substitute_index_file(struct mg_connection *conn, char *path, size_t /* Traverse index files list. For each entry, append it to the given * path and see if the file exists. If it exists, break the loop */ - while ((list = next_option(list, &filename_vec, NULL)) != NULL) { + while ((list = XX_httplib_next_option(list, &filename_vec, NULL)) != NULL) { /* Ignore too long entries that may overflow path buffer */ if (filename_vec.len > path_len - (n + 2)) continue; @@ -5701,7 +5698,7 @@ static void prepare_cgi_environment( struct mg_connection *conn, const char *pro /* Add user-specified variables */ s = conn->ctx->config[CGI_ENVIRONMENT]; - while ((s = next_option(s, &var_vec, NULL)) != NULL) { + while ((s = XX_httplib_next_option(s, &var_vec, NULL)) != NULL) { addenv(env, "%.*s", (int)var_vec.len, var_vec.ptr); } @@ -7165,9 +7162,15 @@ static int isbyte(int n) { } /* isbyte */ -static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) { +int XX_httplib_parse_net( const char *spec, uint32_t *net, uint32_t *mask ) { - int n, a, b, c, d, slash = 32, len = 0; + int n; + int a; + int b; + int c; + int d; + int slash = 32; + int len = 0; if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 || sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) && isbyte(a) @@ -7179,7 +7182,8 @@ static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) { } return len; -} + +} /* XX_httplib_parse_net */ static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri) { @@ -7190,7 +7194,7 @@ static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri) { char mult; double v; - while ((spec = next_option(spec, &vec, &val)) != NULL) { + while ((spec = XX_httplib_next_option(spec, &vec, &val)) != NULL) { mult = ','; if ((val.ptr == NULL) || (sscanf(val.ptr, "%lf%c", &v, &mult) < 1) || (v < 0) || ((lowercase(&mult) != 'k') @@ -7200,7 +7204,7 @@ static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri) { v *= (lowercase(&mult) == 'k') ? 1024 : ((lowercase(&mult) == 'm') ? 1048576 : 1); if (vec.len == 1 && vec.ptr[0] == '*') { throttle = (int)v; - } else if (parse_net(vec.ptr, &net, &mask) > 0) { + } else if (XX_httplib_parse_net(vec.ptr, &net, &mask) > 0) { if ((remote_ip & mask) == net) { throttle = (int)v; } @@ -8053,7 +8057,7 @@ int XX_httplib_set_ports_option( struct mg_context *ctx ) { len = sizeof(usa); list = ctx->config[LISTENING_PORTS]; - while ((list = next_option(list, &vec, NULL)) != NULL) { + while ((list = XX_httplib_next_option(list, &vec, NULL)) != NULL) { portsTotal++; @@ -8294,37 +8298,3 @@ void XX_httplib_log_access( const struct mg_connection *conn ) { } } /* XX_httplib_log_access */ - - -/* Verify given socket address against the ACL. - * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed. - */ -int XX_httplib_check_acl( struct mg_context *ctx, uint32_t remote_ip ) { - - int allowed; - int flag; - uint32_t net; - uint32_t mask; - struct vec vec; - - if (ctx) { - const char *list = ctx->config[ACCESS_CONTROL_LIST]; - - /* If any ACL is set, deny by default */ - allowed = (list == NULL) ? '+' : '-'; - - while ((list = next_option(list, &vec, NULL)) != NULL) { - flag = vec.ptr[0]; - if ((flag != '+' && flag != '-') || parse_net(&vec.ptr[1], &net, &mask) == 0) { - mg_cry( XX_httplib_fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__); - return -1; - } - - if (net == (remote_ip & mask)) allowed = flag; - } - - return allowed == '+'; - } - return -1; - -} /* XX_httplib_check_acl */