diff -r -c pgsql.orig/configure.in pgsql/configure.in
*** pgsql.orig/configure.in	2006-03-23 16:49:17.000000000 +0100
--- pgsql/configure.in	2006-03-23 16:51:14.000000000 +0100
***************
*** 1088,1093 ****
--- 1088,1101 ----
  PGAC_FUNC_GETPWUID_R_5ARG
  PGAC_FUNC_STRERROR_R_INT
  
+ # this will link libpq against libldap_r
+ if test "$with_ldap" = yes ; then
+   if test "$PORTNAME" != "win32"; then
+     AC_CHECK_LIB(ldap_r,    ldap_simple_bind, [], [AC_MSG_ERROR([library 'ldap_r' is required for LDAP])])
+     PTHREAD_LIBS="$PTHREAD_LIBS -lldap_r"
+   fi
+ fi
+ 
  CFLAGS="$_CFLAGS"
  LIBS="$_LIBS"
  
diff -r -c pgsql.orig/src/interfaces/libpq/fe-connect.c pgsql/src/interfaces/libpq/fe-connect.c
*** pgsql.orig/src/interfaces/libpq/fe-connect.c	2006-03-23 16:49:23.000000000 +0100
--- pgsql/src/interfaces/libpq/fe-connect.c	2006-03-23 16:51:14.000000000 +0100
***************
*** 62,67 ****
--- 62,79 ----
  #endif
  #endif
  
+ #ifdef USE_LDAP
+ #	ifdef WIN32
+ #		include <winldap.h>
+ #	else
+ 		/* OpenLDAP deprecates RFC 1823, but we want standard conformance */
+ #		define LDAP_DEPRECATED 1
+ #		include <ldap.h>
+ 		typedef struct timeval LDAP_TIMEVAL;
+ #	endif
+ static int ldapServiceLookup(const char *, PQconninfoOption *, PQExpBuffer);
+ #endif
+ 
  #include "libpq/ip.h"
  #include "mb/pg_wchar.h"
  
***************
*** 2344,2350 ****
--- 2356,2697 ----
  	return STATUS_OK;
  }
  
+ #ifdef USE_LDAP
+ 
+ #define PGLDAP_TIMEOUT 2
+ #define ld_isspace(x) ((' ' == x) || ('\t' == x))
+ #define ld_islf(x) (('\r' == x) || ('\n' == x))
+ 
+ /*
+  *		ldapServiceLookup
+  *
+  * Search the LDAP URL passed as first argument, treat the result as a
+  * string of connection options that are parsed and added to the array of
+  * options passed as second argument.
+  *
+  * LDAP URLs must conform to RFC 1959 without escape sequences.
+  *
+  * Returns
+  *	0 if the lookup was successful,
+  *	1 if the connection to the LDAP server could be established but
+  *	  the search was unsuccessful,
+  *	2 if a connection could not be established, and
+  *	3 if a fatal error occurred.
+  *
+  * An error message is returned in the third argument for return codes 1 and 3.
+  */
+ static int
+ ldapServiceLookup(const char *purl, PQconninfoOption *options, PQExpBuffer errorMessage) {
+ 	int port=389, scope, rc, msgid, size, state, oldstate, i;
+ 	long lport;
+ 	bool found_keyword;
+ 	char *url, *hostname, *portstr, *endptr, *dn, *scopestr, *filter, *result, *p, *p1 = NULL, *optname = NULL, *optval = NULL;
+ 	char *attrs[2] = {NULL, NULL};
+ 	LDAP *ld = NULL;
+ 	LDAPMessage *res, *entry;
+ 	struct berval **values;
+ 	LDAP_TIMEVAL time;
+ 	time.tv_sec = PGLDAP_TIMEOUT;
+ 	time.tv_usec = 0;
+ 
+ 	/* make working copy of URL */
+ 	if (NULL == (url = malloc(strlen(purl) + 1))) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("out of memory\n"));
+ 		return 3;
+ 	}
+ 	strcpy(url, purl);
+ 
+ 	/* parse URL components, check for correctness */
+ 
+ 	if (0 != strncasecmp(url, "ldap://", 7)) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("bad LDAP URL \"%s\": scheme must be ldap://\n"), purl);
+ 		free(url);
+ 		return 3;
+ 	}
+ 	hostname = url + 7;
+ 	if ('/' == *hostname)
+ 		hostname = "localhost";
+ 	p = strchr(url + 7, ':');
+ 	p1 = strchr(url + 7, '/');
+ 	if ((NULL == p1) || ('\0' == *(p1 + 1)) || ('?' == *(p1 + 1))) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("bad LDAP URL \"%s\": missing distinguished name\n"), purl);
+ 		free(url);
+ 		return 3;
+ 	}
+ 	dn = p1 + 1;
+ 	*p1 = '\0';
+ 	if ((NULL != p) && (p < p1)) {
+ 		portstr = p + 1;
+ 		*p = '\0';
+ 		lport = strtol(portstr, &endptr, 10);
+ 		errno = 0;
+ 		if (('\0' == *portstr) || ('\0' != *endptr) || (errno) || (lport < 0l) || (lport > 65535l)) {
+ 			printfPQExpBuffer(errorMessage,
+ 				libpq_gettext("bad LDAP URL \"%s\": invalid port number\n"), purl);
+ 			free(url);
+ 			return 3;
+ 		}
+ 		port = (int)lport;
+ 	}
+ 	if ((NULL == (p = strchr(dn, '?'))) || ('\0' == *(p + 1)) || ('?' == *(p + 1))) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("bad LDAP URL \"%s\": must have exactly one attribute\n"), purl);
+ 		free(url);
+ 		return 3;
+ 	}
+ 	attrs[0] = p + 1;
+ 	*p = '\0';
+ 	if ((NULL == (p = strchr(attrs[0], '?'))) || ('\0' == *(p + 1)) || ('?' == *(p + 1))) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("bad LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl);
+ 		free(url);
+ 		return 3;
+ 	}
+ 	scopestr = p + 1;
+ 	*p = '\0';
+ 	if (NULL != strchr(attrs[0], ',')) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("bad LDAP URL \"%s\": must have exactly one attribute\n"), purl);
+ 		free(url);
+ 		return 3;
+ 	}
+ 	if ((NULL == (p = strchr(scopestr, '?'))) || ('\0' == *(p + 1)) || ('?' == *(p + 1))) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("bad LDAP URL \"%s\": no filter\n"), purl);
+ 		free(url);
+ 		return 3;
+ 	}
+ 	filter = p + 1;
+ 	*p = '\0';
+ 	if (0 == strcasecmp(scopestr, "base"))
+ 		scope = LDAP_SCOPE_BASE;
+ 	else if (0 == strcasecmp(scopestr, "one"))
+ 		scope = LDAP_SCOPE_ONELEVEL;
+ 	else if (0 == strcasecmp(scopestr, "sub"))
+ 		scope = LDAP_SCOPE_SUBTREE;
+ 	else {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("bad LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl);
+ 		free(url);
+ 		return 3;
+ 	}
+ 	if (NULL != (p = strchr(filter, '?')))
+ 		*p = '\0';
+ 
+ 	/* initialize LDAP structure */
+ 	if (NULL == (ld = ldap_init(hostname, port))) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("error creating LDAP structure\n"));
+ 		free(url);
+ 		return 3;
+ 	}
+ 
+ 	/* initialize connection to the server */
+ 	/* we do an explicit bind because we want to return 2 if the bind fails */
+ 	msgid = ldap_simple_bind(ld, NULL, NULL);
+ 	if (-1 == msgid) {
+ 		/* error in ldap_simple_bind() */
+ 		free(url);
+ 		ldap_unbind(ld);
+ 		return 2;
+ 	}
+ 
+ 	/* wait some time for the connection to succeed */
+ 	res = NULL;
+ 	rc = ldap_result(ld, msgid, LDAP_MSG_ALL, &time, &res);
+ 	if ((-1 == rc) || (NULL == res)) {
+ 		if (NULL != res) {
+ 			/* timeout */
+ 			ldap_msgfree(res);
+ 		}
+ 		/* error in ldap_result() */
+ 		free(url);
+ 		ldap_unbind(ld);
+ 		return 2;
+ 	}
+ 	ldap_msgfree(res);
+ 
+ 	/* search */
+ 	res = NULL;
+ 	rc = ldap_search_st(ld, dn, scope, filter, attrs, 0, &time, &res);
+ 	if (LDAP_SUCCESS != rc) {
+ 		if (NULL != res)
+ 			ldap_msgfree(res);
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("lookup on LDAP server failed: %s\n"),
+ 			ldap_err2string(rc));
+ 		ldap_unbind(ld);
+ 		free(url);
+ 		return 1;
+ 	}
+ 
+ 	/* complain if there was not exactly one result */
+ 	rc = ldap_count_entries(ld, res);
+ 	if (1 != rc) {
+ 		printfPQExpBuffer(errorMessage,
+ 			rc ? libpq_gettext("more than one entry found on LDAP lookup\n")
+ 				: libpq_gettext("no entry found on LDAP lookup\n"));
+ 		ldap_msgfree(res);
+ 		ldap_unbind(ld);
+ 		free(url);
+ 		return 1;
+ 	}
+ 
+ 	/* get entry */
+ 	if (NULL == (entry = ldap_first_entry(ld, res))) {
+ 		/* should never happen */
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("no entry found on LDAP lookup\n"));
+ 		ldap_msgfree(res);
+ 		ldap_unbind(ld);
+ 		free(url);
+ 		return 1;
+ 	}
+ 
+ 	/* get values */
+ 	if (NULL == (values = ldap_get_values_len(ld, entry, attrs[0]))) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("attribute has no values on LDAP lookup\n"));
+ 		ldap_msgfree(res);
+ 		ldap_unbind(ld);
+ 		free(url);
+ 		return 1;
+ 	}
+ 	ldap_msgfree(res);
+ 	free(url);
+ 	if (NULL == values[0]) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("attribute has no values on LDAP lookup\n"));
+ 		ldap_value_free_len(values);
+ 		ldap_unbind(ld);
+ 		return 1;
+ 	}
+ 
+ 	/* concatenate values to a single string */
+ 	size = 0;
+ 	for (i = 0; NULL != values[i]; ++i)
+ 		size += values[i]->bv_len + 1;
+ 	if (NULL == (result = malloc(size + 1))) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("out of memory\n"));
+ 		ldap_value_free_len(values);
+ 		ldap_unbind(ld);
+ 		return 3;
+ 	}
+ 	p = result;
+ 	for (i = 0; NULL != values[i]; ++i) {
+ 		strncpy(p, values[i]->bv_val, values[i]->bv_len);
+ 		p += values[i]->bv_len;
+ 		*(p++) = '\n';
+ 		if (NULL == values[i+1])
+ 			*(p+1) = '\0';
+ 	}
+ 	ldap_value_free_len(values);
+ 
+ 	ldap_unbind(ld);
+ 
+ 	/* parse result string */
+ 	oldstate = state = 0;
+ 	for (p = result; '\0' != *p; ++p) {
+ 		switch (state) {
+ 			case 0:	/* between entries */
+ 				if (! (ld_isspace(*p) || ld_islf(*p))) {
+ 					optname = p;
+ 					state = 1;
+ 				}
+ 				break;
+ 			case 1: /* in option name */
+ 				if (ld_isspace(*p)) {
+ 					*p = '\0';
+ 					state = 2;
+ 				} else if (ld_islf(*p)) {
+ 					printfPQExpBuffer(errorMessage,
+ 						libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"),
+ 						optname);
+ 					return 3;
+ 				} else if ('=' == *p) {
+ 					*p = '\0';
+ 					state = 3;
+ 				}
+ 				break;
+ 			case 2: /* after option name */
+ 				if ('=' == *p) {
+ 					state = 3;
+ 				} else if (! ld_isspace(*p)) {
+ 					printfPQExpBuffer(errorMessage,
+ 						libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"),
+ 						optname);
+ 					return 3;
+ 				}
+ 				break;
+ 			case 3: /* before option value */
+ 				if ('\'' == *p) {
+ 					optval = p+1;
+ 					p1 = p+1;
+ 					state = 5;
+ 				} else if (ld_islf(*p)) {
+ 					optval = optname + strlen(optname);  /* empty */
+ 					state = 0;
+ 				} else if (! ld_isspace(*p)) {
+ 					optval = p;
+ 					state = 4;
+ 				}
+ 				break;
+ 			case 4: /* in unquoted option value */
+ 				if (ld_isspace(*p) || ld_islf(*p)) {
+ 					*p = '\0';
+ 					state = 0;
+ 				}
+ 				break;
+ 			case 5: /* in quoted option value */
+ 				if ('\'' == *p) {
+ 					*p1 = '\0';
+ 					state = 0;
+ 				} else if ('\\' == *p) {
+ 					state = 6;
+ 				} else
+ 					*(p1++) = *p;
+ 				break;
+ 			case 6: /* in quoted option value after escape */
+ 				*(p1++) = *p;
+ 				state = 5;
+ 				break;
+ 		}
+ 
+ 		if ((0 == state) && (0 != oldstate)) {
+ 			found_keyword = false;
+ 			for (i = 0; options[i].keyword; i++) {
+ 				if (strcmp(options[i].keyword, optname) == 0) {
+ 					if (options[i].val == NULL)
+ 						options[i].val = strdup(optval);
+ 					found_keyword = true;
+ 					break;
+ 				}
+ 			}
+ 			if (!found_keyword) {
+ 				printfPQExpBuffer(errorMessage,
+ 					libpq_gettext("invalid connection option \"%s\"\n"),
+ 					optname);
+ 				return 1;
+ 			}
+ 			optname = NULL;
+ 			optval = NULL;
+ 		}
+ 		oldstate = state;
+ 	}
  
+ 	if ((5 == state) || (6 == state)) {
+ 		printfPQExpBuffer(errorMessage,
+ 			libpq_gettext("unterminated quoted string in connection info string\n"));
+ 		return 3;
+ 	}
+ 
+ 	return 0;
+ }
+ #endif
  
  #define MAXBUFSIZE 256
  
***************
*** 2440,2445 ****
--- 2787,2811 ----
  							   *val;
  					bool		found_keyword;
  
+ #ifdef USE_LDAP
+ 					int rc;
+ 					if (0 == strncmp(line, "ldap", 4)) {
+ 						rc = ldapServiceLookup(line, options, errorMessage);
+ 						/* if rc = 2, go on reading for fallback */
+ 						switch (rc) {
+ 							case 0:
+ 								fclose(f);
+ 								return 0;
+ 							case 1:
+ 							case 3:
+ 								fclose(f);
+ 								return 3;
+ 							case 2:
+ 								continue;
+ 						}
+ 					}
+ #endif
+ 
  					key = line;
  					val = strchr(line, '=');
  					if (val == NULL)
diff -r -c pgsql.orig/src/interfaces/libpq/Makefile pgsql/src/interfaces/libpq/Makefile
*** pgsql.orig/src/interfaces/libpq/Makefile	2006-03-23 16:49:23.000000000 +0100
--- pgsql/src/interfaces/libpq/Makefile	2006-03-23 16:51:14.000000000 +0100
***************
*** 59,65 ****
  SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lssl -lsocket -lnsl -lresolv -lintl $(PTHREAD_LIBS), $(LIBS))
  endif
  ifeq ($(PORTNAME), win32)
! SHLIB_LINK += -lshfolder -lwsock32 -lws2_32 $(filter -leay32 -lssleay32 -lcomerr32 -lkrb5_32, $(LIBS))
  endif
  
  
--- 59,65 ----
  SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lssl -lsocket -lnsl -lresolv -lintl $(PTHREAD_LIBS), $(LIBS))
  endif
  ifeq ($(PORTNAME), win32)
! SHLIB_LINK += -lshfolder -lwsock32 -lws2_32 $(filter -leay32 -lssleay32 -lcomerr32 -lkrb5_32 -lwldap32, $(LIBS))
  endif
  
  
diff -r -c pgsql.orig/src/interfaces/libpq/po/de.po pgsql/src/interfaces/libpq/po/de.po
*** pgsql.orig/src/interfaces/libpq/po/de.po	2006-03-23 16:49:23.000000000 +0100
--- pgsql/src/interfaces/libpq/po/de.po	2006-03-23 17:05:00.000000000 +0100
***************
*** 652,654 ****
--- 652,709 ----
  #, c-format
  msgid "certificate could not be obtained: %s\n"
  msgstr "Zertifikat konnte nicht ermittelt werden: %s\n"
+ 
+ #: fe-connect.c:2409
+ #, c-format
+ msgid "bad LDAP URL \"%s\": scheme must be ldap://\n"
+ msgstr "ungültige LDAP URL »%s«: Schema ist nicht ldap://\n"
+ 
+ #: fe-connect.c:2420
+ #, c-format
+ msgid "bad LDAP URL \"%s\": missing distinguished name\n"
+ msgstr "ungültige LDAP URL »%s«: distinguished name fehlt\n"
+ 
+ #: fe-connect.c:2433
+ #, c-format
+ msgid "bad LDAP URL \"%s\": invalid port number\n"
+ msgstr "ungültige LDAP URL »%s«: ungültige Portnummer\n"
+ 
+ #: fe-connect.c:2441 fe-connect.c:2457
+ #, c-format
+ msgid "bad LDAP URL \"%s\": must have exactly one attribute\n"
+ msgstr "ungültige LDAP URL »%s«: muss genau ein Attribut haben\n"
+ 
+ #: fe-connect.c:2449 fe-connect.c:2477
+ #, c-format
+ msgid "bad LDAP URL \"%s\": must have search scope (base/one/sub)\n"
+ msgstr "ungültige LDAP URL »%s«: fehlender Suchbereich (base/one/sub)\n"
+ 
+ #: fe-connect.c:2463
+ #, c-format
+ msgid "bad LDAP URL \"%s\": no filter\n"
+ msgstr "ungültige LDAP URL »%s«: Filter fehlt\n"
+ 
+ #: fe-connect.c:2487
+ #, c-format
+ msgid "error creating LDAP structure\n"
+ msgstr "Fehler beim Erzeugen der LDAP-Struktur\n"
+ 
+ #: fe-connect.c:2524
+ #, c-format
+ msgid "lookup on LDAP server failed: %s\n"
+ msgstr "Suche am LDAP-Server schlug fehl: %s\n"
+ 
+ #: fe-connect.c:2535
+ #, c-format
+ msgid "more than one entry found on LDAP lookup\n"
+ msgstr "bei der LDAP-Suche wurde mehr als ein Eintrag gefunden\n"
+ 
+ #: fe-connect.c:2536 fe-connect.c:2547
+ #, c-format
+ msgid "no entry found on LDAP lookup\n"
+ msgstr "bei der LDAP-Suche wurde kein Eintrag gefunden\n"
+ 
+ #: fe-connect.c:2557 fe-connect.c:2567
+ #, c-format
+ msgid "attribute has no values on LDAP lookup\n"
+ msgstr "bei der LDAP-Suche wurde ein Attribut ohne Werte gefunden\n"
