aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2006-03-06 17:41:44 +0000
committerBruce Momjian <bruce@momjian.us>2006-03-06 17:41:44 +0000
commit357cc01e57a404577b32b0ffe8919c9aeb6a4382 (patch)
tree44b12a6374609691f202881a5aa97187fbd78446 /src/backend
parentebdc35822d4f1466d66845c13f43914bcc7e307f (diff)
downloadpostgresql-357cc01e57a404577b32b0ffe8919c9aeb6a4382.tar.gz
postgresql-357cc01e57a404577b32b0ffe8919c9aeb6a4382.zip
This patch adds native LDAP auth, for those platforms that don't have
PAM (such as Win32, but also unixen without PAM). On Unix, uses OpenLDAP. On win32, uses the builin WinLDAP library. Magnus Hagander
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/libpq/auth.c165
-rw-r--r--src/backend/libpq/hba.c6
-rw-r--r--src/backend/libpq/pg_hba.conf.sample2
3 files changed, 170 insertions, 3 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 4d4e93943e5..60a5c857286 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.134 2006/03/05 15:58:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.135 2006/03/06 17:41:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -69,6 +69,32 @@ static Port *pam_port_cludge; /* Workaround for passing "Port *port" into
* pam_passwd_conv_proc */
#endif /* USE_PAM */
+#ifdef USE_LDAP
+#ifndef WIN32
+/* We use a deprecated function to keep the codepaths the same as the
+ * win32 one. */
+#define LDAP_DEPRECATED 1
+#include <ldap.h>
+#else
+/* Header broken in MingW */
+#define ldap_start_tls_sA __BROKEN_LDAP_HEADER
+#include <winldap.h>
+#undef ldap_start_tls_sA
+
+/* Correct header from the Platform SDK */
+WINLDAPAPI ULONG ldap_start_tls_sA (
+ IN PLDAP ExternalHandle,
+ OUT PULONG ServerReturnValue,
+ OUT LDAPMessage **result,
+ IN PLDAPControlA *ServerControls,
+ IN PLDAPControlA *ClientControls
+);
+#endif
+
+static int CheckLDAPAuth(Port *port);
+#endif
+
+
#ifdef KRB5
/*----------------------------------------------------------------
* MIT Kerberos authentication system - protocol version 5
@@ -327,6 +353,11 @@ auth_failed(Port *port, int status)
errstr = gettext_noop("PAM authentication failed for user \"%s\"");
break;
#endif /* USE_PAM */
+#ifdef USE_LDAP
+ case uaLDAP:
+ errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
+ break;
+#endif /* USE_LDAP */
default:
errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
break;
@@ -455,6 +486,12 @@ ClientAuthentication(Port *port)
break;
#endif /* USE_PAM */
+#ifdef USE_LDAP
+ case uaLDAP:
+ status = CheckLDAPAuth(port);
+ break;
+#endif
+
case uaTrust:
status = STATUS_OK;
break;
@@ -674,6 +711,132 @@ CheckPAMAuth(Port *port, char *user, char *password)
#endif /* USE_PAM */
+#ifdef USE_LDAP
+static int
+CheckLDAPAuth(Port *port)
+{
+ char *passwd;
+ char server[128];
+ char basedn[128];
+ char prefix[128];
+ char suffix[128];
+ LDAP *ldap;
+ int ssl = 0;
+ int r;
+ int ldapversion = LDAP_VERSION3;
+ int ldapport = LDAP_PORT;
+ char fulluser[128];
+
+ if (!port->auth_arg || port->auth_arg[0] == '\0')
+ {
+ ereport(LOG,
+ (errmsg("LDAP configuration URL not specified")));
+ return STATUS_ERROR;
+ }
+
+ /*
+ * Crack the LDAP url. We do a very trivial parse..
+ * ldap[s]://<server>[:<port>]/<basedn>[;prefix[;suffix]]
+ */
+
+ server[0] = '\0';
+ basedn[0] = '\0';
+ prefix[0] = '\0';
+ suffix[0] = '\0';
+
+ /* ldap, including port number */
+ r = sscanf(port->auth_arg,
+ "ldap://%127[^:]:%i/%127[^;];%127[^;];%127s",
+ server, &ldapport, basedn, prefix, suffix);
+ if (r < 3)
+ {
+ /* ldaps, including port number */
+ r = sscanf(port->auth_arg,
+ "ldaps://%127[^:]:%i/%127[^;];%127[^;];%127s",
+ server, &ldapport, basedn, prefix, suffix);
+ if (r >=3) ssl = 1;
+ }
+ if (r < 3)
+ {
+ /* ldap, no port number */
+ r = sscanf(port->auth_arg,
+ "ldap://%127[^/]/%127[^;];%127[^;];%127s",
+ server, basedn, prefix, suffix);
+ }
+ if (r < 2)
+ {
+ /* ldaps, no port number */
+ r = sscanf(port->auth_arg,
+ "ldaps://%127[^/]/%127[^;];%127[^;];%127s",
+ server, basedn, prefix, suffix);
+ if (r >= 2) ssl = 1;
+ }
+ if (r < 2)
+ {
+ ereport(LOG,
+ (errmsg("Invalid LDAP url: '%s'", port->auth_arg)));
+ return STATUS_ERROR;
+ }
+
+ sendAuthRequest(port, AUTH_REQ_PASSWORD);
+
+ passwd = recv_password_packet(port);
+ if (passwd == NULL)
+ return STATUS_EOF; /* client wouldn't send password */
+
+
+ ldap = ldap_init(server, ldapport);
+ if (!ldap)
+ {
+ ereport(LOG,
+ (errmsg("Failed to initialize LDAP: %i",
+#ifndef WIN32
+ errno
+#else
+ (int)LdapGetLastError()
+#endif
+ )));
+ return STATUS_ERROR;
+ }
+
+ if ((r = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldapversion)) != LDAP_SUCCESS)
+ {
+ ereport(LOG,
+ (errmsg("Failed to set LDAP version: %i", r)));
+ return STATUS_ERROR;
+ }
+
+ if (ssl)
+ {
+#ifndef WIN32
+ if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS)
+#else
+ if ((r = ldap_start_tls_sA(ldap, NULL, NULL, NULL, NULL)) != LDAP_SUCCESS)
+#endif
+ {
+ ereport(LOG,
+ (errmsg("Failed to start LDAP TLS session: %i", r)));
+ return STATUS_ERROR;
+ }
+ }
+
+ snprintf(fulluser, sizeof(fulluser)-1, "%s%s%s", prefix, port->user_name, suffix);
+ fulluser[sizeof(fulluser)-1] = '\0';
+
+ 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': %i",fulluser,server,r)));
+ return STATUS_ERROR;
+ }
+
+ return STATUS_OK;
+}
+#endif /* USE_LDAP */
+
/*
* Collect password response packet from frontend.
*
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 31be6ba33eb..a31f968baab 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.150 2006/03/05 15:58:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.151 2006/03/06 17:41:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -613,6 +613,10 @@ parse_hba_auth(ListCell **line_item, UserAuth *userauth_p,
else if (strcmp(token, "pam") == 0)
*userauth_p = uaPAM;
#endif
+#ifdef USE_LDAP
+ else if (strcmp(token,"ldap") == 0)
+ *userauth_p = uaLDAP;
+#endif
else
{
*error_p = true;
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index 521ce4ef096..abf4e827f13 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -35,7 +35,7 @@
# an IP address and netmask in separate columns to specify the set of hosts.
#
# METHOD can be "trust", "reject", "md5", "crypt", "password",
-# "krb5", "ident", or "pam". Note that "password" sends passwords
+# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
# in clear text; "md5" is preferred since it sends encrypted passwords.
#
# OPTION is the ident map or the name of the PAM service, depending on METHOD.