LibreOffice Module extensions (master) 1
ldapaccess.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include "ldapaccess.hxx"
22
23#include <osl/diagnose.h>
25
26#include <com/sun/star/ldap/LdapConnectionException.hpp>
27
28
30
31
32typedef int LdapErrCode;
33
35{
36 LdapMessageHolder() : msg(nullptr) {}
38 {
39 if (msg)
40 ldap_msgfree(msg);
41 }
44
45 LDAPMessage * msg;
46};
47
49{
50 if (isValid()) disconnect();
51}
52
53
55{
56 if (mConnection != nullptr)
57 {
58 ldap_unbind_s(mConnection) ;
59 mConnection = nullptr;
60 }
61}
62
63
64static void checkLdapReturnCode(const char *aOperation,
65 LdapErrCode aRetCode)
66{
67 if (aRetCode == LDAP_SUCCESS) { return ; }
68
69 OUString message;
70
71 if (aOperation != nullptr)
72 {
73 message += OUString::createFromAscii(aOperation) + ": ";
74 }
75 message += OUString::createFromAscii(ldap_err2string(aRetCode)) + " (" ;
76
77#ifndef LDAP_OPT_SIZELIMIT // for use with OpenLDAP
78 char* stub = nullptr;
79 ldap_get_lderrno(aConnection, NULL, &stub) ;
80 if (stub != nullptr)
81 {
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) ;
89 }
90 else
91#endif
92 { message += "No additional information"; }
93
94 message += ")" ;
95 throw ldap::LdapGenericException(message, nullptr, aRetCode) ;
96}
97
99{
100 OSL_ENSURE(!isValid(), "Re-connecting to an LDAP connection that is already established");
101 if (isValid()) disconnect();
102
103 mLdapDefinition = aDefinition;
105}
106
108{
109 if (isValid())
110 return;
111
112 // Connect to the server
114 // Set Protocol V3
115 int version = LDAP_VERSION3;
116 ldap_set_option(mConnection,
117 LDAP_OPT_PROTOCOL_VERSION,
118 &version);
119
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
133
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
144
145 checkLdapReturnCode("SimpleBind", retCode) ;
146}
147
149{
150 if (mLdapDefinition.mServer.isEmpty())
151 {
152 throw ldap::LdapConnectionException("Cannot initialise connection to LDAP: No server specified.");
153 }
154
155 if (mLdapDefinition.mPort == 0) mLdapDefinition.mPort = LDAP_PORT;
156
157#ifdef _WIN32
158 mConnection = ldap_initW(const_cast<PWSTR>(o3tl::toW(mLdapDefinition.mServer.getStr())),
160#else
161 mConnection = ldap_init(OUStringToOString( mLdapDefinition.mServer, RTL_TEXTENCODING_UTF8 ).getStr(),
163#endif
164 if (mConnection == nullptr)
165 {
166 throw ldap::LdapConnectionException(
167 "Cannot initialise connection to LDAP server "
168 + mLdapDefinition.mServer + ":" + OUString::number(mLdapDefinition.mPort));
169 }
170}
171
173 const OUString& aUser, LdapData * data)
174{
175 OSL_ASSERT(data != nullptr);
176 if (!isValid()) { connectSimple(); }
177
178 OUString aUserDn =findUserDn( aUser );
179
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) ;
199
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);
210 }
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);
221 }
222 attr = ldap_next_attribute(mConnection, result.msg, ptr);
223#endif
224 }
225}
226
227 OUString LdapConnection::findUserDn(const OUString& aUser)
228{
229 if (!isValid()) { connectSimple(); }
230
231 if (aUser.isEmpty())
232 {
233 throw lang::IllegalArgumentException(
234 "LdapConnection::findUserDn -User id is empty",
235 nullptr, 0) ;
236 }
237
238 OUString filter = "(&(objectclass="
240 + ")("
242 + "="
243 + aUser
244 + "))";
245
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) ;
263
264 if (entry != nullptr)
265 {
266#ifdef _WIN32
267 PWCHAR charsDn = ldap_get_dnW(mConnection, entry) ;
268
269 userDn = OUString( o3tl::toU( charsDn ) );
270 ldap_memfreeW(charsDn) ;
271#else
272 char *charsDn = ldap_get_dn(mConnection, entry) ;
273
274 userDn = OStringToOUString( charsDn, RTL_TEXTENCODING_UTF8 );
275 ldap_memfree(charsDn) ;
276#endif
277 }
278 else
279 {
280 OSL_FAIL( "LdapConnection::findUserDn-could not get DN for User ");
281 }
282
283 return userDn ;
284}
285
286
287} // extensions::config::ldap
288
289/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
LDAP * mConnection
LDAP connection object.
Definition: ldapaccess.hxx:128
void getUserProfile(const OUString &aUser, LdapData *data)
Gets LdapUserProfile from LDAP repository for specified user.
Definition: ldapaccess.cxx:172
bool isValid() const
Indicates whether the connection is in a valid state.
Definition: ldapaccess.hxx:121
OUString findUserDn(const OUString &aUser)
finds DN of user
Definition: ldapaccess.cxx:227
~LdapConnection()
Destructor, releases the connection.
Definition: ldapaccess.cxx:48
return NULL
Definition: main.m:208
MetadataImporterPluginType * result
Definition: main.m:195
std::map< OUString, OUString > LdapData
Definition: ldapaccess.hxx:72
static void checkLdapReturnCode(const char *aOperation, LdapErrCode aRetCode)
Definition: ldapaccess.cxx:64
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
std::vector< char * > values
Struct containing the information on LDAP connection.
Definition: ldapaccess.hxx:50
OUString mAnonUser
DN to use for "anonymous" connection.
Definition: ldapaccess.hxx:58
OUString mServer
LDAP server name.
Definition: ldapaccess.hxx:52
OUString mUserObjectClass
User Entity Object Class.
Definition: ldapaccess.hxx:62
OUString mUserUniqueAttr
User Entity Unique Attribute.
Definition: ldapaccess.hxx:64
OUString mAnonCredentials
Credentials to use for "anonymous" connection.
Definition: ldapaccess.hxx:60
OUString mBaseDN
Repository base DN.
Definition: ldapaccess.hxx:56
sal_Int32 mPort
LDAP server port number.
Definition: ldapaccess.hxx:54
LdapMessageHolder & operator=(const LdapMessageHolder &)=delete
LdapMessageHolder(const LdapMessageHolder &)=delete