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 { 55 LdapMessageHolder() : msg(0) {} 56 ~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 //------------------------------------------------------------------------------ 69 LdapConnection::~LdapConnection() 70 { 71 if (isValid()) disconnect(); 72 } 73 //------------------------------------------------------------------------------ 74 75 void LdapConnection::disconnect() 76 { 77 if (mConnection != NULL) 78 { 79 (*s_p_unbind_s)(mConnection) ; 80 mConnection = NULL; 81 } 82 } 83 //------------------------------------------------------------------------------ 84 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 , 154 mLdapDefinition.mAnonCredentials) ; 155 156 checkLdapReturnCode("SimpleBind", retCode, mConnection) ; 157 } 158 } 159 //------------------------------------------------------------------------------ 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, 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) ; 181 message.appendAscii(":") ; 182 message.append(mLdapDefinition.mPort) ; 183 throw ldap::LdapConnectionException(message.makeStringAndClear(), 184 NULL) ; 185 } 186 } 187 //------------------------------------------------------------------------------ 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, 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 //------------------------------------------------------------------------------ 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")), 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, 251 LDAP_SCOPE_SUBTREE, 252 filter.makeStringAndClear(), 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 273 extern "C" { static void SAL_CALL thisModule() {} } 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