summaryrefslogtreecommitdiff
path: root/module/mod_auth_singleid.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/mod_auth_singleid.c')
-rw-r--r--module/mod_auth_singleid.c1621
1 files changed, 1621 insertions, 0 deletions
diff --git a/module/mod_auth_singleid.c b/module/mod_auth_singleid.c
new file mode 100644
index 0000000..5d8ddb4
--- /dev/null
+++ b/module/mod_auth_singleid.c
@@ -0,0 +1,1621 @@
+/*
+ * Copyright (c) 2009, 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 <stef@memberwebs.com>
+ *
+ */
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_config.h>
+#include <http_log.h>
+#if 0
+#include <http_protocol.h>
+#include <http_request.h>
+#include <ap_config.h>
+#include <apr_strings.h>
+#include <apr_file_io.h>
+#include <apr_lib.h>
+#endif
+
+#include "consumer.h"
+#include "storage.h"
+
+/* Apache defines these */
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "config.h"
+#include <unistd.h>
+
+extern "C" module AP_MODULE_DECLARE_DATA auth_singleid_module;
+
+#if 0
+
+/* Keep track of a unique identifier */
+static void* conn_current = NULL;
+
+/* And increment this when it goes out of scope */
+static unsigned int conn_seen = 0;
+
+/*
+ * 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;
+
+/* TODO: Support proxy authentication properly */
+
+#define AUTH_PREFIX_BASIC "Basic"
+#define AUTH_PREFIX_DIGEST "Digest"
+#define AUTH_PREFIX_NTLM "NTLM"
+
+#define AUTH_TYPE_BASIC 1 << 1
+#define AUTH_TYPE_DIGEST 1 << 2
+#define AUTH_TYPE_NTLM 1 << 3
+#define AUTH_TYPE_ANY 0x0000FFFF
+
+#endif
+
+#define SINGLEID_AUTHTYPE "SINGLEID"
+
+/* -------------------------------------------------------------------------------
+ * SHARED MEMORY
+ */
+
+static apr_global_mutex_t *shared_lock = NULL;
+static const char *shared_lock_name = NULL;
+
+static int
+shared_initialize (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
+{
+ 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,
+ "auth-singleid: couldn't get temporary directory");
+
+ if (rc == APR_SUCCESS) {
+ lock_name = apr_pstrcat (p, tmpdir, "/", "mod-auth-singleid.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,
+ "auth-singleid: couldn't create temporary file: %s", lock_name);
+ }
+
+ if (file != NULL)
+ apr_file_close (file);
+
+ 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,
+ "auth-singleid: couldn't create shared memory lock: %s", lock_name);
+ }
+
+#ifdef AP_NEED_SET_MUTEX_PERMS
+ if (rc == APR_SUCCESS) {
+ rc = unixd_set_global_mutex_perms (shared_lock);
+ if (rc != APR_SUCCESS)
+ ap_log_error (APLOG_MARK, APLOG_ERR, rc, s,
+ "auth-singleid: Could not set permissions on lock. "
+ "check User and Group directives");
+ }
+#endif
+
+ if (rc == APR_SUCCESS)
+ shared_lock_name = lock_name;
+
+ return OK;
+}
+
+static void
+shared_child (apr_pool_t *p, server_rec *s)
+{
+ apr_status_t rc;
+
+ if (!shared_lock || !shared_lock_name)
+ 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: %s", shared_lock_name);
+ shared_lock = NULL;
+ }
+}
+
+static void*
+shared_create (apr_pool_t* p, size_t size)
+{
+ const char *tmpdir;
+ char *filename;
+ apr_file_t *file;
+ apr_mmap_t *map;
+ void *addr;
+ int rc;
+
+ /* Get the temp directory */
+ rc = apr_temp_dir_get (&tmpdir, p);
+ if (rc != APR_SUCCESS) {
+ ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL,
+ "auth-singleid: couldn't get temporary directory");
+ }
+
+ /* Create the shared file */
+ if (rc == APR_SUCCESS) {
+ filename = apr_pstrcat (p, tmpdir, "/", "mod-auth-singleid.shared.XXXXXX", NULL);
+ rc = apr_file_mktemp (&file, filename, 0, p);
+ if (rc != APR_SUCCESS)
+ ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL,
+ "auth-singleid: couldn't create temporary file: %s", filename);
+ }
+
+ /* Write a shared block to file */
+ if (rc == APR_SUCCESS) {
+ memset (&shared, 0, sizeof (shared));
+ xxxxxx
+ rc = apr_file_write_full (file, &xxxx, size, NULL);
+ if (rc != APR_SUCCESS)
+ ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL,
+ "auth-singleid: 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, size, APR_MMAP_READ | APR_MMAP_WRITE, p);
+ if (rc != APR_SUCCESS)
+ ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL,
+ "auth-singleid: 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,
+ "auth-singleid: couldn't get shared memory");
+ }
+
+ if (rc == APR_SUCCESS)
+ return addr;
+
+ return NULL;
+}
+
+/* -------------------------------------------------------------------------------------------------
+ * COMMON STORAGE
+ */
+
+typedef struct storage_context {
+ void* shared;
+ size_t size;
+} storage_context_t;
+
+/* -------------------------------------------------------------------------------------------------
+ * OPENID CONSUMER
+ */
+
+#if 0
+static void* storage_shared = NULL;
+static size_t storage_size = NULL;
+#endif
+
+#if 0
+
+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 || !shared_lock)
+ return 0;
+
+ apr_global_mutex_lock (shared_lock);
+
+ 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 || !shared_lock)
+ 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);
+}
+#endif
+
+/* -------------------------------------------------------------------------------
+ * Per Directory Config and Context Code
+ */
+
+static void*
+dir_config_creator (apr_pool_t* p, char* dir)
+{
+#if 0
+ 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;
+#endif
+ return NULL;
+}
+
+#if 0
+static const char* set_socket(cmd_parms* cmd, void* config, const char* val)
+{
+ struct sockaddr_any sany;
+
+ 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;
+}
+
+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, AUTH_PREFIX_NTLM) == 0)
+ type = AUTH_TYPE_NTLM;
+ 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;
+}
+#endif
+
+static const command_rec command_table[] =
+{
+#if 0
+ 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" ),
+ AP_INIT_ITERATE( "HttpAuthTypes", set_types, NULL, OR_AUTHCFG,
+ "The types of authentiction allowed (Basic, Digest, NTLM ...)" ),
+ AP_INIT_RAW_ARGS( "HttpAuthDigestDomain", set_domain, NULL, OR_AUTHCFG,
+ "The domain for which digest authentication is relevant" ),
+#endif
+ { NULL }
+};
+
+#if 0
+
+/* -------------------------------------------------------------------------------
+ * Socket handling code
+ */
+
+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;
+
+ /* Make sure we send our list of groups to daemon again */
+ if (ctx->needed_groups)
+ ctx->needed_groups[0] = 0;
+ }
+}
+
+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 = 256;
+ 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)
+ {
+ /* Disconnect from socket quietly so we can reconnect later */
+ disconnect_socket(ctx, r->server);
+ 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 return_errors)
+{
+ 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;
+ }
+
+ if (code)
+ *code = c;
+
+ 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;
+ }
+
+ /* 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 (ccode)
+ *ccode = c;
+ }
+
+ if (details)
+ *details = trim_space (line);
+
+ ret = 0;
+
+finally:
+ if (ret < 0 && ctx->socket >= 0) {
+ disconnect_socket (ctx, r->server);
+ ++ctx->address_seed;
+ }
+
+ return ret;
+}
+
+static int
+read_process_headers(httpauth_context_t* ctx, int ccode,
+ request_rec* r, char **groups)
+{
+ 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";
+ }
+
+ else if (strcasecmp(name, "X-HttpAuth-Groups") == 0)
+ {
+ if (groups && line)
+ *groups = line;
+ }
+
+ 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;
+}
+
+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;
+}
+
+static int
+try_connect_socket (httpauth_context_t *ctx, struct sockaddr_any *sany,
+ request_rec *r)
+{
+ char peername[256];
+ int rc;
+
+ if (sock_any_ntop (sany, peername, sizeof (peername), 0) < 0)
+ strcpy (peername, "[unknown]");
+
+ 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;
+ }
+
+ 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;
+ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "httpauth: connected to daemon: %s", peername);
+
+ return 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);
+ }
+
+ /* 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;
+
+ 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)
+{
+ 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, 0) == -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, 0) == -1)
+ goto finally;
+
+ if(code != 202)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: protocol error: couldn't send handler to daemon (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, 0) == -1)
+ goto finally;
+
+ if(code != 202)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: protocol error: couldn't send domain to daemon (Expected 202, got %d)", code);
+ goto finally;
+ }
+ }
+
+ /* We're cool! */
+ ret = 0;
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "httpauth: handshake with daemon completed");
+
+finally:
+ if(ret == -1 && ctx->socket >= 0) {
+ disconnect_socket(ctx, r->server);
+ ++ctx->address_seed;
+ }
+
+ return ret;
+}
+
+/* Make sure our connection identifier is unique */
+static apr_status_t connection_gone (void *data)
+{
+ conn_current = NULL;
+ conn_seen++;
+ return APR_SUCCESS;
+}
+
+int write_request(httpauth_context_t* ctx, request_rec* r)
+{
+ char pidid[40];
+ char connid[40];
+ int i, c = 0;
+ const char* t;
+ const apr_array_header_t* hdrs_arr;
+ const apr_table_entry_t* elts;
+
+ /* When the connection goes away, call our handler */
+ if(conn_current != r->connection)
+ {
+ conn_current = r->connection;
+ apr_pool_cleanup_register(r->connection->pool, r,
+ connection_gone, apr_pool_cleanup_null);
+ }
+
+ /* A unique per connection id */
+ snprintf(connid, sizeof(connid), "0x%X-%X-%X",
+ (unsigned int)r->connection, conn_seen, (unsigned int)r->connection->id);
+ connid[sizeof(connid) - 1] = 0;
+ snprintf(pidid, sizeof(pidid), "%d", (unsigned int)getpid());
+ pidid[sizeof(pidid) - 1] = 0;
+ t = apr_pstrcat(r->pool, pidid, ":", connid, NULL);
+
+ /* Send the request header to httpauthd */
+ t = apr_pstrcat(r->pool, "AUTH ", t, " ", 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;
+
+ else if(strncasecmp(t, AUTH_PREFIX_NTLM, strlen(AUTH_PREFIX_NTLM)) == 0 &&
+ !(ctx->types & AUTH_TYPE_NTLM))
+ 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
+write_needed_groups(httpauth_context_t *ctx, request_rec *r)
+{
+ const apr_array_header_t *reqs_arr = ap_requires(r);
+ require_line *reqs;
+ const char *groups = NULL;
+ const char *text;
+ char *word;
+ register int x;
+ int m = r->method_number;
+ int code, len;
+
+ if(reqs_arr) {
+ reqs = (require_line*)reqs_arr->elts;
+ for (x = 0; x < reqs_arr->nelts; x++) {
+ if (!(reqs[x].method_mask & (AP_METHOD_BIT << m)))
+ continue;
+
+ text = reqs[x].requirement;
+ word = ap_getword_white (r->pool, &text);
+
+ /* Append all groups to the string */
+ if (strcmp (word, "group") == 0 && text && text[0]) {
+ if (!groups)
+ groups = text;
+ else
+ groups = apr_pstrcat (r->pool, text, " ", groups, NULL);
+ }
+ }
+ }
+
+ /* No groups, no need to send */
+ if (!groups && !ctx->needed_groups)
+ return 0;
+
+ if (!groups)
+ groups = "";
+
+ /* Equal groups, no need to send */
+ if (ctx->needed_groups && strcmp (groups, ctx->needed_groups) == 0)
+ return 0;
+
+ /* Groups changed, send to daemon */
+ text = apr_pstrcat (r->pool, "SET Groups ", groups, "\n", NULL);
+
+ if (write_data (ctx, r->server, text) < 0)
+ return -1;
+
+ ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r,
+ "httpauth: sent groups to daemon: %s", text);
+
+ if (read_response (ctx, r, &code, NULL, NULL, 1) < 0)
+ return -1;
+
+ if (code != 202) {
+ ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: couldn't send groups to daemon (Expected 202, got %d)", code);
+ /* Older versions of the daemon did not support the 'SET Groups' command */
+ if (code != 400)
+ return -1;
+ }
+
+ /* Save away the groups for next time */
+ len = strlen (groups);
+ if (len >= ctx->alloced_groups) {
+ if (len < 512)
+ len = 512;
+ ctx->needed_groups = (char*)apr_pcalloc (ctx->child_pool, len * 2);
+ ctx->alloced_groups = len * 2;
+ }
+ strcpy (ctx->needed_groups, groups);
+ return 0;
+}
+
+static httpauth_request_t*
+setup_request_hreq (request_rec *r, char *user, char *groups)
+{
+ httpauth_request_t* hreq;
+
+ hreq = (httpauth_request_t*)apr_pcalloc (r->pool, sizeof (*hreq));
+ hreq->user = r->user;
+ hreq->groups = groups;
+
+ if (groups)
+ apr_table_setn (r->subprocess_env, "HTTPAUTH_GROUPS", groups);
+ else
+ apr_table_unset (r->subprocess_env, "HTTPAUTH_GROUPS");
+
+ ap_set_module_config (r->request_config, &httpauth_module, hreq);
+
+ return hreq;
+}
+
+#endif
+
+typedef struct session_info {
+ const char *identifier;
+ time_t expiry;
+} session_info_t;
+
+static const char*
+session_cookie_value (request_rec *r, const char *name)
+{
+ const char *cookies;
+ const char *value;
+ char *pair;
+
+ cookies = apr_table_get (r->headers_in, "Cookie");
+ if (cookies == NULL)
+ return NULL;
+
+ while (*cookies) {
+ pair = ap_get_token (r->pool, &cookies, 0);
+ if (!pair)
+ break;
+ if (pair[0] == '$')
+ continue;
+
+ value = ap_stripprefix (pair, name);
+ if (value == pair)
+ continue;
+ while (isspace (value))
+ ++value;
+
+ if (value != '=')
+ continue;
+ while (isspace (value))
+ ++value;
+
+ return value;
+ }
+
+ return NULL;
+}
+
+static char*
+session_create_sig (apr_pool_t *p, const char *value)
+{
+ unsigned char digest[APR_SHA1_DIGESTSIZE];
+ char *sig;
+
+ apr_sha1_ctx_t ctx;
+ apr_sha1_init (&ctx);
+ apr_sha1_update (&ctx, session_secret, strlen (session_secret));
+ apr_sha1_update (&ctx, "\0", 1);
+ apr_sha1_update (&ctx, value, strlen (value));
+ apr_sha1_final (digest, &ctx);
+
+ sig = apr_pcalloc (p, apr_base64_encode_len (digest));
+ apr_base64_encode (sig, digest, sizeof (digest));
+ return sig;
+}
+
+static int
+session_validate_sig (apr_pool_t *p, const char *sig, const char *value)
+{
+ char *valid = session_create_sig (p, value);
+ return strcmp (sig, valid) == 0;
+}
+
+static session_info_t*
+session_load_info (request_rec *r)
+{
+ session_info_t *sess;
+ const char *value;
+ char *token, *sig;
+ const char *t;
+ long expiry;
+
+ value = session_cookie_value (r, "mod-auth-single-id");
+ if (!value)
+ return NULL;
+
+ sig = ap_get_token (r->pool, &value, 1);
+
+ /* The version of the session info, only 1 supported for now */
+ version = ap_get_token (r->pool, &value, 1);
+ if (strcmp(version, "1") != 0)
+ return NULL;
+
+ if (!session_validate_sig (r->pool, sig, value))
+ return NULL;
+
+ token = ap_get_token (r->pool, &value, 1);
+ expiry = strtol (token, &t, 10);
+ if (*t != '\0')
+ return NULL;
+
+ /* Don't let expired sessions be valid */
+ if (expiry < time (NULL))
+ return NULL;
+
+ /* The identifier */
+ identifier = ap_get_token (r->pool, &value, 1);
+ if (!ap_is_url (identifier))
+ return NULL;
+
+ sess = apr_pcalloc (r->pool, sizeof (session_info_t));
+ sess->expiry = expiry;
+ sess->identifier = identifier;
+
+ return sess;
+}
+
+static void
+session_send_info (request_rec *r, session_info_t *sess)
+{
+ char *cookie, *sig, *value;
+
+ /* Create the cookie value and sign it */
+ value = apr_psprintf (r->pool, "1 %d \"%s\"", sess->expiry, ap_escape_quotes (sess->identifier));
+ sig = session_create_sig (r->pool, value);
+
+ /* Build up the full cookie spec */
+ cookie = apr_psprintf (r->pool, "mod-auth-single-id=%s %s; httponly; max-age=86400", sig, value);
+ apr_table_addn (r->headers_out, "Set-Cookie", cookie);
+}
+
+static session_info_t*
+session_copy_info (apr_pool_t *p, session_info_t *sess)
+{
+ session_info_t *copy = apr_pmalloc (p, sizeof (*sess));
+ copy->expiry = sess->expiry;
+ copy->identifier = apr_pstrdup (sess->identifier);
+ return copy;
+}
+
+static void
+set_request_authenticated (request_rec *r, session_info_t *sess)
+{
+ r->user = sess->identifier;
+ r->ap_auth_type = SINGLEID_AUTHTYPE;
+ ap_set_module_config (r->request_config, &auth_singleid_module, sess);
+}
+
+singleid_request_xxxx
+{
+
+}
+
+static int
+hook_authenticate (request_rec* r)
+{
+ session_info_t *sess;
+#if 0
+ httpauth_context_t* ctx;
+ httpauth_request_t* hreq;
+#endif
+ const char* authtype;
+#if 0
+ int code = 0;
+ int ccode = 0;
+ char *groups = NULL;
+ char* details = NULL;
+#endif
+ request_rec* mainreq;
+#if 0
+ int retried = 0;
+#endif
+
+ /* Make sure it's for us */
+ if (!(authtype = ap_auth_type (r)) || strcasecmp (SINGLEID_AUTHTYPE, authtype) != 0)
+ return DECLINED;
+
+#if 0
+ ctx = (httpauth_context_t*)ap_get_module_config(r->per_dir_config, &httpauth_module);
+
+ if(!ctx->socketname || !ctx->handler)
+ return DECLINED;
+#endif
+
+ mainreq = r;
+
+ while (mainreq->main != NULL)
+ mainreq = mainreq->main;
+
+ while (mainreq->prev != NULL)
+ mainreq = mainreq->prev;
+
+ /* Check if we've already authenticated this request */
+ sess = ap_get_module_config (mainreq->request_config, &auth_singleid_module);
+ if (sess != NULL) {
+ if (mainreq != r) {
+ sess = session_copy_info (r->pool, sess);
+ set_request_authenticated (r, sess);
+ }
+ return OK;
+ }
+
+ /* Load the session info from the request and see if we've authenticated */
+ sess = session_load_info (r);
+ if (sess != NULL) {
+ set_request_authenticated (r, sess);
+ return OK;
+ }
+
+ singleid_consumer (r)
+ Consumer consumer(uri, )
+ opkele::params_t params;
+ parse_query_string(r, params);
+
+ /* Is it an openid response? */
+ if ()
+
+ query = openid_parse_response (r);
+ if (query != NULL) {
+ (r, )
+
+
+ }
+
+ /* Otherwise start a new openid authentication */
+
+
+#if 0
+ /*
+ * 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) {
+
+ 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;
+ }
+
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ /* 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");
+
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if(code != 200)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: protocol error: unexpected code while authenticating: %d", code);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* Copy over other headers */
+ if(read_process_headers(ctx, ccode, r, &groups) == -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 */
+ hreq = setup_request_hreq (r, details, groups);
+ return OK;
+ }
+
+ return ccode;
+}
+
+#endif
+#if 0
+
+static const char*
+find_word_quoted (const char *all, const char *word)
+{
+ const char *at;
+ char before, after;
+ size_t len = strlen (word);
+
+ at = all;
+ for (;;) {
+ at = strstr (at, word);
+ if (!at)
+ return NULL;
+
+ before = (at == all) ? 0 : *(at - 1);
+ after = *(at + len);
+
+ /* Beginning and end of a space delimited word */
+ if ((!before || isspace (before)) &&
+ (!after || isspace (after))) {
+ return at;
+ }
+
+ /* Beginning and end of a quoted word */
+ if ((before == '"' || before == '\'') && after == before)
+ return at;
+
+ at += len;
+ }
+}
+
+static int
+httpauth_access(request_rec *r)
+{
+ httpauth_context_t *ctx;
+ httpauth_request_t *hreq;
+ const char* authtype;
+ char *user = r->user;
+ int m = r->method_number;
+ int method_restricted = 0;
+ register int x;
+ const char *text, *word;
+ const apr_array_header_t *reqs_arr = ap_requires (r);
+ require_line *reqs;
+
+ /* Make sure it's for us */
+ if (!(authtype = ap_auth_type (r)) || strcasecmp (HTTPAUTH_AUTHTYPE, authtype) != 0)
+ return DECLINED;
+
+ if (!reqs_arr)
+ return OK;
+
+ /* Dig out our configuration */
+ ctx = ap_get_module_config (r->per_dir_config, &httpauth_module);
+ hreq = ap_get_module_config (r->request_config, &httpauth_module);
+ reqs = (require_line *)reqs_arr->elts;
+
+ for (x = 0; x < reqs_arr->nelts; x++) {
+ if (!(reqs[x].method_mask & (AP_METHOD_BIT << m)))
+ continue;
+
+ method_restricted = 1;
+
+ text = reqs[x].requirement;
+ word = ap_getword_white(r->pool, &text);
+
+ /* Any valid user */
+ if (strcmp (word, "valid-user") == 0) {
+ return OK;
+
+ /* Specific listed users */
+ } else if (strcmp (word, "user") == 0) {
+ while (text[0]) {
+ word = ap_getword_conf (r->pool, &text);
+ if (strcmp (user, word) == 0) {
+ return OK;
+ }
+ }
+
+ /* Specific groups */
+ } else if (strcmp (word, "group") == 0) {
+ if (hreq && hreq->groups) {
+ while (text[0]) {
+ word = ap_getword_conf (r->pool, &text);
+ if (find_word_quoted (hreq->groups, word))
+ return OK;
+ }
+ }
+
+ /* What is this? */
+ } else {
+ ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r,
+ "access to %s failed, reason: unknown require "
+ "directive:\"%s\"", r->uri, reqs[x].requirement);
+ }
+ }
+
+ if (!method_restricted)
+ return OK;
+
+ ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r,
+ "access to %s failed, reason: user %s not allowed access",
+ r->uri, user);
+ return HTTP_UNAUTHORIZED;
+}
+#endif
+
+static void
+register_hooks(apr_pool_t *p)
+{
+ ap_log_perror (APLOG_MARK, APLOG_ERR, 0, p, "mod_auth_singleid registering hooks");
+#if 0
+ 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 (hook_authenticate, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_auth_checker (httpauth_access, NULL, NULL, APR_HOOK_MIDDLE);
+#endif
+}
+
+module AP_MODULE_DECLARE_DATA auth_singleid_module = {
+ STANDARD20_MODULE_STUFF,
+ dir_config_creator, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ command_table, /* command table */
+ register_hooks /* register hooks */
+};