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