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 "ldapoperation.h"
22#include "kldap_config.h"
23
24#include <kdebug.h>
25
26#include <QtCore/QTime>
27
28#include <stdlib.h>
29#ifdef HAVE_SYS_TIME_H
30#include <sys/time.h>
31#endif
32
33#ifdef SASL2_FOUND
34#include <sasl/sasl.h>
35#endif
36
37#ifdef LDAP_FOUND
38# ifndef HAVE_WINLDAP_H
39# include <lber.h>
40# include <ldap.h>
41# else
42# include <w32-ldap-help.h>
43# endif // HAVE_WINLDAP_H
44#endif // LDAP_FOUND
45
46#include "ldapdefs.h"
47
48using namespace KLDAP;
49
50#ifdef LDAP_FOUND
51static void extractControls( LdapControls &ctrls, LDAPControl **pctrls );
52#endif // LDAP_FOUND
53
54/*
55 Returns the difference between msecs and elapsed. If msecs is -1,
56 however, -1 is returned.
57*/
58static int kldap_timeout_value( int msecs, int elapsed )
59{
60 if ( msecs == -1 ) {
61 return -1;
62 }
63
64 int timeout = msecs - elapsed;
65 return timeout < 0 ? 0 : timeout;
66}
67
68class LdapOperation::LdapOperationPrivate
69{
70 public:
71 LdapOperationPrivate();
72 ~LdapOperationPrivate();
73#ifdef LDAP_FOUND
74 int processResult( int rescode, LDAPMessage *msg );
75 int bind( const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data, bool async );
76#endif
77 LdapControls mClientCtrls, mServerCtrls, mControls;
78 LdapObject mObject;
79 QByteArray mExtOid, mExtData;
80 QByteArray mServerCred;
81 QString mMatchedDn;
82 QList<QByteArray> mReferrals;
83
84 LdapConnection *mConnection;
85 };
86
87LdapOperation::LdapOperation()
88 : d( new LdapOperationPrivate )
89{
90 d->mConnection = 0;
91}
92
93LdapOperation::LdapOperation( LdapConnection &conn )
94 : d( new LdapOperationPrivate )
95{
96 setConnection( conn );
97}
98
99LdapOperation::~LdapOperation()
100{
101 delete d;
102}
103
104void LdapOperation::setConnection( LdapConnection &conn )
105{
106 d->mConnection = &conn;
107}
108
109LdapConnection &LdapOperation::connection()
110{
111 return *d->mConnection;
112}
113
114void LdapOperation::setClientControls( const LdapControls &ctrls )
115{
116 d->mClientCtrls = ctrls;
117}
118
119void LdapOperation::setServerControls( const LdapControls &ctrls )
120{
121 d->mServerCtrls = ctrls;
122}
123
124LdapControls LdapOperation::clientControls() const
125{
126 return d->mClientCtrls;
127}
128
129LdapControls LdapOperation::serverControls() const
130{
131 return d->mServerCtrls;
132}
133
134LdapObject LdapOperation::object() const
135{
136 return d->mObject;
137}
138
139LdapControls LdapOperation::controls() const
140{
141 return d->mControls;
142}
143
144QByteArray LdapOperation::extendedOid() const
145{
146 return d->mExtOid;
147}
148
149QByteArray LdapOperation::extendedData() const
150{
151 return d->mExtData;
152}
153
154QString LdapOperation::matchedDn() const
155{
156 return d->mMatchedDn;
157}
158
159QList<QByteArray> LdapOperation::referrals() const
160{
161 return d->mReferrals;
162}
163
164QByteArray LdapOperation::serverCred() const
165{
166 return d->mServerCred;
167}
168
169LdapOperation::LdapOperationPrivate::LdapOperationPrivate()
170{
171}
172
173LdapOperation::LdapOperationPrivate::~LdapOperationPrivate()
174{
175}
176
177#ifdef LDAP_FOUND
178
179#ifdef SASL2_FOUND
180static int kldap_sasl_interact( sasl_interact_t *interact, LdapOperation::SASL_Data *data )
181{
182 if ( data->proc ) {
183 for ( ; interact->id != SASL_CB_LIST_END; interact++ ) {
184 switch ( interact->id ) {
185 case SASL_CB_GETREALM:
186 data->creds.fields |= LdapOperation::SASL_Realm;
187 break;
188 case SASL_CB_AUTHNAME:
189 data->creds.fields |= LdapOperation::SASL_Authname;
190 break;
191 case SASL_CB_PASS:
192 data->creds.fields |= LdapOperation::SASL_Password;
193 break;
194 case SASL_CB_USER:
195 data->creds.fields |= LdapOperation::SASL_Authzid;
196 break;
197 }
198 }
199 int retval;
200 if ( ( retval = data->proc( data->creds, data->data ) ) ) {
201 return retval;
202 }
203 }
204
205 QString value;
206
207 while ( interact->id != SASL_CB_LIST_END ) {
208 value.clear();
209 switch ( interact->id ) {
210 case SASL_CB_GETREALM:
211 value = data->creds.realm;
212 kDebug() << "SASL_REALM=" << value;
213 break;
214 case SASL_CB_AUTHNAME:
215 value = data->creds.authname;
216 kDebug() << "SASL_AUTHNAME=" << value;
217 break;
218 case SASL_CB_PASS:
219 value = data->creds.password;
220 kDebug() << "SASL_PASSWD=[hidden]";
221 break;
222 case SASL_CB_USER:
223 value = data->creds.authzid;
224 kDebug() << "SASL_AUTHZID=" << value;
225 break;
226 }
227 if ( value.isEmpty() ) {
228 interact->result = NULL;
229 interact->len = 0;
230 } else {
231 interact->result = strdup( value.toUtf8() );
232 interact->len = strlen( (const char *)interact->result );
233 }
234 interact++;
235 }
236 return KLDAP_SUCCESS;
237}
238#endif
239
240int LdapOperation::LdapOperationPrivate::bind( const QByteArray &creds,
241 SASL_Callback_Proc *saslproc,
242 void *data, bool async )
243{
244 Q_ASSERT( mConnection );
245 LDAP *ld = (LDAP *) mConnection->handle();
246 LdapServer server;
247 server = mConnection->server();
248
249 int ret;
250
251 if ( server.auth() == LdapServer::SASL ) {
252#if defined( SASL2_FOUND ) && !defined( HAVE_WINLDAP_H )
253 sasl_conn_t *saslconn = (sasl_conn_t *)mConnection->saslHandle();
254 sasl_interact_t *client_interact = NULL;
255 const char *out = NULL;
256 uint outlen;
257 const char *mechusing = NULL;
258 struct berval ccred, *scred;
259 int saslresult;
260 QByteArray sdata = creds;
261
262 QString mech = server.mech();
263 if ( mech.isEmpty() ) {
264 mech = QLatin1String("DIGEST-MD5");
265 }
266
267 SASL_Data sasldata;
268 sasldata.proc = saslproc;
269 sasldata.data = data;
270 sasldata.creds.fields = 0;
271 sasldata.creds.realm = server.realm();
272 sasldata.creds.authname = server.user();
273 sasldata.creds.authzid = server.bindDn();
274 sasldata.creds.password = server.password();
275
276 do {
277 if ( sdata.isEmpty() ) {
278 do {
279 saslresult = sasl_client_start( saslconn, mech.toLatin1(),
280 &client_interact, &out, &outlen, &mechusing );
281
282 if ( saslresult == SASL_INTERACT ) {
283 if ( kldap_sasl_interact( client_interact, &sasldata ) != KLDAP_SUCCESS ) {
284 return KLDAP_SASL_ERROR;
285 }
286 }
287 kDebug() << "sasl_client_start mech: "
288 << mechusing << " outlen " << outlen
289 << " result: " << saslresult;
290 } while ( saslresult == SASL_INTERACT );
291 if ( saslresult != SASL_CONTINUE && saslresult != SASL_OK ) {
292 return KLDAP_SASL_ERROR;
293 }
294
295 } else {
296 kDebug() << "sasl_client_step";
297 do {
298 saslresult = sasl_client_step( saslconn, sdata.data(), sdata.size(),
299 &client_interact, &out, &outlen );
300 if ( saslresult == SASL_INTERACT ) {
301 if ( kldap_sasl_interact( client_interact, &sasldata ) != KLDAP_SUCCESS ) {
302 return KLDAP_SASL_ERROR;
303 }
304 }
305 } while ( saslresult == SASL_INTERACT );
306 kDebug() << "sasl_client_step result" << saslresult;
307 if ( saslresult != SASL_CONTINUE && saslresult != SASL_OK ) {
308 return KLDAP_SASL_ERROR;
309 }
310 }
311
312 ccred.bv_val = (char*) out;
313 ccred.bv_len = outlen;
314
315 if ( async ) {
316 kDebug() << "ldap_sasl_bind";
317 int msgid;
318 ret =
319 ldap_sasl_bind( ld, server.bindDn().toUtf8().data(), mech.toLatin1(),
320 &ccred, 0, 0, &msgid );
321 if ( ret == 0 ) {
322 ret = msgid;
323 }
324 kDebug() << "ldap_sasl_bind msgid" << ret;
325 } else {
326 kDebug() << "ldap_sasl_bind_s";
327 ret =
328 ldap_sasl_bind_s( ld, server.bindDn().toUtf8().data(), mech.toLatin1(),
329 &ccred, 0, 0, &scred );
330 kDebug() << "ldap_sasl_bind_s ret" << ret;
331 if ( scred ) {
332 sdata = QByteArray( scred->bv_val, scred->bv_len );
333 } else {
334 sdata = QByteArray();
335 }
336 }
337 } while ( !async && ret == KLDAP_SASL_BIND_IN_PROGRESS );
338#else
339 kError() << "SASL authentication is not available "
340 << "(re-compile kldap with cyrus-sasl and OpenLDAP development).";
341 return KLDAP_SASL_ERROR;
342#endif
343 } else { //simple auth
344 QByteArray bindname, pass;
345 struct berval ccred;
346 if ( server.auth() == LdapServer::Simple ) {
347 bindname = server.bindDn().toUtf8();
348 pass = server.password().toUtf8();
349 }
350 ccred.bv_val = pass.data();
351 ccred.bv_len = pass.size();
352 kDebug() << "binding to server, bindname: " << bindname << " password: *****";
353
354 if ( async ) {
355 kDebug() << "ldap_sasl_bind (simple)";
356#ifndef HAVE_WINLDAP_H
357 int msgid = 0;
358 ret = ldap_sasl_bind( ld, bindname.data(), 0, &ccred, 0, 0, &msgid );
359 if ( ret == 0 ) {
360 ret = msgid;
361 }
362#else
363 ret = ldap_simple_bind( ld, bindname.data(), pass.data() );
364#endif
365 } else {
366 kDebug() << "ldap_sasl_bind_s (simple)";
367#ifndef HAVE_WINLDAP_H
368 ret = ldap_sasl_bind_s( ld, bindname.data(), 0, &ccred, 0, 0, 0 );
369#else
370 ret = ldap_simple_bind_s( ld, bindname.data(), pass.data() );
371#endif
372 }
373 }
374 return ret;
375}
376
377int LdapOperation::LdapOperationPrivate::processResult( int rescode, LDAPMessage *msg )
378{
379 //kDebug();
380 int retval;
381 LDAP *ld = (LDAP *) mConnection->handle();
382
383 kDebug() << "rescode: " << rescode;
384 switch ( rescode ) {
385 case RES_SEARCH_ENTRY:
386 {
387 //kDebug() << "Found search entry";
388 mObject.clear();
389 LdapAttrMap attrs;
390 char *name;
391 struct berval **bvals;
392 BerElement *entry;
393
394 char *dn = ldap_get_dn( ld, msg );
395 mObject.setDn( QString::fromUtf8( dn ) );
396 ldap_memfree( dn );
397
398 // iterate over the attributes
399 name = ldap_first_attribute( ld, msg, &entry );
400 while ( name != 0 ) {
401 // print the values
402 bvals = ldap_get_values_len( ld, msg, name );
403 LdapAttrValue values;
404 if ( bvals ) {
405 for ( int i = 0; bvals[i] != 0; i++ ) {
406 char *val = bvals[i]->bv_val;
407 unsigned long len = bvals[i]->bv_len;
408 values.append( QByteArray( val, len ) );
409 }
410 ldap_value_free_len( bvals );
411 }
412 attrs[ QString::fromLatin1( name ) ] = values;
413 ldap_memfree( name );
414
415 // next attribute
416 name = ldap_next_attribute( ld, msg, entry );
417 }
418 ber_free( entry, 0 );
419 mObject.setAttributes( attrs );
420 break;
421 }
422 case RES_SEARCH_REFERENCE:
423 // Will only get this if following references is disabled. ignore it
424 rescode = 0;
425 break;
426 case RES_EXTENDED:
427 {
428 char *retoid;
429 struct berval *retdata;
430 retval = ldap_parse_extended_result( ld, msg, &retoid, &retdata, 0 );
431 if ( retval != KLDAP_SUCCESS ) {
432 ldap_msgfree( msg );
433 return -1;
434 }
435 mExtOid = retoid ? QByteArray( retoid ) : QByteArray();
436 mExtData = retdata ? QByteArray( retdata->bv_val, retdata->bv_len ) : QByteArray();
437 ldap_memfree( retoid );
438 ber_bvfree( retdata );
439 break;
440 }
441 case RES_BIND:
442 {
443 struct berval *servercred = 0;
444#ifndef HAVE_WINLDAP_H
445 // FIXME: Error handling Winldap does not have ldap_parse_sasl_bind_result
446 retval = ldap_parse_sasl_bind_result( ld, msg, &servercred, 0 );
447#else
448 retval = KLDAP_SUCCESS;
449#endif
450 if ( retval != KLDAP_SUCCESS && retval != KLDAP_SASL_BIND_IN_PROGRESS ) {
451 kDebug() << "RES_BIND error: " << retval;
452 ldap_msgfree( msg );
453 return -1;
454 }
455 kDebug() << "RES_BIND rescode" << rescode << "retval:" << retval;
456 if ( servercred ) {
457 mServerCred = QByteArray( servercred->bv_val, servercred->bv_len );
458 ber_bvfree( servercred );
459 } else {
460 mServerCred = QByteArray();
461 }
462 break;
463 }
464 default:
465 {
466 LDAPControl **serverctrls = 0;
467 char *matcheddn = 0, *errmsg = 0;
468 char **referralsp;
469 int errcodep;
470 retval =
471 ldap_parse_result( ld, msg, &errcodep, &matcheddn, &errmsg, &referralsp,
472 &serverctrls, 0 );
473 kDebug() << "rescode" << rescode << "retval:" << retval
474 << "matcheddn:" << matcheddn << "errcode:"
475 << errcodep << "errmsg:" << errmsg;
476 if ( retval != KLDAP_SUCCESS ) {
477 ldap_msgfree( msg );
478 return -1;
479 }
480 mControls.clear();
481 if ( serverctrls ) {
482 extractControls( mControls, serverctrls );
483 ldap_controls_free( serverctrls );
484 }
485 mReferrals.clear();
486 if ( referralsp ) {
487 char **tmp = referralsp;
488 while ( *tmp ) {
489 mReferrals.append( QByteArray( *tmp ) );
490 ldap_memfree( *tmp );
491 tmp++;
492 }
493 ldap_memfree( (char *) referralsp );
494 }
495 mMatchedDn.clear();
496 if ( matcheddn ) {
497 mMatchedDn = QString::fromUtf8( matcheddn );
498 ldap_memfree( matcheddn );
499 }
500 if ( errmsg ) {
501 ldap_memfree( errmsg );
502 }
503 }
504 }
505
506 ldap_msgfree( msg );
507
508 return rescode;
509}
510
511static void addModOp( LDAPMod ***pmods, int mod_type, const QString &attr,
512 const QByteArray *value = 0 )
513{
514 // kDebug() << "type:" << mod_type << "attr:" << attr <<
515 // "value:" << QString::fromUtf8(value,value.size()) <<
516 // "size:" << value.size();
517 LDAPMod **mods;
518
519 mods = *pmods;
520
521 uint i = 0;
522
523 if ( mods == 0 ) {
524 mods = (LDAPMod **)malloc( 2 * sizeof( LDAPMod * ) );
525 mods[ 0 ] = (LDAPMod *)malloc( sizeof( LDAPMod ) );
526 mods[ 1 ] = 0;
527 memset( mods[ 0 ], 0, sizeof( LDAPMod ) );
528 } else {
529 while ( mods[ i ] != 0 &&
530 ( strcmp( attr.toUtf8(), mods[i]->mod_type ) != 0 ||
531 ( mods[ i ]->mod_op & ~LDAP_MOD_BVALUES ) != mod_type ) ) i++;
532
533 if ( mods[ i ] == 0 ) {
534 mods = (LDAPMod **)realloc( mods, ( i + 2 ) * sizeof( LDAPMod * ) );
535 if ( mods == 0 ) {
536 kError() << "addModOp: realloc";
537 return;
538 }
539 mods[ i + 1 ] = 0;
540 mods[ i ] = (LDAPMod *) malloc( sizeof( LDAPMod ) );
541 memset( mods[ i ], 0, sizeof( LDAPMod ) );
542 }
543 }
544
545 mods[ i ]->mod_op = mod_type | LDAP_MOD_BVALUES;
546 if ( mods[ i ]->mod_type == 0 ) {
547 mods[ i ]->mod_type = strdup( attr.toUtf8() );
548 }
549
550 *pmods = mods;
551
552 if ( value == 0 ) {
553 return;
554 }
555
556 int vallen = value->size();
557 BerValue *berval;
558 berval = (BerValue *) malloc( sizeof( BerValue ) );
559 berval -> bv_len = vallen;
560 if ( vallen > 0 ) {
561 berval -> bv_val = (char *) malloc( vallen );
562 memcpy( berval -> bv_val, value->data(), vallen );
563 } else {
564 berval -> bv_val = 0;
565 }
566
567 if ( mods[ i ] -> mod_vals.modv_bvals == 0 ) {
568 mods[ i ]->mod_vals.modv_bvals =
569 (BerValue **) malloc( sizeof( BerValue * ) * 2 );
570 mods[ i ]->mod_vals.modv_bvals[ 0 ] = berval;
571 mods[ i ]->mod_vals.modv_bvals[ 1 ] = 0;
572// kDebug() << "new bervalue struct" << attr << value;
573 } else {
574 uint j = 0;
575 while ( mods[ i ]->mod_vals.modv_bvals[ j ] != 0 ) {
576 j++;
577 }
578 mods[ i ]->mod_vals.modv_bvals =
579 (BerValue **)realloc( mods[ i ]->mod_vals.modv_bvals,
580 ( j + 2 ) * sizeof( BerValue * ) );
581 if ( mods[ i ]->mod_vals.modv_bvals == 0 ) {
582 kError() << "addModOp: realloc";
583 free( berval );
584 return;
585 }
586 mods[ i ]->mod_vals.modv_bvals[ j ] = berval;
587 mods[ i ]->mod_vals.modv_bvals[ j+1 ] = 0;
588 kDebug() << j << ". new bervalue";
589 }
590}
591
592static void addControlOp( LDAPControl ***pctrls, const QString &oid,
593 const QByteArray &value, bool critical )
594{
595 LDAPControl **ctrls;
596 LDAPControl *ctrl = (LDAPControl *) malloc( sizeof( LDAPControl ) );
597
598 ctrls = *pctrls;
599
600 kDebug() << "oid:'" << oid << "' val: '" << value << "'";
601 int vallen = value.size();
602 ctrl->ldctl_value.bv_len = vallen;
603 if ( vallen ) {
604 ctrl->ldctl_value.bv_val = (char *) malloc( vallen );
605 memcpy( ctrl->ldctl_value.bv_val, value.data(), vallen );
606 } else {
607 ctrl->ldctl_value.bv_val = 0;
608 }
609 ctrl->ldctl_iscritical = critical;
610 ctrl->ldctl_oid = strdup( oid.toUtf8() );
611
612 uint i = 0;
613
614 if ( ctrls == 0 ) {
615 ctrls = (LDAPControl **)malloc ( 2 * sizeof( LDAPControl * ) );
616 ctrls[ 0 ] = 0;
617 ctrls[ 1 ] = 0;
618 } else {
619 while ( ctrls[ i ] != 0 ) {
620 i++;
621 }
622 ctrls[ i + 1 ] = 0;
623 ctrls =
624 (LDAPControl **)realloc( ctrls, ( i + 2 ) * sizeof( LDAPControl * ) );
625 }
626 ctrls[ i ] = ctrl;
627 *pctrls = ctrls;
628}
629
630static void createControls( LDAPControl ***pctrls, const LdapControls &ctrls )
631{
632 for ( int i = 0; i< ctrls.count(); ++i ) {
633 addControlOp( pctrls, ctrls[i].oid(), ctrls[i].value(), ctrls[i].critical() );
634 }
635}
636
637static void extractControls( LdapControls &ctrls, LDAPControl **pctrls )
638{
639 LDAPControl *ctrl;
640 LdapControl control;
641 int i = 0;
642
643 while ( pctrls[i] ) {
644 ctrl = pctrls[ i ];
645 control.setOid( QString::fromUtf8( ctrl->ldctl_oid ) );
646 control.setValue( QByteArray( ctrl->ldctl_value.bv_val,
647 ctrl->ldctl_value.bv_len ) );
648 control.setCritical( ctrl->ldctl_iscritical );
649 ctrls.append( control );
650 i++;
651 }
652}
653
654int LdapOperation::bind( const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data )
655{
656 return d->bind( creds, saslproc, data, true );
657}
658
659int LdapOperation::bind_s( SASL_Callback_Proc *saslproc, void *data )
660{
661 return d->bind( QByteArray(), saslproc, data, false );
662}
663
664int LdapOperation::search( const LdapDN &base, LdapUrl::Scope scope,
665 const QString &filter, const QStringList &attributes )
666{
667 Q_ASSERT( d->mConnection );
668 LDAP *ld = (LDAP *) d->mConnection->handle();
669
670 char **attrs = 0;
671 int msgid;
672
673 LDAPControl **serverctrls = 0, **clientctrls = 0;
674 createControls( &serverctrls, d->mServerCtrls );
675 createControls( &serverctrls, d->mClientCtrls );
676
677 int count = attributes.count();
678 if ( count > 0 ) {
679 attrs = static_cast<char**>( malloc( ( count + 1 ) * sizeof( char * ) ) );
680 for ( int i=0; i<count; i++ ) {
681 attrs[i] = strdup( attributes.at( i ).toUtf8() );
682 }
683 attrs[count] = 0;
684 }
685
686 int lscope = LDAP_SCOPE_BASE;
687 switch ( scope ) {
688 case LdapUrl::Base:
689 lscope = LDAP_SCOPE_BASE;
690 break;
691 case LdapUrl::One:
692 lscope = LDAP_SCOPE_ONELEVEL;
693 break;
694 case LdapUrl::Sub:
695 lscope = LDAP_SCOPE_SUBTREE;
696 break;
697 }
698
699 kDebug() << "asyncSearch() base=\"" << base.toString()
700 << "\" scope=" << (int)scope
701 << "filter=\"" << filter
702 << "\" attrs=" << attributes;
703 int retval =
704 ldap_search_ext( ld, base.toString().toUtf8().data(), lscope,
705 filter.isEmpty() ? QByteArray( "objectClass=*" ).data() :
706 filter.toUtf8().data(),
707 attrs, 0, serverctrls, clientctrls, 0,
708 d->mConnection->sizeLimit(), &msgid );
709
710 ldap_controls_free( serverctrls );
711 ldap_controls_free( clientctrls );
712
713 // free the attributes list again
714 if ( count > 0 ) {
715 for ( int i=0; i<count; i++ ) {
716 free( attrs[i] );
717 }
718 free( attrs );
719 }
720
721 if ( retval == 0 ) {
722 retval = msgid;
723 }
724 return retval;
725}
726
727int LdapOperation::add( const LdapObject &object )
728{
729 Q_ASSERT( d->mConnection );
730 LDAP *ld = (LDAP *) d->mConnection->handle();
731
732 int msgid;
733 LDAPMod **lmod = 0;
734
735 LDAPControl **serverctrls = 0, **clientctrls = 0;
736 createControls( &serverctrls, d->mServerCtrls );
737 createControls( &serverctrls, d->mClientCtrls );
738
739 for ( LdapAttrMap::ConstIterator it = object.attributes().begin();
740 it != object.attributes().end(); ++it ) {
741 QString attr = it.key();
742 for ( LdapAttrValue::ConstIterator it2 = ( *it ).begin(); it2 != (*it).end(); ++it2 ) {
743 addModOp( &lmod, 0, attr, &( *it2 ) );
744 }
745 }
746
747 int retval =
748 ldap_add_ext( ld, object.dn().toString().toUtf8().data(), lmod, serverctrls,
749 clientctrls, &msgid );
750
751 ldap_controls_free( serverctrls );
752 ldap_controls_free( clientctrls );
753 ldap_mods_free( lmod, 1 );
754 if ( retval == 0 ) {
755 retval = msgid;
756 }
757 return retval;
758}
759
760int LdapOperation::add_s( const LdapObject &object )
761{
762 Q_ASSERT( d->mConnection );
763 LDAP *ld = (LDAP *) d->mConnection->handle();
764
765 LDAPMod **lmod = 0;
766
767 LDAPControl **serverctrls = 0, **clientctrls = 0;
768 createControls( &serverctrls, d->mServerCtrls );
769 createControls( &serverctrls, d->mClientCtrls );
770
771 for ( LdapAttrMap::ConstIterator it = object.attributes().begin();
772 it != object.attributes().end(); ++it ) {
773 QString attr = it.key();
774 for ( LdapAttrValue::ConstIterator it2 = ( *it ).begin(); it2 != (*it).end(); ++it2 ) {
775 addModOp( &lmod, 0, attr, &( *it2 ) );
776 }
777 }
778
779 int retval =
780 ldap_add_ext_s( ld, object.dn().toString().toUtf8().data(), lmod, serverctrls,
781 clientctrls );
782
783 ldap_controls_free( serverctrls );
784 ldap_controls_free( clientctrls );
785 ldap_mods_free( lmod, 1 );
786 return retval;
787}
788
789int LdapOperation::add( const LdapDN &dn, const ModOps &ops )
790{
791 Q_ASSERT( d->mConnection );
792 LDAP *ld = (LDAP *) d->mConnection->handle();
793
794 int msgid;
795 LDAPMod **lmod = 0;
796
797 LDAPControl **serverctrls = 0, **clientctrls = 0;
798 createControls( &serverctrls, d->mServerCtrls );
799 createControls( &serverctrls, d->mClientCtrls );
800
801 for ( int i = 0; i < ops.count(); ++i ) {
802 for ( int j = 0; j < ops[i].values.count(); ++j ) {
803 addModOp( &lmod, 0, ops[i].attr, &ops[i].values[j] );
804 }
805 }
806
807 int retval =
808 ldap_add_ext( ld, dn.toString().toUtf8().data(), lmod, serverctrls,
809 clientctrls, &msgid );
810
811 ldap_controls_free( serverctrls );
812 ldap_controls_free( clientctrls );
813 ldap_mods_free( lmod, 1 );
814 if ( retval == 0 ) {
815 retval = msgid;
816 }
817 return retval;
818}
819
820int LdapOperation::add_s( const LdapDN &dn, const ModOps &ops )
821{
822 Q_ASSERT( d->mConnection );
823 LDAP *ld = (LDAP *) d->mConnection->handle();
824
825 LDAPMod **lmod = 0;
826
827 LDAPControl **serverctrls = 0, **clientctrls = 0;
828 createControls( &serverctrls, d->mServerCtrls );
829 createControls( &serverctrls, d->mClientCtrls );
830
831 for ( int i = 0; i < ops.count(); ++i ) {
832 for ( int j = 0; j < ops[i].values.count(); ++j ) {
833 addModOp( &lmod, 0, ops[i].attr, &ops[i].values[j] );
834 }
835 }
836 kDebug() << dn.toString();
837 int retval =
838 ldap_add_ext_s( ld, dn.toString().toUtf8().data(), lmod, serverctrls,
839 clientctrls );
840
841 ldap_controls_free( serverctrls );
842 ldap_controls_free( clientctrls );
843 ldap_mods_free( lmod, 1 );
844 return retval;
845}
846
847int LdapOperation::rename( const LdapDN &dn, const QString &newRdn,
848 const QString &newSuperior, bool deleteold )
849{
850 Q_ASSERT( d->mConnection );
851 LDAP *ld = (LDAP *) d->mConnection->handle();
852
853 int msgid;
854
855 LDAPControl **serverctrls = 0, **clientctrls = 0;
856 createControls( &serverctrls, d->mServerCtrls );
857 createControls( &serverctrls, d->mClientCtrls );
858
859 int retval = ldap_rename( ld, dn.toString().toUtf8().data(), newRdn.toUtf8().data(),
860 newSuperior.isEmpty() ? (char *) 0 : newSuperior.toUtf8().data(),
861 deleteold, serverctrls, clientctrls, &msgid );
862
863 ldap_controls_free( serverctrls );
864 ldap_controls_free( clientctrls );
865
866 if ( retval == 0 ) {
867 retval = msgid;
868 }
869 return retval;
870}
871
872int LdapOperation::rename_s( const LdapDN &dn, const QString &newRdn,
873 const QString &newSuperior, bool deleteold )
874{
875 Q_ASSERT( d->mConnection );
876 LDAP *ld = (LDAP *) d->mConnection->handle();
877
878 LDAPControl **serverctrls = 0, **clientctrls = 0;
879 createControls( &serverctrls, d->mServerCtrls );
880 createControls( &serverctrls, d->mClientCtrls );
881
882 int retval = ldap_rename_s( ld, dn.toString().toUtf8().data(), newRdn.toUtf8().data(),
883 newSuperior.isEmpty() ? (char *) 0 : newSuperior.toUtf8().data(),
884 deleteold, serverctrls, clientctrls );
885
886 ldap_controls_free( serverctrls );
887 ldap_controls_free( clientctrls );
888
889 return retval;
890}
891
892int LdapOperation::del( const LdapDN &dn )
893{
894 Q_ASSERT( d->mConnection );
895 LDAP *ld = (LDAP *) d->mConnection->handle();
896
897 int msgid;
898
899 LDAPControl **serverctrls = 0, **clientctrls = 0;
900 createControls( &serverctrls, d->mServerCtrls );
901 createControls( &serverctrls, d->mClientCtrls );
902
903 int retval =
904 ldap_delete_ext( ld, dn.toString().toUtf8().data(), serverctrls, clientctrls, &msgid );
905
906 ldap_controls_free( serverctrls );
907 ldap_controls_free( clientctrls );
908
909 if ( retval == 0 ) {
910 retval = msgid;
911 }
912 return retval;
913}
914
915int LdapOperation::del_s( const LdapDN &dn )
916{
917 Q_ASSERT( d->mConnection );
918 LDAP *ld = (LDAP *) d->mConnection->handle();
919
920 LDAPControl **serverctrls = 0, **clientctrls = 0;
921 createControls( &serverctrls, d->mServerCtrls );
922 createControls( &serverctrls, d->mClientCtrls );
923
924 int retval = ldap_delete_ext_s( ld, dn.toString().toUtf8().data(), serverctrls, clientctrls );
925
926 ldap_controls_free( serverctrls );
927 ldap_controls_free( clientctrls );
928
929 return retval;
930}
931
932int LdapOperation::modify( const LdapDN &dn, const ModOps &ops )
933{
934 Q_ASSERT( d->mConnection );
935 LDAP *ld = (LDAP *)d->mConnection->handle();
936
937 int msgid;
938 LDAPMod **lmod = 0;
939
940 LDAPControl **serverctrls = 0, **clientctrls = 0;
941 createControls( &serverctrls, d->mServerCtrls );
942 createControls( &serverctrls, d->mClientCtrls );
943
944 for ( int i = 0; i < ops.count(); ++i ) {
945 int mtype = 0;
946 switch ( ops[i].type ) {
947 case Mod_None:
948 mtype = 0;
949 break;
950 case Mod_Add:
951 mtype = LDAP_MOD_ADD;
952 break;
953 case Mod_Replace:
954 mtype = LDAP_MOD_REPLACE;
955 break;
956 case Mod_Del:
957 mtype = LDAP_MOD_DELETE;
958 break;
959 }
960 addModOp( &lmod, mtype, ops[i].attr, 0 );
961 for ( int j = 0; j < ops[i].values.count(); ++j ) {
962 addModOp( &lmod, mtype, ops[i].attr, &ops[i].values[j] );
963 }
964 }
965
966 int retval =
967 ldap_modify_ext( ld, dn.toString().toUtf8().data(), lmod, serverctrls, clientctrls, &msgid );
968
969 ldap_controls_free( serverctrls );
970 ldap_controls_free( clientctrls );
971 ldap_mods_free( lmod, 1 );
972 if ( retval == 0 ) {
973 retval = msgid;
974 }
975 return retval;
976}
977
978int LdapOperation::modify_s( const LdapDN &dn, const ModOps &ops )
979{
980 Q_ASSERT( d->mConnection );
981 LDAP *ld = (LDAP *) d->mConnection->handle();
982
983 LDAPMod **lmod = 0;
984
985 LDAPControl **serverctrls = 0, **clientctrls = 0;
986 createControls( &serverctrls, d->mServerCtrls );
987 createControls( &serverctrls, d->mClientCtrls );
988
989 for ( int i = 0; i < ops.count(); ++i ) {
990 int mtype = 0;
991 switch ( ops[i].type ) {
992 case Mod_None:
993 mtype = 0;
994 break;
995 case Mod_Add:
996 mtype = LDAP_MOD_ADD;
997 break;
998 case Mod_Replace:
999 mtype = LDAP_MOD_REPLACE;
1000 break;
1001 case Mod_Del:
1002 mtype = LDAP_MOD_DELETE;
1003 break;
1004 }
1005 addModOp( &lmod, mtype, ops[i].attr, 0 );
1006 for ( int j = 0; j < ops[i].values.count(); ++j ) {
1007 addModOp( &lmod, mtype, ops[i].attr, &ops[i].values[j] );
1008 }
1009 }
1010
1011 int retval =
1012 ldap_modify_ext_s( ld, dn.toString().toUtf8().data(), lmod, serverctrls, clientctrls );
1013
1014 ldap_controls_free( serverctrls );
1015 ldap_controls_free( clientctrls );
1016 ldap_mods_free( lmod, 1 );
1017 return retval;
1018}
1019
1020int LdapOperation::compare( const LdapDN &dn, const QString &attr, const QByteArray &value )
1021{
1022 Q_ASSERT( d->mConnection );
1023 LDAP *ld = (LDAP *) d->mConnection->handle();
1024 int msgid;
1025
1026 LDAPControl **serverctrls = 0, **clientctrls = 0;
1027 createControls( &serverctrls, d->mServerCtrls );
1028 createControls( &serverctrls, d->mClientCtrls );
1029
1030 int vallen = value.size();
1031 BerValue *berval;
1032 berval = (BerValue *) malloc( sizeof( BerValue ) );
1033 berval -> bv_val = (char *) malloc( vallen );
1034 berval -> bv_len = vallen;
1035 memcpy( berval -> bv_val, value.data(), vallen );
1036
1037 int retval = ldap_compare_ext( ld, dn.toString().toUtf8().data(), attr.toUtf8().data(), berval,
1038 serverctrls, clientctrls, &msgid );
1039
1040 ber_bvfree( berval );
1041 ldap_controls_free( serverctrls );
1042 ldap_controls_free( clientctrls );
1043
1044 if ( retval == 0 ) {
1045 retval = msgid;
1046 }
1047 return retval;
1048}
1049
1050int LdapOperation::compare_s( const LdapDN &dn, const QString &attr, const QByteArray &value )
1051{
1052 Q_ASSERT( d->mConnection );
1053 LDAP *ld = (LDAP *) d->mConnection->handle();
1054
1055 LDAPControl **serverctrls = 0, **clientctrls = 0;
1056 createControls( &serverctrls, d->mServerCtrls );
1057 createControls( &serverctrls, d->mClientCtrls );
1058
1059 int vallen = value.size();
1060 BerValue *berval;
1061 berval = (BerValue *) malloc( sizeof( BerValue ) );
1062 berval -> bv_val = (char *) malloc( vallen );
1063 berval -> bv_len = vallen;
1064 memcpy( berval -> bv_val, value.data(), vallen );
1065
1066 int retval = ldap_compare_ext_s( ld, dn.toString().toUtf8().data(), attr.toUtf8().data(), berval,
1067 serverctrls, clientctrls );
1068
1069 ber_bvfree( berval );
1070 ldap_controls_free( serverctrls );
1071 ldap_controls_free( clientctrls );
1072
1073 return retval;
1074}
1075
1076int LdapOperation::exop( const QString &oid, const QByteArray &data )
1077{
1078 Q_ASSERT( d->mConnection );
1079#if defined(HAVE_LDAP_EXTENDED_OPERATION) && defined(HAVE_LDAP_EXTENDED_OPERATION_PROTOTYPE)
1080 LDAP *ld = (LDAP *) d->mConnection->handle();
1081 int msgid;
1082
1083 LDAPControl **serverctrls = 0, **clientctrls = 0;
1084 createControls( &serverctrls, d->mServerCtrls );
1085 createControls( &serverctrls, d->mClientCtrls );
1086
1087 int vallen = data.size();
1088 BerValue *berval;
1089 berval = (BerValue *) malloc( sizeof( BerValue ) );
1090 berval -> bv_val = (char *) malloc( vallen );
1091 berval -> bv_len = vallen;
1092 memcpy( berval -> bv_val, data.data(), vallen );
1093
1094 int retval = ldap_extended_operation( ld, oid.toUtf8().data(), berval,
1095 serverctrls, clientctrls, &msgid );
1096
1097 ber_bvfree( berval );
1098 ldap_controls_free( serverctrls );
1099 ldap_controls_free( clientctrls );
1100
1101 if ( retval == 0 ) {
1102 retval = msgid;
1103 }
1104 return retval;
1105#else
1106 kError() << "Your LDAP client libraries don't support extended operations.";
1107 return -1;
1108#endif
1109}
1110
1111int LdapOperation::exop_s( const QString &oid, const QByteArray &data )
1112{
1113#if defined(HAVE_LDAP_EXTENDED_OPERATION) && defined(HAVE_LDAP_EXTENDED_OPERATION_PROTOTYPE)
1114 Q_ASSERT( d->mConnection );
1115 LDAP *ld = (LDAP *) d->mConnection->handle();
1116 BerValue *retdata;
1117 char *retoid;
1118
1119 LDAPControl **serverctrls = 0, **clientctrls = 0;
1120 createControls( &serverctrls, d->mServerCtrls );
1121 createControls( &serverctrls, d->mClientCtrls );
1122
1123 int vallen = data.size();
1124 BerValue *berval;
1125 berval = (BerValue *) malloc( sizeof( BerValue ) );
1126 berval -> bv_val = (char *) malloc( vallen );
1127 berval -> bv_len = vallen;
1128 memcpy( berval -> bv_val, data.data(), vallen );
1129
1130 int retval = ldap_extended_operation_s( ld, oid.toUtf8().data(), berval,
1131 serverctrls, clientctrls, &retoid, &retdata );
1132
1133 ber_bvfree( berval );
1134 ber_bvfree( retdata );
1135 free( retoid );
1136 ldap_controls_free( serverctrls );
1137 ldap_controls_free( clientctrls );
1138
1139 return retval;
1140#else
1141 kError() << "Your LDAP client libraries don't support extended operations.";
1142 return -1;
1143#endif
1144}
1145
1146int LdapOperation::abandon( int id )
1147{
1148 Q_ASSERT( d->mConnection );
1149 LDAP *ld = (LDAP *) d->mConnection->handle();
1150
1151 LDAPControl **serverctrls = 0, **clientctrls = 0;
1152 createControls( &serverctrls, d->mServerCtrls );
1153 createControls( &serverctrls, d->mClientCtrls );
1154
1155 int retval = ldap_abandon_ext( ld, id, serverctrls, clientctrls );
1156
1157 ldap_controls_free( serverctrls );
1158 ldap_controls_free( clientctrls );
1159
1160 return retval;
1161}
1162
1163int LdapOperation::waitForResult( int id, int msecs )
1164{
1165 Q_ASSERT( d->mConnection );
1166 LDAP *ld = (LDAP *) d->mConnection->handle();
1167
1168 LDAPMessage *msg;
1169 int rescode;
1170
1171 QTime stopWatch;
1172 stopWatch.start();
1173 int attempt( 1 );
1174 int timeout( 0 );
1175
1176 do {
1177 // Calculate the timeout value to use and assign it to a timeval structure
1178 // see man select (2) for details
1179 timeout = kldap_timeout_value( msecs, stopWatch.elapsed() );
1180 kDebug() << "(" << id << "," << msecs
1181 << "): Waiting" << timeout
1182 << "msecs for result. Attempt #" << attempt++;
1183 struct timeval tv;
1184 tv.tv_sec = timeout / 1000;
1185 tv.tv_usec = ( timeout % 1000 ) * 1000;
1186
1187 // Wait for a result
1188 rescode = ldap_result( ld, id, 0, timeout < 0 ? 0 : &tv, &msg );
1189 if ( rescode == -1 ) {
1190 return -1;
1191 }
1192 // Act on the return code
1193 if ( rescode != 0 ) {
1194 // Some kind of result is available for processing
1195 return d->processResult( rescode, msg );
1196 }
1197 } while ( msecs == -1 || stopWatch.elapsed() < msecs );
1198
1199 return 0; //timeout
1200}
1201
1202#else
1203
1204int LdapOperation::bind( const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data )
1205{
1206 kError() << "LDAP support not compiled";
1207 return -1;
1208}
1209
1210int LdapOperation::bind_s( SASL_Callback_Proc *saslproc, void *data )
1211{
1212 kError() << "LDAP support not compiled";
1213 return -1;
1214}
1215
1216int LdapOperation::search( const LdapDN &base, LdapUrl::Scope scope,
1217 const QString &filter, const QStringList &attributes )
1218{
1219 kError() << "LDAP support not compiled";
1220 return -1;
1221}
1222
1223int LdapOperation::add( const LdapObject &object )
1224{
1225 kError() << "LDAP support not compiled";
1226 return -1;
1227}
1228
1229int LdapOperation::add_s( const LdapObject &object )
1230{
1231 kError() << "LDAP support not compiled";
1232 return -1;
1233}
1234
1235int LdapOperation::add( const LdapDN &dn, const ModOps &ops )
1236{
1237 kError() << "LDAP support not compiled";
1238 return -1;
1239}
1240
1241int LdapOperation::add_s( const LdapDN &dn, const ModOps &ops )
1242{
1243 kError() << "LDAP support not compiled";
1244 return -1;
1245}
1246
1247int LdapOperation::rename( const LdapDN &dn, const QString &newRdn,
1248 const QString &newSuperior, bool deleteold )
1249{
1250 kError() << "LDAP support not compiled";
1251 return -1;
1252}
1253
1254int LdapOperation::rename_s( const LdapDN &dn, const QString &newRdn,
1255 const QString &newSuperior, bool deleteold )
1256{
1257 kError() << "LDAP support not compiled";
1258 return -1;
1259}
1260
1261int LdapOperation::del( const LdapDN &dn )
1262{
1263 kError() << "LDAP support not compiled";
1264 return -1;
1265}
1266
1267int LdapOperation::del_s( const LdapDN &dn )
1268{
1269 kError() << "LDAP support not compiled";
1270 return -1;
1271}
1272
1273int LdapOperation::modify( const LdapDN &dn, const ModOps &ops )
1274{
1275 kError() << "LDAP support not compiled";
1276 return -1;
1277}
1278
1279int LdapOperation::modify_s( const LdapDN &dn, const ModOps &ops )
1280{
1281 kError() << "LDAP support not compiled";
1282 return -1;
1283}
1284
1285int LdapOperation::compare( const LdapDN &dn, const QString &attr, const QByteArray &value )
1286{
1287 kError() << "LDAP support not compiled";
1288 return -1;
1289}
1290
1291int LdapOperation::exop( const QString &oid, const QByteArray &data )
1292{
1293 kError() << "LDAP support not compiled";
1294 return -1;
1295}
1296
1297int LdapOperation::compare_s( const LdapDN &dn, const QString &attr, const QByteArray &value )
1298{
1299 kError() << "LDAP support not compiled";
1300 return -1;
1301}
1302
1303int LdapOperation::exop_s( const QString &oid, const QByteArray &data )
1304{
1305 kError() << "LDAP support not compiled";
1306 return -1;
1307}
1308
1309int LdapOperation::waitForResult( int id, int msecs )
1310{
1311 kError() << "LDAP support not compiled";
1312 return -1;
1313}
1314
1315int LdapOperation::abandon( int id )
1316{
1317 kError() << "LDAP support not compiled";
1318 return -1;
1319}
1320
1321#endif
1322