Allow LDAP lookups from pg_service.conf.
Albe Laurenz
This commit is contained in:
parent
b517e65348
commit
43c79378c8
85
configure
vendored
85
configure
vendored
@ -17314,6 +17314,91 @@ _ACEOF
|
||||
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"
|
||||
|
||||
|
10
configure.in
10
configure.in
@ -1,5 +1,5 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
dnl $PostgreSQL: pgsql/configure.in,v 1.469 2006/07/24 16:32:44 petere Exp $
|
||||
dnl $PostgreSQL: pgsql/configure.in,v 1.470 2006/07/27 13:20:24 momjian Exp $
|
||||
dnl
|
||||
dnl Developers, please strive to achieve this order:
|
||||
dnl
|
||||
@ -1106,6 +1106,14 @@ AC_CHECK_FUNCS([strerror_r getpwuid_r gethostbyname_r])
|
||||
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"
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.213 2006/07/04 13:22:15 momjian Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.214 2006/07/27 13:20:24 momjian Exp $ -->
|
||||
|
||||
<chapter id="libpq">
|
||||
<title><application>libpq</application> - C Library</title>
|
||||
@ -4126,6 +4126,72 @@ installs too. The file's location can also be specified by the
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="libpq-ldap">
|
||||
<title>LDAP Lookup of Connection Parameters</title>
|
||||
|
||||
<indexterm zone="libpq-ldap">
|
||||
<primary>LDAP connection parameter lookup</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
If <application>libpq</application> has been compiled with LDAP support (option
|
||||
<literal><option>--with-ldap</option></literal> for <command>configure</command>)
|
||||
it is possible to retrieve connection options like <literal>host</literal>
|
||||
or <literal>dbname</literal> via LDAP from a central server.
|
||||
The advantage is that if the connection parameters for a database change,
|
||||
the connection information doesn't have to be updated on all client machines.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
LDAP connection parameter lookup uses the connection service file
|
||||
<filename>pg_service.conf</filename> (see <xref linkend="libpq-pgservice">).
|
||||
A line in a <filename>pg_service.conf</filename> stanza that starts with
|
||||
<literal>ldap://</literal> will be recognized as an LDAP URL and an LDAP
|
||||
query will be performed. The result must be a list of <literal>keyword =
|
||||
value</literal> pairs which will be used to set connection options.
|
||||
The URL must conform to RFC 1959 and be of the form
|
||||
<synopsis>
|
||||
ldap://[<replaceable>hostname</replaceable>[:<replaceable>port</replaceable>]]/<replaceable>search_base</replaceable>?<replaceable>attribute</replaceable>?<replaceable>search_scope</replaceable>?<replaceable>filter</replaceable>
|
||||
</synopsis>
|
||||
where <replaceable>hostname</replaceable>
|
||||
defaults to <literal>localhost</literal> and
|
||||
<replaceable>port</replaceable> defaults to 389.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Processing of <filename>pg_service.conf</filename> is terminated after
|
||||
a successful LDAP lookup, but is continued if the LDAP server cannot be
|
||||
contacted. This is to provide a fallback with
|
||||
further LDAP URL lines that point to different LDAP
|
||||
servers, classical <literal>keyword = value</literal> pairs, or
|
||||
default connection options.
|
||||
If you would rather get an error message in this case, add a
|
||||
syntactically incorrect line after the LDAP URL.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A sample LDAP entry that has been created with the LDIF file
|
||||
<synopsis>
|
||||
version:1
|
||||
dn:cn=mydatabase,dc=mycompany,dc=com
|
||||
changetype:add
|
||||
objectclass:top
|
||||
objectclass:groupOfUniqueNames
|
||||
cn:mydatabase
|
||||
uniqueMember:host=dbserver.mycompany.com
|
||||
uniqueMember:port=5439
|
||||
uniqueMember:dbname=mydb
|
||||
uniqueMember:user=mydb_user
|
||||
uniqueMember:sslmode=require
|
||||
</synopsis>
|
||||
might be queried with the following LDAP URL:
|
||||
<synopsis>
|
||||
ldap://ldap.mycompany.com/dc=mycompany,dc=com?uniqueMember?one?(cn=mydatabase)
|
||||
</synopsis>
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="libpq-ssl">
|
||||
<title>SSL Support</title>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
# Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
# Portions Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
# $PostgreSQL: pgsql/src/interfaces/libpq/Makefile,v 1.146 2006/07/18 22:18:08 momjian Exp $
|
||||
# $PostgreSQL: pgsql/src/interfaces/libpq/Makefile,v 1.147 2006/07/27 13:20:24 momjian Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -62,7 +62,7 @@ else
|
||||
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))
|
||||
SHLIB_LINK += -lshfolder -lwsock32 -lws2_32 $(filter -leay32 -lssleay32 -lcomerr32 -lkrb5_32 -lwldap32, $(LIBS))
|
||||
endif
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* 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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -60,6 +60,19 @@
|
||||
#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 *purl, PQconninfoOption *options,
|
||||
PQExpBuffer errorMessage);
|
||||
#endif
|
||||
|
||||
#include "libpq/ip.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
|
||||
@ -2343,7 +2356,410 @@ pqPacketSend(PGconn *conn, char pack_type,
|
||||
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
|
||||
|
||||
@ -2439,6 +2855,26 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
|
||||
*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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user