summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/chainingdb/cb_search.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/plugins/chainingdb/cb_search.c')
-rw-r--r--ldap/servers/plugins/chainingdb/cb_search.c698
1 files changed, 698 insertions, 0 deletions
diff --git a/ldap/servers/plugins/chainingdb/cb_search.c b/ldap/servers/plugins/chainingdb/cb_search.c
new file mode 100644
index 00000000..d9cf6ef7
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_search.c
@@ -0,0 +1,698 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+ * Build a candidate list for this backentry and scope.
+ * Could be a BASE, ONELEVEL, or SUBTREE search.
+ *
+ * Returns:
+ * 0 - success
+ * <0 - fail
+ *
+ */
+
+int
+chainingdb_build_candidate_list ( Slapi_PBlock *pb )
+{
+
+ Slapi_Backend * be;
+ Slapi_Operation * op;
+ char *target, *filter;
+ int scope,attrsonly,sizelimit,timelimit,rc,searchreferral;
+ char **attrs=NULL;
+ LDAPControl **controls=NULL;
+ LDAPControl **ctrls=NULL;
+ LDAP *ld=NULL;
+ cb_backend_instance *cb = NULL;
+ cb_searchContext *ctx=NULL;
+ struct timeval timeout;
+ time_t optime;
+ int doit,parse_rc;
+ LDAPMessage *res=NULL;
+ char *matched_msg,*error_msg;
+ LDAPControl **serverctrls=NULL;
+ char **referrals=NULL;
+ char *cnxerrbuf=NULL;
+ time_t endbefore=0;
+ time_t endtime;
+ cb_outgoing_conn *cnx;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op );
+ slapi_pblock_get( pb, SLAPI_SEARCH_STRFILTER, &filter );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
+ slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &target );
+
+ if ( LDAP_SUCCESS != (parse_rc=cb_forward_operation(pb) )) {
+
+ /* Don't return errors */
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "local search: base:<%s> scope:<%s> filter:<%s>\n",target,
+ scope==LDAP_SCOPE_SUBTREE?"SUBTREE":scope==LDAP_SCOPE_ONELEVEL ? "ONE-LEVEL" : "BASE" , filter);
+ }
+
+ ctx = (cb_searchContext *)slapi_ch_calloc(1,sizeof(cb_searchContext));
+ ctx->type = CB_SEARCHCONTEXT_ENTRY;
+ ctx->data=NULL;
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ return 0;
+ }
+
+ cb_update_monitor_info(pb,cb,SLAPI_OPERATION_SEARCH);
+
+ /* Check wether the chaining BE is available or not */
+ if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){
+ return -1;
+ }
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "chained search: base:<%s> scope:<%s> filter:<%s>\n",target,
+ scope==LDAP_SCOPE_SUBTREE?"SUBTREE":scope==LDAP_SCOPE_ONELEVEL ? "ONE-LEVEL" : "BASE" , filter);
+ }
+
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs );
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &controls );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+
+
+ if ((scope != LDAP_SCOPE_BASE) && (scope != LDAP_SCOPE_ONELEVEL) && (scope != LDAP_SCOPE_SUBTREE)) {
+ cb_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "Bad scope", 0, NULL );
+ return 1;
+ }
+
+ searchreferral=cb->searchreferral;
+
+ if (( scope != LDAP_SCOPE_BASE ) && ( searchreferral )) {
+
+ int i;
+ struct berval bv,*bvals[2];
+ Slapi_Entry ** aciArray=(Slapi_Entry **) slapi_ch_malloc(2*sizeof(Slapi_Entry *));
+ Slapi_Entry *anEntry = slapi_entry_alloc();
+
+ slapi_entry_set_dn(anEntry,slapi_ch_strdup(target));
+
+ bvals[1]=NULL;
+ bvals[0]=&bv;
+ bv.bv_val="referral";
+ bv.bv_len=strlen(bv.bv_val);
+ slapi_entry_add_values( anEntry, "objectclass", bvals);
+
+ PR_RWLock_Rlock(cb->rwl_config_lock);
+ for (i=0; cb->url_array && cb->url_array[i]; i++) {
+ char * anUrl= slapi_ch_calloc(1,strlen(cb->url_array[i])+strlen(target)+1);
+ sprintf(anUrl,"%s%s",cb->url_array[i],target);
+ bv.bv_val=anUrl;
+ bv.bv_len=strlen(bv.bv_val);
+ slapi_entry_attr_merge( anEntry, "ref", bvals);
+ slapi_ch_free((void **)&anUrl);
+ }
+ PR_RWLock_Unlock(cb->rwl_config_lock);
+
+ aciArray[0]=anEntry;
+ aciArray[1]=NULL;
+
+ ctx = (cb_searchContext *)slapi_ch_calloc(1,sizeof(cb_searchContext));
+ ctx->type = CB_SEARCHCONTEXT_ENTRY;
+ ctx->data=aciArray;
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ return 0;
+ }
+
+ /*
+ ** Time limit management.
+ ** Make sure the operation has not expired
+ */
+
+ if ( timelimit == -1 ) {
+ timeout.tv_sec = timeout.tv_usec = 0;
+ } else {
+ time_t now=current_time();
+ endbefore=optime + timelimit;
+ if (now >= endbefore) {
+ cb_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL,NULL, 0, NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
+ return 1;
+ }
+ timeout.tv_sec=timelimit-(now-optime);
+ timeout.tv_usec=0;
+ }
+
+ /* Operational attribute support for internal searches: */
+ /* The front-end relies on the fact that operational attributes */
+ /* are returned along with standard attrs when the attr list is */
+ /* NULL. To make it work, we need to explicitly request for all*/
+ /* possible operational attrs. Too bad. */
+
+ if ( (attrs == NULL) && operation_is_flag_set(op, OP_FLAG_INTERNAL) ) {
+ attrs = cb->every_attribute;
+
+ }
+ else
+ {
+ int i;
+ if ( attrs != NULL )
+ {
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ if ( strcasecmp( "nsrole", attrs[i] ) == 0 )
+ {
+ attrs = cb->every_attribute;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Grab a connection handle */
+
+ if ( LDAP_SUCCESS != (rc = cb_get_connection(cb->pool,&ld,&cnx,&timeout,&cnxerrbuf))) {
+ if (rc == LDAP_TIMELIMIT_EXCEEDED)
+ cb_send_ldap_result( pb, rc, NULL,cnxerrbuf, 0, NULL);
+ else
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,cnxerrbuf, 0, NULL);
+
+ slapi_ch_free((void **)&cnxerrbuf);
+ /* ping the farm. If the farm is unreachable, we increment the counter */
+ cb_ping_farm(cb,NULL,0);
+ return 1;
+ }
+
+ /*
+ * Control management
+ */
+
+ if ( LDAP_SUCCESS != (rc = cb_update_controls( pb,ld,&ctrls,CB_UPDATE_CONTROLS_ADDAUTH ))) {
+ cb_send_ldap_result( pb, rc, NULL,NULL, 0, NULL);
+ cb_release_op_connection(cb->pool,ld,0);
+ return 1;
+ }
+
+ if ( slapi_op_abandoned( pb )) {
+ cb_release_op_connection(cb->pool,ld,0);
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ return 1;
+ }
+
+ ctx = (cb_searchContext *) slapi_ch_calloc(1,sizeof(cb_searchContext));
+
+ /*
+ ** We need to store the connection handle in the search context
+ ** to make sure we reuse it in the next_entry iteration
+ ** Indeed, if another thread on this connection detects a problem
+ ** on this connection, it may reallocate a new connection and
+ ** a call to get_connection may return a new cnx. Too bad.
+ */
+
+ ctx->ld=ld;
+ ctx->cnx=cnx;
+
+ /* for some reasons, it is an error to pass in a zero'd timeval */
+ /* to ldap_search_ext() */
+ if ((timeout.tv_sec==0) && (timeout.tv_usec==0))
+ timeout.tv_sec=timeout.tv_usec=-1;
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ rc=ldap_search_ext(ld ,target,scope,filter,attrs,attrsonly,
+ ctrls, NULL, &timeout,sizelimit, &(ctx->msgid) );
+
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+
+ if ( LDAP_SUCCESS != rc ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **) &ctx);
+ return 1;
+ }
+
+ /*
+ ** Need to get the very first result to handle
+ ** errors properly, especially no search base.
+ */
+
+ doit=1;
+ while (doit) {
+
+ if (cb_check_forward_abandon(cb,pb,ctx->ld,ctx->msgid)) {
+ slapi_ch_free((void **) &ctx);
+ return 1;
+ }
+
+ rc=ldap_result(ld,ctx->msgid,LDAP_MSG_ONE,&cb->abandon_timeout,&res);
+ switch ( rc ) {
+ case -1:
+ /* An error occurred. return now */
+ rc = ldap_get_lderrno(ld,NULL,NULL);
+ /* tuck away some errors in a OPERATION_ERROR */
+ if (CB_LDAP_CONN_ERROR(rc)) {
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string( rc ), 0, NULL);
+ } else {
+ cb_send_ldap_result(pb,rc, NULL, NULL,0,NULL);
+ }
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ slapi_ch_free((void **)&ctx);
+ return 1;
+ case 0:
+
+ /* Local timeout management */
+ if (timelimit != -1) {
+ if (current_time() > endbefore) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Local timeout expiration\n");
+
+ cb_send_ldap_result(pb,LDAP_TIMELIMIT_EXCEEDED,
+ NULL,NULL, 0, NULL);
+ /* Force connection close */
+ cb_release_op_connection(cb->pool,ld,1);
+ if (res)
+ ldap_msgfree(res);
+ slapi_ch_free((void **)&ctx);
+ return 1;
+ }
+ }
+ /* heart-beat management */
+ if ((rc=cb_ping_farm(cb,cnx,endtime)) != LDAP_SUCCESS) {
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ slapi_ch_free((void **)&ctx);
+ return 1;
+ }
+
+#ifdef CB_YIELD
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+#endif
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
+ case LDAP_RES_SEARCH_REFERENCE:
+ /* Some results received */
+ /* don't parse result here */
+ ctx->pending_result=res;
+ ctx->pending_result_type=rc;
+ doit=0;
+ break;
+ case LDAP_RES_SEARCH_RESULT:
+ matched_msg=NULL;
+ error_msg=NULL;
+ referrals=NULL;
+ serverctrls=NULL;
+ parse_rc=ldap_parse_result(ld,res,&rc,&matched_msg,
+ &error_msg,&referrals, &serverctrls, 0 );
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result(pb,parse_rc,
+ matched_msg,error_msg,0,NULL);
+ rc=-1;
+ } else
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_get_lderrno( ctx->ld, &matched_msg, &error_msg );
+ cb_send_ldap_result( pb, rc, matched_msg,
+ error_msg,0,NULL);
+ /* BEWARE: matched_msg and error_msg points */
+ /* to ld fields. */
+ matched_msg=NULL;
+ error_msg=NULL;
+ rc=-1;
+ }
+
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ if (referrals)
+ charray_free(referrals);
+
+ if (rc!=LDAP_SUCCESS) {
+ cb_release_op_connection(cb->pool,ld,
+ CB_LDAP_CONN_ERROR(rc));
+ ldap_msgfree(res);
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ }
+
+ /* Store the msg in the ctx */
+ /* Parsed in iterate. */
+
+ ctx->pending_result=res;
+ ctx->pending_result_type=LDAP_RES_SEARCH_RESULT;
+ doit=0;
+ }
+ }
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ return 0;
+}
+
+/*
+ * Return the next entry in the result set. The entry is returned
+ * in the pblock.
+ * Returns 0 normally. If -1 is returned, it means that some
+ * exceptional condition, e.g. timelimit exceeded has occurred,
+ * and this routine has sent a result to the client. If zero
+ * is returned and no entry is available in the PBlock, then
+ * we've iterated through all the entries.
+ */
+
+int
+chainingdb_next_search_entry ( Slapi_PBlock *pb )
+{
+
+ char *target;
+ int sizelimit,timelimit, rc, parse_rc, optime,i,retcode, attrsonly;
+ LDAPMessage *res=NULL;
+ char *matched_msg,*error_msg;
+ cb_searchContext *ctx=NULL;
+ Slapi_Entry *entry;
+ LDAPControl **serverctrls=NULL;
+ char **referrals=NULL;
+ cb_backend_instance * cb=NULL;
+ Slapi_Backend * be;
+ time_t endtime;
+
+ matched_msg=error_msg=NULL;
+
+ slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &ctx );
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &target );
+ slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
+
+ cb = cb_get_instance(be);
+
+ if ( NULL == ctx ) {
+ /* End of local search */
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Unexpected NULL ctx in chainingdb_next_search_entry\n");
+ return 0;
+ }
+
+ if ( NULL != ctx->tobefreed ) {
+ slapi_entry_free(ctx->tobefreed);
+ ctx->tobefreed=NULL;
+ }
+
+ if ( ctx->type == CB_SEARCHCONTEXT_ENTRY ) {
+
+ int n;
+ Slapi_Entry ** ptr;
+ if ( (timelimit != -1) && (timelimit != 0)) {
+ time_t now=current_time();
+
+ if (now > (optime + timelimit)) {
+ cb_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL,NULL, 0, NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ for ( n = 0, ptr=(Slapi_Entry **)ctx->data; ptr != NULL && ptr[n] != NULL; n++ ) {
+ slapi_entry_free(ptr[n]);
+ }
+ if (ctx->data)
+ slapi_ch_free((void **)&ctx->data);
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ }
+ }
+
+ /*
+ ** Return the Slapi_Entry of the result set one
+ ** by one
+ */
+
+ for ( n = 0, ptr=(Slapi_Entry **)ctx->data; ptr != NULL && ptr[n] != NULL; n++ );
+ if ( n != 0) {
+ Slapi_Entry * anEntry=ptr[n-1];
+ ptr[n-1]=NULL;
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,anEntry);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ cb_set_acl_policy(pb);
+ ctx->tobefreed=anEntry;
+ } else {
+ slapi_ch_free((void **) &ctx);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+ }
+ return 0;
+ }
+
+ /*
+ * Grab a connection handle. Should be the same as the one
+ * used in the build_candidate list. To be certain of that, grab it from
+ * the context.
+ */
+
+ /* Poll the server for the results of the search operation.
+ * Passing LDAP_MSG_ONE indicates that you want to receive
+ * the entries one at a time, as they come in. If the next
+ * entry that you retrieve is NULL, there are no more entries.
+ */
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ while (1) {
+
+ if (cb_check_forward_abandon(cb,pb,ctx->ld,ctx->msgid)) {
+ /* cnx handle released */
+ if (ctx->pending_result)
+ ldap_msgfree(ctx->pending_result);
+ slapi_ch_free((void **) &ctx);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+ return -1;
+ }
+
+ /* Check for time limit done by the remote farm server */
+ /* Check for size limit done by the remote farm server */
+
+ /* Use pending msg if one is available */
+ if (ctx->pending_result) {
+ res=ctx->pending_result;
+ rc=ctx->pending_result_type;
+ ctx->pending_result=NULL;
+ } else {
+
+
+ rc=ldap_result(ctx->ld,ctx->msgid,
+ LDAP_MSG_ONE, &cb->abandon_timeout, &res );
+ }
+
+ /* The server can return three types of results back to the client,
+ * and the return value of ldap_result() indicates the result type:
+ * LDAP_RES_SEARCH_ENTRY identifies an entry found by the search,
+ * LDAP_RES_SEARCH_REFERENCE identifies a search reference returned
+ * by the server, and LDAP_RES_SEARCH_RESULT is the last result
+ * sent from the server to the client after the operation completes.
+ * We need to check for each of these types of results.
+ */
+
+ switch ( rc ) {
+ case -1:
+
+ /* An error occurred. */
+ rc = ldap_get_lderrno( ctx->ld, NULL, NULL );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, ldap_err2string( rc ), 0, NULL);
+
+ if (res)
+ ldap_msgfree(res);
+ cb_release_op_connection(cb->pool,ctx->ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ case 0:
+ /* heart-beat management */
+ if ((rc=cb_ping_farm(cb,ctx->cnx,endtime)) != LDAP_SUCCESS) {
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+
+ if (res)
+ ldap_msgfree(res);
+ cb_release_op_connection(cb->pool,ctx->ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ }
+#ifdef CB_YIELD
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+#endif
+ break;
+
+ case LDAP_RES_SEARCH_ENTRY:
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ /* The server sent one of the entries found by the search */
+ if ((entry = cb_LDAPMessage2Entry(ctx->ld,res,attrsonly)) == NULL) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,"Invalid entry received.\n");
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL , 0, NULL);
+
+ ldap_msgfree(res);
+ cb_release_op_connection(cb->pool,ctx->ld,0);
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ }
+
+ ctx->tobefreed=entry;
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,entry);
+ cb_set_acl_policy(pb);
+ ldap_msgfree(res);
+ return 0;
+
+ case LDAP_RES_SEARCH_REFERENCE:
+
+ /* The server sent a search reference encountered during the
+ * search operation.
+ */
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ parse_rc = ldap_parse_reference( ctx->ld, res, &referrals, NULL, 1 );
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string( parse_rc ), 0, NULL);
+ cb_release_op_connection(cb->pool,ctx->ld,CB_LDAP_CONN_ERROR(parse_rc));
+ slapi_ch_free((void **)&ctx);
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+ return -1;
+ }
+
+ /*
+ ** build a dummy entry on the fly with a ref attribute
+ */
+
+ {
+
+ struct berval bv;
+ int i;
+ struct berval *bvals[2];
+ Slapi_Entry *anEntry = slapi_entry_alloc();
+ slapi_entry_set_dn(anEntry,slapi_ch_strdup(target));
+
+ bvals[1]=NULL;
+ bvals[0]=&bv;
+
+ bv.bv_val="referral";
+ bv.bv_len=strlen(bv.bv_val);
+ slapi_entry_add_values( anEntry, "objectclass", bvals);
+
+ for (i=0;referrals[i] != NULL; i++) {
+ bv.bv_val=referrals[i];
+ bv.bv_len=strlen(bv.bv_val);
+ slapi_entry_add_values( anEntry, "ref", bvals);
+ }
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,anEntry);
+ cb_set_acl_policy(pb);
+ }
+
+ if (referrals != NULL) {
+ ldap_value_free( referrals );
+ }
+
+ return 0;
+
+ case LDAP_RES_SEARCH_RESULT:
+
+ /* Parse the final result received from the server. Note the last
+ * argument is a non-zero value, which indicates that the
+ * LDAPMessage structure will be freed when done.
+ */
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ parse_rc = ldap_parse_result( ctx->ld, res,
+ &rc,&matched_msg,&error_msg, &referrals, &serverctrls, 1 );
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, matched_msg,
+ ldap_err2string( parse_rc ), 0, NULL);
+
+ retcode=-1;
+ } else
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_get_lderrno( ctx->ld, &matched_msg, &error_msg );
+ cb_send_ldap_result( pb, rc, matched_msg, NULL, 0, NULL);
+
+ /* BEWARE: Don't free matched_msg && error_msg */
+ /* Points to the ld fields */
+ matched_msg=NULL;
+ error_msg=NULL;
+ retcode=-1;
+ } else {
+ /* Add control response sent by the farm server */
+ for (i=0; serverctrls && serverctrls[i];i++)
+ slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, serverctrls[i]);
+ retcode=0;
+ }
+
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (referrals)
+ charray_free(referrals);
+
+ cb_release_op_connection(cb->pool,ctx->ld,0);
+ slapi_ch_free((void **)&ctx);
+ return retcode;
+
+ default:
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "chainingdb_next_search_entry:default case.\n");
+
+ }
+ }
+
+ /* Not reached */
+ /* return 0; */
+}
+
+int
+chaining_back_entry_release ( Slapi_PBlock *pb ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM, "chaining_back_entry_release\n");
+ return 0;
+}
+