summaryrefslogtreecommitdiff
path: root/daemon/simple.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/simple.c')
-rw-r--r--daemon/simple.c188
1 files changed, 125 insertions, 63 deletions
diff --git a/daemon/simple.c b/daemon/simple.c
index d51e9d9..e33e833 100644
--- a/daemon/simple.c
+++ b/daemon/simple.c
@@ -33,20 +33,13 @@ typedef struct simple_context
/* Context ----------------------------------------------------------- */
hash_t* cache; /* Some cached records or basic */
+
+#ifdef _DEBUG
+ const char* debug_nonce;
+#endif
}
simple_context_t;
-/* The defaults for the context */
-static const simple_context_t simple_defaults =
-{
- NULL, /* filename */
- NULL, /* realm */
- NULL, /* domains */
- 0, /* cache_max */
- 0, /* cache_timeout */
- NULL /* cache */
-};
-
/* -------------------------------------------------------------------------------
* Internal Functions
@@ -156,6 +149,7 @@ static int complete_digest_ha1(simple_context_t* ctx, digest_record_t* rec,
FILE* f;
int found = 0;
char* t;
+ char* t2;
char line[SIMPLE_MAXLINE];
ASSERT(ctx && rec && buf && user && user[0] && code);
@@ -195,33 +189,39 @@ static int complete_digest_ha1(simple_context_t* ctx, digest_record_t* rec,
/* Check the user */
if(strcmp(line, user) == 0)
{
- /* Now decode the rest of the line and see if it matches up */
- t = ha_bufdechex(buf, t, MD5_LEN);
-
- if(t != NULL)
+ /* Otherwise it might be a digest type ha1. */
+ t2 = strchr(t, ':');
+ if(t2)
{
- memcpy(rec->ha1, t, MD5_LEN);
- found = 1;
- break;
+ *t2 = 0;
+ t2++;
+
+ /* Check the realm */
+ if(strcmp(t, ctx->realm) == 0)
+ {
+ /* Now try antd decode the ha1 */
+ t = ha_bufdechex(buf, t2, MD5_LEN);
+ if(t != NULL)
+ {
+ memcpy(rec->ha1, t, MD5_LEN);
+ found = 1;
+ break;
+ }
+ }
}
- else
- {
- if(ha_buferr(buf))
- break;
-
+ if(!t2 || !found)
ha_messagex(LOG_WARNING, "user '%s' found in file, but password not in digest format", user);
- }
}
}
-
- fclose(f);
}
+ fclose(f);
+
if(ha_buferr(buf))
return HA_ERROR;
- return found ? HA_FALSE : HA_OK;
+ return found ? HA_OK : HA_FALSE;
}
static int validate_user_password(simple_context_t* ctx, ha_buffer_t* buf,
@@ -264,6 +264,14 @@ static int validate_user_password(simple_context_t* ctx, ha_buffer_t* buf,
break;
}
+ /* Take white space off end of line */
+ t = line + strlen(line);
+ while(t != line && isspace(*(t - 1)))
+ {
+ *(t - 1) = 0;
+ t--;
+ }
+
t = strchr(line, ':');
if(t)
{
@@ -274,40 +282,48 @@ static int validate_user_password(simple_context_t* ctx, ha_buffer_t* buf,
/* Check the user */
if(strcmp(line, user) == 0)
{
- /* We can validate against an ha1, so check if it decodes as one */
- t2 = ha_bufdechex(buf, t, MD5_LEN);
+ /* Not sure if crypt is thread safe so we lock */
+ ha_lock(NULL);
- if(t2 && memcmp(ha1, t2, MD5_LEN) == 0)
+ /* Check the password */
+ t2 = crypt(clearpw, t);
+
+ ha_unlock(NULL);
+
+ if(strcmp(crypt(clearpw, t), t) == 0)
{
- memcpy(ha1, t2, MD5_LEN);
found = 1;
break;
}
- /* Otherwise we try a nice crypt style password */
- else
+ /* Otherwise it might be a digest type ha1. */
+ t2 = strchr(t, ':');
+ if(t2)
{
- /* Not sure if crypt is thread safe so we lock */
- ha_lock();
-
- /* Check the password */
- if(strcmp(crypt(clearpw, t), t) == 0)
+ *t2 = 0;
+ t2++;
+
+ /* Check the realm */
+ if(strcmp(t, ctx->realm) == 0)
+ {
+ /* Now try antd decode the ha1 */
+ t = ha_bufdechex(buf, t2, MD5_LEN);
+ if(t && memcmp(ha1, t, MD5_LEN) == 0)
+ {
found = 1;
-
- ha_unlock();
-
- if(found)
- break;
+ break;
+ }
+ }
}
if(ha_buferr(buf))
break;
}
}
-
- fclose(f);
}
+ fclose(f);
+
if(ha_buferr(buf))
return HA_ERROR;
@@ -347,8 +363,9 @@ static int simple_basic_response(simple_context_t* ctx, const char* header,
finally:
- if(resp->code == HA_SERVER_ACCEPT)
+ if(ret = HA_OK)
{
+ resp->code = HA_SERVER_ACCEPT;
resp->detail = basic.user;
/* We put this connection into the successful connections */
@@ -361,16 +378,33 @@ finally:
static int simple_digest_challenge(simple_context_t* ctx, ha_response_t* resp,
ha_buffer_t* buf, int stale)
{
- unsigned char nonce[DIGEST_NONCE_LEN];
+ const char* nonce_str;
const char* header;
ASSERT(ctx && resp && buf);
/* Generate an nonce */
- digest_makenonce(nonce, g_simple_secret, NULL);
+
+#ifdef _DEBUG
+ if(ctx->debug_nonce)
+ {
+ nonce_str = ctx->debug_nonce;
+ ha_messagex(LOG_WARNING, "using debug nonce. security non-existant.");
+ }
+ else
+#endif
+ {
+ unsigned char nonce[DIGEST_NONCE_LEN];
+ digest_makenonce(nonce, g_simple_secret, NULL);
+
+ nonce_str = ha_bufenchex(buf, nonce, DIGEST_NONCE_LEN);
+ if(!nonce_str)
+ return HA_ERROR;
+ }
+
/* Now generate a message to send */
- header = digest_challenge(buf, nonce, ctx->realm, ctx->domains, stale);
+ header = digest_challenge(buf, nonce_str, ctx->realm, ctx->domains, stale);
if(!header)
return HA_ERROR;
@@ -403,14 +437,34 @@ static int simple_digest_response(simple_context_t* ctx, const char* header,
if(digest_parse(header, buf, &dg, nonce) == HA_ERROR)
return HA_ERROR;
- r = digest_checknonce(nonce, g_simple_secret, &expiry);
- if(r != HA_OK)
+#ifdef _DEBUG
+ if(ctx->debug_nonce)
{
- if(r == HA_FALSE)
+ if(dg.nonce && strcmp(dg.nonce, ctx->debug_nonce) != 0)
+ {
+ ret = HA_FALSE;
ha_messagex(LOG_WARNING, "digest response contains invalid nonce");
+ goto finally;
+ }
- ret = r;
- goto finally;
+ /* Do a rough hash into the real nonce, for use as a key */
+ md5_string(nonce, ctx->debug_nonce);
+
+ /* Debug nonce's never expire */
+ expiry = time(NULL);
+ }
+ else
+#endif
+ {
+ r = digest_checknonce(nonce, g_simple_secret, &expiry);
+ if(r != HA_OK)
+ {
+ if(r == HA_FALSE)
+ ha_messagex(LOG_WARNING, "digest response contains invalid nonce");
+
+ ret = r;
+ goto finally;
+ }
}
rec = get_cached_digest(ctx, nonce);
@@ -520,6 +574,14 @@ int simple_config(ha_context_t* context, const char* name, const char* value)
return HA_OK;
}
+#ifdef _DEBUG
+ else if(strcmp(name, "digestdebugnonce") == 0)
+ {
+ ctx->debug_nonce = value;
+ return HA_OK;
+ }
+#endif
+
return HA_FALSE;
}
@@ -600,7 +662,7 @@ int simple_process(ha_context_t* context, ha_request_t* req,
ha_response_t* resp, ha_buffer_t* buf)
{
simple_context_t* ctx = (simple_context_t*)(context->data);
- const char* header;
+ const char* header = NULL;
int ret = HA_FALSE;
int found = 0;
basic_header_t basic;
@@ -652,13 +714,6 @@ int simple_process(ha_context_t* context, ha_request_t* req,
{
resp->code = HA_SERVER_DECLINE;
- if(context->types & HA_TYPE_DIGEST)
- {
- ret = simple_digest_challenge(ctx, resp, buf, 0);
- if(ret == HA_ERROR)
- return ret;
- }
-
if(context->types & HA_TYPE_BASIC)
{
ha_bufmcat(buf, "BASIC realm=\"", ctx->realm , "\"", NULL);
@@ -668,6 +723,13 @@ int simple_process(ha_context_t* context, ha_request_t* req,
ha_addheader(resp, "WWW-Authenticate", ha_bufdata(buf));
}
+
+ if(context->types & HA_TYPE_DIGEST)
+ {
+ ret = simple_digest_challenge(ctx, resp, buf, 0);
+ if(ret == HA_ERROR)
+ return ret;
+ }
}
return ret;
@@ -685,7 +747,7 @@ ha_handler_t simple_handler =
simple_destroy, /* Uninitialization routine */
simple_config, /* Config routine */
simple_process, /* Processing routine */
- &simple_defaults, /* A default context */
+ NULL, /* A default context */
sizeof(simple_context_t) /* Size of the context */
};