Example #1
0
int
fe_op_search( Operation *op, SlapReply *rs )
{
	BackendDB		*bd = op->o_bd;

	if ( op->ors_scope == LDAP_SCOPE_BASE ) {
		Entry *entry = NULL;

		if ( BER_BVISEMPTY( &op->o_req_ndn ) ) {
#ifdef LDAP_CONNECTIONLESS
			/* Ignore LDAPv2 CLDAP Root DSE queries */
			if (op->o_protocol == LDAP_VERSION2 && op->o_conn->c_is_udp) {
				goto return_results;
			}
#endif
			/* check restrictions */
			if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
				send_ldap_result( op, rs );
				goto return_results;
			}

			rs->sr_err = root_dse_info( op->o_conn, &entry, &rs->sr_text );

		} else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) {
			/* check restrictions */
			if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
				send_ldap_result( op, rs );
				goto return_results;
			}

			rs->sr_err = schema_info( &entry, &rs->sr_text );
		}

		if( rs->sr_err != LDAP_SUCCESS ) {
			send_ldap_result( op, rs );
			goto return_results;

		} else if ( entry != NULL ) {
			if ( get_assert( op ) &&
				( test_filter( op, entry, get_assertion( op )) != LDAP_COMPARE_TRUE )) {
				rs->sr_err = LDAP_ASSERTION_FAILED;
				goto fail1;
			}

			rs->sr_err = test_filter( op, entry, op->ors_filter );

			if( rs->sr_err == LDAP_COMPARE_TRUE ) {
				/* note: we set no limits because either
				 * no limit is specified, or at least 1
				 * is specified, and we're going to return
				 * at most one entry */			
				op->ors_slimit = SLAP_NO_LIMIT;
				op->ors_tlimit = SLAP_NO_LIMIT;

				rs->sr_entry = entry;
				rs->sr_attrs = op->ors_attrs;
				rs->sr_operational_attrs = NULL;
				rs->sr_flags = 0;
				send_search_entry( op, rs );
				rs->sr_entry = NULL;
				rs->sr_operational_attrs = NULL;
			}
			rs->sr_err = LDAP_SUCCESS;
fail1:
			entry_free( entry );
			send_ldap_result( op, rs );
			goto return_results;
		}
	}

	if( BER_BVISEMPTY( &op->o_req_ndn ) && !BER_BVISEMPTY( &default_search_nbase ) ) {
		slap_sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx );
		slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );

		ber_dupbv_x( &op->o_req_dn, &default_search_base, op->o_tmpmemctx );
		ber_dupbv_x( &op->o_req_ndn, &default_search_nbase, op->o_tmpmemctx );
	}

	/*
	 * We could be serving multiple database backends.  Select the
	 * appropriate one, or send a referral to our "referral server"
	 * if we don't hold it.
	 */

	op->o_bd = select_backend( &op->o_req_ndn, 1 );
	if ( op->o_bd == NULL ) {
		rs->sr_ref = referral_rewrite( default_referral,
			NULL, &op->o_req_dn, op->ors_scope );

		if (!rs->sr_ref) rs->sr_ref = default_referral;
		rs->sr_err = LDAP_REFERRAL;
		op->o_bd = bd;
		send_ldap_result( op, rs );

		if (rs->sr_ref != default_referral)
		ber_bvarray_free( rs->sr_ref );
		rs->sr_ref = NULL;
		goto return_results;
	}

	/* check restrictions */
	if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		goto return_results;
	}

	/* check for referrals */
	if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
		goto return_results;
	}

	if ( SLAP_SHADOW(op->o_bd) && get_dontUseCopy(op) ) {
		/* don't use shadow copy */
		BerVarray defref = op->o_bd->be_update_refs
			? op->o_bd->be_update_refs : default_referral;

		if( defref != NULL ) {
			rs->sr_ref = referral_rewrite( defref,
				NULL, &op->o_req_dn, op->ors_scope );
			if( !rs->sr_ref) rs->sr_ref = defref;
			rs->sr_err = LDAP_REFERRAL;
			send_ldap_result( op, rs );

			if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref );

		} else {
			send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
				"copy not used; no referral information available" );
		}

	} else if ( op->o_bd->be_search ) {
		if ( limits_check( op, rs ) == 0 ) {
			/* actually do the search and send the result(s) */
			(op->o_bd->be_search)( op, rs );
		}
		/* else limits_check() sends error */

	} else {
		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
			"operation not supported within namingContext" );
	}

return_results:;
	op->o_bd = bd;
	return rs->sr_err;
}
Example #2
0
static int sssvlv_op_search(
	Operation		*op,
	SlapReply		*rs)
{
	slap_overinst			*on			= (slap_overinst *)op->o_bd->bd_info;
	sssvlv_info				*si			= on->on_bi.bi_private;
	int						rc			= SLAP_CB_CONTINUE;
	int	ok, need_unlock = 0;
	sort_ctrl *sc;
	PagedResultsState *ps;
	vlv_ctrl *vc;
	int sess_id;

	if ( op->o_ctrlflag[sss_cid] <= SLAP_CONTROL_IGNORED ) {
		if ( op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ) {
			sort_op so; memset(&so, 0, sizeof(so));
			so.so_vlv_rc = LDAP_VLV_SSS_MISSING;
			so.so_vlv = op->o_ctrlflag[vlv_cid];
			LDAPControl *ctrls[2];
			rc = pack_vlv_response_control( op, rs, &so, ctrls );
			if ( rc == LDAP_SUCCESS ) {
				ctrls[1] = NULL;
				slap_add_ctrls( op, rs, ctrls );
			}
			rs->sr_err = LDAP_VLV_ERROR;
			rs->sr_text = "Sort control is required with VLV";
			goto leave;
		}
		/* Not server side sort so just continue */
		return SLAP_CB_CONTINUE;
	}

	Debug(LDAP_DEBUG_TRACE,
		"==> sssvlv_search: <%s> %s, control flag: %d\n",
		op->o_req_dn.bv_val, op->ors_filterstr.bv_val,
		op->o_ctrlflag[sss_cid]);

	sc = op->o_controls[sss_cid];
	if ( sc->sc_nkeys > si->svi_max_keys ) {
		rs->sr_text = "Too many sort keys";
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		goto leave;
	}

	ps = ( op->o_pagedresults > SLAP_CONTROL_IGNORED ) ?
		(PagedResultsState*)(op->o_pagedresults_state) : NULL;
	vc = op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ?
		op->o_controls[vlv_cid] : NULL;

	if ( ps && vc ) {
		rs->sr_text = "VLV incompatible with PagedResults";
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		goto leave;
	}

	ldap_pvt_thread_mutex_lock( &sort_conns_mutex );
	ok = need_unlock = 1;
	sort_op *so = NULL;

	/* Is there already a sort running on this conn? */
	sess_id = find_session_by_context( si->svi_max_percon, op->o_conn->c_conn_idx, vc ? vc->vc_context : NO_VC_CONTEXT, ps ? ps->ps_cookie : NO_PS_COOKIE );
	if ( sess_id >= 0 ) {
		so = sort_conns[op->o_conn->c_conn_idx][sess_id];
		if (so->so_running) {
			/* another thread is handling, response busy to client */
			ok = 0;
			so = NULL;
		} else {
			/* Is it a continuation of a VLV search? */
			if ( !vc || so->so_vlv <= SLAP_CONTROL_IGNORED ||
					vc->vc_context != so->so_vcontext ) {
				/* Is it a continuation of a paged search? */
				if ( !ps || so->so_paged <= SLAP_CONTROL_IGNORED ||
					op->o_conn->c_pagedresults_state.ps_cookie != ps->ps_cookie ) {
					ok = 0;
				} else if ( !ps->ps_size ) {
					/* Abandoning current request */
					ok = 0;
					so->so_nentries = 0;
					rs->sr_err = LDAP_SUCCESS;
				}
			}
			if (( vc && so->so_paged > SLAP_CONTROL_IGNORED ) ||
					( ps && so->so_vlv > SLAP_CONTROL_IGNORED )) {
				/* changed from paged to vlv or vice versa, abandon */
				ok = 0;
				so->so_nentries = 0;
				rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
			}
			if ( ok ) {
				/* occupy before mutex unlock */
				so->so_running = 1;
			}
		}
	/* Are there too many running overall? */
	} else if ( si->svi_num >= si->svi_max ) {
		ok = 0;
	} else if ( ( sess_id = find_next_session(si->svi_max_percon, op->o_conn->c_conn_idx ) ) < 0 ) {
		ok = 0;
	} else {
		/* OK, this connection going a sort running as the sess_id */
	}

	if (! ok || so != NULL) {
		assert(need_unlock != 0);
		ldap_pvt_thread_mutex_unlock( &sort_conns_mutex );
		need_unlock = 0;
	}

	if ( ok ) {
		/* If we're a global overlay, this check got bypassed */
		if ( !op->ors_limit && limits_check( op, rs )) {
			if (need_unlock) {
				ldap_pvt_thread_mutex_unlock( &sort_conns_mutex );
				need_unlock = 0;
			}
			if (so)
				free_sort_op( op->o_conn, so );
			return rs->sr_err;
		}
		/* are we continuing a VLV search? */
		if ( so && vc && vc->vc_context ) {
			assert(need_unlock == 0);
			so->so_ctrl = sc;
			send_list( op, rs, so );
			send_result( op, rs, so );
			rc = LDAP_SUCCESS;
		/* are we continuing a paged search? */
		} else if ( so && ps && ps->ps_cookie ) {
			assert(need_unlock == 0);
			so->so_ctrl = sc;
			send_page( op, rs, so );
			send_result( op, rs, so );
			rc = LDAP_SUCCESS;
		} else {
			/* Install serversort response callback to handle a new search */
			assert(need_unlock != 0);
			assert(so == NULL);

			so = ch_calloc( 1, sizeof(sort_op));
			slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback),
				op->o_tmpmemctx );
			LDAP_ENSURE(so != NULL && cb != NULL); /* FIXME: LDAP_OTHER */

			cb->sc_response		= sssvlv_op_response;
			cb->sc_next			= op->o_callback;
			cb->sc_private		= so;

			assert(so->so_tree == NULL);
			so->so_ctrl = sc;
			so->so_info = si;
			if ( ps ) {
				so->so_paged = op->o_pagedresults;
				so->so_page_size = ps->ps_size;
				op->o_pagedresults = SLAP_CONTROL_IGNORED;
				assert(so->so_page_size != 0);
			} else {
				if ( vc ) {
					so->so_vlv = op->o_ctrlflag[vlv_cid];
					assert(so->so_vlv_target == 0);
					assert(so->so_vlv_rc == 0);
					assert(so->so_vlv != SLAP_CONTROL_NONE);
				} else {
					assert(so->so_vlv == SLAP_CONTROL_NONE);
				}
			}
			so->so_session = sess_id;
			so->so_vlv = op->o_ctrlflag[vlv_cid];
			so->so_vcontext = (size_t)so;
			assert(so->so_nentries == 0);
			op->o_callback = cb;

			assert(sess_id >= 0);
			so->so_running = 1;
			sort_conns[op->o_conn->c_conn_idx][sess_id] = so;
			si->svi_num++;
			ldap_pvt_thread_mutex_unlock( &sort_conns_mutex );
			need_unlock = 0;
		}
		assert(need_unlock == 0);
	} else {
		assert(need_unlock == 0);
		if ( so && !so->so_nentries ) {
			free_sort_op( op->o_conn, so );
		} else {
			rs->sr_text = "Other sort requests already in progress";
			rs->sr_err = LDAP_BUSY;
		}
leave:
		assert(need_unlock == 0);
		rc = rs->sr_err;
		send_ldap_result( op, rs );
	}

	assert(need_unlock == 0);
	return rc;
}