From 3dc8cb104d3392e00514bb829c50390a9598fe3c Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 12 Jun 2008 03:40:09 +0000 Subject: - apache2x module now supports connecting to multiple daemon addresses and failover between them. --- ChangeLog | 2 + apache1x/Makefile.am | 2 +- apache1x/mod_httpauth.c | 4 +- apache2x/Makefile.am | 8 +- apache2x/mod_httpauth.c | 571 +++++++++++++++++++++++++++++++++++------------- common/sock-any.c | 506 ++++++++++++++++++++++++++++++++++++++++++ common/sock-any.h | 104 +++++++++ common/sock_any.c | 355 ------------------------------ common/sock_any.h | 88 -------- common/stringx.c | 1 + daemon/Makefile.am | 2 +- daemon/httpauthd.c | 2 +- 12 files changed, 1044 insertions(+), 601 deletions(-) create mode 100644 common/sock-any.c create mode 100644 common/sock-any.h delete mode 100644 common/sock_any.c delete mode 100644 common/sock_any.h diff --git a/ChangeLog b/ChangeLog index 1ab0d41..0d0912e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,8 @@ - Build warning fixes. - Allow better migration of live digest sessions between httpauth daemons by using the 'stale' flag when things seem out of date. + - apache2x module now supports connecting to multiple daemon addresses + and failover between them. 0.9.2 [22-05-2008] - Authenticate sub requests properly in the apache module. diff --git a/apache1x/Makefile.am b/apache1x/Makefile.am index d043935..a768b2e 100644 --- a/apache1x/Makefile.am +++ b/apache1x/Makefile.am @@ -7,7 +7,7 @@ INC=-I../ -I../common/ all: mod_httpauth.so -mod_httpauth.so: mod_httpauth.c ../common/sock_any.c +mod_httpauth.so: mod_httpauth.c ../common/sock-any.c @APXS@ -c -Wc,-g -Wc,-O0 $(DEF) $(INC) $(LIB) mod_httpauth.c # install the DSO file into the Apache installation diff --git a/apache1x/mod_httpauth.c b/apache1x/mod_httpauth.c index fffaf9d..bb71ea7 100644 --- a/apache1x/mod_httpauth.c +++ b/apache1x/mod_httpauth.c @@ -44,7 +44,7 @@ #include #include -#include "sock_any.h" +#include "sock-any.h" #include "stringx.h" #define DEFAULT_PORT 8020 @@ -898,5 +898,5 @@ module MODULE_VAR_EXPORT httpauth_module = * object file, at least when statically compiled. * so we include this here */ -#include "../common/sock_any.c" +#include "../common/sock-any.c" #include "../common/stringx.c" diff --git a/apache2x/Makefile.am b/apache2x/Makefile.am index a1396c4..6019b06 100644 --- a/apache2x/Makefile.am +++ b/apache2x/Makefile.am @@ -1,14 +1,14 @@ EXTRA_DIST = mod_httpauth.c -DEF= -INC=-I../ -I../common/ +DEF = +INC = -I../ -I../common/ all: mod_httpauth.so -mod_httpauth.so: mod_httpauth.c ../common/sock_any.c - @APXS@ -c -Wc,-g -Wc,-O0 $(DEF) $(INC) $(LIB) mod_httpauth.c +mod_httpauth.so: mod_httpauth.c ../common/sock-any.c + @APXS@ -c -Wc,-g -Wc,-O0 -Wc,-Wall $(DEF) $(INC) $(LIB) mod_httpauth.c # install the DSO file into the Apache installation # and activate it in the Apache configuration diff --git a/apache2x/mod_httpauth.c b/apache2x/mod_httpauth.c index d6697ae..58e6f2e 100644 --- a/apache2x/mod_httpauth.c +++ b/apache2x/mod_httpauth.c @@ -41,13 +41,23 @@ #include #include #include +#include #include #include +#include "apr_file_io.h" #include +#include + +/* Apache defines these */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION #include -#include "sock_any.h" +#include "sock-any.h" #include "stringx.h" #define DEFAULT_PORT 8020 @@ -60,24 +70,48 @@ static void* conn_current = NULL; /* And increment this when it goes out of scope */ static unsigned int conn_seen = 0; -typedef struct httpauth_context -{ - const char* socketname; - int socket; - int types; - const char* handler; - const char* domain; - char* needed_groups; - int alloced_groups; - apr_pool_t* child_pool; -} -httpauth_context_t; +/* + * Per directory configuration. + */ +typedef struct httpauth_context { + const char* socketname; + int socket; + int types; + const char* handler; + const char* domain; + char* needed_groups; + int alloced_groups; + apr_pool_t* child_pool; + + int address_seed; + int retries; + + int shared_version; + void *shared_block; +} httpauth_context_t; + +/* + * Tagged onto a request once authenticated, used for access + * groups and revalidating an already authenticated request. + */ typedef struct httpauth_request { const char *user; const char *groups; } httpauth_request_t; +/* + * Shared between all instances of a httpauth_context in + * different processes on a server. + */ +typedef struct httpauth_shared { + int version; + struct sockaddr_any address; +} httpauth_shared_t; + +static apr_global_mutex_t *shared_lock = NULL; +static const char *shared_lock_name = NULL; + /* TODO: Support proxy authentication properly */ #define AUTH_PREFIX_BASIC "Basic" @@ -92,33 +126,197 @@ typedef struct httpauth_request { #define HTTPAUTH_AUTHTYPE "HTTPAUTH" /* ------------------------------------------------------------------------------- - * Configuration code + * Shared memory */ -static void* httpauth_dir_config(apr_pool_t* p, char* dir) +static int +httpauth_initialize (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { - httpauth_context_t* ctx; + apr_file_t *file = NULL; + const char *tmpdir; + char *lock_name; + int rc; + + /* This may be called more than once */ + if (shared_lock) + return OK; + + rc = apr_temp_dir_get (&tmpdir, p); + if (rc != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_ERR, rc, s, + "httpauth: couldn't get temporary directory"); + + if (rc == APR_SUCCESS) { + lock_name = apr_pstrcat (p, tmpdir, "/", "mod-httpauth.lock.XXXXXX", NULL); + rc = apr_file_mktemp (&file, lock_name, 0, p); + if (rc != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, + "httpauth: couldn't create temporary file: %s", lock_name); + } + + if (rc == APR_SUCCESS) { + rc = apr_global_mutex_create (&shared_lock, lock_name, APR_LOCK_DEFAULT, p); + if (rc != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_ERR, rc, s, + "httpauth: couldn't create shared memory lock"); + } + + if (file != NULL) + apr_file_close (file); + shared_lock_name = lock_name; + + return OK; +} + +static void +httpauth_child (apr_pool_t *p, server_rec *s) +{ + apr_status_t rc; + + if (!shared_lock) + return; + + rc = apr_global_mutex_child_init (&shared_lock, shared_lock_name, p); + if (rc != APR_SUCCESS) { + ap_log_error (APLOG_MARK, APLOG_ERR, rc, s, + "httpauth: couldn't create lock for shared memory in child"); + shared_lock = NULL; + } +} + +static int +shared_get_if_changed (httpauth_context_t *ctx, int version, httpauth_shared_t *shared) +{ + httpauth_shared_t *block; + int ret = 0; + + if (!ctx->shared_block) + return 0; - ctx = (httpauth_context_t*)apr_pcalloc(p, sizeof(*ctx)); - memset(ctx, 0, sizeof(*ctx)); + apr_global_mutex_lock (shared_lock); - ctx->socket = -1; - ctx->types = 0xFFFFFFFF; - ctx->child_pool = p; - ctx->needed_groups = NULL; - ctx->alloced_groups = 0; - return ctx; + block = ctx->shared_block; + if (block->version != version) { + ret = 1; + if (shared) + memcpy (shared, block, sizeof (*shared)); + } + + apr_global_mutex_unlock (shared_lock); + + return ret; +} + +static void +shared_set_if_changed (httpauth_context_t *ctx, httpauth_shared_t *shared) +{ + httpauth_shared_t *block; + + if (!ctx->shared_block) + return; + + apr_global_mutex_lock (shared_lock); + + block = ctx->shared_block; + if (memcmp (shared, block, sizeof (*shared)) != 0) { + + /* Increment the version beyond all */ + if (block->version > shared->version) + shared->version = block->version; + ++shared->version; + + /* And write it out */ + memcpy (block, shared, sizeof (*shared)); + } + + apr_global_mutex_unlock (shared_lock); +} + +/* ------------------------------------------------------------------------------- + * Per Directory Config and Context Code + */ + +static void* httpauth_dir_config (apr_pool_t* p, char* dir) +{ + httpauth_context_t* ctx; + httpauth_shared_t shared; + const char *tmpdir; + char *filename; + apr_file_t *file; + apr_mmap_t *map; + void *addr; + int rc; + + ctx = (httpauth_context_t*)apr_pcalloc(p, sizeof(*ctx)); + memset(ctx, 0, sizeof(*ctx)); + + ctx->socket = -1; + ctx->types = 0xFFFFFFFF; + ctx->child_pool = p; + ctx->needed_groups = NULL; + ctx->alloced_groups = 0; + ctx->shared_version = 0; + ctx->retries = 1; + + if (!dir) + return ctx; + + /* Get the temp directory */ + rc = apr_temp_dir_get (&tmpdir, p); + if (rc != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, + "httpauth: couldn't get temporary directory"); + + /* Create the shared file */ + if (rc == APR_SUCCESS) { + filename = apr_pstrcat (p, tmpdir, "/", "mod-httpauth.board.XXXXXX", NULL); + rc = apr_file_mktemp (&file, filename, 0, p); + if (rc != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, + "httpauth: couldn't create temporary file: %s", filename); + } + + /* Write a shared block to file */ + if (rc == APR_SUCCESS) { + memset (&shared, 0, sizeof (shared)); + rc = apr_file_write_full (file, &shared, sizeof (shared), NULL); + if (rc != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, + "httpauth: couldn't write to temporary file: %s", filename); + } + + /* Map the shared file into memory */ + if (rc == APR_SUCCESS) { + rc = apr_mmap_create (&map, file, 0, sizeof (shared), + APR_MMAP_READ | APR_MMAP_WRITE, p); + if (rc != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, + "httpauth: couldn't map temporary file: %s", filename); + } + + /* Get the actual address of the mapping */ + if (rc == APR_SUCCESS) { + rc = apr_mmap_offset (&addr, map, 0); + if (rc != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, + "httpauth: couldn't get shared memory"); + } + + if (rc == APR_SUCCESS) + ctx->shared_block = addr; + + return ctx; } static const char* set_socket(cmd_parms* cmd, void* config, const char* val) { - struct sockaddr_any sany; + struct sockaddr_any sany; - if(sock_any_pton(val, &sany, DEFAULT_PORT) == -1) - return "Invalid socket name or ip in HttpAuthSocket"; + if (sock_any_pton_n (val, &sany, 1, DEFAULT_PORT | SANY_OPT_NORESOLV) == -1) + return "Invalid socket name or ip in HttpAuthSocket"; - ((httpauth_context_t*)config)->socketname = val; - return NULL; + ((httpauth_context_t*)config)->socketname = val; + return NULL; } static const char* set_handler(cmd_parms* cmd, void* config, const char* val) @@ -161,7 +359,7 @@ static const char* set_domain(cmd_parms* cmd, void* config, const char* val) static const command_rec httpauth_cmds[] = { - AP_INIT_TAKE1( "HttpAuthSocket", set_socket, NULL, OR_AUTHCFG, + AP_INIT_RAW_ARGS( "HttpAuthSocket", set_socket, NULL, OR_AUTHCFG, "The socket that httpauthd is listening on" ), AP_INIT_TAKE1( "HttpAuthHandler", set_handler, NULL, OR_AUTHCFG, "The handler that httpauthd should use to authenticate" ), @@ -193,6 +391,8 @@ void disconnect_socket(httpauth_context_t* ctx, server_rec* s) cleanup_socket); close(ctx->socket); ctx->socket = -1; + + /* Make sure we send our list of groups to daemon again */ if (ctx->needed_groups) ctx->needed_groups[0] = 0; } @@ -310,63 +510,68 @@ int read_line(httpauth_context_t* ctx, request_rec* r, char** line) return 0; } -int read_response(httpauth_context_t* ctx, request_rec* r, - int* code, int* ccode, char** details, - int return_errors) +int +read_response (httpauth_context_t *ctx, request_rec *r, + int *code, int *ccode, char **details, + int return_errors) { - int c; - char* line; - char* t; - char* t2; - - if(read_line(ctx, r, &line) == -1) - return -1; - - line = trim_space(line); + int c, ret = -1; + char *line; + char *t; + char *t2; + + if (read_line (ctx, r, &line) == -1) + return -1; + + line = trim_space (line); + + ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, + "httpauth: received response line from daemon: %s", line); + + /* Get response code */ + t = ap_getword_nc (r->pool, &line, ' '); + c = strtol (t, &t2, 10); + if (*t2 || c < 100 || c > 999) { + ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, + "httpauth: protocol error: invalid code: %s", t); + goto finally; + } - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: received response line from daemon: %s", line); + if (code) + *code = c; - /* Get response code */ - t = ap_getword_nc(r->pool, &line, ' '); - c = strtol(t, &t2, 10); - if(*t2 || c < 100 || c > 999) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: invalid code: %s", t); - return -1; - } + if (c >= 400 && !return_errors) { + ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, + "httpauth: received error from httpauthd: %d %s", c, line); + goto finally; + } - if(code) - *code = c; + /* Get the second response code if we're a 200 */ + if (c == 200) { + t = ap_getword_nc (r->pool, &line, ' '); + c = strtol (t, &t2, 10); + if (*t2 || c < 100 || c > 999) { + ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, + "httpauth: protocol error: invalid code: %s", t); + goto finally; + } - if(c >= 400 && !return_errors) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: received error from httpauthd: %d %s", c, line); - return -1; - } + if (ccode) + *ccode = c; + } - /* Get the second response code if we're a 200 */ - if(c == 200) - { - t = ap_getword_nc(r->pool, &line, ' '); - c = strtol(t, &t2, 10); - if(*t2 || c < 100 || c > 999) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: invalid code: %s", t); - return -1; - } + if (details) + *details = trim_space (line); - if(ccode) - *ccode = c; - } + ret = 0; - if(details) - *details = trim_space(line); +finally: + if (ret < 0 && ctx->socket >= 0) { + disconnect_socket (ctx, r->server); + ++ctx->address_seed; + } - return 0; + return ret; } static int @@ -513,46 +718,94 @@ int write_data(httpauth_context_t* ctx, server_rec* s, const char* data) return 0; } -int connect_socket(httpauth_context_t* ctx, request_rec* r) +static int +try_connect_socket (httpauth_context_t *ctx, struct sockaddr_any *sany, + request_rec *r) { - struct sockaddr_any sany; - int ret = -1; + char peername[256]; + int rc; - disconnect_socket(ctx, r->server); + if (sock_any_ntop (sany, peername, sizeof (peername), 0) < 0) + strcpy (peername, "[unknown]"); - if(sock_any_pton(ctx->socketname, &sany, DEFAULT_PORT) == -1) - { - ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, - "httpauth: Invalid socket name or ip."); - goto finally; - } + ctx->socket = socket (SANY_TYPE (*sany), SOCK_STREAM, 0); + if(ctx->socket == -1) { + ap_log_rerror (APLOG_MARK, APLOG_CRIT, APR_FROM_OS_ERROR (errno), r, + "httpauth: Can't create socket"); + return -1; + } - ctx->socket = socket(SANY_TYPE(sany), SOCK_STREAM, 0); - if(ctx->socket == -1) - { - ap_log_rerror(APLOG_MARK, APLOG_CRIT, APR_FROM_OS_ERROR(errno), r, - "httpauth: Can't create socket: %s", ctx->socketname); - goto finally; - } + if (connect (ctx->socket, &SANY_ADDR (*sany), SANY_LEN(*sany)) != 0) { + rc = APR_FROM_OS_ERROR (errno); + ap_log_rerror (APLOG_MARK, APLOG_CRIT, rc, r, + "httpauth: Can't connect to httpauthd at: %s", peername); + close (ctx->socket); + ctx->socket = -1; + return -1; + } - apr_pool_cleanup_register(ctx->child_pool, (void*)(long)ctx->socket, - cleanup_socket, cleanup_socket); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "httpauth: connected to daemon: %s", peername); - if(connect(ctx->socket, &SANY_ADDR(sany), SANY_LEN(sany)) != 0) - { - ap_log_rerror(APLOG_MARK, APLOG_CRIT, APR_FROM_OS_ERROR(errno), r, - "httpauth: Can't connect to httpauthd"); - goto finally; - } + return 0; +} - ret = 0; +static int +connect_socket(httpauth_context_t* ctx, request_rec* r) +{ + httpauth_shared_t shared; + struct sockaddr_any sany[16]; + int i, which, count = 0; + int rc = -1; + + disconnect_socket(ctx, r->server); + memset (&shared, 0, sizeof (shared)); + + /* Find out what everyone else is connected to */ + if (shared_get_if_changed (ctx, ctx->shared_version, &shared) && shared.version > 0) { + ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, + "httpauth: trying shared address..."); + rc = try_connect_socket (ctx, &shared.address, r); + } -finally: - if(ret == -1) - disconnect_socket(ctx, r->server); + /* Now try to connect to all the other addresses */ + if (rc < 0) { + ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, + "httpauth: resolving daemon address(s)"); + + count = sock_any_pton_n (ctx->socketname, sany, 16, DEFAULT_PORT); + if (count < 0) { + ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, + "httpauth: Invalid socket name or ip: %s", ctx->socketname); + rc = -1; + } + + /* We know how many addresses we have to retry with */ + if (count > 0) + ctx->retries = count; - errno = 0; - return ret; + for (i = 0; i != count; ++i) { + which = (i + ctx->address_seed) % count; + rc = try_connect_socket (ctx, &sany[which], r); + + /* Successful, then let others know we're connected here */ + if (rc >= 0) { + memcpy (&shared.address, &sany[which], sizeof (shared.address)); + break; + } + } + } + + /* Yay, successful */ + if (rc >= 0) { + shared_set_if_changed (ctx, &shared); + ctx->shared_version = shared.version; + apr_pool_cleanup_register(ctx->child_pool, (void*)(long)ctx->socket, + cleanup_socket, cleanup_socket); + errno = 0; + } + + return rc; } int connect_httpauth(httpauth_context_t* ctx, request_rec* r) @@ -631,13 +884,15 @@ int connect_httpauth(httpauth_context_t* ctx, request_rec* r) /* We're cool! */ ret = 0; - ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "httpauth: connected to daemon"); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "httpauth: handshake with daemon completed"); finally: - if(ret == -1) - disconnect_socket(ctx, r->server); + if(ret == -1 && ctx->socket >= 0) { + disconnect_socket(ctx, r->server); + ++ctx->address_seed; + } - return ret; + return ret; } /* Make sure our connection identifier is unique */ @@ -811,6 +1066,7 @@ static int httpauth_authenticate(request_rec* r) httpauth_request_t* hreq; const char* authtype; int code = 0; + int ccode = 0; char *groups = NULL; char* details = NULL; @@ -843,43 +1099,60 @@ static int httpauth_authenticate(request_rec* r) return OK; } + /* + * Check if we're in sync with the other processes, + * and connected to the same daemon + */ + if (ctx->socket != -1 && shared_get_if_changed (ctx, ctx->shared_version, NULL)) { + ap_log_rerror (APLOG_MARK, APLOG_INFO, 0, r, + "httpauth: syncing connection with other processes"); + disconnect_socket (ctx, r->server); + } + /* For jumping to when a connection has been closed */ retry: - if(ctx->socket == -1) - { - if(connect_httpauth(ctx, r) == -1) - return HTTP_INTERNAL_SERVER_ERROR; - } + if (ctx->socket == -1) { + if (connect_httpauth (ctx, r) == -1) { - /* Make sure we're starting on a clean slate */ - read_junk(ctx, r); + if (ctx->socket == -1 && retried < ctx->retries) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + "httpauth: trying to connect to daemon again"); + ++retried; + goto retry; + } - /* Send off a request, along with groups, and read response */ - if(write_needed_groups(ctx, r) == -1 || - write_request(ctx, r) == -1 || - read_response(ctx, r, &code, &ccode, &details, 0) == -1) - { - /* - * If our connection was closed by httpauthd then this - * is where we get the error. Just do one retry to - * try and reconnect. This happens often when restarting - * httpauthd. - */ + return HTTP_INTERNAL_SERVER_ERROR; + } + } - if(ctx->socket == -1 && !retried) - { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "httpauth: reconnecting to to httpauthd"); - retried = 1; - goto retry; - } + /* Make sure we're starting on a clean slate */ + read_junk (ctx, r); + + /* Send off a request, along with groups, and read response */ + if (write_needed_groups (ctx, r) == -1 || + write_request (ctx, r) == -1 || + read_response (ctx, r, &code, &ccode, &details, 0) == -1) { + + /* + * If our connection was closed by httpauthd then this + * is where we get the error. Just do one retry to + * try and reconnect. This happens often when restarting + * httpauthd. + */ + + if (ctx->socket == -1 && retried < ctx->retries) { + ap_log_rerror (APLOG_MARK, APLOG_WARNING, 0, r, + "httpauth: reconnecting to to httpauthd"); + ++retried; + goto retry; + } - ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), r, - "httpauth: couldn't send request to httpauthd"); + ap_log_rerror (APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), r, + "httpauth: couldn't send request to httpauthd"); - return HTTP_INTERNAL_SERVER_ERROR; - } + return HTTP_INTERNAL_SERVER_ERROR; + } if(code != 200) { @@ -951,7 +1224,7 @@ httpauth_access(request_rec *r) int m = r->method_number; int method_restricted = 0; register int x; - const char *text, *word, *at; + const char *text, *word; const apr_array_header_t *reqs_arr = ap_requires (r); require_line *reqs; @@ -1018,10 +1291,10 @@ httpauth_access(request_rec *r) static void register_hooks(apr_pool_t *p) { - /* static const char* cfg_post[] = { "http_core.c", NULL }; */ - - ap_hook_check_user_id(httpauth_authenticate, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_auth_checker(httpauth_access, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_post_config (httpauth_initialize, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init (httpauth_child, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_check_user_id (httpauth_authenticate, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_auth_checker (httpauth_access, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA httpauth_module = @@ -1029,7 +1302,7 @@ module AP_MODULE_DECLARE_DATA httpauth_module = STANDARD20_MODULE_STUFF, httpauth_dir_config, /* dir config creater */ NULL, /* dir merger --- default is to override */ - NULL, /* server config */ + NULL, /* server config */ NULL, /* merge server config */ httpauth_cmds, /* command table */ register_hooks /* register hooks */ @@ -1040,5 +1313,5 @@ module AP_MODULE_DECLARE_DATA httpauth_module = * object file, at least when statically compiled. * so we include this here */ -#include "../common/sock_any.c" +#include "../common/sock-any.c" #include "../common/stringx.c" diff --git a/common/sock-any.c b/common/sock-any.c new file mode 100644 index 0000000..581ef5b --- /dev/null +++ b/common/sock-any.c @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2004, Stefan Walter + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * + * CONTRIBUTORS + * Stef Walter + * + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "sock-any.h" + +#include + +#define LOCALHOST_ADDR 0x7F000001 +#define WHITESPACE " \t\n\r\v" + +int +sock_any_pton(const char* addr, struct sockaddr_any* any, int opts) +{ + size_t l; + char buf[256]; + char* t; + char* t2; + int defport = (opts & 0xFFFF); + + assert (addr); + assert (any); + + if (!addr[0]) { + errno = EINVAL; + return -1; + } + + memset(any, 0, sizeof(*any)); + + /* Just a port? */ + do { + #define PORT_CHARS "0123456789" + #define PORT_MIN 1 + #define PORT_MAX 5 + + int port = 0; + + l = strspn (addr, PORT_CHARS); + if (l < PORT_MIN || l > PORT_MAX || addr[l] != 0) + break; + + port = strtol (addr, &t2, 10); + if (*t2 || port <= 0 || port >= 65536) + break; + + any->s.in.sin_port = htons (port); + + /* Fill in the type based on defaults */ +#ifdef HAVE_INET6 + if (opts & SANY_OPT_DEFINET6) + any->s.in.sin_family = AF_INET6; + else +#endif + any->s.in.sin_family = AF_INET; + + /* Fill in the address based on defaults */ + if (opts & SANY_OPT_DEFLOCAL) { +#ifdef HAVE_INET6 + if(opts & SANY_OPT_DEFINET6) + memcpy(&(any->s.in.sin6_addr), &in6addr_loopback, sizeof(struct in6_addr)); + else + any->s.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif + } + + /* + * Note the 'any' option is the default since we zero out + * the entire structure above. + */ + + any->namelen = sizeof (any->s.in); + return AF_INET; + } + while (0); + + /* Look and see if we can parse an ipv4 address */ + do + { + #define IPV4_CHARS "0123456789." + #define IPV4_MIN 3 + #define IPV4_MAX 21 + + int port = 0; + t = NULL; + + l = strlen (addr); + if(l < IPV4_MIN || l > IPV4_MAX) + break; + + strcpy (buf, addr); + + /* Find the last set that contains just numbers */ + l = strspn (buf, IPV4_CHARS); + if(l < IPV4_MIN) + break; + + /* Either end of string or port */ + if (buf[l] != 0 && buf[l] != ':') + break; + + /* Get the port out */ + if (buf[l] != 0) { + t = buf + l + 1; + buf[l] = 0; + } + + if (t) { + port = strtol(t, &t2, 10); + if(*t2 || port <= 0 || port >= 65536) + break; + } + + any->s.in.sin_family = AF_INET; + any->s.in.sin_port = htons ((unsigned short)(port <= 0 ? defport : port)); + + if (inet_pton (AF_INET, buf, &(any->s.in.sin_addr)) <= 0) + break; + + any->namelen = sizeof(any->s.in); + return AF_INET; + } + while(0); + +#ifdef HAVE_INET6 + do + { + #define IPV6_CHARS "0123456789:" + #define IPV6_MIN 3 + #define IPV6_MAX 51 + + int port = -1; + t = NULL; + + l = strlen(addr); + if (l < IPV6_MIN || l > IPV6_MAX) + break; + + /* If it starts with a '[' then we can get port */ + if (buf[0] == '[') { + port = 0; + addr++; + } + + strcpy (buf, addr); + + /* Find the last set that contains just numbers */ + l = strspn(buf, IPV6_CHARS); + if (l < IPV6_MIN) + break; + + /* Either end of string or port */ + if (buf[l] != 0) { + /* If had bracket, then needs to end with a bracket */ + if (port != 0 || buf[l] != ']') + break; + + /* Get the port out */ + t = buf + l + 1; + + if(*t = ':') + t++; + } + + if (t) { + port = strtol (t, &t, 10); + if (*t || port <= 0 || port >= 65536) + break; + } + + any->s.in6.sin6_family = AF_INET6; + any->s.in6.sin6_port = htons ((unsigned short)port <= 0 : defport : port); + + if (inet_pton(AF_INET6, buf, &(any->s.in6.sin6_addr)) >= 0) + break; + + any->namelen = sizeof (any->s.in6); + return AF_INET6; + } while (0); +#endif + + /* A unix socket path */ + do { + /* No colon and must have a path component */ + if (strchr (addr, ':') || !strchr (addr, '/')) + break; + + l = strlen(addr); + if (l >= sizeof(any->s.un.sun_path)) + break; + + any->s.un.sun_family = AF_UNIX; + strcpy (any->s.un.sun_path, addr); + + any->namelen = sizeof (any->s.un) - (sizeof (any->s.un.sun_path) - l); + return AF_UNIX; + } while(0); + + /* A DNS name and a port? */ + do { + struct addrinfo* res; + int port = 0; + int family = 0; + t = NULL; + + l = strlen(addr); + if (l >= 255 || !isalpha(addr[0])) + break; + + /* Some basic illegal character checks */ + if (strcspn(addr, " /\\") != l) + break; + + strcpy (buf, addr); + + /* Find the last set that contains just numbers */ + t = strchr (buf, ':'); + if (t) { + *t = 0; + t++; + } + + if (t) { + port = strtol (t, &t2, 10); + if (*t2 || port <= 0 || port >= 65536) + break; + } + + if (!(opts & SANY_OPT_NORESOLV)) { + /* Try and resolve the domain name */ + if (getaddrinfo (buf, NULL, NULL, &res) != 0 || !res) + break; + + memcpy (&(any->s.a), res->ai_addr, sizeof (struct sockaddr)); + any->namelen = res->ai_addrlen; + family = any->s.a.sa_family; + freeaddrinfo (res); + } else { + family = SANY_AF_DNS; +#ifdef HAVE_INET6 + if (opt & SANY_OPT_DEFINET6) + { + any->s.a.sa_family = AF_INET6; + any->namelen = sizeof (any->s.in6); + } else +#endif + { + any->s.a.sa_family = AF_INET; + any->namelen = sizeof(any->s.in); + } + } + + port = htons ((unsigned short)(port <= 0 ? defport : port)); + + switch (any->s.a.sa_family) { + case PF_INET: + any->s.in.sin_port = port; + break; +#ifdef HAVE_INET6 + case PF_INET6: + any->s.in6.sin6_port = port; + break; +#endif + }; + + return family; + } while (0); + + errno = EAFNOSUPPORT; + return -1; +} + +int +sock_any_pton_n (const char *string, struct sockaddr_any *addrs, int n_addrs, int opts) +{ + struct addrinfo hints, *res, *ai; + const char *end; + int rc, num; + char port[16]; + + /* + * Can't have a single address that's longer than + * sockaddr_any structure when in textual form + */ + char buf[sizeof(struct sockaddr_any)]; + + assert (string); + assert (addrs); + + num = n_addrs; + memset (&hints, 0, sizeof (hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_NUMERICSERV; + + /* + * Not actually limitted to these, just need to specify these + * or we'll get multiple results from the resolver. + */ + hints.ai_protocol = IPPROTO_TCP; + hints.ai_socktype = SOCK_STREAM; + + while (string && *string && n_addrs) { + + /* Skip initial blanks */ + while (*string && strchr (WHITESPACE, *string)) + ++string; + + if (!*string) + break; + + /* Find the next word */ + end = string + strcspn (string, WHITESPACE); + assert (end != string); + if (end - string >= sizeof (buf)) { + errno = ENOSPC; + return -1; + } + + /* Parse, but not resolve the address */ + strncpy (buf, string, end - string); + buf[end - string] = 0; + rc = sock_any_pton (buf, addrs, opts | SANY_OPT_NORESOLV); + + if (rc < 0) + return -1; + + /* Parsed to an address */ + if (rc != SANY_AF_DNS) { + ++addrs; + --n_addrs; + + /* Needs DNS resolution */ + } else if (!(opts & SANY_OPT_NORESOLV)) { + + /* Save the port out of the half resolved address */ + switch (addrs->s.a.sa_family) { + case PF_INET: + snprintf (port, sizeof (port), "%d", (int)ntohs (addrs->s.in.sin_port)); + break; +#ifdef HAVE_INET6 + case PF_INET6: + snprintf (port, sizeof (port), "%d", (int)ntohs (addrs->s.in.sin_port)); + break; +#endif + default: + port[0] = 0; + break; + }; + + if (getaddrinfo (buf, port[0] ? port : NULL, &hints, &res) != 0 || !res) + return -1; + + for (ai = res; ai && n_addrs; ai = ai->ai_next) { + + /* Copy in the resolved address */ + memcpy (&(addrs->s.a), res->ai_addr, res->ai_addrlen); + addrs->namelen = res->ai_addrlen; + + ++addrs; + --n_addrs; + } + + freeaddrinfo (res); + } + + string = end; + } + + + /* The number of addrs we used */ + return num - n_addrs; +} + +int +sock_any_ntop (const struct sockaddr_any* any, char* addr, size_t addrlen, int opts) +{ + int len = 0; + int port = 0; + + assert (any); + assert (addr); + + switch (any->s.a.sa_family) { + case AF_UNIX: + len = strlen (any->s.un.sun_path); + if (addrlen < len + 1) { + errno = ENOSPC; + return -1; + } + + strcpy (addr, any->s.un.sun_path); + break; + + case AF_INET: + if (inet_ntop (any->s.a.sa_family, &(any->s.in.sin_addr), addr, addrlen) == NULL) + return -1; + port = ntohs (any->s.in.sin_port); + break; + +#ifdef HAVE_INET6 + case AF_INET6: + if (inet_ntop (any->s.a.sa_family, &(any->s.in6.sin6_addr), addr, addrlen) == NULL) + return -1; + port = ntohs (any->s.in6.sin6_port); + break; +#endif + + default: + errno = EAFNOSUPPORT; + return -1; + } + + if (!(opts & SANY_OPT_NOPORT) && port != 0) + { + strncat (addr, ":", addrlen); + addr[addrlen - 1] = 0; + + len = strlen (addr); + addr += len; + addrlen -= len; + + snprintf (addr, addrlen, "%d", port); + } + + return 0; +} + +int +sock_any_cmp (const struct sockaddr_any* a1, const struct sockaddr_any* a2, int opts) +{ + assert (a1); + assert (a2); + + if (a1->s.a.sa_family != a2->s.a.sa_family) + return -1; + + switch (a1->s.a.sa_family) { + case AF_UNIX: + return strcmp (a1->s.un.sun_path, a2->s.un.sun_path); + + case AF_INET: + if (memcmp (&(a1->s.in.sin_addr), &(a2->s.in.sin_addr), sizeof(a2->s.in.sin_addr)) != 0) + return -1; + if (!(opts && SANY_OPT_NOPORT) && a1->s.in.sin_port != a2->s.in.sin_port) + return -1; + return 0; +#ifdef HAVE_INET6 + case AF_INET6: + if(memcmp(&(a1->s.in6.sin6_addr), &(a2->s.in6.sin6_addr), sizeof(a2->s.in6.sin6_addr)) != 0) + return -1; + if(!(opts && SANY_OPT_NOPORT) && a1->s.in6.sin6_port != a2->s.in6.sin6_port) + return -1; + return 0; +#endif + default: + errno = EAFNOSUPPORT; + return -1; + } +} diff --git a/common/sock-any.h b/common/sock-any.h new file mode 100644 index 0000000..c22d1c7 --- /dev/null +++ b/common/sock-any.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2004, Stefan Walter + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * + * CONTRIBUTORS + * Stef Walter + * + */ + +#ifndef __SOCK_ANY_H__ +#define __SOCK_ANY_H__ + +#include +#include +#include + +struct sockaddr_any +{ + union _sockaddr_any { + /* The header */ + struct sockaddr a; + + /* The different types */ + struct sockaddr_un un; + struct sockaddr_in in; +#ifdef HAVE_INET6 + struct sockaddr_in6 in6; +#endif + } s; + size_t namelen; +}; + +#define SANY_ADDR(any) ((any).s.a) +#define SANY_LEN(any) ((any).namelen) +#define SANY_TYPE(any) ((any).s.a.sa_family) + +/* -------------------------------------------------------------------------- */ + +/* Returns AF_XXX family type or -1 */ +int sock_any_pton (const char *string, struct sockaddr_any *addr, int opts); + +int sock_any_pton_n (const char *string, struct sockaddr_any *addrs, int n_addrs, int opts); + +/* The default port to fill in when no IP/IPv6 port specified */ +#define SANY_OPT_DEFPORT(p) (int)((p) & 0xFFFF) + +/* When only port specified default to IPANY */ +#define SANY_OPT_DEFANY 0x00000000 + +/* When only port specified default to LOCALHOST */ +#define SANY_OPT_DEFLOCAL 0x00100000 + +/* When only port specified default to IPv6 */ +#define SANY_OPT_DEFINET6 0x00200000 + +/* Don't resolve host name */ +#define SANY_OPT_NORESOLV 0x01000000 + +/* The family type returned when resolving is needed */ +#define SANY_AF_DNS 0x01000000 + +/* -------------------------------------------------------------------------- */ + +/* Returns -1 when failed */ +int sock_any_ntop (const struct sockaddr_any *any, char *addr, size_t addrlen, int opts); + +/* Don't print or compare the port */ +#define SANY_OPT_NOPORT 0x01000000 + +/* -------------------------------------------------------------------------- */ + +/* Returns 0 for equal */ +int sock_any_cmp(const struct sockaddr_any *a1, const struct sockaddr_any *a2, int opts); + +#endif /* __SOCK_ANY_H__ */ diff --git a/common/sock_any.c b/common/sock_any.c deleted file mode 100644 index 5972e62..0000000 --- a/common/sock_any.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (c) 2004, Stefan Walter - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * - * CONTRIBUTORS - * Stef Walter - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "sock_any.h" - -#include - -#define LOCALHOST_ADDR 0x7F000001 - -int sock_any_pton(const char* addr, struct sockaddr_any* any, int opts) -{ - size_t l; - char buf[256]; - char* t; - char* t2; - int defport = (opts & 0xFFFF); - - memset(any, 0, sizeof(*any)); - - /* Just a port? */ - do - { - #define PORT_CHARS "0123456789" - #define PORT_MIN 1 - #define PORT_MAX 5 - - int port = 0; - - l = strspn(addr, PORT_CHARS); - if(l < PORT_MIN || l > PORT_MAX || addr[l] != 0) - break; - - port = strtol(addr, &t2, 10); - if(*t2 || port <= 0 || port >= 65536) - break; - - any->s.in.sin_port = htons(port); - - /* Fill in the type based on defaults */ -#ifdef HAVE_INET6 - if(opts & SANY_OPT_DEFINET6) - any->s.in.sin_family = AF_INET6; - else -#endif - any->s.in.sin_family = AF_INET; - - /* Fill in the address based on defaults */ - if(opts & SANY_OPT_DEFLOCAL) - { -#ifdef HAVE_INET6 - if(opts & SANY_OPT_DEFINET6) - memcpy(&(any->s.in.sin6_addr), &in6addr_loopback, sizeof(struct in6_addr)); - else -#endif - any->s.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - } - - /* - * Note the 'any' option is the default since we zero out - * the entire structure above. - */ - - any->namelen = sizeof(any->s.in); - return AF_INET; - } - while(0); - - /* Look and see if we can parse an ipv4 address */ - do - { - #define IPV4_PORT_CHARS - #define IPV4_CHARS "0123456789." - #define IPV4_MIN 3 - #define IPV4_MAX 18 - - int port = 0; - t = NULL; - - l = strlen(addr); - if(l < IPV4_MIN || l > IPV4_MAX) - break; - - strcpy(buf, addr); - - /* Find the last set that contains just numbers */ - l = strspn(buf, IPV4_CHARS); - if(l < IPV4_MIN) - break; - - /* Either end of string or port */ - if(buf[l] != 0 && buf[l] != ':') - break; - - /* Get the port out */ - if(buf[l] != 0) - { - t = buf + l + 1; - buf[l] = 0; - } - - if(t) - { - port = strtol(t, &t2, 10); - if(*t2 || port <= 0 || port >= 65536) - break; - } - - any->s.in.sin_family = AF_INET; - any->s.in.sin_port = htons((unsigned short)(port <= 0 ? defport : port)); - - if(inet_pton(AF_INET, buf, &(any->s.in.sin_addr)) <= 0) - break; - - any->namelen = sizeof(any->s.in); - return AF_INET; - } - while(0); - -#ifdef HAVE_INET6 - do - { - #define IPV6_CHARS "0123456789:" - #define IPV6_MIN 3 - #define IPV6_MAX 48 - - int port = -1; - t = NULL; - - l = strlen(addr); - if(l < IPV6_MIN || l > IPV6_MAX) - break; - - /* If it starts with a '[' then we can get port */ - if(buf[0] == '[') - { - port = 0; - addr++; - } - - strcpy(buf, addr); - - /* Find the last set that contains just numbers */ - l = strspn(buf, IPV6_CHARS); - if(l < IPV6_MIN) - break; - - /* Either end of string or port */ - if(buf[l] != 0) - { - /* If had bracket, then needs to end with a bracket */ - if(port != 0 || buf[l] != ']') - break; - - /* Get the port out */ - t = buf + l + 1; - - if(*t = ':') - t++; - } - - if(t) - { - port = strtol(t, &t, 10); - if(*t || port <= 0 || port >= 65536) - break; - } - - any->s.in6.sin6_family = AF_INET6; - any->s.in6.sin6_port = htons((unsigned short)port <= 0 : defport : port); - - if(inet_pton(AF_INET6, buf, &(any->s.in6.sin6_addr)) >= 0) - break; - - any->namelen = sizeof(any->s.in6); - return AF_INET6; - } - while(0); -#endif - - /* A unix socket path */ - do - { - /* No colon and must have a path component */ - if(strchr(addr, ':') || !strchr(addr, '/')) - break; - - l = strlen(addr); - if(l >= sizeof(any->s.un.sun_path)) - break; - - any->s.un.sun_family = AF_UNIX; - strcpy(any->s.un.sun_path, addr); - - any->namelen = sizeof(any->s.un) - (sizeof(any->s.un.sun_path) - l); - return AF_UNIX; - } - while(0); - - /* A DNS name and a port? */ - do - { - struct addrinfo* res; - int port = 0; - t = NULL; - - l = strlen(addr); - if(l >= 255 || !isalpha(addr[0])) - break; - - /* Some basic illegal character checks */ - if(strcspn(addr, " /\\") != l) - break; - - strcpy(buf, addr); - - /* Find the last set that contains just numbers */ - t = strchr(buf, ':'); - if(t) - { - *t = 0; - t++; - } - - if(t) - { - port = strtol(t, &t2, 10); - if(*t2 || port <= 0 || port >= 65536) - break; - } - - /* Try and resolve the domain name */ - if(getaddrinfo(buf, NULL, NULL, &res) != 0 || !res) - break; - - memcpy(&(any->s.a), res->ai_addr, sizeof(struct sockaddr)); - any->namelen = res->ai_addrlen; - freeaddrinfo(res); - - port = htons((unsigned short)(port <= 0 ? defport : port)); - - switch(any->s.a.sa_family) - { - case PF_INET: - any->s.in.sin_port = port; - break; -#ifdef HAVE_INET6 - case PF_INET6: - any->s.in6.sin6_port = port; - break; -#endif - }; - - return any->s.a.sa_family; - } - while(0); - - return -1; -} - -int sock_any_ntop(struct sockaddr_any* any, char* addr, size_t addrlen, int opts) -{ - int len = 0; - int port = 0; - - switch(any->s.a.sa_family) - { - case AF_UNIX: - len = strlen(any->s.un.sun_path); - if(addrlen < len + 1) - { - errno = ENOSPC; - return -1; - } - - strcpy(addr, any->s.un.sun_path); - break; - - case AF_INET: - if(inet_ntop(any->s.a.sa_family, &(any->s.in.sin_addr), addr, addrlen) == NULL) - return -1; - port = ntohs(any->s.in.sin_port); - break; - -#ifdef HAVE_INET6 - case AF_INET6: - if(inet_ntop(any->s.a.sa_family, &(any->s.in6.sin6_addr), addr, addrlen) == NULL) - return -1; - port = ntohs(any->s.in6.sin6_port); - break; -#endif - - default: - errno = EAFNOSUPPORT; - return -1; - } - - if(!(opts & SANY_OPT_NOPORT) && port != 0) - { - strncat(addr, ":", addrlen); - addr[addrlen - 1] = 0; - - len = strlen(addr); - addr += len; - addrlen -= len; - - snprintf(addr, addrlen, "%d", port); - } - - return 0; -} diff --git a/common/sock_any.h b/common/sock_any.h deleted file mode 100644 index 27c17cf..0000000 --- a/common/sock_any.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2004, Stefan Walter - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * - * CONTRIBUTORS - * Stef Walter - * - */ - -#ifndef __SOCK_ANY_H__ -#define __SOCK_ANY_H__ - -#include -#include -#include - -struct sockaddr_any -{ - union _sockaddr_any - { - /* The header */ - struct sockaddr a; - - /* The different types */ - struct sockaddr_un un; - struct sockaddr_in in; -#ifdef HAVE_INET6 - struct sockaddr_in6 in6; -#endif - } s; - size_t namelen; -}; - -#define SANY_ADDR(any) ((any).s.a) -#define SANY_LEN(any) ((any).namelen) -#define SANY_TYPE(any) ((any).s.a.sa_family) - -int sock_any_pton(const char* addr, struct sockaddr_any* any, int opts); - -/* The default port to fill in when no IP/IPv6 port specified */ -#define SANY_OPT_DEFPORT(p) (int)((p) & 0xFFFF) - -/* When only port specified default to IPANY */ -#define SANY_OPT_DEFANY 0x00000000 - -/* When only port specified default to LOCALHOST */ -#define SANY_OPT_DEFLOCAL 0x00100000 - -/* When only port specified default to IPv6 */ -#ifdef HAVE_INET6 -#define SANY_OPT_DEFINET6 0x00200000 -#endif - -int sock_any_ntop(struct sockaddr_any* any, char* addr, size_t addrlen, int opts); - -/* Don't print the port */ -#define SANY_OPT_NOPORT 0x01000000 - -#endif /* __SOCK_ANY_H__ */ diff --git a/common/stringx.c b/common/stringx.c index 24cf9d1..b48dee9 100644 --- a/common/stringx.c +++ b/common/stringx.c @@ -44,6 +44,7 @@ #include #include +#undef WHITESPACE #define WHITESPACE " \t\r\n\v" const char* trim_start(const char* data) diff --git a/daemon/Makefile.am b/daemon/Makefile.am index c2fee2a..2e7be2f 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -31,7 +31,7 @@ httpauthd_SOURCES = httpauthd.c httpauthd.h usuals.h bd.h bd.c misc.c basic.h ba digest.h digest.c defaults.h simple.c dummy.c \ ../common/compat.h ../common/compat.c ../common/buffer.h ../common/buffer.c \ ../common/hash.h ../common/hash.c ../common/md5.h ../common/md5.c \ - ../common/sha1.h ../common/sha1.c ../common/sock_any.c ../common/sock_any.h \ + ../common/sha1.h ../common/sha1.c ../common/sock-any.c ../common/sock-any.h \ ../common/stringx.c ../common/stringx.h $(EXTRA_SRC) httpauthd_CFLAGS = -D_THREAD_SAFE -pthread -DLinux \ diff --git a/daemon/httpauthd.c b/daemon/httpauthd.c index 09fb1d7..1adf8db 100644 --- a/daemon/httpauthd.c +++ b/daemon/httpauthd.c @@ -37,7 +37,7 @@ #include "usuals.h" #include "httpauthd.h" #include "defaults.h" -#include "sock_any.h" +#include "sock-any.h" #include "stringx.h" /* -- cgit v1.2.3