2 Copyright (C) 2000-2007 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "NGLdapConnection.h"
23 #include "NGLdapSearchResultEnumerator.h"
24 #include "NGLdapEntry.h"
25 #include "NGLdapAttribute.h"
26 #include "NGLdapModification.h"
27 #include "EOQualifier+LDAP.h"
31 static BOOL LDAPDebugEnabled = NO;
32 static BOOL LDAPInitialBindSpecific = NO;
33 static NSString *LDAPInitialBindDN = @"" ;
34 static NSString *LDAPInitialBindPW = @"" ;
36 /* this is required by SuSE EMail Server III */
37 static BOOL LDAPUseLatin1Creds = NO;
39 @interface NGLdapConnection(Privates)
43 @implementation NGLdapConnection
45 static void freeMods(LDAPMod **mods) {
53 for (i = 0; mods[i] != NULL; i++) {
54 struct berval **values;
57 if ((values = buf[i].mod_bvalues) != NULL) {
60 for (j = 0; values[j] != NULL; j++)
66 if ((type = buf[i].mod_type) != NULL)
75 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
76 static BOOL didInit = NO;
80 LDAPDebugEnabled = [ud boolForKey:@"LDAPDebugEnabled"];
81 LDAPInitialBindSpecific = [ud boolForKey:@"LDAPInitialBindSpecific"];
82 LDAPInitialBindDN = [[ud stringForKey:@"LDAPInitialBindDN"] copy];
83 LDAPInitialBindPW = [[ud stringForKey:@"LDAPInitialBindPW"] copy];
84 LDAPUseLatin1Creds = [ud boolForKey:@"LDAPUseLatin1Creds"];
88 static int ldap_version3 = LDAP_VERSION3;
91 if (self->handle != NULL) {
92 ldap_unbind(self->handle);
96 self->handle = ldap_init((char *)[self->hostName UTF8String], self->port);
97 if (self->handle == NULL)
100 /* setup options (must be done before the bind) */
102 ldap_set_option(self->handle, LDAP_OPT_PROTOCOL_VERSION, &ldap_version3);
103 if (rc != LDAP_OPT_SUCCESS)
104 [self logWithFormat:@"WARN: could not set protocol version to LDAPv3!"];
106 rc = ldap_set_option(self->handle, LDAP_OPT_REFERRALS, LDAP_OPT_OFF) ;
107 if (rc != LDAP_OPT_SUCCESS)
108 [self logWithFormat:@"Note: could not disable LDAP referrals."];
113 - (id)initWithHostName:(NSString *)_hostName port:(int)_port {
114 self->hostName = [_hostName copy];
115 self->port = (_port != 0) ? _port : 389;
117 if (![self _reinit]) {
122 [self setCacheTimeout:120.0];
123 [self setCacheMaxMemoryUsage:16000];
124 [self setQueryTimeLimit:0.0];
125 [self setQuerySizeLimit:0];
129 - (id)initWithHostName:(NSString *)_hostName {
130 return [self initWithHostName:_hostName port:0];
134 if (self->handle != NULL) {
138 // call unbind to free resources
140 err = ldap_unbind(self->handle);
146 [self->hostName release];
152 - (NSString *)hostName {
153 return self->hostName;
161 - (void *)ldapHandle {
167 - (NSException *)_exceptionForErrorCode:(int)_err
168 operation:(NSString *)_operation
169 userInfo:(NSDictionary *)_ui
172 NSString *name, *reason;
174 name = @"LDAPException";
180 case LDAP_INAPPROPRIATE_AUTH:
181 reason = @"inappropriate authorization";
184 case LDAP_INVALID_CREDENTIALS:
185 reason = @"invalid credentials";
188 case LDAP_INSUFFICIENT_ACCESS:
189 reason = @"insufficient access";
192 case LDAP_SERVER_DOWN:
193 reason = @"the server is down";
197 reason = @"the operation timed out";
200 case LDAP_AUTH_UNKNOWN:
201 reason = @"authorization unknown";
204 case LDAP_NOT_ALLOWED_ON_NONLEAF:
205 reason = @"operation not allowed on non-leaf record";
209 reason = [NSString stringWithFormat:
210 @"operation %@ failed with code 0x%X",
215 e = [NSException exceptionWithName:name
225 return self->flags.isBound ? YES : NO;
229 if (self->flags.isBound) {
232 err = ldap_unbind(self->handle);
233 self->flags.isBound = 0;
238 - (BOOL)bindWithMethod:(NSString *)_method
239 binddn:(NSString *)_login credentials:(NSString *)_cred
241 static NSString *loginKey = @"login";
247 if (self->handle == NULL)
250 if ((_method == nil) || ([_method isEqualToString:@"simple"])) {
251 method = LDAP_AUTH_SIMPLE;
253 else if ([_method isEqualToString:@"krbv41"]) {
254 method = LDAP_AUTH_KRBV41;
256 else if ([_method isEqualToString:@"krbv42"]) {
257 method = LDAP_AUTH_KRBV42;
263 l = (char *)[_login UTF8String];
264 p = LDAPUseLatin1Creds
265 ? (char *)[_cred cString]
266 : (char *)[_cred UTF8String];
268 err = (method == LDAP_AUTH_SIMPLE)
269 ? ldap_simple_bind_s(self->handle, l, p)
270 : ldap_bind_s(self->handle, l, p, method);
272 if (err == LDAP_SUCCESS) {
273 self->flags.isBound = YES;
279 if (_login == nil) _login = @"<nil>";
280 ui = [[NSDictionary alloc]
281 initWithObjects:&_login forKeys:&loginKey count:1];
282 e = [self _exceptionForErrorCode:err operation:@"bind" userInfo:ui];
283 [ui release]; ui = nil;
290 /* running queries */
292 - (void)setQueryTimeLimit:(NSTimeInterval)_timeLimit {
293 self->timeLimit = _timeLimit;
295 - (NSTimeInterval)queryTimeLimit {
296 return self->timeLimit;
299 - (void)setQuerySizeLimit:(unsigned int)_sizeLimit {
300 self->sizeLimit = _sizeLimit;
302 - (unsigned int)querySizeLimit {
303 return self->sizeLimit;
306 - (NSEnumerator *)_searchAtBaseDN:(NSString *)_base
307 qualifier:(EOQualifier *)_q
308 attributes:(NSArray *)_attributes
314 NGLdapSearchResultEnumerator *e;
316 if (self->handle == NULL)
319 if ((filter = [_q ldapFilterString]) == nil)
320 filter = @"(objectclass=*)";
322 if (_attributes != nil) {
325 acount = [_attributes count];
326 attrs = calloc(acount + 3, sizeof(char *));
328 for (i = 0; i < acount; i++)
329 attrs[i] = (char *)[[_attributes objectAtIndex:i] UTF8String];
335 if (LDAPDebugEnabled) {
336 NSLog(@"%s: search with at base %s filter %s for attrs %s\n",
337 __PRETTY_FUNCTION__, _base, filter,
343 if (self->sizeLimit > 0)
344 ldap_set_option(self->handle, LDAP_OPT_SIZELIMIT, &(self->sizeLimit));
346 if (self->timeLimit > 0.0) {
347 int tl = self->timeLimit; /* specified in seconds */
348 ldap_set_option(self->handle, LDAP_OPT_TIMELIMIT, &tl);
353 msgid = ldap_search(self->handle,
354 (char *)[_base UTF8String],
356 (char *)[filter UTF8String],
360 /* free attributes */
361 if (attrs != NULL) free(attrs); attrs = NULL;
368 e = [[NGLdapSearchResultEnumerator alloc]
369 initWithConnection:self messageID:msgid];
371 return [e autorelease];
374 - (NSEnumerator *)flatSearchAtBaseDN:(NSString *)_base
375 qualifier:(EOQualifier *)_q
376 attributes:(NSArray *)_attributes
378 return [self _searchAtBaseDN:_base
380 attributes:_attributes
381 scope:LDAP_SCOPE_ONELEVEL];
384 - (NSEnumerator *)deepSearchAtBaseDN:(NSString *)_base
385 qualifier:(EOQualifier *)_q
386 attributes:(NSArray *)_attributes
388 return [self _searchAtBaseDN:_base
390 attributes:_attributes
391 scope:LDAP_SCOPE_SUBTREE];
394 - (NSEnumerator *)baseSearchAtBaseDN:(NSString *)_base
395 qualifier:(EOQualifier *)_q
396 attributes:(NSArray *)_attributes
398 return [self _searchAtBaseDN:_base
400 attributes:_attributes
401 scope:LDAP_SCOPE_BASE];
404 - (NGLdapEntry *)entryAtDN:(NSString *)_dn attributes:(NSArray *)_attrs {
408 e = [self _searchAtBaseDN:_dn
411 scope:LDAP_SCOPE_BASE];
413 entry = [e nextObject];
415 if ([e nextObject] != nil) {
416 [self logWithFormat:@"WARN: more than one search results in base search!"];
417 /* consume all entries */
418 while ([e nextObject] != nil) // TODO: can't we cancel the request?
427 - (void)setCacheTimeout:(NSTimeInterval)_to {
428 if (self->cacheTimeout != _to) {
429 self->cacheTimeout = _to;
431 if (self->isCacheEnabled) {
432 #if LDAP_API_VERSION > 2000
433 NSLog(@"WARNING(%s): setting cache-timeout unsupported on the client "
434 @"library version!", __PRETTY_FUNCTION__);
436 ldap_disable_cache(self->handle);
437 ldap_enable_cache(self->handle, _to, [self cacheMaxMemoryUsage]);
442 - (NSTimeInterval)cacheTimeout {
443 return self->cacheTimeout;
446 - (void)setCacheMaxMemoryUsage:(long)_maxMem {
447 if (self->cacheMaxMemory != _maxMem) {
448 self->cacheMaxMemory = _maxMem;
450 if (self->isCacheEnabled) {
451 #if LDAP_API_VERSION > 2000
452 NSLog(@"WARNING(%s): setting maxmem usage unsupported on the client "
453 @"library version!", __PRETTY_FUNCTION__);
455 ldap_disable_cache(self->handle);
456 ldap_enable_cache(self->handle, [self cacheTimeout], _maxMem);
461 - (long)cacheMaxMemoryUsage {
462 return self->cacheMaxMemory;
465 - (void)setUseCache:(BOOL)_flag {
467 #if LDAP_API_VERSION > 2000
468 NSLog(@"WARNING(%s): setting cache-usage unsupported on the client "
469 @"library version!", __PRETTY_FUNCTION__);
471 ldap_enable_cache(self->handle,
472 [self cacheTimeout], [self cacheMaxMemoryUsage]);
474 self->isCacheEnabled = YES;
477 #if LDAP_API_VERSION > 2000
478 NSLog(@"WARNING(%s): setting cache-usage unsupported on the client "
479 @"library version!", __PRETTY_FUNCTION__);
481 ldap_disable_cache(self->handle);
483 self->isCacheEnabled = NO;
486 - (BOOL)doesUseCache {
487 return self->isCacheEnabled;
491 #if !(LDAP_API_VERSION > 2000)
492 ldap_flush_cache(self->handle);
495 - (void)destroyCache {
496 #if !(LDAP_API_VERSION > 2000)
497 ldap_destroy_cache(self->handle);
499 self->isCacheEnabled = NO;
502 - (void)cacheForgetEntryWithDN:(NSString *)_dn {
503 if (_dn == nil) return;
504 #if !(LDAP_API_VERSION > 2000)
505 ldap_uncache_entry(self->handle, (char *)[_dn UTF8String]);
511 - (BOOL)addEntry:(NGLdapEntry *)_entry {
521 /* construct attributes */
525 NGLdapAttribute *attribute;
527 count = [_entry count];
529 attrBuf = calloc(count, sizeof(LDAPMod));
530 NSAssert(attrBuf, @"couldn't allocate attribute buffer");
532 attrs = calloc(count + 1, sizeof(LDAPMod *));
533 NSAssert(attrs, @"couldn't allocate attribute ptr buffer");
535 e = [[[_entry attributes] allValues] objectEnumerator];
536 for (i = 0; (attribute = [e nextObject]) && (i < count); i++) {
537 unsigned valCount, j;
538 struct berval **values;
544 key = [attribute attributeName];
546 valCount = [attribute count];
547 values = calloc(valCount + 1, sizeof(struct berval *));
549 ve = [attribute valueEnumerator];
550 for (j = 0; (v = [ve nextObject]) && (j < valCount); j++) {
553 bv = malloc(sizeof(struct berval));
555 bv->bv_len = [v length];
556 bv->bv_val = (void *)[v bytes];
559 values[valCount] = NULL;
561 attrName = strdup([key UTF8String]);
563 attrBuf[i].mod_op = LDAP_MOD_BVALUES;
564 attrBuf[i].mod_type = attrName;
565 attrBuf[i].mod_bvalues = values;
566 attrs[i] = &(attrBuf[i]);
571 /* start operation */
573 msgid = ldap_add(self->handle, (char *)[[_entry dn] UTF8String], attrs);
575 /* deconstruct attributes */
581 /* check operation return value */
584 [[self _exceptionForErrorCode:
585 0 /* was in v1: ((LDAP *)self->handle)->ld_errno */
587 userInfo:[NSDictionary dictionaryWithObject:_entry forKey:@"entry"]]
595 res = ldap_result(self->handle, msgid, 0, NULL /* timeout */, &msg);
601 err = ldap_result2error(self->handle, msg, 1 /* free msg */);
602 [[self _exceptionForErrorCode:err
604 userInfo:[NSDictionary dictionaryWithObject:_entry forKey:@"entry"]]
610 if (msg) ldap_msgfree(msg);
617 - (BOOL)compareAttribute:(NSString *)_attr ofEntryWithDN:(NSString *)_dn
625 res = ldap_compare_s(self->handle,
626 (char *)[_dn UTF8String],
627 (char *)[_attr UTF8String],
628 (char *)[[_value stringValue] UTF8String]);
630 if (res == LDAP_COMPARE_TRUE)
632 if (res == LDAP_COMPARE_FALSE)
635 [[self _exceptionForErrorCode:res
637 userInfo:[NSDictionary dictionaryWithObject:_dn forKey:@"dn"]]
643 - (BOOL)removeEntryWithDN:(NSString *)_dn {
649 res = ldap_delete_s(self->handle, (char *)[_dn UTF8String]);
651 if (res == LDAP_SUCCESS)
654 [[self _exceptionForErrorCode:res
656 userInfo:[NSDictionary dictionaryWithObject:_dn forKey:@"dn"]]
662 - (BOOL)modifyEntryWithDN:(NSString *)_dn changes:(NSArray *)_mods {
671 if ((count = [_mods count]) == 0)
676 mods = calloc(count + 1, sizeof(LDAPMod *));
677 modBuf = calloc(count, sizeof(LDAPMod));
678 NSAssert(mods, @"couldn't allocate modification array");
679 NSAssert(modBuf, @"couldn't allocate modification buffer");
681 for (i = 0; i < count; i++) {
682 NGLdapModification *mod;
683 NGLdapAttribute *attr;
688 struct berval **values;
691 mod = [_mods objectAtIndex:i];
692 mods[i] = &(modBuf[i]);
694 switch ([mod operation]) {
695 case NGLdapAddAttribute:
696 modBuf[i].mod_op = LDAP_MOD_ADD;
698 case NGLdapDeleteAttribute:
699 modBuf[i].mod_op = LDAP_MOD_DELETE;
701 case NGLdapReplaceAttribute:
702 modBuf[i].mod_op = LDAP_MOD_REPLACE;
705 modBuf[i].mod_op |= LDAP_MOD_BVALUES;
707 attr = [mod attribute];
708 attrName = [attr attributeName];
709 /* TODO: use UTF-8, UNICODE */
711 modBuf[i].mod_type = strdup(modBuf[i].mod_type);
713 valCount = [attr count];
714 values = calloc(valCount + 1, sizeof(struct berval *));
716 e = [attr valueEnumerator];
717 for (j = 0; (value = [e nextObject]) && (j < valCount); j++) {
720 bv = malloc(sizeof(struct berval));
721 bv->bv_len = [value length];
722 bv->bv_val = (void *)[value bytes];
725 values[valCount] = NULL;
727 modBuf[i].mod_bvalues = values;
733 res = ldap_modify_s(self->handle, (char *)[_dn UTF8String], mods);
735 /* free structures */
744 [[self _exceptionForErrorCode:
745 0 /* was in v1: ((LDAP *)self->handle)->ld_errno */
747 userInfo:[NSDictionary dictionaryWithObject:_dn forKey:@"dn"]]
756 - (NGLdapEntry *)schemaEntry {
759 if ((e = [self entryAtDN:@"cn=schema" attributes:nil]))
765 - (NGLdapEntry *)rootDSE {
768 if ((e = [self entryAtDN:@"" attributes:nil]))
774 - (NGLdapEntry *)configEntry {
777 if ((e = [self entryAtDN:@"cn=config" attributes:nil]))
783 - (NSArray *)namingContexts {
785 NSEnumerator *values;
789 if ((e = [self rootDSE])) {
791 return [[e attributeWithName:@"namingcontexts"] allStringValues];
794 if ((e = [self configEntry]) == nil)
799 values = [[e attributeWithName:@"database"] stringValueEnumerator];
800 ma = [NSMutableArray arrayWithCapacity:4];
802 while ((value = [values nextObject])) {
805 r = [value rangeOfString:@":"];
807 /* couldn't parse value */
810 value = [value substringFromIndex:(r.location + r.length)];
811 [ma addObject:value];
818 - (NSString *)description {
821 s = [NSMutableString stringWithCapacity:100];
822 [s appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
825 [s appendString:@" bound"];
827 if ([self doesUseCache]) {
828 [s appendFormat:@" cache[to=%.2fs,mem=%i]",
829 [self cacheTimeout], [self cacheMaxMemoryUsage]];
832 [s appendString:@">"];
837 /* PlainPasswordCheck */
839 + (NSString *)uidAttributeName {
840 static NSString *uidAttr = nil;
841 if (uidAttr == nil) {
842 // TODO: can't we do this in +initialize? (maybe not if setup later by OGo)
843 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
845 uidAttr = [[ud stringForKey:@"LDAPLoginAttributeName"] copy];
846 if (![uidAttr isNotEmpty]) uidAttr = @"uid";
851 - (NSString *)dnForLogin:(NSString *)_login baseDN:(NSString *)_baseDN {
860 int ldap_search_result ;
862 if (LDAPDebugEnabled)
863 [self logWithFormat:@"dn for login '%@' on %@", _login, _baseDN];
865 if (self->handle == NULL) {
866 if (![self _reinit]) {
867 NSLog(@"%s: _reinit failed...:", __PRETTY_FUNCTION__);
871 if (![self isBound]) {
875 if (LDAPInitialBindSpecific) {
876 // TODO: can't we just check whether the DN is set?
877 if (LDAPDebugEnabled) {
879 @" attempt to do a simple, authenticated bind "
880 @"(dn=%@,pwd=%s) ..",
882 [LDAPInitialBindPW length] > 0 ? "yes":"no"];
885 didBind = [self bindWithMethod:@"simple" binddn:LDAPInitialBindDN
886 credentials:LDAPInitialBindPW];
889 if (LDAPDebugEnabled)
890 [self logWithFormat:@" attempt to do a simple, anonymous bind .."];
892 didBind = [self bindWithMethod:@"simple" binddn:@"" credentials:@""];
901 if (LDAPDebugEnabled) [self logWithFormat:@" bind failed !"];
905 if (LDAPDebugEnabled) [self logWithFormat:@" bound."];
908 filter = [NSString stringWithFormat:@"(%@=%@)",
909 [[self class] uidAttributeName],
912 if (LDAPDebugEnabled)
913 [self logWithFormat:@" search: uid='%@': '%@'", _login, filter];
915 /* we only check the DN anyway .. */
916 attrs[0] = "objectclass";
919 ldap_search_result = ldap_search_s(self->handle,
920 (char *)[_baseDN UTF8String],
922 (char *)[filter UTF8String],
925 if ((ldap_search_result != LDAP_SUCCESS) &&
926 (ldap_search_result != LDAP_PARTIAL_RESULTS)) {
931 if (LDAPDebugEnabled)
932 [self logWithFormat:@" search failed"];
938 If the entry count is not equal to one, either the UID was not unique or
941 if (((matchCount = ldap_count_entries(self->handle, result))) != 1) {
942 if (didBind) [self unbind];
943 if (LDAPDebugEnabled)
944 [self logWithFormat:@" failed: %i matches", matchCount];
948 /* get first entry */
949 if ((entry = ldap_first_entry(self->handle, result)) == NULL) {
950 if (didBind) [self unbind];
951 if (LDAPDebugEnabled)
952 [self logWithFormat:@" could not retrieve first entry !"];
956 /* get DN of first entry */
957 if ((dn = ldap_get_dn(self->handle, entry)) == NULL) {
958 /* could not get DN */
959 if (didBind) [self unbind];
960 if (LDAPDebugEnabled) [self logWithFormat:@" got no DN for entry !"];
966 strDN = [[[NSString alloc] initWithUTF8String:dn] autorelease];
969 // Note: this is not NSLog because of GCC crashers with exception handlers
970 fprintf(stderr, "Got exception %s while NSUTF8StringEncoding, "
971 "use defaultCStringEncoding",
972 [[localException description] UTF8String]);
978 if (LDAPDebugEnabled) {
980 @"could not convert DN to UTF-8 string, try cString .."];
982 strDN = [[[NSString alloc] initWithCString:dn] autorelease];
984 if (dn != NULL) free(dn); dn = NULL;
986 if (result != NULL) {
987 ldap_msgfree(result);
991 if (LDAPDebugEnabled)
992 [self logWithFormat:@" return DN %@", strDN];
997 - (BOOL)checkPassword:(NSString *)_pwd ofLogin:(NSString *)_login
998 atBaseDN:(NSString *)_baseDN
1003 if (LDAPDebugEnabled)
1004 [self logWithFormat:@"check pwd of login '%@' on %@", _login, _baseDN];
1006 if (![_pwd isNotEmpty]) {
1007 if (LDAPDebugEnabled) [self logWithFormat:@" no password provided."];
1011 if (self->handle == NULL) {
1012 if (![self _reinit]) {
1013 NSLog(@"%s: _reinit failed...:", __PRETTY_FUNCTION__);
1016 strDN = [self dnForLogin:_login baseDN:_baseDN];
1018 if (![strDN isNotEmpty]) {
1019 if (LDAPDebugEnabled) {
1020 [self logWithFormat:@" missing dn for login %@ atBaseDN %@",
1026 if (LDAPDebugEnabled) {
1027 [self logWithFormat:@" attempting to bind login %@ DN: %@ %s!",
1029 [_pwd isNotEmpty] ? "(with password) " : "(empty password) "];
1033 Now bind as the DN with the password supplied earlier...
1034 Successful bind means the password was correct, otherwise the
1035 password is invalid.
1040 /* Note: beware: do _not_ use empty passwords! (unauthenticated binds) */
1041 didBind = [self bindWithMethod:@"simple" binddn:strDN credentials:_pwd];
1048 /* invalid login or password */
1049 if (LDAPDebugEnabled)
1050 [self logWithFormat:@" simple bind failed for DN: '%@'", strDN];
1056 if (LDAPDebugEnabled) [self logWithFormat:@" bound successfully !"];
1060 + (BOOL)checkPassword:(NSString *)_pwd ofLogin:(NSString *)_login
1061 atBaseDN:(NSString *)_baseDN
1062 onHost:(NSString *)_hostName port:(int)_port
1064 NGLdapConnection *ldap;
1066 if (LDAPDebugEnabled) {
1067 NSLog(@"LDAP: check pwd of login '%@' on %@,%i,%@ ...",
1068 _login, _hostName, _port, _baseDN);
1070 if (![_pwd isNotEmpty]) {
1071 if (LDAPDebugEnabled) [self logWithFormat:@" no password provided."];
1075 if ((ldap = [[self alloc] initWithHostName:_hostName port:_port]) == nil) {
1076 if (LDAPDebugEnabled)
1077 NSLog(@"LDAP: got no connection to %@,%i ...", _hostName, _port);
1080 ldap = [ldap autorelease];
1081 if (LDAPDebugEnabled)
1082 NSLog(@"LDAP: use connection: %@", ldap);
1084 return [ldap checkPassword:_pwd ofLogin:_login atBaseDN:_baseDN];
1087 @end /* NGLdapConnection */