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