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