1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ldapaccess.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_extensions.hxx"
34 #include "ldapaccess.hxx"
36 #include "ldapuserprof.hxx"
37 #include <rtl/ustrbuf.hxx>
38 #include <rtl/strbuf.hxx>
41 namespace extensions
{ namespace config
{ namespace ldap
{
43 oslModule
LdapConnection::s_Ldap_Module
= NULL
;
44 t_ldap_unbind_s
LdapConnection::s_p_unbind_s
= NULL
;
45 t_ldap_simple_bind_s
LdapConnection::s_p_simple_bind_s
= NULL
;
46 t_ldap_set_option
LdapConnection::s_p_set_option
= NULL
;
47 t_ldap_err2string
LdapConnection::s_p_err2string
= NULL
;
48 t_ldap_init
LdapConnection::s_p_init
= NULL
;
49 t_ldap_msgfree
LdapConnection::s_p_msgfree
= NULL
;
50 t_ldap_get_dn
LdapConnection::s_p_get_dn
= NULL
;
51 t_ldap_first_entry
LdapConnection::s_p_first_entry
= NULL
;
52 t_ldap_search_s
LdapConnection::s_p_search_s
= NULL
;
53 t_ldap_value_free
LdapConnection::s_p_value_free
= NULL
;
54 t_ldap_get_values
LdapConnection::s_p_get_values
= NULL
;
55 t_ldap_memfree
LdapConnection::s_p_memfree
= NULL
;
56 //------------------------------------------------------------------------------
57 typedef int LdapErrCode
;
58 //------------------------------------------------------------------------------
59 struct LdapMessageHolder
61 LdapMessageHolder() : msg(0) {}
65 (*LdapConnection::s_p_msgfree
)(msg
);
71 LdapMessageHolder(LdapMessageHolder
const&);
72 void operator=(LdapMessageHolder
const&);
74 //------------------------------------------------------------------------------
75 LdapConnection::~LdapConnection()
77 if (isValid()) disconnect();
79 //------------------------------------------------------------------------------
81 void LdapConnection::disconnect()
83 if (mConnection
!= NULL
)
85 (*s_p_unbind_s
)(mConnection
) ;
89 //------------------------------------------------------------------------------
91 static void checkLdapReturnCode(const sal_Char
*aOperation
,
93 LDAP
* /*aConnection*/)
95 if (aRetCode
== LDAP_SUCCESS
) { return ; }
97 static const sal_Char
*kNoSpecificMessage
= "No additional information" ;
98 rtl::OUStringBuffer message
;
100 if (aOperation
!= NULL
)
102 message
.appendAscii(aOperation
).appendAscii(": ") ;
104 message
.appendAscii((*LdapConnection::s_p_err2string
)(aRetCode
)).appendAscii(" (") ;
105 sal_Char
*stub
= NULL
;
107 #ifndef LDAP_OPT_SIZELIMIT // for use with OpenLDAP
108 (*s_p_get_lderrno
)(aConnection
, NULL
, &stub
) ;
112 message
.appendAscii(stub
) ;
113 // It would seem the message returned is actually
114 // not a copy of a string but rather some static
115 // string itself. At any rate freeing it seems to
116 // cause some undue problems at least on Windows.
117 // This call is thus disabled for the moment.
118 //(*s_p_memfree)(stub) ;
120 else { message
.appendAscii(kNoSpecificMessage
) ; }
121 message
.appendAscii(")") ;
122 throw ldap::LdapGenericException(message
.makeStringAndClear(),
125 //------------------------------------------------------------------------------
126 void LdapConnection::connectSimple(const LdapDefinition
& aDefinition
)
127 throw (ldap::LdapConnectionException
, ldap::LdapGenericException
)
129 OSL_ENSURE(!isValid(), "Recoonecting an LDAP connection that is already established");
130 if (isValid()) disconnect();
132 mLdapDefinition
= aDefinition
;
135 //------------------------------------------------------------------------------
136 void LdapConnection::connectSimple()
137 throw (ldap::LdapConnectionException
, ldap::LdapGenericException
)
141 // Connect to the server
144 int version
= LDAP_VERSION3
;
145 (*s_p_set_option
)(mConnection
,
146 LDAP_OPT_PROTOCOL_VERSION
,
149 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT // OpenLDAP doesn't support this and the func
150 /* timeout is specified in milliseconds -> 4 seconds*/
152 (*s_p_set_option
)( mConnection
,
153 LDAP_X_OPT_CONNECT_TIMEOUT
,
158 LdapErrCode retCode
= (*s_p_simple_bind_s
)(mConnection
,
159 mLdapDefinition
.mAnonUser
,
160 mLdapDefinition
.mAnonCredentials
) ;
162 checkLdapReturnCode("SimpleBind", retCode
, mConnection
) ;
165 //------------------------------------------------------------------------------
166 void LdapConnection::initConnection()
167 throw (ldap::LdapConnectionException
)
169 if (mLdapDefinition
.mServer
.getLength() == 0)
171 rtl::OUStringBuffer message
;
173 message
.appendAscii("Cannot initialise connection to LDAP: No server specified.") ;
174 throw ldap::LdapConnectionException(message
.makeStringAndClear(), NULL
) ;
177 if (mLdapDefinition
.mPort
== 0) mLdapDefinition
.mPort
= LDAP_PORT
;
179 mConnection
= (*s_p_init
)(mLdapDefinition
.mServer
,
180 mLdapDefinition
.mPort
) ;
181 if (mConnection
== NULL
)
183 rtl::OUStringBuffer message
;
185 message
.appendAscii("Cannot initialise connection to LDAP server ") ;
186 message
.appendAscii(mLdapDefinition
.mServer
) ;
187 message
.appendAscii(":") ;
188 message
.append(mLdapDefinition
.mPort
) ;
189 throw ldap::LdapConnectionException(message
.makeStringAndClear(),
193 //------------------------------------------------------------------------------
194 void LdapConnection::getUserProfile(const rtl::OUString
& aUser
,
195 const LdapUserProfileMap
& aUserProfileMap
,
196 LdapUserProfile
& aUserProfile
)
197 throw (lang::IllegalArgumentException
,
198 ldap::LdapConnectionException
, ldap::LdapGenericException
)
200 if (!isValid()) { connectSimple(); }
202 rtl::OString aUserDn
=findUserDn( rtl::OUStringToOString(aUser
, RTL_TEXTENCODING_ASCII_US
));
204 LdapMessageHolder result
;
205 LdapErrCode retCode
= (*s_p_search_s
)(mConnection
,
209 const_cast<sal_Char
**>(aUserProfileMap
.getLdapAttributes()),
210 0, // Attributes + values
213 checkLdapReturnCode("getUserProfile", retCode
,mConnection
) ;
216 aUserProfileMap
.ldapToUserProfile(mConnection
,
221 //------------------------------------------------------------------------------
222 rtl::OString
LdapConnection::findUserDn(const rtl::OString
& aUser
)
223 throw (lang::IllegalArgumentException
,
224 ldap::LdapConnectionException
, ldap::LdapGenericException
)
226 if (!isValid()) { connectSimple(); }
228 if (aUser
.getLength() == 0)
230 throw lang::IllegalArgumentException(
231 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM
232 ("LdapConnection::findUserDn -User id is empty")),
238 rtl::OStringBuffer
filter( "(&(objectclass=" );
240 filter
.append( mLdapDefinition
.mUserObjectClass
).append(")(") ;
241 filter
.append( mLdapDefinition
.mUserUniqueAttr
).append("=").append(aUser
).append("))") ;
243 LdapMessageHolder result
;
244 sal_Char
* attributes
[2];
245 attributes
[0]= const_cast<sal_Char
*>(LDAP_NO_ATTRS
);
247 LdapErrCode retCode
= (*s_p_search_s
)(mConnection
,
248 mLdapDefinition
.mBaseDN
,
250 filter
.makeStringAndClear(), attributes
, 0, &result
.msg
) ;
252 checkLdapReturnCode("FindUserDn", retCode
,mConnection
) ;
253 rtl::OString userDn
;
254 LDAPMessage
*entry
= (*s_p_first_entry
)(mConnection
, result
.msg
) ;
258 sal_Char
*charsDn
= (*s_p_get_dn
)(mConnection
, entry
) ;
261 (*s_p_memfree
)(charsDn
) ;
265 OSL_ENSURE( false, "LdapConnection::findUserDn-could not get DN for User ");
270 //------------------------------------------------------------------------------
271 rtl::OString
LdapConnection::getSingleAttribute(
272 const rtl::OString
& aDn
,
273 const rtl::OString
& aAttribute
)
274 throw (ldap::LdapConnectionException
, ldap::LdapGenericException
)
276 if (!isValid()) { connectSimple(); }
277 const sal_Char
*attributes
[2] ;
280 attributes
[0] = aAttribute
;
282 LdapMessageHolder result
;
283 LdapErrCode retCode
= (*s_p_search_s
)(mConnection
,
287 const_cast<sal_Char
**>(attributes
),
288 0, // Attributes + values
291 if (retCode
== LDAP_NO_SUCH_OBJECT
)
295 checkLdapReturnCode("GetSingleAttribute", retCode
, mConnection
) ;
296 LDAPMessage
*entry
= (*s_p_first_entry
)(mConnection
, result
.msg
) ;
300 sal_Char
**values
= (*s_p_get_values
)(mConnection
, entry
,
305 if (*values
!= NULL
) { value
= *values
; }
306 (*s_p_value_free
)(values
) ;
312 extern "C" { static void SAL_CALL
thisModule() {} }
313 void LdapConnection::loadModule()
315 if ( !s_Ldap_Module
)
317 #if defined(WIN) || defined(WNT)
318 # define LIBLDAP "nsldap32v50.dll"
320 # ifdef WITH_OPENLDAP
321 # define xstr(s) str(s)
323 # define LIBLDAP "libldap-" xstr(LDAP_VENDOR_VERSION_MAJOR) "." xstr(LDAP_VENDOR_VERSION_MINOR) ".so." xstr(LDAP_VENDOR_VERSION_MAJOR)
325 # define LIBLDAP "libldap50.so"
328 const ::rtl::OUString
sModuleName(RTL_CONSTASCII_USTRINGPARAM(LIBLDAP
));
330 // load the dbtools library
331 s_Ldap_Module
= osl_loadModuleRelative(&thisModule
, sModuleName
.pData
, 0);
332 if ( s_Ldap_Module
!= NULL
)
334 s_p_unbind_s
= (t_ldap_unbind_s
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_unbind_s").pData
));
335 s_p_simple_bind_s
= (t_ldap_simple_bind_s
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_simple_bind_s").pData
));
336 s_p_set_option
= (t_ldap_set_option
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_set_option").pData
));
337 s_p_err2string
= (t_ldap_err2string
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_err2string").pData
));
338 s_p_init
= (t_ldap_init
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_init").pData
));
339 s_p_msgfree
= (t_ldap_msgfree
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_msgfree").pData
));
340 s_p_get_dn
= (t_ldap_get_dn
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_get_dn").pData
));
341 s_p_first_entry
= (t_ldap_first_entry
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_first_entry").pData
));
342 s_p_search_s
= (t_ldap_search_s
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_search_s").pData
));
343 s_p_value_free
= (t_ldap_value_free
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_value_free").pData
));
344 s_p_get_values
= (t_ldap_get_values
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_get_values").pData
));
345 s_p_memfree
= (t_ldap_memfree
)(osl_getFunctionSymbol(s_Ldap_Module
, ::rtl::OUString::createFromAscii("ldap_memfree").pData
));
350 //------------------------------------------------------------------------------
351 } } } // extensions.config.ldap