From cf1238cd9763f0a6e3454ddf75ac56ff722f18ee Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 12 Oct 2017 22:33:34 -0400 Subject: [PATCH] Log diagnostic messages if errors occur during LDAP auth. Diagnostic messages seem likely to help users diagnose root causes more easily, so let's report them as errdetail. Author: Thomas Munro Reviewed-By: Ashutosh Bapat, Christoph Berg, Alvaro Herrera, Peter Eisentraut Discussion: https://postgr.es/m/CAEepm=2_dA-SYpFdmNVwvKsEBXOUj=K4ooKovHmvj6jnMdt8dw@mail.gmail.com --- src/backend/libpq/auth.c | 48 +++++++++++++++++++++++++++++++------ src/test/ldap/t/001_auth.pl | 11 ++++++++- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 11ef4a5858..2728c66a35 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -2305,6 +2305,8 @@ CheckBSDAuth(Port *port, char *user) */ #ifdef USE_LDAP +static int errdetail_for_ldap(LDAP *ldap); + /* * Initialize a connection to the LDAP server, including setting up * TLS if requested. @@ -2332,7 +2334,9 @@ InitializeLDAPConnection(Port *port, LDAP **ldap) if ((r = ldap_set_option(*ldap, LDAP_OPT_PROTOCOL_VERSION, &ldapversion)) != LDAP_SUCCESS) { ereport(LOG, - (errmsg("could not set LDAP protocol version: %s", ldap_err2string(r)))); + (errmsg("could not set LDAP protocol version: %s", + ldap_err2string(r)), + errdetail_for_ldap(*ldap))); ldap_unbind(*ldap); return STATUS_ERROR; } @@ -2385,7 +2389,9 @@ InitializeLDAPConnection(Port *port, LDAP **ldap) #endif { ereport(LOG, - (errmsg("could not start LDAP TLS session: %s", ldap_err2string(r)))); + (errmsg("could not start LDAP TLS session: %s", + ldap_err2string(r)), + errdetail_for_ldap(*ldap))); ldap_unbind(*ldap); return STATUS_ERROR; } @@ -2508,7 +2514,9 @@ CheckLDAPAuth(Port *port) { ereport(LOG, (errmsg("could not perform initial LDAP bind for ldapbinddn \"%s\" on server \"%s\": %s", - port->hba->ldapbinddn, port->hba->ldapserver, ldap_err2string(r)))); + port->hba->ldapbinddn, port->hba->ldapserver, + ldap_err2string(r)), + errdetail_for_ldap(ldap))); ldap_unbind(ldap); pfree(passwd); return STATUS_ERROR; @@ -2534,7 +2542,8 @@ CheckLDAPAuth(Port *port) { ereport(LOG, (errmsg("could not search LDAP for filter \"%s\" on server \"%s\": %s", - filter, port->hba->ldapserver, ldap_err2string(r)))); + filter, port->hba->ldapserver, ldap_err2string(r)), + errdetail_for_ldap(ldap))); ldap_unbind(ldap); pfree(passwd); pfree(filter); @@ -2573,7 +2582,9 @@ CheckLDAPAuth(Port *port) (void) ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &error); ereport(LOG, (errmsg("could not get dn for the first entry matching \"%s\" on server \"%s\": %s", - filter, port->hba->ldapserver, ldap_err2string(error)))); + filter, port->hba->ldapserver, + ldap_err2string(error)), + errdetail_for_ldap(ldap))); ldap_unbind(ldap); pfree(passwd); pfree(filter); @@ -2618,23 +2629,46 @@ CheckLDAPAuth(Port *port) port->hba->ldapsuffix ? port->hba->ldapsuffix : ""); r = ldap_simple_bind_s(ldap, fulluser, passwd); - ldap_unbind(ldap); if (r != LDAP_SUCCESS) { ereport(LOG, (errmsg("LDAP login failed for user \"%s\" on server \"%s\": %s", - fulluser, port->hba->ldapserver, ldap_err2string(r)))); + fulluser, port->hba->ldapserver, ldap_err2string(r)), + errdetail_for_ldap(ldap))); + ldap_unbind(ldap); pfree(passwd); pfree(fulluser); return STATUS_ERROR; } + ldap_unbind(ldap); pfree(passwd); pfree(fulluser); return STATUS_OK; } + +/* + * Add a detail error message text to the current error if one can be + * constructed from the LDAP 'diagnostic message'. + */ +static int +errdetail_for_ldap(LDAP *ldap) +{ + char *message; + int rc; + + rc = ldap_get_option(ldap, LDAP_OPT_DIAGNOSTIC_MESSAGE, &message); + if (rc == LDAP_SUCCESS && message != NULL) + { + errdetail("LDAP diagnostics: %s", message); + ldap_memfree(message); + } + + return 0; +} + #endif /* USE_LDAP */ diff --git a/src/test/ldap/t/001_auth.pl b/src/test/ldap/t/001_auth.pl index a7cac6210b..38760ece61 100644 --- a/src/test/ldap/t/001_auth.pl +++ b/src/test/ldap/t/001_auth.pl @@ -2,7 +2,7 @@ use strict; use warnings; use TestLib; use PostgresNode; -use Test::More tests => 14; +use Test::More tests => 15; my ($slapd, $ldap_bin_dir, $ldap_schema_dir); @@ -175,3 +175,12 @@ $node->reload; $ENV{"PGPASSWORD"} = 'secret1'; test_access($node, 'test1', 0, 'combined LDAP URL and search filter'); + +note "diagnostic message"; + +unlink($node->data_dir . '/pg_hba.conf'); +$node->append_conf('pg_hba.conf', qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapprefix="uid=" ldapsuffix=",dc=example,dc=net" ldaptls=1}); +$node->reload; + +$ENV{"PGPASSWORD"} = 'secret1'; +test_access($node, 'test1', 2, 'any attempt fails due to unsupported TLS');