blob: 9923b507237eb054307bee56981f86aae3ba5f61 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_extensions.hxx"
#include "ldapaccess.hxx"
#include <rtl/ustrbuf.hxx>
#include <rtl/strbuf.hxx>
namespace extensions { namespace config { namespace ldap {
oslModule LdapConnection::s_Ldap_Module = NULL;
t_ldap_unbind_s LdapConnection::s_p_unbind_s = NULL;
t_ldap_simple_bind_s LdapConnection::s_p_simple_bind_s = NULL;
t_ldap_set_option LdapConnection::s_p_set_option = NULL;
t_ldap_err2string LdapConnection::s_p_err2string = NULL;
t_ldap_init LdapConnection::s_p_init = NULL;
t_ldap_msgfree LdapConnection::s_p_msgfree = NULL;
t_ldap_get_dn LdapConnection::s_p_get_dn = NULL;
t_ldap_first_entry LdapConnection::s_p_first_entry = NULL;
t_ldap_first_attribute LdapConnection::s_p_first_attribute = NULL;
t_ldap_next_attribute LdapConnection::s_p_next_attribute = NULL;
t_ldap_search_s LdapConnection::s_p_search_s = NULL;
t_ldap_value_free LdapConnection::s_p_value_free = NULL;
t_ldap_get_values LdapConnection::s_p_get_values = NULL;
t_ldap_memfree LdapConnection::s_p_memfree = NULL;
//------------------------------------------------------------------------------
typedef int LdapErrCode;
//------------------------------------------------------------------------------
struct LdapMessageHolder
{
LdapMessageHolder() : msg(0) {}
~LdapMessageHolder()
{
if (msg)
(*LdapConnection::s_p_msgfree)(msg);
}
LDAPMessage * msg;
private:
LdapMessageHolder(LdapMessageHolder const&);
void operator=(LdapMessageHolder const&);
};
//------------------------------------------------------------------------------
LdapConnection::~LdapConnection()
{
if (isValid()) disconnect();
}
//------------------------------------------------------------------------------
void LdapConnection::disconnect()
{
if (mConnection != NULL)
{
(*s_p_unbind_s)(mConnection) ;
mConnection = NULL;
}
}
//------------------------------------------------------------------------------
static void checkLdapReturnCode(const sal_Char *aOperation,
LdapErrCode aRetCode,
LDAP * /*aConnection*/)
{
if (aRetCode == LDAP_SUCCESS) { return ; }
static const sal_Char *kNoSpecificMessage = "No additional information" ;
rtl::OUStringBuffer message ;
if (aOperation != NULL)
{
message.appendAscii(aOperation).appendAscii(": ") ;
}
message.appendAscii((*LdapConnection::s_p_err2string)(aRetCode)).appendAscii(" (") ;
sal_Char *stub = NULL ;
#ifndef LDAP_OPT_SIZELIMIT // for use with OpenLDAP
(*s_p_get_lderrno)(aConnection, NULL, &stub) ;
#endif
if (stub != NULL)
{
message.appendAscii(stub) ;
// It would seem the message returned is actually
// not a copy of a string but rather some static
// string itself. At any rate freeing it seems to
// cause some undue problems at least on Windows.
// This call is thus disabled for the moment.
//(*s_p_memfree)(stub) ;
}
else { message.appendAscii(kNoSpecificMessage) ; }
message.appendAscii(")") ;
throw ldap::LdapGenericException(message.makeStringAndClear(),
NULL, aRetCode) ;
}
//------------------------------------------------------------------------------
void LdapConnection::connectSimple(const LdapDefinition& aDefinition)
throw (ldap::LdapConnectionException, ldap::LdapGenericException)
{
OSL_ENSURE(!isValid(), "Recoonecting an LDAP connection that is already established");
if (isValid()) disconnect();
mLdapDefinition = aDefinition;
connectSimple();
}
//------------------------------------------------------------------------------
void LdapConnection::connectSimple()
throw (ldap::LdapConnectionException, ldap::LdapGenericException)
{
if (!isValid())
{
// Connect to the server
initConnection() ;
// Set Protocol V3
int version = LDAP_VERSION3;
(*s_p_set_option)(mConnection,
LDAP_OPT_PROTOCOL_VERSION,
&version);
#ifdef LDAP_X_OPT_CONNECT_TIMEOUT // OpenLDAP doesn't support this and the func
/* timeout is specified in milliseconds -> 4 seconds*/
int timeout = 4000;
(*s_p_set_option)( mConnection,
LDAP_X_OPT_CONNECT_TIMEOUT,
&timeout );
#endif
// Do the bind
LdapErrCode retCode = (*s_p_simple_bind_s)(mConnection,
mLdapDefinition.mAnonUser.getStr(),
mLdapDefinition.mAnonCredentials.getStr()) ;
checkLdapReturnCode("SimpleBind", retCode, mConnection) ;
}
}
//------------------------------------------------------------------------------
void LdapConnection::initConnection()
throw (ldap::LdapConnectionException)
{
if (mLdapDefinition.mServer.getLength() == 0)
{
rtl::OUStringBuffer message ;
message.appendAscii("Cannot initialise connection to LDAP: No server specified.") ;
throw ldap::LdapConnectionException(message.makeStringAndClear(), NULL) ;
}
if (mLdapDefinition.mPort == 0) mLdapDefinition.mPort = LDAP_PORT;
mConnection = (*s_p_init)( mLdapDefinition.mServer.getStr(),
mLdapDefinition.mPort) ;
if (mConnection == NULL)
{
rtl::OUStringBuffer message ;
message.appendAscii("Cannot initialise connection to LDAP server ") ;
message.appendAscii( mLdapDefinition.mServer.getStr());
message.appendAscii(":") ;
message.append(mLdapDefinition.mPort) ;
throw ldap::LdapConnectionException(message.makeStringAndClear(),
NULL) ;
}
}
//------------------------------------------------------------------------------
void LdapConnection::getUserProfile(
const rtl::OUString& aUser, LdapData * data)
throw (lang::IllegalArgumentException,
ldap::LdapConnectionException, ldap::LdapGenericException)
{
OSL_ASSERT(data != 0);
if (!isValid()) { connectSimple(); }
rtl::OString aUserDn =findUserDn( rtl::OUStringToOString(aUser, RTL_TEXTENCODING_ASCII_US));
LdapMessageHolder result;
LdapErrCode retCode = (*s_p_search_s)(mConnection,
aUserDn.getStr(),
LDAP_SCOPE_BASE,
"(objectclass=*)",
0,
0, // Attributes + values
&result.msg) ;
checkLdapReturnCode("getUserProfile", retCode,mConnection) ;
void * ptr;
char * attr = (*s_p_first_attribute)(mConnection, result.msg, &ptr);
while (attr != 0) {
char ** values = (*s_p_get_values)(mConnection, result.msg, attr);
if (values != 0) {
data->insert(
LdapData::value_type(
rtl::OStringToOUString(attr, RTL_TEXTENCODING_ASCII_US),
rtl::OStringToOUString(*values, RTL_TEXTENCODING_UTF8)));
(*s_p_value_free)(values);
}
attr = (*s_p_next_attribute)(mConnection, result.msg, ptr);
}
}
//------------------------------------------------------------------------------
rtl::OString LdapConnection::findUserDn(const rtl::OString& aUser)
throw (lang::IllegalArgumentException,
ldap::LdapConnectionException, ldap::LdapGenericException)
{
if (!isValid()) { connectSimple(); }
if (aUser.getLength() == 0)
{
throw lang::IllegalArgumentException(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM
("LdapConnection::findUserDn -User id is empty")).getStr(),
NULL, 0) ;
}
rtl::OStringBuffer filter( "(&(objectclass=" );
filter.append( mLdapDefinition.mUserObjectClass ).append(")(") ;
filter.append( mLdapDefinition.mUserUniqueAttr ).append("=").append(aUser).append("))") ;
LdapMessageHolder result;
sal_Char * attributes [2];
attributes[0]= const_cast<sal_Char *>(LDAP_NO_ATTRS);
attributes[1]= NULL;
LdapErrCode retCode = (*s_p_search_s)(mConnection,
mLdapDefinition.mBaseDN.getStr(),
LDAP_SCOPE_SUBTREE,
filter.getStr(), attributes, 0, &result.msg) ;
checkLdapReturnCode("FindUserDn", retCode,mConnection) ;
rtl::OString userDn ;
LDAPMessage *entry = (*s_p_first_entry)(mConnection, result.msg) ;
if (entry != NULL)
{
sal_Char *charsDn = (*s_p_get_dn)(mConnection, entry) ;
userDn = charsDn ;
(*s_p_memfree)(charsDn) ;
}
else
{
OSL_ENSURE( false, "LdapConnection::findUserDn-could not get DN for User ");
}
return userDn ;
}
extern "C" { static void SAL_CALL thisModule() {} }
void LdapConnection::loadModule()
{
if ( !s_Ldap_Module )
{
#if defined(WNT)
# define LIBLDAP "nsldap32v50.dll"
#else
# ifdef WITH_OPENLDAP
# define xstr(s) str(s)
# define str(s) #s
# define LIBLDAP "libldap-" xstr(LDAP_VENDOR_VERSION_MAJOR) "." xstr(LDAP_VENDOR_VERSION_MINOR) ".so." xstr(LDAP_VENDOR_VERSION_MAJOR)
# else
# define LIBLDAP "libldap50.so"
# endif
#endif
const ::rtl::OUString sModuleName(RTL_CONSTASCII_USTRINGPARAM(LIBLDAP));
// load the dbtools library
s_Ldap_Module = osl_loadModuleRelative(&thisModule, sModuleName.pData, 0);
if ( s_Ldap_Module != NULL )
{
s_p_unbind_s = (t_ldap_unbind_s)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_unbind_s").pData));
s_p_simple_bind_s = (t_ldap_simple_bind_s)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_simple_bind_s").pData));
s_p_set_option = (t_ldap_set_option)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_set_option").pData));
s_p_err2string = (t_ldap_err2string)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_err2string").pData));
s_p_init = (t_ldap_init)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_init").pData));
s_p_msgfree = (t_ldap_msgfree)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_msgfree").pData));
s_p_get_dn = (t_ldap_get_dn)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_get_dn").pData));
s_p_first_entry = (t_ldap_first_entry)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_first_entry").pData));
s_p_first_attribute = (t_ldap_first_attribute)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_first_attribute").pData));
s_p_next_attribute = (t_ldap_next_attribute)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_next_attribute").pData));
s_p_search_s = (t_ldap_search_s)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_search_s").pData));
s_p_value_free = (t_ldap_value_free)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_value_free").pData));
s_p_get_values = (t_ldap_get_values)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_get_values").pData));
s_p_memfree = (t_ldap_memfree)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_memfree").pData));
}
}
}
//------------------------------------------------------------------------------
} } } // extensions.config.ldap