summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/slapd/search.c')
-rw-r--r--ldap/servers/slapd/search.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/ldap/servers/slapd/search.c b/ldap/servers/slapd/search.c
new file mode 100644
index 00000000..471d3157
--- /dev/null
+++ b/ldap/servers/slapd/search.c
@@ -0,0 +1,283 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "slap.h"
+#include "pratom.h"
+#include "snmp_collator.h"
+
+static void log_search_access (Slapi_PBlock *pb, const char *base, int scope, const char *filter, const char *msg);
+
+void
+do_search( Slapi_PBlock *pb )
+{
+ Slapi_Operation *operation;
+ BerElement *ber;
+ int i, err;
+ int scope, deref, attrsonly;
+ int sizelimit, timelimit;
+ long long_scope,long_deref,long_sizelimit,long_timelimit;
+ char *base = NULL, *fstr = NULL;
+ struct slapi_filter *filter = NULL;
+ char **attrs = NULL;
+ int psearch = 0;
+ struct berval *psbvp;
+ int changetypes;
+ int send_entchg_controls;
+ int changesonly = 0;
+ int rc = -1;
+ char *original_base = 0;
+ char *new_base = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ ber = operation->o_ber;
+
+ /* count the search request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsSearchOps);
+
+ /*
+ * Parse the search request. It looks like this:
+ *
+ * SearchRequest := [APPLICATION 3] SEQUENCE {
+ * baseObject DistinguishedName,
+ * scope ENUMERATED {
+ * baseObject (0),
+ * singleLevel (1),
+ * wholeSubtree (2)
+ * },
+ * derefAliases ENUMERATED {
+ * neverDerefaliases (0),
+ * derefInSearching (1),
+ * derefFindingBaseObj (2),
+ * alwaysDerefAliases (3)
+ * },
+ * sizelimit INTEGER (0 .. 65535),
+ * timelimit INTEGER (0 .. 65535),
+ * attrsOnly BOOLEAN,
+ * filter Filter,
+ * attributes SEQUENCE OF AttributeType
+ * }
+ */
+
+ /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
+ if ( ber_scanf( ber, "{aiiiib", &base, &long_scope, &long_deref, &long_sizelimit, &long_timelimit, &attrsonly ) == LBER_ERROR ){
+ slapi_ch_free((void**)&base );
+ log_search_access (pb, "???", -1, "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL );
+ return;
+ }
+ scope = long_scope;
+ deref = long_deref;
+ sizelimit = long_sizelimit;
+ timelimit = long_timelimit;
+
+ /*
+ * ignore negative time and size limits since they make no sense
+ */
+ if ( timelimit < 0 ) {
+ timelimit = 0;
+ }
+ if ( sizelimit < 0 ) {
+ sizelimit = 0;
+ }
+
+ if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL
+ && scope != LDAP_SCOPE_SUBTREE ) {
+ log_search_access (pb, base, scope, "???", "Unknown search scope");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "Unknown search scope", 0, NULL );
+ goto free_and_return;
+ }
+ /* check and record the scope for snmp */
+ if ( scope == LDAP_SCOPE_ONELEVEL) {
+ /* count the one level search request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps);
+
+ } else if (scope == LDAP_SCOPE_SUBTREE) {
+ /* count the subtree search request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps);
+ }
+
+ /* filter - returns a "normalized" version */
+ filter = NULL;
+ fstr = NULL;
+ if ( (err = get_filter( pb->pb_conn, ber, scope, &filter, &fstr )) != 0 ) {
+ char *errtxt;
+
+ if ( LDAP_UNWILLING_TO_PERFORM == err ) {
+ errtxt = "The search filter is too deeply nested";
+ } else {
+ errtxt = "Bad search filter";
+ }
+ log_search_access( pb, base, scope, "???", errtxt );
+ send_ldap_result( pb, err, NULL, errtxt, 0, NULL );
+ goto free_and_return;
+ }
+
+ /* attributes */
+ attrs = NULL;
+ if ( ber_scanf( ber, "{v}}", &attrs ) == LBER_ERROR ) {
+ log_search_access (pb, base, scope, fstr, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
+ NULL );
+ goto free_and_return;
+ }
+
+ /*
+ * This search is performed against the legacy consumer, so ask explicitly
+ * for the aci attribute as it is an operational in 5.0
+ */
+ if ( operation->o_flags & OP_FLAG_LEGACY_REPLICATION_DN )
+ {
+ /* If attrs==NULL in a 4.x request, means that we want all the attributes, as aci is
+ * now operational, we need to ask it explicilty as well as all the attributes
+ */
+ if ( (attrs == NULL) || (attrs[0] == NULL) )
+ {
+ charray_add(&attrs, slapi_attr_syntax_normalize("aci"));
+ charray_add(&attrs, slapi_attr_syntax_normalize(LDAP_ALL_USER_ATTRS));
+ }
+ else
+ {
+ for ( i = 0; attrs[i] != NULL; i++ )
+ {
+ if ( strcasecmp(attrs[i], LDAP_ALL_USER_ATTRS) == 0 )
+ {
+ charray_add(&attrs, slapi_attr_syntax_normalize("aci"));
+ break;
+ }
+ }
+ }
+ }
+
+ if ( attrs != NULL ) {
+ operation->o_searchattrs = cool_charray_dup( attrs );
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ char *type;
+
+ type = slapi_attr_syntax_normalize(attrs[i]);
+ slapi_ch_free( (void**)&(attrs[i]) );
+ attrs[i] = type;
+ }
+ }
+ if ( slapd_ldap_debug & LDAP_DEBUG_ARGS ) {
+ char abuf[ 1024 ], *astr;
+
+ if ( NULL == attrs ) {
+ astr = "ALL";
+ } else {
+ strarray2str( attrs, abuf, sizeof( abuf ), 1 /* include quotes */);
+ astr = abuf;
+ }
+ slapi_log_error( SLAPI_LOG_ARGS, NULL, "SRCH base=\"%s\" "
+ "scope=%d deref=%d "
+ "sizelimit=%d timelimit=%d attrsonly=%d filter=\"%s\" "
+ "attrs=%s\n", base, scope, deref, sizelimit, timelimit,
+ attrsonly, fstr, astr );
+ }
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend. get_ldapmessage_controls()
+ * reads the controls and sets any we know about in the pb.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ log_search_access (pb, base, scope, fstr, "failed to decode LDAP controls");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+
+ /* we support persistent search for regular operations only */
+ if ( slapi_control_present( operation->o_params.request_controls,
+ LDAP_CONTROL_PERSISTENTSEARCH, &psbvp, NULL )){
+ operation_set_flag(operation, OP_FLAG_PS);
+ psearch = 1;
+ if ( ps_parse_control_value( psbvp, &changetypes,
+ &changesonly, &send_entchg_controls ) != LDAP_SUCCESS )
+ {
+ changetypes = LDAP_CHANGETYPE_ANY;
+ send_entchg_controls = 0;
+ }
+ else if ( changesonly )
+ {
+ operation_set_flag(operation, OP_FLAG_PS_CHANGESONLY);
+ }
+ }
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_TARGET, base );
+ slapi_pblock_set( pb, SLAPI_SEARCH_SCOPE, &scope );
+ slapi_pblock_set( pb, SLAPI_SEARCH_DEREF, &deref );
+ slapi_pblock_set( pb, SLAPI_SEARCH_FILTER, filter );
+ slapi_pblock_set( pb, SLAPI_SEARCH_STRFILTER, fstr );
+ slapi_pblock_set( pb, SLAPI_SEARCH_ATTRS, attrs );
+ slapi_pblock_set( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &operation->o_isroot );
+ slapi_pblock_set( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
+ slapi_pblock_set( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
+
+ /* plugins which play with the search may
+ * change the search params may allocate
+ * memory so we need to keep track of
+ * changed base search strings
+ */
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &original_base);
+
+ op_shared_search (pb, psearch ? 0 : 1/* send result */);
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &new_base);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
+
+ if ( psearch && rc == 0 ) {
+ ps_add( pb, changetypes, send_entchg_controls );
+ }
+
+free_and_return:;
+ if ( !psearch || rc < 0 ) {
+ if(original_base != new_base) {
+ slapi_ch_free_string(&new_base);
+ }
+ slapi_ch_free_string(&base);
+ slapi_ch_free_string(&fstr);
+ slapi_filter_free( filter, 1 );
+ if ( attrs != NULL ) {
+ charray_free( attrs );
+ }
+ /*
+ * Fix for defect 526719 / 553356 : Persistent search op failed.
+ * Marking it as non-persistent so that operation resources get freed
+ */
+ if (psearch){
+ operation->o_flags &= ~OP_FLAG_PS;
+ }
+ }
+}
+
+static void log_search_access (Slapi_PBlock *pb, const char *base, int scope, const char *fstr, const char *msg)
+{
+ char ebuf[BUFSIZ];
+ slapi_log_access(LDAP_DEBUG_STATS,
+ "conn=%d op=%d SRCH base=\"%s\" scope=%d filter=\"%s\", %s\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid,
+ escape_string(base, ebuf), scope, fstr, msg ? msg : "");
+
+}