12a97ec55SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
32a97ec55SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
42a97ec55SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
52a97ec55SAndrew Rist  * distributed with this work for additional information
62a97ec55SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
72a97ec55SAndrew Rist  * to you under the Apache License, Version 2.0 (the
82a97ec55SAndrew Rist  * "License"); you may not use this file except in compliance
92a97ec55SAndrew Rist  * with the License.  You may obtain a copy of the License at
102a97ec55SAndrew Rist  *
112a97ec55SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
122a97ec55SAndrew Rist  *
132a97ec55SAndrew Rist  * Unless required by applicable law or agreed to in writing,
142a97ec55SAndrew Rist  * software distributed under the License is distributed on an
152a97ec55SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
162a97ec55SAndrew Rist  * KIND, either express or implied.  See the License for the
172a97ec55SAndrew Rist  * specific language governing permissions and limitations
182a97ec55SAndrew Rist  * under the License.
192a97ec55SAndrew Rist  *
202a97ec55SAndrew Rist  *************************************************************/
212a97ec55SAndrew Rist 
222a97ec55SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_extensions.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "ldapaccess.hxx"
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
30cdf0e10cSrcweir #include <rtl/strbuf.hxx>
31cdf0e10cSrcweir 
32cdf0e10cSrcweir 
33cdf0e10cSrcweir namespace extensions { namespace config { namespace ldap {
34cdf0e10cSrcweir 
35cdf0e10cSrcweir oslModule		LdapConnection::s_Ldap_Module = NULL;
36cdf0e10cSrcweir t_ldap_unbind_s          LdapConnection::s_p_unbind_s = NULL;
37cdf0e10cSrcweir t_ldap_simple_bind_s	 LdapConnection::s_p_simple_bind_s = NULL;
38cdf0e10cSrcweir t_ldap_set_option        LdapConnection::s_p_set_option = NULL;
39cdf0e10cSrcweir t_ldap_err2string        LdapConnection::s_p_err2string = NULL;
40cdf0e10cSrcweir t_ldap_init              LdapConnection::s_p_init = NULL;
41cdf0e10cSrcweir t_ldap_msgfree           LdapConnection::s_p_msgfree = NULL;
42cdf0e10cSrcweir t_ldap_get_dn            LdapConnection::s_p_get_dn = NULL;
43cdf0e10cSrcweir t_ldap_first_entry       LdapConnection::s_p_first_entry = NULL;
44cdf0e10cSrcweir t_ldap_first_attribute   LdapConnection::s_p_first_attribute = NULL;
45cdf0e10cSrcweir t_ldap_next_attribute    LdapConnection::s_p_next_attribute = NULL;
46cdf0e10cSrcweir t_ldap_search_s          LdapConnection::s_p_search_s = NULL;
47cdf0e10cSrcweir t_ldap_value_free        LdapConnection::s_p_value_free = NULL;
48cdf0e10cSrcweir t_ldap_get_values        LdapConnection::s_p_get_values = NULL;
49cdf0e10cSrcweir t_ldap_memfree           LdapConnection::s_p_memfree = NULL;
50cdf0e10cSrcweir //------------------------------------------------------------------------------
51cdf0e10cSrcweir typedef int LdapErrCode;
52cdf0e10cSrcweir //------------------------------------------------------------------------------
53cdf0e10cSrcweir struct LdapMessageHolder
54cdf0e10cSrcweir {
LdapMessageHolderextensions::config::ldap::LdapMessageHolder55cdf0e10cSrcweir     LdapMessageHolder() : msg(0) {}
~LdapMessageHolderextensions::config::ldap::LdapMessageHolder56cdf0e10cSrcweir     ~LdapMessageHolder()
57cdf0e10cSrcweir     {
58cdf0e10cSrcweir         if (msg)
59cdf0e10cSrcweir             (*LdapConnection::s_p_msgfree)(msg);
60cdf0e10cSrcweir     }
61cdf0e10cSrcweir 
62cdf0e10cSrcweir     LDAPMessage * msg;
63cdf0e10cSrcweir 
64cdf0e10cSrcweir private:
65cdf0e10cSrcweir     LdapMessageHolder(LdapMessageHolder const&);
66cdf0e10cSrcweir     void operator=(LdapMessageHolder const&);
67cdf0e10cSrcweir };
68cdf0e10cSrcweir //------------------------------------------------------------------------------
~LdapConnection()69cdf0e10cSrcweir LdapConnection::~LdapConnection()
70cdf0e10cSrcweir {
71cdf0e10cSrcweir     if (isValid()) disconnect();
72cdf0e10cSrcweir }
73cdf0e10cSrcweir //------------------------------------------------------------------------------
74cdf0e10cSrcweir 
disconnect()75cdf0e10cSrcweir void LdapConnection::disconnect()
76cdf0e10cSrcweir {
77cdf0e10cSrcweir     if (mConnection != NULL)
78cdf0e10cSrcweir     {
79cdf0e10cSrcweir         (*s_p_unbind_s)(mConnection) ;
80cdf0e10cSrcweir         mConnection = NULL;
81cdf0e10cSrcweir     }
82cdf0e10cSrcweir }
83cdf0e10cSrcweir //------------------------------------------------------------------------------
84cdf0e10cSrcweir 
checkLdapReturnCode(const sal_Char * aOperation,LdapErrCode aRetCode,LDAP *)85cdf0e10cSrcweir static void checkLdapReturnCode(const sal_Char *aOperation,
86cdf0e10cSrcweir                                 LdapErrCode aRetCode,
87cdf0e10cSrcweir                                 LDAP * /*aConnection*/)
88cdf0e10cSrcweir {
89cdf0e10cSrcweir     if (aRetCode == LDAP_SUCCESS) { return ; }
90cdf0e10cSrcweir 
91cdf0e10cSrcweir     static const sal_Char *kNoSpecificMessage = "No additional information" ;
92cdf0e10cSrcweir     rtl::OUStringBuffer message ;
93cdf0e10cSrcweir 
94cdf0e10cSrcweir     if (aOperation != NULL)
95cdf0e10cSrcweir     {
96cdf0e10cSrcweir         message.appendAscii(aOperation).appendAscii(": ") ;
97cdf0e10cSrcweir     }
98cdf0e10cSrcweir     message.appendAscii((*LdapConnection::s_p_err2string)(aRetCode)).appendAscii(" (") ;
99cdf0e10cSrcweir     sal_Char *stub = NULL ;
100cdf0e10cSrcweir 
101cdf0e10cSrcweir #ifndef LDAP_OPT_SIZELIMIT // for use with OpenLDAP
102cdf0e10cSrcweir     (*s_p_get_lderrno)(aConnection, NULL, &stub) ;
103cdf0e10cSrcweir #endif
104cdf0e10cSrcweir     if (stub != NULL)
105cdf0e10cSrcweir     {
106cdf0e10cSrcweir         message.appendAscii(stub) ;
107cdf0e10cSrcweir         // It would seem the message returned is actually
108cdf0e10cSrcweir         // not a copy of a string but rather some static
109cdf0e10cSrcweir         // string itself. At any rate freeing it seems to
110cdf0e10cSrcweir         // cause some undue problems at least on Windows.
111cdf0e10cSrcweir         // This call is thus disabled for the moment.
112cdf0e10cSrcweir         //(*s_p_memfree)(stub) ;
113cdf0e10cSrcweir     }
114cdf0e10cSrcweir     else { message.appendAscii(kNoSpecificMessage) ; }
115cdf0e10cSrcweir     message.appendAscii(")") ;
116cdf0e10cSrcweir     throw ldap::LdapGenericException(message.makeStringAndClear(),
117cdf0e10cSrcweir                                      NULL, aRetCode) ;
118cdf0e10cSrcweir }
119cdf0e10cSrcweir //------------------------------------------------------------------------------
connectSimple(const LdapDefinition & aDefinition)120cdf0e10cSrcweir void  LdapConnection::connectSimple(const LdapDefinition& aDefinition)
121cdf0e10cSrcweir    throw (ldap::LdapConnectionException, ldap::LdapGenericException)
122cdf0e10cSrcweir {
123cdf0e10cSrcweir     OSL_ENSURE(!isValid(), "Recoonecting an LDAP connection that is already established");
124cdf0e10cSrcweir     if (isValid()) disconnect();
125cdf0e10cSrcweir 
126cdf0e10cSrcweir     mLdapDefinition = aDefinition;
127cdf0e10cSrcweir     connectSimple();
128cdf0e10cSrcweir }
129cdf0e10cSrcweir //------------------------------------------------------------------------------
connectSimple()130cdf0e10cSrcweir void  LdapConnection::connectSimple()
131cdf0e10cSrcweir    throw (ldap::LdapConnectionException, ldap::LdapGenericException)
132cdf0e10cSrcweir {
133cdf0e10cSrcweir     if (!isValid())
134cdf0e10cSrcweir 	{
135cdf0e10cSrcweir 		// Connect to the server
136cdf0e10cSrcweir 		initConnection() ;
137cdf0e10cSrcweir 		// Set Protocol V3
138cdf0e10cSrcweir 		int version = LDAP_VERSION3;
139cdf0e10cSrcweir 		(*s_p_set_option)(mConnection,
140cdf0e10cSrcweir 						LDAP_OPT_PROTOCOL_VERSION,
141cdf0e10cSrcweir 						&version);
142cdf0e10cSrcweir 
143cdf0e10cSrcweir #ifdef LDAP_X_OPT_CONNECT_TIMEOUT // OpenLDAP doesn't support this and the func
144cdf0e10cSrcweir         /* timeout is specified in milliseconds -> 4 seconds*/
145cdf0e10cSrcweir         int timeout = 4000;
146cdf0e10cSrcweir         (*s_p_set_option)( mConnection,
147cdf0e10cSrcweir                         LDAP_X_OPT_CONNECT_TIMEOUT,
148cdf0e10cSrcweir                         &timeout );
149cdf0e10cSrcweir #endif
150cdf0e10cSrcweir 
151cdf0e10cSrcweir         // Do the bind
152cdf0e10cSrcweir 		LdapErrCode retCode = (*s_p_simple_bind_s)(mConnection,
153*24c56ab9SHerbert Dürr                                                mLdapDefinition.mAnonUser.getStr(),
154*24c56ab9SHerbert Dürr                                                mLdapDefinition.mAnonCredentials.getStr()) ;
155cdf0e10cSrcweir 
156cdf0e10cSrcweir 		checkLdapReturnCode("SimpleBind", retCode, mConnection) ;
157cdf0e10cSrcweir 	}
158cdf0e10cSrcweir }
159cdf0e10cSrcweir //------------------------------------------------------------------------------
initConnection()160cdf0e10cSrcweir void LdapConnection::initConnection()
161cdf0e10cSrcweir     throw (ldap::LdapConnectionException)
162cdf0e10cSrcweir {
163cdf0e10cSrcweir     if (mLdapDefinition.mServer.getLength() == 0)
164cdf0e10cSrcweir     {
165cdf0e10cSrcweir         rtl::OUStringBuffer message ;
166cdf0e10cSrcweir 
167cdf0e10cSrcweir         message.appendAscii("Cannot initialise connection to LDAP: No server specified.") ;
168cdf0e10cSrcweir         throw ldap::LdapConnectionException(message.makeStringAndClear(), NULL) ;
169cdf0e10cSrcweir     }
170cdf0e10cSrcweir 
171cdf0e10cSrcweir     if (mLdapDefinition.mPort == 0) mLdapDefinition.mPort = LDAP_PORT;
172cdf0e10cSrcweir 
173*24c56ab9SHerbert Dürr     mConnection = (*s_p_init)( mLdapDefinition.mServer.getStr(),
174cdf0e10cSrcweir                             mLdapDefinition.mPort) ;
175cdf0e10cSrcweir     if (mConnection == NULL)
176cdf0e10cSrcweir     {
177cdf0e10cSrcweir         rtl::OUStringBuffer message ;
178cdf0e10cSrcweir 
179cdf0e10cSrcweir         message.appendAscii("Cannot initialise connection to LDAP server ") ;
180*24c56ab9SHerbert Dürr         message.appendAscii( mLdapDefinition.mServer.getStr());
181cdf0e10cSrcweir         message.appendAscii(":") ;
182cdf0e10cSrcweir         message.append(mLdapDefinition.mPort) ;
183cdf0e10cSrcweir         throw ldap::LdapConnectionException(message.makeStringAndClear(),
184cdf0e10cSrcweir 			                                NULL) ;
185cdf0e10cSrcweir     }
186cdf0e10cSrcweir }
187cdf0e10cSrcweir //------------------------------------------------------------------------------
getUserProfile(const rtl::OUString & aUser,LdapData * data)188cdf0e10cSrcweir  void LdapConnection::getUserProfile(
189cdf0e10cSrcweir      const rtl::OUString& aUser, LdapData * data)
190cdf0e10cSrcweir     throw (lang::IllegalArgumentException,
191cdf0e10cSrcweir             ldap::LdapConnectionException, ldap::LdapGenericException)
192cdf0e10cSrcweir {
193cdf0e10cSrcweir     OSL_ASSERT(data != 0);
194cdf0e10cSrcweir     if (!isValid()) { connectSimple(); }
195cdf0e10cSrcweir 
196cdf0e10cSrcweir     rtl::OString aUserDn =findUserDn( rtl::OUStringToOString(aUser, RTL_TEXTENCODING_ASCII_US));
197cdf0e10cSrcweir 
198cdf0e10cSrcweir     LdapMessageHolder result;
199cdf0e10cSrcweir     LdapErrCode retCode = (*s_p_search_s)(mConnection,
200*24c56ab9SHerbert Dürr 									  aUserDn.getStr(),
201cdf0e10cSrcweir 									  LDAP_SCOPE_BASE,
202cdf0e10cSrcweir 									  "(objectclass=*)",
203cdf0e10cSrcweir 									  0,
204cdf0e10cSrcweir 									  0, // Attributes + values
205cdf0e10cSrcweir 									  &result.msg) ;
206cdf0e10cSrcweir 
207cdf0e10cSrcweir     checkLdapReturnCode("getUserProfile", retCode,mConnection) ;
208cdf0e10cSrcweir 
209cdf0e10cSrcweir     void * ptr;
210cdf0e10cSrcweir     char * attr = (*s_p_first_attribute)(mConnection, result.msg, &ptr);
211cdf0e10cSrcweir     while (attr != 0) {
212cdf0e10cSrcweir         char ** values = (*s_p_get_values)(mConnection, result.msg, attr);
213cdf0e10cSrcweir         if (values != 0) {
214cdf0e10cSrcweir             data->insert(
215cdf0e10cSrcweir                 LdapData::value_type(
216cdf0e10cSrcweir                     rtl::OStringToOUString(attr, RTL_TEXTENCODING_ASCII_US),
217cdf0e10cSrcweir                     rtl::OStringToOUString(*values, RTL_TEXTENCODING_UTF8)));
218cdf0e10cSrcweir             (*s_p_value_free)(values);
219cdf0e10cSrcweir         }
220cdf0e10cSrcweir         attr = (*s_p_next_attribute)(mConnection, result.msg, ptr);
221cdf0e10cSrcweir     }
222cdf0e10cSrcweir }
223cdf0e10cSrcweir //------------------------------------------------------------------------------
findUserDn(const rtl::OString & aUser)224cdf0e10cSrcweir  rtl::OString LdapConnection::findUserDn(const rtl::OString& aUser)
225cdf0e10cSrcweir     throw (lang::IllegalArgumentException,
226cdf0e10cSrcweir             ldap::LdapConnectionException, ldap::LdapGenericException)
227cdf0e10cSrcweir {
228cdf0e10cSrcweir     if (!isValid()) { connectSimple(); }
229cdf0e10cSrcweir 
230cdf0e10cSrcweir     if (aUser.getLength() == 0)
231cdf0e10cSrcweir     {
232cdf0e10cSrcweir         throw lang::IllegalArgumentException(
233cdf0e10cSrcweir 			rtl::OUString(RTL_CONSTASCII_USTRINGPARAM
234*24c56ab9SHerbert Dürr 			("LdapConnection::findUserDn -User id is empty")).getStr(),
235cdf0e10cSrcweir 				NULL, 0) ;
236cdf0e10cSrcweir     }
237cdf0e10cSrcweir 
238cdf0e10cSrcweir 
239cdf0e10cSrcweir 
240cdf0e10cSrcweir     rtl::OStringBuffer filter( "(&(objectclass=" );
241cdf0e10cSrcweir 
242cdf0e10cSrcweir     filter.append( mLdapDefinition.mUserObjectClass ).append(")(") ;
243cdf0e10cSrcweir     filter.append( mLdapDefinition.mUserUniqueAttr ).append("=").append(aUser).append("))") ;
244cdf0e10cSrcweir 
245cdf0e10cSrcweir     LdapMessageHolder result;
246cdf0e10cSrcweir     sal_Char * attributes [2];
247cdf0e10cSrcweir     attributes[0]= const_cast<sal_Char *>(LDAP_NO_ATTRS);
248cdf0e10cSrcweir     attributes[1]= NULL;
249cdf0e10cSrcweir     LdapErrCode retCode = (*s_p_search_s)(mConnection,
250*24c56ab9SHerbert Dürr                                       mLdapDefinition.mBaseDN.getStr(),
251cdf0e10cSrcweir                                       LDAP_SCOPE_SUBTREE,
252*24c56ab9SHerbert Dürr                                       filter.getStr(), attributes, 0, &result.msg) ;
253cdf0e10cSrcweir 
254cdf0e10cSrcweir     checkLdapReturnCode("FindUserDn", retCode,mConnection) ;
255cdf0e10cSrcweir     rtl::OString userDn ;
256cdf0e10cSrcweir     LDAPMessage *entry = (*s_p_first_entry)(mConnection, result.msg) ;
257cdf0e10cSrcweir 
258cdf0e10cSrcweir     if (entry != NULL)
259cdf0e10cSrcweir     {
260cdf0e10cSrcweir         sal_Char *charsDn = (*s_p_get_dn)(mConnection, entry) ;
261cdf0e10cSrcweir 
262cdf0e10cSrcweir         userDn = charsDn ;
263cdf0e10cSrcweir         (*s_p_memfree)(charsDn) ;
264cdf0e10cSrcweir     }
265cdf0e10cSrcweir     else
266cdf0e10cSrcweir     {
267cdf0e10cSrcweir         OSL_ENSURE( false, "LdapConnection::findUserDn-could not get DN for User ");
268cdf0e10cSrcweir     }
269cdf0e10cSrcweir 
270cdf0e10cSrcweir     return userDn ;
271cdf0e10cSrcweir }
272cdf0e10cSrcweir 
thisModule()273cdf0e10cSrcweir extern "C" { static void SAL_CALL thisModule() {} }
loadModule()274cdf0e10cSrcweir void LdapConnection::loadModule()
275cdf0e10cSrcweir {
276cdf0e10cSrcweir     if ( !s_Ldap_Module )
277cdf0e10cSrcweir     {
278cdf0e10cSrcweir #if defined(WNT)
279cdf0e10cSrcweir #       define LIBLDAP "nsldap32v50.dll"
280cdf0e10cSrcweir #else
281cdf0e10cSrcweir #   ifdef WITH_OPENLDAP
282cdf0e10cSrcweir #       define xstr(s) str(s)
283cdf0e10cSrcweir #       define str(s) #s
284cdf0e10cSrcweir #       define LIBLDAP "libldap-" xstr(LDAP_VENDOR_VERSION_MAJOR) "." xstr(LDAP_VENDOR_VERSION_MINOR) ".so." xstr(LDAP_VENDOR_VERSION_MAJOR)
285cdf0e10cSrcweir #   else
286cdf0e10cSrcweir #       define LIBLDAP "libldap50.so"
287cdf0e10cSrcweir #   endif
288cdf0e10cSrcweir #endif
289cdf0e10cSrcweir         const ::rtl::OUString sModuleName(RTL_CONSTASCII_USTRINGPARAM(LIBLDAP));
290cdf0e10cSrcweir 
291cdf0e10cSrcweir 		// load the dbtools library
292cdf0e10cSrcweir 		s_Ldap_Module = osl_loadModuleRelative(&thisModule, sModuleName.pData, 0);
293cdf0e10cSrcweir         if ( s_Ldap_Module != NULL )
294cdf0e10cSrcweir         {
295cdf0e10cSrcweir             s_p_unbind_s = (t_ldap_unbind_s)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_unbind_s").pData));
296cdf0e10cSrcweir             s_p_simple_bind_s = (t_ldap_simple_bind_s)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_simple_bind_s").pData));
297cdf0e10cSrcweir             s_p_set_option = (t_ldap_set_option)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_set_option").pData));
298cdf0e10cSrcweir             s_p_err2string = (t_ldap_err2string)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_err2string").pData));
299cdf0e10cSrcweir             s_p_init = (t_ldap_init)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_init").pData));
300cdf0e10cSrcweir             s_p_msgfree = (t_ldap_msgfree)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_msgfree").pData));
301cdf0e10cSrcweir             s_p_get_dn = (t_ldap_get_dn)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_get_dn").pData));
302cdf0e10cSrcweir             s_p_first_entry = (t_ldap_first_entry)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_first_entry").pData));
303cdf0e10cSrcweir             s_p_first_attribute = (t_ldap_first_attribute)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_first_attribute").pData));
304cdf0e10cSrcweir             s_p_next_attribute = (t_ldap_next_attribute)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_next_attribute").pData));
305cdf0e10cSrcweir             s_p_search_s = (t_ldap_search_s)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_search_s").pData));
306cdf0e10cSrcweir             s_p_value_free = (t_ldap_value_free)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_value_free").pData));
307cdf0e10cSrcweir             s_p_get_values = (t_ldap_get_values)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_get_values").pData));
308cdf0e10cSrcweir             s_p_memfree = (t_ldap_memfree)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_memfree").pData));
309cdf0e10cSrcweir         }
310cdf0e10cSrcweir     }
311cdf0e10cSrcweir }
312cdf0e10cSrcweir 
313cdf0e10cSrcweir //------------------------------------------------------------------------------
314cdf0e10cSrcweir } } } // extensions.config.ldap
315cdf0e10cSrcweir 
316