1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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) {}
42 LdapMessageHolder(const LdapMessageHolder
&) = delete;
43 LdapMessageHolder
& operator=(const LdapMessageHolder
&) = delete;
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
,
67 if (aRetCode
== LDAP_SUCCESS
) { return ; }
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
79 ldap_get_lderrno(aConnection
, NULL
, &stub
) ;
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) ;
92 { message
+= "No additional information"; }
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
;
107 void LdapConnection::connectSimple()
112 // Connect to the server
115 int version
= LDAP_VERSION3
;
116 ldap_set_option(mConnection
,
117 LDAP_OPT_PROTOCOL_VERSION
,
120 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT // OpenLDAP doesn't support this and the func
121 /* timeout is specified in milliseconds -> 4 seconds*/
124 ldap_set_optionW( mConnection
,
125 LDAP_X_OPT_CONNECT_TIMEOUT
,
128 ldap_set_option( mConnection
,
129 LDAP_X_OPT_CONNECT_TIMEOUT
,
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())) );
140 LdapErrCode retCode
= ldap_simple_bind_s(mConnection
,
141 OUStringToOString( mLdapDefinition
.mAnonUser
, RTL_TEXTENCODING_UTF8
).getStr(),
142 OUStringToOString( mLdapDefinition
.mAnonCredentials
, RTL_TEXTENCODING_UTF8
).getStr()) ;
145 checkLdapReturnCode("SimpleBind", retCode
) ;
148 void LdapConnection::initConnection()
150 if (mLdapDefinition
.mServer
.isEmpty())
152 throw ldap::LdapConnectionException(u
"Cannot initialise connection to LDAP: No server specified."_ustr
);
155 if (mLdapDefinition
.mPort
== 0) mLdapDefinition
.mPort
= LDAP_PORT
;
158 mConnection
= ldap_initW(const_cast<PWSTR
>(o3tl::toW(mLdapDefinition
.mServer
.getStr())),
159 mLdapDefinition
.mPort
) ;
161 mConnection
= ldap_init(OUStringToOString( mLdapDefinition
.mServer
, RTL_TEXTENCODING_UTF8
).getStr(),
162 mLdapDefinition
.mPort
) ;
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
;
182 LdapErrCode retCode
= ldap_search_sW(mConnection
,
183 const_cast<PWSTR
>(o3tl::toW(aUserDn
.getStr())),
185 const_cast<PWSTR
>( L
"(objectclass=*)" ),
187 0, // Attributes + values
190 LdapErrCode retCode
= ldap_search_s(mConnection
,
191 OUStringToOString( aUserDn
, RTL_TEXTENCODING_UTF8
).getStr(),
195 0, // Attributes + values
198 checkLdapReturnCode("getUserProfile", retCode
) ;
202 PWCHAR attr
= ldap_first_attributeW(mConnection
, result
.msg
, &ptr
);
204 PWCHAR
* values
= ldap_get_valuesW(mConnection
, result
.msg
, attr
);
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
);
213 char * attr
= ldap_first_attribute(mConnection
, result
.msg
, &ptr
);
215 char ** values
= ldap_get_values(mConnection
, result
.msg
, attr
);
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
);
227 OUString
LdapConnection::findUserDn(const OUString
& aUser
)
229 if (!isValid()) { connectSimple(); }
233 throw lang::IllegalArgumentException(
234 u
"LdapConnection::findUserDn -User id is empty"_ustr
,
238 OUString filter
= "(&(objectclass="
239 + mLdapDefinition
.mUserObjectClass
241 + mLdapDefinition
.mUserUniqueAttr
246 LdapMessageHolder result
;
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())),
252 const_cast<PWSTR
>(o3tl::toW(filter
.getStr())), attributes
, 0, &result
.msg
) ;
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(),
258 OUStringToOString( filter
, RTL_TEXTENCODING_UTF8
).getStr(), attributes
, 0, &result
.msg
) ;
260 checkLdapReturnCode("FindUserDn", retCode
) ;
262 LDAPMessage
*entry
= ldap_first_entry(mConnection
, result
.msg
) ;
264 if (entry
!= nullptr)
267 PWCHAR charsDn
= ldap_get_dnW(mConnection
, entry
) ;
269 userDn
= OUString( o3tl::toU( charsDn
) );
270 ldap_memfreeW(charsDn
) ;
272 char *charsDn
= ldap_get_dn(mConnection
, entry
) ;
274 userDn
= OStringToOUString( charsDn
, RTL_TEXTENCODING_UTF8
);
275 ldap_memfree(charsDn
) ;
280 OSL_FAIL( "LdapConnection::findUserDn-could not get DN for User ");
287 } // extensions::config::ldap
289 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */