KLdap

ldapconnection.cpp
1/*
2 This file is part of libkldap.
3 SPDX-FileCopyrightText: 2004-2006 Szombathelyi György <gyurco@freemail.hu>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "ldapconnection.h"
9using namespace Qt::Literals::StringLiterals;
10
11#include "kldap_config.h" // LDAP_FOUND
12#include "ldapdefs.h"
13
14#include "ldap_core_debug.h"
15#include <KLocalizedString>
16#include <cstdlib>
17
18#include <sasl/sasl.h>
19static const sasl_callback_t callbacks[] = {{SASL_CB_ECHOPROMPT, nullptr, nullptr},
20 {SASL_CB_NOECHOPROMPT, nullptr, nullptr},
21 {SASL_CB_GETREALM, nullptr, nullptr},
22 {SASL_CB_USER, nullptr, nullptr},
23 {SASL_CB_AUTHNAME, nullptr, nullptr},
24 {SASL_CB_PASS, nullptr, nullptr},
25 {SASL_CB_CANON_USER, nullptr, nullptr},
26 {SASL_CB_LIST_END, nullptr, nullptr}};
27
28static bool ldapoperation_sasl_initialized = false;
29
30#if LDAP_FOUND
31#if !HAVE_WINLDAP_H
32#include <lber.h>
33#include <ldap.h>
34#else
35#include "w32-ldap-help.h"
36#endif // HAVE_WINLDAP_H
37
38#ifndef LDAP_OPT_SUCCESS
39#define LDAP_OPT_SUCCESS 0
40#endif
41
42#endif
43
44using namespace KLDAPCore;
45
46class Q_DECL_HIDDEN LdapConnection::LdapConnectionPrivate
47{
48public:
49 LdapConnectionPrivate();
50 LdapServer mServer;
51 QString mConnectionError;
52
53#if LDAP_FOUND
54 LDAP *mLDAP;
55#else
56 void *mLDAP;
57#endif
58 sasl_conn_t *mSASLconn;
59};
60
61LdapConnection::LdapConnectionPrivate::LdapConnectionPrivate()
62{
63 mSASLconn = nullptr;
64 if (!ldapoperation_sasl_initialized) {
65 sasl_client_init(nullptr);
66 ldapoperation_sasl_initialized = true;
67 }
68}
69
71 : d(new LdapConnectionPrivate)
72{
73 d->mLDAP = nullptr;
74}
75
77 : d(new LdapConnectionPrivate)
78{
79 d->mLDAP = nullptr;
80 setUrl(url);
81}
82
84 : d(new LdapConnectionPrivate)
85{
86 d->mLDAP = nullptr;
88}
89
90LdapConnection::~LdapConnection()
91{
92 close();
93}
94
96{
97 d->mServer.setUrl(url);
98}
99
101{
102 d->mServer = server;
103}
104
106{
107 return d->mServer;
108}
109
111{
112 return (void *)d->mLDAP;
113}
114
116{
117 return (void *)d->mSASLconn;
118}
119
121{
122 // No translated error messages yet
123#if LDAP_FOUND
124 return QString::fromUtf8(ldap_err2string(code));
125#else
126 return i18n("No LDAP Support...");
127#endif
128}
129
131{
132 const char *str;
133 str = sasl_errdetail(d->mSASLconn);
134 return QString::fromLocal8Bit(str);
135}
136
138{
139 return d->mConnectionError;
140}
141
142#if LDAP_FOUND
143int LdapConnection::getOption(int option, void *value) const
144{
145 Q_ASSERT(d->mLDAP);
146 return ldap_get_option(d->mLDAP, option, value);
147}
148
149int LdapConnection::setOption(int option, void *value)
150{
151 Q_ASSERT(d->mLDAP);
152 return ldap_set_option(d->mLDAP, option, value);
153}
154
156{
157 Q_ASSERT(d->mLDAP);
158 int err;
159 ldap_get_option(d->mLDAP, LDAP_OPT_ERROR_NUMBER, &err);
160 return err;
161}
162
164{
165 Q_ASSERT(d->mLDAP);
166 char *errmsg;
167 ldap_get_option(d->mLDAP, LDAP_OPT_ERROR_STRING, &errmsg);
168 QString msg = QString::fromLocal8Bit(errmsg);
169 free(errmsg);
170 return msg;
171}
172
173bool LdapConnection::setSizeLimit(int sizelimit)
174{
175 Q_ASSERT(d->mLDAP);
176 qCDebug(LDAP_CORE_LOG) << "sizelimit:" << sizelimit;
177 if (setOption(LDAP_OPT_SIZELIMIT, &sizelimit) != LDAP_OPT_SUCCESS) {
178 return false;
179 }
180 return true;
181}
182
184{
185 Q_ASSERT(d->mLDAP);
186 int sizelimit;
187 if (getOption(LDAP_OPT_SIZELIMIT, &sizelimit) != LDAP_OPT_SUCCESS) {
188 return -1;
189 }
190 return sizelimit;
191}
192
193bool LdapConnection::setTimeLimit(int timelimit)
194{
195 Q_ASSERT(d->mLDAP);
196 qCDebug(LDAP_CORE_LOG) << "timelimit:" << timelimit;
197 if (setOption(LDAP_OPT_TIMELIMIT, &timelimit) != LDAP_OPT_SUCCESS) {
198 return false;
199 }
200 return true;
201}
202
204{
205 Q_ASSERT(d->mLDAP);
206 int timelimit;
207 if (getOption(LDAP_OPT_TIMELIMIT, &timelimit) != LDAP_OPT_SUCCESS) {
208 return -1;
209 }
210 return timelimit;
211}
212
214{
215 int ret;
216 QString url;
217 if (d->mLDAP) {
218 close();
219 }
220
221 int version = d->mServer.version();
222 int timeout = d->mServer.timeout();
223
224 url = d->mServer.security() == LdapServer::SSL ? QStringLiteral("ldaps") : QStringLiteral("ldap");
225 url += "://"_L1;
226 url += d->mServer.host();
227 url += QLatin1Char(':');
228 url += QString::number(d->mServer.port());
229 qCDebug(LDAP_CORE_LOG) << "ldap url:" << url;
230#if HAVE_LDAP_INITIALIZE
231 ret = ldap_initialize(&d->mLDAP, url.toLatin1().constData());
232#else
233 d->mLDAP = ldap_init(d->mServer.host().toLatin1().data(), d->mServer.port());
234 if (d->mLDAP == 0) {
235 ret = -1;
236 } else {
237 ret = LDAP_SUCCESS;
238 }
239#endif
240 if (ret != LDAP_SUCCESS) {
241 d->mConnectionError = i18n("An error occurred during the connection initialization phase.");
242 return ret;
243 }
244
245 qCDebug(LDAP_CORE_LOG) << "setting version to:" << version;
246 if (setOption(LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS) {
247 ret = ldapErrorCode();
248 d->mConnectionError = i18n("Cannot set protocol version to %1.", version);
249 close();
250 return ret;
251 }
252
253#if defined(LDAP_OPT_TIMEOUT)
254 qCDebug(LDAP_CORE_LOG) << "setting timeout to:" << timeout;
255
256 if (timeout) {
257 if (setOption(LDAP_OPT_TIMEOUT, &timeout) != LDAP_OPT_SUCCESS) {
258 ret = ldapErrorCode();
259 d->mConnectionError = i18np("Cannot set timeout to %1 second.", "Cannot set timeout to %1 seconds.", timeout);
260 close();
261 return ret;
262 }
263 }
264#endif
265
266 qCDebug(LDAP_CORE_LOG) << "setting security to:" << d->mServer.security();
267 if (d->mServer.security() != LdapServer::None) {
268 bool initContext = false;
269 if (d->mServer.tlsCACertFile().isEmpty() == false) {
270 if (setOption(LDAP_OPT_X_TLS_CACERTFILE, d->mServer.tlsCACertFile().toUtf8().data()) != LDAP_OPT_SUCCESS) {
271 d->mConnectionError = i18n("Could not set CA certificate file.");
272 return -1;
273 }
274 initContext = true;
275 }
276
277 if (d->mServer.tlsRequireCertificate() != LdapServer::TLSReqCertDefault) {
278 int reqcert;
279 switch (d->mServer.tlsRequireCertificate()) {
280 case LdapServer::TLSReqCertAllow:
281 reqcert = LDAP_OPT_X_TLS_ALLOW;
282 break;
283 case LdapServer::TLSReqCertDemand:
284 reqcert = LDAP_OPT_X_TLS_DEMAND;
285 break;
286 case LdapServer::TLSReqCertHard:
287 reqcert = LDAP_OPT_X_TLS_HARD;
288 break;
289 case LdapServer::TLSReqCertNever:
290 reqcert = LDAP_OPT_X_TLS_NEVER;
291 break;
292 case LdapServer::TLSReqCertTry:
293 reqcert = LDAP_OPT_X_TLS_TRY;
294 break;
295 default:
296 d->mConnectionError = i18n("Invalid TLS require certificate mode.");
297 return -1;
298 }
299
300 if (setOption(LDAP_OPT_X_TLS_REQUIRE_CERT, &reqcert) != LDAP_OPT_SUCCESS) {
301 d->mConnectionError = i18n("Could not set TLS require certificate mode.");
302 return -1;
303 }
304 initContext = true;
305 }
306
307 if (initContext) {
308 int isServer = 0;
309 if (setOption(LDAP_OPT_X_TLS_NEWCTX, &isServer) != LDAP_OPT_SUCCESS) {
310 d->mConnectionError = i18n("Could not initialize new TLS context.");
311 return -1;
312 }
313 }
314 }
315
316 if (d->mServer.security() == LdapServer::TLS) {
317 qCDebug(LDAP_CORE_LOG) << "start TLS";
318
319#if HAVE_LDAP_START_TLS_S
320 if ((ret = ldap_start_tls_s(d->mLDAP, nullptr, nullptr)) != LDAP_SUCCESS) {
321 d->mConnectionError = ldapErrorString();
322 close();
323 return ret;
324 }
325#else
326 close();
327 d->mConnectionError = i18n("TLS support not available in the LDAP client libraries.");
328 return -1;
329#endif
330 }
331
332 qCDebug(LDAP_CORE_LOG) << "setting sizelimit to:" << d->mServer.sizeLimit();
333 if (d->mServer.sizeLimit()) {
334 if (!setSizeLimit(d->mServer.sizeLimit())) {
335 ret = ldapErrorCode();
336 close();
337 d->mConnectionError = i18n("Cannot set size limit.");
338 return ret;
339 }
340 }
341
342 qCDebug(LDAP_CORE_LOG) << "setting timelimit to:" << d->mServer.timeLimit();
343 if (d->mServer.timeLimit()) {
344 if (!setTimeLimit(d->mServer.timeLimit())) {
345 ret = ldapErrorCode();
346 close();
347 d->mConnectionError = i18n("Cannot set time limit.");
348 return ret;
349 }
350 }
351
352 qCDebug(LDAP_CORE_LOG) << "initializing SASL client";
353 const int saslresult = sasl_client_new("ldap", d->mServer.host().toLatin1().constData(), nullptr, nullptr, callbacks, 0, &d->mSASLconn);
354 if (saslresult != SASL_OK) {
355 d->mConnectionError = i18n("Cannot initialize the SASL client.");
356 return KLDAP_SASL_ERROR;
357 }
358
359 return 0;
360}
361
363{
364 if (d->mLDAP) {
365#if HAVE_LDAP_UNBIND_EXT
366 ldap_unbind_ext(d->mLDAP, nullptr, nullptr);
367#else
368 ldap_unbind(d->mLDAP);
369#endif
370 }
371 d->mLDAP = nullptr;
372 if (d->mSASLconn) {
373 sasl_dispose(&d->mSASLconn);
374 d->mSASLconn = nullptr;
375 }
376 qCDebug(LDAP_CORE_LOG) << "connection closed!";
377}
378
379#else // LDAP_FOUND
380
381int LdapConnection::getOption(int option, void *value) const
382{
383 qCritical() << "No LDAP support...";
384 return -1;
385}
386
387int LdapConnection::setOption(int option, void *value)
388{
389 qCritical() << "No LDAP support...";
390 return -1;
391}
392
394{
395 qCritical() << "No LDAP support...";
396 return -1;
397}
398
400{
401 qCritical() << "No LDAP support...";
402 return QString();
403}
404
406{
407 qCritical() << "No LDAP support...";
408 return false;
409}
410
412{
413 qCritical() << "No LDAP support...";
414 return -1;
415}
416
418{
419 qCritical() << "No LDAP support...";
420 return false;
421}
422
424{
425 qCritical() << "No LDAP support...";
426 return -1;
427}
428
430{
431 d->mConnectionError = i18n(
432 "LDAP support not compiled in. Please recompile libkldap with the "
433 "OpenLDAP (or compatible) client libraries, or complain to your "
434 "distribution packagers.");
435 qCritical() << "No LDAP support...";
436 return -1;
437}
438
440{
441 qCritical() << "No LDAP support...";
442}
443
444#endif
This class represents a connection to an LDAP server.
QString ldapErrorString() const
Returns the LDAP error string from the last operation.
const LdapServer & server() const
Returns the connection parameters which was specified with an LDAP Url or a LdapServer structure.
int timeLimit() const
Returns the current time limit.
int connect()
Sets up the connection parameters with creating a handle to the LDAP server.
LdapConnection()
Constructs an LdapConnection object.
QString saslErrorString() const
Returns the SASL error string from the last SASL operation.
int getOption(int option, void *value) const
Gets an option from the connection.
void setUrl(const LdapUrl &url)
Sets the connection parameters via the specified url.
int sizeLimit() const
Returns the current size limit.
int setOption(int option, void *value)
Sets an option in the connection.
QString connectionError() const
Returns a translated error string if connect() failed.
void close()
Closes the LDAP connection.
bool setTimeLimit(int timelimit)
Sets the time limit for the connection.
void setServer(const LdapServer &server)
Sets the connection parameters via the specified server structure.
int ldapErrorCode() const
Returns the LDAP error code from the last operation.
void * saslHandle() const
Returns the opaqe sasl-library specific SASL object.
static QString errorString(int code)
Returns a translated error message from the specified LDAP error code.
void * handle() const
Returns the opaqe client-library specific LDAP object.
bool setSizeLimit(int sizelimit)
Sets the size limit for the connection.
A class that contains LDAP server connection settings.
Definition ldapserver.h:27
A special url class for LDAP.
Definition ldapurl.h:30
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KDB_EXPORT KDbVersionInfo version()
const char * constData() const const
QString fromLocal8Bit(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
QString number(double n, char format, int precision)
QByteArray toLatin1() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:07 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.