search.c 12 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
4
 * Copyright 1998-2021 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
7
8
9
10
11
12
13
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
14
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
15
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
16
17
18
19
20
21
22
23
24
25
 * 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.
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
26
27
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
28
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
29
30
31
32

#include <ac/string.h>
#include <ac/socket.h>

Howard Chu's avatar
Howard Chu committed
33
#include "lutil.h"
34
#include "slap.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
35

36
int
37
do_search(
38
    Operation	*op,	/* info about the op to which we're responding */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
39
40
    SlapReply	*rs	/* all the response data we'll send */ )
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
41
	struct berval base = BER_BVNULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
42
	ber_len_t	siz, off, i;
43

44
	Debug( LDAP_DEBUG_TRACE, "%s do_search\n",
45
		op->o_log_prefix );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
46
47
48
49
50
51
52
53
	/*
	 * Parse the search request.  It looks like this:
	 *
	 *	SearchRequest := [APPLICATION 3] SEQUENCE {
	 *		baseObject	DistinguishedName,
	 *		scope		ENUMERATED {
	 *			baseObject	(0),
	 *			singleLevel	(1),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
54
55
	 *			wholeSubtree (2),
	 *          subordinate (3)  -- OpenLDAP extension
Kurt Zeilenga's avatar
Kurt Zeilenga committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
	 *		},
	 *		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 */
72
	if ( ber_scanf( op->o_ber, "{miiiib" /*}*/,
Howard Chu's avatar
Howard Chu committed
73
74
		&base, &op->ors_scope, &op->ors_deref, &op->ors_slimit,
	    &op->ors_tlimit, &op->ors_attrsonly ) == LBER_ERROR )
75
	{
76
77
		send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
		rs->sr_err = SLAPD_DISCONNECT;
78
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
79
	}
80

81
82
83
84
85
86
87
88
89
90
	if ( op->ors_tlimit < 0 || op->ors_tlimit > SLAP_MAX_LIMIT ) {
		send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid time limit" );
		goto return_results;
	}

	if ( op->ors_slimit < 0 || op->ors_slimit > SLAP_MAX_LIMIT ) {
		send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid size limit" );
		goto return_results;
	}

Howard Chu's avatar
Howard Chu committed
91
	switch( op->ors_scope ) {
92
93
94
	case LDAP_SCOPE_BASE:
	case LDAP_SCOPE_ONELEVEL:
	case LDAP_SCOPE_SUBTREE:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
95
	case LDAP_SCOPE_SUBORDINATE:
96
97
		break;
	default:
98
		send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid scope" );
99
100
101
		goto return_results;
	}

Howard Chu's avatar
Howard Chu committed
102
	switch( op->ors_deref ) {
103
104
105
106
107
108
	case LDAP_DEREF_NEVER:
	case LDAP_DEREF_FINDING:
	case LDAP_DEREF_SEARCHING:
	case LDAP_DEREF_ALWAYS:
		break;
	default:
109
		send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid deref" );
110
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
111
	}
112

Howard Chu's avatar
Howard Chu committed
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 ) {
Howard Chu's avatar
Howard Chu committed
115
		Debug( LDAP_DEBUG_ANY, "%s do_search: invalid dn: \"%s\"\n",
116
			op->o_log_prefix, base.bv_val );
117
		send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
118
119
		goto return_results;
	}
Howard Chu's avatar
Howard Chu committed
120

Howard Chu's avatar
Howard Chu committed
121
122
	Debug( LDAP_DEBUG_ARGS, "SRCH \"%s\" %d %d    %d %d %d\n",
		base.bv_val, op->ors_scope, op->ors_deref,
Howard Chu's avatar
Howard Chu committed
123
		op->ors_slimit, op->ors_tlimit, op->ors_attrsonly);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
124
125

	/* filter - returns a "normalized" version */
126
	rs->sr_err = get_filter( op, op->o_ber, &op->ors_filter, &rs->sr_text );
127
128
129
130
	if( rs->sr_err != LDAP_SUCCESS ) {
		if( rs->sr_err == SLAPD_DISCONNECT ) {
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			send_ldap_disconnect( op, rs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
131
			rs->sr_err = SLAPD_DISCONNECT;
132
		} else {
133
			send_ldap_result( op, rs );
134
		}
135
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
136
	}
Howard Chu's avatar
Howard Chu committed
137
	filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
Sang Seok Lim's avatar
Sang Seok Lim committed
138
	
139
	Debug( LDAP_DEBUG_ARGS, "    filter: %s\n",
140
		!BER_BVISEMPTY( &op->ors_filterstr ) ? op->ors_filterstr.bv_val : "empty" );
141

Kurt Zeilenga's avatar
Kurt Zeilenga committed
142
	/* attributes */
143
	siz = sizeof(AttributeName);
144
	off = offsetof(AttributeName,an_name);
Howard Chu's avatar
Howard Chu committed
145
	if ( ber_scanf( op->o_ber, "{M}}", &op->ors_attrs, &siz, off ) == LBER_ERROR ) {
146
147
		send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding attrs error" );
		rs->sr_err = SLAPD_DISCONNECT;
148
149
		goto return_results;
	}
150
	for ( i=0; i<siz; i++ ) {
151
		const char *dummy;	/* ignore msgs from bv2ad */
Howard Chu's avatar
Howard Chu committed
152
153
		op->ors_attrs[i].an_desc = NULL;
		op->ors_attrs[i].an_oc = NULL;
154
		op->ors_attrs[i].an_flags = 0;
155
156
157
		if ( slap_bv2ad( &op->ors_attrs[i].an_name,
			&op->ors_attrs[i].an_desc, &dummy ) != LDAP_SUCCESS )
		{
158
			if ( slap_bv2undef_ad( &op->ors_attrs[i].an_name,
159
				&op->ors_attrs[i].an_desc, &dummy,
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
				SLAP_AD_PROXIED|SLAP_AD_NOINSERT ) )
			{
				struct berval *bv = &op->ors_attrs[i].an_name;

				/* RFC 4511 LDAPv3: All User Attributes */
				if ( bvmatch( bv, slap_bv_all_user_attrs ) ) {
					continue;
				}

				/* RFC 3673 LDAPv3: All Operational Attributes */
				if ( bvmatch( bv, slap_bv_all_operational_attrs ) ) {
					continue;
				}

				/* RFC 4529 LDAP: Requesting Attributes by Object Class */
				if ( bv->bv_len > 1 && bv->bv_val[0] == '@' ) {
					/* FIXME: check if remaining is valid oc name? */
					continue;
				}

				/* add more "exceptions" to RFC 4511 4.5.1.8. */

				/* invalid attribute description? remove */
				if ( ad_keystring( bv ) ) {
					/* NOTE: parsed in-place, don't modify;
					 * rather add "1.1", which must be ignored */
					BER_BVSTR( &op->ors_attrs[i].an_name, LDAP_NO_ATTRS );
				}

				/* otherwise leave in place... */
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
192
	}
193

194
	if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
195
		Debug( LDAP_DEBUG_ANY, "%s do_search: get_ctrls failed\n",
196
			op->o_log_prefix );
197
		goto return_results;
198
	}
199

Howard Chu's avatar
Howard Chu committed
200
201
202
	if (LogTest( LDAP_DEBUG_ARGS ) ) {
		char abuf[BUFSIZ/2], *ptr = abuf;
		unsigned len = 0, alen;
203

Howard Chu's avatar
Howard Chu committed
204
205
206
207
		if ( !siz ) {
			len = 1;
			abuf[0] = '\0';
		}
208
		for ( i = 0; i<siz; i++ ) {
Howard Chu's avatar
Howard Chu committed
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
			alen = op->ors_attrs[i].an_name.bv_len;
			if (alen >= sizeof(abuf)) {
				alen = sizeof(abuf)-1;
			}
			if (len && (len + 1 + alen >= sizeof(abuf))) {
				Debug( LDAP_DEBUG_ARGS, "    attrs: %s\n", abuf );
				len = 0;
				ptr = abuf;
			}
			if (len) {
				*ptr++ = ' ';
				len++;
			}
			ptr = lutil_strncopy(ptr, op->ors_attrs[i].an_name.bv_val, alen);
			len += alen;
			*ptr = '\0';
		}
		if (len) {
			Debug( LDAP_DEBUG_ARGS, "    attrs: %s\n", abuf );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
228
229
		}
	}
230

231
	if (LogTest( LDAP_DEBUG_STATS ) ) {
Howard Chu's avatar
Howard Chu committed
232
		char abuf[BUFSIZ/2], *ptr = abuf;
233
		unsigned len = 0, alen;
Howard Chu's avatar
Howard Chu committed
234

235
		sprintf(abuf, "scope=%d deref=%d", op->ors_scope, op->ors_deref);
236
		Debug( LDAP_DEBUG_STATS,
237
238
		        "%s SRCH base=\"%s\" %s filter=\"%s\"\n",
		        op->o_log_prefix, op->o_req_dn.bv_val, abuf,
239
		        op->ors_filterstr.bv_val );
Howard Chu's avatar
Howard Chu committed
240
241

		for ( i = 0; i<siz; i++ ) {
Howard Chu's avatar
Howard Chu committed
242
			alen = op->ors_attrs[i].an_name.bv_len;
Howard Chu's avatar
Howard Chu committed
243
244
245
246
			if (alen >= sizeof(abuf)) {
				alen = sizeof(abuf)-1;
			}
			if (len && (len + 1 + alen >= sizeof(abuf))) {
247
248
				Debug( LDAP_DEBUG_STATS, "%s SRCH attr=%s\n",
				    op->o_log_prefix, abuf );
249
				len = 0;
Howard Chu's avatar
Howard Chu committed
250
251
252
253
254
255
				ptr = abuf;
			}
			if (len) {
				*ptr++ = ' ';
				len++;
			}
Howard Chu's avatar
Howard Chu committed
256
			ptr = lutil_strncopy(ptr, op->ors_attrs[i].an_name.bv_val, alen);
Howard Chu's avatar
Howard Chu committed
257
258
			len += alen;
			*ptr = '\0';
Howard Chu's avatar
Howard Chu committed
259
260
		}
		if (len) {
261
262
			Debug( LDAP_DEBUG_STATS, "%s SRCH attr=%s\n",
					op->o_log_prefix, abuf );
Howard Chu's avatar
Howard Chu committed
263
264
		}
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
265

266
267
	op->o_bd = frontendDB;
	rs->sr_err = frontendDB->be_search( op, rs );
268
269
270
271
	if ( rs->sr_err == SLAPD_ASYNCOP ) {
		/* skip cleanup */
		return rs->sr_err;
	}
272
273
274
275
276
277
278
279
280
281
282
283

return_results:;
	if ( !BER_BVISNULL( &op->o_req_dn ) ) {
		slap_sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx );
	}
	if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
		slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );
	}
	if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
		op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
	}
	if ( op->ors_filter != NULL) {
284
		filter_free_x( op, op->ors_filter, 1 );
285
286
287
288
289
290
291
292
293
294
295
	}
	if ( op->ors_attrs != NULL ) {
		op->o_tmpfree( op->ors_attrs, op->o_tmpmemctx );
	}

	return rs->sr_err;
}

int
fe_op_search( Operation *op, SlapReply *rs )
{
296
	BackendDB		*bd = op->o_bd;
297

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

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
301
		if ( BER_BVISEMPTY( &op->o_req_ndn ) ) {
302
#ifdef LDAP_CONNECTIONLESS
303
			/* Ignore LDAPv2 CLDAP Root DSE queries */
304
			if (op->o_protocol == LDAP_VERSION2 && op->o_conn->c_is_udp) {
305
306
307
				goto return_results;
			}
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
308
			/* check restrictions */
309
310
			if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
				send_ldap_result( op, rs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
311
312
313
				goto return_results;
			}

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

316
		} else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
317
			/* check restrictions */
318
319
			if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
				send_ldap_result( op, rs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
320
321
322
				goto return_results;
			}

323
			rs->sr_err = schema_info( &entry, &rs->sr_text );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
324
325
		}

326
327
		if( rs->sr_err != LDAP_SUCCESS ) {
			send_ldap_result( op, rs );
328
329
330
			goto return_results;

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

Howard Chu's avatar
Howard Chu committed
337
			rs->sr_err = test_filter( op, entry, op->ors_filter );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
338

339
			if( rs->sr_err == LDAP_COMPARE_TRUE ) {
340
341
342
343
344
345
346
				/* 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;

347
				rs->sr_entry = entry;
Howard Chu's avatar
Howard Chu committed
348
				rs->sr_attrs = op->ors_attrs;
349
				rs->sr_operational_attrs = NULL;
350
				rs->sr_flags = 0;
351
352
				send_search_entry( op, rs );
				rs->sr_entry = NULL;
353
				rs->sr_operational_attrs = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
354
			}
355
			rs->sr_err = LDAP_SUCCESS;
356
357
fail1:
			entry_free( entry );
358
			send_ldap_result( op, rs );
359
360
			goto return_results;
		}
Julio Sánchez Fernández's avatar
   
Julio Sánchez Fernández committed
361
362
	}

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

367
368
		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 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
369
370
371
372
373
374
375
	}

	/*
	 * 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.
	 */
376

377
	op->o_bd = select_backend( &op->o_req_ndn, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
378
	if ( op->o_bd == NULL ) {
379
		rs->sr_ref = referral_rewrite( default_referral,
Howard Chu's avatar
Howard Chu committed
380
			NULL, &op->o_req_dn, op->ors_scope );
381

382
		if (!rs->sr_ref) rs->sr_ref = default_referral;
383
		rs->sr_err = LDAP_REFERRAL;
384
		op->o_bd = bd;
385
		send_ldap_result( op, rs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
386

387
		if (rs->sr_ref != default_referral)
388
389
		ber_bvarray_free( rs->sr_ref );
		rs->sr_ref = NULL;
390
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
391
392
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
393
	/* check restrictions */
394
395
	if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
396
397
398
		goto return_results;
	}

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

404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
	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 ) {
424
		if ( limits_check( op, rs ) == 0 ) {
425
			/* actually do the search and send the result(s) */
426
427
428
429
			(op->o_bd->be_search)( op, rs );
		}
		/* else limits_check() sends error */

430
	} else {
431
432
		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
			"operation not supported within namingContext" );
433
434
	}

435
return_results:;
436
	op->o_bd = bd;
437
	return rs->sr_err;
438
439
}