From 86e45cfbd0655193e363be6daadbfd5434566a03 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 12 Aug 2004 00:50:29 +0000 Subject: - Added postgresql database support - Lots of changes to properly abstract bd handlers - Handle multiple passwords and ha1s properly. --- daemon/ldap.c | 176 ++++++++++++++++++++++++---------------------------------- 1 file changed, 74 insertions(+), 102 deletions(-) (limited to 'daemon/ldap.c') 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; -- cgit v1.2.3