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