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