From 85b1783d5c40195162f23d6848c28f9c9d1dc730 Mon Sep 17 00:00:00 2001 From: Jong Hyuk Choi Date: Wed, 5 Feb 2003 07:37:02 +0000 Subject: [PATCH] LDAP Sync Operation (draft-zeilenga-ldup-sync) as a groundwork for an LDAP replication design --- clients/tools/ldapsearch.c | 261 ++++++++++-- include/ldap.h | 56 ++- libraries/libldap/error.c | 12 + servers/slapd/abandon.c | 2 +- servers/slapd/back-bdb/add.c | 6 +- servers/slapd/back-bdb/back-bdb.h | 2 +- servers/slapd/back-bdb/delete.c | 8 +- servers/slapd/back-bdb/init.c | 2 +- servers/slapd/back-bdb/lcup.c | 483 ++++++++++++---------- servers/slapd/back-bdb/modify.c | 20 +- servers/slapd/back-bdb/modrdn.c | 20 +- servers/slapd/back-bdb/proto-bdb.h | 68 +++- servers/slapd/back-bdb/search.c | 620 ++++++++++++++++++++++------- servers/slapd/cancel.c | 17 +- servers/slapd/connection.c | 24 +- servers/slapd/controls.c | 130 +++++- servers/slapd/operation.c | 7 +- servers/slapd/search.c | 28 +- servers/slapd/slap.h | 48 ++- 19 files changed, 1342 insertions(+), 472 deletions(-) diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c index ec86820b88..46745acef2 100644 --- a/clients/tools/ldapsearch.c +++ b/clients/tools/ldapsearch.c @@ -76,6 +76,10 @@ usage( void ) * " sp///\n" * */ #endif +#ifdef LDAP_SYNC +" [!]sync= ro[/] (ldap sync - refreshOnly)\n" +" rp[/][/] (ldap sync - refreshAndPersist)\n" +#endif " -F prefix URL prefix for files (default: %s)\n" " -l limit time limit (in seconds) for search\n" " -L print responses in LDIFv1 format\n" @@ -147,11 +151,20 @@ static int includeufn, vals2tmp = 0, ldif = 0; static int subentries = 0, valuesReturnFilter = 0; static char *vrFilter = NULL; -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) static int lcup = 0; +static int ldapsync = 0; +#endif + +#ifdef LDAP_CLIENT_UPDATE static int lcup_cint = 0; static struct berval lcup_cookie = { 0, NULL }; -static int lcup_slimit = 0; +static int lcup_slimit = -1; +#endif + +#ifdef LDAP_SYNC +static struct berval sync_cookie = { 0, NULL }; +static int sync_slimit = -1; #endif static int pagedResults = 0; @@ -290,29 +303,35 @@ handle_private_option( int i ) #endif #ifdef LDAP_CLIENT_UPDATE - } else if ( strcasecmp( control, "lcup" ) == 0 ) { - char *cookiep; - char *slimitp; - if ( lcup ) { - fprintf( stderr, "client update control previously specified\n"); - exit( EXIT_FAILURE ); - } - if ( cvalue == NULL ) { - fprintf( stderr, - "missing specification of client update control\n"); - exit( EXIT_FAILURE ); - } - if ( strncasecmp( cvalue, "p", 1 ) == 0 ) { - lcup = LDAP_CUP_PERSIST_ONLY; - cvalue += 2; - cookiep = strchr( cvalue, '/' ); - *cookiep++ = '\0'; - lcup_cint = atoi( cvalue ); - cvalue = cookiep; - slimitp = strchr( cvalue, '/' ); - *slimitp++ = '\0'; - ber_str2bv( cookiep, 0, 0, &lcup_cookie ); - lcup_slimit = atoi( slimitp ); + } else if ( strcasecmp( control, "lcup" ) == 0 ) { + char *cookiep; + char *slimitp; + if ( lcup ) { + fprintf( stderr, "client update control previously specified\n"); + exit( EXIT_FAILURE ); + } + if ( ldapsync != -1 ) { + fprintf( stderr, "ldap sync control previously specified\n"); + exit( EXIT_FAILURE ); + } + if ( cvalue == NULL ) { + fprintf( stderr, + "missing specification of client update control\n"); + exit( EXIT_FAILURE ); + } + if ( strncasecmp( cvalue, "p", 1 ) == 0 ) { + lcup = LDAP_CUP_PERSIST_ONLY; + cvalue = strchr( cvalue, '/' ); + cvalue++; + cookiep = strchr( cvalue, '/' ); + *cookiep++ = '\0'; + lcup_cint = atoi( cvalue ); + cvalue = cookiep; + slimitp = strchr( cvalue, '/' ); + *slimitp++ = '\0'; + while ( isspace( *cookiep ) ) cookiep++; + ber_str2bv( cookiep, 0, 0, &lcup_cookie ); + lcup_slimit = atoi( slimitp ); /* } else if ( strncasecmp( cvalue, "s", 1 ) == 0 ) { lcup = LDAP_CUP_SYNC_ONLY; @@ -342,6 +361,56 @@ handle_private_option( int i ) if ( crit ) lcup *= -1; #endif +#ifdef LDAP_SYNC + } else if ( strcasecmp( control, "sync" ) == 0 ) { + char *cookiep; + char *slimitp; + if ( ldapsync ) { + fprintf( stderr, "ldap sync control previously specified\n" ); + exit( EXIT_FAILURE ); + } + if ( lcup ) { + fprintf( stderr, "client update control previously specified\n" ); + exit( EXIT_FAILURE ); + } + if ( cvalue == NULL ) { + fprintf( stderr, + "missing specification of ldap sync control\n"); + exit( EXIT_FAILURE ); + } + if ( strncasecmp( cvalue, "ro", 2 ) == 0 ) { + ldapsync = LDAP_SYNC_REFRESH_ONLY; + cookiep = strchr( cvalue, '/' ); + if ( cookiep != NULL ) { + cookiep++; + if ( *cookiep != '\0' ) { + ber_str2bv( cookiep, 0, 0, &sync_cookie ); + } + } + } else if ( strncasecmp( cvalue, "rp", 2 ) == 0 ) { + ldapsync = LDAP_SYNC_REFRESH_AND_PERSIST; + cookiep = strchr( cvalue, '/' ); + if ( cookiep != NULL ) { + *cookiep++ = '\0'; + cvalue = cookiep; + } + slimitp = strchr( cvalue, '/' ); + if ( slimitp != NULL ) { + *slimitp++ = '\0'; + } + if ( cookiep != NULL && *cookiep != '\0' ) + ber_str2bv( cookiep, 0, 0, &sync_cookie ); + if ( slimitp != NULL && *slimitp != '\0' ) + sync_slimit = atoi( slimitp ); + } else { + fprintf( stderr, + "ldap sync control value \"%s\" invalid\n", + cvalue ); + exit( EXIT_FAILURE ); + } + if ( crit ) ldapsync *= -1; +#endif + } else { fprintf( stderr, "Invalid control name: %s\n", control ); usage(); @@ -434,6 +503,11 @@ main( int argc, char **argv ) struct berval *cubvalp = NULL; #endif +#ifdef LDAP_SYNC + BerElement *syncber = NULL; + struct berval *syncbvalp = NULL; +#endif + npagedresponses = npagedentries = npagedreferences = npagedextended = npagedpartial = 0; @@ -530,7 +604,10 @@ getNextPage: || valuesReturnFilter || pageSize #ifdef LDAP_CLIENT_UPDATE || lcup -#endif /* LDAP_CLIENT_UPDATE */ +#endif +#ifdef LDAP_SYNC + || ldapsync +#endif ) { int err; int i=0; @@ -560,25 +637,61 @@ getNextPage: #endif #ifdef LDAP_CLIENT_UPDATE - if ( lcup ) { - if (( cuber = ber_alloc_t(LBER_USE_DER)) == NULL ) { + if ( lcup ) { + if (( cuber = ber_alloc_t(LBER_USE_DER)) == NULL ) { + return EXIT_FAILURE; + } + + if ( lcup_cookie.bv_len == 0 ) { + err = ber_printf( cuber, "{ei}", abs(lcup), lcup_cint ); + } else { + err = ber_printf( cuber, "{ei{sO}}", abs(lcup), lcup_cint, + LDAP_LCUP_COOKIE_OID, &lcup_cookie ); + } + + if ( err == LBER_ERROR ) { + ber_free( cuber, 1 ); + fprintf( stderr, "client update control encoding error!\n" ); + return EXIT_FAILURE; + } + + if ( ber_flatten( cuber, &cubvalp ) == LBER_ERROR ) { + return EXIT_FAILURE; + } + + c[i].ldctl_oid = LDAP_CONTROL_CLIENT_UPDATE; + c[i].ldctl_value = (*cubvalp); + c[i].ldctl_iscritical = lcup < 0; + i++; + } +#endif + +#ifdef LDAP_SYNC + if ( ldapsync ) { + if (( syncber = ber_alloc_t(LBER_USE_DER)) == NULL ) { return EXIT_FAILURE; } - err = ber_printf( cuber, "{ei{sO}}", abs(lcup), lcup_cint, - LDAP_CLIENT_UPDATE_COOKIE, &lcup_cookie); + + if ( sync_cookie.bv_len == 0 ) { + err = ber_printf( syncber, "{e}", abs(ldapsync) ); + } else { + err = ber_printf( syncber, "{eO}", abs(ldapsync), + &sync_cookie ); + } + if ( err == LBER_ERROR ) { - ber_free( cuber, 1 ); - fprintf( stderr, "client update control encoding error!\n" ); + ber_free( syncber, 1 ); + fprintf( stderr, "ldap sync control encoding error!\n" ); return EXIT_FAILURE; } - if ( ber_flatten( cuber, &cubvalp ) == LBER_ERROR ) { + if ( ber_flatten( syncber, &syncbvalp ) == LBER_ERROR ) { return EXIT_FAILURE; } - c[i].ldctl_oid = LDAP_CONTROL_CLIENT_UPDATE; - c[i].ldctl_value=(*cubvalp); - c[i].ldctl_iscritical = lcup < 0; + c[i].ldctl_oid = LDAP_CONTROL_SYNC; + c[i].ldctl_value = (*syncbvalp); + c[i].ldctl_iscritical = ldapsync < 0; i++; } #endif @@ -776,7 +889,13 @@ static int dosearch( int nextended; int npartial; LDAPMessage *res, *msg; - ber_int_t msgid; + ber_int_t msgid; +#ifdef LDAP_SYNC + char *retoid = NULL; + struct berval *retdata = NULL; + int nresponses_psearch = -1; + int cancel_msgid = -1; +#endif if( filtpatt != NULL ) { filter = malloc( strlen( filtpatt ) + strlen( value ) ); @@ -806,6 +925,8 @@ static int dosearch( rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly, sctrls, cctrls, timeout, sizelimit, &msgid ); + printf("msgid = %d\n", msgid); + if ( filtpatt != NULL ) { free( filter ); } @@ -833,7 +954,11 @@ static int dosearch( msg != NULL; msg = ldap_next_message( ld, msg ) ) { - if( nresponses++ ) putchar('\n'); + if ( nresponses++ ) putchar('\n'); +#if LDAP_SYNC + if ( nresponses_psearch >= 0 ) + nresponses_psearch++; +#endif switch( ldap_msgtype( msg ) ) { case LDAP_RES_SEARCH_ENTRY: @@ -854,6 +979,16 @@ static int dosearch( /* unsolicited extended operation */ goto done; } + +#ifdef LDAP_SYNC + if ( cancel_msgid != -1 && + cancel_msgid == ldap_msgid( msg ) ) { + printf("Cancelled \n"); + printf("cancel_msgid = %d\n", cancel_msgid); + goto done; + } +#endif + break; case LDAP_RES_EXTENDED_PARTIAL: @@ -866,14 +1001,62 @@ static int dosearch( if ( pageSize != 0 ) { rc = parse_page_control( ld, msg, &cookie ); } + +#ifdef LDAP_CLIENT_UPDATE + if ( lcup == LDAP_CUP_PERSIST_ONLY || + lcup == LDAP_CUP_SYNC_AND_PERSIST ) { + break; + } +#endif +#if defined(LDAP_CLIENT_UPDATE) && defined(LDAP_SYNC) + else +#endif +#ifdef LDAP_SYNC + if ( ldapsync == LDAP_SYNC_REFRESH_AND_PERSIST ) { + break; + } +#endif + goto done; + +#ifdef LDAP_SYNC + case LDAP_RES_INTERMEDIATE_RESP: + ldap_parse_intermediate_resp_result( ld, msg, &retoid, &retdata, 0 ); + nresponses_psearch = 0; + + if ( strcmp( retoid, LDAP_SYNC_INFO ) ) { + printf("Unexpected Intermediate Response\n"); + ldap_memfree( retoid ); + ber_bvfree( retdata ); + goto done; + } else { + printf("SyncInfo Received\n"); + ldap_memfree( retoid ); + ber_bvfree( retdata ); + break; + } +#endif } + #ifdef LDAP_CLIENT_UPDATE - if ( nresponses >= lcup_slimit ) { + if ( lcup && lcup_slimit != -1 && nresponses >= lcup_slimit ) { ldap_abandon (ld, ldap_msgid(msg)); goto done; } #endif +#ifdef LDAP_SYNC + if ( ldapsync && sync_slimit != -1 && + nresponses_psearch >= sync_slimit ) { + BerElement *msgidber = NULL; + struct berval *msgidvalp = NULL; + msgidber = ber_alloc_t(LBER_USE_DER); + ber_printf(msgidber, "{i}", msgid); + ber_flatten(msgidber, &msgidvalp); + ldap_extended_operation(ld, LDAP_EXOP_X_CANCEL, + msgidvalp, NULL, NULL, &cancel_msgid); + nresponses_psearch = -1; + } +#endif } diff --git a/include/ldap.h b/include/ldap.h index 361a824439..9b18a75110 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -205,11 +205,29 @@ typedef struct ldapcontrol { /* #define LDAP_CLIENT_UPDATE 1 +#define LDAP_SYNC 2 */ + #ifdef LDAP_CLIENT_UPDATE #define LDAP_CONTROL_CLIENT_UPDATE "1.3.6.1.4.1.4203.666.5.3" #define LDAP_CONTROL_ENTRY_UPDATE "1.3.6.1.4.1.4203.666.5.4" -#define LDAP_CONTROL_CLIENT_UPDATE_DONE "1.3.6.1.4.1.4203.666.5.5" +#define LDAP_CONTROL_CLIENT_UPDATE_DONE "1.3.6.1.4.1.4203.666.5.5" +#define LDAP_LCUP_COOKIE_OID "1.3.6.1.4.1.4203.666.10.1" +#endif + +#ifdef LDAP_SYNC +#define LDAP_CONTROL_SYNC "1.3.6.1.4.1.4203.666.5.TBD1" +#define LDAP_CONTROL_SYNC_STATE "1.3.6.1.4.1.4203.666.5.TBD2" +#define LDAP_CONTROL_SYNC_DONE "1.3.6.1.4.1.4203.666.5.TBD3" +#define LDAP_SYNC_INFO "1.3.6.1.4.1.4203.666.5.TBD4" + +#define LDAP_SYNC_REFRESH_DONE 0 +#define LDAP_SYNC_NEW_COOKIE 1 + +#define LDAP_SYNC_PRESENT 0 +#define LDAP_SYNC_ADD 1 +#define LDAP_SYNC_MODIFY 2 +#define LDAP_SYNC_DELETE 3 #endif #define LDAP_CONTROL_SORTREQUEST "1.2.840.113556.1.4.473" @@ -278,8 +296,12 @@ typedef struct ldapcontrol { #define LDAP_TAG_LDAPCRED ((ber_tag_t) 0x04U) /* octet string */ #ifdef LDAP_CLIENT_UPDATE -#define LDAP_TAG_COOKIE ((ber_tag_t) 0x30U) /* sequence */ -#endif /* LDAP_CLIENT_UPDATE */ +#define LDAP_LCUP_TAG_COOKIE ((ber_tag_t) 0x30U) /* sequence */ +#endif + +#ifdef LDAP_SYNC +#define LDAP_SYNC_TAG_COOKIE ((ber_tag_t) 0x04U) /* octet string */ +#endif #define LDAP_TAG_CONTROLS ((ber_tag_t) 0xa0U) /* context specific + constructed + 0 */ #define LDAP_TAG_REFERRAL ((ber_tag_t) 0xa3U) /* context specific + constructed + 3 */ @@ -477,15 +499,7 @@ typedef struct ldapcontrol { #define LDAP_CUP_UNSUPPORTED_SCHEME 0x65 #define LDAP_CUP_CLIENT_DISCONNECT 0x66 #define LDAP_CUP_RELOAD_REQUIRED 0x67 - -/* LCUP update type */ -#define LDAP_CUP_SYNC_ONLY 0x00 -#define LDAP_CUP_SYNC_AND_PERSIST 0x01 -#define LDAP_CUP_PERSIST_ONLY 0x02 - -/* LCUP default cookie interval */ -#define LDAP_CUP_DEFAULT_SEND_COOKIE_INTERVAL 0x01 -#endif /* LDAP_CLIENT_UPDATE */ +#endif /* resultCode for Cancel Response */ #define LDAP_CANCELLED 0x68 @@ -498,6 +512,24 @@ typedef struct ldapcontrol { #define LDAP_CANCEL_ACK 0x02 #define LDAP_CANCEL_DONE 0x03 +#ifdef LDAP_CLIENT_UPDATE +/* LCUP update type */ +#define LDAP_CUP_NONE 0x00 +#define LDAP_CUP_SYNC_ONLY 0x01 +#define LDAP_CUP_PERSIST_ONLY 0x02 +#define LDAP_CUP_SYNC_AND_PERSIST 0x03 + +/* LCUP default cookie interval */ +#define LDAP_CUP_DEFAULT_SEND_COOKIE_INTERVAL 0x01 +#endif /* LDAP_CLIENT_UPDATE */ + +/* LDAP SYNC request type */ +#ifdef LDAP_SYNC +#define LDAP_SYNC_NONE 0x00 +#define LDAP_SYNC_REFRESH_ONLY 0x01 +#define LDAP_SYNC_REFRESH_AND_PERSIST 0x03 +#endif + /* * This structure represents both ldap messages and ldap responses. * These are really the same, except in the case of search responses, diff --git a/libraries/libldap/error.c b/libraries/libldap/error.c index 204cd71957..7b6dfb68b9 100644 --- a/libraries/libldap/error.c +++ b/libraries/libldap/error.c @@ -92,6 +92,18 @@ static struct ldaperror ldap_builtin_errlist[] = { {LDAP_MORE_RESULTS_TO_RETURN, "More results to return" }, {LDAP_CLIENT_LOOP, "Client Loop" }, {LDAP_REFERRAL_LIMIT_EXCEEDED, "Referral Limit Exceeded" }, +#ifdef LDAP_CLIENT_UPDATE + {LDAP_CUP_RESOURCES_EXHAUSTED, "LDAP Client Update Resource Exhausted" }, + {LDAP_CUP_SECURITY_VIOLATION, "LDAP Client Update Security Violation" }, + {LDAP_CUP_INVALID_COOKIE, "LDAP Client Update Invalid Cookie" }, + {LDAP_CUP_UNSUPPORTED_SCHEME, "LDAP Client Update Unsupported Scheme" }, + {LDAP_CUP_CLIENT_DISCONNECT, "LDAP Client Update Client Disconnect" }, + {LDAP_CUP_RELOAD_REQUIRED, "LDAP Client Update Reload Required" }, +#endif + {LDAP_CANCELLED, "LDAP Cancelled" }, + {LDAP_NO_SUCH_OPERATION, "LDAP No Operation to Cancel" }, + {LDAP_TOO_LATE, "LDAP Too Late to Cancel" }, + {LDAP_CANNOT_CANCEL, "LDAP Cannot Cancel" }, {-1, NULL} }; diff --git a/servers/slapd/abandon.c b/servers/slapd/abandon.c index 593c57206c..33bd0ab159 100644 --- a/servers/slapd/abandon.c +++ b/servers/slapd/abandon.c @@ -109,7 +109,7 @@ do_abandon( done: -#if LDAP_CLIENT_UPDATE +#ifdef LDAP_CLIENT_UPDATE for ( i = 0; i < nbackends; i++ ) { if ( strncmp( backends[i].be_type, "bdb", 3 ) ) continue; if ( bdb_abandon( &backends[i], conn, id ) == LDAP_SUCCESS ) { diff --git a/servers/slapd/back-bdb/add.c b/servers/slapd/back-bdb/add.c index 4ca3700ee9..8bc54ede34 100644 --- a/servers/slapd/back-bdb/add.c +++ b/servers/slapd/back-bdb/add.c @@ -42,7 +42,7 @@ bdb_add( #endif int noop = 0; -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) Operation* ps_list; #endif @@ -547,10 +547,10 @@ return_results: send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) if ( rc == LDAP_SUCCESS && !noop ) { LDAP_LIST_FOREACH ( ps_list, &bdb->psearch_list, link ) { - bdb_psearch( be, conn, op, ps_list, e, LCUP_PSEARCH_BY_ADD ); + bdb_psearch( be, conn, op, ps_list, e, LDAP_PSEARCH_BY_ADD ); } } #endif /* LDAP_CLIENT_UPDATE */ diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index 8ba473fe97..e306c86438 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -132,7 +132,7 @@ struct bdb_info { ID bi_lastid; ldap_pvt_thread_mutex_t bi_lastid_mutex; -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) LDAP_LIST_HEAD(pl, slap_op) psearch_list; #endif #ifdef SLAP_IDL_CACHE diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c index 5d7f432a13..e31f250f81 100644 --- a/servers/slapd/back-bdb/delete.c +++ b/servers/slapd/back-bdb/delete.c @@ -44,7 +44,7 @@ bdb_delete( int noop = 0; -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) Operation* ps_list; #endif @@ -493,13 +493,13 @@ retry: /* transaction retry */ return_results: send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) if ( rc == LDAP_SUCCESS && !noop ) { LDAP_LIST_FOREACH( ps_list, &bdb->psearch_list, link ) { - bdb_psearch( be, conn, op, ps_list, e, LCUP_PSEARCH_BY_DELETE ); + bdb_psearch( be, conn, op, ps_list, e, LDAP_PSEARCH_BY_DELETE ); } } -#endif /* LDAP_CLIENT_UPDATE */ +#endif if(rc == LDAP_SUCCESS && bdb->bi_txn_cp ) { ldap_pvt_thread_yield(); diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index 0ad31a1782..2f2bb16acc 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -95,7 +95,7 @@ bdb_db_init( BackendDB *be ) bdb->bi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH; bdb->bi_search_stack = NULL; -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) LDAP_LIST_INIT (&bdb->psearch_list); #endif diff --git a/servers/slapd/back-bdb/lcup.c b/servers/slapd/back-bdb/lcup.c index 099ee20279..6217c36514 100644 --- a/servers/slapd/back-bdb/lcup.c +++ b/servers/slapd/back-bdb/lcup.c @@ -13,20 +13,25 @@ #include "idl.h" #include "external.h" -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + +#define IS_BDB_REPLACE (( psearch_type == LDAP_PSEARCH_BY_DELETE ) || \ + ( psearch_type == LDAP_PSEARCH_BY_SCOPEOUT )) +#define IS_BDB_LCUP_REPLACE (( protocol == LDAP_CLIENT_UPDATE ) && IS_BDB_REPLACE ) static int psearch_base_candidate( BackendDB *be, - Entry *e, + Entry *e, ID *ids ); + static int psearch_candidates( - BackendDB *be, - Operation *op, - Entry *e, - Filter *filter, - int scope, - int deref, - ID *ids ); + BackendDB *be, + Operation *op, + Entry *e, + Filter *filter, + int scope, + int deref, + ID *ids ); int bdb_abandon( @@ -50,6 +55,39 @@ bdb_abandon( return LDAP_UNAVAILABLE; } +int +bdb_cancel( + BackendDB *be, + Connection *conn, + ber_int_t id ) +{ + Operation *ps_list; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + + LDAP_LIST_FOREACH ( ps_list, &bdb->psearch_list, link ) { + if ( ps_list->o_connid == conn->c_connid ) { + if ( ps_list->o_msgid == id ) { + ps_list->o_cancel = LDAP_CANCEL_DONE; + LDAP_LIST_REMOVE( ps_list, link ); + +#if 0 + bdb_build_sync_done_ctrl( conn, ps_list, ps_list->ctrls, 1, &latest_entrycsn_bv ); + send_search_result( conn, ps_list, LDAP_CANCELLED, + NULL, NULL, NULL, ps_list->ctrls, ps_list->nentries); +#endif + send_search_result( conn, ps_list, LDAP_CANCELLED, + NULL, NULL, NULL, NULL, 0); + + + + slap_op_free ( ps_list ); + return LDAP_SUCCESS; + } + } + } + return LDAP_UNAVAILABLE; +} + int bdb_add_psearch_spec( BackendDB *be, @@ -64,30 +102,33 @@ bdb_add_psearch_spec( Filter *filter, struct berval *fstr, AttributeName *attrs, - int attrsonly ) + int attrsonly, + int protocol ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; - LDAP_LIST_FIRST(&op->psearch_spec) = (struct lcup_search_spec *) - calloc ( 1, sizeof ( struct lcup_search_spec ) ); + LDAP_LIST_FIRST( &op->psearch_spec ) = (struct ldap_psearch_spec *) + calloc ( 1, sizeof ( struct ldap_psearch_spec ) ); - LDAP_LIST_FIRST(&op->psearch_spec)->op = op; + LDAP_LIST_FIRST( &op->psearch_spec )->op = op; - LDAP_LIST_FIRST(&op->psearch_spec)->base = ber_dupbv(NULL, base); - LDAP_LIST_FIRST(&op->psearch_spec)->nbase = ber_dupbv(NULL, nbase); + LDAP_LIST_FIRST( &op->psearch_spec )->base = ber_dupbv(NULL, base); + LDAP_LIST_FIRST( &op->psearch_spec )->nbase = ber_dupbv(NULL, nbase); - LDAP_LIST_FIRST(&op->psearch_spec)->scope = scope; - LDAP_LIST_FIRST(&op->psearch_spec)->deref = deref; - LDAP_LIST_FIRST(&op->psearch_spec)->slimit = slimit; - LDAP_LIST_FIRST(&op->psearch_spec)->tlimit = tlimit; + LDAP_LIST_FIRST( &op->psearch_spec )->scope = scope; + LDAP_LIST_FIRST( &op->psearch_spec )->deref = deref; + LDAP_LIST_FIRST( &op->psearch_spec )->slimit = slimit; + LDAP_LIST_FIRST( &op->psearch_spec )->tlimit = tlimit; - LDAP_LIST_FIRST(&op->psearch_spec)->filter = filter; - LDAP_LIST_FIRST(&op->psearch_spec)->filterstr = ber_dupbv(NULL, fstr); - LDAP_LIST_FIRST(&op->psearch_spec)->attrs = attrs; + LDAP_LIST_FIRST( &op->psearch_spec )->filter = filter; + LDAP_LIST_FIRST( &op->psearch_spec )->filterstr = ber_dupbv(NULL, fstr); + LDAP_LIST_FIRST( &op->psearch_spec )->attrs = attrs; - LDAP_LIST_FIRST(&op->psearch_spec)->attrsonly = attrsonly; + LDAP_LIST_FIRST( &op->psearch_spec )->attrsonly = attrsonly; - LDAP_LIST_FIRST(&op->psearch_spec)->entry_count = 0; + LDAP_LIST_FIRST( &op->psearch_spec )->entry_count = 0; + + LDAP_LIST_FIRST( &op->psearch_spec )->protocol = protocol; LDAP_LIST_INSERT_HEAD( &bdb->psearch_list, op, link ); } @@ -99,26 +140,29 @@ bdb_psearch( Operation *op, Operation *ps_op, Entry *entry, - int psearch_type ) + int psearch_type ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; - const char *text = NULL; + const char *text = NULL; time_t stoptime; unsigned cursor; ID id; ID candidates[BDB_IDL_UM_SIZE]; Entry *e = NULL; - BerVarray v2refs = NULL; - Entry *matched = NULL; + BerVarray v2refs = NULL; + Entry *matched = NULL; struct berval realbase = { 0, NULL }; int nentries = 0; int manageDSAit; - Filter lcupf, csnfnot, csnfeq, csnfand, csnfge; - AttributeAssertion aa_ge, aa_eq; - struct berval entrycsn_bv = { 0, NULL }; - struct berval latest_entrycsn_bv = { 0, NULL }; + Filter cookief, csnfnot, csnfeq, csnfand, csnfge; + AttributeAssertion aa_ge, aa_eq; + struct berval entrycsn_bv = { 0, NULL }; + struct berval latest_entrycsn_bv = { 0, NULL }; + + LDAPControl *ctrls[SLAP_SEARCH_MAX_CTRLS]; + int num_ctrls = 0; struct slap_limits_set *limit = NULL; int isroot = 0; @@ -128,31 +172,18 @@ bdb_psearch( DB_LOCK lock; Connection *ps_conn = ps_op->o_conn; - struct berval *base = LDAP_LIST_FIRST(&ps_op->psearch_spec)->base; - struct berval *nbase = LDAP_LIST_FIRST(&ps_op->psearch_spec)->nbase; - int scope = LDAP_LIST_FIRST(&ps_op->psearch_spec)->scope; - int deref = LDAP_LIST_FIRST(&ps_op->psearch_spec)->deref; - int slimit = LDAP_LIST_FIRST(&ps_op->psearch_spec)->slimit; - int tlimit = LDAP_LIST_FIRST(&ps_op->psearch_spec)->tlimit; - Filter *filter = LDAP_LIST_FIRST(&ps_op->psearch_spec)->filter; - struct berval *filterstr = LDAP_LIST_FIRST(&ps_op->psearch_spec)->filterstr; - int attrsonly = LDAP_LIST_FIRST(&ps_op->psearch_spec)->attrsonly; + struct berval *base = LDAP_LIST_FIRST( &ps_op->psearch_spec )->base; + struct berval *nbase = LDAP_LIST_FIRST( &ps_op->psearch_spec )->nbase; + int scope = LDAP_LIST_FIRST( &ps_op->psearch_spec )->scope; + int deref = LDAP_LIST_FIRST( &ps_op->psearch_spec )->deref; + int slimit = LDAP_LIST_FIRST( &ps_op->psearch_spec )->slimit; + int tlimit = LDAP_LIST_FIRST( &ps_op->psearch_spec )->tlimit; + Filter *filter = LDAP_LIST_FIRST( &ps_op->psearch_spec )->filter; + struct berval *filterstr = LDAP_LIST_FIRST( &ps_op->psearch_spec )->filterstr; + int attrsonly = LDAP_LIST_FIRST( &ps_op->psearch_spec )->attrsonly; + int protocol = LDAP_LIST_FIRST( &ps_op->psearch_spec )->protocol; AttributeName uuid_attr[2]; - AttributeName *attrs = uuid_attr; - - if ( psearch_type != LCUP_PSEARCH_BY_DELETE && - psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) - { - attrs = LDAP_LIST_FIRST(&ps_op->psearch_spec)->attrs; - } else { - attrs[0].an_desc = slap_schema.si_ad_entryUUID; - attrs[0].an_oc = NULL; - ber_dupbv( &attrs[0].an_name, &attrs[0].an_desc->ad_cname ); - attrs[1].an_desc = NULL; - attrs[1].an_oc = NULL; - attrs[1].an_name.bv_len = 0; - attrs[1].an_name.bv_val = NULL; - } + AttributeName *attrs; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ENTRY, "bdb_back_search\n", 0, 0, 0 ); @@ -170,10 +201,41 @@ bdb_psearch( default: send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER, NULL, "internal error", NULL, NULL ); - if ( psearch_type == LCUP_PSEARCH_BY_DELETE || - psearch_type == LCUP_PSEARCH_BY_SCOPEOUT ) - ch_free( attrs[0].an_name.bv_val ); return rc; + } + + for ( num_ctrls = 0; num_ctrls < SLAP_SEARCH_MAX_CTRLS; num_ctrls++ ) + ctrls[num_ctrls] = NULL; + num_ctrls = 0; + + if ( !IS_BDB_REPLACE ) { + attrs = LDAP_LIST_FIRST(&ps_op->psearch_spec)->attrs; + } else { +#ifdef LDAP_CLIENT_UPDATE + if ( protocol == LDAP_CLIENT_UPDATE ) { + attrs = uuid_attr; + attrs[0].an_desc = slap_schema.si_ad_entryUUID; + attrs[0].an_oc = NULL; + ber_dupbv( &attrs[0].an_name, &attrs[0].an_desc->ad_cname ); + attrs[1].an_desc = NULL; + attrs[1].an_oc = NULL; + attrs[1].an_name.bv_len = 0; + attrs[1].an_name.bv_val = NULL; + } else +#endif +#ifdef LDAP_SYNC + if (protocol == LDAP_SYNC ) { + attrs = uuid_attr; + attrs[0].an_desc = NULL; + attrs[0].an_oc = NULL; + attrs[0].an_name.bv_len = 0; + attrs[0].an_name.bv_val = NULL; + } else +#endif + { + rc = 1; + goto done; + } } if ( nbase->bv_len == 0 ) { @@ -209,9 +271,10 @@ dn2entry_retry: send_ldap_result( ps_conn, ps_op, LDAP_BUSY, NULL, "ldap server busy", NULL, NULL ); LOCK_ID_FREE( bdb->bi_dbenv, locker ); - if ( psearch_type == LCUP_PSEARCH_BY_DELETE || - psearch_type == LCUP_PSEARCH_BY_SCOPEOUT ) +#ifdef LDAP_CLIENT_UPDATE + if ( IS_BDB_LCUP_REPLACE ) ch_free( attrs[0].an_name.bv_val ); +#endif return LDAP_BUSY; case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: @@ -228,9 +291,10 @@ dn2entry_retry: send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER, NULL, "internal error", NULL, NULL ); LOCK_ID_FREE( bdb->bi_dbenv, locker ); - if ( psearch_type == LCUP_PSEARCH_BY_DELETE || - psearch_type == LCUP_PSEARCH_BY_SCOPEOUT ) +#ifdef LDAP_CLIENT_UPDATE + if ( IS_BDB_LCUP_REPLACE ) ch_free( attrs[0].an_name.bv_val ); +#endif return rc; } @@ -267,9 +331,10 @@ dn2entry_retry: LOCK_ID_FREE( bdb->bi_dbenv, locker ); if ( refs ) ber_bvarray_free( refs ); if ( matched_dn.bv_val ) ber_memfree( matched_dn.bv_val ); - if ( psearch_type == LCUP_PSEARCH_BY_DELETE || - psearch_type == LCUP_PSEARCH_BY_SCOPEOUT ) +#ifdef LDAP_CLIENT_UPDATE + if ( IS_BDB_LCUP_REPLACE ) ch_free( attrs[0].an_name.bv_val ); +#endif return rc; } @@ -307,9 +372,10 @@ dn2entry_retry: LOCK_ID_FREE( bdb->bi_dbenv, locker ); ber_bvarray_free( refs ); ber_memfree( matched_dn.bv_val ); - if ( psearch_type == LCUP_PSEARCH_BY_DELETE || - psearch_type == LCUP_PSEARCH_BY_SCOPEOUT ) +#ifdef LDAP_CLIENT_UPDATE + if ( IS_BDB_LCUP_REPLACE ) ch_free( attrs[0].an_name.bv_val ); +#endif return 1; } @@ -444,28 +510,61 @@ dn2entry_retry: } } - lcupf.f_choice = LDAP_FILTER_AND; - lcupf.f_and = &csnfnot; - lcupf.f_next = NULL; - - csnfnot.f_choice = LDAP_FILTER_NOT; - csnfnot.f_not = &csnfeq; - csnfnot.f_next = &csnfand; - - csnfeq.f_choice = LDAP_FILTER_EQUALITY; - csnfeq.f_ava = &aa_eq; - csnfeq.f_av_desc = slap_schema.si_ad_entryCSN; - ber_dupbv( &csnfeq.f_av_value, &ps_op->o_clientupdate_state ); - - csnfand.f_choice = LDAP_FILTER_AND; - csnfand.f_and = &csnfge; - csnfand.f_next = NULL; - - csnfge.f_choice = LDAP_FILTER_GE; - csnfge.f_ava = &aa_ge; - csnfge.f_av_desc = slap_schema.si_ad_entryCSN; - ber_dupbv( &csnfge.f_av_value, &ps_op->o_clientupdate_state ); - csnfge.f_next = filter; +#ifdef LDAP_CLIENT_UPDATE + if ( protocol == LDAP_CLIENT_UPDATE ) { + cookief.f_choice = LDAP_FILTER_AND; + cookief.f_and = &csnfnot; + cookief.f_next = NULL; + + csnfnot.f_choice = LDAP_FILTER_NOT; + csnfnot.f_not = &csnfeq; + csnfnot.f_next = &csnfand; + + csnfeq.f_choice = LDAP_FILTER_EQUALITY; + csnfeq.f_ava = &aa_eq; + csnfeq.f_av_desc = slap_schema.si_ad_entryCSN; + ber_dupbv( &csnfeq.f_av_value, &ps_op->o_clientupdate_state ); + + csnfand.f_choice = LDAP_FILTER_AND; + csnfand.f_and = &csnfge; + csnfand.f_next = NULL; + + csnfge.f_choice = LDAP_FILTER_GE; + csnfge.f_ava = &aa_ge; + csnfge.f_av_desc = slap_schema.si_ad_entryCSN; + ber_dupbv( &csnfge.f_av_value, &ps_op->o_clientupdate_state ); + csnfge.f_next = filter; + } +#endif +#if defined(LDAP_CLIENT_UPDATE) && defined(LDAP_SYNC) + else +#endif +#ifdef LDAP_SYNC + if ( protocol == LDAP_SYNC ) { + cookief.f_choice = LDAP_FILTER_AND; + cookief.f_and = &csnfnot; + cookief.f_next = NULL; + + csnfnot.f_choice = LDAP_FILTER_NOT; + csnfnot.f_not = &csnfeq; + csnfnot.f_next = &csnfand; + + csnfeq.f_choice = LDAP_FILTER_EQUALITY; + csnfeq.f_ava = &aa_eq; + csnfeq.f_av_desc = slap_schema.si_ad_entryCSN; + ber_dupbv( &csnfeq.f_av_value, &ps_op->o_sync_state ); + + csnfand.f_choice = LDAP_FILTER_AND; + csnfand.f_and = &csnfge; + csnfand.f_next = NULL; + + csnfge.f_choice = LDAP_FILTER_GE; + csnfge.f_ava = &aa_ge; + csnfge.f_av_desc = slap_schema.si_ad_entryCSN; + ber_dupbv( &csnfge.f_av_value, &ps_op->o_sync_state ); + csnfge.f_next = filter; + } +#endif id = entry->e_id; @@ -604,8 +703,8 @@ dn2entry_retry: goto test_done; } - if ( psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) { - rc = test_filter( be, ps_conn, ps_op, e, &lcupf ); + if ( psearch_type != LDAP_PSEARCH_BY_SCOPEOUT ) { + rc = test_filter( be, ps_conn, ps_op, e, &cookief ); } else { rc = LDAP_COMPARE_TRUE; } @@ -647,144 +746,87 @@ dn2entry_retry: } else #endif { - if ( psearch_type == LCUP_PSEARCH_BY_ADD || - psearch_type == LCUP_PSEARCH_BY_DELETE || - psearch_type == LCUP_PSEARCH_BY_MODIFY || - psearch_type == LCUP_PSEARCH_BY_SCOPEOUT ) - { - Attribute* a; - int ret; - int res; - const char *text = NULL; - LDAPControl *ctrls[2]; - struct berval *bv; - char berbuf[LBER_ELEMENT_SIZEOF]; - BerElement *ber = (BerElement *)berbuf; - - ber_init2( ber, NULL, LBER_USE_DER ); - - LDAP_LIST_FIRST(&ps_op->psearch_spec)->entry_count++; - - ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) ); - ctrls[1] = NULL; - - if ( LDAP_LIST_FIRST( - &ps_op->psearch_spec)->entry_count % - ps_op->o_clientupdate_interval == 0 ) - { - /* Send cookie */ - for ( a = e->e_attrs; a != NULL; a = a->a_next ) { - AttributeDescription *desc = a->a_desc; - if ( desc == slap_schema.si_ad_entryCSN ) { - ber_dupbv( &entrycsn_bv, &a->a_vals[0] ); - if ( latest_entrycsn_bv.bv_val == NULL ) { - ber_dupbv( &latest_entrycsn_bv, - &entrycsn_bv ); - } else { - res = value_match( &ret, desc, - desc->ad_type->sat_ordering, - SLAP_MR_ASSERTION_SYNTAX_MATCH, - &entrycsn_bv, &latest_entrycsn_bv, - &text ); - if ( res != LDAP_SUCCESS ) { - ret = 0; -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: " - "value_match failed\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_search: " - "value_match failed\n", - 0, 0, 0 ); -#endif - } - - if ( ret > 0 ) { - ch_free(latest_entrycsn_bv.bv_val); - latest_entrycsn_bv.bv_val = NULL; - ber_dupbv( &latest_entrycsn_bv, - &entrycsn_bv ); - } - } - } - } - - if ( psearch_type != LCUP_PSEARCH_BY_DELETE || - psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) - { - ber_printf( ber, "{bb{sON}N}", - SLAP_LCUP_STATE_UPDATE_FALSE, - SLAP_LCUP_ENTRY_DELETED_FALSE, - LCUP_COOKIE_OID, &entrycsn_bv ); - } else { - ber_printf( ber, "{bb{sON}N}", - SLAP_LCUP_STATE_UPDATE_FALSE, - SLAP_LCUP_ENTRY_DELETED_TRUE, - LCUP_COOKIE_OID, &entrycsn_bv ); - } - - ch_free( entrycsn_bv.bv_val ); - entrycsn_bv.bv_val = NULL; - - } else { - /* Do not send cookie */ - if ( psearch_type != LCUP_PSEARCH_BY_DELETE || - psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) - { - ber_printf( ber, "{bbN}", - SLAP_LCUP_STATE_UPDATE_FALSE, - SLAP_LCUP_ENTRY_DELETED_FALSE ); - } else { - ber_printf( ber, "{bbN}", - SLAP_LCUP_STATE_UPDATE_FALSE, - SLAP_LCUP_ENTRY_DELETED_TRUE ); - } - } - - ctrls[0]->ldctl_oid = LDAP_CONTROL_ENTRY_UPDATE; - ctrls[0]->ldctl_iscritical = ps_op->o_clientupdate; - ret = ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ); - - if ( ret < 0 ) { - ber_free_buf( ber ); -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: ber_flatten2 failed\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_search: ber_flatten2 failed\n", - 0, 0, 0 ); +#ifdef LDAP_SYNC + int premodify_found = 0; + int entry_sync_state; #endif - send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER, - NULL, "internal error", NULL, NULL ); - goto done; - } - - result = send_search_entry( be, ps_conn, ps_op, - e, attrs, attrsonly, ctrls); - - ber_free_buf( ber ); - ch_free( ctrls[0] ); - if ( psearch_type == LCUP_PSEARCH_BY_MODIFY ) { + if ( psearch_type == LDAP_PSEARCH_BY_ADD || + psearch_type == LDAP_PSEARCH_BY_DELETE || + psearch_type == LDAP_PSEARCH_BY_MODIFY || + psearch_type == LDAP_PSEARCH_BY_SCOPEOUT ) + { + if ( psearch_type == LDAP_PSEARCH_BY_MODIFY ) { struct psid_entry* psid_e; - LDAP_LIST_FOREACH( psid_e, &op->premodify_list, - link) + LDAP_LIST_FOREACH( psid_e, &op->premodify_list, link) { - if( psid_e->ps == - LDAP_LIST_FIRST(&ps_op->psearch_spec)) + if( psid_e->ps == LDAP_LIST_FIRST(&ps_op->psearch_spec)) { +#ifdef LDAP_SYNC + premodify_found = 1; +#endif LDAP_LIST_REMOVE(psid_e, link); break; } } if (psid_e != NULL) free (psid_e); } +#ifdef LDAP_SYNC + if ( psearch_type == LDAP_PSEARCH_BY_ADD ) + entry_sync_state = LDAP_SYNC_ADD; + else if ( psearch_type == LDAP_PSEARCH_BY_DELETE ) + entry_sync_state = LDAP_SYNC_DELETE; + else if ( psearch_type == LDAP_PSEARCH_BY_MODIFY ) { + if ( premodify_found ) + entry_sync_state = LDAP_SYNC_MODIFY; + else + entry_sync_state = LDAP_SYNC_ADD; + } else if ( psearch_type == LDAP_PSEARCH_BY_SCOPEOUT ) + entry_sync_state = LDAP_SYNC_DELETE; + else { + rc = 1; + goto done; + } +#endif + +#ifdef LDAP_CLIENT_UPDATE + if ( protocol == LDAP_CLIENT_UPDATE ) { + int entry_count = ++(LDAP_LIST_FIRST(&ps_op->psearch_spec)->entry_count); + if ( IS_BDB_REPLACE ) { + rc = bdb_build_lcup_update_ctrl( ps_conn, ps_op, e, entry_count, ctrls, + num_ctrls++, &latest_entrycsn_bv, SLAP_LCUP_ENTRY_DELETED_TRUE ); + } else { + rc = bdb_build_lcup_update_ctrl( ps_conn, ps_op, e, entry_count, ctrls, + num_ctrls++, &latest_entrycsn_bv, SLAP_LCUP_ENTRY_DELETED_FALSE ); + } + if ( rc != LDAP_SUCCESS ) + goto done; + result = send_search_entry( be, ps_conn, ps_op, e, attrs, attrsonly, ctrls ); + if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL ) + ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); + ch_free( ctrls[--num_ctrls] ); + ctrls[num_ctrls] = NULL; + } else +#endif +#ifdef LDAP_SYNC + if ( protocol == LDAP_SYNC ) { + rc = bdb_build_sync_state_ctrl( ps_conn, ps_op, e, entry_sync_state, ctrls, + num_ctrls++, 1, &latest_entrycsn_bv ); + if ( rc != LDAP_SUCCESS ) + goto done; + result = send_search_entry( be, ps_conn, ps_op, e, attrs, attrsonly, ctrls ); + if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL ) + ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); + ch_free( ctrls[--num_ctrls] ); + ctrls[num_ctrls] = NULL; + } else +#endif + { + rc = 1; + goto done; + } - } else if ( psearch_type == LCUP_PSEARCH_BY_PREMODIFY ) { + } else if ( psearch_type == LDAP_PSEARCH_BY_PREMODIFY ) { struct psid_entry* psid_e; psid_e = (struct psid_entry *) calloc (1, sizeof(struct psid_entry)); @@ -844,9 +886,10 @@ done: if( v2refs ) ber_bvarray_free( v2refs ); if( realbase.bv_val ) ch_free( realbase.bv_val ); - if ( psearch_type == LCUP_PSEARCH_BY_DELETE || - psearch_type == LCUP_PSEARCH_BY_SCOPEOUT ) +#ifdef LDAP_CLIENT_UPDATE + if ( IS_BDB_LCUP_REPLACE ) ch_free( attrs[0].an_name.bv_val ); +#endif return rc; } @@ -1034,4 +1077,4 @@ static int psearch_candidates( } -#endif /* LDAP_CLIENT_UPDATE */ +#endif diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c index 92f376fa17..400b143596 100644 --- a/servers/slapd/back-bdb/modify.c +++ b/servers/slapd/back-bdb/modify.c @@ -277,7 +277,7 @@ bdb_modify( int noop = 0; -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) Operation* ps_list; struct psid_entry* pm_list; struct psid_entry* pm_prev; @@ -302,7 +302,7 @@ retry: /* transaction retry */ "bdb_modify: retrying...\n", 0, 0, 0); #endif -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) pm_list = LDAP_LIST_FIRST(&op->premodify_list); while ( pm_list != NULL ) { LDAP_LIST_REMOVE ( pm_list, link ); @@ -423,13 +423,13 @@ retry: /* transaction retry */ goto done; } -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) if ( rc == LDAP_SUCCESS && !op->o_noop ) { LDAP_LIST_FOREACH ( ps_list, &bdb->psearch_list, link ) { - bdb_psearch(be, conn, op, ps_list, e, LCUP_PSEARCH_BY_PREMODIFY ); + bdb_psearch(be, conn, op, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY ); } } -#endif /* LDAP_CLIENT_UPDATE */ +#endif /* Modify the entry */ rc = bdb_modify_internal( be, conn, op, ltid, modlist, e, @@ -518,23 +518,23 @@ return_results: send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) if ( rc == LDAP_SUCCESS && !op->o_noop ) { /* Loop through in-scope entries for each psearch spec */ LDAP_LIST_FOREACH ( ps_list, &bdb->psearch_list, link ) { - bdb_psearch( be, conn, op, ps_list, e, LCUP_PSEARCH_BY_MODIFY ); + bdb_psearch( be, conn, op, ps_list, e, LDAP_PSEARCH_BY_MODIFY ); } pm_list = LDAP_LIST_FIRST(&op->premodify_list); while ( pm_list != NULL ) { bdb_psearch(be, conn, op, pm_list->ps->op, - e, LCUP_PSEARCH_BY_SCOPEOUT); + e, LDAP_PSEARCH_BY_SCOPEOUT); LDAP_LIST_REMOVE ( pm_list, link ); pm_prev = pm_list; pm_list = LDAP_LIST_NEXT ( pm_list, link ); free (pm_prev); } } -#endif /* LDAP_CLIENT_UPDATE */ +#endif if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) { ldap_pvt_thread_yield(); @@ -544,7 +544,7 @@ return_results: done: if( ltid != NULL ) { -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) pm_list = LDAP_LIST_FIRST(&op->premodify_list); while ( pm_list != NULL ) { LDAP_LIST_REMOVE ( pm_list, link ); diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c index 60019a5264..23d4d6cb84 100644 --- a/servers/slapd/back-bdb/modrdn.c +++ b/servers/slapd/back-bdb/modrdn.c @@ -62,7 +62,7 @@ bdb_modrdn( int noop = 0; -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) Operation* ps_list; struct psid_entry* pm_list; struct psid_entry* pm_prev; @@ -95,7 +95,7 @@ retry: /* transaction retry */ Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn: retrying...\n", 0, 0, 0 ); #endif -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) pm_list = LDAP_LIST_FIRST(&op->premodify_list); while ( pm_list != NULL ) { LDAP_LIST_REMOVE ( pm_list, link ); @@ -731,13 +731,13 @@ retry: /* transaction retry */ goto return_results; } -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) if ( rc == LDAP_SUCCESS && !op->o_noop ) { LDAP_LIST_FOREACH ( ps_list, &bdb->psearch_list, link ) { - bdb_psearch(be, conn, op, ps_list, e, LCUP_PSEARCH_BY_PREMODIFY ); + bdb_psearch(be, conn, op, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY ); } } -#endif /* LDAP_CLIENT_UPDATE */ +#endif /* modify entry */ rc = bdb_modify_internal( be, conn, op, ltid, &mod[0], e, @@ -833,23 +833,23 @@ return_results: send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) if ( rc == LDAP_SUCCESS && !op->o_noop ) { /* Loop through in-scope entries for each psearch spec */ LDAP_LIST_FOREACH ( ps_list, &bdb->psearch_list, link ) { - bdb_psearch( be, conn, op, ps_list, e, LCUP_PSEARCH_BY_MODIFY ); + bdb_psearch( be, conn, op, ps_list, e, LDAP_PSEARCH_BY_MODIFY ); } pm_list = LDAP_LIST_FIRST(&op->premodify_list); while ( pm_list != NULL ) { bdb_psearch(be, conn, op, pm_list->ps->op, - e, LCUP_PSEARCH_BY_SCOPEOUT); + e, LDAP_PSEARCH_BY_SCOPEOUT); LDAP_LIST_REMOVE ( pm_list, link ); pm_prev = pm_list; pm_list = LDAP_LIST_NEXT ( pm_list, link ); free (pm_prev); } } -#endif /* LDAP_CLIENT_UPDATE */ +#endif if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) { ldap_pvt_thread_yield(); @@ -893,7 +893,7 @@ done: } if( ltid != NULL ) { -#ifdef LDAP_CLIENT_UPDATE +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) pm_list = LDAP_LIST_FIRST(&op->premodify_list); while ( pm_list != NULL ) { LDAP_LIST_REMOVE ( pm_list, link ); diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h index 9365b4f3b2..5ec4228d43 100644 --- a/servers/slapd/back-bdb/proto-bdb.h +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -364,13 +364,19 @@ int bdb_cache_delete_entry( ); void bdb_cache_release_all( Cache *cache ); +/* + * lcup.c + */ + #ifdef LDAP_CLIENT_UPDATE int bdb_abandon( BackendDB *be, Connection *conn, ber_int_t id ); +#endif +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) int bdb_add_psearch_spec( BackendDB *be, Connection *conn, @@ -384,7 +390,8 @@ int bdb_add_psearch_spec( Filter *filter, struct berval *fstr, AttributeName *attrs, - int attrsonly + int attrsonly, + int protocol ); int bdb_psearch( @@ -395,7 +402,66 @@ int bdb_psearch( Entry *entry, int psearch_type ); +#endif + +/* + * search.c + */ +#ifdef LDAP_CLIENT_UPDATE +int +bdb_build_lcup_update_ctrl( + Connection *conn, + Operation *op, + Entry *e, + int entry_count, + LDAPControl **ctrls, + int num_ctrls, + struct berval *latest_entrycsn_bv, + int isdeleted ); + +int +bdb_build_lcup_done_ctrl( + Connection *conn, + Operation *op, + LDAPControl **ctrls, + int num_ctrls, + struct berval *latest_entrycsn_bv ); +#endif + +#ifdef LDAP_SYNC +int +bdb_build_sync_state_ctrl( + Connection *conn, + Operation *op, + Entry *e, + int entry_sync_state, + LDAPControl **ctrls, + int num_ctrls, + int send_cookie, + struct berval *latest_entrycsn_bv ); + +int +bdb_build_sync_done_ctrl( + Connection *conn, + Operation *op, + LDAPControl **ctrls, + int num_ctrls, + int send_cookie, + struct berval *latest_entrycsn_bv ); + +int +bdb_send_ldap_intermediate( + Connection *conn, + Operation *op, + ber_int_t err, + const char *matched, + const char *text, + BerVarray refs, + const char *rspoid, + int state, + struct berval *cookie, + LDAPControl **ctrls ); #endif #ifdef BDB_REUSE_LOCKERS diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 9916cdb22e..14df815a20 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -65,13 +65,20 @@ bdb_search( int tentries = 0; ID lastid = NOID; -#ifdef LDAP_CLIENT_UPDATE - Filter lcupf, csnfnot, csnfeq, csnfand, csnfge; +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + Filter cookief, csnfnot, csnfeq, csnfand, csnfge; AttributeAssertion aa_ge, aa_eq; int entry_count = 0; - struct berval entrycsn_bv = { 0, NULL }; - struct berval latest_entrycsn_bv = { 0, NULL }; -#endif /* LDAP_CLIENT_UPDATE */ + struct berval latest_entrycsn_bv = { 0, NULL }; + LDAPControl *ctrls[SLAP_SEARCH_MAX_CTRLS]; + int num_ctrls = 0; +#endif + +#ifdef LDAP_SYNC + int rc_sync = 0; + int entry_sync_state; + AttributeName null_attr; +#endif struct slap_limits_set *limit = NULL; int isroot = 0; @@ -88,11 +95,32 @@ bdb_search( #ifdef LDAP_CLIENT_UPDATE if ( op->o_clientupdate_type & SLAP_LCUP_PERSIST ) { - bdb_add_psearch_spec( be, conn, op, base, base, scope, - deref, slimit, tlimit, filter, filterstr, attrs, attrsonly ); + bdb_add_psearch_spec( be, conn, op, base, base, scope, deref, slimit, + tlimit, filter, filterstr, attrs, attrsonly, LDAP_CLIENT_UPDATE ); return LDAP_SUCCESS; } #endif +#if defined(LDAP_CLIENT_UPDATE) && defined(LDAP_SYNC) + else +#endif +#ifdef LDAP_SYNC + /* psearch needs to be registered before refresh begins */ + /* psearch and refresh transmission is serialized in send_ldap_ber() */ + if ( op->o_sync_mode & SLAP_SYNC_PERSIST ) { + bdb_add_psearch_spec( be, conn, op, base, base, scope, deref, slimit, + tlimit, filter, filterstr, attrs, attrsonly, LDAP_SYNC ); + } + null_attr.an_desc = NULL; + null_attr.an_oc = NULL; + null_attr.an_name.bv_len = 0; + null_attr.an_name.bv_val = NULL; +#endif + +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + for ( num_ctrls = 0; num_ctrls < SLAP_SEARCH_MAX_CTRLS; num_ctrls++ ) + ctrls[num_ctrls] = NULL; + num_ctrls = 0; +#endif manageDSAit = get_manageDSAit( op ); @@ -394,9 +422,9 @@ dn2entry_retry: #ifdef LDAP_CLIENT_UPDATE if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) { - lcupf.f_choice = LDAP_FILTER_AND; - lcupf.f_and = &csnfnot; - lcupf.f_next = NULL; + cookief.f_choice = LDAP_FILTER_AND; + cookief.f_and = &csnfnot; + cookief.f_next = NULL; csnfnot.f_choice = LDAP_FILTER_NOT; csnfnot.f_not = &csnfeq; @@ -417,7 +445,36 @@ dn2entry_retry: ber_dupbv( &csnfge.f_av_value, &op->o_clientupdate_state ); csnfge.f_next = filter; } -#endif /* LDAP_CLIENT_UPDATE */ +#endif +#if defined(LDAP_CLIENT_UPDATE) && defined(LDAP_SYNC) + else +#endif +#ifdef LDAP_SYNC + if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) { + cookief.f_choice = LDAP_FILTER_AND; + cookief.f_and = &csnfnot; + cookief.f_next = NULL; + + csnfnot.f_choice = LDAP_FILTER_NOT; + csnfnot.f_not = &csnfeq; + csnfnot.f_next = &csnfand; + + csnfeq.f_choice = LDAP_FILTER_EQUALITY; + csnfeq.f_ava = &aa_eq; + csnfeq.f_av_desc = slap_schema.si_ad_entryCSN; + ber_dupbv( &csnfeq.f_av_value, &op->o_sync_state ); + + csnfand.f_choice = LDAP_FILTER_AND; + csnfand.f_and = &csnfge; + csnfand.f_next = NULL; + + csnfge.f_choice = LDAP_FILTER_GE; + csnfge.f_ava = &aa_ge; + csnfge.f_av_desc = slap_schema.si_ad_entryCSN; + ber_dupbv( &csnfge.f_av_value, &op->o_sync_state ); + csnfge.f_next = filter; + } +#endif for ( id = bdb_idl_first( candidates, &cursor ); id != NOID; @@ -601,9 +658,22 @@ id2entry_retry: /* if it matches the filter and scope, send it */ #ifdef LDAP_CLIENT_UPDATE if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) { - rc = test_filter( be, conn, op, e, &lcupf ); + rc = test_filter( be, conn, op, e, &cookief ); + } else +#endif +#ifdef LDAP_SYNC + if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) { + rc_sync = test_filter( be, conn, op, e, &cookief ); + rc = test_filter( be, conn, op, e, filter ); + if ( rc == LDAP_COMPARE_TRUE ) { + if ( rc_sync == LDAP_COMPARE_TRUE ) { + entry_sync_state = LDAP_SYNC_ADD; + } else { + entry_sync_state = LDAP_SYNC_PRESENT; + } + } } else -#endif /* LDAP_CLIENT_UPDATE */ +#endif { rc = test_filter( be, conn, op, e, filter ); } @@ -658,100 +728,41 @@ id2entry_retry: { #ifdef LDAP_CLIENT_UPDATE if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) { - Attribute* a; - int ret; - int res; - const char *text = NULL; - LDAPControl *ctrls[2]; - char berbuf[LBER_ELEMENT_SIZEOF]; - BerElement *ber = (BerElement *)berbuf; - - ber_init2( ber, 0, LBER_USE_DER ); - - entry_count++; - - ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) ); - ctrls[1] = NULL; - - if ( entry_count % op->o_clientupdate_interval == 0 ) { - /* Send cookie */ - for ( a = e->e_attrs; a != NULL; a = a->a_next ) { - AttributeDescription *desc = a->a_desc; - if ( desc == slap_schema.si_ad_entryCSN ) { - ber_dupbv( &entrycsn_bv, &a->a_vals[0] ); - if ( latest_entrycsn_bv.bv_val == NULL ) { - ber_dupbv( &latest_entrycsn_bv, &entrycsn_bv ); - } else { - res = value_match( &ret, desc, - desc->ad_type->sat_ordering, - SLAP_MR_ASSERTION_SYNTAX_MATCH, - &entrycsn_bv, &latest_entrycsn_bv, &text ); - if ( res != LDAP_SUCCESS ) { - ret = 0; -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: value_match failed\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_search: value_match failed\n", - 0, 0, 0 ); -#endif - } - - if ( ret > 0 ) { - ch_free( latest_entrycsn_bv.bv_val ); - latest_entrycsn_bv.bv_val = NULL; - ber_dupbv( &latest_entrycsn_bv, - &entrycsn_bv ); - } - } - } - } - - ber_printf( ber, - "{bb{sON}N}", - SLAP_LCUP_STATE_UPDATE_FALSE, - SLAP_LCUP_ENTRY_DELETED_FALSE, - LCUP_COOKIE_OID, &entrycsn_bv ); - - ch_free( entrycsn_bv.bv_val ); - entrycsn_bv.bv_val = NULL; - - } else { - /* Do not send cookie */ - ber_printf( ber, - "{bbN}", - SLAP_LCUP_STATE_UPDATE_FALSE, - SLAP_LCUP_ENTRY_DELETED_FALSE ); - } + rc = bdb_build_lcup_update_ctrl( conn, op, e, ++entry_count, ctrls, + num_ctrls++, &latest_entrycsn_bv, SLAP_LCUP_ENTRY_DELETED_FALSE ); + if ( rc != LDAP_SUCCESS ) + goto done; + result = send_search_entry( be, conn, op, + e, attrs, attrsonly, ctrls); - ctrls[0]->ldctl_oid = LDAP_CONTROL_ENTRY_UPDATE; - ctrls[0]->ldctl_iscritical = op->o_clientupdate; - ret = ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ); - if ( ret < 0 ) { - ber_free_buf( ber ); -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: ber_flatten2 failed\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_search: ber_flatten2 failed\n", - 0, 0, 0 ); + if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL ) + ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); + ch_free( ctrls[--num_ctrls] ); + ctrls[num_ctrls] = NULL; + } else #endif - send_ldap_result( conn, op, rc=LDAP_OTHER, - NULL, "internal error", NULL, NULL ); +#ifdef LDAP_SYNC + if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) { + rc = bdb_build_sync_state_ctrl( conn, op, e, entry_sync_state, ctrls, + num_ctrls++, 0, &latest_entrycsn_bv ); + if ( rc != LDAP_SUCCESS ) goto done; - } - result = send_search_entry( be, conn, op, - e, attrs, attrsonly, ctrls); + if ( rc_sync == LDAP_COMPARE_TRUE ) { /* ADD */ + result = send_search_entry( be, conn, op, + e, attrs, attrsonly, ctrls); + } else { /* PRESENT */ + result = send_search_entry( be, conn, op, + e, &null_attr, attrsonly, ctrls); + } - ber_free_buf( ber ); - ch_free( ctrls[0] ); + if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL ) + ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); + ch_free( ctrls[--num_ctrls] ); + ctrls[num_ctrls] = NULL; } else -#endif /* LDAP_CLIENT_UPDATE */ +#endif + { result = send_search_entry( be, conn, op, e, attrs, attrsonly, NULL); @@ -806,47 +817,44 @@ loop_continue: #ifdef LDAP_CLIENT_UPDATE if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) { - int ret; - LDAPControl *ctrls[2]; - char berbuf[LBER_ELEMENT_SIZEOF]; - BerElement *ber = (BerElement *)berbuf; - - ber_init2( ber, NULL, LBER_USE_DER ); + bdb_build_lcup_done_ctrl( conn, op, ctrls, num_ctrls++, &latest_entrycsn_bv ); - ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) ); - ctrls[1] = NULL; - - ber_printf( ber, "{sO", LCUP_COOKIE_OID, &latest_entrycsn_bv ); - ber_printf( ber, "N}" ); + send_search_result( conn, op, + v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, + NULL, NULL, v2refs, ctrls, nentries ); - ctrls[0]->ldctl_oid = LDAP_CONTROL_CLIENT_UPDATE_DONE; - ctrls[0]->ldctl_iscritical = op->o_clientupdate; - ret = ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ); + ch_free( latest_entrycsn_bv.bv_val ); + latest_entrycsn_bv.bv_val = NULL; - if ( ret < 0 ) { - ber_free_buf( ber ); -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: ber_flatten2 failed\n", 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, "bdb_search: ber_flatten2 failed\n", - 0, 0, 0 ); + if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL ) + ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); + ch_free( ctrls[--num_ctrls] ); + ctrls[num_ctrls] = NULL; + } else #endif - send_ldap_result( conn, op, rc=LDAP_OTHER, - NULL, "internal error", NULL, NULL ); - goto done; +#ifdef LDAP_SYNC + if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) { + if ( op->o_sync_mode & SLAP_SYNC_PERSIST ) { + /* refreshAndPersist mode */ + bdb_send_ldap_intermediate( conn, op, + LDAP_SUCCESS, NULL, NULL, NULL, LDAP_SYNC_INFO, + LDAP_SYNC_REFRESH_DONE, &latest_entrycsn_bv, NULL ); + } else { + /* refreshOnly mode */ + bdb_build_sync_done_ctrl( conn, op, ctrls, num_ctrls++, 1, &latest_entrycsn_bv ); + send_search_result( conn, op, + v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, + NULL, NULL, v2refs, ctrls, nentries ); + if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL ) + ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); + ch_free( ctrls[--num_ctrls] ); + ctrls[num_ctrls] = NULL; } - send_search_result( conn, op, - v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, - NULL, NULL, v2refs, ctrls, nentries ); - ch_free( latest_entrycsn_bv.bv_val ); latest_entrycsn_bv.bv_val = NULL; - ch_free( ctrls[0] ); - ber_free_buf( ber ); } else -#endif /* LDAP_CLIENT_UPDATE */ +#endif { send_search_result( conn, op, v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, @@ -871,7 +879,21 @@ done: ch_free( csnfge.f_av_value.bv_val ); } } -#endif /* LDAP_CLIENT_UPDATE */ +#endif +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + else +#endif +#ifdef LDAP_SYNC + if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) { + if ( csnfeq.f_ava != NULL && csnfeq.f_av_value.bv_val != NULL ) { + ch_free( csnfeq.f_av_value.bv_val ); + } + + if ( csnfge.f_ava != NULL && csnfge.f_av_value.bv_val != NULL ) { + ch_free( csnfge.f_av_value.bv_val ); + } + } +#endif LOCK_ID_FREE (bdb->bi_dbenv, locker ); @@ -1159,3 +1181,333 @@ done: (void) ber_free_buf( ber ); } +#ifdef LDAP_CLIENT_UPDATE +int +bdb_build_lcup_update_ctrl( + Connection *conn, + Operation *op, + Entry *e, + int entry_count, + LDAPControl **ctrls, + int num_ctrls, + struct berval *latest_entrycsn_bv, + int isdeleted ) +{ + Attribute* a; + int ret; + int res; + int rc; + const char *text = NULL; + + char berbuf[LBER_ELEMENT_SIZEOF]; + BerElement *ber = (BerElement *)berbuf; + + struct berval entrycsn_bv = { 0, NULL }; + + ber_init2( ber, 0, LBER_USE_DER ); + + ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); + + for ( a = e->e_attrs; a != NULL; a = a->a_next ) { + AttributeDescription *desc = a->a_desc; + if ( desc == slap_schema.si_ad_entryCSN ) { + ber_dupbv( &entrycsn_bv, &a->a_vals[0] ); + if ( latest_entrycsn_bv->bv_val == NULL ) { + ber_dupbv( latest_entrycsn_bv, &entrycsn_bv ); + } else { + res = value_match( &ret, desc, + desc->ad_type->sat_ordering, + SLAP_MR_ASSERTION_SYNTAX_MATCH, + &entrycsn_bv, latest_entrycsn_bv, &text ); + if ( res != LDAP_SUCCESS ) { + ret = 0; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "bdb_search: value_match failed\n", + 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_search: value_match failed\n", + 0, 0, 0 ); +#endif + } + + if ( ret > 0 ) { + ch_free( latest_entrycsn_bv->bv_val ); + latest_entrycsn_bv->bv_val = NULL; + ber_dupbv( latest_entrycsn_bv, &entrycsn_bv ); + } + } + } + } + + if ( entry_count % op->o_clientupdate_interval == 0 ) + ber_printf( ber, + "{bb{sON}N}", + SLAP_LCUP_STATE_UPDATE_FALSE, + isdeleted, + LDAP_LCUP_COOKIE_OID, &entrycsn_bv ); + else /* Do not send cookie */ + ber_printf( ber, + "{bbN}", + SLAP_LCUP_STATE_UPDATE_FALSE, + isdeleted ); + + ch_free( entrycsn_bv.bv_val ); + entrycsn_bv.bv_val = NULL; + + ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_ENTRY_UPDATE; + ctrls[num_ctrls]->ldctl_iscritical = op->o_clientupdate; + ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); + + ber_free_buf( ber ); + + if ( ret < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "bdb_build_lcup_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_build_lcup_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#endif + send_ldap_result( conn, op, rc=LDAP_OTHER, + NULL, "internal error", NULL, NULL ); + return ret; + } + + return LDAP_SUCCESS; +} + +int +bdb_build_lcup_done_ctrl( + Connection *conn, + Operation *op, + LDAPControl **ctrls, + int num_ctrls, + struct berval *latest_entrycsn_bv ) +{ + int ret, rc; + char berbuf[LBER_ELEMENT_SIZEOF]; + BerElement *ber = (BerElement *)berbuf; + + ber_init2( ber, NULL, LBER_USE_DER ); + + ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); + + ber_printf( ber, "{sO", LDAP_LCUP_COOKIE_OID, latest_entrycsn_bv ); + ber_printf( ber, "N}" ); + + ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_CLIENT_UPDATE_DONE; + ctrls[num_ctrls]->ldctl_iscritical = op->o_clientupdate; + ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); + + ber_free_buf( ber ); + + if ( ret < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n", 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#endif + send_ldap_result( conn, op, rc=LDAP_OTHER, + NULL, "internal error", NULL, NULL ); + return ret; + } + + return LDAP_SUCCESS; +} +#endif + +#ifdef LDAP_SYNC +int +bdb_build_sync_state_ctrl( + Connection *conn, + Operation *op, + Entry *e, + int entry_sync_state, + LDAPControl **ctrls, + int num_ctrls, + int send_cookie, + struct berval *latest_entrycsn_bv ) +{ + Attribute* a; + int ret; + int res; + int rc; + const char *text = NULL; + + char berbuf[LBER_ELEMENT_SIZEOF]; + BerElement *ber = (BerElement *)berbuf; + + struct berval entryuuid_bv = { 0, NULL }; + struct berval entrycsn_bv = { 0, NULL }; + + ber_init2( ber, 0, LBER_USE_DER ); + + ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); + + for ( a = e->e_attrs; a != NULL; a = a->a_next ) { + AttributeDescription *desc = a->a_desc; + if ( desc == slap_schema.si_ad_entryCSN ) { + ber_dupbv( &entrycsn_bv, &a->a_vals[0] ); + if ( latest_entrycsn_bv->bv_val == NULL ) { + ber_dupbv( latest_entrycsn_bv, &entrycsn_bv ); + } else { + res = value_match( &ret, desc, + desc->ad_type->sat_ordering, + SLAP_MR_ASSERTION_SYNTAX_MATCH, + &entrycsn_bv, latest_entrycsn_bv, &text ); + if ( res != LDAP_SUCCESS ) { + ret = 0; +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "bdb_search: value_match failed\n", + 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_search: value_match failed\n", + 0, 0, 0 ); +#endif + } + if ( ret > 0 ) { + ch_free( latest_entrycsn_bv->bv_val ); + latest_entrycsn_bv->bv_val = NULL; + ber_dupbv( latest_entrycsn_bv, &entrycsn_bv ); + } + } + } else if ( desc == slap_schema.si_ad_entryUUID ) { + ber_dupbv( &entryuuid_bv, &a->a_vals[0] ); + } + } + + if ( send_cookie ) + ber_printf( ber, "{eOON}", entry_sync_state, &entryuuid_bv, &entrycsn_bv ); + else + ber_printf( ber, "{eON}", entry_sync_state, &entryuuid_bv ); + + ch_free( entrycsn_bv.bv_val ); + entrycsn_bv.bv_val = NULL; + ch_free( entryuuid_bv.bv_val ); + entryuuid_bv.bv_val = NULL; + + ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE; + ctrls[num_ctrls]->ldctl_iscritical = op->o_sync; + ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); + + ber_free_buf( ber ); + + if ( ret < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "bdb_build_sync_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_build_sync_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#endif + send_ldap_result( conn, op, rc=LDAP_OTHER, + NULL, "internal error", NULL, NULL ); + return ret; + } + + return LDAP_SUCCESS; +} + +int +bdb_build_sync_done_ctrl( + Connection *conn, + Operation *op, + LDAPControl **ctrls, + int num_ctrls, + int send_cookie, + struct berval *latest_entrycsn_bv ) +{ + int ret,rc; + char berbuf[LBER_ELEMENT_SIZEOF]; + BerElement *ber = (BerElement *)berbuf; + + ber_init2( ber, NULL, LBER_USE_DER ); + + ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); + + if ( send_cookie ) { + ber_printf( ber, "{ON}", latest_entrycsn_bv ); + } else { + ber_printf( ber, "{N}" ); + } + + ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_DONE; + ctrls[num_ctrls]->ldctl_iscritical = op->o_sync; + ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); + + ber_free_buf( ber ); + + if ( ret < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n", 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#endif + send_ldap_result( conn, op, rc=LDAP_OTHER, + NULL, "internal error", NULL, NULL ); + return ret; + } + + return LDAP_SUCCESS; +} + +int +bdb_send_ldap_intermediate( + Connection *conn, + Operation *op, + ber_int_t err, + const char *matched, + const char *text, + BerVarray refs, + const char *rspoid, + int state, + struct berval *cookie, + LDAPControl **ctrls ) +{ + char berbuf[LBER_ELEMENT_SIZEOF]; + BerElement *ber = (BerElement *)berbuf; + struct berval rspdata; + + int ret, rc; + + ber_init2( ber, NULL, LBER_USE_DER ); + + if ( cookie == NULL ) + ber_printf( ber, "{eN}", state ); + else + ber_printf( ber, "{eON}", state, cookie ); + + ret = ber_flatten2( ber, &rspdata, 0 ); + + if ( ret < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n", 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#endif + send_ldap_result( conn, op, rc=LDAP_OTHER, + NULL, "internal error", NULL, NULL ); + return ret; + } + + send_ldap_intermediate_resp( conn, op, err, matched, text, refs, rspoid, &rspdata, ctrls ); + + ber_free_buf( ber ); + + return LDAP_SUCCESS; +} +#endif diff --git a/servers/slapd/cancel.c b/servers/slapd/cancel.c index f9f12ea9e7..34c071d3c8 100644 --- a/servers/slapd/cancel.c +++ b/servers/slapd/cancel.c @@ -35,6 +35,7 @@ int cancel_extop( int found = 0; int opid; BerElement *ber; + int i; assert( reqoid != NULL ); assert( strcmp( LDAP_EXOP_X_CANCEL, reqoid ) == 0 ); @@ -86,9 +87,22 @@ int cancel_extop( } if ( !found ) { +#ifdef LDAP_SYNC + for ( i = 0; i < nbackends; i++ ) { + if ( strncmp( backends[i].be_type, "bdb", 3 ) ) continue; + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + if ( bdb_cancel( &backends[i], conn, opid ) == LDAP_SUCCESS ) { + return LDAP_SUCCESS; + } else { + *text = "message ID not found"; + return LDAP_NO_SUCH_OPERATION; + } + } +#else *text = "message ID not found"; ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); - return LDAP_NO_SUCH_OPERATION; + return LDAP_NO_SUCH_OPERATION; +#endif } if ( op->o_cancel != LDAP_CANCEL_NONE ) { @@ -114,3 +128,4 @@ int cancel_extop( return rc; } + diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 0f54d412eb..c94ceb3d53 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -1040,12 +1040,26 @@ operations_error: LDAP_STAILQ_REMOVE( &conn->c_ops, arg->co_op, slap_op, o_next); LDAP_STAILQ_NEXT(arg->co_op, o_next) = NULL; + +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + if ( arg->co_op->o_cancel == LDAP_CANCEL_ACK ) + goto co_op_free; +#endif #ifdef LDAP_CLIENT_UPDATE - if ( !( arg->co_op->o_clientupdate_type & SLAP_LCUP_PERSIST ) ) -#endif /* LDAP_CLIENT_UPDATE */ - { - slap_op_free( arg->co_op ); - } + if ( ( arg->co_op->o_clientupdate_type & SLAP_LCUP_PERSIST ) ) + goto no_co_op_free; +#endif +#ifdef LDAP_SYNC + if ( ( arg->co_op->o_sync_mode & SLAP_SYNC_PERSIST ) ) + goto no_co_op_free; +#endif + +co_op_free: + + slap_op_free( arg->co_op ); + +no_co_op_free: + arg->co_op = NULL; arg->co_conn = NULL; free( (char *) arg ); diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index b068b1a7f0..2b20550968 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -58,6 +58,9 @@ static SLAP_CTRL_PARSE_FN parseSubentries; #ifdef LDAP_CLIENT_UPDATE static SLAP_CTRL_PARSE_FN parseClientUpdate; #endif +#ifdef LDAP_SYNC +static SLAP_CTRL_PARSE_FN parseLdupSync; +#endif #undef sc_mask /* avoid conflict with Irix 6.5 */ @@ -108,7 +111,12 @@ static struct slap_control { { LDAP_CONTROL_CLIENT_UPDATE, SLAP_CTRL_SEARCH, NULL, parseClientUpdate }, -#endif /* LDAP_CLIENT_UPDATE */ +#endif +#ifdef LDAP_SYNC + { LDAP_CONTROL_SYNC, + SLAP_CTRL_SEARCH, NULL, + parseLdupSync }, +#endif { NULL, 0, NULL, 0 } }; @@ -829,6 +837,13 @@ static int parseClientUpdate ( return LDAP_PROTOCOL_ERROR; } +#ifdef LDAP_SYNC + if ( op->o_sync != SLAP_NO_CONTROL ) { + *text = "LDAP Client Update and Sync controls used together"; + return LDAP_PROTOCOL_ERROR; + } +#endif + if ( ctrl->ldctl_value.bv_len == 0 ) { *text = "LCUP client update control value is empty (or absent)"; return LDAP_PROTOCOL_ERROR; @@ -897,7 +912,7 @@ static int parseClientUpdate ( return LDAP_PROTOCOL_ERROR; } - if ( tag == LDAP_TAG_COOKIE ) { + if ( tag == LDAP_LCUP_TAG_COOKIE ) { if ( (tag = ber_scanf( ber, /*{*/ "{mm}}", &scheme, &cookie )) == LBER_ERROR ) { *text = "LCUP client update control : decoding error"; @@ -931,4 +946,113 @@ static int parseClientUpdate ( return LDAP_SUCCESS; } -#endif /* LDAP_CLIENT_UPDATE */ +#endif + +#ifdef LDAP_SYNC +static int parseLdupSync ( + Connection *conn, + Operation *op, + LDAPControl *ctrl, + const char **text ) +{ + ber_tag_t tag; + BerElement *ber; + ber_int_t mode; + ber_len_t len; + struct berval cookie = { 0, NULL }; + + if ( op->o_sync != SLAP_NO_CONTROL ) { + *text = "LDAP Sync control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + +#ifdef LDAP_CLIENT_UPDATE + if ( op->o_clientupdate != SLAP_NO_CONTROL ) { + *text = "LDAP Sync and LDAP Client Update controls used together"; + return LDAP_PROTOCOL_ERROR; + } +#endif + + if ( ctrl->ldctl_value.bv_len == 0 ) { + *text = "LDAP Sync control value is empty (or absent)"; + return LDAP_PROTOCOL_ERROR; + } + + /* Parse the control value + * syncRequestValue ::= SEQUENCE { + * mode ENUMERATED { + * -- 0 unused + * refreshOnly (1), + * -- 2 reserved + * refreshAndPersist (3) + * }, + * cookie syncCookie OPTIONAL + * } + */ + + ber = ber_init( &ctrl->ldctl_value ); + if( ber == NULL ) { + *text = "internal error"; + return LDAP_OTHER; + } + + if ( (tag = ber_scanf( ber, "{i" /*}*/, &mode )) == LBER_ERROR ) { + *text = "LDAP Sync control : mode decoding error"; + return LDAP_PROTOCOL_ERROR; + } + + switch( mode ) { + case LDAP_SYNC_REFRESH_ONLY: + mode = SLAP_SYNC_REFRESH; + break; + case LDAP_SYNC_REFRESH_AND_PERSIST: + mode = SLAP_SYNC_REFRESH_AND_PERSIST; + break; + default: + *text = "LDAP Sync control : unknown update mode"; + return LDAP_PROTOCOL_ERROR; + } + + tag = ber_peek_tag( ber, &len ); + + if ( tag == LDAP_SYNC_TAG_COOKIE ) { + if (( ber_scanf( ber, /*{*/ "m}", + &cookie )) == LBER_ERROR ) { + *text = "LDAP Sync control : cookie decoding error"; + return LDAP_PROTOCOL_ERROR; + } + } else { + if (( ber_scanf( ber, /*{*/ "}")) == LBER_ERROR ) { + *text = "LDAP Sync control : decoding error"; + return LDAP_PROTOCOL_ERROR; + } + cookie.bv_len = 0; + cookie.bv_val = NULL; + } + + /* TODO : Cookie Scheme Validation */ +#if 0 + if ( lcup_cookie_scheme_validate(scheme) != LDAP_SUCCESS ) { + *text = "Unsupported LCUP cookie scheme"; + return LCUP_UNSUPPORTED_SCHEME; + } + + if ( lcup_cookie_validate(scheme, cookie) != LDAP_SUCCESS ) { + *text = "Invalid LCUP cookie"; + return LCUP_INVALID_COOKIE; + } +#endif + + ber_dupbv( &op->o_sync_state, &cookie ); + + (void) ber_free( ber, 1 ); + + op->o_sync_mode = (char) mode; + + op->o_sync = ctrl->ldctl_iscritical + ? SLAP_CRITICAL_CONTROL + : SLAP_NONCRITICAL_CONTROL; + + return LDAP_SUCCESS; +} +#endif diff --git a/servers/slapd/operation.c b/servers/slapd/operation.c index e7b9600af0..42f52b2c71 100644 --- a/servers/slapd/operation.c +++ b/servers/slapd/operation.c @@ -46,7 +46,12 @@ slap_op_free( Operation *op ) if ( op->o_clientupdate_state.bv_val != NULL ) { free( op->o_clientupdate_state.bv_val ); } -#endif /* LDAP_CLIENT_UPDATE */ +#endif +#ifdef LDAP_SYNC + if ( op->o_sync_state.bv_val != NULL ) { + free( op->o_sync_state.bv_val ); + } +#endif #if defined( LDAP_SLAPI ) if ( op->o_pb != NULL ) { diff --git a/servers/slapd/search.c b/servers/slapd/search.c index b679e1270e..d6e0bf9c47 100644 --- a/servers/slapd/search.c +++ b/servers/slapd/search.c @@ -415,20 +415,28 @@ do_search( #endif /* LDAP_SLAPI */ return_results:; + #ifdef LDAP_CLIENT_UPDATE - if ( !( op->o_clientupdate_type & SLAP_LCUP_PERSIST ) ) -#endif /* LDAP_CLIENT_UPDATE */ - { - if( pbase.bv_val != NULL) free( pbase.bv_val ); - if( nbase.bv_val != NULL) free( nbase.bv_val ); + if ( ( op->o_clientupdate_type & SLAP_LCUP_PERSIST ) ) + return rc; +#endif +#if defined(LDAP_CLIENT_UPDATE) && defined(LDAP_SYNC) + else +#endif +#ifdef LDAP_SYNC + if ( ( op->o_sync_mode & SLAP_SYNC_PERSIST ) ) + return rc; +#endif + + if( pbase.bv_val != NULL) free( pbase.bv_val ); + if( nbase.bv_val != NULL) free( nbase.bv_val ); - if( fstr.bv_val != NULL) free( fstr.bv_val ); - if( filter != NULL) filter_free( filter ); - if( an != NULL ) free( an ); + if( fstr.bv_val != NULL) free( fstr.bv_val ); + if( filter != NULL) filter_free( filter ); + if( an != NULL ) free( an ); #ifdef LDAP_SLAPI - if( attrs != NULL) ch_free( attrs ); + if( attrs != NULL) ch_free( attrs ); #endif /* LDAP_SLAPI */ - } return rc; } diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 152f971462..c09d1bf0cf 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1615,14 +1615,14 @@ typedef struct slap_paged_state { } PagedResultsState; -#ifdef LDAP_CLIENT_UPDATE -#define LCUP_PSEARCH_BY_ADD 0x01 -#define LCUP_PSEARCH_BY_DELETE 0x02 -#define LCUP_PSEARCH_BY_PREMODIFY 0x03 -#define LCUP_PSEARCH_BY_MODIFY 0x04 -#define LCUP_PSEARCH_BY_SCOPEOUT 0x05 - -struct lcup_search_spec { +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) +#define LDAP_PSEARCH_BY_ADD 0x01 +#define LDAP_PSEARCH_BY_DELETE 0x02 +#define LDAP_PSEARCH_BY_PREMODIFY 0x03 +#define LDAP_PSEARCH_BY_MODIFY 0x04 +#define LDAP_PSEARCH_BY_SCOPEOUT 0x05 + +struct ldap_psearch_spec { struct slap_op *op; struct berval *base; struct berval *nbase; @@ -1634,17 +1634,16 @@ struct lcup_search_spec { struct berval *filterstr; AttributeName *attrs; int attrsonly; - struct lcup_entry *elist; - ldap_pvt_thread_mutex_t elist_mutex; + int protocol; int entry_count; - LDAP_LIST_ENTRY(lcup_search_spec) link; + LDAP_LIST_ENTRY(ldap_psearch_spec) link; }; struct psid_entry { - struct lcup_search_spec* ps; + struct ldap_psearch_spec* ps; LDAP_LIST_ENTRY(psid_entry) link; }; -#endif /* LDAP_CLIENT_UPDATE */ +#endif /* @@ -1691,13 +1690,26 @@ typedef struct slap_op { #define SLAP_LCUP_NONE (0x0) #define SLAP_LCUP_SYNC (0x1) #define SLAP_LCUP_PERSIST (0x2) -#define SLAP_LCUP_SYNC_AND_PERSIST (0x3) +#define SLAP_LCUP_SYNC_AND_PERSIST (0x3) ber_int_t o_clientupdate_interval; struct berval o_clientupdate_state; - LDAP_LIST_HEAD(lss, lcup_search_spec) psearch_spec; +#endif + +#ifdef LDAP_SYNC + char o_sync; + char o_sync_mode; +#define SLAP_SYNC_NONE (0x0) +#define SLAP_SYNC_REFRESH (0x1) +#define SLAP_SYNC_PERSIST (0x2) +#define SLAP_SYNC_REFRESH_AND_PERSIST (0x3) + struct berval o_sync_state; +#endif + +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + LDAP_LIST_HEAD(lss, ldap_psearch_spec) psearch_spec; LDAP_LIST_HEAD(pe, psid_entry) premodify_list; LDAP_LIST_ENTRY(slap_op) link; -#endif /* LDAP_CLIENT_UPDATE */ +#endif #ifdef LDAP_CONNECTIONLESS Sockaddr o_peeraddr; /* UDP peer address */ @@ -1997,6 +2009,10 @@ enum { #define SLAP_LCUP_ENTRY_DELETED_FALSE 0 #endif /* LDAP_CLIENT_UPDATE */ +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) +#define SLAP_SEARCH_MAX_CTRLS 10 +#endif + LDAP_END_DECL #include "proto-slap.h" -- 2.39.5