summaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'daemon')
-rw-r--r--daemon/Makefile.am3
-rw-r--r--daemon/defaults.h1
-rw-r--r--daemon/httpauthd.c353
-rw-r--r--daemon/httpauthd.h35
-rw-r--r--daemon/ldap.c219
-rw-r--r--daemon/misc.c72
-rw-r--r--daemon/ntlm.c138
-rw-r--r--daemon/simple.c143
8 files changed, 635 insertions, 329 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index c93e89f..39a0532 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -4,10 +4,11 @@ bin_PROGRAMS = httpauthd
httpauthd_SOURCES = httpauthd.c httpauthd.h usuals.h compat.h compat.c \
buffer.c misc.c basic.h basic.c ntlm.c hash.c hash.h ntlmssp.h ntlmssp.c \
md5.c md5.h sha1.c sha1.h digest.h digest.c ldap.c defaults.h simple.c \
+ ../common/sock_any.c ../common/sock_any.h \
smblib/smblib.c smblib/smblib-util.c smblib/file.c smblib/smb-errors.c smblib/exper.c smblib/smblib-api.c \
rfcnb/rfcnb-io.c rfcnb/rfcnb-util.c rfcnb/session.c
-httpauthd_CFLAGS = -DLinux
+httpauthd_CFLAGS = -DLinux -I../common/ -I../
# man_MANS = rtfm.1
EXTRA_DIST = protocol.txt smblib rfcnb
diff --git a/daemon/defaults.h b/daemon/defaults.h
index a72e51a..828bec1 100644
--- a/daemon/defaults.h
+++ b/daemon/defaults.h
@@ -6,5 +6,6 @@
#define DEFAULT_PENDING_TIMEOUT 60
#define DEFAULT_TIMEOUT 900
#define DEFAULT_CACHEMAX 1024
+#define DEFAULT_PORT 8020
#endif /* __DEFAULTS_H__ */
diff --git a/daemon/httpauthd.c b/daemon/httpauthd.c
index 2dba6c2..8c0f000 100644
--- a/daemon/httpauthd.c
+++ b/daemon/httpauthd.c
@@ -10,12 +10,12 @@
#include <pthread.h>
#include <fcntl.h>
#include <err.h>
-#include <sys/un.h>
-#include <sys/socket.h>
+#include <signal.h>
#include "usuals.h"
#include "httpauthd.h"
#include "defaults.h"
+#include "sock_any.h"
/*
* This shouldn't be used by handlers,
@@ -100,7 +100,8 @@ httpauth_thread_t;
*/
int g_daemonized = 0; /* Currently running as a daemon */
-int g_debugging = 0; /* In debug mode */
+int g_console = 0; /* debug mode read write from console */
+int g_debuglevel = LOG_ERR; /* what gets logged to console */
const char* g_socket = DEFAULT_SOCKET; /* The socket to communicate on */
int g_maxthreads = DEFAULT_MAXTHREADS; /* The maximum number of threads */
@@ -118,13 +119,14 @@ pthread_mutexattr_t g_mutexattr;
* Forward Declarations
*/
-int usage();
-void* httpauth_thread(void* arg);
-int httpauth_processor(int ifd, int ofd);
-int process_auth(ha_request_t* req, ha_response_t* resp,
- ha_buffer_t* outb);
-int config_parse(const char* file, ha_buffer_t* buf);
-
+static int usage();
+static void* httpauth_thread(void* arg);
+static int httpauth_processor(int ifd, int ofd);
+static int httpauth_respond(int ofd, int scode, int ccode, const char* msg);
+static int process_auth(ha_request_t* req, ha_response_t* resp,
+ ha_buffer_t* outb);
+static int config_parse(const char* file, ha_buffer_t* buf);
+static void on_quit(int signal);
/* -----------------------------------------------------------------------
* Main Program
@@ -150,13 +152,21 @@ int main(int argc, char* argv[])
errx(1, "threading problem. can't create mutex");
/* Parse the arguments nicely */
- while((ch = getopt(argc, argv, "df:X")) != -1)
+ while((ch = getopt(argc, argv, "d:f:X")) != -1)
{
switch(ch)
{
/* Don't daemonize */
case 'd':
- daemonize = 0;
+ {
+ char* t;
+
+ daemonize = 0;
+ g_debuglevel = strtol(optarg, &t, 10);
+ if(*t || g_debuglevel > 4)
+ errx(1, "invalid debug log level");
+ g_debuglevel += LOG_ERR;
+ }
break;
/* The configuration file */
@@ -166,7 +176,8 @@ int main(int argc, char* argv[])
/* Process console input instead */
case 'X':
- g_debugging = 1;
+ g_console = 1;
+ daemonize = 0;
break;
/* Usage information */
@@ -183,6 +194,7 @@ int main(int argc, char* argv[])
if(argc != 0)
return usage();
+ ha_messagex(LOG_DEBUG, "starting up...");
/* From here on out we need to quit in an orderly fashion */
@@ -204,42 +216,37 @@ int main(int argc, char* argv[])
config_parse(conf, &cbuf);
- if(!g_debugging)
+ if(!g_console)
{
- struct sockaddr_un sau;
+ struct sockaddr_any sany;
/* Create the thread buffers */
threads = (httpauth_thread_t*)malloc(sizeof(httpauth_thread_t) * g_maxthreads);
if(!threads)
errx(1, "out of memory");
+ /* Get the socket type */
+ if(sock_any_pton(g_socket, &sany, DEFAULT_PORT) == -1)
+ errx(1, "invalid socket name or ip: %s", g_socket);
+
/* Create the socket */
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ sock = socket(SANY_TYPE(sany), SOCK_STREAM, 0);
if(sock < 0)
err(1, "couldn't open socket");
-
/* Unlink the socket file if it exists */
/* TODO: Is this safe? */
unlink(g_socket);
- /* Setup the socket */
- strncmp(sau.sun_path, g_socket, sizeof(sau.sun_path));
- sau.sun_path[sizeof(sau.sun_path) - 1] = 0;
-
- /* Bind to the socket */
- if(bind(sock, (struct sockaddr*)&sau,
- sizeof(sau) - (sizeof(sau.sun_path) - strlen(sau.sun_path))))
- err(1, "couldn't bind to socket: %s", sau.sun_path);
-
+ if(bind(sock, SANY_ADDR(sany), SANY_LEN(sany)) != 0)
+ err(1, "couldn't bind to socket: %s", g_socket);
/* Let 5 connections queue up */
if(listen(sock, 5) != 0)
err(1, "couldn't listen on socket");
- }
-
- /* TODO: Enable signal processing here */
+ ha_messagex(LOG_DEBUG, "created socket: %s", g_socket);
+ }
/* Initialize all the handlers */
for(h = g_handlers; h; h = h->next)
@@ -253,8 +260,9 @@ int main(int argc, char* argv[])
/* This is for debugging the internal processes */
- if(g_debugging)
+ if(g_console)
{
+ ha_messagex(LOG_DEBUG, "processing from console");
r = httpauth_processor(0, 1);
goto finally;
}
@@ -263,27 +271,41 @@ int main(int argc, char* argv[])
/* This is the daemon section of the code */
else
{
- /* TODO: Daemonize here, and disconnect from terminal */
+ if(daemonize)
+ {
+ /* Fork a daemon nicely here */
+ if(daemon(0, 0) == -1)
+ {
+ ha_message(LOG_ERR, "couldn't run httpauth as daemon");
+ exit(1);
+ }
+
+ g_daemonized = 1;
+ }
+
+ /* Handle some signals */
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+/* signal(SIGINT, on_quit);
+ signal(SIGTERM, on_quit); */
/* Open the system log */
openlog("httpauthd", 0, LOG_AUTHPRIV);
- g_daemonized = 1;
+ ha_messagex(LOG_DEBUG, "accepting connections");
/* Now loop and accept the connections */
while(!g_quit)
{
int fd;
- /* TODO: A nice way to break out of the loop here */
-
fd = accept(sock, 0, 0);
if(fd == -1)
{
switch(errno)
{
- case EAGAIN:
case EINTR:
+ case EAGAIN:
break;
case ECONNABORTED:
@@ -300,13 +322,15 @@ int main(int argc, char* argv[])
continue;
}
+ ha_messagex(LOG_INFO, "accepted connection: %d", fd);
+
/* Look for thread and also clean up others */
for(i = 0; i < g_maxthreads; i++)
{
/* Clean up quit threads */
if(threads[i].tid != 0)
{
- if(threads[i].fd == 0)
+ if(threads[i].fd == -1)
{
pthread_join(threads[i].tid, NULL);
threads[i].tid = 0;
@@ -327,12 +351,14 @@ int main(int argc, char* argv[])
break;
}
- fd = 0;
+ ha_messagex(LOG_DEBUG, "created thread for connection: %d", fd);
+ fd = -1;
+ break;
}
}
/* Check to make sure we have a thread */
- if(fd != 0)
+ if(fd != -1)
{
ha_messagex(LOG_ERR, "too many connections open (max %d)", g_maxthreads);
httpauth_respond(fd, HA_SERVER_ERROR, 0, "too many connections");
@@ -340,7 +366,15 @@ int main(int argc, char* argv[])
}
}
- /* TODO: Quit all threads here */
+ ha_messagex(LOG_INFO, "waiting for threads to quit");
+
+ /* Quit all threads here */
+ for(i = 0; i < g_maxthreads; i++)
+ {
+ /* Clean up quit threads */
+ if(threads[i].tid != 0)
+ pthread_join(threads[i].tid, NULL);
+ }
r = 0;
}
@@ -371,28 +405,129 @@ finally:
return r == -1 ? 1 : 0;
}
-int usage()
+static void on_quit(int signal)
{
- fprintf(stderr, "usage: httpauthd [-dX] [-f conffile]\n");
+ g_quit = 1;
+}
+
+static int usage()
+{
+ fprintf(stderr, "usage: httpauthd [-d level] [-X] [-f conffile]\n");
return 2;
}
-void* httpauth_thread(void* arg)
+static void* httpauth_thread(void* arg)
+{
+ httpauth_thread_t* thread = (httpauth_thread_t*)arg;
+ int r;
+
+ ASSERT(thread);
+ ASSERT(thread->fd != -1);
+
+ /* call the processor */
+ r = httpauth_processor(thread->fd, thread->fd);
+
+ /* mark this as done */
+ thread->fd = -1;
+
+ return (void*)r;
+}
+
+/* -----------------------------------------------------------------------
+ * Logging
+ */
+
+void log_request(ha_request_t* req, ha_buffer_t* buf, int fd)
+{
+ const httpauth_command_t* cmd;
+ const char* t;
+ const char* t2;
+ int i;
+
+ if(g_debuglevel < LOG_DEBUG)
+ return;
+
+ if(req->type == REQTYPE_IGNORE || req->type == -1)
+ return;
+
+ ha_bufcpy(buf, "");
+
+ for(i = 0; i < HA_MAX_ARGS; i++)
+ {
+ if(req->args[i])
+ {
+ ha_bufjoin(buf);
+ ha_bufmcat(buf, ha_buflen(buf) > 0 ? ", " : "", req->args[i], NULL);
+ }
+ }
+
+ t = ha_bufdata(buf);
+
+ t2 = NULL;
+
+ /* Figure out which command it is */
+ for(cmd = kCommands; cmd->name; cmd++)
+ {
+ if(cmd->code == req->type)
+ {
+ t2 = cmd->name;
+ break;
+ }
+ }
+
+ ASSERT(t2);
+
+ ha_messagex(LOG_DEBUG, "received request (from %d): "
+ "[ type: %s / args: %s ]", fd, t2, t);
+
+ for(i = 0; i < HA_MAX_HEADERS; i++)
+ {
+ if(req->headers[i].name)
+ {
+ ASSERT(req->headers[i].data);
+ ha_messagex(LOG_DEBUG, "received header (from %d): [ %s: %s ]", fd,
+ req->headers[i].name, req->headers[i].data);
+ }
+ }
+}
+
+void log_response(ha_response_t* resp, int fd)
{
- int fd, r;
+ int i;
+
+ if(g_debuglevel < LOG_DEBUG)
+ return;
+
+ ha_messagex(LOG_DEBUG, "sending response (to %d): "
+ "[ code: 200 / ccode: %d / detail: %s ]", fd,
+ resp->code, resp->detail ? resp->detail : "");
+
+ for(i = 0; i < HA_MAX_HEADERS; i++)
+ {
+ if(resp->headers[i].name)
+ {
+ ASSERT(resp->headers[i].data);
+ ha_messagex(LOG_DEBUG, "sending header (to %d): [ %s: %s ]", fd,
+ resp->headers[i].name, resp->headers[i].data);
+ }
+ }
+}
- ASSERT(arg);
+void log_respcode(int code, const char* msg, int fd)
+{
+ if(g_debuglevel < LOG_DEBUG)
+ return;
- fd = (int)arg;
- return (void*)httpauth_processor(fd, fd);
+ ha_messagex(LOG_DEBUG, "sending response (to %d): "
+ "[ code: %d / detail: %s ]", fd, code, msg ? msg : "");
}
/* -----------------------------------------------------------------------
* Command Parsing and Handling
*/
-int httpauth_read(int ifd, ha_request_t* req,
- ha_buffer_t* buf)
+static int httpauth_read(int ifd, ha_request_t* req,
+ ha_buffer_t* buf)
{
const httpauth_command_t* cmd;
char* t;
@@ -513,7 +648,7 @@ int httpauth_read(int ifd, ha_request_t* req,
}
else
{
- if(i < MAX_HEADERS)
+ if(i < HA_MAX_HEADERS)
{
t = ha_bufparseword(buf, ":");
@@ -550,7 +685,7 @@ int httpauth_read(int ifd, ha_request_t* req,
return more;
}
-int write_data(int ofd, const char* data)
+static int write_data(int ofd, const char* data)
{
int r;
@@ -566,7 +701,7 @@ int write_data(int ofd, const char* data)
else if(r == -1)
{
- if(errno == EAGAIN || errno == EINTR)
+ if(errno == EAGAIN)
continue;
/* The other end closed. no message */
@@ -580,7 +715,7 @@ int write_data(int ofd, const char* data)
return 0;
}
-int httpauth_respond(int ofd, int scode, int ccode, const char* msg)
+static int httpauth_respond(int ofd, int scode, int ccode, const char* msg)
{
char num[16];
@@ -626,12 +761,16 @@ int httpauth_respond(int ofd, int scode, int ccode, const char* msg)
if(msg && write_data(ofd, msg) < 0)
return HA_CRITERROR;
+ /* When the client code is 0, then caller should log */
+ if(ccode == 0)
+ log_respcode(scode, msg, ofd);
+
return write_data(ofd, "\n");
}
const char kHeaderDelimiter[] = ": ";
-int httpauth_write(int ofd, ha_response_t* resp)
+static int httpauth_write(int ofd, ha_response_t* resp)
{
int i;
int wrote = 0;
@@ -642,7 +781,7 @@ int httpauth_write(int ofd, ha_response_t* resp)
if(httpauth_respond(ofd, HA_SERVER_ACCEPT, resp->code, resp->detail) < 0)
return HA_CRITERROR;
- for(i = 0; i < MAX_HEADERS; i++)
+ for(i = 0; i < HA_MAX_HEADERS; i++)
{
if(resp->headers[i].name)
{
@@ -659,10 +798,12 @@ int httpauth_write(int ofd, ha_response_t* resp)
if(write_data(ofd, "\n") == -1)
return -1;
+ log_response(resp, ofd);
+
return 0;
}
-int httpauth_error(int ofd, int r)
+static int httpauth_error(int ofd, int r)
{
int scode = 0;
const char* msg = NULL;
@@ -691,7 +832,7 @@ int httpauth_error(int ofd, int r)
return httpauth_respond(ofd, scode, 0, msg);
}
-int httpauth_ready(int ofd, ha_buffer_t* buf)
+static int httpauth_ready(int ofd, ha_buffer_t* buf)
{
const char* t;
httpauth_loaded_t* h;
@@ -720,7 +861,7 @@ int httpauth_ready(int ofd, ha_buffer_t* buf)
}
}
-int httpauth_processor(int ifd, int ofd)
+static int httpauth_processor(int ifd, int ofd)
{
ha_buffer_t inb;
ha_buffer_t outb;
@@ -743,13 +884,16 @@ int httpauth_processor(int ifd, int ofd)
}
/* Now loop and handle the commands */
- while(result == -1)
+ while(result == -1 && !g_quit)
{
ha_bufreset(&outb);
ha_bufreset(&inb);
r = httpauth_read(ifd, &req, &inb);
+ if(g_quit)
+ continue;
+
if(ha_buferr(&inb))
r = HA_CRITERROR;
@@ -757,9 +901,11 @@ int httpauth_processor(int ifd, int ofd)
{
httpauth_error(ofd, r);
result = 1;
- continue;
+ break;
}
+ log_request(&req, &inb, ifd);
+
if(r == 0)
result = 0;
@@ -769,13 +915,19 @@ int httpauth_processor(int ifd, int ofd)
r = process_auth(&req, &resp, &outb);
+ if(g_quit)
+ continue;
+
if(ha_buferr(&outb))
r = HA_CRITERROR;
if(r < 0)
{
httpauth_error(ofd, r);
- result = 1;
+
+ if(r == HA_CRITERROR)
+ result = 1;
+
continue;
}
@@ -797,6 +949,8 @@ int httpauth_processor(int ifd, int ofd)
break;
default:
+ ha_messagex(LOG_WARNING, "received unknown command from client: %d", ifd);
+
if(httpauth_respond(ofd, HA_SERVER_BADREQ, 0, "Unknown command") == -1)
{
result = -1;
@@ -819,8 +973,8 @@ finally:
return result;
}
-int process_auth(ha_request_t* req, ha_response_t* resp,
- ha_buffer_t* outb)
+static int process_auth(ha_request_t* req, ha_response_t* resp,
+ ha_buffer_t* outb)
{
httpauth_loaded_t* h;
@@ -832,21 +986,21 @@ int process_auth(ha_request_t* req, ha_response_t* resp,
/* Check our connection argument */
if(!req->args[AUTH_ARG_CONN] || !(req->args[AUTH_ARG_CONN][0]))
{
- ha_messagex(LOG_ERR, "Missing connection ID in request");
+ ha_messagex(LOG_ERR, "missing connection ID in request");
return HA_BADREQ;
}
/* Check our uri argument */
if(!req->args[AUTH_ARG_URI] || !(req->args[AUTH_ARG_URI][0]))
{
- ha_messagex(LOG_ERR, "Missing URI in request");
+ ha_messagex(LOG_ERR, "missing URI in request");
return HA_BADREQ;
}
/* Check our connection arguments */
if(!req->args[AUTH_ARG_METHOD] || !(req->args[AUTH_ARG_METHOD][0]))
{
- ha_messagex(LOG_ERR, "Missing method in request");
+ ha_messagex(LOG_ERR, "missing method in request");
return HA_BADREQ;
}
@@ -856,13 +1010,16 @@ int process_auth(ha_request_t* req, ha_response_t* resp,
{
if(strcasecmp(h->ctx.name, req->args[0]) == 0)
{
+ ha_messagex(LOG_INFO, "processing request with method: %s (%s)",
+ h->ctx.name, h->ctx.handler->type);
+
/* Now let the handler handle it */
ASSERT(h->ctx.handler->f_process);
return (h->ctx.handler->f_process)(&(h->ctx), req, resp, outb);
}
}
- ha_messagex(LOG_ERR, "Unknown authentication type: %s", req->args[0]);
+ ha_messagex(LOG_ERR, "unknown authentication type: %s", req->args[0]);
return HA_BADREQ;
}
@@ -870,8 +1027,8 @@ int process_auth(ha_request_t* req, ha_response_t* resp,
* Configuration
*/
-ha_context_t* config_addhandler(ha_buffer_t* buf, const char* alias,
- ha_handler_t* handler, const ha_context_t* defaults)
+static ha_context_t* config_addhandler(ha_buffer_t* buf, const char* alias,
+ ha_handler_t* handler, const ha_options_t* defaults)
{
httpauth_loaded_t* loaded;
int len;
@@ -885,7 +1042,7 @@ ha_context_t* config_addhandler(ha_buffer_t* buf, const char* alias,
errx(1, "out of memory");
memset(loaded, 0, len);
- memcpy(&(loaded->ctx), defaults, sizeof(ha_context_t));
+ memcpy(&(loaded->ctx.opts), defaults, sizeof(ha_options_t));
if(handler->context_size)
{
@@ -917,7 +1074,7 @@ ha_context_t* config_addhandler(ha_buffer_t* buf, const char* alias,
for(;;)
{
if(strcasecmp(alias, l->ctx.name) == 0)
- errx(1, "duplicate handler section for '%s'", alias);
+ errx(1, "duplicate method section for '%s'", alias);
if(!(l->next))
break;
@@ -928,13 +1085,13 @@ ha_context_t* config_addhandler(ha_buffer_t* buf, const char* alias,
l->next = loaded;
}
+ ha_messagex(LOG_DEBUG, "configuration: method: %s (%s)", alias, handler->type);
return &(loaded->ctx);
}
-
-int config_parse(const char* file, ha_buffer_t* buf)
+static int config_parse(const char* file, ha_buffer_t* buf)
{
- ha_context_t defaults;
+ ha_options_t defaults;
ha_context_t* ctx = NULL;
int line = 0;
int fd;
@@ -957,6 +1114,8 @@ int config_parse(const char* file, ha_buffer_t* buf)
defaults.types = 0xFFFFFFFF; /* All types by default */
defaults.cache_timeout = DEFAULT_TIMEOUT; /* Timeout for cache */
defaults.cache_max = DEFAULT_CACHEMAX;
+ defaults.realm = "";
+
ha_bufreset(buf);
@@ -992,7 +1151,7 @@ int config_parse(const char* file, ha_buffer_t* buf)
name = ha_bufparseline(buf, 1);
if(!name || name[strlen(name) - 1] != ']')
- errx(1, "configuration section invalid (line %d)", line);
+ errx(1, "method section invalid (line %d)", line);
/* remove the bracket */
@@ -1011,7 +1170,7 @@ int config_parse(const char* file, ha_buffer_t* buf)
}
if(handler == NULL)
- errx(1, "unknown handler type '%s' (line %d)", name, line);
+ errx(1, "unknown method type '%s' (line %d)", name, line);
/* If we had a last handler then add it to handlers */
ctx = config_addhandler(buf, name, handler, &defaults);
@@ -1052,7 +1211,6 @@ int config_parse(const char* file, ha_buffer_t* buf)
exit(1);
recog = 1;
}
-
}
/* Otherwise we're in a handler */
@@ -1078,13 +1236,16 @@ int config_parse(const char* file, ha_buffer_t* buf)
/* Options that are legal in both global and internal sections */
if(!recog)
{
+ ha_options_t* opts = ctx ? &(ctx->opts) : &defaults;
+ ASSERT(opts);
+
if(strcmp(name, "cachetimeout") == 0)
{
int v;
if(ha_confint(name, value, 0, 86400, &v) < 0)
exit(1); /* Message already printed */
- (ctx ? ctx : &defaults)->cache_timeout = v;
+ opts->cache_timeout = v;
recog = 1;
}
@@ -1094,7 +1255,7 @@ int config_parse(const char* file, ha_buffer_t* buf)
if(ha_confint(name, value, 0, 0x7FFFFFFF, &v) < 0)
exit(1); /* Message already printed */
- (ctx ? ctx : &defaults)->cache_max = v;
+ opts->cache_max = v;
recog = 1;
}
@@ -1134,17 +1295,49 @@ int config_parse(const char* file, ha_buffer_t* buf)
if(types == 0)
errx(1, "no authentication types for '%s' (line %d)", name, line);
- (ctx ? ctx : &defaults)->types = types;
+ opts->types = types;
recog = 1;
}
+
+ else if(strcmp(name, "realm") == 0)
+ {
+ opts->realm = value;
+ recog = 1;
+ }
+
+ else if(strcmp(name, "digestignoreuri") == 0)
+ {
+ int v;
+ if(ha_confbool(name, value, &v) < 0)
+ exit(1); /* Message already printed */
+
+ opts->digest_ignoreuri = v;
+ recog = 1;
+ }
+
+ else if(strcmp(name, "digestdomains") == 0)
+ {
+ opts->digest_domains = value;
+ recog = 1;
+ }
+
+#ifdef _DEBUG
+ else if(strcmp(name, "digestdebugnonce") == 0)
+ {
+ opts->digest_debugnonce = value;
+ recog = 1;
+ }
+#endif
}
if(!recog)
errx(1, "unrecognized configuration setting '%s' (line %d)", name, line);
+ else
+ ha_messagex(LOG_DEBUG, "configuration: setting: [ %s: %s ]", name, value);
}
if(!g_handlers)
- ha_messagex(LOG_INFO, "no handlers found in configuration file");
+ ha_messagex(LOG_WARNING, "configuration: no methods found in configuration file");
return 0;
}
diff --git a/daemon/httpauthd.h b/daemon/httpauthd.h
index 95187be..cd1d39e 100644
--- a/daemon/httpauthd.h
+++ b/daemon/httpauthd.h
@@ -177,16 +177,29 @@ ha_handler_t;
-struct ha_options;
+typedef struct ha_options
+{
+ /* Basic options */
+ unsigned int types;
+ int cache_timeout;
+ int cache_max;
+
+ /* For basic and digest auth: */
+ const char* realm;
+
+ /* For digest auth: */
+ int digest_ignoreuri;
+ const char* digest_domains;
+ const char* digest_debugnonce;
+}
+ha_options_t;
/* Context passed to the handler functions below */
typedef struct ha_context
{
const char* name; /* A name assigned by the configuration file */
ha_handler_t* handler; /* The original handler structure */
- unsigned int types; /* The types of authentication allowed */
- int cache_timeout; /* Timeout for cached connections */
- int cache_max; /* Maximum amount of cached connections */
+ ha_options_t opts; /* The options */
void* data; /* Handler specific data */
}
ha_context_t;
@@ -202,7 +215,7 @@ ha_context_t;
* should be no need to change it unless we're
* adding or removing commands
*/
-#define MAX_ARGS 4
+#define HA_MAX_ARGS 4
/*
* The maximum number of pertinent headers to read
@@ -211,13 +224,13 @@ ha_context_t;
* of valid headers in httpauthd.c
*/
-#define MAX_HEADERS 2
+#define HA_MAX_HEADERS 2
/*
* The maximum number of handlers. If you add
* handlers make sure to update this number.
*/
-#define MAX_HANDLERS 4
+#define HA_MAX_HANDLERS 4
/* A single header in memory */
@@ -241,8 +254,8 @@ ha_header_t;
typedef struct ha_request
{
int type;
- const char* args[MAX_ARGS];
- ha_header_t headers[MAX_HEADERS];
+ const char* args[HA_MAX_ARGS];
+ ha_header_t headers[HA_MAX_HEADERS];
}
ha_request_t;
@@ -250,7 +263,7 @@ ha_request_t;
#define HA_SERVER_READY 100
#define HA_SERVER_ACCEPT 200
#define HA_SERVER_DECLINE 401
-#define HA_SERVER_BADREQ 402
+#define HA_SERVER_BADREQ 400
#define HA_SERVER_BUSY 500
/* A response to the client */
@@ -258,7 +271,7 @@ typedef struct ha_response
{
int code;
const char* detail;
- ha_header_t headers[MAX_HEADERS];
+ ha_header_t headers[HA_MAX_HEADERS];
}
ha_response_t;
diff --git a/daemon/ldap.c b/daemon/ldap.c
index 9a79d43..a5abd97 100644
--- a/daemon/ldap.c
+++ b/daemon/ldap.c
@@ -69,24 +69,17 @@ typedef struct ldap_context
int port; /* Port to connect to LDAP server on */
int scope; /* Scope for filter */
- const char* realm; /* The realm to use in authentication */
- const char* domains; /* Domains for which digest auth is valid */
-
int dobind; /* Bind to do simple authentication */
- int cache_max; /* Maximum number of connections at once */
- int cache_timeout;
int ldap_max; /* Number of open connections allowed */
int ldap_timeout; /* Maximum amount of time to dedicate to an ldap query */
+ ha_options_t* opts; /* Options from httpauthd.c */
+
/* Context ----------------------------------------------------------- */
hash_t* cache; /* Some cached records or basic */
LDAP** pool; /* Pool of available connections */
int pool_mark; /* Amount of connections allocated */
-
-#ifdef _DEBUG
- const char* debug_nonce;
-#endif
}
ldap_context_t;
@@ -104,19 +97,12 @@ static const ldap_context_t ldap_defaults =
NULL, /* dnmap */
389, /* port */
LDAP_SCOPE_SUBTREE, /* scope */
- "", /* realm */
- NULL, /* domains */
1, /* dobind */
- 1000, /* cache_max */
- 30, /* cache_timeout */
10, /* ldap_max */
30, /* ldap_timeout */
NULL, /* cache */
NULL, /* pool */
0 /* pool_mark */
-#ifdef _DEBUG
- , NULL /* debug_nonce */
-#endif
};
@@ -134,17 +120,17 @@ static int report_ldap(const char* msg, int code)
{
ASSERT(code != LDAP_SUCCESS);
- if(!msg)
- msg = "ldap error";
-
- ha_messagex(LOG_ERR, "%s: %s", msg, ldap_err2string(code));
-
switch(code)
{
case LDAP_NO_MEMORY:
+ ha_messagex(LOG_CRIT, "out of memory");
return HA_CRITERROR;
default:
+ if(!msg)
+ msg = "error";
+
+ ha_messagex(LOG_ERR, "ldap: %s: %s", msg, ldap_err2string(code));
return HA_FAILED;
};
}
@@ -155,7 +141,7 @@ static digest_record_t* get_cached_digest(ldap_context_t* ctx, unsigned char* no
ASSERT(ctx && nonce);
- if(ctx->cache_max == 0)
+ if(ctx->opts->cache_max == 0)
return NULL;
ha_lock(NULL);
@@ -193,7 +179,7 @@ static int save_cached_digest(ldap_context_t* ctx, digest_record_t* rec)
ASSERT(ctx && rec);
- if(ctx->cache_max == 0)
+ if(ctx->opts->cache_max == 0)
{
free_hash_object(NULL, rec);
return HA_FALSE;
@@ -201,7 +187,7 @@ static int save_cached_digest(ldap_context_t* ctx, digest_record_t* rec)
ha_lock(NULL);
- while(hash_count(ctx->cache) >= ctx->cache_max)
+ while(hash_count(ctx->cache) >= ctx->opts->cache_max)
hash_bump(ctx->cache);
r = hash_set(ctx->cache, rec->nonce, rec);
@@ -223,12 +209,12 @@ static int add_cached_basic(ldap_context_t* ctx, unsigned char* key)
ASSERT(ctx && key);
- if(ctx->cache_max == 0)
+ if(ctx->opts->cache_max == 0)
return HA_FALSE;
ha_lock(NULL);
- while(hash_count(ctx->cache) >= ctx->cache_max)
+ while(hash_count(ctx->cache) >= ctx->opts->cache_max)
hash_bump(ctx->cache);
r = hash_set(ctx->cache, key, BASIC_ESTABLISHED);
@@ -279,7 +265,7 @@ static const char* substitute_params(ldap_context_t* ctx, ha_buffer_t* buf,
case 'r':
ha_bufjoin(buf);
- ha_bufcpy(buf, ctx->realm);
+ ha_bufcpy(buf, ctx->opts->realm);
t++;
break;
@@ -388,6 +374,7 @@ static int parse_ldap_ha1(ha_buffer_t* buf, struct berval* bv, unsigned char* ha
/* Raw binary */
if(bv->bv_len == MD5_LEN)
{
+ ha_messagex(LOG_DEBUG, "ldap: found ha1 in raw binary format");
memcpy(ha1, bv->bv_val, MD5_LEN);
return HA_OK;
}
@@ -400,6 +387,7 @@ static int parse_ldap_ha1(ha_buffer_t* buf, struct berval* bv, unsigned char* ha
if(d && len == MD5_LEN)
{
+ ha_messagex(LOG_DEBUG, "ldap: found ha1 in hex encoded format");
memcpy(ha1, d, MD5_LEN);
return HA_OK;
}
@@ -413,6 +401,7 @@ static int parse_ldap_ha1(ha_buffer_t* buf, struct berval* bv, unsigned char* ha
if(d && len == MD5_LEN)
{
+ ha_messagex(LOG_DEBUG, "ldap: found ha1 in b64 encoded format");
memcpy(ha1, ha_bufdata(buf), MD5_LEN);
return HA_OK;
}
@@ -483,6 +472,7 @@ static int validate_ldap_password(ldap_context_t* ctx, LDAP* ld, LDAPMessage* en
if(strcmp(pw, p) == 0)
{
+ ha_messagex(LOG_DEBUG, "ldap: successful validate against password");
res = HA_OK;
break;
}
@@ -492,7 +482,7 @@ static int validate_ldap_password(ldap_context_t* ctx, LDAP* ld, LDAPMessage* en
}
if(res == HA_FALSE && unknown)
- ha_messagex(LOG_ERR, "LDAP does not contain any compatible passwords for user: %s", user);
+ ha_messagex(LOG_ERR, "ldap: server does not contain any compatible passwords for user: %s", user);
return res;
}
@@ -516,7 +506,7 @@ static int validate_ldap_ha1(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry,
if(ha1s)
{
- digest_makeha1(key, user, ctx->realm, clearpw);
+ digest_makeha1(key, user, ctx->opts->realm, clearpw);
for(b = ha1s ; *b; b++)
{
@@ -530,7 +520,7 @@ static int validate_ldap_ha1(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry,
if(r == HA_FALSE)
{
if(first)
- ha_messagex(LOG_ERR, "LDAP contains invalid HA1 digest hash for user: %s", user);
+ ha_messagex(LOG_ERR, "ldap: server contains invalid HA1 digest hash for user: %s", user);
first = 0;
continue;
@@ -538,6 +528,7 @@ static int validate_ldap_ha1(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry,
if(memcmp(key, k, MD5_LEN) == 0)
{
+ ha_messagex(LOG_DEBUG, "ldap: successful validate against ha1");
res = HA_OK;
break;
}
@@ -561,6 +552,7 @@ static LDAP* get_ldap_connection(ldap_context_t* ctx)
/* An open connection in the pool */
if(ctx->pool[i])
{
+ ha_messagex(LOG_DEBUG, "ldap: using cached connection");
ld = ctx->pool[i];
ctx->pool[i] = NULL;
return ld;
@@ -569,14 +561,14 @@ static LDAP* get_ldap_connection(ldap_context_t* ctx)
if(ctx->pool_mark >= ctx->ldap_max)
{
- ha_messagex(LOG_ERR, "too many open connections to LDAP");
+ ha_messagex(LOG_ERR, "ldap: too many open connections");
return NULL;
}
ld = ldap_init(ctx->servers, ctx->port);
if(!ld)
{
- ha_message(LOG_ERR, "couldn't initialize ldap connection");
+ ha_message(LOG_ERR, "ldap: couldn't initialize connection");
return NULL;
}
@@ -586,13 +578,14 @@ static LDAP* get_ldap_connection(ldap_context_t* ctx)
ctx->password ? ctx->password : "");
if(r != LDAP_SUCCESS)
{
- report_ldap("couldn't bind to LDAP server", r);
+ report_ldap("ldap: couldn't bind to LDAP server", r);
ldap_unbind_s(ld);
return NULL;
}
}
ctx->pool_mark++;
+ ha_messagex(LOG_DEBUG, "ldap: opened new connection (total %d)", ctx->pool_mark);
return ld;
}
@@ -621,6 +614,7 @@ static void save_ldap_connection(ldap_context_t* ctx, LDAP* ld)
/* An open connection in the pool */
if(!ctx->pool[i])
{
+ ha_messagex(LOG_DEBUG, "ldap: caching connection for later use");
ctx->pool[i] = ld;
ld = NULL;
break;
@@ -634,6 +628,7 @@ static void save_ldap_connection(ldap_context_t* ctx, LDAP* ld)
{
ldap_unbind_s(ld);
ctx->pool_mark--;
+ ha_messagex(LOG_DEBUG, "ldap: discarding connection (total %d)", ctx->pool_mark);
}
}
@@ -644,6 +639,8 @@ static int retrieve_user_entry(ldap_context_t* ctx, ha_buffer_t* buf, LDAP* ld,
struct timeval tv;
const char* filter;
const char* attrs[3];
+ const char* base;
+ int scope;
int r;
ASSERT(ctx && buf && ld && user && dn && entry && result);
@@ -667,15 +664,19 @@ static int retrieve_user_entry(ldap_context_t* ctx, ha_buffer_t* buf, LDAP* ld,
tv.tv_sec = ctx->ldap_timeout;
tv.tv_usec = 0;
- r = ldap_search_st(ld, *dn ? *dn : ctx->base,
- *dn ? LDAP_SCOPE_BASE : ctx->scope,
- filter, (char**)attrs, 0, &tv, result);
+ base = *dn ? *dn : ctx->base;
+ scope = *dn ? LDAP_SCOPE_BASE : ctx->scope;
+
+ ha_messagex(LOG_DEBUG, "ldap: performing search: [ base: %s / scope: %d / filter: %s ]",
+ base, scope, filter);
+
+ r = ldap_search_st(ld, base, scope, filter, (char**)attrs, 0, &tv, result);
if(r != LDAP_SUCCESS)
{
if(r == LDAP_NO_SUCH_OBJECT)
{
- ha_messagex(LOG_WARNING, "user not found in LDAP: %s", user);
+ ha_messagex(LOG_WARNING, "ldap: user not found in LDAP: %s", user);
return HA_FALSE;
}
@@ -689,15 +690,18 @@ static int retrieve_user_entry(ldap_context_t* ctx, ha_buffer_t* buf, LDAP* ld,
case 1:
*entry = ldap_first_entry(ld, *result);
if(!(*dn))
+ {
*dn = ldap_get_dn(ld, *entry);
+ ha_messagex(LOG_DEBUG, "ldap: found entry for user: %s", *dn);
+ }
return HA_OK;
case 0:
- ha_messagex(LOG_WARNING, "user not found in LDAP: %s", user);
+ ha_messagex(LOG_WARNING, "ldap: user not found in LDAP: %s", user);
break;
default:
- ha_messagex(LOG_WARNING, "more than one user found for filter: %s", filter);
+ ha_messagex(LOG_WARNING, "ldap: more than one user found for filter: %s", filter);
break;
};
@@ -739,6 +743,8 @@ static int complete_digest_ha1(ldap_context_t* ctx, digest_record_t* rec,
ret = HA_CRITERROR;
goto finally;
}
+
+ ha_messagex(LOG_INFO, "ldap: mapped %s to %s", user, dn);
}
/* Okay now we contact the LDAP server. */
@@ -761,10 +767,11 @@ static int complete_digest_ha1(ldap_context_t* ctx, digest_record_t* rec,
if(ret != HA_OK)
{
if(ret == HA_FALSE)
- ha_messagex(LOG_ERR, "LDAP contains invalid HA1 digest hash for user: %s", user);
+ ha_messagex(LOG_ERR, "ldap: server contains invalid HA1 for user: %s", user);
}
}
+ ha_messagex(LOG_DEBUG, "ldap: using HA1 from ldap");
ldap_value_free_len(ha1s);
goto finally;
}
@@ -779,17 +786,20 @@ static int complete_digest_ha1(ldap_context_t* ctx, digest_record_t* rec,
if(t)
{
- digest_makeha1(rec->ha1, user, ctx->realm, t);
+ digest_makeha1(rec->ha1, user, ctx->opts->realm, t);
ret = HA_OK;
}
ldap_value_free(pws);
if(ret == HA_OK)
+ {
+ ha_messagex(LOG_DEBUG, "ldap: using clear password from ldap");
goto finally;
+ }
}
- ha_messagex(LOG_ERR, "LDAP contains no cleartext password for user: %s", user);
+ ha_messagex(LOG_ERR, "ldap: server contains no clear password or HA1 for user: %s", user);
finally:
@@ -824,6 +834,8 @@ static int basic_ldap_response(ldap_context_t* ctx, const char* header,
/* Check and see if this connection is in the cache */
if(have_cached_basic(ctx, basic.key))
{
+ ha_messagex(LOG_NOTICE, "ldap: validated basic user against cache: %s",
+ basic.user);
found = 1;
ret = HA_OK;
goto finally;
@@ -832,7 +844,10 @@ static int basic_ldap_response(ldap_context_t* ctx, const char* header,
/* If we have a user name and password */
if(!basic.user || !basic.user[0] ||
!basic.password || !basic.password[0])
+ {
+ ha_messagex(LOG_NOTICE, "ldap: no valid basic auth info");
goto finally;
+ }
ld = get_ldap_connection(ctx);
@@ -857,6 +872,8 @@ static int basic_ldap_response(ldap_context_t* ctx, const char* header,
ret = HA_CRITERROR;
goto finally;
}
+
+ ha_messagex(LOG_INFO, "ldap: mapped %s to %s", basic.user, dn);
}
@@ -895,7 +912,9 @@ static int basic_ldap_response(ldap_context_t* ctx, const char* header,
if(r != LDAP_SUCCESS)
{
if(r == LDAP_INVALID_CREDENTIALS)
- ha_messagex(LOG_WARNING, "invalid login for: %s", basic.user);
+ ha_messagex(LOG_WARNING, "ldap: basic authentication (via bind) failed for user: %s",
+ basic.user);
+
else
report_ldap("couldn't bind to LDAP server", r);
@@ -903,6 +922,7 @@ static int basic_ldap_response(ldap_context_t* ctx, const char* header,
}
/* It worked! */
+ ha_messagex(LOG_NOTICE, "ldap: validated basic user using bind: %s", basic.user);
found = 1;
}
@@ -915,10 +935,15 @@ static int basic_ldap_response(ldap_context_t* ctx, const char* header,
ret = validate_ldap_ha1(ctx, ld, entry, buf, basic.user, basic.password);
if(ret == HA_OK)
+ {
+ ha_messagex(LOG_NOTICE, "ldap: validated basic user password/ha1: %s", basic.user);
found = 1;
+ }
else
- ha_messagex(LOG_WARNING, "invalid, unreadable or unrecognized password for user: %s", basic.user);
+ {
+ ha_messagex(LOG_WARNING, "ldap: invalid, unreadable or unrecognized password for user: %s", basic.user);
+ }
}
@@ -952,10 +977,10 @@ static int digest_ldap_challenge(ldap_context_t* ctx, ha_response_t* resp,
ASSERT(ctx && resp && buf);
#ifdef _DEBUG
- if(ctx->debug_nonce)
+ if(ctx->opts->digest_debugnonce)
{
- nonce_str = ctx->debug_nonce;
- ha_messagex(LOG_WARNING, "using debug nonce. security non-existant.");
+ nonce_str = ctx->opts->digest_debugnonce;
+ ha_messagex(LOG_WARNING, "simple: using debug nonce. security non-existant.");
}
else
#endif
@@ -969,7 +994,8 @@ static int digest_ldap_challenge(ldap_context_t* ctx, ha_response_t* resp,
}
/* Now generate a message to send */
- header = digest_challenge(buf, nonce_str, ctx->realm, ctx->domains, stale);
+ header = digest_challenge(buf, nonce_str, ctx->opts->realm,
+ ctx->opts->digest_domains, stale);
if(!header)
return HA_CRITERROR;
@@ -978,6 +1004,7 @@ static int digest_ldap_challenge(ldap_context_t* ctx, ha_response_t* resp,
resp->code = HA_SERVER_DECLINE;
ha_addheader(resp, "WWW-Authenticate", header);
+ ha_messagex(LOG_DEBUG, "ldap: created digest challenge with nonce: %s", nonce_str);
return HA_OK;
}
@@ -1003,18 +1030,18 @@ static int digest_ldap_response(ldap_context_t* ctx, const char* header,
return r;
#ifdef _DEBUG
- if(ctx->debug_nonce)
+ if(ctx->opts->digest_debugnonce)
{
- if(dg.nonce && strcmp(dg.nonce, ctx->debug_nonce) != 0)
+ if(dg.nonce && strcmp(dg.nonce, ctx->opts->digest_debugnonce) != 0)
{
ret = HA_FALSE;
resp->code = HA_SERVER_BADREQ;
- ha_messagex(LOG_WARNING, "digest response contains invalid nonce");
+ ha_messagex(LOG_WARNING, "ldap: digest response contains invalid nonce");
goto finally;
}
/* Do a rough hash into the real nonce, for use as a key */
- md5_string(nonce, ctx->debug_nonce);
+ md5_string(nonce, ctx->opts->digest_debugnonce);
/* Debug nonce's never expire */
expiry = time(NULL);
@@ -1028,25 +1055,29 @@ static int digest_ldap_response(ldap_context_t* ctx, const char* header,
if(r == HA_FALSE)
{
resp->code = HA_SERVER_BADREQ;
- ha_messagex(LOG_WARNING, "digest response contains invalid nonce");
+ ha_messagex(LOG_WARNING, "ldap: digest response contains invalid nonce");
}
goto finally;
}
}
-
rec = get_cached_digest(ctx, nonce);
/* Check to see if we're stale */
- if((expiry + ctx->cache_timeout) <= time(NULL))
+ if((expiry + ctx->opts->cache_timeout) <= time(NULL))
{
+ ha_messagex(LOG_INFO, "ldap: nonce expired, sending stale challenge: %s",
+ dg.username);
+
stale = 1;
goto finally;
}
if(!rec)
{
+ ha_messagex(LOG_INFO, "ldap: no record in cache, creating one: %s", dg.username);
+
/*
* If we're valid but don't have a record in the
* cache then complete the record properly.
@@ -1070,7 +1101,8 @@ static int digest_ldap_response(ldap_context_t* ctx, const char* header,
/* Increment our nonce count */
rec->nc++;
- ret = digest_check(ctx->realm, method, uri, buf, &dg, rec);
+ ret = digest_check(ctx->opts->realm, method,
+ ctx->opts->digest_ignoreuri ? NULL : uri, buf, &dg, rec);
if(ret == HA_BADREQ)
{
@@ -1084,8 +1116,12 @@ static int digest_ldap_response(ldap_context_t* ctx, const char* header,
resp->detail = dg.username;
/* Figure out if we need a new nonce */
- if((expiry + (ctx->cache_timeout - (ctx->cache_timeout / 8))) < time(NULL))
+ if((expiry + (ctx->opts->cache_timeout -
+ (ctx->opts->cache_timeout / 8))) < time(NULL))
{
+ ha_messagex(LOG_INFO, "ldap: nonce almost expired, creating new one: %s",
+ dg.username);
+
digest_makenonce(nonce, g_ldap_secret, NULL);
stale = 1;
}
@@ -1100,6 +1136,8 @@ static int digest_ldap_response(ldap_context_t* ctx, const char* header,
if(t[0])
ha_addheader(resp, "Authentication-Info", t);
+ ha_messagex(LOG_NOTICE, "ldap: validated digest user: %s", dg.username);
+
/* Put the connection into the cache */
if((r = save_cached_digest(ctx, rec)) < 0)
ret = r;
@@ -1179,18 +1217,6 @@ int ldap_config(ha_context_t* context, const char* name, const char* value)
return HA_OK;
}
- else if(strcmp(name, "realm") == 0)
- {
- ctx->realm = value;
- return HA_OK;
- }
-
- else if(strcmp(name, "digestdomains") == 0)
- {
- ctx->domains = value;
- return HA_OK;
- }
-
else if(strcmp(name, "ldapscope") == 0)
{
if(strcmp(value, "sub") == 0 || strcmp(value, "subtree") == 0)
@@ -1224,14 +1250,6 @@ int ldap_config(ha_context_t* context, const char* name, const char* value)
return ha_confint(name, value, 0, 86400, &(ctx->ldap_timeout));
}
-#ifdef _DEBUG
- else if(strcmp(name, "digestdebugnonce") == 0)
- {
- ctx->debug_nonce = value;
- return HA_OK;
- }
-#endif
-
return HA_FALSE;
}
@@ -1240,6 +1258,7 @@ int ldap_inithand(ha_context_t* context)
/* Global initialization */
if(!context)
{
+ ha_messagex(LOG_DEBUG, "ldap: generating secret");
return ha_genrandom(g_ldap_secret, DIGEST_SECRET_LEN);
}
@@ -1252,9 +1271,9 @@ int ldap_inithand(ha_context_t* context)
ASSERT(ctx);
/* Make sure there are some types of authentication we can do */
- if(!(context->types & (HA_TYPE_BASIC | HA_TYPE_DIGEST)))
+ if(!(context->opts.types & (HA_TYPE_BASIC | HA_TYPE_DIGEST)))
{
- ha_messagex(LOG_ERR, "LDAP module configured, but does not implement any "
+ ha_messagex(LOG_ERR, "ldap: module configured, but does not implement any "
"configured authentication type.");
return HA_FAILED;
}
@@ -1262,14 +1281,14 @@ int ldap_inithand(ha_context_t* context)
/* Check for mandatory configuration */
if(!ctx->servers)
{
- ha_messagex(LOG_ERR, "LDAP configuration incomplete. "
+ ha_messagex(LOG_ERR, "ldap: configuration incomplete. "
"Must have LDAPServers.");
return HA_FAILED;
}
if(!ctx->dnmap && (!ctx->filter || !ctx->base))
{
- ha_messagex(LOG_ERR, "LDAP configuration incomplete. "
+ ha_messagex(LOG_ERR, "ldap: configuration incomplete. "
"When not using LDAPDNMap must specify LDAPBase and LDAPFilter.");
return HA_FAILED;
}
@@ -1299,8 +1318,9 @@ int ldap_inithand(ha_context_t* context)
memset(ctx->pool, 0, sizeof(LDAP*) * ctx->ldap_max);
/* Copy some settings over for easy access */
- ctx->cache_max = context->cache_max;
- ctx->cache_timeout = context->cache_timeout;
+ ctx->opts = &(context->opts);
+
+ ha_messagex(LOG_INFO, "ldap: initialized handler");
}
return HA_OK;
@@ -1333,6 +1353,8 @@ void ldap_destroy(ha_context_t* context)
/* And free the connection pool */
free(ctx->pool);
}
+
+ ha_messagex(LOG_INFO, "ldap: uninitialized handler");
}
int ldap_process(ha_context_t* context, ha_request_t* req,
@@ -1341,7 +1363,7 @@ int ldap_process(ha_context_t* context, ha_request_t* req,
ldap_context_t* ctx = (ldap_context_t*)context->data;
time_t t = time(NULL);
const char* header = NULL;
- int ret;
+ int ret, r;
ASSERT(req && resp && buf);
ASSERT(req->args[AUTH_ARG_METHOD]);
@@ -1350,21 +1372,24 @@ int ldap_process(ha_context_t* context, ha_request_t* req,
ha_lock(NULL);
/* Purge out stale connection stuff. */
- hash_purge(ctx->cache, t - ctx->cache_timeout);
+ r = hash_purge(ctx->cache, t - ctx->opts->cache_timeout);
ha_unlock(NULL);
+ if(r > 0)
+ ha_messagex(LOG_DEBUG, "ldap: purged cache records: %d", r);
/* We use this below to detect whether to send a default response */
resp->code = -1;
/* Check the headers and see if we got a response thingy */
- if(context->types & HA_TYPE_DIGEST)
+ if(context->opts.types & HA_TYPE_DIGEST)
{
header = ha_getheader(req, "Authorization", HA_PREFIX_DIGEST);
if(header)
{
+ ha_messagex(LOG_DEBUG, "ldap: processing basic auth header");
ret = digest_ldap_response(ctx, header, req->args[AUTH_ARG_METHOD],
req->args[AUTH_ARG_URI], resp, buf);
if(ret < 0)
@@ -1373,11 +1398,12 @@ int ldap_process(ha_context_t* context, ha_request_t* req,
}
/* Or a basic authentication */
- if(!header && context->types & HA_TYPE_BASIC)
+ if(!header && context->opts.types & HA_TYPE_BASIC)
{
header = ha_getheader(req, "Authorization", HA_PREFIX_BASIC);
if(header)
{
+ ha_messagex(LOG_DEBUG, "ldap: processing digest auth header");
ret = basic_ldap_response(ctx, header, resp, buf);
if(ret < 0)
return ret;
@@ -1390,21 +1416,22 @@ int ldap_process(ha_context_t* context, ha_request_t* req,
{
resp->code = HA_SERVER_DECLINE;
- if(context->types & HA_TYPE_DIGEST)
- {
- ret = digest_ldap_challenge(ctx, resp, buf, 0);
- if(ret < 0)
- return ret;
- }
-
- if(context->types & HA_TYPE_BASIC)
+ if(context->opts.types & HA_TYPE_BASIC)
{
- ha_bufmcat(buf, "BASIC realm=\"", ctx->realm , "\"", NULL);
+ ha_bufmcat(buf, "BASIC realm=\"", ctx->opts->realm , "\"", NULL);
if(ha_buferr(buf))
return HA_CRITERROR;
ha_addheader(resp, "WWW-Authenticate", ha_bufdata(buf));
+ ha_messagex(LOG_DEBUG, "ldap: sent basic auth request");
+ }
+
+ if(context->opts.types & HA_TYPE_DIGEST)
+ {
+ ret = digest_ldap_challenge(ctx, resp, buf, 0);
+ if(ret < 0)
+ return ret;
}
}
diff --git a/daemon/misc.c b/daemon/misc.c
index cda6dc2..a38eda9 100644
--- a/daemon/misc.c
+++ b/daemon/misc.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include <fcntl.h>
-extern int g_debugging;
+extern int g_debuglevel;
extern int g_daemonized;
extern pthread_mutex_t g_mutex;
@@ -29,11 +29,14 @@ void ha_messagex(int level, const char* msg, ...)
/* Either to syslog or stderr */
if(g_daemonized)
- vsyslog(level, msg, ap);
+ {
+ if(level < LOG_DEBUG)
+ vsyslog(level, msg, ap);
+ }
else
{
- if(g_debugging || level > LOG_INFO)
+ if(g_debuglevel >= level)
vwarnx(msg, ap);
}
@@ -50,21 +53,24 @@ void ha_message(int level, const char* msg, ...)
/* Either to syslog or stderr */
if(g_daemonized)
{
- char* m = (char*)alloca(strlen(msg) + MAX_MSGLEN + sizeof(kMsgDelimiter));
-
- if(m)
+ if(level < LOG_DEBUG)
{
- strcpy(m, msg);
- strcat(m, kMsgDelimiter);
- strerror_r(errno, m + strlen(m), MAX_MSGLEN);
- }
+ char* m = (char*)alloca(strlen(msg) + MAX_MSGLEN + sizeof(kMsgDelimiter));
- vsyslog(LOG_ERR, m ? m : msg, ap);
+ if(m)
+ {
+ strcpy(m, msg);
+ strcat(m, kMsgDelimiter);
+ strerror_r(errno, m + strlen(m), MAX_MSGLEN);
+ }
+
+ vsyslog(LOG_ERR, m ? m : msg, ap);
+ }
}
else
{
- if(g_debugging || level > LOG_INFO)
- vwarnx(msg, ap);
+ if(g_debuglevel >= level)
+ vwarn(msg, ap);
}
va_end(ap);
@@ -81,7 +87,7 @@ ha_header_t* ha_findheader(ha_request_t* req, const char* name)
ASSERT(req && name);
- for(i = 0; i < MAX_HEADERS; i++)
+ for(i = 0; i < HA_MAX_HEADERS; i++)
{
if(req->headers[i].name)
{
@@ -99,7 +105,7 @@ const char* ha_getheader(ha_request_t* req, const char* name, const char* prefix
ASSERT(req && name);
- for(i = 0; i < MAX_HEADERS; i++)
+ for(i = 0; i < HA_MAX_HEADERS; i++)
{
if(req->headers[i].name)
{
@@ -125,7 +131,7 @@ void ha_addheader(ha_response_t* resp, const char* name, const char* data)
ASSERT(resp && name && data);
- for(i = 0; i < MAX_HEADERS; i++)
+ for(i = 0; i < HA_MAX_HEADERS; i++)
{
if(!(resp->headers[i].name))
{
@@ -135,7 +141,7 @@ void ha_addheader(ha_response_t* resp, const char* name, const char* data)
}
}
- ha_messagex(LOG_ERR, "too many headers in response. discarding '%s'", name);
+ ha_messagex(LOG_WARNING, "too many headers in response. discarding '%s'", name);
}
@@ -145,12 +151,41 @@ void ha_addheader(ha_response_t* resp, const char* name, const char* data)
void ha_lock(pthread_mutex_t* mtx)
{
- int r = pthread_mutex_lock(mtx ? mtx : &g_mutex);
+ int r;
+
+#ifdef _DEBUG
+ int wait = 0;
+#endif
+
+ if(!mtx)
+ mtx = &g_mutex;
+
+#ifdef _DEBUG
+ r = pthread_mutex_trylock(mtx);
+ if(r == EBUSY)
+ {
+ wait = 1;
+ ha_message(LOG_DEBUG, "thread will block: %d", pthread_self());
+ r = pthread_mutex_lock(mtx);
+ }
+
+#else
+ r = pthread_mutex_lock(mtx);
+
+#endif
+
if(r != 0)
{
errno = r;
ha_message(LOG_CRIT, "threading problem. couldn't lock mutex");
}
+
+#ifdef _DEBUG
+ else if(wait)
+ {
+ ha_message(LOG_DEBUG, "thread unblocked: %d", pthread_self());
+ }
+#endif
}
void ha_unlock(pthread_mutex_t* mtx)
@@ -586,3 +621,4 @@ int ha_genrandom(unsigned char* data, size_t len)
close(dd);
return r == -1 ? HA_FAILED : HA_OK;
}
+
diff --git a/daemon/ntlm.c b/daemon/ntlm.c
index ef889f1..bbbac5e 100644
--- a/daemon/ntlm.c
+++ b/daemon/ntlm.c
@@ -44,7 +44,6 @@ typedef struct ntlm_context
const char* backup; /* Backup server if primary is down */
int pending_max; /* Maximum number of connections at once */
int pending_timeout; /* Timeout for authentication (in seconds) */
- const char* basic_realm; /* The realm for basic authentication */
/* Context ----------------------------------------------------------- */
hash_t* pending; /* Pending connections */
@@ -57,7 +56,7 @@ ntlm_context_t;
static const ntlm_context_t ntlm_defaults =
{
NULL, NULL, NULL, DEFAULT_PENDING_MAX, DEFAULT_PENDING_TIMEOUT,
- NULL, NULL, NULL
+ NULL, NULL
};
@@ -94,12 +93,13 @@ static ntlm_connection_t* makeconnection(ntlm_context_t* ctx)
ctx->domain, conn->nonce);
if(!conn->handle)
{
- ha_messagex(LOG_ERR, "couldn't connect to the domain server %s (backup: %s)",
+ ha_messagex(LOG_ERR, "ntlm: couldn't connect to the domain server %s (backup: %s)",
ctx->server, ctx->backup ? ctx->backup : "none");
free(conn);
return NULL;
}
+ ha_messagex(LOG_INFO, "ntlm: established connection to server");
return conn;
}
@@ -109,6 +109,7 @@ static void freeconnection(ntlm_connection_t* conn)
if(conn->handle)
{
+ ha_messagex(LOG_DEBUG, "ntlm: disconnected from server");
ntlmssp_disconnect(conn->handle);
conn->handle = NULL;
}
@@ -183,7 +184,10 @@ int ntlm_auth_basic(ntlm_context_t* ctx, char* key, const char* header,
*/
conn = getpending(ctx, key);
if(conn)
+ {
+ ha_messagex(LOG_WARNING, "ntlm: basic auth killed a pending ntlm auth in progress");
freeconnection(conn);
+ }
if((r = basic_parse(header, buf, &basic)) < 0)
return r;
@@ -196,43 +200,53 @@ int ntlm_auth_basic(ntlm_context_t* ctx, char* key, const char* header,
ha_unlock(NULL);
+ if(found)
+ ha_messagex(LOG_NOTICE, "ntlm: validated basic user against cache: %s", basic.user);
- /* Try to find a domain in the user */
- if((t = strchr(basic.user, '\\')) != NULL ||
- (t = strchr(basic.user, '/')) != NULL)
+ else
{
- /* Break at the domain */
- domain = basic.user;
- basic.user = t + 1;
- *t = 0;
-
- /* Make sure this is our domain */
- if(strcasecmp(domain, ctx->domain) != 0)
- domain = NULL;
- }
+ /* Try to find a domain in the user */
+ if((t = strchr(basic.user, '\\')) != NULL ||
+ (t = strchr(basic.user, '/')) != NULL)
+ {
+ /* Break at the domain */
+ domain = basic.user;
+ basic.user = t + 1;
+ *t = 0;
+
+ /* Make sure this is our domain */
+ if(strcasecmp(domain, ctx->domain) != 0)
+ domain = NULL;
+ }
- if(!domain)
- {
- /* Use the default domain if none specified */
- domain = ctx->domain;
- }
+ if(!domain)
+ {
+ /* Use the default domain if none specified */
+ domain = ctx->domain;
+ }
- /* Make sure above did not fail */
- if(!found && basic.user && basic.user[0] && basic.password &&
- domain && domain[0])
- {
- /* We need to lock to go into smblib */
- ha_lock(&g_smblib_mutex);
+ /* Make sure above did not fail */
+ if(basic.user && basic.user[0] && basic.password &&
+ domain && domain[0])
+ {
+ ha_messagex(LOG_DEBUG, "ntlm: checking user against server: %s", basic.user);
- /* Found in smbval/valid.h */
- if(ntlmssp_validuser(basic.user, basic.password, ctx->server,
- ctx->backup, domain) == NTV_NO_ERROR)
- {
- /* If valid then we return */
- found = 1;
- }
+ /* We need to lock to go into smblib */
+ ha_lock(&g_smblib_mutex);
- ha_unlock(&g_smblib_mutex);
+ /* Found in smbval/valid.h */
+ if(ntlmssp_validuser(basic.user, basic.password, ctx->server,
+ ctx->backup, domain) == NTV_NO_ERROR)
+ {
+ /* If valid then we return */
+ found = 1;
+ }
+
+ ha_unlock(&g_smblib_mutex);
+ }
+
+ if(found)
+ ha_messagex(LOG_NOTICE, "ntlm: validated basic user against server: %s", basic.user);
}
if(found)
@@ -300,7 +314,7 @@ int ntlm_auth_ntlm(ntlm_context_t* ctx, void* key, const char* header,
r = ntlmssp_decode_msg(&ntlmssp, d, len, &flags);
if(r != 0)
{
- ha_messagex(LOG_ERR, "decoding NTLM message failed (error %d)", r);
+ ha_messagex(LOG_WARNING, "ntlm: decoding NTLMSSP message failed (error %d)", r);
resp->code = HA_SERVER_BADREQ;
goto finally;
}
@@ -340,7 +354,7 @@ int ntlm_auth_ntlm(ntlm_context_t* ctx, void* key, const char* header,
}
else
{
- ha_messagex(LOG_ERR, "received out of order NTLM request from client");
+ ha_messagex(LOG_ERR, "ntlm: received out of order NTLM request from client");
resp->code = HA_SERVER_BADREQ;
}
@@ -421,6 +435,7 @@ int ntlm_auth_ntlm(ntlm_context_t* ctx, void* key, const char* header,
}
else
{
+ ha_messagex(LOG_DEBUG, "ntlm: sending ntlm challenge");
ha_addheader(resp, "WWW-Authenticate", ha_bufdata(buf));
resp->code = HA_SERVER_DECLINE;
}
@@ -439,14 +454,14 @@ int ntlm_auth_ntlm(ntlm_context_t* ctx, void* key, const char* header,
*/
if(!conn || !conn->handle)
{
- ha_messagex(LOG_ERR, "received out of order NTLM response from client");
+ ha_messagex(LOG_WARNING, "ntlm: received out of order NTLM response from client");
resp->code = HA_SERVER_BADREQ;
goto finally;
}
if(!ntlmssp.user)
{
- ha_messagex(LOG_ERR, "received NTLM response without user name");
+ ha_messagex(LOG_WARNING, "ntlm: received NTLM response without user name");
resp->code = HA_SERVER_BADREQ;
goto finally;
}
@@ -468,7 +483,7 @@ int ntlm_auth_ntlm(ntlm_context_t* ctx, void* key, const char* header,
* Note that we don't set a code here. This causes our
* caller to put in all the proper headers for us.
*/
- ha_messagex(LOG_ERR, "failed NTLM logon for user '%s'", ntlmssp.user);
+ ha_messagex(LOG_WARNING, "ntlm: failed NTLM logon for user '%s'", ntlmssp.user);
ret = HA_FALSE;
}
@@ -477,6 +492,7 @@ int ntlm_auth_ntlm(ntlm_context_t* ctx, void* key, const char* header,
{
int r;
resp->detail = ntlmssp.user;
+ ha_messagex(LOG_NOTICE, "ntlm: validated ntlm user against server", ntlmssp.user);
ha_lock(NULL);
@@ -500,7 +516,7 @@ int ntlm_auth_ntlm(ntlm_context_t* ctx, void* key, const char* header,
}
default:
- ha_messagex(LOG_ERR, "received invalid NTLM message (type %d)", ntlmssp.msg_type);
+ ha_messagex(LOG_WARNING, "ntlm: received invalid NTLM message (type %d)", ntlmssp.msg_type);
resp->code = HA_SERVER_BADREQ;
goto finally;
};
@@ -555,12 +571,6 @@ int ntlm_config(ha_context_t* context, const char* name, const char* value)
return ha_confint(name, value, 1, 86400, &(ctx->pending_timeout));
}
- else if(strcmp(name, "realm") == 0)
- {
- ctx->basic_realm = value;
- return HA_OK;
- }
-
return HA_FALSE;
}
@@ -574,7 +584,7 @@ int ntlm_init(ha_context_t* context)
ASSERT(ctx);
/* Make sure there are some types of authentication we can do */
- if(!(context->types & (HA_TYPE_BASIC | HA_TYPE_NTLM)))
+ if(!(context->opts.types & (HA_TYPE_BASIC | HA_TYPE_NTLM)))
{
ha_messagex(LOG_ERR, "NTLM module configured, but does not implement any "
"configured authentication type.");
@@ -599,6 +609,8 @@ int ntlm_init(ha_context_t* context)
ha_messagex(LOG_CRIT, "out of memory");
return HA_CRITERROR;
}
+
+ ha_messagex(LOG_INFO, "ntlm: initialized handler");
}
/* Global Initialization */
@@ -630,6 +642,8 @@ void ntlm_destroy(ha_context_t* context)
if(ctx->established)
hash_free(ctx->established);
+
+ ha_messagex(LOG_INFO, "ntlm: uninitialized handler");
}
/* Global Destroy */
@@ -649,7 +663,7 @@ int ntlm_process(ha_context_t* context, ha_request_t* req,
unsigned char key[NTLM_HASH_KEY_LEN];
const char* header = NULL;
time_t t = time(NULL);
- int ret;
+ int ret, r;
ASSERT(context && req && resp && buf);
ASSERT(req->args[AUTH_ARG_CONN]);
@@ -667,14 +681,16 @@ int ntlm_process(ha_context_t* context, ha_request_t* req,
* authenticated connections which have expired as
* well as half open connections which expire.
*/
- hash_purge(ctx->pending, t - ctx->pending_timeout);
- hash_purge(ctx->established, t - context->cache_timeout);
+ r = hash_purge(ctx->pending, t - ctx->pending_timeout);
+ r += hash_purge(ctx->established, t - context->opts.cache_timeout);
ha_unlock(NULL);
+ if(r > 0)
+ ha_messagex(LOG_DEBUG, "ntlm: purged info from cache: %d", r);
/* Look for a NTLM header */
- if(context->types & HA_TYPE_NTLM)
+ if(context->opts.types & HA_TYPE_NTLM)
{
header = ha_getheader(req, "Authorization", HA_PREFIX_NTLM);
if(header)
@@ -683,6 +699,7 @@ int ntlm_process(ha_context_t* context, ha_request_t* req,
while(*header && isspace(*header))
header++;
+ ha_messagex(LOG_DEBUG, "ntlm: processing ntlm auth header");
ret = ntlm_auth_ntlm(ctx, key, header, resp, buf);
if(ret < 0)
return ret;
@@ -690,7 +707,7 @@ int ntlm_process(ha_context_t* context, ha_request_t* req,
}
/* If basic is enabled, and no NTLM */
- if(!header && context->types & HA_TYPE_BASIC)
+ if(!header && context->opts.types & HA_TYPE_BASIC)
{
/* Look for a Basic header */
header = ha_getheader(req, "Authorization", HA_PREFIX_BASIC);
@@ -700,6 +717,7 @@ int ntlm_process(ha_context_t* context, ha_request_t* req,
while(*header && isspace(*header))
header++;
+ ha_messagex(LOG_DEBUG, "ntlm: processing basic auth header");
ret = ntlm_auth_basic(ctx, key, header, resp, buf);
if(ret < 0)
return ret;
@@ -725,6 +743,11 @@ int ntlm_process(ha_context_t* context, ha_request_t* req,
}
ha_unlock(NULL);
+
+ if(resp->code == HA_SERVER_ACCEPT)
+ ha_messagex(LOG_NOTICE, "ntlm: validated user against connection cache");
+
+ /* TODO: We need to be able to retrieve the user here somehow */
}
@@ -734,18 +757,21 @@ int ntlm_process(ha_context_t* context, ha_request_t* req,
/* If authentication failed tell the browser about it */
resp->code = HA_SERVER_DECLINE;
- if(context->types & HA_TYPE_NTLM)
+ if(context->opts.types & HA_TYPE_NTLM)
+ {
ha_addheader(resp, "WWW-Authenticate", HA_PREFIX_NTLM);
+ ha_messagex(LOG_DEBUG, "ntlm: sent ntlm auth request");
+ }
- if(context->types & HA_TYPE_BASIC)
+ if(context->opts.types & HA_TYPE_BASIC)
{
- ha_bufmcat(buf, HA_PREFIX_BASIC, "realm=\"",
- ctx->basic_realm ? ctx->basic_realm : "", "\"", NULL);
+ ha_bufmcat(buf, HA_PREFIX_BASIC, "realm=\"", context->opts.realm, "\"", NULL);
if(ha_buferr(buf))
return HA_CRITERROR;
ha_addheader(resp, "WWW-Authenticate", ha_bufdata(buf));
+ ha_messagex(LOG_DEBUG, "ntlm: sent basic auth request");
}
}
diff --git a/daemon/simple.c b/daemon/simple.c
index 4c7fb28..5b4eb60 100644
--- a/daemon/simple.c
+++ b/daemon/simple.c
@@ -25,18 +25,12 @@ unsigned char g_simple_secret[DIGEST_SECRET_LEN];
typedef struct simple_context
{
+ /* Settings ----------------------------------------------------------- */
const char* filename; /* The file name with the user names */
- const char* realm; /* The realm for basic authentication */
- const char* domains; /* Domains for which digest auth is valid */
- int cache_max; /* Maximum number of connections at once */
- int cache_timeout;
+ ha_options_t* opts; /* Options from httpauthd.c */
/* Context ----------------------------------------------------------- */
hash_t* cache; /* Some cached records or basic */
-
-#ifdef _DEBUG
- const char* debug_nonce;
-#endif
}
simple_context_t;
@@ -57,7 +51,7 @@ static digest_record_t* get_cached_digest(simple_context_t* ctx, unsigned char*
ASSERT(ctx && nonce);
- if(ctx->cache_max == 0)
+ if(ctx->opts->cache_max == 0)
return NULL;
ha_lock(NULL);
@@ -95,7 +89,7 @@ static int save_cached_digest(simple_context_t* ctx, digest_record_t* rec)
ASSERT(ctx && rec);
- if(ctx->cache_max == 0)
+ if(ctx->opts->cache_max == 0)
{
free_hash_object(NULL, rec);
return HA_FALSE;
@@ -103,7 +97,7 @@ static int save_cached_digest(simple_context_t* ctx, digest_record_t* rec)
ha_lock(NULL);
- while(hash_count(ctx->cache) >= ctx->cache_max)
+ while(hash_count(ctx->cache) >= ctx->opts->cache_max)
hash_bump(ctx->cache);
r = hash_set(ctx->cache, rec->nonce, rec);
@@ -126,12 +120,12 @@ static int add_cached_basic(simple_context_t* ctx, unsigned char* key)
ASSERT(ctx && key);
- if(ctx->cache_max == 0)
+ if(ctx->opts->cache_max == 0)
return HA_FALSE;
ha_lock(NULL);
- while(hash_count(ctx->cache) >= ctx->cache_max)
+ while(hash_count(ctx->cache) >= ctx->opts->cache_max)
hash_bump(ctx->cache);
r = hash_set(ctx->cache, key, BASIC_ESTABLISHED);
@@ -158,11 +152,12 @@ static int complete_digest_ha1(simple_context_t* ctx, digest_record_t* rec,
int ret = HA_FALSE;
ASSERT(ctx && rec && buf && user && user[0]);
+ ha_messagex(LOG_DEBUG, "searching password file for user's ha1: %s", user);
f = fopen(ctx->filename, "r");
if(!f)
{
- ha_message(LOG_ERR, "can't open file for basic auth: %s", ctx->filename);
+ ha_message(LOG_ERR, "simple: can't open file for basic auth: %s", ctx->filename);
return HA_FAILED;
}
@@ -178,7 +173,7 @@ static int complete_digest_ha1(simple_context_t* ctx, digest_record_t* rec,
if(ferror(f))
{
- ha_message(LOG_ERR, "error reading basic password file");
+ ha_message(LOG_ERR, "simple: error reading basic password file");
ret = HA_FAILED;
break;
}
@@ -201,7 +196,7 @@ static int complete_digest_ha1(simple_context_t* ctx, digest_record_t* rec,
t2++;
/* Check the realm */
- if(strcmp(t, ctx->realm) == 0)
+ if(strcmp(t, ctx->opts->realm) == 0)
{
len = MD5_LEN;
@@ -209,6 +204,7 @@ static int complete_digest_ha1(simple_context_t* ctx, digest_record_t* rec,
t = ha_bufdechex(buf, t2, &len);
if(t && len == MD5_LEN)
{
+ ha_messagex(LOG_DEBUG, "simple: found ha1 for user: %s", user);
memcpy(rec->ha1, t, MD5_LEN);
ret = HA_OK;
break;
@@ -217,7 +213,7 @@ static int complete_digest_ha1(simple_context_t* ctx, digest_record_t* rec,
}
if(!t2 || ret != HA_OK)
- ha_messagex(LOG_WARNING, "user '%s' found in file, but password not in digest format", user);
+ ha_messagex(LOG_WARNING, "simple: user '%s' found in file, but password not in digest format", user);
}
}
}
@@ -243,15 +239,16 @@ static int validate_user_password(simple_context_t* ctx, ha_buffer_t* buf,
ASSERT(ctx && buf);
ASSERT(user && user[0] && clearpw);
+ ha_messagex(LOG_DEBUG, "simple: validating user against password file: %s", user);
f = fopen(ctx->filename, "r");
if(!f)
{
- ha_message(LOG_ERR, "can't open file for basic auth: %s", ctx->filename);
+ ha_message(LOG_ERR, "simple: can't open file for basic auth: %s", ctx->filename);
return HA_FAILED;
}
- digest_makeha1(ha1, user, ctx->realm, clearpw);
+ digest_makeha1(ha1, user, ctx->opts->realm, clearpw);
/*
* Note: There should be no returns or jumps between
@@ -265,7 +262,7 @@ static int validate_user_password(simple_context_t* ctx, ha_buffer_t* buf,
if(ferror(f))
{
- ha_message(LOG_ERR, "error reading basic password file");
+ ha_message(LOG_ERR, "simple: error reading basic password file");
ret = HA_FAILED;
break;
}
@@ -298,6 +295,7 @@ static int validate_user_password(simple_context_t* ctx, ha_buffer_t* buf,
if(strcmp(crypt(clearpw, t), t) == 0)
{
+ ha_messagex(LOG_DEBUG, "simple: found valid crypt password for user: %s", user);
ret = HA_OK;
break;
}
@@ -310,7 +308,7 @@ static int validate_user_password(simple_context_t* ctx, ha_buffer_t* buf,
t2++;
/* Check the realm */
- if(strcmp(t, ctx->realm) == 0)
+ if(strcmp(t, ctx->opts->realm) == 0)
{
len = MD5_LEN;
@@ -318,6 +316,7 @@ static int validate_user_password(simple_context_t* ctx, ha_buffer_t* buf,
t = ha_bufdechex(buf, t2, &len);
if(t && len == MD5_LEN && memcmp(ha1, t, MD5_LEN) == 0)
{
+ ha_messagex(LOG_DEBUG, "simple: found valid ha1 for user: %s", user);
ret = HA_OK;
break;
}
@@ -356,6 +355,7 @@ static int simple_basic_response(simple_context_t* ctx, const char* header,
/* Check and see if this connection is in the cache */
if(have_cached_basic(ctx, basic.key))
{
+ ha_messagex(LOG_NOTICE, "simple: validated basic user against cache: %s", basic.user);
found = 1;
ret = HA_OK;
goto finally;
@@ -369,9 +369,15 @@ static int simple_basic_response(simple_context_t* ctx, const char* header,
ret = validate_user_password(ctx, buf, basic.user, basic.password);
+ if(ret == HA_OK)
+ ha_messagex(LOG_NOTICE, "simple: validated basic user against file: %s", basic.user);
+
+ else
+ ha_messagex(LOG_WARNING, "simple: basic authentication failed for user: %s", basic.user);
+
finally:
- if(ret = HA_OK)
+ if(ret == HA_OK)
{
resp->code = HA_SERVER_ACCEPT;
resp->detail = basic.user;
@@ -384,7 +390,7 @@ finally:
}
static int simple_digest_challenge(simple_context_t* ctx, ha_response_t* resp,
- ha_buffer_t* buf, int stale)
+ ha_buffer_t* buf, int stale)
{
const char* nonce_str;
const char* header;
@@ -394,10 +400,10 @@ static int simple_digest_challenge(simple_context_t* ctx, ha_response_t* resp,
/* Generate an nonce */
#ifdef _DEBUG
- if(ctx->debug_nonce)
+ if(ctx->opts->digest_debugnonce)
{
- nonce_str = ctx->debug_nonce;
- ha_messagex(LOG_WARNING, "using debug nonce. security non-existant.");
+ nonce_str = ctx->opts->digest_debugnonce;
+ ha_messagex(LOG_WARNING, "simple: using debug nonce. security non-existant.");
}
else
#endif
@@ -412,7 +418,8 @@ static int simple_digest_challenge(simple_context_t* ctx, ha_response_t* resp,
/* Now generate a message to send */
- header = digest_challenge(buf, nonce_str, ctx->realm, ctx->domains, stale);
+ header = digest_challenge(buf, nonce_str, ctx->opts->realm,
+ ctx->opts->digest_domains, stale);
if(!header)
return HA_CRITERROR;
@@ -421,6 +428,7 @@ static int simple_digest_challenge(simple_context_t* ctx, ha_response_t* resp,
resp->code = HA_SERVER_DECLINE;
ha_addheader(resp, "WWW-Authenticate", header);
+ ha_messagex(LOG_DEBUG, "simple: created digest challenge with nonce: %s", nonce_str);
return HA_OK;
}
@@ -446,18 +454,18 @@ static int simple_digest_response(simple_context_t* ctx, const char* header,
return r;
#ifdef _DEBUG
- if(ctx->debug_nonce)
+ if(ctx->opts->digest_debugnonce)
{
- if(dg.nonce && strcmp(dg.nonce, ctx->debug_nonce) != 0)
+ if(dg.nonce && strcmp(dg.nonce, ctx->opts->digest_debugnonce) != 0)
{
resp->code = HA_SERVER_BADREQ;
ret = HA_FALSE;
- ha_messagex(LOG_WARNING, "digest response contains invalid nonce");
+ ha_messagex(LOG_WARNING, "simple: digest response contains invalid nonce");
goto finally;
}
/* Do a rough hash into the real nonce, for use as a key */
- md5_string(nonce, ctx->debug_nonce);
+ md5_string(nonce, ctx->opts->digest_debugnonce);
/* Debug nonce's never expire */
expiry = time(NULL);
@@ -471,7 +479,7 @@ static int simple_digest_response(simple_context_t* ctx, const char* header,
if(r == HA_FALSE)
{
resp->code = HA_SERVER_BADREQ;
- ha_messagex(LOG_WARNING, "digest response contains invalid nonce");
+ ha_messagex(LOG_WARNING, "simple: digest response contains invalid nonce");
}
ret = r;
@@ -482,14 +490,19 @@ static int simple_digest_response(simple_context_t* ctx, const char* header,
rec = get_cached_digest(ctx, nonce);
/* Check to see if we're stale */
- if((expiry + ctx->cache_timeout) <= time(NULL))
+ if((expiry + ctx->opts->cache_timeout) <= time(NULL))
{
+ ha_messagex(LOG_INFO, "simple: nonce expired, sending stale challenge: %s",
+ dg.username);
+
stale = 1;
goto finally;
}
if(!rec)
{
+ ha_messagex(LOG_INFO, "simple: no record in cache, creating one: %s", dg.username);
+
/*
* If we're valid but don't have a record in the
* cache then complete the record properly.
@@ -513,7 +526,8 @@ static int simple_digest_response(simple_context_t* ctx, const char* header,
/* Increment our nonce count */
rec->nc++;
- ret = digest_check(ctx->realm, method, uri, buf, &dg, rec);
+ ret = digest_check(ctx->opts->realm, method,
+ ctx->opts->digest_ignoreuri ? NULL : uri, buf, &dg, rec);
if(ret == HA_BADREQ)
{
@@ -527,8 +541,12 @@ static int simple_digest_response(simple_context_t* ctx, const char* header,
resp->detail = dg.username;
/* Figure out if we need a new nonce */
- if((expiry + (ctx->cache_timeout - (ctx->cache_timeout / 8))) < time(NULL))
+ if((expiry + (ctx->opts->cache_timeout -
+ (ctx->opts->cache_timeout / 8))) < time(NULL))
{
+ ha_messagex(LOG_INFO, "simple: nonce almost expired, creating new one: %s",
+ dg.username);
+
digest_makenonce(nonce, g_simple_secret, NULL);
stale = 1;
}
@@ -543,6 +561,8 @@ static int simple_digest_response(simple_context_t* ctx, const char* header,
if(t[0])
ha_addheader(resp, "Authentication-Info", t);
+ ha_messagex(LOG_NOTICE, "simple: validated digest user: %s", dg.username);
+
/* Put the connection into the cache */
if((r = save_cached_digest(ctx, rec)) < 0)
ret = r;
@@ -580,26 +600,6 @@ int simple_config(ha_context_t* context, const char* name, const char* value)
return HA_OK;
}
- else if(strcmp(name, "realm") == 0)
- {
- ctx->realm = value;
- return HA_OK;
- }
-
- else if(strcmp(name, "digestdomains") == 0)
- {
- ctx->domains = value;
- return HA_OK;
- }
-
-#ifdef _DEBUG
- else if(strcmp(name, "digestdebugnonce") == 0)
- {
- ctx->debug_nonce = value;
- return HA_OK;
- }
-#endif
-
return HA_FALSE;
}
@@ -608,6 +608,7 @@ int simple_init(ha_context_t* context)
/* Global initialization */
if(!context)
{
+ ha_messagex(LOG_DEBUG, "simple: generating secret");
return ha_genrandom(g_simple_secret, DIGEST_SECRET_LEN);
}
@@ -620,9 +621,9 @@ int simple_init(ha_context_t* context)
ASSERT(ctx);
/* Make sure there are some types of authentication we can do */
- if(!(context->types & (HA_TYPE_BASIC | HA_TYPE_DIGEST)))
+ if(!(context->opts.types & (HA_TYPE_BASIC | HA_TYPE_DIGEST)))
{
- ha_messagex(LOG_ERR, "Simple module configured, but does not implement any "
+ ha_messagex(LOG_ERR, "simple: module configured, but does not implement any "
"configured authentication type.");
return HA_FAILED;
}
@@ -631,7 +632,7 @@ int simple_init(ha_context_t* context)
/* Check to make sure the file exists */
if(!ctx->filename)
{
- ha_messagex(LOG_ERR, "Basic configuration incomplete. "
+ ha_messagex(LOG_ERR, "simple: configuration incomplete. "
"Must have a PasswordFile configured.");
return HA_FAILED;
}
@@ -639,7 +640,7 @@ int simple_init(ha_context_t* context)
fd = open(ctx->filename, O_RDONLY);
if(fd == -1)
{
- ha_message(LOG_ERR, "can't open file for simple authentication: %s", ctx->filename);
+ ha_message(LOG_ERR, "simple: can't open file for authentication: %s", ctx->filename);
return HA_FAILED;
}
@@ -655,9 +656,9 @@ int simple_init(ha_context_t* context)
}
/* Copy some settings over for easy access */
- ctx->cache_max = context->cache_max;
- ctx->cache_timeout = context->cache_timeout;
+ ctx->opts = &(context->opts);
+ ha_messagex(LOG_INFO, "simple: initialized handler");
}
return HA_OK;
@@ -673,6 +674,8 @@ void simple_destroy(ha_context_t* context)
if(ctx->cache)
hash_free(ctx->cache);
+
+ ha_messagex(LOG_INFO, "simple: uninitialized handler");
}
}
@@ -684,6 +687,7 @@ int simple_process(ha_context_t* context, ha_request_t* req,
int ret = HA_FALSE;
int found = 0;
basic_header_t basic;
+ int r;
ASSERT(context && req && resp && buf);
ASSERT(req->args[AUTH_ARG_METHOD]);
@@ -692,21 +696,24 @@ int simple_process(ha_context_t* context, ha_request_t* req,
ha_lock(NULL);
/* Purge the cache */
- hash_purge(ctx->cache, time(NULL) - ctx->cache_timeout);
+ r = hash_purge(ctx->cache, time(NULL) - ctx->opts->cache_timeout);
ha_unlock(NULL);
+ if(r > 0)
+ ha_messagex(LOG_DEBUG, "simple: purged cache records: %d", r);
/* We use this below to detect whether to send a default response */
resp->code = -1;
/* Check the headers and see if we got a response thingy */
- if(context->types & HA_TYPE_DIGEST)
+ if(context->opts.types & HA_TYPE_DIGEST)
{
header = ha_getheader(req, "Authorization", HA_PREFIX_DIGEST);
if(header)
{
+ ha_messagex(LOG_DEBUG, "simple: processing digest auth header");
ret = simple_digest_response(ctx, header, req->args[AUTH_ARG_METHOD],
req->args[AUTH_ARG_URI], resp, buf);
if(ret < 0)
@@ -715,8 +722,9 @@ int simple_process(ha_context_t* context, ha_request_t* req,
}
/* Or a basic authentication */
- if(!header && context->types & HA_TYPE_BASIC)
+ if(!header && context->opts.types & HA_TYPE_BASIC)
{
+ ha_messagex(LOG_DEBUG, "simple: processing basic auth header");
header = ha_getheader(req, "Authorization", HA_PREFIX_BASIC);
if(header)
{
@@ -732,17 +740,18 @@ int simple_process(ha_context_t* context, ha_request_t* req,
{
resp->code = HA_SERVER_DECLINE;
- if(context->types & HA_TYPE_BASIC)
+ if(context->opts.types & HA_TYPE_BASIC)
{
- ha_bufmcat(buf, "BASIC realm=\"", ctx->realm , "\"", NULL);
+ ha_bufmcat(buf, "BASIC realm=\"", ctx->opts->realm , "\"", NULL);
if(ha_buferr(buf))
return HA_CRITERROR;
ha_addheader(resp, "WWW-Authenticate", ha_bufdata(buf));
+ ha_messagex(LOG_DEBUG, "simple: sent basic auth request");
}
- if(context->types & HA_TYPE_DIGEST)
+ if(context->opts.types & HA_TYPE_DIGEST)
{
ret = simple_digest_challenge(ctx, resp, buf, 0);
if(ret < 0)