summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2004-04-25 05:50:07 +0000
committerStef Walter <stef@memberwebs.com>2004-04-25 05:50:07 +0000
commit570c17aa3bb6a39030ebefc5618f0c3fa8cf0089 (patch)
tree34fd08eb06f92c4aadec308151ddc8fc80dcab08
parent36ab0775e1c5ec4352f36074cea8bfbe49302b80 (diff)
Debugging of simple authentication handler
-rw-r--r--common/buffer.c257
-rw-r--r--common/compat.c13
-rw-r--r--common/compat.h3
-rw-r--r--configure.in3
-rw-r--r--daemon/digest.c35
-rw-r--r--daemon/digest.h2
-rw-r--r--daemon/httpauthd.c10
-rw-r--r--daemon/httpauthd.h14
-rw-r--r--daemon/ldap.c7
-rw-r--r--daemon/misc.c3
-rw-r--r--daemon/simple.c188
-rw-r--r--sample/httpauthd.conf3
12 files changed, 366 insertions, 172 deletions
diff --git a/common/buffer.c b/common/buffer.c
index 0bba3bf..db23d79 100644
--- a/common/buffer.c
+++ b/common/buffer.c
@@ -8,44 +8,106 @@
* Memory Buffer
*/
+#define BUF_IS_EMPTY(b) ((b)->_pp == (b)->_rp)
+#define BUF_IN_JOIN(b) (!BUF_IS_EMPTY(b) && *((b)->_rp - 1) != 0)
+#define BUF_NEW_BLOCK(b) ((b)->_pp = (b)->_rp)
+
+/* TODO: Increase this size to 2048 once we're done debugging */
+#define BUF_INITIAL 80
+#define BUF_DELTA 16
+
+#define INTERNAL_DATA(intl) ((void*)(((unsigned char*)(intl)) + sizeof(*(intl))))
+
+#define FILL_BETWEEN(b, e, x) memset((b), x, ((char*)(e)) - ((char*)(b)));
+
/*
* LEGEND:
- * _al: allocated
- * _dt: data
+ * _ft: first buffer block
+ * _dt: current buffer block
* _rp: read/write point
* _pp: parse/begin point
*/
+typedef struct ha_buffer_internal
+{
+ char* end;
+ struct ha_buffer_internal* next;
+}
+internal_t;
+
void buffer_bump(ha_buffer_t* buf, int count)
{
+ int allocated;
+ internal_t* intl;
+
ASSERT(buf && count);
if(ha_buferr(buf))
return;
- if(buf->_rp + count >= buf->_dt + buf->_al)
+ ASSERT(BUF_DELTA < BUF_INITIAL);
+
+ /* Handle this common case first for efficiency */
+ if(buf->_rp + (count + BUF_DELTA) < buf->_dt->end)
+ return;
+
+ /* Now when in joins we let it go closer */
+ if(BUF_IN_JOIN(buf) && (buf->_rp + count < buf->_dt->end))
+ return;
+
+ /* Okay now we know we have to extend */
+ allocated = buf->_dt->end - (char*)(buf->_dt);
+ ASSERT(allocated > 0 && (allocated % BUF_INITIAL) == 0);
+
+ /* Enlarge the size as much as needed */
+ do
+ {
+ allocated *= 2;
+ }
+ while(allocated < count);
+
+ ASSERT(sizeof(internal_t) < allocated);
+ intl = (internal_t*)malloc(allocated);
+ if(!intl)
+ {
+ ha_messagex(LOG_CRIT, "out of memory");
+ buf->_dt = NULL;
+ buf->_pp = buf->_rp = NULL;
+ return;
+ }
+ else
{
- char* old = buf->_dt;
- int alloc = buf->_al;
- int diff;
+ void* beg = INTERNAL_DATA(intl);
+ intl->end = ((char*)(intl) + allocated);
+ intl->next = NULL;
- while((buf->_al + count) > alloc)
- alloc *= 2;
+#ifdef _DEBUG
+ FILL_BETWEEN(beg, intl->end, 0xCD);
+#endif
- buf->_dt = (char*)reallocf(buf->_dt, alloc * sizeof(char));
- if(!buf->_dt)
+ if(BUF_IN_JOIN(buf))
{
- buf->_al = 0;
- buf->_rp = buf->_pp = NULL;
- ha_messagex(LOG_CRIT, "out of memory");
- return;
- }
+ int diff = buf->_rp - buf->_pp;
+
+ /* Always true in a join */
+ ASSERT(buf->_pp < buf->_rp);
- buf->_al = alloc;
+ /* Copy the memory and blank out old */
+ memcpy(beg, buf->_pp, diff);
+#ifdef _DEBUG
+ FILL_BETWEEN(buf->_pp, buf->_rp, 0xDD);
+#endif
+
+ buf->_pp = beg;
+ buf->_rp = buf->_pp + diff;
+ }
+ else
+ {
+ buf->_rp = buf->_pp = INTERNAL_DATA(intl);
+ }
- diff = buf->_dt - old;
- buf->_rp += diff;
- buf->_pp += diff;
+ buf->_dt->next = intl;
+ buf->_dt = intl;
}
}
@@ -53,39 +115,57 @@ void ha_bufinit(ha_buffer_t* buf)
{
ASSERT(buf);
memset(buf, 0, sizeof(*buf));
- ha_bufreset(buf);
+
+ ASSERT(BUF_INITIAL > sizeof(internal_t));
+ buf->_ft = (internal_t*)malloc(BUF_INITIAL);
+ if(buf->_ft)
+ {
+ buf->_ft->end = ((char*)(buf->_ft) + BUF_INITIAL);
+ buf->_ft->next = NULL;
+
+#ifdef _DEBUG
+ FILL_BETWEEN(INTERNAL_DATA(buf->_ft), buf->_ft->end, 0xCD);
+#endif
+
+ ha_bufreset(buf);
+ }
}
void ha_bufreset(ha_buffer_t* buf)
{
- ASSERT(buf);
+#ifdef _DEBUG
+ internal_t* intl;
+#endif
- if(!buf->_dt || buf->_al == 0)
- {
- buf->_dt = (char*)reallocf(buf->_dt, 256 * sizeof(char));
- if(!buf->_dt)
- {
- buf->_al = 0;
- buf->_rp = buf->_pp = NULL;
- ha_messagex(LOG_CRIT, "out of memory");
- return;
- }
+ ASSERT(buf);
+ ASSERT(buf->_ft);
- buf->_al = 256;
- }
+#ifdef _DEBUG
+ /* Go through all the buffers and set them to 0xCD */
+ for(intl = buf->_ft; intl; intl = intl->next)
+ FILL_BETWEEN(INTERNAL_DATA(intl), intl->end, 0xCD);
+#endif
- buf->_rp = buf->_dt;
- buf->_pp = buf->_dt;
+ buf->_dt = buf->_ft;
+ buf->_rp = buf->_pp = (char*)INTERNAL_DATA(buf->_ft);
}
void ha_buffree(ha_buffer_t* buf)
{
+ internal_t* intl;
+ internal_t* next;
+
ASSERT(buf);
- if(buf->_dt)
- free(buf->_dt);
+ /* Go through free all the buffers and set them to 0xDD */
+ for(intl = buf->_ft; intl; intl = next)
+ {
+ next = intl->next;
+ FILL_BETWEEN(INTERNAL_DATA(intl), intl->end, 0xDD);
+ free(intl);
+ }
- buf->_al = 0;
+ buf->_ft = buf->_dt = NULL;
buf->_rp = buf->_pp = NULL;
}
@@ -258,9 +338,8 @@ char* ha_bufmcat(ha_buffer_t* buf, ...)
if(ha_buferr(buf))
return NULL;
- /* Move up the block pointer if we're not joining strings */
- if(ha_buflen(buf) > 0 && *(buf->_rp - 1) != 0)
- buf->_pp = buf->_rp;
+ if(!BUF_IN_JOIN(buf))
+ BUF_NEW_BLOCK(buf);
while((str = va_arg(ap, char*)) != NULL)
{
@@ -298,16 +377,15 @@ char* ha_bufncpy(ha_buffer_t* buf, const char* src, size_t len)
if(ha_buferr(buf))
return NULL;
- /* Move up the block pointer if we're not joining strings */
- if(ha_buflen(buf) > 0 && *(buf->_rp - 1) != 0)
- buf->_pp = buf->_rp;
-
/* Always add one for the terminating char */
buffer_bump(buf, len + 1);
if(ha_buferr(buf))
return NULL;
+ if(!BUF_IN_JOIN(buf))
+ BUF_NEW_BLOCK(buf);
+
memcpy(buf->_rp, src, len * sizeof(char));
buf->_rp += (len + 1);
*(buf->_rp - 1) = 0;
@@ -324,17 +402,16 @@ void* ha_bufmalloc(ha_buffer_t* buf, size_t sz)
return NULL;
/* TODO: Align memory on an appropriate boundary here */
-
- /* We're not working with strings so always bump the pointer up */
- buf->_pp = buf->_rp;
-
buffer_bump(buf, sz);
if(ha_buferr(buf))
return NULL;
+ BUF_NEW_BLOCK(buf);
+ ret = (void*)buf->_pp;
buf->_rp += sz;
- return (void*)buf->_pp;
+ buf->_pp = buf->_rp;
+ return ret;
}
void* ha_bufmemdup(ha_buffer_t* buf, const void* src, size_t bytes)
@@ -390,6 +467,9 @@ char* ha_bufenc64(ha_buffer_t* buf, const void* source, size_t len)
if(ha_buferr(buf))
return NULL;
+ if(!BUF_IN_JOIN(buf))
+ BUF_NEW_BLOCK(buf);
+
while(2 < len)
{
input[0] = *src++;
@@ -450,6 +530,7 @@ void* ha_bufdec64(ha_buffer_t* buf, const char* src, size_t bytes)
int state = 0;
int ch;
char* pos;
+ void* ret;
size_t done = 0;
ASSERT(buf && src);
@@ -457,6 +538,8 @@ void* ha_bufdec64(ha_buffer_t* buf, const char* src, size_t bytes)
if(ha_buferr(buf))
return NULL;
+ BUF_NEW_BLOCK(buf);
+
if(bytes == 0)
bytes = ~0;
@@ -472,7 +555,7 @@ void* ha_bufdec64(ha_buffer_t* buf, const char* src, size_t bytes)
if(pos == 0) /* A non-base64 character. */
break;
- buffer_bump(buf, 3);
+ buffer_bump(buf, 4);
if(ha_buferr(buf))
return;
@@ -480,8 +563,7 @@ void* ha_bufdec64(ha_buffer_t* buf, const char* src, size_t bytes)
switch(state)
{
case 0:
- *(buf->_rp++) = (pos - BASE64C) << 2;
- done++;
+ *(buf->_rp) = (pos - BASE64C) << 2;
state = 1;
break;
@@ -505,18 +587,23 @@ void* ha_bufdec64(ha_buffer_t* buf, const char* src, size_t bytes)
state = 0;
break;
};
-
- /* TODO: Validate ending and return error if invalid somehow */
}
+ if(state != 3)
+ buf->_rp++;
+
+ /* TODO: Validate ending and return error if invalid somehow */
+
/* If we were asked for a specific amount of bytes, then return null */
if(bytes != ~0 && bytes != done)
return NULL;
- return buf->_pp;
+ ret = (void*)buf->_pp;
+ buf->_pp = buf->_rp;
+ return ret;
}
-static const char HEXC[] = "0123456789ABCDEF";
+static const char HEXC[] = "0123456789abcdef";
char* ha_bufenchex(ha_buffer_t* buf, const void* source, size_t len)
{
@@ -530,21 +617,18 @@ char* ha_bufenchex(ha_buffer_t* buf, const void* source, size_t len)
if(ha_buferr(buf))
return NULL;
+ if(!BUF_IN_JOIN(buf))
+ BUF_NEW_BLOCK(buf);
+
while(len > 0)
{
j = *(src) >> 4 & 0xf;
- if(j <= 9)
- *(buf->_rp++) = (j + '0');
- else
- *(buf->_rp++) = (j + 'a' - 10);
+ *(buf->_rp++) = HEXC[j];
j = *(src++) & 0xf;
- len--;
+ *(buf->_rp++) = HEXC[j];
- if(j <= 9)
- *(buf->_rp++) = (j + '0');
- else
- *(buf->_rp++) = (j + 'a' - 10);
+ len--;
}
*(buf->_rp++) = 0;
@@ -553,10 +637,11 @@ char* ha_bufenchex(ha_buffer_t* buf, const void* source, size_t len)
void* ha_bufdechex(ha_buffer_t* buf, const char* src, size_t bytes)
{
- unsigned short a;
- unsigned short b;
+ unsigned short j;
size_t done = 0;
+ int state = 0;
char* pos;
+ void* ret;
ASSERT(buf && src);
@@ -573,29 +658,41 @@ void* ha_bufdechex(ha_buffer_t* buf, const char* src, size_t bytes)
if(ha_buferr(buf))
return NULL;
- while(src[0] && src[1] && done < bytes)
+ BUF_NEW_BLOCK(buf);
+
+ while(src[0] && done < bytes)
{
/* Find the position */
- pos = strchr(HEXC, src[0]);
+ pos = strchr(HEXC, tolower(src[0]));
if(pos == 0)
break;
- a = HEXC - pos;
-
- pos = strchr(HEXC, src[1]);
- if(pos == 0);
- break;
+ j = pos - HEXC;
- b = HEXC - pos;
+ if(!state)
+ {
+ *(buf->_rp) = (j & 0xf) << 4;
+ state = 1;
+ }
+ else
+ {
+ *(buf->_rp++) |= (j & 0xf);
+ done++;
+ state = 0;
+ }
- *(buf->_rp++) = ((a & 0xf) << 4) | (b & 0xf);
- src += 2;
- done++;
+ src++;
}
+ /* All bytes have to come in pairs */
+ if(state != 0)
+ return NULL;
+
/* If we were asked for a specific amount of bytes, then return null */
if(bytes != ~0 && bytes != done)
return NULL;
- return buf->_pp;
+ ret = (void*)buf->_pp;
+ buf->_pp = buf->_rp;
+ return ret;
}
diff --git a/common/compat.c b/common/compat.c
index 6a4b914..5618ee5 100644
--- a/common/compat.c
+++ b/common/compat.c
@@ -28,3 +28,16 @@ char* strlwr(char* s)
return s;
}
#endif
+
+#ifndef HAVE_STRUPR
+char* strupr(char* s)
+{
+ char* t = s;
+ while(*t)
+ {
+ *t = toupper(*t);
+ t++;
+ }
+ return s;
+}
+#endif
diff --git a/common/compat.h b/common/compat.h
index c250db1..bb7311c 100644
--- a/common/compat.h
+++ b/common/compat.h
@@ -36,5 +36,8 @@ void* reallocf(void* p, size_t sz);
char* strlwr(char* s);
#endif
+#ifndef HAVE_STRUPR
+char* strupr(char* s);
+#endif
#endif /* _COMPAT_H_ */
diff --git a/configure.in b/configure.in
index 2abbf10..6ab2633 100644
--- a/configure.in
+++ b/configure.in
@@ -57,7 +57,8 @@ AC_ARG_ENABLE(debug,
[Compile binaries in debug mode]))
if test "$enable_debug" = "yes"; then
- CFLAGS="$CFLAGS -g -O0 -D_DEBUG=1"
+ CFLAGS="$CFLAGS -g -O0"
+ AC_DEFINE_UNQUOTED(_DEBUG, 1, [In debug mode])
echo "enabling debug compile mode"
fi
diff --git a/daemon/digest.c b/daemon/digest.c
index 79b4ff3..099ca49 100644
--- a/daemon/digest.c
+++ b/daemon/digest.c
@@ -87,16 +87,13 @@ digest_record_t* digest_makerec(unsigned char* nonce, const char* user)
return rec;
}
-const char* digest_challenge(ha_buffer_t* buf, unsigned char* nonce,
+const char* digest_challenge(ha_buffer_t* buf, const char* nonce_str,
const char* realm, const char* domains, int stale)
{
- ASSERT(buf && realm && nonce);
+ ASSERT(buf && realm && nonce_str);
- ha_bufmcat(buf, HA_PREFIX_DIGEST, " realm=\"", realm, "\", nonce=\"", NULL);
- ha_bufjoin(buf);
- ha_bufenc64(buf, nonce, DIGEST_NONCE_LEN);
- ha_bufjoin(buf);
- ha_bufmcat(buf, "\", qop=\"auth\", algorithm=\"MD5\"", NULL);
+ ha_bufmcat(buf, HA_PREFIX_DIGEST, " realm=\"", realm, "\", nonce=\"",
+ nonce_str, "\", qop=\"auth\", algorithm=\"MD5\"", NULL);
if(domains)
{
@@ -143,7 +140,7 @@ int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec,
if(!header)
return HA_ERROR;
- memset(rec, 0, sizeof(rec));
+ memset(rec, 0, sizeof(*rec));
while(header[0])
{
@@ -178,8 +175,6 @@ int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec,
if(next == '=')
{
- header++;
-
while(header[0] && isspace(header[0]))
header++;
@@ -191,6 +186,7 @@ int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec,
while(header[0] && header[0] != '\"')
header++;
+ next = header[0];
header[0] = 0;
header++;
}
@@ -202,15 +198,19 @@ int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec,
while(header[0] && header[0] != ',' && !isspace(header[0]))
header++;
+ next = header[0];
header[0] = 0;
header++;
}
- while(header[0] && header[0] != ',')
- header++;
+ if(next != ',')
+ {
+ while(header[0] && header[0] != ',')
+ header++;
- if(header[0])
- header++;
+ if(header[0])
+ header++;
+ }
if(!strcasecmp(key, "username"))
rec->username = value;
@@ -320,7 +320,7 @@ int digest_check(const char* realm, const char* method, const char* uri,
char* e;
long nc = strtol(dg->nc, &e, 10);
- if(e != (dg->nc + strlen(e)) || nc != rec->nc)
+ if(*e || nc != rec->nc)
{
ha_messagex(LOG_WARNING, "digest response has invalid nc value: %s",
dg->nc);
@@ -455,6 +455,9 @@ const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg,
ASSERT(buf && dg && rec);
+ /* This makes a new buffer */
+ ha_bufcpy(buf, "");
+
if(next)
{
nextnonce = ha_bufenc64(buf, next, DIGEST_NONCE_LEN);
@@ -464,7 +467,7 @@ const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg,
}
/* For older clients RFC 2069 */
- if(dg->qop)
+ if(!dg->qop)
{
if(nextnonce)
ha_bufmcat(buf, "nextnonce=\"", nextnonce, "\"", NULL);
diff --git a/daemon/digest.h b/daemon/digest.h
index 6bd7acc..0f5e6b2 100644
--- a/daemon/digest.h
+++ b/daemon/digest.h
@@ -48,7 +48,7 @@ int ha_digestcheck(const char* realm, const char* method, const char* uri,
const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg,
digest_record_t* rec, unsigned char* next);
-const char* digest_challenge(ha_buffer_t* buf, unsigned char* nonce,
+const char* digest_challenge(ha_buffer_t* buf, const char* nonce_str,
const char* realm, const char* domains, int stale);
void digest_makeha1(unsigned char* digest, const char* user,
diff --git a/daemon/httpauthd.c b/daemon/httpauthd.c
index a2985a3..465ac68 100644
--- a/daemon/httpauthd.c
+++ b/daemon/httpauthd.c
@@ -68,7 +68,7 @@ const char* kAuthHeaders[] =
/* The command definitions */
const httpauth_command_t kCommands[] =
{
- { "auth", REQTYPE_AUTH, 3, kAuthHeaders },
+ { "auth", REQTYPE_AUTH, 4, kAuthHeaders },
{ "quit", REQTYPE_QUIT, 0, 0 },
{ NULL, -1, -1 }
};
@@ -434,6 +434,12 @@ int httpauth_read(int ifd, ha_request_t* req,
}
}
+ else
+ {
+ req->type = REQTYPE_IGNORE;
+ return more;
+ }
+
/* Check for invalid command */
if(req->type == -1)
return more;
@@ -734,6 +740,8 @@ int httpauth_processor(int ifd, int ofd)
result = 0;
break;
+ case REQTYPE_IGNORE:
+ break;
default:
if(httpauth_respond(ofd, HA_SERVER_BADREQ, "Unknown command") == -1)
diff --git a/daemon/httpauthd.h b/daemon/httpauthd.h
index 55a4d90..7f51895 100644
--- a/daemon/httpauthd.h
+++ b/daemon/httpauthd.h
@@ -6,11 +6,13 @@
* Memory Buffers
*/
+struct ha_buffer_internal;
+
/* A buffer which owns memory */
typedef struct ha_buffer
{
- int _al;
- char* _dt;
+ struct ha_buffer_internal* _ft;
+ struct ha_buffer_internal* _dt;
char* _pp;
char* _rp;
}
@@ -191,7 +193,7 @@ ha_context_t;
* should be no need to change it unless we're
* adding or removing commands
*/
-#define MAX_ARGS 6
+#define MAX_ARGS 4
/*
* The maximum number of pertinent headers to read
@@ -222,9 +224,9 @@ ha_header_t;
#define REQTYPE_QUIT 1
#define REQTYPE_AUTH 2
-#define AUTH_ARG_CONN 0
-#define AUTH_ARG_METHOD 1
-#define AUTH_ARG_URI 2
+#define AUTH_ARG_CONN 1
+#define AUTH_ARG_METHOD 2
+#define AUTH_ARG_URI 3
/* A single request from client */
typedef struct ha_request
diff --git a/daemon/ldap.c b/daemon/ldap.c
index 2474d09..440c531 100644
--- a/daemon/ldap.c
+++ b/daemon/ldap.c
@@ -920,15 +920,20 @@ static int digest_ldap_challenge(ldap_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_ldap_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;
diff --git a/daemon/misc.c b/daemon/misc.c
index c3f5ff4..9dba389 100644
--- a/daemon/misc.c
+++ b/daemon/misc.c
@@ -208,8 +208,7 @@ int ha_confint(const char* name, const char* conf, int min, int max, int* value)
errno = 0;
*value = strtol(conf, &p, 10);
- if(p != (name + strlen(name)) || errno == ERANGE ||
- (*value < min) || (*value > max))
+ if(*p || errno == ERANGE || (*value < min) || (*value > max))
{
ha_messagex(LOG_ERR, "invalid configuration value '%s': must be a number between %d and %d", name, min, max);
return HA_ERROR;
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 */
};
diff --git a/sample/httpauthd.conf b/sample/httpauthd.conf
index a296c36..4c97858 100644
--- a/sample/httpauthd.conf
+++ b/sample/httpauthd.conf
@@ -3,9 +3,10 @@
# and blank lines
MaxThreads: 18
CacheTimeout: 300
-AuthTypes: NTLM
+AuthTypes: Basic Digest
[Simple]
Realm: blah
PasswordFile: /data/projects/httpauth/sample/passwd.file
+DigestDebugNonce: AkCLQA==560f26e24db2d4cecbe5d6e24d958377ab73def9