diff options
Diffstat (limited to 'daemon/simple.c')
-rw-r--r-- | daemon/simple.c | 143 |
1 files changed, 76 insertions, 67 deletions
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) |