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