~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to libraries/libldap/ldap_sync.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $OpenLDAP: pkg/ldap/libraries/libldap/ldap_sync.c,v 1.2.2.3 2008/02/11 23:26:41 kurt Exp $ */
 
2
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
3
 *
 
4
 * Copyright 2006-2008 The OpenLDAP Foundation.
 
5
 * All rights reserved.
 
6
 *
 
7
 * Redistribution and use in source and binary forms, with or without
 
8
 * modification, are permitted only as authorized by the OpenLDAP
 
9
 * Public License.
 
10
 *
 
11
 * A copy of this license is available in the file LICENSE in the
 
12
 * top-level directory of the distribution or, alternatively, at
 
13
 * <http://www.OpenLDAP.org/license.html>.
 
14
 */
 
15
/* ACKNOWLEDGEMENTS:
 
16
 * This program was originally developed by Pierangelo Masarati
 
17
 * for inclusion in OpenLDAP Software.
 
18
 */
 
19
 
 
20
/*
 
21
 * Proof-of-concept API that implement the client-side
 
22
 * of the "LDAP Content Sync Operation" (RFC 4533)
 
23
 */
 
24
 
 
25
#include "portable.h"
 
26
 
 
27
#include <ac/time.h>
 
28
 
 
29
#include "ldap-int.h"
 
30
 
 
31
#ifdef LDAP_SYNC_TRACE
 
32
static const char *
 
33
ldap_sync_state2str( int state )
 
34
{
 
35
        switch ( state ) {
 
36
        case LDAP_SYNC_PRESENT:
 
37
                return "LDAP_SYNC_PRESENT";
 
38
 
 
39
        case LDAP_SYNC_ADD:
 
40
                return "LDAP_SYNC_ADD";
 
41
 
 
42
        case LDAP_SYNC_MODIFY:
 
43
                return "LDAP_SYNC_MODIFY";
 
44
 
 
45
        case LDAP_SYNC_DELETE:
 
46
                return "LDAP_SYNC_DELETE";
 
47
 
 
48
        default:
 
49
                return "(unknown)";
 
50
        }
 
51
}
 
52
#endif
 
53
 
 
54
/*
 
55
 * initialize the persistent search structure
 
56
 */
 
57
ldap_sync_t *
 
58
ldap_sync_initialize( ldap_sync_t *ls_in )
 
59
{
 
60
        ldap_sync_t     *ls = ls_in;
 
61
 
 
62
        if ( ls == NULL ) {
 
63
                ls = ldap_memalloc( sizeof( ldap_sync_t ) );
 
64
                if ( ls == NULL ) {
 
65
                        return NULL;
 
66
                }
 
67
 
 
68
        } else {
 
69
                memset( ls, 0, sizeof( ldap_sync_t ) );
 
70
        }
 
71
 
 
72
        ls->ls_scope = LDAP_SCOPE_SUBTREE;
 
73
        ls->ls_timeout = -1;
 
74
 
 
75
        return ls;
 
76
}
 
77
 
 
78
/*
 
79
 * destroy the persistent search structure
 
80
 */
 
81
void
 
82
ldap_sync_destroy( ldap_sync_t *ls, int freeit )
 
83
{
 
84
        assert( ls != NULL );
 
85
 
 
86
        if ( ls->ls_base != NULL ) {
 
87
                ldap_memfree( ls->ls_base );
 
88
                ls->ls_base = NULL;
 
89
        }
 
90
 
 
91
        if ( ls->ls_filter != NULL ) {
 
92
                ldap_memfree( ls->ls_filter );
 
93
                ls->ls_filter = NULL;
 
94
        }
 
95
 
 
96
        if ( ls->ls_attrs != NULL ) {
 
97
                int     i;
 
98
 
 
99
                for ( i = 0; ls->ls_attrs[ i ] != NULL; i++ ) {
 
100
                        ldap_memfree( ls->ls_attrs[ i ] );
 
101
                }
 
102
                ldap_memfree( ls->ls_attrs );
 
103
                ls->ls_attrs = NULL;
 
104
        }
 
105
 
 
106
        if ( ls->ls_ld != NULL ) {
 
107
                (void)ldap_unbind_ext( ls->ls_ld, NULL, NULL );
 
108
#ifdef LDAP_SYNC_TRACE
 
109
                fprintf( stderr, "ldap_unbind_ext()\n" );
 
110
#endif /* LDAP_SYNC_TRACE */
 
111
                ls->ls_ld = NULL;
 
112
        }
 
113
 
 
114
        if ( ls->ls_cookie.bv_val != NULL ) {
 
115
                ldap_memfree( ls->ls_cookie.bv_val );
 
116
                ls->ls_cookie.bv_val = NULL;
 
117
        }
 
118
 
 
119
        if ( freeit ) {
 
120
                ldap_memfree( ls );
 
121
        }
 
122
}
 
123
 
 
124
/*
 
125
 * handle the LDAP_RES_SEARCH_ENTRY response
 
126
 */
 
127
static int
 
128
ldap_sync_search_entry( ldap_sync_t *ls, LDAPMessage *res )
 
129
{
 
130
        LDAPControl             **ctrls = NULL;
 
131
        int                     rc = LDAP_SUCCESS,
 
132
                                i;
 
133
        BerElement              *ber = NULL;
 
134
        struct berval           entryUUID = { 0 },
 
135
                                cookie = { 0 };
 
136
        int                     state = -1;
 
137
        ber_len_t               len;
 
138
        ldap_sync_refresh_t     phase = ls->ls_refreshPhase;
 
139
 
 
140
#ifdef LDAP_SYNC_TRACE
 
141
        fprintf( stderr, "\tgot LDAP_RES_SEARCH_ENTRY\n" );
 
142
#endif /* LDAP_SYNC_TRACE */
 
143
 
 
144
        assert( ls != NULL );
 
145
        assert( res != NULL );
 
146
 
 
147
        /* OK */
 
148
 
 
149
        /* extract:
 
150
         * - data
 
151
         * - entryUUID
 
152
         *
 
153
         * check that:
 
154
         * - Sync State Control is "add"
 
155
         */
 
156
 
 
157
        /* the control MUST be present */
 
158
 
 
159
        /* extract controls */
 
160
        ldap_get_entry_controls( ls->ls_ld, res, &ctrls );
 
161
        if ( ctrls == NULL ) {
 
162
                rc = LDAP_OTHER;
 
163
                goto done;
 
164
        }
 
165
 
 
166
        /* lookup the sync state control */
 
167
        for ( i = 0; ctrls[ i ] != NULL; i++ ) {
 
168
                if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_STATE ) == 0 ) {
 
169
                        break;
 
170
                }
 
171
        }
 
172
 
 
173
        /* control must be present; there might be other... */
 
174
        if ( ctrls[ i ] == NULL ) {
 
175
                rc = LDAP_OTHER;
 
176
                goto done;
 
177
        }
 
178
 
 
179
        /* extract data */
 
180
        ber = ber_init( &ctrls[ i ]->ldctl_value );
 
181
        /* scan entryUUID in-place ("m") */
 
182
        ber_scanf( ber, "{em" /*"}"*/, &state, &entryUUID );
 
183
        if ( entryUUID.bv_len == 0 ) {
 
184
                rc = LDAP_OTHER;
 
185
                goto done;
 
186
        }
 
187
 
 
188
        if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
 
189
                /* scan cookie in-place ("m") */
 
190
                ber_scanf( ber, /*"{"*/ "m}", &cookie );
 
191
                if ( cookie.bv_val != NULL ) {
 
192
                        ber_bvreplace( &ls->ls_cookie, &cookie );
 
193
                }
 
194
#ifdef LDAP_SYNC_TRACE
 
195
                fprintf( stderr, "\t\tgot cookie=%s\n",
 
196
                        cookie.bv_val ? cookie.bv_val : "(null)" );
 
197
#endif /* LDAP_SYNC_TRACE */
 
198
        }
 
199
 
 
200
        switch ( state ) {
 
201
        case LDAP_SYNC_PRESENT:
 
202
        case LDAP_SYNC_DELETE:
 
203
        case LDAP_SYNC_ADD:
 
204
        case LDAP_SYNC_MODIFY:
 
205
                /* NOTE: ldap_sync_refresh_t is defined
 
206
                 * as the corresponding LDAP_SYNC_*
 
207
                 * for the 4 above cases */
 
208
                phase = state;
 
209
#ifdef LDAP_SYNC_TRACE
 
210
                fprintf( stderr, "\t\tgot syncState=%s\n", ldap_sync_state2str( state ) );
 
211
#endif /* LDAP_SYNC_TRACE */
 
212
                break;
 
213
 
 
214
        default:
 
215
                rc = LDAP_OTHER;
 
216
#ifdef LDAP_SYNC_TRACE
 
217
                fprintf( stderr, "\t\tgot unknown syncState=%d\n", state );
 
218
#endif /* LDAP_SYNC_TRACE */
 
219
                goto done;
 
220
        }
 
221
 
 
222
        if ( ls->ls_search_entry ) {
 
223
                rc = ls->ls_search_entry( ls, res, &entryUUID, phase );
 
224
        }
 
225
 
 
226
done:;
 
227
        if ( ber != NULL ) {
 
228
                ber_free( ber, 1 );
 
229
        }
 
230
 
 
231
        if ( ctrls != NULL ) {
 
232
                ldap_controls_free( ctrls );
 
233
        }
 
234
 
 
235
        return rc;
 
236
}
 
237
 
 
238
/*
 
239
 * handle the LDAP_RES_SEARCH_REFERENCE response
 
240
 * (to be implemented yet)
 
241
 */
 
242
static int
 
243
ldap_sync_search_reference( ldap_sync_t *ls, LDAPMessage *res )
 
244
{
 
245
        int             rc = 0;
 
246
 
 
247
#ifdef LDAP_SYNC_TRACE
 
248
        fprintf( stderr, "\tgot LDAP_RES_SEARCH_REFERENCE\n" );
 
249
#endif /* LDAP_SYNC_TRACE */
 
250
 
 
251
        assert( ls != NULL );
 
252
        assert( res != NULL );
 
253
 
 
254
        if ( ls->ls_search_reference ) {
 
255
                rc = ls->ls_search_reference( ls, res );
 
256
        }
 
257
 
 
258
        return rc;
 
259
}
 
260
 
 
261
/*
 
262
 * handle the LDAP_RES_SEARCH_RESULT response
 
263
 */
 
264
static int
 
265
ldap_sync_search_result( ldap_sync_t *ls, LDAPMessage *res )
 
266
{
 
267
        int             err;
 
268
        char            *matched = NULL,
 
269
                        *msg = NULL;
 
270
        LDAPControl     **ctrls = NULL;
 
271
        int             rc;
 
272
        int             refreshDeletes = -1;
 
273
 
 
274
#ifdef LDAP_SYNC_TRACE
 
275
        fprintf( stderr, "\tgot LDAP_RES_SEARCH_RESULT\n" );
 
276
#endif /* LDAP_SYNC_TRACE */
 
277
 
 
278
        assert( ls != NULL );
 
279
        assert( res != NULL );
 
280
 
 
281
        /* should not happen in refreshAndPersist... */
 
282
        rc = ldap_parse_result( ls->ls_ld,
 
283
                res, &err, &matched, &msg, NULL, &ctrls, 0 );
 
284
#ifdef LDAP_SYNC_TRACE
 
285
        fprintf( stderr,
 
286
                "\tldap_parse_result(%d, \"%s\", \"%s\") == %d\n",
 
287
                err,
 
288
                matched ? matched : "",
 
289
                msg ? msg : "",
 
290
                rc );
 
291
#endif /* LDAP_SYNC_TRACE */
 
292
        if ( rc == LDAP_SUCCESS ) {
 
293
                rc = err;
 
294
        }
 
295
 
 
296
        ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
 
297
 
 
298
        switch ( rc ) {
 
299
        case LDAP_SUCCESS: {
 
300
                int             i;
 
301
                BerElement      *ber = NULL;
 
302
                ber_len_t       len;
 
303
                struct berval   cookie = { 0 };
 
304
 
 
305
                /* deal with control; then fallthru to handler */
 
306
                if ( ctrls == NULL ) {
 
307
                        rc = LDAP_OTHER;
 
308
                        goto done;
 
309
                }
 
310
 
 
311
                /* lookup the sync state control */
 
312
                for ( i = 0; ctrls[ i ] != NULL; i++ ) {
 
313
                        if ( strcmp( ctrls[ i ]->ldctl_oid,
 
314
                                LDAP_CONTROL_SYNC_DONE ) == 0 )
 
315
                        {
 
316
                                break;
 
317
                        }
 
318
                }
 
319
 
 
320
                /* control must be present; there might be other... */
 
321
                if ( ctrls[ i ] == NULL ) {
 
322
                        rc = LDAP_OTHER;
 
323
                        goto done;
 
324
                }
 
325
 
 
326
                /* extract data */
 
327
                ber = ber_init( &ctrls[ i ]->ldctl_value );
 
328
 
 
329
                ber_scanf( ber, "{" /*"}"*/);
 
330
                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
 
331
                        ber_scanf( ber, "m", &cookie );
 
332
                        if ( cookie.bv_val != NULL ) {
 
333
                                ber_bvreplace( &ls->ls_cookie, &cookie );
 
334
                        }
 
335
#ifdef LDAP_SYNC_TRACE
 
336
                        fprintf( stderr, "\t\tgot cookie=%s\n",
 
337
                                cookie.bv_val ? cookie.bv_val : "(null)" );
 
338
#endif /* LDAP_SYNC_TRACE */
 
339
                }
 
340
 
 
341
                refreshDeletes = 0;
 
342
                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
 
343
                        ber_scanf( ber, "b", &refreshDeletes );
 
344
                        if ( refreshDeletes ) {
 
345
                                refreshDeletes = 1;
 
346
                        }
 
347
                }
 
348
 
 
349
                ber_scanf( ber, /*"{"*/ "}" );
 
350
 
 
351
                /* NOTE: if any goto/return between ber_init() and here
 
352
                 * is introduced, don't forget to ber_free() */
 
353
                ber_free( ber, 1 );
 
354
 
 
355
#ifdef LDAP_SYNC_TRACE
 
356
                fprintf( stderr, "\t\tgot refreshDeletes=%s\n",
 
357
                        refreshDeletes ? "TRUE" : "FALSE" );
 
358
#endif /* LDAP_SYNC_TRACE */
 
359
 
 
360
                /* FIXME: what should we do with the refreshDelete? */
 
361
                switch ( refreshDeletes ) {
 
362
                case 0:
 
363
                        ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
 
364
                        break;
 
365
 
 
366
                default:
 
367
                        ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
 
368
                        break;
 
369
                }
 
370
 
 
371
                } /* fallthru */
 
372
 
 
373
        case LDAP_SYNC_REFRESH_REQUIRED:
 
374
                /* TODO: check for Sync Done Control */
 
375
                /* FIXME: perhaps the handler should be called
 
376
                 * also in case of failure; we'll deal with this 
 
377
                 * later when implementing refreshOnly */
 
378
                if ( ls->ls_search_result ) {
 
379
                        err = ls->ls_search_result( ls, res, refreshDeletes );
 
380
                }
 
381
                break;
 
382
 
 
383
        default:
 
384
                break;
 
385
        }
 
386
 
 
387
done:;
 
388
        if ( matched != NULL ) {
 
389
                ldap_memfree( matched );
 
390
        }
 
391
 
 
392
        if ( msg != NULL ) {
 
393
                ldap_memfree( msg );
 
394
        }
 
395
 
 
396
        if ( ctrls != NULL ) {
 
397
                ldap_controls_free( ctrls );
 
398
        }
 
399
 
 
400
        ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
 
401
 
 
402
        return rc;
 
403
}
 
404
 
 
405
/*
 
406
 * handle the LDAP_RES_INTERMEDIATE response
 
407
 */
 
408
static int
 
409
ldap_sync_search_intermediate( ldap_sync_t *ls, LDAPMessage *res, int *refreshDone )
 
410
{
 
411
        int                     rc;
 
412
        char                    *retoid = NULL;
 
413
        struct berval           *retdata = NULL;
 
414
        BerElement              *ber = NULL;
 
415
        ber_len_t               len;
 
416
        ber_tag_t               tag,
 
417
                                syncinfo_tag;
 
418
        struct berval           cookie;
 
419
        int                     refreshDeletes = 0;
 
420
        BerVarray               syncUUIDs = NULL;
 
421
        ldap_sync_refresh_t     phase;
 
422
 
 
423
#ifdef LDAP_SYNC_TRACE
 
424
        fprintf( stderr, "\tgot LDAP_RES_INTERMEDIATE\n" );
 
425
#endif /* LDAP_SYNC_TRACE */
 
426
 
 
427
        assert( ls != NULL );
 
428
        assert( res != NULL );
 
429
        assert( refreshDone != NULL );
 
430
 
 
431
        *refreshDone = 0;
 
432
 
 
433
        rc = ldap_parse_intermediate( ls->ls_ld, res,
 
434
                &retoid, &retdata, NULL, 0 );
 
435
#ifdef LDAP_SYNC_TRACE
 
436
        fprintf( stderr, "\t%sldap_parse_intermediate(%s) == %d\n",
 
437
                rc != LDAP_SUCCESS ? "!!! " : "",
 
438
                retoid == NULL ? "\"\"" : retoid,
 
439
                rc );
 
440
#endif /* LDAP_SYNC_TRACE */
 
441
        /* parsing must be successful, and yield the OID
 
442
         * of the sync info intermediate response */
 
443
        if ( rc != LDAP_SUCCESS ) {
 
444
                goto done;
 
445
        }
 
446
 
 
447
        if ( retoid == NULL || strcmp( retoid, LDAP_SYNC_INFO ) != 0 ) {
 
448
                rc = LDAP_OTHER;
 
449
                goto done;
 
450
        }
 
451
 
 
452
        /* init ber using the value in the response */
 
453
        ber = ber_init( retdata );
 
454
        if ( ber == NULL ) {
 
455
                goto done;
 
456
        }
 
457
 
 
458
        syncinfo_tag = ber_peek_tag( ber, &len );
 
459
        switch ( syncinfo_tag ) {
 
460
        case LDAP_TAG_SYNC_NEW_COOKIE:
 
461
                ber_scanf( ber, "tm", &tag, &cookie );
 
462
                if ( cookie.bv_val != NULL ) {
 
463
                        ber_bvreplace( &ls->ls_cookie, &cookie );
 
464
                }
 
465
#ifdef LDAP_SYNC_TRACE
 
466
                fprintf( stderr, "\t\tgot cookie=%s\n",
 
467
                        cookie.bv_val ? cookie.bv_val : "(null)" );
 
468
#endif /* LDAP_SYNC_TRACE */
 
469
                break;
 
470
 
 
471
        case LDAP_TAG_SYNC_REFRESH_DELETE:
 
472
        case LDAP_TAG_SYNC_REFRESH_PRESENT:
 
473
                if ( syncinfo_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
 
474
#ifdef LDAP_SYNC_TRACE
 
475
                        fprintf( stderr, "\t\tgot refreshDelete\n" );
 
476
#endif /* LDAP_SYNC_TRACE */
 
477
                        switch ( ls->ls_refreshPhase ) {
 
478
                        case LDAP_SYNC_CAPI_NONE:
 
479
                        case LDAP_SYNC_CAPI_PRESENTS:
 
480
                                ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
 
481
                                break;
 
482
 
 
483
                        default:
 
484
                                /* TODO: impossible; handle */
 
485
                                rc = LDAP_OTHER;
 
486
                                goto done;
 
487
                        }
 
488
 
 
489
                } else {
 
490
#ifdef LDAP_SYNC_TRACE
 
491
                        fprintf( stderr, "\t\tgot refreshPresent\n" );
 
492
#endif /* LDAP_SYNC_TRACE */
 
493
                        switch ( ls->ls_refreshPhase ) {
 
494
                        case LDAP_SYNC_CAPI_NONE:
 
495
                                ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
 
496
                                break;
 
497
 
 
498
                        default:
 
499
                                /* TODO: impossible; handle */
 
500
                                rc = LDAP_OTHER;
 
501
                                goto done;
 
502
                        }
 
503
                }
 
504
 
 
505
                ber_scanf( ber, "t{" /*"}"*/, &tag );
 
506
                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
 
507
                        ber_scanf( ber, "m", &cookie );
 
508
                        if ( cookie.bv_val != NULL ) {
 
509
                                ber_bvreplace( &ls->ls_cookie, &cookie );
 
510
                        }
 
511
#ifdef LDAP_SYNC_TRACE
 
512
                        fprintf( stderr, "\t\tgot cookie=%s\n",
 
513
                                cookie.bv_val ? cookie.bv_val : "(null)" );
 
514
#endif /* LDAP_SYNC_TRACE */
 
515
                }
 
516
 
 
517
                *refreshDone = 1;
 
518
                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDONE ) {
 
519
                        ber_scanf( ber, "b", refreshDone );
 
520
                }
 
521
 
 
522
#ifdef LDAP_SYNC_TRACE
 
523
                fprintf( stderr, "\t\tgot refreshDone=%s\n",
 
524
                        *refreshDone ? "TRUE" : "FALSE" );
 
525
#endif /* LDAP_SYNC_TRACE */
 
526
 
 
527
                ber_scanf( ber, /*"{"*/ "}" );
 
528
 
 
529
                if ( *refreshDone ) {
 
530
                        ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
 
531
                }
 
532
 
 
533
                if ( ls->ls_intermediate ) {
 
534
                        ls->ls_intermediate( ls, res, NULL, ls->ls_refreshPhase );
 
535
                }
 
536
 
 
537
                break;
 
538
 
 
539
        case LDAP_TAG_SYNC_ID_SET:
 
540
#ifdef LDAP_SYNC_TRACE
 
541
                fprintf( stderr, "\t\tgot syncIdSet\n" );
 
542
#endif /* LDAP_SYNC_TRACE */
 
543
                ber_scanf( ber, "t{" /*"}"*/, &tag );
 
544
                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
 
545
                        ber_scanf( ber, "m", &cookie );
 
546
                        if ( cookie.bv_val != NULL ) {
 
547
                                ber_bvreplace( &ls->ls_cookie, &cookie );
 
548
                        }
 
549
#ifdef LDAP_SYNC_TRACE
 
550
                        fprintf( stderr, "\t\tgot cookie=%s\n",
 
551
                                cookie.bv_val ? cookie.bv_val : "(null)" );
 
552
#endif /* LDAP_SYNC_TRACE */
 
553
                }
 
554
 
 
555
                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
 
556
                        ber_scanf( ber, "b", &refreshDeletes );
 
557
                }
 
558
 
 
559
                ber_scanf( ber, "[W]", &syncUUIDs );
 
560
                ber_scanf( ber, /*"{"*/ "}" );
 
561
                if ( syncUUIDs == NULL ) {
 
562
                        rc = LDAP_OTHER;
 
563
                        goto done;
 
564
                }
 
565
 
 
566
#ifdef LDAP_SYNC_TRACE
 
567
                {
 
568
                        int     i;
 
569
 
 
570
                        fprintf( stderr, "\t\tgot refreshDeletes=%s\n",
 
571
                                refreshDeletes ? "TRUE" : "FALSE" );
 
572
                        for ( i = 0; syncUUIDs[ i ].bv_val != NULL; i++ ) {
 
573
                                char    buf[ BUFSIZ ];
 
574
                                fprintf( stderr, "\t\t%s\n", 
 
575
                                        lutil_uuidstr_from_normalized(
 
576
                                                syncUUIDs[ i ].bv_val, syncUUIDs[ i ].bv_len,
 
577
                                                buf, sizeof( buf ) ) );
 
578
                        }
 
579
                }
 
580
#endif /* LDAP_SYNC_TRACE */
 
581
 
 
582
                if ( refreshDeletes ) {
 
583
                        phase = LDAP_SYNC_CAPI_DELETES_IDSET;
 
584
 
 
585
                } else {
 
586
                        phase = LDAP_SYNC_CAPI_PRESENTS_IDSET;
 
587
                }
 
588
 
 
589
                /* FIXME: should touch ls->ls_refreshPhase? */
 
590
                if ( ls->ls_intermediate ) {
 
591
                        ls->ls_intermediate( ls, res, syncUUIDs, phase );
 
592
                }
 
593
 
 
594
                ber_bvarray_free( syncUUIDs );
 
595
                break;
 
596
 
 
597
        default:
 
598
#ifdef LDAP_SYNC_TRACE
 
599
                fprintf( stderr, "\t\tunknown tag!\n" );
 
600
#endif /* LDAP_SYNC_TRACE */
 
601
                goto done;
 
602
        }
 
603
 
 
604
done:;
 
605
        if ( ber != NULL ) {
 
606
                ber_free( ber, 1 );
 
607
        }
 
608
 
 
609
        if ( retoid != NULL ) {
 
610
                ldap_memfree( retoid );
 
611
        }
 
612
 
 
613
        if ( retdata != NULL ) {
 
614
                ber_bvfree( retdata );
 
615
        }
 
616
 
 
617
        return rc;
 
618
}
 
619
 
 
620
/*
 
621
 * initialize the sync
 
622
 */
 
623
int
 
624
ldap_sync_init( ldap_sync_t *ls, int mode )
 
625
{
 
626
        LDAPControl     ctrl = { 0 },
 
627
                        *ctrls[ 2 ];
 
628
        BerElement      *ber = NULL;
 
629
        int             rc;
 
630
        struct timeval  tv = { 0 },
 
631
                        *tvp = NULL;
 
632
        LDAPMessage     *res = NULL;
 
633
 
 
634
#ifdef LDAP_SYNC_TRACE
 
635
        fprintf( stderr, "ldap_sync_init(%s)...\n",
 
636
                mode == LDAP_SYNC_REFRESH_AND_PERSIST ?
 
637
                        "LDAP_SYNC_REFRESH_AND_PERSIST" :
 
638
                        ( mode == LDAP_SYNC_REFRESH_ONLY ? 
 
639
                                "LDAP_SYNC_REFRESH_ONLY" : "unknown" ) );
 
640
#endif /* LDAP_SYNC_TRACE */
 
641
 
 
642
        assert( ls != NULL );
 
643
        assert( ls->ls_ld != NULL );
 
644
 
 
645
        /* support both refreshOnly and refreshAndPersist */
 
646
        switch ( mode ) {
 
647
        case LDAP_SYNC_REFRESH_AND_PERSIST:
 
648
        case LDAP_SYNC_REFRESH_ONLY:
 
649
                break;
 
650
 
 
651
        default:
 
652
                fprintf( stderr, "ldap_sync_init: unknown mode=%d\n", mode );
 
653
                return LDAP_PARAM_ERROR;
 
654
        }
 
655
 
 
656
        /* check consistency of cookie and reloadHint at initial refresh */
 
657
        if ( ls->ls_cookie.bv_val == NULL && ls->ls_reloadHint != 0 ) {
 
658
                fprintf( stderr, "ldap_sync_init: inconsistent cookie/rhint\n" );
 
659
                return LDAP_PARAM_ERROR;
 
660
        }
 
661
 
 
662
        ctrls[ 0 ] = &ctrl;
 
663
        ctrls[ 1 ] = NULL;
 
664
 
 
665
        /* prepare the Sync Request control */
 
666
        ber = ber_alloc_t( LBER_USE_DER );
 
667
#ifdef LDAP_SYNC_TRACE
 
668
        fprintf( stderr, "%sber_alloc_t() %s= NULL\n",
 
669
                ber == NULL ? "!!! " : "",
 
670
                ber == NULL ? "=" : "!" );
 
671
#endif /* LDAP_SYNC_TRACE */
 
672
        if ( ber == NULL ) {
 
673
                rc = LDAP_NO_MEMORY;
 
674
                goto done;
 
675
        }
 
676
 
 
677
        ls->ls_refreshPhase = LDAP_SYNC_CAPI_NONE;
 
678
 
 
679
        if ( ls->ls_cookie.bv_val != NULL ) {
 
680
                ber_printf( ber, "{eOb}", mode,
 
681
                        &ls->ls_cookie, ls->ls_reloadHint );
 
682
 
 
683
        } else {
 
684
                ber_printf( ber, "{eb}", mode, ls->ls_reloadHint );
 
685
        }
 
686
 
 
687
        rc = ber_flatten2( ber, &ctrl.ldctl_value, 0 );
 
688
#ifdef LDAP_SYNC_TRACE
 
689
        fprintf( stderr,
 
690
                "%sber_flatten2() == %d\n",
 
691
                rc ? "!!! " : "",
 
692
                rc );
 
693
#endif /* LDAP_SYNC_TRACE */
 
694
        if ( rc == LBER_ERROR ) {
 
695
                rc = LDAP_OTHER;
 
696
                goto done;
 
697
        }
 
698
 
 
699
        /* make the control critical, as we cannot proceed without */
 
700
        ctrl.ldctl_oid = LDAP_CONTROL_SYNC;
 
701
        ctrl.ldctl_iscritical = 1;
 
702
 
 
703
        /* timelimit? */
 
704
        if ( ls->ls_timelimit ) {
 
705
                tv.tv_sec = ls->ls_timelimit;
 
706
                tvp = &tv;
 
707
        }
 
708
 
 
709
        /* actually run the search */
 
710
        rc = ldap_search_ext( ls->ls_ld,
 
711
                ls->ls_base, ls->ls_scope, ls->ls_filter,
 
712
                ls->ls_attrs, 0, ctrls, NULL,
 
713
                tvp, ls->ls_sizelimit, &ls->ls_msgid );
 
714
#ifdef LDAP_SYNC_TRACE
 
715
        fprintf( stderr,
 
716
                "%sldap_search_ext(\"%s\", %d, \"%s\") == %d\n",
 
717
                rc ? "!!! " : "",
 
718
                ls->ls_base, ls->ls_scope, ls->ls_filter, rc );
 
719
#endif /* LDAP_SYNC_TRACE */
 
720
        if ( rc != LDAP_SUCCESS ) {
 
721
                goto done;
 
722
        }
 
723
 
 
724
        /* initial content/content update phase */
 
725
        for ( ; ; ) {
 
726
                LDAPMessage     *msg = NULL;
 
727
 
 
728
                /* NOTE: this very short timeout is just to let
 
729
                 * ldap_result() yield long enough to get something */
 
730
                tv.tv_sec = 0;
 
731
                tv.tv_usec = 100000;
 
732
 
 
733
                rc = ldap_result( ls->ls_ld, ls->ls_msgid,
 
734
                        LDAP_MSG_RECEIVED, &tv, &res );
 
735
#ifdef LDAP_SYNC_TRACE
 
736
                fprintf( stderr,
 
737
                        "\t%sldap_result(%d) == %d\n",
 
738
                        rc == -1 ? "!!! " : "",
 
739
                        ls->ls_msgid, rc );
 
740
#endif /* LDAP_SYNC_TRACE */
 
741
                switch ( rc ) {
 
742
                case 0:
 
743
                        /*
 
744
                         * timeout
 
745
                         *
 
746
                         * TODO: can do something else in the meanwhile)
 
747
                         */
 
748
                        break;
 
749
 
 
750
                case -1:
 
751
                        /* smtg bad! */
 
752
                        goto done;
 
753
 
 
754
                default:
 
755
                        for ( msg = ldap_first_message( ls->ls_ld, res );
 
756
                                msg != NULL;
 
757
                                msg = ldap_next_message( ls->ls_ld, msg ) )
 
758
                        {
 
759
                                int     refreshDone;
 
760
 
 
761
                                switch ( ldap_msgtype( msg ) ) {
 
762
                                case LDAP_RES_SEARCH_ENTRY:
 
763
                                        rc = ldap_sync_search_entry( ls, res );
 
764
                                        break;
 
765
 
 
766
                                case LDAP_RES_SEARCH_REFERENCE:
 
767
                                        rc = ldap_sync_search_reference( ls, res );
 
768
                                        break;
 
769
 
 
770
                                case LDAP_RES_SEARCH_RESULT:
 
771
                                        rc = ldap_sync_search_result( ls, res );
 
772
                                        goto done_search;
 
773
 
 
774
                                case LDAP_RES_INTERMEDIATE:
 
775
                                        rc = ldap_sync_search_intermediate( ls, res, &refreshDone );
 
776
                                        if ( rc != LDAP_SUCCESS || refreshDone ) {
 
777
                                                goto done_search;
 
778
                                        }
 
779
                                        break;
 
780
 
 
781
                                default:
 
782
#ifdef LDAP_SYNC_TRACE
 
783
                                        fprintf( stderr, "\tgot something unexpected...\n" );
 
784
#endif /* LDAP_SYNC_TRACE */
 
785
 
 
786
                                        ldap_msgfree( res );
 
787
 
 
788
                                        rc = LDAP_OTHER;
 
789
                                        goto done;
 
790
                                }
 
791
                        }
 
792
                        ldap_msgfree( res );
 
793
                        res = NULL;
 
794
                        break;
 
795
                }
 
796
        }
 
797
 
 
798
done_search:;
 
799
        ldap_msgfree( res );
 
800
 
 
801
done:;
 
802
        if ( ber != NULL ) {
 
803
                ber_free( ber, 1 );
 
804
        }
 
805
 
 
806
        return rc;
 
807
}
 
808
 
 
809
/*
 
810
 * initialize the refreshOnly sync
 
811
 */
 
812
int
 
813
ldap_sync_init_refresh_only( ldap_sync_t *ls )
 
814
{
 
815
        return ldap_sync_init( ls, LDAP_SYNC_REFRESH_ONLY );
 
816
}
 
817
 
 
818
/*
 
819
 * initialize the refreshAndPersist sync
 
820
 */
 
821
int
 
822
ldap_sync_init_refresh_and_persist( ldap_sync_t *ls )
 
823
{
 
824
        return ldap_sync_init( ls, LDAP_SYNC_REFRESH_AND_PERSIST );
 
825
}
 
826
 
 
827
/*
 
828
 * poll for new responses
 
829
 */
 
830
int
 
831
ldap_sync_poll( ldap_sync_t *ls )
 
832
{
 
833
        struct  timeval         tv,
 
834
                                *tvp = NULL;
 
835
        LDAPMessage             *res = NULL,
 
836
                                *msg;
 
837
        int                     rc = 0;
 
838
 
 
839
#ifdef LDAP_SYNC_TRACE
 
840
        fprintf( stderr, "ldap_sync_poll...\n" );
 
841
#endif /* LDAP_SYNC_TRACE */
 
842
 
 
843
        assert( ls != NULL );
 
844
        assert( ls->ls_ld != NULL );
 
845
 
 
846
        if ( ls->ls_timeout != -1 ) {
 
847
                tv.tv_sec = ls->ls_timeout;
 
848
                tv.tv_usec = 0;
 
849
                tvp = &tv;
 
850
        }
 
851
 
 
852
        rc = ldap_result( ls->ls_ld, ls->ls_msgid,
 
853
                LDAP_MSG_RECEIVED, tvp, &res );
 
854
        if ( rc <= 0 ) {
 
855
                return rc;
 
856
        }
 
857
 
 
858
        for ( msg = ldap_first_message( ls->ls_ld, res );
 
859
                msg;
 
860
                msg = ldap_next_message( ls->ls_ld, msg ) )
 
861
        {
 
862
                int     refreshDone;
 
863
 
 
864
                switch ( ldap_msgtype( msg ) ) {
 
865
                case LDAP_RES_SEARCH_ENTRY:
 
866
                        rc = ldap_sync_search_entry( ls, res );
 
867
                        break;
 
868
 
 
869
                case LDAP_RES_SEARCH_REFERENCE:
 
870
                        rc = ldap_sync_search_reference( ls, res );
 
871
                        break;
 
872
 
 
873
                case LDAP_RES_SEARCH_RESULT:
 
874
                        rc = ldap_sync_search_result( ls, res );
 
875
                        goto done_search;
 
876
 
 
877
                case LDAP_RES_INTERMEDIATE:
 
878
                        rc = ldap_sync_search_intermediate( ls, res, &refreshDone );
 
879
                        if ( rc != LDAP_SUCCESS || refreshDone ) {
 
880
                                goto done_search;
 
881
                        }
 
882
                        break;
 
883
 
 
884
                default:
 
885
#ifdef LDAP_SYNC_TRACE
 
886
                        fprintf( stderr, "\tgot something unexpected...\n" );
 
887
#endif /* LDAP_SYNC_TRACE */
 
888
 
 
889
                        ldap_msgfree( res );
 
890
 
 
891
                        rc = LDAP_OTHER;
 
892
                        goto done;
 
893
                }
 
894
        }
 
895
 
 
896
done_search:;
 
897
        ldap_msgfree( res );
 
898
 
 
899
done:;
 
900
        return rc;
 
901
}
 
902