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"
9#include "kldap_config.h" // LDAP_FOUND
10#include "ldapdefs.h"
11
12#include "ldap_core_debug.h"
13#include <KLocalizedString>
14#include <cstdlib>
15
16#include <sasl/sasl.h>
17static const sasl_callback_t callbacks[] = {{SASL_CB_ECHOPROMPT, nullptr, nullptr},
18 {SASL_CB_NOECHOPROMPT, nullptr, nullptr},
19 {SASL_CB_GETREALM, nullptr, nullptr},
20 {SASL_CB_USER, nullptr, nullptr},
21 {SASL_CB_AUTHNAME, nullptr, nullptr},
22 {SASL_CB_PASS, nullptr, nullptr},
23 {SASL_CB_CANON_USER, nullptr, nullptr},
24 {SASL_CB_LIST_END, nullptr, nullptr}};
25
26static bool ldapoperation_sasl_initialized = false;
27
28#if LDAP_FOUND
29#if !HAVE_WINLDAP_H
30#include <lber.h>
31#include <ldap.h>
32#else
33#include "w32-ldap-help.h"
34#endif // HAVE_WINLDAP_H
35
36#ifndef LDAP_OPT_SUCCESS
37#define LDAP_OPT_SUCCESS 0
38#endif
39
40#endif
41
42using namespace KLDAPCore;
43
44class Q_DECL_HIDDEN LdapConnection::LdapConnectionPrivate
45{
46public:
47 LdapConnectionPrivate();
48 LdapServer mServer;
49 QString mConnectionError;
50
51#if LDAP_FOUND
52 LDAP *mLDAP;
53#else
54 void *mLDAP;
55#endif
56 sasl_conn_t *mSASLconn;
57};
58
59LdapConnection::LdapConnectionPrivate::LdapConnectionPrivate()
60{
61 mSASLconn = nullptr;
62 if (!ldapoperation_sasl_initialized) {
63 sasl_client_init(nullptr);
64 ldapoperation_sasl_initialized = true;
65 }
66}
67
69 : d(new LdapConnectionPrivate)
70{
71 d->mLDAP = nullptr;
72}
73
75 : d(new LdapConnectionPrivate)
76{
77 d->mLDAP = nullptr;
78 setUrl(url);
79}
80
82 : d(new LdapConnectionPrivate)
83{
84 d->mLDAP = nullptr;
86}
87
88LdapConnection::~LdapConnection()
89{
90 close();
91}
92
94{
95 d->mServer.setUrl(url);
96}
97
99{
100 d->mServer = server;
101}
102
104{
105 return d->mServer;
106}
107
109{
110 return (void *)d->mLDAP;
111}
112
114{
115 return (void *)d->mSASLconn;
116}
117
119{
120 // No translated error messages yet
121#if LDAP_FOUND
122 return QString::fromUtf8(ldap_err2string(code));
123#else
124 return i18n("No LDAP Support...");
125#endif
126}
127
129{
130 const char *str;
131 str = sasl_errdetail(d->mSASLconn);
132 return QString::fromLocal8Bit(str);
133}
134
136{
137 return d->mConnectionError;
138}
139
140#if LDAP_FOUND
141int LdapConnection::getOption(int option, void *value) const
142{
143 Q_ASSERT(d->mLDAP);
144 return ldap_get_option(d->mLDAP, option, value);
145}
146
147int LdapConnection::setOption(int option, void *value)
148{
149 Q_ASSERT(d->mLDAP);
150 return ldap_set_option(d->mLDAP, option, value);
151}
152
154{
155 Q_ASSERT(d->mLDAP);
156 int err;
157 ldap_get_option(d->mLDAP, LDAP_OPT_ERROR_NUMBER, &err);
158 return err;
159}
160
162{
163 Q_ASSERT(d->mLDAP);
164 char *errmsg;
165 ldap_get_option(d->mLDAP, LDAP_OPT_ERROR_STRING, &errmsg);
166 QString msg = QString::fromLocal8Bit(errmsg);
167 free(errmsg);
168 return msg;
169}
170
171bool LdapConnection::setSizeLimit(int sizelimit)
172{
173 Q_ASSERT(d->mLDAP);
174 qCDebug(LDAP_LOG) << "sizelimit:" << sizelimit;
175 if (setOption(LDAP_OPT_SIZELIMIT, &sizelimit) != LDAP_OPT_SUCCESS) {
176 return false;
177 }
178 return true;
179}
180
182{
183 Q_ASSERT(d->mLDAP);
184 int sizelimit;
185 if (getOption(LDAP_OPT_SIZELIMIT, &sizelimit) != LDAP_OPT_SUCCESS) {
186 return -1;
187 }
188 return sizelimit;
189}
190
191bool LdapConnection::setTimeLimit(int timelimit)
192{
193 Q_ASSERT(d->mLDAP);
194 qCDebug(LDAP_LOG) << "timelimit:" << timelimit;
195 if (setOption(LDAP_OPT_TIMELIMIT, &timelimit) != LDAP_OPT_SUCCESS) {
196 return false;
197 }
198 return true;
199}
200
202{
203 Q_ASSERT(d->mLDAP);
204 int timelimit;
205 if (getOption(LDAP_OPT_TIMELIMIT, &timelimit) != LDAP_OPT_SUCCESS) {
206 return -1;
207 }
208 return timelimit;
209}
210
212{
213 int ret;
214 QString url;
215 if (d->mLDAP) {
216 close();
217 }
218
219 int version = d->mServer.version();
220 int timeout = d->mServer.timeout();
221
222 url = d->mServer.security() == LdapServer::SSL ? QStringLiteral("ldaps") : QStringLiteral("ldap");
223 url += QLatin1StringView("://");
224 url += d->mServer.host();
225 url += QLatin1Char(':');
226 url += QString::number(d->mServer.port());
227 qCDebug(LDAP_LOG) << "ldap url:" << url;
228#if HAVE_LDAP_INITIALIZE
229 ret = ldap_initialize(&d->mLDAP, url.toLatin1().constData());
230#else
231 d->mLDAP = ldap_init(d->mServer.host().toLatin1().data(), d->mServer.port());
232 if (d->mLDAP == 0) {
233 ret = -1;
234 } else {
235 ret = LDAP_SUCCESS;
236 }
237#endif
238 if (ret != LDAP_SUCCESS) {
239 d->mConnectionError = i18n("An error occurred during the connection initialization phase.");
240 return ret;
241 }
242
243 qCDebug(LDAP_LOG) << "setting version to:" << version;
244 if (setOption(LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS) {
245 ret = ldapErrorCode();
246 d->mConnectionError = i18n("Cannot set protocol version to %1.", version);
247 close();
248 return ret;
249 }
250
251#if defined(LDAP_OPT_TIMEOUT)
252 qCDebug(LDAP_LOG) << "setting timeout to:" << timeout;
253
254 if (timeout) {
255 if (setOption(LDAP_OPT_TIMEOUT, &timeout) != LDAP_OPT_SUCCESS) {
256 ret = ldapErrorCode();
257 d->mConnectionError = i18np("Cannot set timeout to %1 second.", "Cannot set timeout to %1 seconds.", timeout);
258 close();
259 return ret;
260 }
261 }
262#endif
263
264 qCDebug(LDAP_LOG) << "setting security to:" << d->mServer.security();
265 if (d->mServer.security() != LdapServer::None) {
266 bool initContext = false;
267 if (d->mServer.tlsCACertFile().isEmpty() == false) {
268 if (setOption(LDAP_OPT_X_TLS_CACERTFILE, d->mServer.tlsCACertFile().toUtf8().data()) != LDAP_OPT_SUCCESS) {
269 d->mConnectionError = i18n("Could not set CA certificate file.");
270 return -1;
271 }
272 initContext = true;
273 }
274
275 if (d->mServer.tlsRequireCertificate() != LdapServer::TLSReqCertDefault) {
276 int reqcert;
277 switch (d->mServer.tlsRequireCertificate()) {
278 case LdapServer::TLSReqCertAllow:
279 reqcert = LDAP_OPT_X_TLS_ALLOW;
280 break;
281 case LdapServer::TLSReqCertDemand:
282 reqcert = LDAP_OPT_X_TLS_DEMAND;
283 break;
284 case LdapServer::TLSReqCertHard:
285 reqcert = LDAP_OPT_X_TLS_HARD;
286 break;
287 case LdapServer::TLSReqCertNever:
288 reqcert = LDAP_OPT_X_TLS_NEVER;
289 break;
290 case LdapServer::TLSReqCertTry:
291 reqcert = LDAP_OPT_X_TLS_TRY;
292 break;
293 default:
294 d->mConnectionError = i18n("Invalid TLS require certificate mode.");
295 return -1;
296 }
297
298 if (setOption(LDAP_OPT_X_TLS_REQUIRE_CERT, &reqcert) != LDAP_OPT_SUCCESS) {
299 d->mConnectionError = i18n("Could not set TLS require certificate mode.");
300 return -1;
301 }
302 initContext = true;
303 }
304
305 if (initContext) {
306 int isServer = 0;
307 if (setOption(LDAP_OPT_X_TLS_NEWCTX, &isServer) != LDAP_OPT_SUCCESS) {
308 d->mConnectionError = i18n("Could not initialize new TLS context.");
309 return -1;
310 }
311 }
312 }
313
314 if (d->mServer.security() == LdapServer::TLS) {
315 qCDebug(LDAP_LOG) << "start TLS";
316
317#if HAVE_LDAP_START_TLS_S
318 if ((ret = ldap_start_tls_s(d->mLDAP, nullptr, nullptr)) != LDAP_SUCCESS) {
319 d->mConnectionError = ldapErrorString();
320 close();
321 return ret;
322 }
323#else
324 close();
325 d->mConnectionError = i18n("TLS support not available in the LDAP client libraries.");
326 return -1;
327#endif
328 }
329
330 qCDebug(LDAP_LOG) << "setting sizelimit to:" << d->mServer.sizeLimit();
331 if (d->mServer.sizeLimit()) {
332 if (!setSizeLimit(d->mServer.sizeLimit())) {
333 ret = ldapErrorCode();
334 close();
335 d->mConnectionError = i18n("Cannot set size limit.");
336 return ret;
337 }
338 }
339
340 qCDebug(LDAP_LOG) << "setting timelimit to:" << d->mServer.timeLimit();
341 if (d->mServer.timeLimit()) {
342 if (!setTimeLimit(d->mServer.timeLimit())) {
343 ret = ldapErrorCode();
344 close();
345 d->mConnectionError = i18n("Cannot set time limit.");
346 return ret;
347 }
348 }
349
350 qCDebug(LDAP_LOG) << "initializing SASL client";
351 const int saslresult = sasl_client_new("ldap", d->mServer.host().toLatin1().constData(), nullptr, nullptr, callbacks, 0, &d->mSASLconn);
352 if (saslresult != SASL_OK) {
353 d->mConnectionError = i18n("Cannot initialize the SASL client.");
354 return KLDAP_SASL_ERROR;
355 }
356
357 return 0;
358}
359
361{
362 if (d->mLDAP) {
363#if HAVE_LDAP_UNBIND_EXT
364 ldap_unbind_ext(d->mLDAP, nullptr, nullptr);
365#else
366 ldap_unbind(d->mLDAP);
367#endif
368 }
369 d->mLDAP = nullptr;
370 if (d->mSASLconn) {
371 sasl_dispose(&d->mSASLconn);
372 d->mSASLconn = nullptr;
373 }
374 qCDebug(LDAP_LOG) << "connection closed!";
375}
376
377#else // LDAP_FOUND
378
379int LdapConnection::getOption(int option, void *value) const
380{
381 qCritical() << "No LDAP support...";
382 return -1;
383}
384
385int LdapConnection::setOption(int option, void *value)
386{
387 qCritical() << "No LDAP support...";
388 return -1;
389}
390
392{
393 qCritical() << "No LDAP support...";
394 return -1;
395}
396
398{
399 qCritical() << "No LDAP support...";
400 return QString();
401}
402
404{
405 qCritical() << "No LDAP support...";
406 return false;
407}
408
410{
411 qCritical() << "No LDAP support...";
412 return -1;
413}
414
416{
417 qCritical() << "No LDAP support...";
418 return false;
419}
420
422{
423 qCritical() << "No LDAP support...";
424 return -1;
425}
426
428{
429 d->mConnectionError = i18n(
430 "LDAP support not compiled in. Please recompile libkldap with the "
431 "OpenLDAP (or compatible) client libraries, or complain to your "
432 "distribution packagers.");
433 qCritical() << "No LDAP support...";
434 return -1;
435}
436
438{
439 qCritical() << "No LDAP support...";
440}
441
442#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 Tue Mar 26 2024 11:18:34 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.