diff options
author | Stef Walter <stef@memberwebs.com> | 2004-04-21 17:37:06 +0000 |
---|---|---|
committer | Stef Walter <stef@memberwebs.com> | 2004-04-21 17:37:06 +0000 |
commit | ff76efc3e5e1b0e4ca3b10b7402406f619509bba (patch) | |
tree | c3b1e49235f67eabd22d31ebfc14934743b70858 /daemon/basic.c | |
parent | 01430fca169c1b8d7b1b4f1bdd529aa6bc4be80b (diff) |
Initial Import
Diffstat (limited to 'daemon/basic.c')
-rw-r--r-- | daemon/basic.c | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/daemon/basic.c b/daemon/basic.c new file mode 100644 index 0000000..a8325af --- /dev/null +++ b/daemon/basic.c @@ -0,0 +1,243 @@ + +/* On some linux this is required to get crypt to show itself */ +#define _XOPEN_SOURCE + +#include "usuals.h" +#include "httpauthd.h" +#include "defaults.h" + +#include <syslog.h> +#include <fcntl.h> +#include <unistd.h> + +#define BASIC_MAXLINE 128 + +/* This needs to be the same as an MD5 hash length */ +#define BASIC_HASH_KEY_LEN 16 +#define BASIC_ESTABLISHED (void*)1 + +/* ------------------------------------------------------------------------------- + * Structures + */ + +typedef struct basic_context +{ + const char* filename; /* The file name with the user names */ + const char* realm; /* The realm for basic authentication */ + + /* Context ----------------------------------------------------------- */ + hash_t* established; /* Established connections */ +} +basic_context_t; + +/* ------------------------------------------------------------------------------- + * Handler Functions + */ + +int basic_config(ha_context_t* context, const char* name, const char* value) +{ + basic_context_t* ctx = (basic_context_t*)(context.data); + + if(strcmp(name, "basicfile") == 0) + { + ctx->filename = value; + return HA_OK; + } + + else if(strcmp(name, "realm") == 0) + { + ctx->realm = value; + return HA_OK; + } + + return HA_FALSE; +} + +int basic_init(ha_context_t* context) +{ + /* Don't do global init */ + if(!context) + return HA_OK; + + basic_context_t* ctx = (basic_context_t*)(context.data); + int fd; + + /* Make sure there are some types of authentication we can do */ + if(!(context->types & HA_TYPE_BASIC)) + { + ha_messagex(LOG_ERR, "Basic module configured, but does not implement any " + "configured authentication type."); + return HA_ERROR; + } + + /* Check to make sure the file exists */ + if(!ctx->filename) + { + ha_messagex(LOG_ERR, "Basic configuration incomplete. " + "Must have a BasicFile configured."); + return HA_ERROR; + } + + fd = open(ctx->filename, O_RDONLY); + if(fd == -1) + { + ha_message(LOG_ERR, "can't open file for basic authentication: %s", ctx->filename); + return HA_ERROR; + } + + close(fd); + + /* Initialize our cache table */ + if(!(ctx->established = hash_create(BASIC_HASH_KEY_LEN))) + { + ha_messagex(LOG_CRIT, "out of memory"); + return HA_ERROR; + } + + return HA_OK; +} + +int basic_process(ha_context_t* context, ha_request_t* req, + ha_response_t* resp, ha_buffer_t* buf) +{ + basic_context_t* ctx = (basic_context_t*)(context.data); + const char* header; + char* t; + int found = 0; + ha_basic_header_t basic; + + memset(&basic, 0, sizeof(basic)); + + ha_lock(NULL); + + /* Purge the cache */ + hash_purge(ctx->established, time(NULL) - context->timeout); + + ha_unlock(NULL); + + + /* + * Init checked and made sure basic auth is enabled, so we + * can take that for granted here. + */ + + header = ha_getheader(req, "Authorization", BASIC_PREFIX); + if(header) + { + if(ha_parsebasic(header, buf, &basic) == HA_ERROR) + return HA_ERROR; + + /* Check and see if this connection is in the cache */ + ha_lock(NULL); + + if(hash_get(ctx->established, basic.key) == BASIC_ESTABLISHED) + { + hash_touch(ctx->established, basic.key); + found = 1; + } + + ha_unlock(NULL); + } + + + /* If we have a user name and password that wasn't in the cache */ + if(!found && basic.user && basic.user[0] && + basic.password && basic.password[0]) + { + FILE* f; + char line[BASIC_MAXLINE]; + + f = fopen(ctx->filename, "r"); + if(!f) + { + ha_message(LOG_ERR, "can't open file for basic auth: %s", ctx->filename); + resp->code = HA_SERVER_ERROR; + return HA_FALSE; + } + + /* + * Note: There should be no returns or jumps between + * this point and the closing of the file below. + */ + + /* Now look through the whole file */ + while(!feof(f)) + { + fgets(line, BASIC_MAXLINE, f); + + if(ferror(f)) + ha_message(LOG_ERR, "error reading basic password file"); + + t = strchr(line, ':'); + if(t) + { + /* Split the line */ + *t = 0; + t++; + + /* Check the user */ + if(strcmp(line, basic.user) == 0) + { + /* Not sure if crypt is thread safe so we lock */ + ha_lock(); + + /* Check the password */ + if(strcmp(crypt(basic.password, t), t) == 0) + found = 1; + + ha_unlock(); + + if(found) + break; + } + } + } + + fclose(f); + } + + /* If we found a user then tell them what it was */ + if(found) + { + resp->code = HA_SERVER_ACCEPT; + resp->detail = basic.user; + + /* We put this connection into the successful connections */ + if(!hash_set(ctx->established, basic.key, BASIC_ESTABLISHED)) + { + ha_messagex(LOG_CRIT, "out of memory"); + return HA_ERROR; + } + } + + /* Otherwise make the browser authenticate */ + else + { + resp->code = HA_SERVER_DECLINE; + + ha_bufnext(buf); + ha_bufcat(buf, "BASIC realm=\"", ctx->realm ? ctx->realm : "", + "\"", NULL); + + ha_addheader(resp, "WWW-Authenticate", ha_bufdata(buf)); + } + + return HA_OK; +} + + +/* ------------------------------------------------------------------------------- + * Handler Definition + */ + +ha_handler_t basic_handler = +{ + "Basic", /* The type */ + basic_init, /* Initialization function */ + basic_destroy, /* Uninitialization routine */ + basic_config, /* Config routine */ + basic_process, /* Processing routine */ + NULL, /* A default context */ + sizeof(basic_context_t) /* Size of the context */ +}; + |