Index: configure.in =================================================================== RCS file: /projects/cvsroot/pgsql/configure.in,v retrieving revision 1.432 diff -c -r1.432 configure.in *** configure.in 5 Nov 2005 16:42:01 -0000 1.432 --- configure.in 31 Dec 2005 16:11:37 -0000 *************** *** 447,452 **** --- 447,463 ---- # + # LDAP + # + AC_MSG_CHECKING([whether to build with LDAP support]) + PGAC_ARG_BOOL(with, ldap, no, + [ --with-ldap build with LDAP support], + [AC_DEFINE([USE_LDAP], 1, [Define to 1 to build with LDAP support. (--with-ldap)])]) + AC_MSG_RESULT([$with_ldap]) + AC_SUBST(with_ldap) + + + # # Bonjour # AC_MSG_CHECKING([whether to build with Bonjour support]) *************** *** 678,683 **** --- 689,702 ---- fi + if test "$with_ldap" = yes ; then + if test "$PORTNAME" != "win32"; then + AC_CHECK_LIB(ldap, ldap_bind, [], [AC_MSG_ERROR([library 'ldap' is required for LDAP])]) + else + AC_CHECK_LIB(wldap32, ldap_bind, [], [AC_MSG_ERROR([library 'wldap32' is required for LDAP])]) + fi + fi + ## ## Header files ## *************** *** 753,758 **** --- 772,790 ---- [AC_MSG_ERROR([header file or is required for PAM.])])]) fi + if test "$with_ldap" = yes ; then + if test "$PORTNAME" != "win32"; then + AC_CHECK_HEADERS(ldap.h, [], + [AC_MSG_ERROR([header file is required for LDAP])]) + else + AC_CHECK_HEADERS(winldap.h, [], + [AC_MSG_ERROR([header file is required for LDAP])], + [AC_INCLUDES_DEFAULT + #include + ]) + fi + fi + if test "$with_bonjour" = yes ; then AC_CHECK_HEADER(DNSServiceDiscovery/DNSServiceDiscovery.h, [], [AC_MSG_ERROR([header file is required for Bonjour])]) fi Index: src/backend/libpq/auth.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/libpq/auth.c,v retrieving revision 1.132 diff -c -r1.132 auth.c *** src/backend/libpq/auth.c 17 Oct 2005 16:24:19 -0000 1.132 --- src/backend/libpq/auth.c 31 Dec 2005 16:11:37 -0000 *************** *** 69,74 **** --- 69,100 ---- * 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 + #else + /* Header broken in MingW */ + #define ldap_start_tls_sA __BROKEN_LDAP_HEADER + #include + #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,332 **** --- 353,363 ---- 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,460 **** --- 486,497 ---- break; #endif /* USE_PAM */ + #ifdef USE_LDAP + case uaLDAP: + status = CheckLDAPAuth(port); + break; + #endif + case uaTrust: status = STATUS_OK; break; *************** *** 674,679 **** --- 711,842 ---- #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]://[:]/[;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. * Index: src/backend/libpq/hba.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/libpq/hba.c,v retrieving revision 1.149 diff -c -r1.149 hba.c *** src/backend/libpq/hba.c 17 Oct 2005 16:24:19 -0000 1.149 --- src/backend/libpq/hba.c 31 Dec 2005 16:11:38 -0000 *************** *** 613,618 **** --- 613,622 ---- 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; Index: src/backend/libpq/pg_hba.conf.sample =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/libpq/pg_hba.conf.sample,v retrieving revision 1.60 diff -c -r1.60 pg_hba.conf.sample *** src/backend/libpq/pg_hba.conf.sample 11 Oct 2005 22:58:15 -0000 1.60 --- src/backend/libpq/pg_hba.conf.sample 31 Dec 2005 16:11:38 -0000 *************** *** 35,41 **** # 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 # 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. --- 35,41 ---- # an IP address and netmask in separate columns to specify the set of hosts. # # METHOD can be "trust", "reject", "md5", "crypt", "password", ! # "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. Index: src/include/pg_config.h.in =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/pg_config.h.in,v retrieving revision 1.87 diff -c -r1.87 pg_config.h.in *** src/include/pg_config.h.in 20 Aug 2005 23:26:32 -0000 1.87 --- src/include/pg_config.h.in 31 Dec 2005 16:11:38 -0000 *************** *** 639,644 **** --- 639,647 ---- /* Define to 1 to build with PAM support. (--with-pam) */ #undef USE_PAM + /* Define to 1 to build with LDAP support. (--with-ldap) */ + #undef USE_LDAP + /* Use replacement snprintf() functions. */ #undef USE_SNPRINTF Index: src/include/libpq/hba.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/libpq/hba.h,v retrieving revision 1.41 diff -c -r1.41 hba.h *** src/include/libpq/hba.h 15 Oct 2005 02:49:44 -0000 1.41 --- src/include/libpq/hba.h 31 Dec 2005 16:11:38 -0000 *************** *** 26,31 **** --- 26,34 ---- #ifdef USE_PAM ,uaPAM #endif /* USE_PAM */ + #ifdef USE_LDAP + ,uaLDAP + #endif } UserAuth; typedef struct Port hbaPort;