diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:35:32 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:35:32 +0000 |
commit | 5ea77a75dd2d2158401331879f3c8f47940a732c (patch) | |
tree | d89dc06e9f4850a900f161e25f84e922c4f86cc8 /libraries/libldap/ldap_sync.c | |
parent | Initial commit. (diff) | |
download | openldap-upstream/2.5.13+dfsg.tar.xz openldap-upstream/2.5.13+dfsg.zip |
Adding upstream version 2.5.13+dfsg.upstream/2.5.13+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libraries/libldap/ldap_sync.c')
-rw-r--r-- | libraries/libldap/ldap_sync.c | 928 |
1 files changed, 928 insertions, 0 deletions
diff --git a/libraries/libldap/ldap_sync.c b/libraries/libldap/ldap_sync.c new file mode 100644 index 0000000..6c99e3a --- /dev/null +++ b/libraries/libldap/ldap_sync.c @@ -0,0 +1,928 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2006-2022 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This program was originally developed by Pierangelo Masarati + * for inclusion in OpenLDAP Software. + */ + +/* + * Proof-of-concept API that implement the client-side + * of the "LDAP Content Sync Operation" (RFC 4533) + */ + +#include "portable.h" + +#include <ac/time.h> + +#include "ldap-int.h" + +#ifdef LDAP_SYNC_TRACE +static const char * +ldap_sync_state2str( int state ) +{ + switch ( state ) { + case LDAP_SYNC_PRESENT: + return "LDAP_SYNC_PRESENT"; + + case LDAP_SYNC_ADD: + return "LDAP_SYNC_ADD"; + + case LDAP_SYNC_MODIFY: + return "LDAP_SYNC_MODIFY"; + + case LDAP_SYNC_DELETE: + return "LDAP_SYNC_DELETE"; + + default: + return "(unknown)"; + } +} +#endif + +/* + * initialize the persistent search structure + */ +ldap_sync_t * +ldap_sync_initialize( ldap_sync_t *ls_in ) +{ + ldap_sync_t *ls = ls_in; + + if ( ls == NULL ) { + ls = ldap_memalloc( sizeof( ldap_sync_t ) ); + if ( ls == NULL ) { + return NULL; + } + } + memset( ls, 0, sizeof( ldap_sync_t ) ); + + ls->ls_scope = LDAP_SCOPE_SUBTREE; + ls->ls_timeout = -1; + + return ls; +} + +/* + * destroy the persistent search structure + */ +void +ldap_sync_destroy( ldap_sync_t *ls, int freeit ) +{ + assert( ls != NULL ); + + if ( ls->ls_base != NULL ) { + ldap_memfree( ls->ls_base ); + ls->ls_base = NULL; + } + + if ( ls->ls_filter != NULL ) { + ldap_memfree( ls->ls_filter ); + ls->ls_filter = NULL; + } + + if ( ls->ls_attrs != NULL ) { + int i; + + for ( i = 0; ls->ls_attrs[ i ] != NULL; i++ ) { + ldap_memfree( ls->ls_attrs[ i ] ); + } + ldap_memfree( ls->ls_attrs ); + ls->ls_attrs = NULL; + } + + if ( ls->ls_ld != NULL ) { + (void)ldap_unbind_ext( ls->ls_ld, NULL, NULL ); +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "ldap_unbind_ext()\n" ); +#endif /* LDAP_SYNC_TRACE */ + ls->ls_ld = NULL; + } + + if ( ls->ls_cookie.bv_val != NULL ) { + ldap_memfree( ls->ls_cookie.bv_val ); + ls->ls_cookie.bv_val = NULL; + } + + if ( freeit ) { + ldap_memfree( ls ); + } +} + +/* + * handle the LDAP_RES_SEARCH_ENTRY response + */ +static int +ldap_sync_search_entry( ldap_sync_t *ls, LDAPMessage *res ) +{ + LDAPControl **ctrls = NULL; + int rc = LDAP_OTHER, + i; + BerElement *ber = NULL; + struct berval entryUUID = { 0 }, + cookie = { 0 }; + int state = -1; + ber_len_t len; + ldap_sync_refresh_t phase; + +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\tgot LDAP_RES_SEARCH_ENTRY\n" ); +#endif /* LDAP_SYNC_TRACE */ + + assert( ls != NULL ); + assert( res != NULL ); + + phase = ls->ls_refreshPhase; + + /* OK */ + + /* extract: + * - data + * - entryUUID + * + * check that: + * - Sync State Control is "add" + */ + + /* the control MUST be present */ + + /* extract controls */ + ldap_get_entry_controls( ls->ls_ld, res, &ctrls ); + if ( ctrls == NULL ) { + goto done; + } + + /* lookup the sync state control */ + for ( i = 0; ctrls[ i ] != NULL; i++ ) { + if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_STATE ) == 0 ) { + break; + } + } + + /* control must be present; there might be other... */ + if ( ctrls[ i ] == NULL ) { + goto done; + } + + /* extract data */ + ber = ber_init( &ctrls[ i ]->ldctl_value ); + if ( ber == NULL ) { + goto done; + } + /* scan entryUUID in-place ("m") */ + if ( ber_scanf( ber, "{em" /*"}"*/, &state, &entryUUID ) == LBER_ERROR + || entryUUID.bv_len == 0 ) + { + goto done; + } + + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { + /* scan cookie in-place ("m") */ + if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) == LBER_ERROR ) { + goto done; + } + if ( cookie.bv_val != NULL ) { + ber_bvreplace( &ls->ls_cookie, &cookie ); + } +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot cookie=%s\n", + cookie.bv_val ? cookie.bv_val : "(null)" ); +#endif /* LDAP_SYNC_TRACE */ + } + + switch ( state ) { + case LDAP_SYNC_PRESENT: + case LDAP_SYNC_DELETE: + case LDAP_SYNC_ADD: + case LDAP_SYNC_MODIFY: + /* NOTE: ldap_sync_refresh_t is defined + * as the corresponding LDAP_SYNC_* + * for the 4 above cases */ + phase = state; +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot syncState=%s\n", ldap_sync_state2str( state ) ); +#endif /* LDAP_SYNC_TRACE */ + break; + + default: +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot unknown syncState=%d\n", state ); +#endif /* LDAP_SYNC_TRACE */ + goto done; + } + + rc = ls->ls_search_entry + ? ls->ls_search_entry( ls, res, &entryUUID, phase ) + : LDAP_SUCCESS; + +done:; + if ( ber != NULL ) { + ber_free( ber, 1 ); + } + + if ( ctrls != NULL ) { + ldap_controls_free( ctrls ); + } + + return rc; +} + +/* + * handle the LDAP_RES_SEARCH_REFERENCE response + * (to be implemented yet) + */ +static int +ldap_sync_search_reference( ldap_sync_t *ls, LDAPMessage *res ) +{ + int rc = 0; + +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\tgot LDAP_RES_SEARCH_REFERENCE\n" ); +#endif /* LDAP_SYNC_TRACE */ + + assert( ls != NULL ); + assert( res != NULL ); + + if ( ls->ls_search_reference ) { + rc = ls->ls_search_reference( ls, res ); + } + + return rc; +} + +/* + * handle the LDAP_RES_SEARCH_RESULT response + */ +static int +ldap_sync_search_result( ldap_sync_t *ls, LDAPMessage *res ) +{ + int err; + char *matched = NULL, + *msg = NULL; + LDAPControl **ctrls = NULL; + int rc; + int refreshDeletes = -1; + +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\tgot LDAP_RES_SEARCH_RESULT\n" ); +#endif /* LDAP_SYNC_TRACE */ + + assert( ls != NULL ); + assert( res != NULL ); + + /* should not happen in refreshAndPersist... */ + rc = ldap_parse_result( ls->ls_ld, + res, &err, &matched, &msg, NULL, &ctrls, 0 ); +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, + "\tldap_parse_result(%d, \"%s\", \"%s\") == %d\n", + err, + matched ? matched : "", + msg ? msg : "", + rc ); +#endif /* LDAP_SYNC_TRACE */ + if ( rc == LDAP_SUCCESS ) { + rc = err; + } + + ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE; + + switch ( rc ) { + case LDAP_SUCCESS: { + int i; + BerElement *ber = NULL; + ber_len_t len; + struct berval cookie = { 0 }; + + rc = LDAP_OTHER; + + /* deal with control; then fallthru to handler */ + if ( ctrls == NULL ) { + goto done; + } + + /* lookup the sync state control */ + for ( i = 0; ctrls[ i ] != NULL; i++ ) { + if ( strcmp( ctrls[ i ]->ldctl_oid, + LDAP_CONTROL_SYNC_DONE ) == 0 ) + { + break; + } + } + + /* control must be present; there might be other... */ + if ( ctrls[ i ] == NULL ) { + goto done; + } + + /* extract data */ + ber = ber_init( &ctrls[ i ]->ldctl_value ); + if ( ber == NULL ) { + goto done; + } + + if ( ber_scanf( ber, "{" /*"}"*/) == LBER_ERROR ) { + goto ber_done; + } + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { + if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { + goto ber_done; + } + if ( cookie.bv_val != NULL ) { + ber_bvreplace( &ls->ls_cookie, &cookie ); + } +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot cookie=%s\n", + cookie.bv_val ? cookie.bv_val : "(null)" ); +#endif /* LDAP_SYNC_TRACE */ + } + + refreshDeletes = 0; + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) { + if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) { + goto ber_done; + } + if ( refreshDeletes ) { + refreshDeletes = 1; + } + } + + if ( ber_scanf( ber, /*"{"*/ "}" ) != LBER_ERROR ) { + rc = LDAP_SUCCESS; + } + + ber_done:; + ber_free( ber, 1 ); + if ( rc != LDAP_SUCCESS ) { + break; + } + +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot refreshDeletes=%s\n", + refreshDeletes ? "TRUE" : "FALSE" ); +#endif /* LDAP_SYNC_TRACE */ + + /* FIXME: what should we do with the refreshDelete? */ + switch ( refreshDeletes ) { + case 0: + ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS; + break; + + default: + ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES; + break; + } + + } /* fallthru */ + + case LDAP_SYNC_REFRESH_REQUIRED: + /* TODO: check for Sync Done Control */ + /* FIXME: perhaps the handler should be called + * also in case of failure; we'll deal with this + * later when implementing refreshOnly */ + if ( ls->ls_search_result ) { + err = ls->ls_search_result( ls, res, refreshDeletes ); + } + break; + } + +done:; + if ( matched != NULL ) { + ldap_memfree( matched ); + } + + if ( msg != NULL ) { + ldap_memfree( msg ); + } + + if ( ctrls != NULL ) { + ldap_controls_free( ctrls ); + } + + ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE; + + return rc; +} + +/* + * handle the LDAP_RES_INTERMEDIATE response + */ +static int +ldap_sync_search_intermediate( ldap_sync_t *ls, LDAPMessage *res, int *refreshDone ) +{ + int rc; + char *retoid = NULL; + struct berval *retdata = NULL; + BerElement *ber = NULL; + ber_len_t len; + ber_tag_t syncinfo_tag; + struct berval cookie; + int refreshDeletes = 0; + BerVarray syncUUIDs = NULL; + ldap_sync_refresh_t phase; + +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\tgot LDAP_RES_INTERMEDIATE\n" ); +#endif /* LDAP_SYNC_TRACE */ + + assert( ls != NULL ); + assert( res != NULL ); + assert( refreshDone != NULL ); + + *refreshDone = 0; + + rc = ldap_parse_intermediate( ls->ls_ld, res, + &retoid, &retdata, NULL, 0 ); +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t%sldap_parse_intermediate(%s) == %d\n", + rc != LDAP_SUCCESS ? "!!! " : "", + retoid == NULL ? "\"\"" : retoid, + rc ); +#endif /* LDAP_SYNC_TRACE */ + /* parsing must be successful, and yield the OID + * of the sync info intermediate response */ + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + rc = LDAP_OTHER; + + if ( retoid == NULL || strcmp( retoid, LDAP_SYNC_INFO ) != 0 ) { + goto done; + } + + /* init ber using the value in the response */ + ber = ber_init( retdata ); + if ( ber == NULL ) { + goto done; + } + + syncinfo_tag = ber_peek_tag( ber, &len ); + switch ( syncinfo_tag ) { + case LDAP_TAG_SYNC_NEW_COOKIE: + if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { + goto done; + } + if ( cookie.bv_val != NULL ) { + ber_bvreplace( &ls->ls_cookie, &cookie ); + } +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot cookie=%s\n", + cookie.bv_val ? cookie.bv_val : "(null)" ); +#endif /* LDAP_SYNC_TRACE */ + break; + + case LDAP_TAG_SYNC_REFRESH_DELETE: + case LDAP_TAG_SYNC_REFRESH_PRESENT: + if ( syncinfo_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) { +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot refreshDelete\n" ); +#endif /* LDAP_SYNC_TRACE */ + switch ( ls->ls_refreshPhase ) { + case LDAP_SYNC_CAPI_NONE: + case LDAP_SYNC_CAPI_PRESENTS: + ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES; + break; + + default: + /* TODO: impossible; handle */ + goto done; + } + + } else { +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot refreshPresent\n" ); +#endif /* LDAP_SYNC_TRACE */ + switch ( ls->ls_refreshPhase ) { + case LDAP_SYNC_CAPI_NONE: + ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS; + break; + + default: + /* TODO: impossible; handle */ + goto done; + } + } + + if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) { + goto done; + } + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { + if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { + goto done; + } + if ( cookie.bv_val != NULL ) { + ber_bvreplace( &ls->ls_cookie, &cookie ); + } +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot cookie=%s\n", + cookie.bv_val ? cookie.bv_val : "(null)" ); +#endif /* LDAP_SYNC_TRACE */ + } + + *refreshDone = 1; + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDONE ) { + if ( ber_scanf( ber, "b", refreshDone ) == LBER_ERROR ) { + goto done; + } + } + +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot refreshDone=%s\n", + *refreshDone ? "TRUE" : "FALSE" ); +#endif /* LDAP_SYNC_TRACE */ + + if ( ber_scanf( ber, /*"{"*/ "}" ) == LBER_ERROR ) { + goto done; + } + + if ( *refreshDone ) { + ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE; + } + + if ( ls->ls_intermediate ) { + ls->ls_intermediate( ls, res, NULL, ls->ls_refreshPhase ); + } + + break; + + case LDAP_TAG_SYNC_ID_SET: +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot syncIdSet\n" ); +#endif /* LDAP_SYNC_TRACE */ + if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) { + goto done; + } + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { + if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) { + goto done; + } + if ( cookie.bv_val != NULL ) { + ber_bvreplace( &ls->ls_cookie, &cookie ); + } +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tgot cookie=%s\n", + cookie.bv_val ? cookie.bv_val : "(null)" ); +#endif /* LDAP_SYNC_TRACE */ + } + + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) { + if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) { + goto done; + } + } + + if ( ber_scanf( ber, /*"{"*/ "[W]}", &syncUUIDs ) == LBER_ERROR + || syncUUIDs == NULL ) + { + goto done; + } + +#ifdef LDAP_SYNC_TRACE + { + int i; + + fprintf( stderr, "\t\tgot refreshDeletes=%s\n", + refreshDeletes ? "TRUE" : "FALSE" ); + for ( i = 0; syncUUIDs[ i ].bv_val != NULL; i++ ) { + char buf[ BUFSIZ ]; + fprintf( stderr, "\t\t%s\n", + lutil_uuidstr_from_normalized( + syncUUIDs[ i ].bv_val, syncUUIDs[ i ].bv_len, + buf, sizeof( buf ) ) ); + } + } +#endif /* LDAP_SYNC_TRACE */ + + if ( refreshDeletes ) { + phase = LDAP_SYNC_CAPI_DELETES_IDSET; + + } else { + phase = LDAP_SYNC_CAPI_PRESENTS_IDSET; + } + + /* FIXME: should touch ls->ls_refreshPhase? */ + if ( ls->ls_intermediate ) { + ls->ls_intermediate( ls, res, syncUUIDs, phase ); + } + + ber_bvarray_free( syncUUIDs ); + break; + + default: +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\t\tunknown tag!\n" ); +#endif /* LDAP_SYNC_TRACE */ + goto done; + } + + rc = LDAP_SUCCESS; + +done:; + if ( ber != NULL ) { + ber_free( ber, 1 ); + } + + if ( retoid != NULL ) { + ldap_memfree( retoid ); + } + + if ( retdata != NULL ) { + ber_bvfree( retdata ); + } + + return rc; +} + +/* + * initialize the sync + */ +int +ldap_sync_init( ldap_sync_t *ls, int mode ) +{ + LDAPControl ctrl = { 0 }, + *ctrls[ 2 ]; + BerElement *ber = NULL; + int rc; + struct timeval tv = { 0 }, + *tvp = NULL; + LDAPMessage *res = NULL; + +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "ldap_sync_init(%s)...\n", + mode == LDAP_SYNC_REFRESH_AND_PERSIST ? + "LDAP_SYNC_REFRESH_AND_PERSIST" : + ( mode == LDAP_SYNC_REFRESH_ONLY ? + "LDAP_SYNC_REFRESH_ONLY" : "unknown" ) ); +#endif /* LDAP_SYNC_TRACE */ + + assert( ls != NULL ); + assert( ls->ls_ld != NULL ); + + /* support both refreshOnly and refreshAndPersist */ + switch ( mode ) { + case LDAP_SYNC_REFRESH_AND_PERSIST: + case LDAP_SYNC_REFRESH_ONLY: + break; + + default: + fprintf( stderr, "ldap_sync_init: unknown mode=%d\n", mode ); + return LDAP_PARAM_ERROR; + } + + /* check consistency of cookie and reloadHint at initial refresh */ + if ( ls->ls_cookie.bv_val == NULL && ls->ls_reloadHint != 0 ) { + fprintf( stderr, "ldap_sync_init: inconsistent cookie/rhint\n" ); + return LDAP_PARAM_ERROR; + } + + ctrls[ 0 ] = &ctrl; + ctrls[ 1 ] = NULL; + + /* prepare the Sync Request control */ + ber = ber_alloc_t( LBER_USE_DER ); +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "%sber_alloc_t() %s= NULL\n", + ber == NULL ? "!!! " : "", + ber == NULL ? "=" : "!" ); +#endif /* LDAP_SYNC_TRACE */ + if ( ber == NULL ) { + rc = LDAP_NO_MEMORY; + goto done; + } + + ls->ls_refreshPhase = LDAP_SYNC_CAPI_NONE; + + if ( ls->ls_cookie.bv_val != NULL ) { + ber_printf( ber, "{eOb}", mode, + &ls->ls_cookie, ls->ls_reloadHint ); + + } else { + ber_printf( ber, "{eb}", mode, ls->ls_reloadHint ); + } + + rc = ber_flatten2( ber, &ctrl.ldctl_value, 0 ); +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, + "%sber_flatten2() == %d\n", + rc ? "!!! " : "", + rc ); +#endif /* LDAP_SYNC_TRACE */ + if ( rc < 0 ) { + rc = LDAP_OTHER; + goto done; + } + + /* make the control critical, as we cannot proceed without */ + ctrl.ldctl_oid = LDAP_CONTROL_SYNC; + ctrl.ldctl_iscritical = 1; + + /* timelimit? */ + if ( ls->ls_timelimit ) { + tv.tv_sec = ls->ls_timelimit; + tvp = &tv; + } + + /* actually run the search */ + rc = ldap_search_ext( ls->ls_ld, + ls->ls_base, ls->ls_scope, ls->ls_filter, + ls->ls_attrs, 0, ctrls, NULL, + tvp, ls->ls_sizelimit, &ls->ls_msgid ); +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, + "%sldap_search_ext(\"%s\", %d, \"%s\") == %d\n", + rc ? "!!! " : "", + ls->ls_base, ls->ls_scope, ls->ls_filter, rc ); +#endif /* LDAP_SYNC_TRACE */ + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + /* initial content/content update phase */ + for ( ; ; ) { + LDAPMessage *msg = NULL; + + /* NOTE: this very short timeout is just to let + * ldap_result() yield long enough to get something */ + tv.tv_sec = 0; + tv.tv_usec = 100000; + + rc = ldap_result( ls->ls_ld, ls->ls_msgid, + LDAP_MSG_RECEIVED, &tv, &res ); +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, + "\t%sldap_result(%d) == %d\n", + rc == -1 ? "!!! " : "", + ls->ls_msgid, rc ); +#endif /* LDAP_SYNC_TRACE */ + switch ( rc ) { + case 0: + /* + * timeout + * + * TODO: can do something else in the meanwhile) + */ + break; + + case -1: + /* smtg bad! */ + goto done; + + default: + for ( msg = ldap_first_message( ls->ls_ld, res ); + msg != NULL; + msg = ldap_next_message( ls->ls_ld, msg ) ) + { + int refreshDone; + + switch ( ldap_msgtype( msg ) ) { + case LDAP_RES_SEARCH_ENTRY: + rc = ldap_sync_search_entry( ls, res ); + break; + + case LDAP_RES_SEARCH_REFERENCE: + rc = ldap_sync_search_reference( ls, res ); + break; + + case LDAP_RES_SEARCH_RESULT: + rc = ldap_sync_search_result( ls, res ); + goto done_search; + + case LDAP_RES_INTERMEDIATE: + rc = ldap_sync_search_intermediate( ls, res, &refreshDone ); + if ( rc != LDAP_SUCCESS || refreshDone ) { + goto done_search; + } + break; + + default: +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\tgot something unexpected...\n" ); +#endif /* LDAP_SYNC_TRACE */ + + ldap_msgfree( res ); + + rc = LDAP_OTHER; + goto done; + } + } + ldap_msgfree( res ); + res = NULL; + break; + } + } + +done_search:; + ldap_msgfree( res ); + +done:; + if ( ber != NULL ) { + ber_free( ber, 1 ); + } + + return rc; +} + +/* + * initialize the refreshOnly sync + */ +int +ldap_sync_init_refresh_only( ldap_sync_t *ls ) +{ + return ldap_sync_init( ls, LDAP_SYNC_REFRESH_ONLY ); +} + +/* + * initialize the refreshAndPersist sync + */ +int +ldap_sync_init_refresh_and_persist( ldap_sync_t *ls ) +{ + return ldap_sync_init( ls, LDAP_SYNC_REFRESH_AND_PERSIST ); +} + +/* + * poll for new responses + */ +int +ldap_sync_poll( ldap_sync_t *ls ) +{ + struct timeval tv, + *tvp = NULL; + LDAPMessage *res = NULL, + *msg; + int rc = 0; + +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "ldap_sync_poll...\n" ); +#endif /* LDAP_SYNC_TRACE */ + + assert( ls != NULL ); + assert( ls->ls_ld != NULL ); + + if ( ls->ls_timeout != -1 ) { + tv.tv_sec = ls->ls_timeout; + tv.tv_usec = 0; + tvp = &tv; + } + + rc = ldap_result( ls->ls_ld, ls->ls_msgid, + LDAP_MSG_RECEIVED, tvp, &res ); + if ( rc <= 0 ) { + return rc; + } + + for ( msg = ldap_first_message( ls->ls_ld, res ); + msg; + msg = ldap_next_message( ls->ls_ld, msg ) ) + { + int refreshDone; + + switch ( ldap_msgtype( msg ) ) { + case LDAP_RES_SEARCH_ENTRY: + rc = ldap_sync_search_entry( ls, res ); + break; + + case LDAP_RES_SEARCH_REFERENCE: + rc = ldap_sync_search_reference( ls, res ); + break; + + case LDAP_RES_SEARCH_RESULT: + rc = ldap_sync_search_result( ls, res ); + goto done_search; + + case LDAP_RES_INTERMEDIATE: + rc = ldap_sync_search_intermediate( ls, res, &refreshDone ); + if ( rc != LDAP_SUCCESS || refreshDone ) { + goto done_search; + } + break; + + default: +#ifdef LDAP_SYNC_TRACE + fprintf( stderr, "\tgot something unexpected...\n" ); +#endif /* LDAP_SYNC_TRACE */ + + ldap_msgfree( res ); + + rc = LDAP_OTHER; + goto done; + } + } + +done_search:; + ldap_msgfree( res ); + +done:; + return rc; +} |