fi
+# this will link libpq against libldap_r
+if test "$with_ldap" = yes ; then
+ if test "$PORTNAME" != "win32"; then
+
+echo "$as_me:$LINENO: checking for ldap_simple_bind in -lldap_r" >&5
+echo $ECHO_N "checking for ldap_simple_bind in -lldap_r... $ECHO_C" >&6
+if test "${ac_cv_lib_ldap_r_ldap_simple_bind+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lldap_r $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char ldap_simple_bind ();
+int
+main ()
+{
+ldap_simple_bind ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_ldap_r_ldap_simple_bind=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_ldap_r_ldap_simple_bind=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ldap_r_ldap_simple_bind" >&5
+echo "${ECHO_T}$ac_cv_lib_ldap_r_ldap_simple_bind" >&6
+if test $ac_cv_lib_ldap_r_ldap_simple_bind = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBLDAP_R 1
+_ACEOF
+
+ LIBS="-lldap_r $LIBS"
+
+else
+ { { echo "$as_me:$LINENO: error: library 'ldap_r' is required for LDAP" >&5
+echo "$as_me: error: library 'ldap_r' is required for LDAP" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ PTHREAD_LIBS="$PTHREAD_LIBS -lldap_r"
+ fi
+fi
+
CFLAGS="$_CFLAGS"
LIBS="$_LIBS"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.333 2006/06/07 22:24:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.334 2006/07/27 13:20:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#endif
#endif
+#ifdef USE_LDAP
+#ifdef WIN32
+#include
+#else
+/* OpenLDAP deprecates RFC 1823, but we want standard conformance */
+#define LDAP_DEPRECATED 1
+#include
+typedef struct timeval LDAP_TIMEVAL;
+#endif
+static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
+ PQExpBuffer errorMessage);
+#endif
+
#include "libpq/ip.h"
#include "mb/pg_wchar.h"
return STATUS_OK;
}
+#ifdef USE_LDAP
+
+#define LDAP_URL "ldap://"
+#define LDAP_DEF_PORT 389
+#define PGLDAP_TIMEOUT 2
+#define ld_is_sp_tab(x) ((x) == ' ' || (x) == '\t')
+#define ld_is_nl_cr(x) ((x) == '\r' || (x) == '\n')
+
+
+/*
+ * 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.
+ * ldap://host:port/dn?attributes?scope?filter?extensions
+ *
+ * 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 = LDAP_DEF_PORT, scope, rc, msgid, size, state, oldstate, i;
+ 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 = {PGLDAP_TIMEOUT, 0};
+
+ if ((url = strdup(purl)) == NULL)
+ {
+ printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n"));
+ return 3;
+ }
+
+ /*
+ * Parse URL components, check for correctness. Basically, url has
+ * '\0' placed at component boundaries and variables are pointed
+ * at each component.
+ */
+
+ if (strncasecmp(url, LDAP_URL, strlen(LDAP_URL)) != 0)
+ {
+ printfPQExpBuffer(errorMessage,
+ libpq_gettext("bad LDAP URL \"%s\": scheme must be ldap://\n"), purl);
+ free(url);
+ return 3;
+ }
+
+ /* hostname */
+ hostname = url + strlen(LDAP_URL);
+ if (*hostname == '/') /* no hostname? */
+ hostname = "localhost"; /* the default */
+
+ /* dn, "distinguished name" */
+ p = strchr(url + strlen(LDAP_URL), '/');
+ if (p == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
+ {
+ printfPQExpBuffer(errorMessage, libpq_gettext(
+ "bad LDAP URL \"%s\": missing distinguished name\n"), purl);
+ free(url);
+ return 3;
+ }
+ *p = '\0'; /* terminate hostname */
+ dn = p + 1;
+
+ /* attribute */
+ if ((p = strchr(dn, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
+ {
+ printfPQExpBuffer(errorMessage, libpq_gettext(
+ "bad LDAP URL \"%s\": must have exactly one attribute\n"), purl);
+ free(url);
+ return 3;
+ }
+ *p = '\0';
+ attrs[0] = p + 1;
+
+ /* scope */
+ if ((p = strchr(attrs[0], '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
+ {
+ printfPQExpBuffer(errorMessage, libpq_gettext(
+ "bad LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl);
+ free(url);
+ return 3;
+ }
+ *p = '\0';
+ scopestr = p + 1;
+
+ /* filter */
+ if ((p = strchr(scopestr, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
+ {
+ printfPQExpBuffer(errorMessage,
+ libpq_gettext("bad LDAP URL \"%s\": no filter\n"), purl);
+ free(url);
+ return 3;
+ }
+ *p = '\0';
+ filter = p + 1;
+ if ((p = strchr(filter, '?')) != NULL)
+ *p = '\0';
+
+ /* port number? */
+ if ((p1 = strchr(hostname, ':')) != NULL)
+ {
+ long lport;
+
+ *p1 = '\0';
+ portstr = p1 + 1;
+ errno = 0;
+ lport = strtol(portstr, &endptr, 10);
+ if (*portstr == '\0' || *endptr != '\0' || errno || lport < 0 || lport > 65535)
+ {
+ printfPQExpBuffer(errorMessage, libpq_gettext(
+ "bad LDAP URL \"%s\": invalid port number\n"), purl);
+ free(url);
+ return 3;
+ }
+ port = (int) lport;
+ }
+
+ /* Allow only one attribute */
+ if (strchr(attrs[0], ',') != NULL)
+ {
+ printfPQExpBuffer(errorMessage, libpq_gettext(
+ "bad LDAP URL \"%s\": must have exactly one attribute\n"), purl);
+ free(url);
+ return 3;
+ }
+
+ /* set scope */
+ if (strcasecmp(scopestr, "base") == 0)
+ scope = LDAP_SCOPE_BASE;
+ else if (strcasecmp(scopestr, "one") == 0)
+ scope = LDAP_SCOPE_ONELEVEL;
+ else if (strcasecmp(scopestr, "sub") == 0)
+ 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;
+ }
+
+ /* initialize LDAP structure */
+ if ((ld = ldap_init(hostname, port)) == NULL)
+ {
+ 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.
+ */
+ if ((msgid = ldap_simple_bind(ld, NULL, NULL)) == -1)
+ {
+ /* error in ldap_simple_bind() */
+ free(url);
+ ldap_unbind(ld);
+ return 2;
+ }
+
+ /* wait some time for the connection to succeed */
+ res = NULL;
+ if ((rc = ldap_result(ld, msgid, LDAP_MSG_ALL, &time, &res)) == -1 ||
+ res == NULL)
+ {
+ if (res != NULL)
+ {
+ /* timeout */
+ ldap_msgfree(res);
+ }
+ /* error in ldap_result() */
+ free(url);
+ ldap_unbind(ld);
+ return 2;
+ }
+ ldap_msgfree(res);
+
+ /* search */
+ res = NULL;
+ if ((rc = ldap_search_st(ld, dn, scope, filter, attrs, 0, &time, &res))
+ != LDAP_SUCCESS)
+ {
+ if (res != NULL)
+ 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 */
+ if ((rc = ldap_count_entries(ld, res)) != 1)
+ {
+ 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 ((entry = ldap_first_entry(ld, res)) == NULL)
+ {
+ /* 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 ((values = ldap_get_values_len(ld, entry, attrs[0])) == NULL)
+ {
+ 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 (values[0] == NULL)
+ {
+ 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 */
+ for (size = 0, i = 0; values[i] != NULL; ++i)
+ size += values[i]->bv_len + 1;
+ if ((result = malloc(size + 1)) == NULL)
+ {
+ printfPQExpBuffer(errorMessage,
+ libpq_gettext("out of memory\n"));
+ ldap_value_free_len(values);
+ ldap_unbind(ld);
+ return 3;
+ }
+ for (p = result, i = 0; values[i] != NULL; ++i)
+ {
+ strncpy(p, values[i]->bv_val, values[i]->bv_len);
+ p += values[i]->bv_len;
+ *(p++) = '\n';
+ if (values[i + 1] == NULL)
+ *(p + 1) = '\0';
+ }
+
+ ldap_value_free_len(values);
+ ldap_unbind(ld);
+
+ /* parse result string */
+ oldstate = state = 0;
+ for (p = result; *p != '\0'; ++p)
+ {
+ switch (state)
+ {
+ case 0: /* between entries */
+ if (!ld_is_sp_tab(*p) && !ld_is_nl_cr(*p))
+ {
+ optname = p;
+ state = 1;
+ }
+ break;
+ case 1: /* in option name */
+ if (ld_is_sp_tab(*p))
+ {
+ *p = '\0';
+ state = 2;
+ }
+ else if (ld_is_nl_cr(*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_is_sp_tab(*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_is_nl_cr(*p))
+ {
+ optval = optname + strlen(optname); /* empty */
+ state = 0;
+ }
+ else if (!ld_is_sp_tab(*p))
+ {
+ optval = p;
+ state = 4;
+ }
+ break;
+ case 4: /* in unquoted option value */
+ if (ld_is_sp_tab(*p) || ld_is_nl_cr(*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 (state == 0 && oldstate != 0)
+ {
+ 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 (state == 5 || state == 6)
+ {
+ printfPQExpBuffer(errorMessage, libpq_gettext(
+ "unterminated quoted string in connection info string\n"));
+ return 3;
+ }
+
+ return 0;
+}
+#endif
#define MAXBUFSIZE 256
*val;
bool found_keyword;
+#ifdef USE_LDAP
+ if (strncmp(line, "ldap", 4) == 0)
+ {
+ int 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)