1 /* $OpenLDAP: pkg/ldap/servers/slapd/search.c,v 1.181.2.5 2008/04/14 22:16:16 quanah Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
15 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
16 * All rights reserved.
18 * Redistribution and use in source and binary forms are permitted
19 * provided that this notice is preserved and that due credit is given
20 * to the University of Michigan at Ann Arbor. The name of the University
21 * may not be used to endorse or promote products derived from this
22 * software without specific prior written permission. This software
23 * is provided ``as is'' without express or implied warranty.
30 #include <ac/string.h>
31 #include <ac/socket.h>
38 Operation
*op
, /* info about the op to which we're responding */
39 SlapReply
*rs
/* all the response data we'll send */ )
41 struct berval base
= BER_BVNULL
;
42 ber_len_t siz
, off
, i
;
44 Debug( LDAP_DEBUG_TRACE
, "%s do_search\n",
45 op
->o_log_prefix
, 0, 0 );
47 * Parse the search request. It looks like this:
49 * SearchRequest := [APPLICATION 3] SEQUENCE {
50 * baseObject DistinguishedName,
55 * subordinate (3) -- OpenLDAP extension
57 * derefAliases ENUMERATED {
58 * neverDerefaliases (0),
59 * derefInSearching (1),
60 * derefFindingBaseObj (2),
61 * alwaysDerefAliases (3)
63 * sizelimit INTEGER (0 .. 65535),
64 * timelimit INTEGER (0 .. 65535),
67 * attributes SEQUENCE OF AttributeType
71 /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
72 if ( ber_scanf( op
->o_ber
, "{miiiib" /*}*/,
73 &base
, &op
->ors_scope
, &op
->ors_deref
, &op
->ors_slimit
,
74 &op
->ors_tlimit
, &op
->ors_attrsonly
) == LBER_ERROR
)
76 send_ldap_discon( op
, rs
, LDAP_PROTOCOL_ERROR
, "decoding error" );
77 rs
->sr_err
= SLAPD_DISCONNECT
;
81 if ( op
->ors_tlimit
< 0 || op
->ors_tlimit
> SLAP_MAX_LIMIT
) {
82 send_ldap_error( op
, rs
, LDAP_PROTOCOL_ERROR
, "invalid time limit" );
86 if ( op
->ors_slimit
< 0 || op
->ors_slimit
> SLAP_MAX_LIMIT
) {
87 send_ldap_error( op
, rs
, LDAP_PROTOCOL_ERROR
, "invalid size limit" );
91 switch( op
->ors_scope
) {
93 case LDAP_SCOPE_ONELEVEL
:
94 case LDAP_SCOPE_SUBTREE
:
95 case LDAP_SCOPE_SUBORDINATE
:
98 send_ldap_error( op
, rs
, LDAP_PROTOCOL_ERROR
, "invalid scope" );
102 switch( op
->ors_deref
) {
103 case LDAP_DEREF_NEVER
:
104 case LDAP_DEREF_FINDING
:
105 case LDAP_DEREF_SEARCHING
:
106 case LDAP_DEREF_ALWAYS
:
109 send_ldap_error( op
, rs
, LDAP_PROTOCOL_ERROR
, "invalid deref" );
113 rs
->sr_err
= dnPrettyNormal( NULL
, &base
, &op
->o_req_dn
, &op
->o_req_ndn
, op
->o_tmpmemctx
);
114 if( rs
->sr_err
!= LDAP_SUCCESS
) {
115 Debug( LDAP_DEBUG_ANY
, "%s do_search: invalid dn (%s)\n",
116 op
->o_log_prefix
, base
.bv_val
, 0 );
117 send_ldap_error( op
, rs
, LDAP_INVALID_DN_SYNTAX
, "invalid DN" );
121 Debug( LDAP_DEBUG_ARGS
, "SRCH \"%s\" %d %d",
122 base
.bv_val
, op
->ors_scope
, op
->ors_deref
);
123 Debug( LDAP_DEBUG_ARGS
, " %d %d %d\n",
124 op
->ors_slimit
, op
->ors_tlimit
, op
->ors_attrsonly
);
126 /* filter - returns a "normalized" version */
127 rs
->sr_err
= get_filter( op
, op
->o_ber
, &op
->ors_filter
, &rs
->sr_text
);
128 if( rs
->sr_err
!= LDAP_SUCCESS
) {
129 if( rs
->sr_err
== SLAPD_DISCONNECT
) {
130 rs
->sr_err
= LDAP_PROTOCOL_ERROR
;
131 send_ldap_disconnect( op
, rs
);
132 rs
->sr_err
= SLAPD_DISCONNECT
;
134 send_ldap_result( op
, rs
);
138 filter2bv_x( op
, op
->ors_filter
, &op
->ors_filterstr
);
140 Debug( LDAP_DEBUG_ARGS
, " filter: %s\n",
141 !BER_BVISEMPTY( &op
->ors_filterstr
) ? op
->ors_filterstr
.bv_val
: "empty", 0, 0 );
144 siz
= sizeof(AttributeName
);
145 off
= offsetof(AttributeName
,an_name
);
146 if ( ber_scanf( op
->o_ber
, "{M}}", &op
->ors_attrs
, &siz
, off
) == LBER_ERROR
) {
147 send_ldap_discon( op
, rs
, LDAP_PROTOCOL_ERROR
, "decoding attrs error" );
148 rs
->sr_err
= SLAPD_DISCONNECT
;
151 for ( i
=0; i
<siz
; i
++ ) {
152 const char *dummy
; /* ignore msgs from bv2ad */
153 op
->ors_attrs
[i
].an_desc
= NULL
;
154 op
->ors_attrs
[i
].an_oc
= NULL
;
155 op
->ors_attrs
[i
].an_oc_exclude
= 0;
156 if ( slap_bv2ad( &op
->ors_attrs
[i
].an_name
,
157 &op
->ors_attrs
[i
].an_desc
, &dummy
) != LDAP_SUCCESS
)
159 slap_bv2undef_ad( &op
->ors_attrs
[i
].an_name
,
160 &op
->ors_attrs
[i
].an_desc
, &dummy
,
161 SLAP_AD_PROXIED
|SLAP_AD_NOINSERT
);
165 if( get_ctrls( op
, rs
, 1 ) != LDAP_SUCCESS
) {
166 Debug( LDAP_DEBUG_ANY
, "%s do_search: get_ctrls failed\n",
167 op
->o_log_prefix
, 0, 0 );
171 Debug( LDAP_DEBUG_ARGS
, " attrs:", 0, 0, 0 );
174 for ( i
= 0; i
<siz
; i
++ ) {
175 Debug( LDAP_DEBUG_ARGS
, " %s", op
->ors_attrs
[i
].an_name
.bv_val
, 0, 0 );
179 Debug( LDAP_DEBUG_ARGS
, "\n", 0, 0, 0 );
181 if ( StatslogTest( LDAP_DEBUG_STATS
) ) {
182 char abuf
[BUFSIZ
/2], *ptr
= abuf
;
185 sprintf(abuf
, "scope=%d deref=%d", op
->ors_scope
, op
->ors_deref
);
186 Statslog( LDAP_DEBUG_STATS
,
187 "%s SRCH base=\"%s\" %s filter=\"%s\"\n",
188 op
->o_log_prefix
, op
->o_req_dn
.bv_val
, abuf
,
189 op
->ors_filterstr
.bv_val
, 0 );
191 for ( i
= 0; i
<siz
; i
++ ) {
192 alen
= op
->ors_attrs
[i
].an_name
.bv_len
;
193 if (alen
>= sizeof(abuf
)) {
194 alen
= sizeof(abuf
)-1;
196 if (len
&& (len
+ 1 + alen
>= sizeof(abuf
))) {
197 Statslog( LDAP_DEBUG_STATS
, "%s SRCH attr=%s\n",
198 op
->o_log_prefix
, abuf
, 0, 0, 0 );
206 ptr
= lutil_strncopy(ptr
, op
->ors_attrs
[i
].an_name
.bv_val
, alen
);
211 Statslog( LDAP_DEBUG_STATS
, "%s SRCH attr=%s\n",
212 op
->o_log_prefix
, abuf
, 0, 0, 0 );
216 op
->o_bd
= frontendDB
;
217 rs
->sr_err
= frontendDB
->be_search( op
, rs
);
220 if ( !BER_BVISNULL( &op
->o_req_dn
) ) {
221 slap_sl_free( op
->o_req_dn
.bv_val
, op
->o_tmpmemctx
);
223 if ( !BER_BVISNULL( &op
->o_req_ndn
) ) {
224 slap_sl_free( op
->o_req_ndn
.bv_val
, op
->o_tmpmemctx
);
226 if ( !BER_BVISNULL( &op
->ors_filterstr
) ) {
227 op
->o_tmpfree( op
->ors_filterstr
.bv_val
, op
->o_tmpmemctx
);
229 if ( op
->ors_filter
!= NULL
) {
230 filter_free_x( op
, op
->ors_filter
);
232 if ( op
->ors_attrs
!= NULL
) {
233 op
->o_tmpfree( op
->ors_attrs
, op
->o_tmpmemctx
);
240 fe_op_search( Operation
*op
, SlapReply
*rs
)
242 BackendDB
*bd
= op
->o_bd
;
244 if ( op
->ors_scope
== LDAP_SCOPE_BASE
) {
247 if ( BER_BVISEMPTY( &op
->o_req_ndn
) ) {
248 #ifdef LDAP_CONNECTIONLESS
249 /* Ignore LDAPv2 CLDAP Root DSE queries */
250 if (op
->o_protocol
== LDAP_VERSION2
&& op
->o_conn
->c_is_udp
) {
254 /* check restrictions */
255 if( backend_check_restrictions( op
, rs
, NULL
) != LDAP_SUCCESS
) {
256 send_ldap_result( op
, rs
);
260 rs
->sr_err
= root_dse_info( op
->o_conn
, &entry
, &rs
->sr_text
);
262 } else if ( bvmatch( &op
->o_req_ndn
, &frontendDB
->be_schemandn
) ) {
263 /* check restrictions */
264 if( backend_check_restrictions( op
, rs
, NULL
) != LDAP_SUCCESS
) {
265 send_ldap_result( op
, rs
);
269 rs
->sr_err
= schema_info( &entry
, &rs
->sr_text
);
272 if( rs
->sr_err
!= LDAP_SUCCESS
) {
273 send_ldap_result( op
, rs
);
276 } else if ( entry
!= NULL
) {
277 rs
->sr_err
= test_filter( op
, entry
, op
->ors_filter
);
279 if( rs
->sr_err
== LDAP_COMPARE_TRUE
) {
280 /* note: we set no limits because either
281 * no limit is specified, or at least 1
282 * is specified, and we're going to return
283 * at most one entry */
284 op
->ors_slimit
= SLAP_NO_LIMIT
;
285 op
->ors_tlimit
= SLAP_NO_LIMIT
;
287 rs
->sr_entry
= entry
;
288 rs
->sr_attrs
= op
->ors_attrs
;
289 rs
->sr_operational_attrs
= NULL
;
291 send_search_entry( op
, rs
);
293 rs
->sr_operational_attrs
= NULL
;
297 rs
->sr_err
= LDAP_SUCCESS
;
298 send_ldap_result( op
, rs
);
303 if( BER_BVISEMPTY( &op
->o_req_ndn
) && !BER_BVISEMPTY( &default_search_nbase
) ) {
304 slap_sl_free( op
->o_req_dn
.bv_val
, op
->o_tmpmemctx
);
305 slap_sl_free( op
->o_req_ndn
.bv_val
, op
->o_tmpmemctx
);
307 ber_dupbv_x( &op
->o_req_dn
, &default_search_base
, op
->o_tmpmemctx
);
308 ber_dupbv_x( &op
->o_req_ndn
, &default_search_nbase
, op
->o_tmpmemctx
);
312 * We could be serving multiple database backends. Select the
313 * appropriate one, or send a referral to our "referral server"
314 * if we don't hold it.
317 op
->o_bd
= select_backend( &op
->o_req_ndn
, 1 );
318 if ( op
->o_bd
== NULL
) {
319 rs
->sr_ref
= referral_rewrite( default_referral
,
320 NULL
, &op
->o_req_dn
, op
->ors_scope
);
322 if (!rs
->sr_ref
) rs
->sr_ref
= default_referral
;
323 rs
->sr_err
= LDAP_REFERRAL
;
325 send_ldap_result( op
, rs
);
327 if (rs
->sr_ref
!= default_referral
)
328 ber_bvarray_free( rs
->sr_ref
);
333 /* check restrictions */
334 if( backend_check_restrictions( op
, rs
, NULL
) != LDAP_SUCCESS
) {
335 send_ldap_result( op
, rs
);
339 /* check for referrals */
340 if( backend_check_referrals( op
, rs
) != LDAP_SUCCESS
) {
344 if ( SLAP_SHADOW(op
->o_bd
) && get_dontUseCopy(op
) ) {
345 /* don't use shadow copy */
346 BerVarray defref
= op
->o_bd
->be_update_refs
347 ? op
->o_bd
->be_update_refs
: default_referral
;
349 if( defref
!= NULL
) {
350 rs
->sr_ref
= referral_rewrite( defref
,
351 NULL
, &op
->o_req_dn
, op
->ors_scope
);
352 if( !rs
->sr_ref
) rs
->sr_ref
= defref
;
353 rs
->sr_err
= LDAP_REFERRAL
;
354 send_ldap_result( op
, rs
);
356 if (rs
->sr_ref
!= defref
) ber_bvarray_free( rs
->sr_ref
);
359 send_ldap_error( op
, rs
, LDAP_UNWILLING_TO_PERFORM
,
360 "copy not used; no referral information available" );
363 } else if ( op
->o_bd
->be_search
) {
364 if ( limits_check( op
, rs
) == 0 ) {
365 /* actually do the search and send the result(s) */
366 (op
->o_bd
->be_search
)( op
, rs
);
368 /* else limits_check() sends error */
371 send_ldap_error( op
, rs
, LDAP_UNWILLING_TO_PERFORM
,
372 "operation not supported within namingContext" );