summaryrefslogtreecommitdiff
path: root/apache2x/mod_httpauth.c
diff options
context:
space:
mode:
Diffstat (limited to 'apache2x/mod_httpauth.c')
-rw-r--r--apache2x/mod_httpauth.c799
1 files changed, 799 insertions, 0 deletions
diff --git a/apache2x/mod_httpauth.c b/apache2x/mod_httpauth.c
new file mode 100644
index 0000000..c6d6e56
--- /dev/null
+++ b/apache2x/mod_httpauth.c
@@ -0,0 +1,799 @@
+/*
+ * Copyright (c) 2004, Nate Nielsen
+ * 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
+ * Nate Nielsen <nielsen@memberwebs.com>
+ *
+ */
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_config.h>
+#include <http_log.h>
+#include <http_protocol.h>
+#include <ap_config.h>
+#include <apr_strings.h>
+#include <apr_lib.h>
+
+#include "sock_any.h"
+#include "stringx.h"
+
+#define DEFAULT_PORT 8020
+
+module AP_MODULE_DECLARE_DATA httpauth_module;
+
+typedef struct httpauth_context
+{
+ const char* socketname;
+ int socket;
+ int types;
+ const char* handler;
+ const char* domain;
+ apr_pool_t* child_pool;
+}
+httpauth_context_t;
+
+/* TODO: Support proxy authentication properly */
+
+#define AUTH_PREFIX_BASIC "Basic"
+#define AUTH_PREFIX_DIGEST "Digest"
+
+#define AUTH_TYPE_BASIC 1 << 1
+#define AUTH_TYPE_DIGEST 1 << 2
+#define AUTH_TYPE_ANY 0x0000FFFF
+
+#define HTTPAUTH_AUTHTYPE "HTTPAUTH"
+
+/* -------------------------------------------------------------------------------
+ * Configuration code
+ */
+
+static void* httpauth_dir_config(apr_pool_t* p, char* dir)
+{
+ httpauth_context_t* ctx;
+
+ ctx = (httpauth_context_t*)apr_pcalloc(p, sizeof(*ctx));
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->socket = -1;
+ ctx->types = 0xFFFFFFFF;
+ ctx->child_pool = p;
+ return ctx;
+}
+
+static const char* set_socket(cmd_parms* cmd, void* config, const char* val)
+{
+ struct sockaddr_any sany;
+
+ if(sock_any_pton(val, &sany, DEFAULT_PORT) == -1)
+ return "Invalid socket name or ip in HttpAuthSocket";
+
+ ((httpauth_context_t*)config)->socketname = val;
+ return NULL;
+}
+
+static const char* set_handler(cmd_parms* cmd, void* config, const char* val)
+{
+ httpauth_context_t* conf = (httpauth_context_t*)config;
+ conf->handler = val;
+ return NULL;
+}
+
+static const char* set_types(cmd_parms* cmd, void* config, const char* val)
+{
+ httpauth_context_t* conf = (httpauth_context_t*)config;
+ int type = 0;
+
+ if(strcasecmp(val, AUTH_PREFIX_BASIC) == 0)
+ type = AUTH_TYPE_BASIC;
+ else if(strcasecmp(val, AUTH_PREFIX_DIGEST) == 0)
+ type = AUTH_TYPE_DIGEST;
+ else if(strcasecmp(val, "any"))
+ type = AUTH_TYPE_ANY;
+ else
+ return "Invalid type in HttpAuthTypes";
+
+ if(conf->types == 0xFFFFFFFF)
+ conf->types = type;
+ else
+ conf->types |= type;
+
+ return NULL;
+}
+
+static const char* set_domain(cmd_parms* cmd, void* config, const char* val)
+{
+ httpauth_context_t* conf = (httpauth_context_t*)config;
+ conf->domain = trim_space(apr_pstrdup(cmd->pool, val));
+ return NULL;
+}
+
+static const command_rec httpauth_cmds[] =
+{
+ AP_INIT_TAKE1( "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" ),
+ AP_INIT_ITERATE( "HttpAuthTypes", set_types, NULL, OR_AUTHCFG,
+ "The types of authentiction allowed (Basic, Digest, ...)" ),
+ AP_INIT_RAW_ARGS( "HttpAuthDigestDomain", set_domain, NULL, OR_AUTHCFG,
+ "The domain for which digest authentication is relevant" ),
+ { NULL }
+};
+
+/* -------------------------------------------------------------------------------
+ * Socket handling code
+ */
+
+void read_junk(httpauth_context_t* ctx, request_rec* r)
+{
+ char buf[16];
+ const char* t;
+ int said = 0;
+ int l;
+
+ if(ctx->socket == -1)
+ return;
+
+ /* Make it non blocking */
+ fcntl(ctx->socket, F_SETFL, fcntl(ctx->socket, F_GETFL, 0) | O_NONBLOCK);
+
+ for(;;)
+ {
+ l = read(ctx->socket, buf, sizeof(buf) - 1);
+ if(l <= 0)
+ break;
+
+ buf[l] = 0;
+ t = trim_start(buf);
+
+ if(!said && *t)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ "httpauth: received junk data from daemon");
+ said = 1;
+ }
+ }
+
+ fcntl(ctx->socket, F_SETFL, fcntl(ctx->socket, F_GETFL, 0) & ~O_NONBLOCK);
+}
+
+int read_line(httpauth_context_t* ctx, request_rec* r, char** line)
+{
+ int l;
+ int al = 128;
+ char* t;
+ const char* e;
+
+ e = t = NULL;
+ *line = NULL;
+
+ for(;;)
+ {
+ if(!*line || t + 2 == e)
+ {
+ char* n;
+ int d;
+
+ n = (char*)apr_palloc(r->pool, al * 2);
+
+ if(*line)
+ memcpy(n, *line, al);
+
+ al *= 2;
+
+ /* The difference */
+ d = t - *line;
+
+ *line = n;
+ t = n + d;
+ e = n + al;
+ }
+
+ l = read(ctx->socket, (void*)t, sizeof(char));
+
+ /* We got a character */
+ if(l == 1)
+ {
+ /* Skip junky CRLFs */
+ if(*t == '\r')
+ {
+ *t = ' ';
+ continue;
+ }
+
+ /* End of line */
+ else if(*t == '\n')
+ {
+ t++;
+ break;
+ }
+
+ t++;
+ }
+
+ /* If it's the end of file then return that */
+ else if(l == 0)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: unexpected end of data from daemon");
+ return -1;
+ }
+
+ /* Transient errors */
+ else if(l == -1 && errno == EAGAIN)
+ continue;
+
+ /* Fatal errors */
+ else if(l == -1)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), r,
+ "httpauth: couldn't read data from daemon");
+ return -1;
+ }
+ }
+
+ *t = 0;
+ return 0;
+}
+
+int read_response(httpauth_context_t* ctx, request_rec* r,
+ int* code, int* ccode, char** details)
+{
+ int c;
+ 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);
+ return -1;
+ }
+
+ if(code)
+ *code = c;
+
+ if(c >= 400)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: received error from httpauthd: %d %s", c, line);
+ return -1;
+ }
+
+ /* 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(ccode)
+ *ccode = c;
+ }
+
+ if(details)
+ *details = trim_space(line);
+
+ return 0;
+}
+
+int read_copy_headers(httpauth_context_t* ctx, int ccode, request_rec* r)
+{
+ char* line;
+ const char* name;
+ apr_table_t* headers;
+ int c = 0;
+
+ if(ccode > 299)
+ headers = r->err_headers_out;
+ else
+ headers = r->headers_out;
+
+ for(;;)
+ {
+ if(read_line(ctx, r, &line) == -1)
+ return -1;
+
+ /* If that's it then break */
+ if(!*line)
+ break;
+
+ if(apr_isspace(*line))
+ {
+ line = (char*)trim_start(line);
+
+ /* End of headers */
+ if(!*line)
+ break;
+
+ if(c > 0)
+ {
+ /*
+ * TODO: We really should be supporting headers split
+ * across lines. But httpauthd doesn't currently produce
+ * headers like that, so we don't need to care about it.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ "httpauth: protocol error: server sent us an split header, which we don't support.");
+ }
+ else
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: protocol error: invalid headers.");
+ }
+ }
+
+ name = ap_getword_nc(r->pool, &line, ':');
+ if(!name || !*name)
+ break;
+
+ /*
+ * If that was the end of the line, then it's an
+ * invalid header :(
+ */
+ if(!*line)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: protocol header: invalid headers");
+ return -1;
+ }
+
+ line = trim_space(line);
+
+ if(strcasecmp(name, "WWW-Authenticate") == 0)
+ {
+ if(strncasecmp(line, AUTH_PREFIX_BASIC, strlen(AUTH_PREFIX_BASIC)) == 0 &&
+ !(ctx->types & AUTH_TYPE_BASIC))
+ continue;
+
+ else if(strncasecmp(line, AUTH_PREFIX_DIGEST, strlen(AUTH_PREFIX_DIGEST)) == 0 &&
+ !(ctx->types & AUTH_TYPE_DIGEST))
+ continue;
+
+ /* Only allow unknown if we don't have it */
+ else if(!(ctx->types & AUTH_TYPE_ANY))
+ continue;
+
+ /* Fix up when we're a proxy */
+ if(r->proxyreq == PROXYREQ_PROXY)
+ name = "Proxy-Authenticate";
+ }
+
+ else if(strcasecmp(name, "Authentication-Info") == 0)
+ {
+ if(r->proxyreq == PROXYREQ_PROXY)
+ name = "Proxy-Authentication-Info";
+ }
+
+ c++;
+ apr_table_addn(headers, name, line);
+ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "httpauth: received %d headers from daemon", c);
+
+ return 0;
+}
+
+
+static apr_status_t cleanup_socket(void *fdv)
+{
+ close((int)(long)fdv);
+ return OK;
+}
+
+void disconnect_socket(httpauth_context_t* ctx, server_rec* s)
+{
+ if(ctx->socket != -1)
+ {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+ "httpauth: disconnecting from daemon");
+
+ apr_pool_cleanup_kill(ctx->child_pool, (void*)(long)ctx->socket,
+ cleanup_socket);
+ close(ctx->socket);
+ ctx->socket = -1;
+ }
+}
+
+int write_data(httpauth_context_t* ctx, server_rec* s, const char* data)
+{
+ int r;
+
+ if(ctx->socket == -1)
+ {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+ "httpauth: Socket to httpauthd daemon closed. Can't write data.");
+ return -1;
+ }
+
+ while(*data != 0)
+ {
+ r = write(ctx->socket, data, strlen(data));
+
+ if(r > 0)
+ data += r;
+
+ else if(r == -1)
+ {
+ if(errno == EAGAIN)
+ continue;
+
+ /* The other end closed. no message */
+ if(errno == EPIPE)
+ disconnect_socket(ctx, s);
+
+ else
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), s,
+ "httpauth: Couldn't write data to daemon");
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int connect_socket(httpauth_context_t* ctx, request_rec* r)
+{
+ struct sockaddr_any sany;
+ apr_status_t st;
+ int ret = -1;
+
+ disconnect_socket(ctx, r->server);
+
+ 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: %s", ctx->socketname);
+ goto finally;
+ }
+
+ apr_pool_cleanup_register(ctx->child_pool, (void*)(long)ctx->socket,
+ cleanup_socket, cleanup_socket);
+
+ 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;
+ }
+
+ ret = 0;
+
+finally:
+ if(ret == -1)
+ disconnect_socket(ctx, r->server);
+
+ errno = 0;
+ return ret;
+}
+
+int connect_httpauth(httpauth_context_t* ctx, request_rec* r)
+{
+ int ret = -1;
+ int code;
+ char* details;
+ const char* t;
+
+ if(connect_socket(ctx, r) == -1)
+ goto finally;
+
+ if(read_response(ctx, r, &code, NULL, &details) == -1)
+ goto finally;
+
+ if(code != 100)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: protocol error (Expected 100, got %d)", code);
+ goto finally;
+ }
+
+ /* Check theversion number */
+ details = trim_space(details);
+
+ if(strcmp(details, "HTTPAUTH/1.0") != 0)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: Daemon speaking incompatible protocol version: %s", details);
+ goto finally;
+ }
+
+ /* Send our handler */
+ if(ctx->handler)
+ {
+ t = apr_pstrcat(r->pool, "SET Handler ", ctx->handler, "\n", NULL);
+
+ if(write_data(ctx, r->server, t) == -1)
+ goto finally;
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "httpauth: sent handler to daemon: %s", t);
+
+ if(read_response(ctx, r, &code, NULL, NULL) == -1)
+ goto finally;
+
+ if(code != 202)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: protocol error (Expected 202, got %d)", code);
+ goto finally;
+ }
+ }
+
+ /* Send any setup info we have */
+ if(ctx->domain)
+ {
+ t = apr_pstrcat(r->pool, "SET Domain ", ctx->domain, "\n", NULL);
+
+ if(write_data(ctx, r->server, t) == -1)
+ goto finally;
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "httpauth: sent domains to daemon: %s", t);
+
+ if(read_response(ctx, r, &code, NULL, NULL) == -1)
+ goto finally;
+
+ if(code != 202)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: protocol error (Expected 202, got %d)", code);
+ goto finally;
+ }
+ }
+
+ /* We're cool! */
+ ret = 0;
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "httpauth: connected to daemon");
+
+finally:
+ if(ret == -1)
+ disconnect_socket(ctx, r->server);
+
+ return ret;
+}
+
+int write_request(httpauth_context_t* ctx, request_rec* r)
+{
+ int i, c = 0;
+ const char* t;
+ const apr_array_header_t* hdrs_arr;
+ const apr_table_entry_t* elts;
+
+ /* Send the request header to httpauthd */
+ t = apr_pstrcat(r->pool, "AUTH XXX ", r->method,
+ " ", r->unparsed_uri, "\n", NULL);
+
+ if(write_data(ctx, r->server, t) == -1)
+ return -1;
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "httpauth: sent auth request to daemon: %s", t);
+
+ /* Now send the headers to httpauthd */
+
+ hdrs_arr = apr_table_elts(r->headers_in);
+ elts = (const apr_table_entry_t*)hdrs_arr->elts;
+
+ for(i = 0; i < hdrs_arr->nelts; i++)
+ {
+ if(!elts[i].val)
+ continue;
+
+ /* Filter out headers we don't want */
+ if(strcasecmp(elts[i].key, r->proxyreq == PROXYREQ_PROXY ?
+ "Proxy-Authorization" : "Authorization") == 0)
+ {
+ t = trim_start(elts[i].val);
+
+ if(strncasecmp(t, AUTH_PREFIX_BASIC, strlen(AUTH_PREFIX_BASIC)) == 0 &&
+ !(ctx->types & AUTH_TYPE_BASIC))
+ continue;
+
+ else if(strncasecmp(t, AUTH_PREFIX_DIGEST, strlen(AUTH_PREFIX_DIGEST)) == 0 &&
+ !(ctx->types & AUTH_TYPE_DIGEST))
+ continue;
+
+ /* Only allow unknown if we don't have it */
+ else if(!(ctx->types & AUTH_TYPE_ANY))
+ continue;
+
+ /* Extra blank line when at end */
+ t = apr_pstrcat(r->pool, "Authorization: ", elts[i].val, "\n", NULL);
+
+ if(write_data(ctx, r->server, t) == -1)
+ return HTTP_INTERNAL_SERVER_ERROR;
+
+ c++;
+ }
+ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "httpauth: sent %d headers to daemon", c);
+
+ return write_data(ctx, r->server, "\n");
+}
+
+static int httpauth_authenticate(request_rec* r)
+{
+ httpauth_context_t* ctx;
+ const char* authtype;
+ int code = 0;
+ int ccode = 0;
+ char* details = NULL;
+ request_rec* mainreq;
+ int retried = 0;
+
+ /* Make sure it's for us */
+ if(!(authtype = ap_auth_type(r)) || strcasecmp(HTTPAUTH_AUTHTYPE, authtype) != 0)
+ return DECLINED;
+
+ ctx = (httpauth_context_t*)ap_get_module_config(r->per_dir_config,
+ &httpauth_module);
+
+ if(!ctx->socketname || !ctx->handler)
+ return DECLINED;
+
+ mainreq = r;
+
+ while(mainreq->main != NULL)
+ mainreq = mainreq->main;
+
+ while(mainreq->prev != NULL)
+ mainreq = mainreq->prev;
+
+ /* Check if we've already authenticated this request */
+ if(ap_get_module_config(mainreq->request_config, &httpauth_module))
+ return OK;
+
+/* 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;
+ }
+
+ /* Make sure we're starting on a clean slate */
+ read_junk(ctx, r);
+
+ /* Send off a request */
+ if(write_request(ctx, r) == -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)
+ {
+ retried = 1;
+ goto retry;
+ }
+
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* Read a response line */
+ if(read_response(ctx, r, &code, &ccode, &details) == -1)
+ return HTTP_INTERNAL_SERVER_ERROR;
+
+ if(code != 200)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: protocol error: unexpected code: %d", code);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* Copy over other headers */
+ if(read_copy_headers(ctx, ccode, r) == -1)
+ return HTTP_INTERNAL_SERVER_ERROR;
+
+ if(ccode == 200)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "httpauth: successful authentication for user: %s", details);
+
+ r->user = apr_pstrdup(r->pool, details);
+ r->ap_auth_type = HTTPAUTH_AUTHTYPE;
+
+ /* Mark request as successfully authenticated */
+ ap_set_module_config(r->request_config, &httpauth_module, details);
+ return OK;
+ }
+
+ return ccode;
+}
+
+static int httpauth_access(request_rec *r)
+{
+ /* TODO: We need to support require directives */
+ return OK;
+}
+
+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);
+}
+
+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, /* merge server config */
+ httpauth_cmds, /* command table */
+ register_hooks /* register hooks */
+};
+
+/*
+ * Apache modules seem to want to be all in one
+ * object file, at least when statically compiled.
+ * so we include this here
+ */
+#include "../common/sock_any.c"
+#include "../common/stringx.c"