Back to index

openldap  2.4.31
ldap_sync.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 2006-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* ACKNOWLEDGEMENTS:
00016  * This program was originally developed by Pierangelo Masarati
00017  * for inclusion in OpenLDAP Software.
00018  */
00019 
00020 /*
00021  * Proof-of-concept API that implement the client-side
00022  * of the "LDAP Content Sync Operation" (RFC 4533)
00023  */
00024 
00025 #include "portable.h"
00026 
00027 #include <ac/time.h>
00028 
00029 #include "ldap-int.h"
00030 
00031 #ifdef LDAP_SYNC_TRACE
00032 static const char *
00033 ldap_sync_state2str( int state )
00034 {
00035        switch ( state ) {
00036        case LDAP_SYNC_PRESENT:
00037               return "LDAP_SYNC_PRESENT";
00038 
00039        case LDAP_SYNC_ADD:
00040               return "LDAP_SYNC_ADD";
00041 
00042        case LDAP_SYNC_MODIFY:
00043               return "LDAP_SYNC_MODIFY";
00044 
00045        case LDAP_SYNC_DELETE:
00046               return "LDAP_SYNC_DELETE";
00047 
00048        default:
00049               return "(unknown)";
00050        }
00051 }
00052 #endif
00053 
00054 /*
00055  * initialize the persistent search structure
00056  */
00057 ldap_sync_t *
00058 ldap_sync_initialize( ldap_sync_t *ls_in )
00059 {
00060        ldap_sync_t   *ls = ls_in;
00061 
00062        if ( ls == NULL ) {
00063               ls = ldap_memalloc( sizeof( ldap_sync_t ) );
00064               if ( ls == NULL ) {
00065                      return NULL;
00066               }
00067 
00068        } else {
00069               memset( ls, 0, sizeof( ldap_sync_t ) );
00070        }
00071 
00072        ls->ls_scope = LDAP_SCOPE_SUBTREE;
00073        ls->ls_timeout = -1;
00074 
00075        return ls;
00076 }
00077 
00078 /*
00079  * destroy the persistent search structure
00080  */
00081 void
00082 ldap_sync_destroy( ldap_sync_t *ls, int freeit )
00083 {
00084        assert( ls != NULL );
00085 
00086        if ( ls->ls_base != NULL ) {
00087               ldap_memfree( ls->ls_base );
00088               ls->ls_base = NULL;
00089        }
00090 
00091        if ( ls->ls_filter != NULL ) {
00092               ldap_memfree( ls->ls_filter );
00093               ls->ls_filter = NULL;
00094        }
00095 
00096        if ( ls->ls_attrs != NULL ) {
00097               int    i;
00098 
00099               for ( i = 0; ls->ls_attrs[ i ] != NULL; i++ ) {
00100                      ldap_memfree( ls->ls_attrs[ i ] );
00101               }
00102               ldap_memfree( ls->ls_attrs );
00103               ls->ls_attrs = NULL;
00104        }
00105 
00106        if ( ls->ls_ld != NULL ) {
00107               (void)ldap_unbind_ext( ls->ls_ld, NULL, NULL );
00108 #ifdef LDAP_SYNC_TRACE
00109               fprintf( stderr, "ldap_unbind_ext()\n" );
00110 #endif /* LDAP_SYNC_TRACE */
00111               ls->ls_ld = NULL;
00112        }
00113 
00114        if ( ls->ls_cookie.bv_val != NULL ) {
00115               ldap_memfree( ls->ls_cookie.bv_val );
00116               ls->ls_cookie.bv_val = NULL;
00117        }
00118 
00119        if ( freeit ) {
00120               ldap_memfree( ls );
00121        }
00122 }
00123 
00124 /*
00125  * handle the LDAP_RES_SEARCH_ENTRY response
00126  */
00127 static int
00128 ldap_sync_search_entry( ldap_sync_t *ls, LDAPMessage *res )
00129 {
00130        LDAPControl          **ctrls = NULL;
00131        int                  rc = LDAP_OTHER,
00132                             i;
00133        BerElement           *ber = NULL;
00134        struct berval        entryUUID = { 0 },
00135                             cookie = { 0 };
00136        int                  state = -1;
00137        ber_len_t            len;
00138        ldap_sync_refresh_t  phase;
00139 
00140 #ifdef LDAP_SYNC_TRACE
00141        fprintf( stderr, "\tgot LDAP_RES_SEARCH_ENTRY\n" );
00142 #endif /* LDAP_SYNC_TRACE */
00143 
00144        assert( ls != NULL );
00145        assert( res != NULL );
00146 
00147        phase = ls->ls_refreshPhase;
00148 
00149        /* OK */
00150 
00151        /* extract:
00152         * - data
00153         * - entryUUID
00154         *
00155         * check that:
00156         * - Sync State Control is "add"
00157         */
00158 
00159        /* the control MUST be present */
00160 
00161        /* extract controls */
00162        ldap_get_entry_controls( ls->ls_ld, res, &ctrls );
00163        if ( ctrls == NULL ) {
00164               goto done;
00165        }
00166 
00167        /* lookup the sync state control */
00168        for ( i = 0; ctrls[ i ] != NULL; i++ ) {
00169               if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_STATE ) == 0 ) {
00170                      break;
00171               }
00172        }
00173 
00174        /* control must be present; there might be other... */
00175        if ( ctrls[ i ] == NULL ) {
00176               goto done;
00177        }
00178 
00179        /* extract data */
00180        ber = ber_init( &ctrls[ i ]->ldctl_value );
00181        if ( ber == NULL ) {
00182               goto done;
00183        }
00184        /* scan entryUUID in-place ("m") */
00185        if ( ber_scanf( ber, "{em" /*"}"*/, &state, &entryUUID ) == LBER_ERROR
00186               || entryUUID.bv_len == 0 )
00187        {
00188               goto done;
00189        }
00190 
00191        if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
00192               /* scan cookie in-place ("m") */
00193               if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) == LBER_ERROR ) {
00194                      goto done;
00195               }
00196               if ( cookie.bv_val != NULL ) {
00197                      ber_bvreplace( &ls->ls_cookie, &cookie );
00198               }
00199 #ifdef LDAP_SYNC_TRACE
00200               fprintf( stderr, "\t\tgot cookie=%s\n",
00201                      cookie.bv_val ? cookie.bv_val : "(null)" );
00202 #endif /* LDAP_SYNC_TRACE */
00203        }
00204 
00205        switch ( state ) {
00206        case LDAP_SYNC_PRESENT:
00207        case LDAP_SYNC_DELETE:
00208        case LDAP_SYNC_ADD:
00209        case LDAP_SYNC_MODIFY:
00210               /* NOTE: ldap_sync_refresh_t is defined
00211                * as the corresponding LDAP_SYNC_*
00212                * for the 4 above cases */
00213               phase = state;
00214 #ifdef LDAP_SYNC_TRACE
00215               fprintf( stderr, "\t\tgot syncState=%s\n", ldap_sync_state2str( state ) );
00216 #endif /* LDAP_SYNC_TRACE */
00217               break;
00218 
00219        default:
00220 #ifdef LDAP_SYNC_TRACE
00221               fprintf( stderr, "\t\tgot unknown syncState=%d\n", state );
00222 #endif /* LDAP_SYNC_TRACE */
00223               goto done;
00224        }
00225 
00226        rc = ls->ls_search_entry
00227               ? ls->ls_search_entry( ls, res, &entryUUID, phase )
00228               : LDAP_SUCCESS;
00229 
00230 done:;
00231        if ( ber != NULL ) {
00232               ber_free( ber, 1 );
00233        }
00234 
00235        if ( ctrls != NULL ) {
00236               ldap_controls_free( ctrls );
00237        }
00238 
00239        return rc;
00240 }
00241 
00242 /*
00243  * handle the LDAP_RES_SEARCH_REFERENCE response
00244  * (to be implemented yet)
00245  */
00246 static int
00247 ldap_sync_search_reference( ldap_sync_t *ls, LDAPMessage *res )
00248 {
00249        int           rc = 0;
00250 
00251 #ifdef LDAP_SYNC_TRACE
00252        fprintf( stderr, "\tgot LDAP_RES_SEARCH_REFERENCE\n" );
00253 #endif /* LDAP_SYNC_TRACE */
00254 
00255        assert( ls != NULL );
00256        assert( res != NULL );
00257 
00258        if ( ls->ls_search_reference ) {
00259               rc = ls->ls_search_reference( ls, res );
00260        }
00261 
00262        return rc;
00263 }
00264 
00265 /*
00266  * handle the LDAP_RES_SEARCH_RESULT response
00267  */
00268 static int
00269 ldap_sync_search_result( ldap_sync_t *ls, LDAPMessage *res )
00270 {
00271        int           err;
00272        char          *matched = NULL,
00273                      *msg = NULL;
00274        LDAPControl   **ctrls = NULL;
00275        int           rc;
00276        int           refreshDeletes = -1;
00277 
00278 #ifdef LDAP_SYNC_TRACE
00279        fprintf( stderr, "\tgot LDAP_RES_SEARCH_RESULT\n" );
00280 #endif /* LDAP_SYNC_TRACE */
00281 
00282        assert( ls != NULL );
00283        assert( res != NULL );
00284 
00285        /* should not happen in refreshAndPersist... */
00286        rc = ldap_parse_result( ls->ls_ld,
00287               res, &err, &matched, &msg, NULL, &ctrls, 0 );
00288 #ifdef LDAP_SYNC_TRACE
00289        fprintf( stderr,
00290               "\tldap_parse_result(%d, \"%s\", \"%s\") == %d\n",
00291               err,
00292               matched ? matched : "",
00293               msg ? msg : "",
00294               rc );
00295 #endif /* LDAP_SYNC_TRACE */
00296        if ( rc == LDAP_SUCCESS ) {
00297               rc = err;
00298        }
00299 
00300        ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
00301 
00302        switch ( rc ) {
00303        case LDAP_SUCCESS: {
00304               int           i;
00305               BerElement    *ber = NULL;
00306               ber_len_t     len;
00307               struct berval cookie = { 0 };
00308 
00309               rc = LDAP_OTHER;
00310 
00311               /* deal with control; then fallthru to handler */
00312               if ( ctrls == NULL ) {
00313                      goto done;
00314               }
00315 
00316               /* lookup the sync state control */
00317               for ( i = 0; ctrls[ i ] != NULL; i++ ) {
00318                      if ( strcmp( ctrls[ i ]->ldctl_oid,
00319                             LDAP_CONTROL_SYNC_DONE ) == 0 )
00320                      {
00321                             break;
00322                      }
00323               }
00324 
00325               /* control must be present; there might be other... */
00326               if ( ctrls[ i ] == NULL ) {
00327                      goto done;
00328               }
00329 
00330               /* extract data */
00331               ber = ber_init( &ctrls[ i ]->ldctl_value );
00332               if ( ber == NULL ) {
00333                      goto done;
00334               }
00335 
00336               if ( ber_scanf( ber, "{" /*"}"*/) == LBER_ERROR ) {
00337                      goto ber_done;
00338               }
00339               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
00340                      if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
00341                             goto ber_done;
00342                      }
00343                      if ( cookie.bv_val != NULL ) {
00344                             ber_bvreplace( &ls->ls_cookie, &cookie );
00345                      }
00346 #ifdef LDAP_SYNC_TRACE
00347                      fprintf( stderr, "\t\tgot cookie=%s\n",
00348                             cookie.bv_val ? cookie.bv_val : "(null)" );
00349 #endif /* LDAP_SYNC_TRACE */
00350               }
00351 
00352               refreshDeletes = 0;
00353               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
00354                      if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) {
00355                             goto ber_done;
00356                      }
00357                      if ( refreshDeletes ) {
00358                             refreshDeletes = 1;
00359                      }
00360               }
00361 
00362               if ( ber_scanf( ber, /*"{"*/ "}" ) != LBER_ERROR ) {
00363                      rc = LDAP_SUCCESS;
00364               }
00365 
00366        ber_done:;
00367               ber_free( ber, 1 );
00368               if ( rc != LDAP_SUCCESS ) {
00369                      break;
00370               }
00371 
00372 #ifdef LDAP_SYNC_TRACE
00373               fprintf( stderr, "\t\tgot refreshDeletes=%s\n",
00374                      refreshDeletes ? "TRUE" : "FALSE" );
00375 #endif /* LDAP_SYNC_TRACE */
00376 
00377               /* FIXME: what should we do with the refreshDelete? */
00378               switch ( refreshDeletes ) {
00379               case 0:
00380                      ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
00381                      break;
00382 
00383               default:
00384                      ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
00385                      break;
00386               }
00387 
00388               } /* fallthru */
00389 
00390        case LDAP_SYNC_REFRESH_REQUIRED:
00391               /* TODO: check for Sync Done Control */
00392               /* FIXME: perhaps the handler should be called
00393                * also in case of failure; we'll deal with this 
00394                * later when implementing refreshOnly */
00395               if ( ls->ls_search_result ) {
00396                      err = ls->ls_search_result( ls, res, refreshDeletes );
00397               }
00398               break;
00399        }
00400 
00401 done:;
00402        if ( matched != NULL ) {
00403               ldap_memfree( matched );
00404        }
00405 
00406        if ( msg != NULL ) {
00407               ldap_memfree( msg );
00408        }
00409 
00410        if ( ctrls != NULL ) {
00411               ldap_controls_free( ctrls );
00412        }
00413 
00414        ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
00415 
00416        return rc;
00417 }
00418 
00419 /*
00420  * handle the LDAP_RES_INTERMEDIATE response
00421  */
00422 static int
00423 ldap_sync_search_intermediate( ldap_sync_t *ls, LDAPMessage *res, int *refreshDone )
00424 {
00425        int                  rc;
00426        char                 *retoid = NULL;
00427         struct berval              *retdata = NULL;
00428        BerElement           *ber = NULL;
00429        ber_len_t            len;
00430        ber_tag_t            syncinfo_tag;
00431        struct berval        cookie;
00432        int                  refreshDeletes = 0;
00433        BerVarray            syncUUIDs = NULL;
00434        ldap_sync_refresh_t  phase;
00435 
00436 #ifdef LDAP_SYNC_TRACE
00437        fprintf( stderr, "\tgot LDAP_RES_INTERMEDIATE\n" );
00438 #endif /* LDAP_SYNC_TRACE */
00439 
00440        assert( ls != NULL );
00441        assert( res != NULL );
00442        assert( refreshDone != NULL );
00443 
00444        *refreshDone = 0;
00445 
00446        rc = ldap_parse_intermediate( ls->ls_ld, res,
00447               &retoid, &retdata, NULL, 0 );
00448 #ifdef LDAP_SYNC_TRACE
00449        fprintf( stderr, "\t%sldap_parse_intermediate(%s) == %d\n",
00450               rc != LDAP_SUCCESS ? "!!! " : "",
00451               retoid == NULL ? "\"\"" : retoid,
00452               rc );
00453 #endif /* LDAP_SYNC_TRACE */
00454        /* parsing must be successful, and yield the OID
00455         * of the sync info intermediate response */
00456        if ( rc != LDAP_SUCCESS ) {
00457               goto done;
00458        }
00459 
00460        rc = LDAP_OTHER;
00461 
00462        if ( retoid == NULL || strcmp( retoid, LDAP_SYNC_INFO ) != 0 ) {
00463               goto done;
00464        }
00465 
00466        /* init ber using the value in the response */
00467        ber = ber_init( retdata );
00468        if ( ber == NULL ) {
00469               goto done;
00470        }
00471 
00472        syncinfo_tag = ber_peek_tag( ber, &len );
00473        switch ( syncinfo_tag ) {
00474        case LDAP_TAG_SYNC_NEW_COOKIE:
00475               if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
00476                      goto done;
00477               }
00478               if ( cookie.bv_val != NULL ) {
00479                      ber_bvreplace( &ls->ls_cookie, &cookie );
00480               }
00481 #ifdef LDAP_SYNC_TRACE
00482               fprintf( stderr, "\t\tgot cookie=%s\n",
00483                      cookie.bv_val ? cookie.bv_val : "(null)" );
00484 #endif /* LDAP_SYNC_TRACE */
00485               break;
00486 
00487        case LDAP_TAG_SYNC_REFRESH_DELETE:
00488        case LDAP_TAG_SYNC_REFRESH_PRESENT:
00489               if ( syncinfo_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
00490 #ifdef LDAP_SYNC_TRACE
00491                      fprintf( stderr, "\t\tgot refreshDelete\n" );
00492 #endif /* LDAP_SYNC_TRACE */
00493                      switch ( ls->ls_refreshPhase ) {
00494                      case LDAP_SYNC_CAPI_NONE:
00495                      case LDAP_SYNC_CAPI_PRESENTS:
00496                             ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
00497                             break;
00498 
00499                      default:
00500                             /* TODO: impossible; handle */
00501                             goto done;
00502                      }
00503 
00504               } else {
00505 #ifdef LDAP_SYNC_TRACE
00506                      fprintf( stderr, "\t\tgot refreshPresent\n" );
00507 #endif /* LDAP_SYNC_TRACE */
00508                      switch ( ls->ls_refreshPhase ) {
00509                      case LDAP_SYNC_CAPI_NONE:
00510                             ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
00511                             break;
00512 
00513                      default:
00514                             /* TODO: impossible; handle */
00515                             goto done;
00516                      }
00517               }
00518 
00519               if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) {
00520                      goto done;
00521               }
00522               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
00523                      if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
00524                             goto done;
00525                      }
00526                      if ( cookie.bv_val != NULL ) {
00527                             ber_bvreplace( &ls->ls_cookie, &cookie );
00528                      }
00529 #ifdef LDAP_SYNC_TRACE
00530                      fprintf( stderr, "\t\tgot cookie=%s\n",
00531                             cookie.bv_val ? cookie.bv_val : "(null)" );
00532 #endif /* LDAP_SYNC_TRACE */
00533               }
00534 
00535               *refreshDone = 1;
00536               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDONE ) {
00537                      if ( ber_scanf( ber, "b", refreshDone ) == LBER_ERROR ) {
00538                             goto done;
00539                      }
00540               }
00541 
00542 #ifdef LDAP_SYNC_TRACE
00543               fprintf( stderr, "\t\tgot refreshDone=%s\n",
00544                      *refreshDone ? "TRUE" : "FALSE" );
00545 #endif /* LDAP_SYNC_TRACE */
00546 
00547               if ( ber_scanf( ber, /*"{"*/ "}" ) == LBER_ERROR ) {
00548                      goto done;
00549               }
00550 
00551               if ( *refreshDone ) {
00552                      ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
00553               }
00554 
00555               if ( ls->ls_intermediate ) {
00556                      ls->ls_intermediate( ls, res, NULL, ls->ls_refreshPhase );
00557               }
00558 
00559               break;
00560 
00561        case LDAP_TAG_SYNC_ID_SET:
00562 #ifdef LDAP_SYNC_TRACE
00563               fprintf( stderr, "\t\tgot syncIdSet\n" );
00564 #endif /* LDAP_SYNC_TRACE */
00565               if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) {
00566                      goto done;
00567               }
00568               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
00569                      if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
00570                             goto done;
00571                      }
00572                      if ( cookie.bv_val != NULL ) {
00573                             ber_bvreplace( &ls->ls_cookie, &cookie );
00574                      }
00575 #ifdef LDAP_SYNC_TRACE
00576                      fprintf( stderr, "\t\tgot cookie=%s\n",
00577                             cookie.bv_val ? cookie.bv_val : "(null)" );
00578 #endif /* LDAP_SYNC_TRACE */
00579               }
00580 
00581               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
00582                      if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) {
00583                             goto done;
00584                      }
00585               }
00586 
00587               if ( ber_scanf( ber, /*"{"*/ "[W]}", &syncUUIDs ) == LBER_ERROR
00588                      || syncUUIDs == NULL )
00589               {
00590                      goto done;
00591               }
00592 
00593 #ifdef LDAP_SYNC_TRACE
00594               {
00595                      int    i;
00596 
00597                      fprintf( stderr, "\t\tgot refreshDeletes=%s\n",
00598                             refreshDeletes ? "TRUE" : "FALSE" );
00599                      for ( i = 0; syncUUIDs[ i ].bv_val != NULL; i++ ) {
00600                             char   buf[ BUFSIZ ];
00601                             fprintf( stderr, "\t\t%s\n", 
00602                                    lutil_uuidstr_from_normalized(
00603                                           syncUUIDs[ i ].bv_val, syncUUIDs[ i ].bv_len,
00604                                           buf, sizeof( buf ) ) );
00605                      }
00606               }
00607 #endif /* LDAP_SYNC_TRACE */
00608 
00609               if ( refreshDeletes ) {
00610                      phase = LDAP_SYNC_CAPI_DELETES_IDSET;
00611 
00612               } else {
00613                      phase = LDAP_SYNC_CAPI_PRESENTS_IDSET;
00614               }
00615 
00616               /* FIXME: should touch ls->ls_refreshPhase? */
00617               if ( ls->ls_intermediate ) {
00618                      ls->ls_intermediate( ls, res, syncUUIDs, phase );
00619               }
00620 
00621               ber_bvarray_free( syncUUIDs );
00622               break;
00623 
00624        default:
00625 #ifdef LDAP_SYNC_TRACE
00626               fprintf( stderr, "\t\tunknown tag!\n" );
00627 #endif /* LDAP_SYNC_TRACE */
00628               goto done;
00629        }
00630 
00631        rc = LDAP_SUCCESS;
00632 
00633 done:;
00634        if ( ber != NULL ) {
00635               ber_free( ber, 1 );
00636        }
00637 
00638        if ( retoid != NULL ) {
00639               ldap_memfree( retoid );
00640        }
00641 
00642        if ( retdata != NULL ) {
00643               ber_bvfree( retdata );
00644        }
00645 
00646        return rc;
00647 }
00648 
00649 /*
00650  * initialize the sync
00651  */
00652 int
00653 ldap_sync_init( ldap_sync_t *ls, int mode )
00654 {
00655        LDAPControl   ctrl = { 0 },
00656                      *ctrls[ 2 ];
00657        BerElement    *ber = NULL;
00658        int           rc;
00659        struct timeval       tv = { 0 },
00660                      *tvp = NULL;
00661        LDAPMessage   *res = NULL;
00662 
00663 #ifdef LDAP_SYNC_TRACE
00664        fprintf( stderr, "ldap_sync_init(%s)...\n",
00665               mode == LDAP_SYNC_REFRESH_AND_PERSIST ?
00666                      "LDAP_SYNC_REFRESH_AND_PERSIST" :
00667                      ( mode == LDAP_SYNC_REFRESH_ONLY ? 
00668                             "LDAP_SYNC_REFRESH_ONLY" : "unknown" ) );
00669 #endif /* LDAP_SYNC_TRACE */
00670 
00671        assert( ls != NULL );
00672        assert( ls->ls_ld != NULL );
00673 
00674        /* support both refreshOnly and refreshAndPersist */
00675        switch ( mode ) {
00676        case LDAP_SYNC_REFRESH_AND_PERSIST:
00677        case LDAP_SYNC_REFRESH_ONLY:
00678               break;
00679 
00680        default:
00681               fprintf( stderr, "ldap_sync_init: unknown mode=%d\n", mode );
00682               return LDAP_PARAM_ERROR;
00683        }
00684 
00685        /* check consistency of cookie and reloadHint at initial refresh */
00686        if ( ls->ls_cookie.bv_val == NULL && ls->ls_reloadHint != 0 ) {
00687               fprintf( stderr, "ldap_sync_init: inconsistent cookie/rhint\n" );
00688               return LDAP_PARAM_ERROR;
00689        }
00690 
00691        ctrls[ 0 ] = &ctrl;
00692        ctrls[ 1 ] = NULL;
00693 
00694        /* prepare the Sync Request control */
00695        ber = ber_alloc_t( LBER_USE_DER );
00696 #ifdef LDAP_SYNC_TRACE
00697        fprintf( stderr, "%sber_alloc_t() %s= NULL\n",
00698               ber == NULL ? "!!! " : "",
00699               ber == NULL ? "=" : "!" );
00700 #endif /* LDAP_SYNC_TRACE */
00701        if ( ber == NULL ) {
00702               rc = LDAP_NO_MEMORY;
00703               goto done;
00704        }
00705 
00706        ls->ls_refreshPhase = LDAP_SYNC_CAPI_NONE;
00707 
00708        if ( ls->ls_cookie.bv_val != NULL ) {
00709               ber_printf( ber, "{eOb}", mode,
00710                      &ls->ls_cookie, ls->ls_reloadHint );
00711 
00712        } else {
00713               ber_printf( ber, "{eb}", mode, ls->ls_reloadHint );
00714        }
00715 
00716        rc = ber_flatten2( ber, &ctrl.ldctl_value, 0 );
00717 #ifdef LDAP_SYNC_TRACE
00718        fprintf( stderr,
00719               "%sber_flatten2() == %d\n",
00720               rc ? "!!! " : "",
00721               rc );
00722 #endif /* LDAP_SYNC_TRACE */
00723        if ( rc < 0 ) {
00724               rc = LDAP_OTHER;
00725                 goto done;
00726         }
00727 
00728        /* make the control critical, as we cannot proceed without */
00729        ctrl.ldctl_oid = LDAP_CONTROL_SYNC;
00730        ctrl.ldctl_iscritical = 1;
00731 
00732        /* timelimit? */
00733        if ( ls->ls_timelimit ) {
00734               tv.tv_sec = ls->ls_timelimit;
00735               tvp = &tv;
00736        }
00737 
00738        /* actually run the search */
00739        rc = ldap_search_ext( ls->ls_ld,
00740               ls->ls_base, ls->ls_scope, ls->ls_filter,
00741               ls->ls_attrs, 0, ctrls, NULL,
00742               tvp, ls->ls_sizelimit, &ls->ls_msgid );
00743 #ifdef LDAP_SYNC_TRACE
00744        fprintf( stderr,
00745               "%sldap_search_ext(\"%s\", %d, \"%s\") == %d\n",
00746               rc ? "!!! " : "",
00747               ls->ls_base, ls->ls_scope, ls->ls_filter, rc );
00748 #endif /* LDAP_SYNC_TRACE */
00749        if ( rc != LDAP_SUCCESS ) {
00750               goto done;
00751        }
00752 
00753        /* initial content/content update phase */
00754        for ( ; ; ) {
00755               LDAPMessage   *msg = NULL;
00756 
00757               /* NOTE: this very short timeout is just to let
00758                * ldap_result() yield long enough to get something */
00759               tv.tv_sec = 0;
00760               tv.tv_usec = 100000;
00761 
00762               rc = ldap_result( ls->ls_ld, ls->ls_msgid,
00763                      LDAP_MSG_RECEIVED, &tv, &res );
00764 #ifdef LDAP_SYNC_TRACE
00765               fprintf( stderr,
00766                      "\t%sldap_result(%d) == %d\n",
00767                      rc == -1 ? "!!! " : "",
00768                      ls->ls_msgid, rc );
00769 #endif /* LDAP_SYNC_TRACE */
00770               switch ( rc ) {
00771               case 0:
00772                      /*
00773                       * timeout
00774                       *
00775                       * TODO: can do something else in the meanwhile)
00776                       */
00777                      break;
00778 
00779               case -1:
00780                      /* smtg bad! */
00781                      goto done;
00782 
00783               default:
00784                      for ( msg = ldap_first_message( ls->ls_ld, res );
00785                             msg != NULL;
00786                             msg = ldap_next_message( ls->ls_ld, msg ) )
00787                      {
00788                             int    refreshDone;
00789 
00790                             switch ( ldap_msgtype( msg ) ) {
00791                             case LDAP_RES_SEARCH_ENTRY:
00792                                    rc = ldap_sync_search_entry( ls, res );
00793                                    break;
00794 
00795                             case LDAP_RES_SEARCH_REFERENCE:
00796                                    rc = ldap_sync_search_reference( ls, res );
00797                                    break;
00798 
00799                             case LDAP_RES_SEARCH_RESULT:
00800                                    rc = ldap_sync_search_result( ls, res );
00801                                    goto done_search;
00802 
00803                             case LDAP_RES_INTERMEDIATE:
00804                                    rc = ldap_sync_search_intermediate( ls, res, &refreshDone );
00805                                    if ( rc != LDAP_SUCCESS || refreshDone ) {
00806                                           goto done_search;
00807                                    }
00808                                    break;
00809 
00810                             default:
00811 #ifdef LDAP_SYNC_TRACE
00812                                    fprintf( stderr, "\tgot something unexpected...\n" );
00813 #endif /* LDAP_SYNC_TRACE */
00814 
00815                                    ldap_msgfree( res );
00816 
00817                                    rc = LDAP_OTHER;
00818                                    goto done;
00819                             }
00820                      }
00821                      ldap_msgfree( res );
00822                      res = NULL;
00823                      break;
00824               }
00825        }
00826 
00827 done_search:;
00828        ldap_msgfree( res );
00829 
00830 done:;
00831        if ( ber != NULL ) {
00832               ber_free( ber, 1 );
00833        }
00834 
00835        return rc;
00836 }
00837 
00838 /*
00839  * initialize the refreshOnly sync
00840  */
00841 int
00842 ldap_sync_init_refresh_only( ldap_sync_t *ls )
00843 {
00844        return ldap_sync_init( ls, LDAP_SYNC_REFRESH_ONLY );
00845 }
00846 
00847 /*
00848  * initialize the refreshAndPersist sync
00849  */
00850 int
00851 ldap_sync_init_refresh_and_persist( ldap_sync_t *ls )
00852 {
00853        return ldap_sync_init( ls, LDAP_SYNC_REFRESH_AND_PERSIST );
00854 }
00855 
00856 /*
00857  * poll for new responses
00858  */
00859 int
00860 ldap_sync_poll( ldap_sync_t *ls )
00861 {
00862        struct timeval              tv,
00863                             *tvp = NULL;
00864        LDAPMessage          *res = NULL,
00865                             *msg;
00866        int                  rc = 0;
00867 
00868 #ifdef LDAP_SYNC_TRACE
00869        fprintf( stderr, "ldap_sync_poll...\n" );
00870 #endif /* LDAP_SYNC_TRACE */
00871 
00872        assert( ls != NULL );
00873        assert( ls->ls_ld != NULL );
00874 
00875        if ( ls->ls_timeout != -1 ) {
00876               tv.tv_sec = ls->ls_timeout;
00877               tv.tv_usec = 0;
00878               tvp = &tv;
00879        }
00880 
00881        rc = ldap_result( ls->ls_ld, ls->ls_msgid,
00882               LDAP_MSG_RECEIVED, tvp, &res );
00883        if ( rc <= 0 ) {
00884               return rc;
00885        }
00886 
00887        for ( msg = ldap_first_message( ls->ls_ld, res );
00888               msg;
00889               msg = ldap_next_message( ls->ls_ld, msg ) )
00890        {
00891               int    refreshDone;
00892 
00893               switch ( ldap_msgtype( msg ) ) {
00894               case LDAP_RES_SEARCH_ENTRY:
00895                      rc = ldap_sync_search_entry( ls, res );
00896                      break;
00897 
00898               case LDAP_RES_SEARCH_REFERENCE:
00899                      rc = ldap_sync_search_reference( ls, res );
00900                      break;
00901 
00902               case LDAP_RES_SEARCH_RESULT:
00903                      rc = ldap_sync_search_result( ls, res );
00904                      goto done_search;
00905 
00906               case LDAP_RES_INTERMEDIATE:
00907                      rc = ldap_sync_search_intermediate( ls, res, &refreshDone );
00908                      if ( rc != LDAP_SUCCESS || refreshDone ) {
00909                             goto done_search;
00910                      }
00911                      break;
00912 
00913               default:
00914 #ifdef LDAP_SYNC_TRACE
00915                      fprintf( stderr, "\tgot something unexpected...\n" );
00916 #endif /* LDAP_SYNC_TRACE */
00917 
00918                      ldap_msgfree( res );
00919 
00920                      rc = LDAP_OTHER;
00921                      goto done;
00922               }
00923        }
00924 
00925 done_search:;
00926        ldap_msgfree( res );
00927 
00928 done:;
00929        return rc;
00930 }