KLdap

ldapsearch.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 "ldapsearch.h"
9#include "ldapdefs.h"
10#include "ldapdn.h"
11
12#include <QTimer>
13
14#include "ldap_core_debug.h"
15#include <KLocalizedString>
16using namespace KLDAPCore;
17
18// blocking the GUI for xxx milliseconds
19#define LDAPSEARCH_BLOCKING_TIMEOUT 10
20
21class LdapSearchPrivate
22{
23public:
24 explicit LdapSearchPrivate(LdapSearch *parent)
25 : mParent(parent)
26 {
27 }
28
29 void result();
30 bool connect();
31 void closeConnection();
32 [[nodiscard]] bool startSearch(const LdapDN &base, LdapUrl::Scope scope, const QString &filter, const QStringList &attributes, int pagesize, int count);
33
34 LdapSearch *const mParent;
35 LdapConnection *mConn = nullptr;
36 LdapOperation mOp;
37 bool mOwnConnection = false;
38 bool mAbandoned = false;
39 int mId;
40 int mPageSize;
41 LdapDN mBase;
42 QString mFilter;
43 QStringList mAttributes;
44 LdapUrl::Scope mScope;
45
46 QString mErrorString;
47 int mError;
48 int mCount;
49 int mMaxCount;
50 bool mFinished = false;
51};
52
53void LdapSearchPrivate::result()
54{
55 if (mAbandoned) {
56 mOp.abandon(mId);
57 return;
58 }
59 const int res = mOp.waitForResult(mId, LDAPSEARCH_BLOCKING_TIMEOUT);
60
61 qCDebug(LDAP_CORE_LOG) << "LDAP result:" << res;
62
63 if (res != 0 && (res == -1 || (mConn->ldapErrorCode() != KLDAP_SUCCESS && mConn->ldapErrorCode() != KLDAP_SASL_BIND_IN_PROGRESS))) {
64 // error happened, but no timeout
65 mError = mConn->ldapErrorCode();
66 mErrorString = mConn->ldapErrorString();
67 Q_EMIT mParent->result(mParent);
68 return;
69 }
70
71 // binding
72 if (res == LdapOperation::RES_BIND) {
73 const QByteArray servercc = mOp.serverCred();
74
75 qCDebug(LDAP_CORE_LOG) << "LdapSearch RES_BIND";
76 if (mConn->ldapErrorCode() == KLDAP_SUCCESS) { // bind succeeded
77 qCDebug(LDAP_CORE_LOG) << "bind succeeded";
78 LdapControls savedctrls = mOp.serverControls();
79 if (mPageSize) {
80 LdapControls ctrls = savedctrls;
82 mOp.setServerControls(ctrls);
83 }
84
85 mId = mOp.search(mBase, mScope, mFilter, mAttributes);
86 mOp.setServerControls(savedctrls);
87 } else { // next bind step
88 qCDebug(LDAP_CORE_LOG) << "bind next step";
89 mId = mOp.bind(servercc);
90 }
91 if (mId < 0) {
92 if (mId == KLDAP_SASL_ERROR) {
93 mError = mId;
94 mErrorString = mConn->saslErrorString();
95 } else {
96 mError = mConn->ldapErrorCode();
97 mErrorString = mConn->ldapErrorString();
98 }
99 Q_EMIT mParent->result(mParent);
100 return;
101 }
102 QTimer::singleShot(0, mParent, [this]() {
103 result();
104 });
105 return;
106 }
107
108 // End of entries
109 if (res == LdapOperation::RES_SEARCH_RESULT) {
110 if (mPageSize) {
111 QByteArray cookie;
112 int estsize = -1;
113 const int numberOfControls(mOp.controls().count());
114 for (int i = 0; i < numberOfControls; ++i) {
115 estsize = mOp.controls().at(i).parsePageControl(cookie);
116 if (estsize != -1) {
117 break;
118 }
119 }
120 qCDebug(LDAP_CORE_LOG) << " estimated size:" << estsize;
121 if (estsize != -1 && !cookie.isEmpty()) {
122 LdapControls ctrls;
123 LdapControls savedctrls;
124 savedctrls = mOp.serverControls();
125 ctrls = savedctrls;
126 LdapControl::insert(ctrls, LdapControl::createPageControl(mPageSize, cookie));
127 mOp.setServerControls(ctrls);
128 mId = mOp.search(mBase, mScope, mFilter, mAttributes);
129 mOp.setServerControls(savedctrls);
130 if (mId == -1) {
131 mError = mConn->ldapErrorCode();
132 mErrorString = mConn->ldapErrorString();
133 Q_EMIT mParent->result(mParent);
134 return;
135 }
136 // continue with the next page
137 QTimer::singleShot(0, mParent, [this]() {
138 result();
139 });
140 return;
141 }
142 }
143 mFinished = true;
144 Q_EMIT mParent->result(mParent);
145 return;
146 }
147
148 // Found an entry
149 if (res == LdapOperation::RES_SEARCH_ENTRY) {
150 Q_EMIT mParent->data(mParent, mOp.object());
151 mCount++;
152 }
153
154 // If not reached the requested entries, continue
155 if (mMaxCount <= 0 || mCount < mMaxCount) {
156 QTimer::singleShot(0, mParent, [this]() {
157 result();
158 });
159 }
160 // If reached the requested entries, indicate it
161 if (mMaxCount > 0 && mCount == mMaxCount) {
162 qCDebug(LDAP_CORE_LOG) << mCount << " entries reached";
163 Q_EMIT mParent->result(mParent);
164 }
165}
166
167bool LdapSearchPrivate::connect()
168{
169 const int ret = mConn->connect();
170 if (ret != KLDAP_SUCCESS) {
171 mError = ret;
172 mErrorString = mConn->connectionError();
173 closeConnection();
174 return false;
175 }
176 return true;
177}
178
179void LdapSearchPrivate::closeConnection()
180{
181 if (mOwnConnection && mConn) {
182 delete mConn;
183 mConn = nullptr;
184 }
185}
186
187// This starts the real job
188bool LdapSearchPrivate::startSearch(const LdapDN &base, LdapUrl::Scope scope, const QString &filter, const QStringList &attributes, int pagesize, int count)
189{
190 qCDebug(LDAP_CORE_LOG) << "search: base=" << base.toString() << "scope=" << static_cast<int>(scope) << "filter=" << filter << "attributes=" << attributes
191 << "pagesize=" << pagesize;
192 mAbandoned = false;
193 mError = 0;
194 mErrorString.clear();
195 mOp.setConnection(*mConn);
196 mPageSize = pagesize;
197 mBase = base;
198 mScope = scope;
199 mFilter = filter;
200 mAttributes = attributes;
201 mMaxCount = count;
202 mCount = 0;
203 mFinished = false;
204
205 LdapControls savedctrls = mOp.serverControls();
206 if (pagesize) {
207 LdapControls ctrls = savedctrls;
208 mConn->setOption(0x0008, nullptr); // Disable referals or paging won't work
210 mOp.setServerControls(ctrls);
211 }
212
213 mId = mOp.bind();
214 if (mId < 0) {
215 if (mId == KLDAP_SASL_ERROR) {
216 mError = mId;
217 mErrorString = mConn->saslErrorString();
218 } else {
219 mError = mConn->ldapErrorCode();
220 mErrorString = mConn->ldapErrorString();
221 if (mError == -1 && mErrorString.isEmpty()) {
222 mErrorString = i18n("Cannot access to server. Please reconfigure it.");
223 }
224 }
225 return false;
226 }
227 qCDebug(LDAP_CORE_LOG) << "startSearch msg id=" << mId;
228
229 // maybe do this with threads?- need thread-safe client libs!!!
230 QTimer::singleShot(0, mParent, [this]() {
231 result();
232 });
233
234 return true;
235}
236
237///////////////////////////////////////////////
238
240 : d(new LdapSearchPrivate(this))
241{
242 d->mOwnConnection = true;
243 d->mConn = nullptr;
244}
245
247 : d(new LdapSearchPrivate(this))
248{
249 d->mOwnConnection = false;
250 d->mConn = &connection;
251}
252
253LdapSearch::~LdapSearch()
254{
255 d->closeConnection();
256}
257
259{
260 d->closeConnection();
261 d->mOwnConnection = false;
262 d->mConn = &connection;
263}
264
266{
267 d->mOp.setClientControls(ctrls);
268}
269
271{
272 d->mOp.setServerControls(ctrls);
273}
274
275bool LdapSearch::search(const LdapServer &server, const QStringList &attributes, int count)
276{
277 if (d->mOwnConnection) {
278 d->closeConnection();
279 d->mConn = new LdapConnection(server);
280 if (!d->connect()) {
281 return false;
282 }
283 }
284 return d->startSearch(server.baseDn(), server.scope(), server.filter(), attributes, server.pageSize(), count);
285}
286
287bool LdapSearch::search(const LdapUrl &url, int count)
288{
289 if (d->mOwnConnection) {
290 d->closeConnection();
291 d->mConn = new LdapConnection(url);
292 if (!d->connect()) {
293 return false;
294 }
295 }
296 bool critical = true;
297 const int pagesize = url.extension(QStringLiteral("x-pagesize"), critical).toInt();
298 return d->startSearch(url.dn(), url.scope(), url.filter(), url.attributes(), pagesize, count);
299}
300
301bool LdapSearch::search(const LdapDN &base, LdapUrl::Scope scope, const QString &filter, const QStringList &attributes, int pagesize, int count)
302{
303 Q_ASSERT(!d->mOwnConnection);
304 return d->startSearch(base, scope, filter, attributes, pagesize, count);
305}
306
308{
309 Q_ASSERT(!d->mFinished);
310 d->mCount = 0;
311 QTimer::singleShot(0, this, [this]() {
312 d->result();
313 });
314}
315
317{
318 return d->mFinished;
319}
320
322{
323 d->mAbandoned = true;
324}
325
327{
328 return d->mError;
329}
330
332{
333 return d->mErrorString;
334}
335
336#include "moc_ldapsearch.cpp"
This class represents a connection to an LDAP server.
QString ldapErrorString() const
Returns the LDAP error string from the last operation.
int connect()
Sets up the connection parameters with creating a handle to the LDAP server.
QString saslErrorString() const
Returns the SASL error string from the last SASL operation.
int setOption(int option, void *value)
Sets an option in the connection.
QString connectionError() const
Returns a translated error string if connect() failed.
int ldapErrorCode() const
Returns the LDAP error code from the last operation.
static void insert(LdapControls &list, const LdapControl &ctrl)
Inserts a unique control against a list of controls.
static LdapControl createPageControl(int pagesize, const QByteArray &cookie=QByteArray())
Creates a paging search control.
This class allows sending an ldap operation (search, rename, modify, delete, compare,...
int abandon(int id)
Abandons a long-running operation.
QByteArray serverCred() const
Returns the server response for a bind request (result returned RES_BIND).
void setConnection(LdapConnection &conn)
Sets the connection object.
void setServerControls(const LdapControls &ctrls)
Sets the server controls which will sent with each operation.
LdapObject object() const
Returns the result object if result() returned RES_SEARCH_ENTRY.
int bind(const QByteArray &creds=QByteArray(), SASL_Callback_Proc *saslproc=nullptr, void *data=nullptr)
Binds to the server which specified in the connection object.
LdapControls controls() const
Returns the server controls from the returned ldap message (grabbed by result()).
LdapControls serverControls() const
Returns the server controls (which set by setServerControls()).
int waitForResult(int id, int msecs=-1)
Waits for up to msecs milliseconds for a result message from the LDAP server.
int search(const LdapDN &base, LdapUrl::Scope scope, const QString &filter, const QStringList &attrs)
Starts a search operation with the given base DN, scope, filter and result attributes.
This class starts a search operation on a LDAP server and returns the search values via a Qt signal.
Definition ldapsearch.h:33
void continueSearch()
Continues the search (if you set count to non-zero in search(), and isFinished() is false)
QString errorString() const
Returns the error description of the search operation.
LdapSearch()
Constructs an LdapSearch object.
void setConnection(LdapConnection &connection)
Sets the connection for this object to use for searches from now onwards, regardless of the LDAP Url ...
void result(KLDAPCore::LdapSearch *search)
Emitted when the searching finished.
bool isFinished() const
Returns true if the search is finished else returns false.
int error() const
Returns the error code of the search operation (0 if no error).
void abandon()
Tries to abandon the search.
void data(KLDAPCore::LdapSearch *search, const KLDAPCore::LdapObject &obj)
Emitted for each result object.
bool search(const LdapServer &server, const QStringList &attributes=QStringList(), int count=0)
Starts a search operation on the LDAP server.
void setClientControls(const LdapControls &ctrls)
Sets the client controls which will sent with each operation.
void setServerControls(const LdapControls &ctrls)
Sets the server controls which will sent with each operation.
A class that contains LDAP server connection settings.
Definition ldapserver.h:27
QString filter() const
Returns the filter string of the LDAP connection.
LdapDN baseDn() const
Returns the baseDn of the LDAP connection.
int pageSize() const
Returns the page size of the LDAP connection.
LdapUrl::Scope scope() const
Returns the search scope of the LDAP connection.
A special url class for LDAP.
Definition ldapurl.h:30
Scope scope() const
Returns the scope part of the LDAP url.
Definition ldapurl.cpp:93
LdapDN dn() const
Returns the dn part of the LDAP url.
Definition ldapurl.cpp:72
enum { Base, One, Sub } Scope
Describes the scope of the LDAP url.
Definition ldapurl.h:44
QStringList attributes() const
Returns the attributes part of the LDAP url.
Definition ldapurl.cpp:82
QString filter() const
Returns the filter part of the LDAP url.
Definition ldapurl.cpp:104
Extension extension(const QString &extension) const
Returns the specified extension.
Definition ldapurl.cpp:120
QString i18n(const char *text, const TYPE &arg...)
bool isEmpty() const const
const_reference at(qsizetype i) const const
qsizetype count() const const
void clear()
bool isEmpty() const const
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:34:09 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.