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