xref: /trunk/main/extensions/source/config/ldap/ldapaccess.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
122     OSL_ENSURE(!isValid(), "Recoonecting an LDAP connection that is already established");
123     if (isValid()) disconnect();
124 
125     mLdapDefinition = aDefinition;
126     connectSimple();
127 }
128 //------------------------------------------------------------------------------
connectSimple()129 void  LdapConnection::connectSimple()
130 {
131     if (!isValid())
132     {
133         // Connect to the server
134         initConnection() ;
135         // Set Protocol V3
136         int version = LDAP_VERSION3;
137         (*s_p_set_option)(mConnection,
138                         LDAP_OPT_PROTOCOL_VERSION,
139                         &version);
140 
141 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT // OpenLDAP doesn't support this and the func
142         /* timeout is specified in milliseconds -> 4 seconds*/
143         int timeout = 4000;
144         (*s_p_set_option)( mConnection,
145                         LDAP_X_OPT_CONNECT_TIMEOUT,
146                         &timeout );
147 #endif
148 
149         // Do the bind
150         LdapErrCode retCode = (*s_p_simple_bind_s)(mConnection,
151                                                mLdapDefinition.mAnonUser.getStr(),
152                                                mLdapDefinition.mAnonCredentials.getStr()) ;
153 
154         checkLdapReturnCode("SimpleBind", retCode, mConnection) ;
155     }
156 }
157 //------------------------------------------------------------------------------
initConnection()158 void LdapConnection::initConnection()
159 {
160     if (mLdapDefinition.mServer.getLength() == 0)
161     {
162         rtl::OUStringBuffer message ;
163 
164         message.appendAscii("Cannot initialise connection to LDAP: No server specified.") ;
165         throw ldap::LdapConnectionException(message.makeStringAndClear(), NULL) ;
166     }
167 
168     if (mLdapDefinition.mPort == 0) mLdapDefinition.mPort = LDAP_PORT;
169 
170     mConnection = (*s_p_init)( mLdapDefinition.mServer.getStr(),
171                             mLdapDefinition.mPort) ;
172     if (mConnection == NULL)
173     {
174         rtl::OUStringBuffer message ;
175 
176         message.appendAscii("Cannot initialise connection to LDAP server ") ;
177         message.appendAscii( mLdapDefinition.mServer.getStr());
178         message.appendAscii(":") ;
179         message.append(mLdapDefinition.mPort) ;
180         throw ldap::LdapConnectionException(message.makeStringAndClear(),
181                                             NULL) ;
182     }
183 }
184 //------------------------------------------------------------------------------
getUserProfile(const rtl::OUString & aUser,LdapData * data)185  void LdapConnection::getUserProfile(
186      const rtl::OUString& aUser, LdapData * data)
187 {
188     OSL_ASSERT(data != 0);
189     if (!isValid()) { connectSimple(); }
190 
191     rtl::OString aUserDn =findUserDn( rtl::OUStringToOString(aUser, RTL_TEXTENCODING_ASCII_US));
192 
193     LdapMessageHolder result;
194     LdapErrCode retCode = (*s_p_search_s)(mConnection,
195                                       aUserDn.getStr(),
196                                       LDAP_SCOPE_BASE,
197                                       "(objectclass=*)",
198                                       0,
199                                       0, // Attributes + values
200                                       &result.msg) ;
201 
202     checkLdapReturnCode("getUserProfile", retCode,mConnection) ;
203 
204     void * ptr;
205     char * attr = (*s_p_first_attribute)(mConnection, result.msg, &ptr);
206     while (attr != 0) {
207         char ** values = (*s_p_get_values)(mConnection, result.msg, attr);
208         if (values != 0) {
209             data->insert(
210                 LdapData::value_type(
211                     rtl::OStringToOUString(attr, RTL_TEXTENCODING_ASCII_US),
212                     rtl::OStringToOUString(*values, RTL_TEXTENCODING_UTF8)));
213             (*s_p_value_free)(values);
214         }
215         attr = (*s_p_next_attribute)(mConnection, result.msg, ptr);
216     }
217 }
218 //------------------------------------------------------------------------------
findUserDn(const rtl::OString & aUser)219  rtl::OString LdapConnection::findUserDn(const rtl::OString& aUser)
220 {
221     if (!isValid()) { connectSimple(); }
222 
223     if (aUser.getLength() == 0)
224     {
225         throw lang::IllegalArgumentException(
226             rtl::OUString(RTL_CONSTASCII_USTRINGPARAM
227             ("LdapConnection::findUserDn -User id is empty")).getStr(),
228                 NULL, 0) ;
229     }
230 
231 
232 
233     rtl::OStringBuffer filter( "(&(objectclass=" );
234 
235     filter.append( mLdapDefinition.mUserObjectClass ).append(")(") ;
236     filter.append( mLdapDefinition.mUserUniqueAttr ).append("=").append(aUser).append("))") ;
237 
238     LdapMessageHolder result;
239     sal_Char * attributes [2];
240     attributes[0]= const_cast<sal_Char *>(LDAP_NO_ATTRS);
241     attributes[1]= NULL;
242     LdapErrCode retCode = (*s_p_search_s)(mConnection,
243                                       mLdapDefinition.mBaseDN.getStr(),
244                                       LDAP_SCOPE_SUBTREE,
245                                       filter.getStr(), attributes, 0, &result.msg) ;
246 
247     checkLdapReturnCode("FindUserDn", retCode,mConnection) ;
248     rtl::OString userDn ;
249     LDAPMessage *entry = (*s_p_first_entry)(mConnection, result.msg) ;
250 
251     if (entry != NULL)
252     {
253         sal_Char *charsDn = (*s_p_get_dn)(mConnection, entry) ;
254 
255         userDn = charsDn ;
256         (*s_p_memfree)(charsDn) ;
257     }
258     else
259     {
260         OSL_ENSURE( false, "LdapConnection::findUserDn-could not get DN for User ");
261     }
262 
263     return userDn ;
264 }
265 
thisModule()266 extern "C" { static void SAL_CALL thisModule() {} }
loadModule()267 void LdapConnection::loadModule()
268 {
269     if ( !s_Ldap_Module )
270     {
271 #if defined(WNT)
272 #       define LIBLDAP "nsldap32v50.dll"
273 #else
274 #   ifdef WITH_OPENLDAP
275 #       define xstr(s) str(s)
276 #       define str(s) #s
277 #       define LIBLDAP "libldap-" xstr(LDAP_VENDOR_VERSION_MAJOR) "." xstr(LDAP_VENDOR_VERSION_MINOR) ".so." xstr(LDAP_VENDOR_VERSION_MAJOR)
278 #   else
279 #       define LIBLDAP "libldap50.so"
280 #   endif
281 #endif
282         const ::rtl::OUString sModuleName(RTL_CONSTASCII_USTRINGPARAM(LIBLDAP));
283 
284         // load the dbtools library
285         s_Ldap_Module = osl_loadModuleRelative(&thisModule, sModuleName.pData, 0);
286         if ( s_Ldap_Module != NULL )
287         {
288             s_p_unbind_s = (t_ldap_unbind_s)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_unbind_s").pData));
289             s_p_simple_bind_s = (t_ldap_simple_bind_s)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_simple_bind_s").pData));
290             s_p_set_option = (t_ldap_set_option)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_set_option").pData));
291             s_p_err2string = (t_ldap_err2string)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_err2string").pData));
292             s_p_init = (t_ldap_init)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_init").pData));
293             s_p_msgfree = (t_ldap_msgfree)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_msgfree").pData));
294             s_p_get_dn = (t_ldap_get_dn)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_get_dn").pData));
295             s_p_first_entry = (t_ldap_first_entry)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_first_entry").pData));
296             s_p_first_attribute = (t_ldap_first_attribute)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_first_attribute").pData));
297             s_p_next_attribute = (t_ldap_next_attribute)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_next_attribute").pData));
298             s_p_search_s = (t_ldap_search_s)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_search_s").pData));
299             s_p_value_free = (t_ldap_value_free)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_value_free").pData));
300             s_p_get_values = (t_ldap_get_values)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_get_values").pData));
301             s_p_memfree = (t_ldap_memfree)(osl_getFunctionSymbol(s_Ldap_Module, ::rtl::OUString::createFromAscii("ldap_memfree").pData));
302         }
303     }
304 }
305 
306 //------------------------------------------------------------------------------
307 } } } // extensions.config.ldap
308