Loop over a list of ldap servers. We don't use the build in failover in
ldap_init since we want to use different URIs and perdition currently doesn't
use ldap_initialize.

diff -Naur tmp/perdition-1.17/perdition/db/ldap/perditiondb_ldap.c perdition-1.17/perdition/db/ldap/perditiondb_ldap.c
--- tmp/perdition-1.17/perdition/db/ldap/perditiondb_ldap.c	2005-11-07 16:10:37.000000000 +0100
+++ perdition-1.17/perdition/db/ldap/perditiondb_ldap.c	2005-11-07 16:09:52.000000000 +0100
@@ -41,7 +41,7 @@
 #endif
 
 
-static char *pldap_filter = NULL;
+static char **pldap_filters = NULL;
 
 #ifdef WITH_LDAP_SET_OPTION
 static int pldap_version = PERDITIONDB_LDAP_VERSION;
@@ -63,24 +63,63 @@
 
 int dbserver_init(char *options_str)
 {
+	int i=0;
+	int status=-1;
+	char *options;
+	char *options_end;
+	char *cur;
+	char *end=NULL;
+
 	if (options_str == NULL) {
 		options_str = PERDITIONDB_LDAP_DEFAULT_URL;
 	}
 
-	/*
-	 * Some checks to see if the URL is sane in LDAP terms
-	 */
-	if (ldap_is_ldap_url(options_str) == 0) {
-		VANESSA_LOGGER_DEBUG("ldap_is_ldap_url: not an LDAP URL");
-		return (-1);
+	pldap_filters = (char**) calloc(PERDITIONDB_LDAP_MAX_SERVERS, sizeof(char*));
+	if( pldap_filters == NULL) {
+		VANESSA_LOGGER_DEBUG_ERRNO("pldap_filters_calloc");
+		goto leave;
 	}
 
-	pldap_filter = strdup(options_str);
-	if(!pldap_filter) {
-		VANESSA_LOGGER_DEBUG_ERRNO("pldap_filter");
+	options=strdup(options_str);
+	if(!options) {
+		VANESSA_LOGGER_DEBUG("dbserver_init_strdup");
+		goto leave;
+	} else {
+		options_end=&options[strlen(options)];
 	}
+	
+	/* split options_str into the different LDAP URIs */
+	for(i=0, cur=options;
+	    end != options_end && cur != options_end && i < PERDITIONDB_LDAP_MAX_SERVERS;
+	    i++) {
+		if(!(end = index(cur,' ')))
+			end=options_end;
+		*end=0;
+		pldap_filters[i]=strdup(cur);
+		if(!pldap_filters[i]) {
+			VANESSA_LOGGER_DEBUG("dbserver_init_strdup");
+			status=-1;
+			goto leave;
+		}
+		cur=end+1;
+		while(*cur == ' ')
+			cur++;
+	};
 
-	return (0);
+	/*
+	 * Some checks to see if all the URLs are sane in LDAP terms
+	 */
+	for(i = 0; i < PERDITIONDB_LDAP_MAX_SERVERS && pldap_filters[i] != NULL; i++) {
+		if (ldap_is_ldap_url(pldap_filters[i]) == 0) {
+			VANESSA_LOGGER_DEBUG_UNSAFE("ldap_is_ldap_url: %s not an LDAP URL", pldap_filters[i]);
+			status = -1;
+		}
+	}
+	status = 0;
+leave:
+	if(options)
+		free(options);
+	return status;
 }
 
 /**********************************************************************
@@ -98,9 +137,13 @@
 
 int dbserver_fini(void)
 {
-	if(pldap_filter) {
-		free(pldap_filter);
-		pldap_filter=NULL;
+	int i;
+
+	if(pldap_filters) {
+		for(i = 0; i < PERDITIONDB_LDAP_MAX_SERVERS && pldap_filters[i] != NULL; i++) {
+			free(pldap_filters[i]);
+		}
+		free(pldap_filters);
 	}
 	return (0);
 }
@@ -311,9 +354,10 @@
 	LDAPMessage *mptr = NULL;
 	BerElement *ber = NULL;
 	int count;
-	int attrcount = 0;
-	int status = -1;
+	int attrcount;
+	int status;
 	int err;
+	int i;
 	char *pstr;
 	char **bv_val = NULL;
 	char **returns = NULL;
@@ -325,196 +369,200 @@
 	*len_return = 0;
 
 
-	/* get filter string */
-	if (pldap_get_filter(key_str, pldap_filter, &lud) < 0) {
-		VANESSA_LOGGER_DEBUG("pldap_get_filter");
-		lud = NULL;
-		status = -3;
-		goto leave;
-	}
+	for(i = 0; i < PERDITIONDB_LDAP_MAX_SERVERS && pldap_filters[i] != NULL; i++) {
+		char* pldap_filter = pldap_filters[i];
+
+		status = -1;
 
-	/* Open LDAP connection */
+		/* get filter string */
+		if (pldap_get_filter(key_str, pldap_filter, &lud) < 0) {
+			VANESSA_LOGGER_DEBUG("pldap_get_filter");
+			lud = NULL;
+			status = -3;
+			goto next_server_or_leave;
+		}
+
+		/* Open LDAP connection */
 #if 0
-//#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-	err = ldap_initialize(&connection, pldap_filter);
-	if (err != LDAP_SUCCESS) {
-		VANESSA_LOGGER_DEBUG_UNSAFE("ldap_initialize: %s",
-				ldap_err2string(err));
-		goto leave;
-	}
+	        //#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+		err = ldap_initialize(&connection, pldap_filter);
+		if (err != LDAP_SUCCESS) {
+			VANESSA_LOGGER_DEBUG_UNSAFE("ldap_initialize: %s",
+					ldap_err2string(err));
+			goto next_server_or_leave;
+		}
 #else
-	connection = ldap_init(lud->lud_host, lud->lud_port);
-	if (!connection) {
-		VANESSA_LOGGER_DEBUG_ERRNO("ldap_init");
-		goto leave;
-	}
+		connection = ldap_init(lud->lud_host, lud->lud_port);
+		if (!connection) {
+			VANESSA_LOGGER_DEBUG_ERRNO("ldap_init");
+			goto next_server_or_leave;
+		}
 #endif
 
 #ifdef WITH_LDAP_LUD_EXTS
-	/* Check extensions */
-	if(pldap_scan_exts(lud->lud_exts, &binddn, &bindpw)) {
-		VANESSA_LOGGER_DEBUG("ldap_scan_exts");
-		goto leave;
-	}
+		/* Check extensions */
+		if(pldap_scan_exts(lud->lud_exts, &binddn, &bindpw)) {
+			VANESSA_LOGGER_DEBUG("ldap_scan_exts");
+			goto next_server_or_leave;
+		}
 #endif /* WITH_LDAP_LUD_EXTS */
 
 #ifdef WITH_LDAP_SET_OPTION
 #ifdef LDAP_OPT_NETWORK_TIMEOUT
-	{
-		struct timeval mytimeval;
-		mytimeval.tv_sec = 10;
-		mytimeval.tv_usec = 0;
-		if (ldap_set_option(connection, LDAP_OPT_NETWORK_TIMEOUT,
-				    &mytimeval) != LDAP_OPT_SUCCESS) {
-			VANESSA_LOGGER_DEBUG("ldap_network_timeout");
-			return (-1);
+		{
+			struct timeval mytimeval;
+			mytimeval.tv_sec = 10;
+			mytimeval.tv_usec = 0;
+			if (ldap_set_option(connection, LDAP_OPT_NETWORK_TIMEOUT,
+					    &mytimeval) != LDAP_OPT_SUCCESS) {
+				VANESSA_LOGGER_DEBUG("ldap_network_timeout");
+				goto next_server_or_leave;
+			}
 		}
-	}
 #endif /* LDAP_OPT_NETWORK_TIMEOUT */
 
-	err = ldap_set_option(connection, LDAP_OPT_PROTOCOL_VERSION, 
-				&pldap_version);
-	if(err != LDAP_SUCCESS) {
-		VANESSA_LOGGER_DEBUG_UNSAFE("ldap_protocol_version: %s: %s",
-				ldap_err2string(err), strerror(errno));
-		return(-1);
-	}
+		err = ldap_set_option(connection, LDAP_OPT_PROTOCOL_VERSION, 
+					&pldap_version);
+		if(err != LDAP_SUCCESS) {
+			VANESSA_LOGGER_DEBUG_UNSAFE("ldap_protocol_version: %s: %s",
+					ldap_err2string(err), strerror(errno));
+			goto next_server_or_leave;
+		}
 #endif /* WITH_LDAP_SET_OPTION */
 
-	err = ldap_bind_s(connection, binddn, bindpw, LDAP_AUTH_SIMPLE);
-	if (err != LDAP_SUCCESS) {
-		VANESSA_LOGGER_DEBUG_UNSAFE("ldap_bind_s: %s", 
-				ldap_err2string(err));
-		goto leave;
-	}
+		err = ldap_bind_s(connection, binddn, bindpw, LDAP_AUTH_SIMPLE);
+		if (err != LDAP_SUCCESS) {
+			VANESSA_LOGGER_DEBUG_UNSAFE("ldap_bind_s: %s", 
+					ldap_err2string(err));
+			goto next_server_or_leave;
+		}
 
+		/* Perform the search */
+		err = ldap_search_s(connection, lud->lud_dn, lud->lud_scope,
+				   lud->lud_filter, lud->lud_attrs, 0, &res);
+		if (err != LDAP_SUCCESS) {
+			VANESSA_LOGGER_DEBUG_UNSAFE("ldap_search_s: %s",
+					ldap_err2string(err));
+			goto next_server_or_leave;
+		}
 
+		/* Warn about multiple entries being returned */
+		err = ldap_count_entries(connection, res);
+		if(err < 0) {
+			VANESSA_LOGGER_DEBUG_UNSAFE("ldap_count_entries: %s",
+					ldap_err2string(err));
+			goto next_server_or_leave;
+		}
+		if (err > 1) {
+			VANESSA_LOGGER_LOG_UNSAFE(LOG_WARNING, 
+					"multiple entries returned by filter: "
+					"base: %s; scope: %s; filter: %s", 
+					lud->lud_dn, lud->lud_scope, lud->lud_filter);
+		}
 
-	/* Perform the search */
-	err = ldap_search_s(connection, lud->lud_dn, lud->lud_scope,
-			   lud->lud_filter, lud->lud_attrs, 0, &res);
-	if (err != LDAP_SUCCESS) {
-		VANESSA_LOGGER_DEBUG_UNSAFE("ldap_search_s: %s",
-				ldap_err2string(err));
-		goto leave;
-	}
+		/* See what we got back - we only bother with the first entry */
+		if ((mptr = ldap_first_entry(connection, res)) == NULL) {
+			VANESSA_LOGGER_DEBUG("ldap_first_entry");
+			status = -2;
+			goto next_server_or_leave;
+		}
 
-	/* Warn about multiple entries being returned */
-	err = ldap_count_entries(connection, res);
-	if(err < 0) {
-		VANESSA_LOGGER_DEBUG_UNSAFE("ldap_count_entries: %s",
-				ldap_err2string(err));
-		goto leave;
-	}
-	if (err > 1) {
-		VANESSA_LOGGER_LOG_UNSAFE(LOG_WARNING, 
-				"multiple entries returned by filter: "
-				"base: %s; scope: %s; filter: %s", 
-				lud->lud_dn, lud->lud_scope, lud->lud_filter);
-	}
+		/* See how many attributes we got */
+		for (attrcount = 0;
+		     lud->lud_attrs[attrcount] != NULL && attrcount < 3; attrcount++);
+
+		/* Store the attributes somewhere */
+		returns = (char **) calloc(attrcount, sizeof(char *));
+		if (!returns) {
+			VANESSA_LOGGER_DEBUG_ERRNO("calloc ldap_returns");
+			status = -3;
+			goto next_server_or_leave;
+		}
 
-	/* See what we got back - we only bother with the first entry */
-	if ((mptr = ldap_first_entry(connection, res)) == NULL) {
-		VANESSA_LOGGER_DEBUG("ldap_first_entry");
-		status = -2;
-		goto leave;
-	}
+		*len_return = 0;
+		for (pstr = ldap_first_attribute(connection, mptr, &ber);
+		     pstr != NULL;
+		     pstr = ldap_next_attribute(connection, mptr, ber)) {
+			bv_val = ldap_get_values(connection, mptr, pstr);
+
+			for (count = 0; count < attrcount; count++) {
+				if (strcasecmp(lud->lud_attrs[count], pstr) != 0) {
+					continue;
+				}
+				*len_return += strlen(*bv_val);
+				if (returns[count] != NULL) {
+					free(returns[count]);
+				}
+				returns[count] = (char *) malloc(strlen(*bv_val) + 1);
+				if(!returns[count]) {
+					VANESSA_LOGGER_DEBUG_ERRNO("malloc");
+					ldap_value_free(bv_val);
+					ldap_memfree(pstr);
+					status = -3;
+					goto next_server_or_leave;
+				}
+				strcpy(returns[count], *bv_val);
+				break;
+			}
 
-	/* See how many attributes we got */
-	for (attrcount = 0; 
-	     lud->lud_attrs[attrcount] != NULL && attrcount < 3; attrcount++);
-
-	/* Store the attributes somewhere */
-	returns = (char **) calloc(attrcount, sizeof(char *));
-	if (!returns) {
-		VANESSA_LOGGER_DEBUG_ERRNO("calloc ldap_returns");
-		status = -3;
-		goto leave;
-	}
+			ldap_value_free(bv_val);
+			ldap_memfree(pstr);
+		}
 
-	*len_return = 0;
-	for (pstr = ldap_first_attribute(connection, mptr, &ber);
-	     pstr != NULL;
-	     pstr = ldap_next_attribute(connection, mptr, ber)) {
-		bv_val = ldap_get_values(connection, mptr, pstr);
+		ber_free(ber, 0);
+		ber = NULL;
+
+		/* Add in some extra for the separators and terminating NULL */
+		*len_return += 2 + strlen(opt.domain_delimiter);
+
+		if ((*str_return = (char *) calloc(1, *len_return)) == NULL) {
+			VANESSA_LOGGER_DEBUG_ERRNO("str_return calloc");
+			status = -3;
+			goto next_server_or_leave;
+		}
 
+		/* Build the return string */
+		if (attrcount > 0 && returns[0]) {
+			strcat(*str_return, returns[0]);
+		}
+		if (attrcount > 1 && returns[1]) {
+			if (returns[0]) {
+				strcat(*str_return, opt.domain_delimiter);
+			}
+			strcat(*str_return, returns[1]);
+		}
+		if (attrcount > 2 && returns[2] && returns[1]) {
+			strcat(*str_return, ":");
+			strcat(*str_return, returns[2]);
+		}
 		for (count = 0; count < attrcount; count++) {
-			if (strcasecmp(lud->lud_attrs[count], pstr) != 0) {
+			if (!returns[count]) {
 				continue;
 			}
-			*len_return += strlen(*bv_val);
-			if (returns[count] != NULL) {
-				free(returns[count]);
-			}
-			returns[count] = (char *) malloc(strlen(*bv_val) + 1);
-			if(!returns[count]) {
-				VANESSA_LOGGER_DEBUG_ERRNO("malloc");
-				ldap_value_free(bv_val);
-				ldap_memfree(pstr);
-				status = -3;
-				goto leave;
-			}
-			strcpy(returns[count], *bv_val);
-			break;
+			free(returns[count]);
+			returns[count] = NULL;
 		}
+		status = 0;
 
-		ldap_value_free(bv_val);
-		ldap_memfree(pstr);
-	}
-
-	ber_free(ber, 0);
-	ber = NULL;
-
-	/* Add in some extra for the separators and terminating NULL */
-	*len_return += 2 + strlen(opt.domain_delimiter);
-
-	if ((*str_return = (char *) calloc(1, *len_return)) == NULL) {
-		VANESSA_LOGGER_DEBUG_ERRNO("str_return calloc");
-		status = -3;
-		goto leave;
-	}
-
-	/* Build the return string */
-	if (attrcount > 0 && returns[0]) {
-		strcat(*str_return, returns[0]);
-	}
-	if (attrcount > 1 && returns[1]) {
-		if (returns[0]) {
-			strcat(*str_return, opt.domain_delimiter);
-		}
-		strcat(*str_return, returns[1]);
-	}
-	if (attrcount > 2 && returns[2] && returns[1]) {
-		strcat(*str_return, ":");
-		strcat(*str_return, returns[2]);
-	}
-	for (count = 0; count < attrcount; count++) {
-		if (!returns[count]) {
-			continue;
+next_server_or_leave:
+		if (returns) {
+			for (count = 0; count < attrcount; count++)
+				if (returns[count] != NULL)
+					free(returns[count]);
+			free(returns);
 		}
-		free(returns[count]);
-		returns[count] = NULL;
-	}
-
-	status = 0;
-
-      leave:
-	if (returns) {
-		for (count = 0; count < attrcount; count++)
-			if (returns[count] != NULL)
-				free(returns[count]);
-		free(returns);
-	}
-	if (ber)
-		ber_free(ber, 0);
-	if (res)
-		ldap_msgfree(res);
-	if (connection) {
-		ldap_unbind_s(connection);
-	}
-	if(lud) {
-		ldap_free_urldesc(lud);
+		if (ber)
+			ber_free(ber, 0);
+		if (res)
+			ldap_msgfree(res);
+		if (connection) {
+			ldap_unbind_s(connection);
+		}
+		if(lud) {
+			ldap_free_urldesc(lud);
+		}
+		if(status != -1) /* continue on ldap errors, otherwise exit, successfull or not */
+			break;
 	}
-
 	return (status);
 }
diff -Naur tmp/perdition-1.17/perdition/db/ldap/perditiondb_ldap.h perdition-1.17/perdition/db/ldap/perditiondb_ldap.h
--- tmp/perdition-1.17/perdition/db/ldap/perditiondb_ldap.h	2005-06-22 07:50:04.000000000 +0200
+++ perdition-1.17/perdition/db/ldap/perditiondb_ldap.h	2005-11-07 15:00:03.000000000 +0100
@@ -47,6 +47,8 @@
 		 const char *options_str,
 		 char **str_return, int *len_return);
 
+/* maximum number of ldap servers */
+#define PERDITIONDB_LDAP_MAX_SERVERS 16
 
 #define PERDITIONDB_LDAP_DEFAULT_URL \
   "ldap://localhost/" \
