From bbcee9aa65b4cf698fa1f8d1f7c9cb8983dd5fd5 Mon Sep 17 00:00:00 2001 From: helge Date: Mon, 30 Jan 2006 16:37:36 +0000 Subject: [PATCH] fixed OGo bug #995, ActiveDirectory binds with umlauts git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1208 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-ldap/NGLdap/ChangeLog | 6 ++ sope-ldap/NGLdap/NGLdapConnection.m | 140 +++++++++++++++++----------- sope-ldap/NGLdap/Version | 2 +- 3 files changed, 92 insertions(+), 56 deletions(-) diff --git a/sope-ldap/NGLdap/ChangeLog b/sope-ldap/NGLdap/ChangeLog index 2c218331..5f653129 100644 --- a/sope-ldap/NGLdap/ChangeLog +++ b/sope-ldap/NGLdap/ChangeLog @@ -1,3 +1,9 @@ +2006-01-30 Helge Hess + + * NGLdapConnection.m: set LDAP options prior performing a bind. Default + to UTF-8 credentials (can be changed back to Latin1 using the + LDAPUseLatin1Creds default). This should fix OGo bug #995 (v4.5.28) + 2005-11-17 Helge Hess * NGLdapURL.m: properly include string.h to avoid a warning (v4.5.27) diff --git a/sope-ldap/NGLdap/NGLdapConnection.m b/sope-ldap/NGLdap/NGLdapConnection.m index 6634ade9..b791632f 100644 --- a/sope-ldap/NGLdap/NGLdapConnection.m +++ b/sope-ldap/NGLdap/NGLdapConnection.m @@ -34,7 +34,7 @@ static NSString *LDAPInitialBindDN = @"" ; static NSString *LDAPInitialBindPW = @"" ; /* this is required by SuSE EMail Server III */ -#define ISOLATIN1_CREDENTIALS 1 +static BOOL LDAPUseLatin1Creds = NO; @interface NGLdapConnection(Privates) - (BOOL)_reinit; @@ -81,19 +81,32 @@ static void freeMods(LDAPMod **mods) { LDAPInitialBindSpecific = [ud boolForKey:@"LDAPInitialBindSpecific"]; LDAPInitialBindDN = [[ud stringForKey:@"LDAPInitialBindDN"] copy]; LDAPInitialBindPW = [[ud stringForKey:@"LDAPInitialBindPW"] copy]; + LDAPUseLatin1Creds = [ud boolForKey:@"LDAPUseLatin1Creds"]; } - (BOOL)_reinit { - if (self->handle) { + static int ldap_version3 = LDAP_VERSION3; + int rc; + + if (self->handle != NULL) { ldap_unbind(self->handle); self->handle = NULL; } self->handle = ldap_init((char *)[self->hostName cString], self->port); - if (self->handle == NULL) return NO; - + + /* setup options (must be done before the bind) */ + rc = + ldap_set_option(self->handle, LDAP_OPT_PROTOCOL_VERSION, &ldap_version3); + if (rc != LDAP_OPT_SUCCESS) + [self logWithFormat:@"WARN: could not set protocol version to LDAPv3!"]; + + rc = ldap_set_option(self->handle, LDAP_OPT_REFERRALS, LDAP_OPT_OFF) ; + if (rc != LDAP_OPT_SUCCESS) + [self logWithFormat:@"Note: could not disable LDAP referrals."]; + return YES; } @@ -116,7 +129,7 @@ static void freeMods(LDAPMod **mods) { } - (void)dealloc { - if (self->handle) { + if (self->handle != NULL) { if ([self isBound]) [self unbind]; else { @@ -223,10 +236,9 @@ static void freeMods(LDAPMod **mods) { - (BOOL)bindWithMethod:(NSString *)_method binddn:(NSString *)_login credentials:(NSString *)_cred { - int ldap_version3 = LDAP_VERSION3 ; int method, err; const char *l, *p; - + if (self->handle == NULL) [self _reinit]; @@ -244,18 +256,15 @@ static void freeMods(LDAPMod **mods) { return NO; l = (char *)[_login UTF8String]; -#if ISOLATIN1_CREDENTIALS - p = (char *)[_cred cString]; -#else - p = (char *)[_cred UTF8String]; -#endif + p = LDAPUseLatin1Creds + ? (char *)[_cred cString] + : (char *)[_cred UTF8String]; + err = (method == LDAP_AUTH_SIMPLE) ? ldap_simple_bind_s(self->handle, l, p) : ldap_bind_s(self->handle, l, p, method); if (err == LDAP_SUCCESS) { - ldap_set_option(self->handle, LDAP_OPT_PROTOCOL_VERSION, &ldap_version3) ; - ldap_set_option(self->handle, LDAP_OPT_REFERRALS, LDAP_OPT_OFF) ; self->flags.isBound = YES; return YES; } @@ -287,23 +296,25 @@ static void freeMods(LDAPMod **mods) { if ((filter = [_q ldapFilterString]) == nil) filter = @"(objectclass=*)"; - if (_attributes) { + if (_attributes != nil) { unsigned i, acount; acount = [_attributes count]; - attrs = calloc(acount + 1, sizeof(char *)); + attrs = calloc(acount + 3, sizeof(char *)); for (i = 0; i < acount; i++) attrs[i] = (char *)[[_attributes objectAtIndex:i] UTF8String]; + attrs[i] = NULL; } else attrs = NULL; - if (LDAPDebugEnabled) + if (LDAPDebugEnabled) { printf("%s: search with at base %s filter %s for attrs %s\n", __PRETTY_FUNCTION__, [_base cString], [filter cString], [[_attributes description] cString]); - + } + msgid = ldap_search(self->handle, (char *)[_base UTF8String], _scope, @@ -312,9 +323,7 @@ static void freeMods(LDAPMod **mods) { 0); /* free attributes */ - if (attrs) { - free(attrs); attrs = NULL; - } + if (attrs != NULL) free(attrs); attrs = NULL; if (msgid == -1) { /* trouble */ @@ -368,10 +377,10 @@ static void freeMods(LDAPMod **mods) { entry = [e nextObject]; - if ([e nextObject]) { - NSLog(@"more than one search results in base search !!!"); + if ([e nextObject] != nil) { + [self logWithFormat:@"WARN: more than one search results in base search!"]; /* consume all entries */ - while ([e nextObject]) + while ([e nextObject] != nil) // TODO: can't we cancel the request? ; } @@ -795,16 +804,16 @@ static void freeMods(LDAPMod **mods) { return s; } -@end /* NGLdapConnection */ - -@implementation NGLdapConnection(PlainPasswordCheck) +/* PlainPasswordCheck */ + (NSString *)uidAttributeName { static NSString *uidAttr = nil; if (uidAttr == nil) { - uidAttr = [[[NSUserDefaults standardUserDefaults] - stringForKey:@"LDAPLoginAttributeName"] copy]; - if ([uidAttr length] == 0) uidAttr = @"uid"; + // TODO: can't we do this in +initialize? (maybe not if setup later by OGo) + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; + + uidAttr = [[ud stringForKey:@"LDAPLoginAttributeName"] copy]; + if (![uidAttr isNotEmpty]) uidAttr = @"uid"; } return uidAttr; } @@ -831,14 +840,28 @@ static void freeMods(LDAPMod **mods) { } if (![self isBound]) { didBind = NO; - if (LDAPDebugEnabled) - [self logWithFormat:@" attempt to do a simple, anonymous bind .."]; - NS_DURING - if (LDAPInitialBindSpecific) - didBind = [self bindWithMethod:@"simple" binddn:LDAPInitialBindDN credentials:LDAPInitialBindPW]; - else + NS_DURING { + if (LDAPInitialBindSpecific) { + // TODO: can't we just check whether the DN is set? + if (LDAPDebugEnabled) { + [self logWithFormat: + @" attempt to do a simple, authenticated bind " + @"(dn=%@,pwd=%s) ..", + LDAPInitialBindDN, + [LDAPInitialBindPW length] > 0 ? "yes":"no"]; + } + + didBind = [self bindWithMethod:@"simple" binddn:LDAPInitialBindDN + credentials:LDAPInitialBindPW]; + } + else { + if (LDAPDebugEnabled) + [self logWithFormat:@" attempt to do a simple, anonymous bind .."]; + didBind = [self bindWithMethod:@"simple" binddn:@"" credentials:@""]; + } + } NS_HANDLER didBind = NO; NS_ENDHANDLER; @@ -851,11 +874,14 @@ static void freeMods(LDAPMod **mods) { didBind = YES; if (LDAPDebugEnabled) [self logWithFormat:@" bound."]; } + filter = [NSString stringWithFormat:@"(%@=%@)", [[self class] uidAttributeName], _login]; - if (LDAPDebugEnabled) [self logWithFormat:@" search: '%@'", filter]; + if (LDAPDebugEnabled) + [self logWithFormat:@" search: uid='%@': '%@'", _login, filter]; + /* we only check the DN anyway .. */ attrs[0] = "objectclass"; attrs[1] = NULL; @@ -866,14 +892,15 @@ static void freeMods(LDAPMod **mods) { (char *)[filter UTF8String], attrs, 1, &result) ; - if ((ldap_search_result != LDAP_SUCCESS) && (ldap_search_result != LDAP_PARTIAL_RESULTS)) { + if ((ldap_search_result != LDAP_SUCCESS) && + (ldap_search_result != LDAP_PARTIAL_RESULTS)) { /* search failed */ if (didBind) [self unbind]; - if (LDAPDebugEnabled) { + if (LDAPDebugEnabled) [self logWithFormat:@" search failed"]; - } + return nil; } @@ -898,11 +925,12 @@ static void freeMods(LDAPMod **mods) { /* get DN of first entry */ if ((dn = ldap_get_dn(self->handle, entry)) == NULL) { - /* couldn't get DN */ + /* could not get DN */ if (didBind) [self unbind]; if (LDAPDebugEnabled) [self logWithFormat:@" got no DN for entry !"]; return nil; } + strDN = nil; NS_DURING { strDN = [[[NSString alloc] initWithUTF8String:dn] autorelease]; @@ -917,20 +945,21 @@ static void freeMods(LDAPMod **mods) { if (strDN == nil) { if (LDAPDebugEnabled) { - [self debugWithFormat: + [self logWithFormat: @"could not convert DN to UTF-8 string, try cString .."]; } strDN = [[[NSString alloc] initWithCString:dn] autorelease]; } - free(dn); dn = NULL; + if (dn != NULL) free(dn); dn = NULL; - if (result) { + if (result != NULL) { ldap_msgfree(result); } [self unbind]; - if (LDAPDebugEnabled) { + + if (LDAPDebugEnabled) [self logWithFormat:@" return DN %@", strDN]; - } + return strDN; } @@ -955,19 +984,20 @@ static void freeMods(LDAPMod **mods) { } strDN = [self dnForLogin:_login baseDN:_baseDN]; - if (LDAPDebugEnabled) { - [self logWithFormat:@" attempting to bind login %@ DN: %@ %s!", - _login, strDN, - [_pwd length] > 0 ? "(with password) " : "(empty password) "]; - } - - if (!strDN) { + if ([strDN length] == 0) { if (LDAPDebugEnabled) { [self logWithFormat:@" missing dn for login %@ atBaseDN %@", _login, _baseDN]; } return NO; } + + if (LDAPDebugEnabled) { + [self logWithFormat:@" attempting to bind login %@ DN: %@ %s!", + _login, strDN, + [_pwd length] > 0 ? "(with password) " : "(empty password) "]; + } + /* Now bind as the DN with the password supplied earlier... Successful bind means the password was correct, otherwise the @@ -986,7 +1016,7 @@ static void freeMods(LDAPMod **mods) { if (!didBind) { /* invalid login or password */ if (LDAPDebugEnabled) - [self logWithFormat:@" could not simple bind DN '%@' !", strDN]; + [self logWithFormat:@" simple bind failed for DN: '%@'", strDN]; [self unbind]; return NO; @@ -1023,4 +1053,4 @@ static void freeMods(LDAPMod **mods) { return [ldap checkPassword:_pwd ofLogin:_login atBaseDN:_baseDN]; } -@end /* NGLdapConnection(PlainPasswordCheck) */ +@end /* NGLdapConnection */ diff --git a/sope-ldap/NGLdap/Version b/sope-ldap/NGLdap/Version index aee3f1fb..fdf3cd94 100644 --- a/sope-ldap/NGLdap/Version +++ b/sope-ldap/NGLdap/Version @@ -2,4 +2,4 @@ MAJOR_VERSION=4 MINOR_VERSION=5 -SUBMINOR_VERSION:=27 +SUBMINOR_VERSION:=28 -- 2.39.5