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 37static const char * 38ldap_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 */ 62ldap_sync_t * 63ldap_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 */ 84void 85ldap_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 */ 130static int 131ldap_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 233done:; 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 */ 249static int 250ldap_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 */ 271static int 272ldap_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 404done:; 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 */ 425static int 426ldap_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 636done:; 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 */ 655int 656ldap_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 830done_search:; 831 ldap_msgfree( res ); 832 833done:; 834 if ( ber != NULL ) { 835 ber_free( ber, 1 ); 836 } 837 838 return rc; 839} 840 841/* 842 * initialize the refreshOnly sync 843 */ 844int 845ldap_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 */ 853int 854ldap_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 */ 862int 863ldap_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 928done_search:; 929 ldap_msgfree( res ); 930 931done:; 932 return rc; 933} 934