summaryrefslogtreecommitdiff
path: root/daemon/ldap.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/ldap.c')
-rw-r--r--daemon/ldap.c176
1 files changed, 74 insertions, 102 deletions
diff --git a/daemon/ldap.c b/daemon/ldap.c
index 719ac0d..1df7651 100644
--- a/daemon/ldap.c
+++ b/daemon/ldap.c
@@ -72,13 +72,15 @@ typedef struct ldap_context
ldap_context_t;
/* Forward declarations for callbacks */
-static int complete_digest(ha_request_t* rq, const char* user, unsigned char* ha1);
+static int validate_digest(ha_request_t* rq, const char* user, digest_context_t* dg);
static int validate_basic(ha_request_t* rq, const char* user, const char* password);
+static void escape_ldap(const ha_request_t* rq, ha_buffer_t* buf, const char* value);
/* The defaults for the context */
static const ldap_context_t ldap_defaults =
{
- BD_CALLBACKS(complete_digest, validate_basic),
+ BD_CALLBACKS(validate_digest,
+ validate_basic, escape_ldap),
NULL, /* servers */
NULL, /* filter */
NULL, /* base */
@@ -122,7 +124,7 @@ static int report_ldap(const ha_request_t* rq, const char* msg, int code)
#define LDAP_NO_ESCAPE "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
#define LDAP_HEX "0123456789abcdef"
-static const char* escape_ldap(ha_buffer_t* buf, const char* str)
+static void escape_ldap(const ha_request_t* rq, ha_buffer_t* buf, const char* str)
{
const char* t = str;
size_t pos;
@@ -155,62 +157,8 @@ static const char* escape_ldap(ha_buffer_t* buf, const char* str)
t++;
}
}
-
- return ha_bufdata(buf);
}
-static const char* substitute_params(const ha_request_t* rq, ldap_context_t* ctx,
- const char* user, const char* str)
-{
- const char* t;
-
- ASSERT(ctx && rq && user && str);
-
- /* TODO: We need to be escaping the user and realm properly */
- /* This starts a new block to join */
- ha_bufcpy(rq->buf, "");
-
- while(str[0])
- {
- t = strchr(str, '%');
- if(!t)
- {
- ha_bufjoin(rq->buf);
- ha_bufcpy(rq->buf, str);
- break;
- }
-
- ha_bufjoin(rq->buf);
- ha_bufncpy(rq->buf, str, t - str);
-
- t++;
-
- switch(t[0])
- {
- case 'u':
- ha_bufjoin(rq->buf);
- escape_ldap(rq->buf, user);
- t++;
- break;
-
- case 'r':
- ha_bufjoin(rq->buf);
- escape_ldap(rq->buf, rq->context->realm);
- t++;
- break;
-
- case '%':
- ha_bufjoin(rq->buf);
- ha_bufcpy(rq->buf, "%");
- t++;
- break;
- };
-
- str = t;
- }
-
- return ha_bufdata(rq->buf);
-}
static const char* make_password_md5(ha_buffer_t* buf, const char* clearpw)
{
@@ -280,16 +228,14 @@ static int parse_ldap_password(const char** password)
return LDAP_PW_UNKNOWN;
}
-static const char* find_cleartext_password(ha_buffer_t* buf, const char** pws)
+static const char** find_cleartext_password(ha_buffer_t* buf, const char** pws)
{
ASSERT(buf);
for(; pws && *pws; pws++)
{
- const char* pw = *pws;
-
- if(parse_ldap_password(&pw) == LDAP_PW_CLEAR)
- return pw;
+ if(parse_ldap_password(pws) == LDAP_PW_CLEAR)
+ return pws;
}
return NULL;
@@ -478,12 +424,14 @@ static LDAP* get_ldap_connection(const ha_request_t* rq, ldap_context_t* ctx)
ASSERT(ctx);
+ /* TODO: What about multiple threads here? */
+
for(i = 0; i < ctx->ldap_max; i++)
{
/* An open connection in the pool */
if(ctx->pool[i])
{
- ha_messagex(rq, LOG_DEBUG, "using cached connection");
+ ha_messagex(rq, LOG_DEBUG, "using cached LDAP connection");
ld = ctx->pool[i];
ctx->pool[i] = NULL;
return ld;
@@ -492,14 +440,14 @@ static LDAP* get_ldap_connection(const ha_request_t* rq, ldap_context_t* ctx)
if(ctx->pool_mark >= ctx->ldap_max)
{
- ha_messagex(rq, LOG_ERR, "too many open connections");
+ ha_messagex(rq, LOG_ERR, "too many open LDAP connections");
return NULL;
}
ld = ldap_init(ctx->servers, ctx->port);
if(!ld)
{
- ha_message(rq, LOG_ERR, "couldn't initialize connection");
+ ha_message(rq, LOG_ERR, "couldn't initialize LDAP connection");
return NULL;
}
@@ -544,7 +492,6 @@ static void save_ldap_connection(const ha_request_t* rq, ldap_context_t* ctx, LD
case LDAP_SERVER_DOWN:
case LDAP_LOCAL_ERROR:
case LDAP_NO_MEMORY:
- discard_ldap_connection(rq, ctx, ld);
break;
default:
@@ -553,7 +500,7 @@ static void save_ldap_connection(const ha_request_t* rq, ldap_context_t* ctx, LD
/* An open connection in the pool */
if(!ctx->pool[i])
{
- ha_messagex(rq, LOG_DEBUG, "caching connection for later use");
+ ha_messagex(rq, LOG_DEBUG, "caching ldap connection for later use");
ctx->pool[i] = ld;
ld = NULL;
break;
@@ -561,6 +508,9 @@ static void save_ldap_connection(const ha_request_t* rq, ldap_context_t* ctx, LD
}
break;
};
+
+ if(ld != NULL)
+ discard_ldap_connection(rq, ctx, ld);
}
static int retrieve_user_entry(const ha_request_t* rq, ldap_context_t* ctx, LDAP* ld,
@@ -579,7 +529,7 @@ static int retrieve_user_entry(const ha_request_t* rq, ldap_context_t* ctx, LDAP
if(ctx->filter)
{
/* Filters can also have %u and %r */
- filter = substitute_params(rq, ctx, user, ctx->filter);
+ filter = bd_substitute(rq, user, ctx->filter);
if(!filter)
return HA_CRITERROR;
}
@@ -639,19 +589,20 @@ static int retrieve_user_entry(const ha_request_t* rq, ldap_context_t* ctx, LDAP
return HA_FALSE;
}
-static int complete_digest(ha_request_t* rq, const char* user, unsigned char* ha1)
+static int validate_digest(ha_request_t* rq, const char* user, digest_context_t* dg)
{
ldap_context_t* ctx = (ldap_context_t*)rq->context->ctx_data;
LDAP* ld = NULL; /* freed in finally */
LDAPMessage* results = NULL; /* freed in finally */
LDAPMessage* entry = NULL; /* no need to free */
struct berval** ha1s = NULL; /* freed manually */
- char** pws;
+ const char** pws;
int ret = HA_FALSE;
const char* dn = NULL;
int r;
+ int foundany = 0;
- ASSERT(rq && ha1 && user);
+ ASSERT(rq && dg && user);
ld = get_ldap_connection(rq, ctx);
if(!ld)
@@ -668,7 +619,7 @@ static int complete_digest(ha_request_t* rq, const char* user, unsigned char* ha
if(ctx->dnmap)
{
/* The map can have %u and %r to denote user and realm */
- dn = substitute_params(rq, ctx, user, ctx->dnmap);
+ dn = bd_substitute(rq, user, ctx->dnmap);
if(!dn)
{
ret = HA_FAILED;
@@ -690,56 +641,77 @@ static int complete_digest(ha_request_t* rq, const char* user, unsigned char* ha
if(ctx->ha1_attr)
ha1s = ldap_get_values_len(ld, entry, ctx->ha1_attr);
- if(ha1s)
+ if(ha1s && *ha1s)
{
- if(*ha1s)
+ int foundinvalid = 0;
+
+ while(*ha1s)
{
- ret = parse_ldap_ha1(rq, *ha1s, ha1);
- if(ret != HA_OK)
+ r = parse_ldap_ha1(rq, *ha1s, dg->ha1);
+
+ if(r == HA_FALSE)
+ {
+ foundinvalid = 1;
+ }
+
+ else if(r == HA_OK)
{
- if(ret == HA_FALSE)
- ha_messagex(rq, LOG_ERR, "server contains invalid HA1 for user: %s", user);
+ foundany = 1;
+
+ /* Run the actual check */
+ ret = digest_complete_check(dg, rq->buf);
+
+ if(ret != HA_FALSE)
+ goto finally;
}
+
+ else if(r < 0)
+ goto finally;
+
+ ha1s++;
}
- ha_messagex(rq, LOG_DEBUG, "using HA1 from ldap");
- ldap_value_free_len(ha1s);
- goto finally;
+ if(foundinvalid)
+ ha_messagex(rq, LOG_ERR, "server contains invalid HA1 for user: %s", user);
}
/* If no ha1 set or none found, use password and make a HA1 */
- pws = ldap_get_values(ld, entry, ctx->pw_attr);
+ pws = (const char**)ldap_get_values(ld, entry, ctx->pw_attr);
- if(pws)
+ if(pws && *pws)
{
/* Find a cleartext password */
- const char* t = find_cleartext_password(rq->buf, (const char**)pws);
-
- if(t)
+ while((pws = find_cleartext_password(rq->buf, pws)))
{
- digest_makeha1(ha1, user, rq->context->realm, t);
- ret = HA_OK;
- }
+ foundany = 1;
- ldap_value_free(pws);
+ digest_makeha1(dg->ha1, user, rq->context->realm, *pws);
- if(ret == HA_OK)
- {
- ha_messagex(rq, LOG_DEBUG, "using clear password from ldap");
- goto finally;
+ /* Run the actual check */
+ ret = digest_complete_check(dg, rq->buf);
+
+ if(ret != HA_FALSE)
+ goto finally;
}
}
- ha_messagex(rq, LOG_ERR, "server contains no clear password or HA1 for user: %s", user);
+ if(!foundany)
+ ha_messagex(rq, LOG_WARNING, "server contains no clear password or HA1 for user: %s", user);
finally:
- if(ld)
- save_ldap_connection(rq, ctx, ld);
+ if(ha1s)
+ ldap_value_free_len(ha1s);
+
+ if(pws)
+ ldap_value_free((char**)pws);
if(results)
ldap_msgfree(results);
+ if(ld)
+ save_ldap_connection(rq, ctx, ld);
+
return ret;
}
@@ -772,7 +744,7 @@ static int validate_basic(ha_request_t* rq, const char* user, const char* passwo
if(ctx->dnmap)
{
/* The map can have %u and %r to denote user and realm */
- dn = substitute_params(rq, ctx, user, ctx->dnmap);
+ dn = bd_substitute(rq, user, ctx->dnmap);
if(!dn)
{
ret = HA_CRITERROR;
@@ -867,12 +839,12 @@ static int validate_basic(ha_request_t* rq, const char* user, const char* passwo
finally:
- if(ld)
- save_ldap_connection(rq, ctx, ld);
-
if(results)
ldap_msgfree(results);
+ if(ld)
+ save_ldap_connection(rq, ctx, ld);
+
/* TODO: Check to make sure this fits within the return values */
return ret;
}
@@ -1015,7 +987,7 @@ int ldap_inithand(ha_context_t* context)
}
memset(ctx->pool, 0, sizeof(LDAP*) * ctx->ldap_max);
- ha_messagex(NULL, LOG_INFO, "initialized handler");
+ ha_messagex(NULL, LOG_INFO, "initialized ldap handler");
}
return HA_OK;