diff options
Diffstat (limited to 'extensions/source/config/ldap/ldapaccess.cxx')
-rw-r--r-- | extensions/source/config/ldap/ldapaccess.cxx | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/extensions/source/config/ldap/ldapaccess.cxx b/extensions/source/config/ldap/ldapaccess.cxx new file mode 100644 index 000000000..7e35408b3 --- /dev/null +++ b/extensions/source/config/ldap/ldapaccess.cxx @@ -0,0 +1,289 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "ldapaccess.hxx" + +#include <osl/diagnose.h> +#include <o3tl/char16_t2wchar_t.hxx> + +#include <com/sun/star/ldap/LdapConnectionException.hpp> + + +namespace extensions::config::ldap { + + +typedef int LdapErrCode; + +struct LdapMessageHolder +{ + LdapMessageHolder() : msg(nullptr) {} + ~LdapMessageHolder() + { + if (msg) + ldap_msgfree(msg); + } + LdapMessageHolder(const LdapMessageHolder&) = delete; + LdapMessageHolder& operator=(const LdapMessageHolder&) = delete; + + LDAPMessage * msg; +}; + +LdapConnection::~LdapConnection() +{ + if (isValid()) disconnect(); +} + + +void LdapConnection::disconnect() +{ + if (mConnection != nullptr) + { + ldap_unbind_s(mConnection) ; + mConnection = nullptr; + } +} + + +static void checkLdapReturnCode(const char *aOperation, + LdapErrCode aRetCode) +{ + if (aRetCode == LDAP_SUCCESS) { return ; } + + OUString message; + + if (aOperation != nullptr) + { + message += OUString::createFromAscii(aOperation) + ": "; + } + message += OUString::createFromAscii(ldap_err2string(aRetCode)) + " (" ; + +#ifndef LDAP_OPT_SIZELIMIT // for use with OpenLDAP + char* stub = nullptr; + ldap_get_lderrno(aConnection, NULL, &stub) ; + if (stub != nullptr) + { + message += OUString::createFromAscii(stub) ; + // It would seem the message returned is actually + // not a copy of a string but rather some static + // string itself. At any rate freeing it seems to + // cause some undue problems at least on Windows. + // This call is thus disabled for the moment. + //ldap_memfree(stub) ; + } + else +#endif + { message += "No additional information"; } + + message += ")" ; + throw ldap::LdapGenericException(message, nullptr, aRetCode) ; +} + +void LdapConnection::connectSimple(const LdapDefinition& aDefinition) +{ + OSL_ENSURE(!isValid(), "Re-connecting to an LDAP connection that is already established"); + if (isValid()) disconnect(); + + mLdapDefinition = aDefinition; + connectSimple(); +} + +void LdapConnection::connectSimple() +{ + if (isValid()) + return; + + // Connect to the server + initConnection() ; + // Set Protocol V3 + int version = LDAP_VERSION3; + ldap_set_option(mConnection, + LDAP_OPT_PROTOCOL_VERSION, + &version); + +#ifdef LDAP_X_OPT_CONNECT_TIMEOUT // OpenLDAP doesn't support this and the func + /* timeout is specified in milliseconds -> 4 seconds*/ + int timeout = 4000; +#ifdef _WIN32 + ldap_set_optionW( mConnection, + LDAP_X_OPT_CONNECT_TIMEOUT, + &timeout ); +#else + ldap_set_option( mConnection, + LDAP_X_OPT_CONNECT_TIMEOUT, + &timeout ); +#endif +#endif + + // Do the bind +#ifdef _WIN32 + LdapErrCode retCode = ldap_simple_bind_sW(mConnection, + const_cast<PWSTR>(o3tl::toW(mLdapDefinition.mAnonUser.getStr())), + const_cast<PWSTR>(o3tl::toW(mLdapDefinition.mAnonCredentials.getStr())) ); +#else + LdapErrCode retCode = ldap_simple_bind_s(mConnection, + OUStringToOString( mLdapDefinition.mAnonUser, RTL_TEXTENCODING_UTF8 ).getStr(), + OUStringToOString( mLdapDefinition.mAnonCredentials, RTL_TEXTENCODING_UTF8 ).getStr()) ; +#endif + + checkLdapReturnCode("SimpleBind", retCode) ; +} + +void LdapConnection::initConnection() +{ + if (mLdapDefinition.mServer.isEmpty()) + { + throw ldap::LdapConnectionException("Cannot initialise connection to LDAP: No server specified."); + } + + if (mLdapDefinition.mPort == 0) mLdapDefinition.mPort = LDAP_PORT; + +#ifdef _WIN32 + mConnection = ldap_initW(const_cast<PWSTR>(o3tl::toW(mLdapDefinition.mServer.getStr())), + mLdapDefinition.mPort) ; +#else + mConnection = ldap_init(OUStringToOString( mLdapDefinition.mServer, RTL_TEXTENCODING_UTF8 ).getStr(), + mLdapDefinition.mPort) ; +#endif + if (mConnection == nullptr) + { + throw ldap::LdapConnectionException( + "Cannot initialise connection to LDAP server " + + mLdapDefinition.mServer + ":" + OUString::number(mLdapDefinition.mPort)); + } +} + + void LdapConnection::getUserProfile( + const OUString& aUser, LdapData * data) +{ + OSL_ASSERT(data != nullptr); + if (!isValid()) { connectSimple(); } + + OUString aUserDn =findUserDn( aUser ); + + LdapMessageHolder result; +#ifdef _WIN32 + LdapErrCode retCode = ldap_search_sW(mConnection, + const_cast<PWSTR>(o3tl::toW(aUserDn.getStr())), + LDAP_SCOPE_BASE, + const_cast<PWSTR>( L"(objectclass=*)" ), + nullptr, + 0, // Attributes + values + &result.msg) ; +#else + LdapErrCode retCode = ldap_search_s(mConnection, + OUStringToOString( aUserDn, RTL_TEXTENCODING_UTF8 ).getStr(), + LDAP_SCOPE_BASE, + "(objectclass=*)", + nullptr, + 0, // Attributes + values + &result.msg) ; +#endif + checkLdapReturnCode("getUserProfile", retCode) ; + + BerElement * ptr; +#ifdef _WIN32 + PWCHAR attr = ldap_first_attributeW(mConnection, result.msg, &ptr); + while (attr) { + PWCHAR * values = ldap_get_valuesW(mConnection, result.msg, attr); + if (values) { + const OUString aAttr( o3tl::toU( attr ) ); + const OUString aValues( o3tl::toU( *values ) ); + data->emplace( aAttr, aValues ); + ldap_value_freeW(values); + } + attr = ldap_next_attributeW(mConnection, result.msg, ptr); +#else + char * attr = ldap_first_attribute(mConnection, result.msg, &ptr); + while (attr) { + char ** values = ldap_get_values(mConnection, result.msg, attr); + if (values) { + data->emplace( + OStringToOUString(attr, RTL_TEXTENCODING_ASCII_US), + OStringToOUString(*values, RTL_TEXTENCODING_UTF8)); + ldap_value_free(values); + } + attr = ldap_next_attribute(mConnection, result.msg, ptr); +#endif + } +} + + OUString LdapConnection::findUserDn(const OUString& aUser) +{ + if (!isValid()) { connectSimple(); } + + if (aUser.isEmpty()) + { + throw lang::IllegalArgumentException( + "LdapConnection::findUserDn -User id is empty", + nullptr, 0) ; + } + + OUString filter = "(&(objectclass=" + + mLdapDefinition.mUserObjectClass + + ")(" + + mLdapDefinition.mUserUniqueAttr + + "=" + + aUser + + "))"; + + LdapMessageHolder result; +#ifdef _WIN32 + PWCHAR attributes [2] = { const_cast<PWCHAR>( L"1.1" ), nullptr }; + LdapErrCode retCode = ldap_search_sW(mConnection, + const_cast<PWSTR>(o3tl::toW(mLdapDefinition.mBaseDN.getStr())), + LDAP_SCOPE_SUBTREE, + const_cast<PWSTR>(o3tl::toW(filter.getStr())), attributes, 0, &result.msg) ; +#else + char * attributes [2] = { const_cast<char *>(LDAP_NO_ATTRS), nullptr }; + LdapErrCode retCode = ldap_search_s(mConnection, + OUStringToOString( mLdapDefinition.mBaseDN, RTL_TEXTENCODING_UTF8 ).getStr(), + LDAP_SCOPE_SUBTREE, + OUStringToOString( filter, RTL_TEXTENCODING_UTF8 ).getStr(), attributes, 0, &result.msg) ; +#endif + checkLdapReturnCode("FindUserDn", retCode) ; + OUString userDn ; + LDAPMessage *entry = ldap_first_entry(mConnection, result.msg) ; + + if (entry != nullptr) + { +#ifdef _WIN32 + PWCHAR charsDn = ldap_get_dnW(mConnection, entry) ; + + userDn = OUString( o3tl::toU( charsDn ) ); + ldap_memfreeW(charsDn) ; +#else + char *charsDn = ldap_get_dn(mConnection, entry) ; + + userDn = OStringToOUString( charsDn, RTL_TEXTENCODING_UTF8 ); + ldap_memfree(charsDn) ; +#endif + } + else + { + OSL_FAIL( "LdapConnection::findUserDn-could not get DN for User "); + } + + return userDn ; +} + + +} // extensions::config::ldap + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |