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