]> err.no Git - sope/blobdiff - sope-ldap/NGLdap/NGLdapConnection.m
fixed OGo bug #995, ActiveDirectory binds with umlauts
[sope] / sope-ldap / NGLdap / NGLdapConnection.m
index 6634ade955341cc4b8ff24cd809909e67e00b694..b791632fbc80b1fe38bcca6faa535bd0937ca3ea 100644 (file)
@@ -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 */