]> git.sur5r.net Git - openldap/blob - libraries/libldap/ldap_sync.c
Warnings cleanup
[openldap] / libraries / libldap / ldap_sync.c
1 /* $OpenLDAP$ */
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 < 0 ) {
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