1/*
2 This file is part of libkldap.
3 Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21#include "ldapconnection.h"
22#include "ldapdefs.h"
23#include "kldap_config.h" // SASL2_FOUND, LDAP_FOUND
24
25#include <stdlib.h>
26#include <klocalizedstring.h>
27#include <kdebug.h>
28
29#ifdef SASL2_FOUND
30#include <sasl/sasl.h>
31static sasl_callback_t callbacks[] = {
32 { SASL_CB_ECHOPROMPT, NULL, NULL },
33 { SASL_CB_NOECHOPROMPT, NULL, NULL },
34 { SASL_CB_GETREALM, NULL, NULL },
35 { SASL_CB_USER, NULL, NULL },
36 { SASL_CB_AUTHNAME, NULL, NULL },
37 { SASL_CB_PASS, NULL, NULL },
38 { SASL_CB_CANON_USER, NULL, NULL },
39 { SASL_CB_LIST_END, NULL, NULL }
40};
41
42static bool ldapoperation_sasl_initialized = false;
43#endif
44
45#ifdef LDAP_FOUND
46# ifndef HAVE_WINLDAP_H
47# include <lber.h>
48# include <ldap.h>
49#else
50# include <w32-ldap-help.h>
51#endif // HAVE_WINLDAP_H
52
53#ifndef LDAP_OPT_SUCCESS
54#define LDAP_OPT_SUCCESS 0
55#endif
56
57#endif
58
59using namespace KLDAP;
60
61class LdapConnection::LdapConnectionPrivate
62{
63 public:
64 LdapConnectionPrivate();
65 LdapServer mServer;
66 QString mConnectionError;
67
68#ifdef LDAP_FOUND
69 LDAP *mLDAP;
70#else
71 void *mLDAP;
72#endif
73#ifdef SASL2_FOUND
74 sasl_conn_t *mSASLconn;
75#else
76 void *mSASLconn;
77#endif
78
79};
80
81LdapConnection::LdapConnectionPrivate::LdapConnectionPrivate()
82{
83 mSASLconn = 0;
84#ifdef SASL2_FOUND
85 if ( !ldapoperation_sasl_initialized ) {
86 sasl_client_init( NULL );
87 ldapoperation_sasl_initialized = true;
88 }
89#endif
90}
91
92LdapConnection::LdapConnection()
93 : d( new LdapConnectionPrivate )
94{
95 d->mLDAP = 0;
96}
97
98LdapConnection::LdapConnection( const LdapUrl &url )
99 : d( new LdapConnectionPrivate )
100{
101 d->mLDAP = 0;
102 setUrl( url );
103}
104
105LdapConnection::LdapConnection( const LdapServer &server )
106 : d( new LdapConnectionPrivate )
107{
108 d->mLDAP = 0;
109 setServer( server );
110}
111
112LdapConnection::~LdapConnection()
113{
114 close();
115 delete d;
116}
117
118void LdapConnection::setUrl( const LdapUrl &url )
119{
120 d->mServer.setUrl( url );
121}
122
123void LdapConnection::setServer( const LdapServer &server )
124{
125 d->mServer = server;
126}
127
128const LdapServer &LdapConnection::server() const
129{
130 return d->mServer;
131}
132
133void *LdapConnection::handle() const
134{
135 return (void *)d->mLDAP;
136}
137
138void *LdapConnection::saslHandle() const
139{
140 return (void *)d->mSASLconn;
141}
142
143QString LdapConnection::errorString( int code )
144{
145 //No translated error messages yet
146#ifdef LDAP_FOUND
147 return QString::fromUtf8( ldap_err2string( code ) );
148 switch ( code ) {
149 case LDAP_OPERATIONS_ERROR:
150 return i18n( "LDAP Operations error" );
151 //FIXME:
152 /* add the LDAP error codes */
153 }
154#else
155 return i18n( "No LDAP Support..." );
156#endif
157}
158
159QString LdapConnection::saslErrorString() const
160{
161#ifdef SASL2_FOUND
162 const char *str;
163 str = sasl_errdetail( d->mSASLconn );
164 return QString::fromLocal8Bit( str );
165#else
166 return i18n( "SASL support is not available. Please recompile libkldap with the "
167 "Cyrus-SASL (or compatible) client libraries, or complain to your "
168 "distribution packagers." );
169#endif
170}
171
172QString LdapConnection::connectionError() const
173{
174 return d->mConnectionError;
175}
176
177#ifdef LDAP_FOUND
178int LdapConnection::getOption( int option, void *value ) const
179{
180 Q_ASSERT( d->mLDAP );
181 return ldap_get_option( d->mLDAP, option, value );
182}
183
184int LdapConnection::setOption( int option, void *value )
185{
186 Q_ASSERT( d->mLDAP );
187 return ldap_set_option( d->mLDAP, option, value );
188}
189
190int LdapConnection::ldapErrorCode() const
191{
192 Q_ASSERT( d->mLDAP );
193 int err;
194 ldap_get_option( d->mLDAP, LDAP_OPT_ERROR_NUMBER, &err );
195 return err;
196}
197
198QString LdapConnection::ldapErrorString() const
199{
200 Q_ASSERT( d->mLDAP );
201 char *errmsg;
202 ldap_get_option( d->mLDAP, LDAP_OPT_ERROR_STRING, &errmsg );
203 QString msg = QString::fromLocal8Bit( errmsg );
204 free( errmsg );
205 return msg;
206}
207
208bool LdapConnection::setSizeLimit( int sizelimit )
209{
210 Q_ASSERT( d->mLDAP );
211 kDebug() << "sizelimit:" << sizelimit;
212 if ( setOption( LDAP_OPT_SIZELIMIT, &sizelimit ) != LDAP_OPT_SUCCESS ) {
213 return false;
214 }
215 return true;
216}
217
218int LdapConnection::sizeLimit() const
219{
220 Q_ASSERT( d->mLDAP );
221 int sizelimit;
222 if ( getOption( LDAP_OPT_SIZELIMIT, &sizelimit ) != LDAP_OPT_SUCCESS ) {
223 return -1;
224 }
225 return sizelimit;
226}
227
228bool LdapConnection::setTimeLimit( int timelimit )
229{
230 Q_ASSERT( d->mLDAP );
231 kDebug() << "timelimit:" << timelimit;
232 if ( setOption( LDAP_OPT_TIMELIMIT, &timelimit ) != LDAP_OPT_SUCCESS ) {
233 return false;
234 }
235 return true;
236}
237
238int LdapConnection::timeLimit() const
239{
240 Q_ASSERT( d->mLDAP );
241 int timelimit;
242 if ( getOption( LDAP_OPT_TIMELIMIT, &timelimit ) != LDAP_OPT_SUCCESS ) {
243 return -1;
244 }
245 return timelimit;
246}
247
248int LdapConnection::connect()
249{
250 int ret;
251 QString url;
252 if ( d->mLDAP ) {
253 close();
254 }
255
256 int version = d->mServer.version();
257 int timeout = d->mServer.timeout();
258
259 url = d->mServer.security() == LdapServer::SSL ? QLatin1String("ldaps") : QLatin1String("ldap");
260 url += QLatin1String("://");
261 url += d->mServer.host();
262 url += QLatin1Char(':');
263 url += QString::number( d->mServer.port() );
264 kDebug() << "ldap url:" << url;
265#ifdef HAVE_LDAP_INITIALIZE
266 ret = ldap_initialize( &d->mLDAP, url.toLatin1() );
267#else
268 d->mLDAP = ldap_init( d->mServer.host().toLatin1().data(), d->mServer.port() );
269 if ( d->mLDAP == 0 ) {
270 ret = -1;
271 } else {
272 ret = LDAP_SUCCESS;
273 }
274#endif
275 if ( ret != LDAP_SUCCESS ) {
276 d->mConnectionError = i18n( "An error occurred during the connection initialization phase." );
277 return ret;
278 }
279
280 kDebug() << "setting version to:" << version;
281 if ( setOption( LDAP_OPT_PROTOCOL_VERSION, &version ) != LDAP_OPT_SUCCESS ) {
282 ret = ldapErrorCode();
283 d->mConnectionError = i18n( "Cannot set protocol version to %1.", version );
284 close();
285 return ret;
286 }
287
288#if defined(LDAP_OPT_TIMEOUT)
289 kDebug() << "setting timeout to:" << timeout;
290
291 if ( timeout ) {
292 if ( setOption( LDAP_OPT_TIMEOUT, &timeout ) != LDAP_OPT_SUCCESS ) {
293 ret = ldapErrorCode();
294 d->mConnectionError = i18np( "Cannot set timeout to %1 second.",
295 "Cannot set timeout to %1 seconds.",
296 timeout );
297 close();
298 return ret;
299 }
300 }
301#endif
302
303 //FIXME: accessing to certificate handling would be good
304 kDebug() << "setting security to:" << d->mServer.security();
305 if ( d->mServer.security() == LdapServer::TLS ) {
306 kDebug() << "start TLS";
307#ifdef HAVE_LDAP_START_TLS_S
308 if ( ( ret = ldap_start_tls_s( d->mLDAP, NULL, NULL ) ) != LDAP_SUCCESS ) {
309 d->mConnectionError = ldapErrorString();
310 close();
311 return ret;
312 }
313#else
314 close();
315 d->mConnectionError = i18n( "TLS support not available in the LDAP client libraries." );
316 return -1;
317#endif
318 }
319
320 kDebug() << "setting sizelimit to:" << d->mServer.sizeLimit();
321 if ( d->mServer.sizeLimit() ) {
322 if ( !setSizeLimit( d->mServer.sizeLimit() ) ) {
323 ret = ldapErrorCode();
324 close();
325 d->mConnectionError = i18n( "Cannot set size limit." );
326 return ret;
327 }
328 }
329
330 kDebug() << "setting timelimit to:" << d->mServer.timeLimit();
331 if ( d->mServer.timeLimit() ) {
332 if ( !setTimeLimit( d->mServer.timeLimit() ) ) {
333 ret = ldapErrorCode();
334 close();
335 d->mConnectionError = i18n( "Cannot set time limit." );
336 return ret;
337 }
338 }
339
340#ifdef SASL2_FOUND
341 kDebug() << "initializing SASL client";
342 int saslresult = sasl_client_new( "ldap", d->mServer.host().toLatin1(),
343 0, 0, callbacks, 0, &d->mSASLconn );
344 if ( saslresult != SASL_OK ) {
345 d->mConnectionError = i18n( "Cannot initialize the SASL client." );
346 return KLDAP_SASL_ERROR;
347 }
348#endif
349
350 return 0;
351}
352
353void LdapConnection::close()
354{
355 if ( d->mLDAP ) {
356#ifdef HAVE_LDAP_UNBIND_EXT
357 ldap_unbind_ext( d->mLDAP, 0, 0 );
358#else
359 ldap_unbind( d->mLDAP );
360#endif
361 }
362 d->mLDAP = 0;
363#ifdef SASL2_FOUND
364 if ( d->mSASLconn ) {
365 sasl_dispose( &d->mSASLconn );
366 d->mSASLconn = 0;
367 }
368#endif
369 kDebug() << "connection closed!";
370}
371#else //LDAP_FOUND
372
373int LdapConnection::getOption( int option, void *value ) const
374{
375 kError() << "No LDAP support...";
376 return -1;
377}
378
379int LdapConnection::setOption( int option, void *value )
380{
381 kError() << "No LDAP support...";
382 return -1;
383}
384
385int LdapConnection::ldapErrorCode() const
386{
387 kError() << "No LDAP support...";
388 return -1;
389}
390
391QString LdapConnection::ldapErrorString() const
392{
393 kError() << "No LDAP support...";
394 return QString();
395}
396
397bool LdapConnection::setSizeLimit( int sizelimit )
398{
399 kError() << "No LDAP support...";
400 return false;
401}
402
403int LdapConnection::sizeLimit() const
404{
405 kError() << "No LDAP support...";
406 return -1;
407}
408
409bool LdapConnection::setTimeLimit( int timelimit )
410{
411 kError() << "No LDAP support...";
412 return false;
413}
414
415int LdapConnection::timeLimit() const
416{
417 kError() << "No LDAP support...";
418 return -1;
419}
420
421int LdapConnection::connect( )
422{
423 d->mConnectionError =
424 i18n( "LDAP support not compiled in. Please recompile libkldap with the "
425 "OpenLDAP (or compatible) client libraries, or complain to your "
426 "distribution packagers." );
427 kError() << "No LDAP support...";
428 return -1;
429}
430
431void LdapConnection::close()
432{
433 kError() << "No LDAP support...";
434}
435
436#endif
437