Avoid potential negative array index access to cached text.
[LibreOffice.git] / extensions / source / config / ldap / ldapaccess.cxx
blob7e35408b3b9e50ed0a618edf1f6f1e4e2bcac8e9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "ldapaccess.hxx"
23 #include <osl/diagnose.h>
24 #include <o3tl/char16_t2wchar_t.hxx>
26 #include <com/sun/star/ldap/LdapConnectionException.hpp>
29 namespace extensions::config::ldap {
32 typedef int LdapErrCode;
34 struct LdapMessageHolder
36 LdapMessageHolder() : msg(nullptr) {}
37 ~LdapMessageHolder()
39 if (msg)
40 ldap_msgfree(msg);
42 LdapMessageHolder(const LdapMessageHolder&) = delete;
43 LdapMessageHolder& operator=(const LdapMessageHolder&) = delete;
45 LDAPMessage * msg;
48 LdapConnection::~LdapConnection()
50 if (isValid()) disconnect();
54 void LdapConnection::disconnect()
56 if (mConnection != nullptr)
58 ldap_unbind_s(mConnection) ;
59 mConnection = nullptr;
64 static void checkLdapReturnCode(const char *aOperation,
65 LdapErrCode aRetCode)
67 if (aRetCode == LDAP_SUCCESS) { return ; }
69 OUString message;
71 if (aOperation != nullptr)
73 message += OUString::createFromAscii(aOperation) + ": ";
75 message += OUString::createFromAscii(ldap_err2string(aRetCode)) + " (" ;
77 #ifndef LDAP_OPT_SIZELIMIT // for use with OpenLDAP
78 char* stub = nullptr;
79 ldap_get_lderrno(aConnection, NULL, &stub) ;
80 if (stub != nullptr)
82 message += OUString::createFromAscii(stub) ;
83 // It would seem the message returned is actually
84 // not a copy of a string but rather some static
85 // string itself. At any rate freeing it seems to
86 // cause some undue problems at least on Windows.
87 // This call is thus disabled for the moment.
88 //ldap_memfree(stub) ;
90 else
91 #endif
92 { message += "No additional information"; }
94 message += ")" ;
95 throw ldap::LdapGenericException(message, nullptr, aRetCode) ;
98 void LdapConnection::connectSimple(const LdapDefinition& aDefinition)
100 OSL_ENSURE(!isValid(), "Re-connecting to an LDAP connection that is already established");
101 if (isValid()) disconnect();
103 mLdapDefinition = aDefinition;
104 connectSimple();
107 void LdapConnection::connectSimple()
109 if (isValid())
110 return;
112 // Connect to the server
113 initConnection() ;
114 // Set Protocol V3
115 int version = LDAP_VERSION3;
116 ldap_set_option(mConnection,
117 LDAP_OPT_PROTOCOL_VERSION,
118 &version);
120 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT // OpenLDAP doesn't support this and the func
121 /* timeout is specified in milliseconds -> 4 seconds*/
122 int timeout = 4000;
123 #ifdef _WIN32
124 ldap_set_optionW( mConnection,
125 LDAP_X_OPT_CONNECT_TIMEOUT,
126 &timeout );
127 #else
128 ldap_set_option( mConnection,
129 LDAP_X_OPT_CONNECT_TIMEOUT,
130 &timeout );
131 #endif
132 #endif
134 // Do the bind
135 #ifdef _WIN32
136 LdapErrCode retCode = ldap_simple_bind_sW(mConnection,
137 const_cast<PWSTR>(o3tl::toW(mLdapDefinition.mAnonUser.getStr())),
138 const_cast<PWSTR>(o3tl::toW(mLdapDefinition.mAnonCredentials.getStr())) );
139 #else
140 LdapErrCode retCode = ldap_simple_bind_s(mConnection,
141 OUStringToOString( mLdapDefinition.mAnonUser, RTL_TEXTENCODING_UTF8 ).getStr(),
142 OUStringToOString( mLdapDefinition.mAnonCredentials, RTL_TEXTENCODING_UTF8 ).getStr()) ;
143 #endif
145 checkLdapReturnCode("SimpleBind", retCode) ;
148 void LdapConnection::initConnection()
150 if (mLdapDefinition.mServer.isEmpty())
152 throw ldap::LdapConnectionException("Cannot initialise connection to LDAP: No server specified.");
155 if (mLdapDefinition.mPort == 0) mLdapDefinition.mPort = LDAP_PORT;
157 #ifdef _WIN32
158 mConnection = ldap_initW(const_cast<PWSTR>(o3tl::toW(mLdapDefinition.mServer.getStr())),
159 mLdapDefinition.mPort) ;
160 #else
161 mConnection = ldap_init(OUStringToOString( mLdapDefinition.mServer, RTL_TEXTENCODING_UTF8 ).getStr(),
162 mLdapDefinition.mPort) ;
163 #endif
164 if (mConnection == nullptr)
166 throw ldap::LdapConnectionException(
167 "Cannot initialise connection to LDAP server "
168 + mLdapDefinition.mServer + ":" + OUString::number(mLdapDefinition.mPort));
172 void LdapConnection::getUserProfile(
173 const OUString& aUser, LdapData * data)
175 OSL_ASSERT(data != nullptr);
176 if (!isValid()) { connectSimple(); }
178 OUString aUserDn =findUserDn( aUser );
180 LdapMessageHolder result;
181 #ifdef _WIN32
182 LdapErrCode retCode = ldap_search_sW(mConnection,
183 const_cast<PWSTR>(o3tl::toW(aUserDn.getStr())),
184 LDAP_SCOPE_BASE,
185 const_cast<PWSTR>( L"(objectclass=*)" ),
186 nullptr,
187 0, // Attributes + values
188 &result.msg) ;
189 #else
190 LdapErrCode retCode = ldap_search_s(mConnection,
191 OUStringToOString( aUserDn, RTL_TEXTENCODING_UTF8 ).getStr(),
192 LDAP_SCOPE_BASE,
193 "(objectclass=*)",
194 nullptr,
195 0, // Attributes + values
196 &result.msg) ;
197 #endif
198 checkLdapReturnCode("getUserProfile", retCode) ;
200 BerElement * ptr;
201 #ifdef _WIN32
202 PWCHAR attr = ldap_first_attributeW(mConnection, result.msg, &ptr);
203 while (attr) {
204 PWCHAR * values = ldap_get_valuesW(mConnection, result.msg, attr);
205 if (values) {
206 const OUString aAttr( o3tl::toU( attr ) );
207 const OUString aValues( o3tl::toU( *values ) );
208 data->emplace( aAttr, aValues );
209 ldap_value_freeW(values);
211 attr = ldap_next_attributeW(mConnection, result.msg, ptr);
212 #else
213 char * attr = ldap_first_attribute(mConnection, result.msg, &ptr);
214 while (attr) {
215 char ** values = ldap_get_values(mConnection, result.msg, attr);
216 if (values) {
217 data->emplace(
218 OStringToOUString(attr, RTL_TEXTENCODING_ASCII_US),
219 OStringToOUString(*values, RTL_TEXTENCODING_UTF8));
220 ldap_value_free(values);
222 attr = ldap_next_attribute(mConnection, result.msg, ptr);
223 #endif
227 OUString LdapConnection::findUserDn(const OUString& aUser)
229 if (!isValid()) { connectSimple(); }
231 if (aUser.isEmpty())
233 throw lang::IllegalArgumentException(
234 "LdapConnection::findUserDn -User id is empty",
235 nullptr, 0) ;
238 OUString filter = "(&(objectclass="
239 + mLdapDefinition.mUserObjectClass
240 + ")("
241 + mLdapDefinition.mUserUniqueAttr
242 + "="
243 + aUser
244 + "))";
246 LdapMessageHolder result;
247 #ifdef _WIN32
248 PWCHAR attributes [2] = { const_cast<PWCHAR>( L"1.1" ), nullptr };
249 LdapErrCode retCode = ldap_search_sW(mConnection,
250 const_cast<PWSTR>(o3tl::toW(mLdapDefinition.mBaseDN.getStr())),
251 LDAP_SCOPE_SUBTREE,
252 const_cast<PWSTR>(o3tl::toW(filter.getStr())), attributes, 0, &result.msg) ;
253 #else
254 char * attributes [2] = { const_cast<char *>(LDAP_NO_ATTRS), nullptr };
255 LdapErrCode retCode = ldap_search_s(mConnection,
256 OUStringToOString( mLdapDefinition.mBaseDN, RTL_TEXTENCODING_UTF8 ).getStr(),
257 LDAP_SCOPE_SUBTREE,
258 OUStringToOString( filter, RTL_TEXTENCODING_UTF8 ).getStr(), attributes, 0, &result.msg) ;
259 #endif
260 checkLdapReturnCode("FindUserDn", retCode) ;
261 OUString userDn ;
262 LDAPMessage *entry = ldap_first_entry(mConnection, result.msg) ;
264 if (entry != nullptr)
266 #ifdef _WIN32
267 PWCHAR charsDn = ldap_get_dnW(mConnection, entry) ;
269 userDn = OUString( o3tl::toU( charsDn ) );
270 ldap_memfreeW(charsDn) ;
271 #else
272 char *charsDn = ldap_get_dn(mConnection, entry) ;
274 userDn = OStringToOUString( charsDn, RTL_TEXTENCODING_UTF8 );
275 ldap_memfree(charsDn) ;
276 #endif
278 else
280 OSL_FAIL( "LdapConnection::findUserDn-could not get DN for User ");
283 return userDn ;
287 } // extensions::config::ldap
289 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */