diff options
Diffstat (limited to 'daemon/httpauthd.c')
-rw-r--r-- | daemon/httpauthd.c | 353 |
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; } |