@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / libpq / auth . c , v 1.187 2009 / 10 / 16 22 : 08 : 36 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / libpq / auth . c , v 1.188 2009 / 12 / 12 21 : 35 : 21 mha Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -2096,40 +2096,18 @@ CheckPAMAuth(Port *port, char *user, char *password)
*/
# ifdef USE_LDAP
/*
* Initialize a connection to the LDAP server , including setting up
* TLS if requested .
*/
static int
CheckLDAPAuth ( Port * port )
InitializeLDAPConnection ( Port * port , LDAP * * ldap )
{
char * passwd ;
LDAP * ldap ;
int r ;
int ldapversion = LDAP_VERSION3 ;
char fulluser [ NAMEDATALEN + 256 + 1 ] ;
if ( ! port - > hba - > ldapserver | | port - > hba - > ldapserver [ 0 ] = = ' \0 ' )
{
ereport ( LOG ,
( errmsg ( " LDAP server not specified " ) ) ) ;
return STATUS_ERROR ;
}
if ( port - > hba - > ldapport = = 0 )
port - > hba - > ldapport = LDAP_PORT ;
sendAuthRequest ( port , AUTH_REQ_PASSWORD ) ;
passwd = recv_password_packet ( port ) ;
if ( passwd = = NULL )
return STATUS_EOF ; /* client wouldn't send password */
if ( strlen ( passwd ) = = 0 )
{
ereport ( LOG ,
( errmsg ( " empty password returned by client " ) ) ) ;
return STATUS_ERROR ;
}
int r ;
ldap = ldap_init ( port - > hba - > ldapserver , port - > hba - > ldapport ) ;
if ( ! ldap )
* ldap = ldap_init ( port - > hba - > ldapserver , port - > hba - > ldapport ) ;
if ( ! * ldap )
{
# ifndef WIN32
ereport ( LOG ,
@ -2143,9 +2121,9 @@ CheckLDAPAuth(Port *port)
return STATUS_ERROR ;
}
if ( ( r = ldap_set_option ( ldap , LDAP_OPT_PROTOCOL_VERSION , & ldapversion ) ) ! = LDAP_SUCCESS )
if ( ( r = ldap_set_option ( * ldap , LDAP_OPT_PROTOCOL_VERSION , & ldapversion ) ) ! = LDAP_SUCCESS )
{
ldap_unbind ( ldap ) ;
ldap_unbind ( * ldap ) ;
ereport ( LOG ,
( errmsg ( " could not set LDAP protocol version: error code %d " , r ) ) ) ;
return STATUS_ERROR ;
@ -2154,7 +2132,7 @@ CheckLDAPAuth(Port *port)
if ( port - > hba - > ldaptls )
{
# ifndef WIN32
if ( ( r = ldap_start_tls_s ( ldap , NULL , NULL ) ) ! = LDAP_SUCCESS )
if ( ( r = ldap_start_tls_s ( * ldap , NULL , NULL ) ) ! = LDAP_SUCCESS )
# else
static __ldap_start_tls_sA _ldap_start_tls_sA = NULL ;
@ -2174,7 +2152,7 @@ CheckLDAPAuth(Port *port)
* should never happen since we import other files from
* wldap32 , but check anyway
*/
ldap_unbind ( ldap ) ;
ldap_unbind ( * ldap ) ;
ereport ( LOG ,
( errmsg ( " could not load wldap32.dll " ) ) ) ;
return STATUS_ERROR ;
@ -2182,7 +2160,7 @@ CheckLDAPAuth(Port *port)
_ldap_start_tls_sA = ( __ldap_start_tls_sA ) GetProcAddress ( ldaphandle , " ldap_start_tls_sA " ) ;
if ( _ldap_start_tls_sA = = NULL )
{
ldap_unbind ( ldap ) ;
ldap_unbind ( * ldap ) ;
ereport ( LOG ,
( errmsg ( " could not load function _ldap_start_tls_sA in wldap32.dll " ) ,
errdetail ( " LDAP over SSL is not supported on this platform. " ) ) ) ;
@ -2195,21 +2173,202 @@ CheckLDAPAuth(Port *port)
* per process and is automatically cleaned up on process exit .
*/
}
if ( ( r = _ldap_start_tls_sA ( ldap , NULL , NULL , NULL , NULL ) ) ! = LDAP_SUCCESS )
if ( ( r = _ldap_start_tls_sA ( * ldap , NULL , NULL , NULL , NULL ) ) ! = LDAP_SUCCESS )
# endif
{
ldap_unbind ( ldap ) ;
ldap_unbind ( * ldap ) ;
ereport ( LOG ,
( errmsg ( " could not start LDAP TLS session: error code %d " , r ) ) ) ;
return STATUS_ERROR ;
}
}
snprintf ( fulluser , sizeof ( fulluser ) , " %s%s%s " ,
return STATUS_OK ;
}
/*
* Perform LDAP authentication
*/
static int
CheckLDAPAuth ( Port * port )
{
char * passwd ;
LDAP * ldap ;
int r ;
char * fulluser ;
if ( ! port - > hba - > ldapserver | | port - > hba - > ldapserver [ 0 ] = = ' \0 ' )
{
ereport ( LOG ,
( errmsg ( " LDAP server not specified " ) ) ) ;
return STATUS_ERROR ;
}
if ( port - > hba - > ldapport = = 0 )
port - > hba - > ldapport = LDAP_PORT ;
sendAuthRequest ( port , AUTH_REQ_PASSWORD ) ;
passwd = recv_password_packet ( port ) ;
if ( passwd = = NULL )
return STATUS_EOF ; /* client wouldn't send password */
if ( strlen ( passwd ) = = 0 )
{
ereport ( LOG ,
( errmsg ( " empty password returned by client " ) ) ) ;
return STATUS_ERROR ;
}
if ( InitializeLDAPConnection ( port , & ldap ) = = STATUS_ERROR )
/* Error message already sent */
return STATUS_ERROR ;
if ( port - > hba - > ldapbasedn )
{
/*
* First perform an LDAP search to find the DN for the user we are trying to log
* in as .
*/
char * filter ;
LDAPMessage * search_message ;
LDAPMessage * entry ;
char * attributes [ 2 ] ;
char * dn ;
char * c ;
/*
* Disallow any characters that we would otherwise need to escape , since they
* aren ' t really reasonable in a username anyway . Allowing them would make it
* possible to inject any kind of custom filters in the LDAP filter .
*/
for ( c = port - > user_name ; * c ; c + + )
{
if ( * c = = ' * ' | |
* c = = ' ( ' | |
* c = = ' ) ' | |
* c = = ' \\ ' | |
* c = = ' / ' )
{
ereport ( LOG ,
( errmsg ( " invalid character in username for LDAP authentication " ) ) ) ;
return STATUS_ERROR ;
}
}
/*
* Bind with a pre - defined username / password ( if available ) for searching . If
* none is specified , this turns into an anonymous bind .
*/
r = ldap_simple_bind_s ( ldap ,
port - > hba - > ldapbinddn ? port - > hba - > ldapbinddn : " " ,
port - > hba - > ldapbindpasswd ? port - > hba - > ldapbindpasswd : " " ) ;
if ( r ! = LDAP_SUCCESS )
{
ereport ( LOG ,
( errmsg ( " could not perform initial LDAP bind for ldapbinddn \" %s \" on server \" %s \" : error code %d " ,
port - > hba - > ldapbinddn , port - > hba - > ldapserver , r ) ) ) ;
return STATUS_ERROR ;
}
/* Fetch just one attribute, else *all* attributes are returned */
attributes [ 0 ] = port - > hba - > ldapsearchattribute ? port - > hba - > ldapsearchattribute : " uid " ;
attributes [ 1 ] = NULL ;
filter = palloc ( strlen ( attributes [ 0 ] ) + strlen ( port - > user_name ) + 4 ) ;
sprintf ( filter , " (%s=%s) " ,
attributes [ 0 ] ,
port - > user_name ) ;
r = ldap_search_s ( ldap ,
port - > hba - > ldapbasedn ,
LDAP_SCOPE_SUBTREE ,
filter ,
attributes ,
0 ,
& search_message ) ;
if ( r ! = LDAP_SUCCESS )
{
ereport ( LOG ,
( errmsg ( " could not search LDAP for filter \" %s \" on server \" %s \" : error code %d " ,
filter , port - > hba - > ldapserver , r ) ) ) ;
pfree ( filter ) ;
return STATUS_ERROR ;
}
if ( ldap_count_entries ( ldap , search_message ) ! = 1 )
{
if ( ldap_count_entries ( ldap , search_message ) = = 0 )
ereport ( LOG ,
( errmsg ( " LDAP search failed for filter \" %s \" on server \" %s \" : no such user " ,
filter , port - > hba - > ldapserver ) ) ) ;
else
ereport ( LOG ,
( errmsg ( " LDAP search failed for filter \" %s \" on server \" %s \" : user is not unique (%d matches) " ,
filter , port - > hba - > ldapserver , ldap_count_entries ( ldap , search_message ) ) ) ) ;
pfree ( filter ) ;
ldap_msgfree ( search_message ) ;
return STATUS_ERROR ;
}
entry = ldap_first_entry ( ldap , search_message ) ;
dn = ldap_get_dn ( ldap , entry ) ;
if ( dn = = NULL )
{
int error ;
( 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 ) ) ) ) ;
pfree ( filter ) ;
ldap_msgfree ( search_message ) ;
return STATUS_ERROR ;
}
fulluser = pstrdup ( dn ) ;
pfree ( filter ) ;
ldap_memfree ( dn ) ;
ldap_msgfree ( search_message ) ;
/* Unbind and disconnect from the LDAP server */
r = ldap_unbind_s ( ldap ) ;
if ( r ! = LDAP_SUCCESS )
{
int error ;
( void ) ldap_get_option ( ldap , LDAP_OPT_ERROR_NUMBER , & error ) ;
ereport ( LOG ,
( errmsg ( " could not unbind after searching for user \" %s \" on server \" %s \" : %s " ,
fulluser , port - > hba - > ldapserver , ldap_err2string ( error ) ) ) ) ;
pfree ( fulluser ) ;
return STATUS_ERROR ;
}
/*
* Need to re - initialize the LDAP connection , so that we can bind
* to it with a different username .
*/
if ( InitializeLDAPConnection ( port , & ldap ) = = STATUS_ERROR )
{
pfree ( fulluser ) ;
/* Error message already sent */
return STATUS_ERROR ;
}
}
else
{
fulluser = palloc ( ( port - > hba - > ldapprefix ? strlen ( port - > hba - > ldapprefix ) : 0 ) +
strlen ( port - > user_name ) +
( port - > hba - > ldapsuffix ? strlen ( port - > hba - > ldapsuffix ) : 0 ) +
1 ) ;
sprintf ( fulluser , " %s%s%s " ,
port - > hba - > ldapprefix ? port - > hba - > ldapprefix : " " ,
port - > user_name ,
port - > hba - > ldapsuffix ? port - > hba - > ldapsuffix : " " ) ;
fulluser [ sizeof ( fulluser ) - 1 ] = ' \0 ' ;
}
r = ldap_simple_bind_s ( ldap , fulluser , passwd ) ;
ldap_unbind ( ldap ) ;
@ -2219,9 +2378,12 @@ CheckLDAPAuth(Port *port)
ereport ( LOG ,
( errmsg ( " LDAP login failed for user \" %s \" on server \" %s \" : error code %d " ,
fulluser , port - > hba - > ldapserver , r ) ) ) ;
pfree ( fulluser ) ;
return STATUS_ERROR ;
}
pfree ( fulluser ) ;
return STATUS_OK ;
}
# endif /* USE_LDAP */