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