summaryrefslogtreecommitdiff
path: root/daemon/httpauthd.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/httpauthd.c')
-rw-r--r--daemon/httpauthd.c353
1 files changed, 273 insertions, 80 deletions
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;
}