xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-ldap/search.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: search.c,v 1.3 2021/08/14 16:14:59 christos Exp $	*/
2 
3 /* search.c - ldap backend search function */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1999-2021 The OpenLDAP Foundation.
8  * Portions Copyright 1999-2003 Howard Chu.
9  * Portions Copyright 2000-2003 Pierangelo Masarati.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* ACKNOWLEDGEMENTS:
21  * This work was initially developed by the Howard Chu for inclusion
22  * in OpenLDAP Software and subsequently enhanced by Pierangelo
23  * Masarati.
24  */
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: search.c,v 1.3 2021/08/14 16:14:59 christos Exp $");
28 
29 #include "portable.h"
30 
31 #include <stdio.h>
32 
33 #include <ac/socket.h>
34 #include <ac/string.h>
35 #include <ac/time.h>
36 
37 #include "slap.h"
38 #include "back-ldap.h"
39 #include "../../../libraries/liblber/lber-int.h"
40 
41 #include "lutil.h"
42 
43 static int
44 ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent,
45 	 struct berval *bdn, int remove_unknown_schema );
46 
47 
48 static ObjectClass *
oc_bvfind_undef_ex(struct berval * ocname,int flag)49 oc_bvfind_undef_ex( struct berval *ocname, int flag )
50 {
51 	ObjectClass	*oc	= oc_bvfind( ocname );
52 
53 	if ( oc || flag ) {
54 		/* oc defined or remove-unknown-schema flag set */
55 		return oc;
56 	}
57 
58 	return oc_bvfind_undef( ocname );
59 }
60 
61 
62 /*
63  * replaces (&) with (objectClass=*) and (|) with (!(objectClass=*))
64  * as the best replacement for RFC 4526 absolute true/absolute false
65  * filters; the only difference (AFAIK) is that they require search
66  * access to objectClass.
67  *
68  * filter->bv_val may be alloc'd on the thread's slab, if equal to
69  * op->ors_filterstr.bv_val, or realloc'd on the thread's slab otherwise.
70  */
71 static int
ldap_back_munge_filter(Operation * op,struct berval * filter)72 ldap_back_munge_filter(
73 	Operation	*op,
74 	struct berval	*filter )
75 {
76 	char *ptr;
77 	int gotit = 0;
78 
79 	Debug( LDAP_DEBUG_ARGS, "=> ldap_back_munge_filter \"%s\"\n",
80 			filter->bv_val );
81 
82 	for ( ptr = strchr( filter->bv_val, '(' );
83 			ptr;
84 			ptr = strchr( ptr, '(' ) )
85 	{
86 		static struct berval
87 			bv_t = BER_BVC( "(&)" ),
88 			bv_f = BER_BVC( "(|)" ),
89 			bv_T = BER_BVC( "(objectClass=*)" ),
90 			bv_F = BER_BVC( "(!(objectClass=*))" );
91 		struct berval *oldbv = NULL,
92 			*newbv = NULL,
93 			oldfilter = BER_BVNULL;
94 
95 		if ( ptr[2] != ')' ) {
96 			ptr++;
97 			continue;
98 		}
99 
100 		switch ( ptr[1] ) {
101 		case '&':
102 			oldbv = &bv_t;
103 			newbv = &bv_T;
104 			break;
105 
106 		case '|':
107 			oldbv = &bv_f;
108 			newbv = &bv_F;
109 			break;
110 
111 		default:
112 			/* should be an error */
113 			continue;
114 		}
115 
116 		oldfilter = *filter;
117 		filter->bv_len += newbv->bv_len - oldbv->bv_len;
118 		if ( filter->bv_val == op->ors_filterstr.bv_val ) {
119 			filter->bv_val = op->o_tmpalloc( filter->bv_len + 1,
120 					op->o_tmpmemctx );
121 
122 			AC_MEMCPY( filter->bv_val, op->ors_filterstr.bv_val,
123 					ptr - oldfilter.bv_val );
124 
125 		} else {
126 			filter->bv_val = op->o_tmprealloc( filter->bv_val,
127 					filter->bv_len + 1, op->o_tmpmemctx );
128 		}
129 
130 		ptr = filter->bv_val + ( ptr - oldfilter.bv_val );
131 
132 		AC_MEMCPY( &ptr[ newbv->bv_len ],
133 				&ptr[ oldbv->bv_len ],
134 				oldfilter.bv_len - ( ptr - filter->bv_val ) - oldbv->bv_len + 1 );
135 		AC_MEMCPY( ptr, newbv->bv_val, newbv->bv_len );
136 
137 		ptr += newbv->bv_len;
138 
139 		gotit++;
140 	}
141 
142 	Debug( LDAP_DEBUG_ARGS, "<= ldap_back_munge_filter \"%s\" (%d)\n",
143 			filter->bv_val, gotit );
144 
145 	return gotit;
146 }
147 
148 int
ldap_back_search(Operation * op,SlapReply * rs)149 ldap_back_search(
150 		Operation	*op,
151 		SlapReply	*rs )
152 {
153 	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;
154 
155 	ldapconn_t	*lc = NULL;
156 	struct timeval	tv;
157 	time_t		stoptime = (time_t)(-1);
158 	LDAPMessage	*res,
159 			*e;
160 	int		rc = 0,
161 			msgid;
162 	struct berval	match = BER_BVNULL,
163 			filter = BER_BVNULL;
164 	int		i, x;
165 	char		**attrs = NULL;
166 	int		freetext = 0, filter_undef = 0;
167 	int		do_retry = 1, dont_retry = 0;
168 	LDAPControl	**ctrls = NULL;
169 	char		**references = NULL;
170 	int		remove_unknown_schema =
171 				 LDAP_BACK_OMIT_UNKNOWN_SCHEMA (li);
172 
173 	rs_assert_ready( rs );
174 	rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */
175 
176 	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
177 		return rs->sr_err;
178 	}
179 
180 	/*
181 	 * FIXME: in case of values return filter, we might want
182 	 * to map attrs and maybe rewrite value
183 	 */
184 
185 	if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
186 		tv.tv_sec = op->ors_tlimit;
187 		tv.tv_usec = 0;
188 		stoptime = op->o_time + op->ors_tlimit;
189 
190 	} else {
191 		LDAP_BACK_TV_SET( &tv );
192 	}
193 
194 	i = 0;
195 	if ( op->ors_attrs ) {
196 		for ( ; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ )
197 			/* just count attrs */ ;
198 	}
199 
200 	x = 0;
201 	if ( op->o_bd->be_extra_anlist ) {
202 		for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ )
203 			/* just count attrs */ ;
204 	}
205 
206 	if ( i > 0 || x > 0 ) {
207 		int j = 0;
208 
209 		attrs = op->o_tmpalloc( ( i + x + 1 )*sizeof( char * ),
210 			op->o_tmpmemctx );
211 		if ( attrs == NULL ) {
212 			rs->sr_err = LDAP_NO_MEMORY;
213 			rc = -1;
214 			goto finish;
215 		}
216 
217 		if ( i > 0 ) {
218 			for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++, j++ ) {
219 				attrs[ j ] = op->ors_attrs[i].an_name.bv_val;
220 			}
221 		}
222 
223 		if ( x > 0 ) {
224 			for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++, j++ ) {
225 				if ( op->o_bd->be_extra_anlist[x].an_desc &&
226 					ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, op->ors_attrs ) )
227 				{
228 					continue;
229 				}
230 
231 				attrs[ j ] = op->o_bd->be_extra_anlist[x].an_name.bv_val;
232 			}
233 		}
234 
235 		attrs[ j ] = NULL;
236 	}
237 
238 	ctrls = op->o_ctrls;
239 	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
240 	if ( rc != LDAP_SUCCESS ) {
241 		goto finish;
242 	}
243 
244 	/* deal with <draft-zeilenga-ldap-t-f> filters */
245 	filter = op->ors_filterstr;
246 retry:
247 	/* this goes after retry because ldap_back_munge_filter()
248 	 * optionally replaces RFC 4526 T-F filters (&) (|)
249 	 * if already computed, they will be re-installed
250 	 * by filter2bv_undef_x() later */
251 	if ( !LDAP_BACK_T_F( li ) ) {
252 		ldap_back_munge_filter( op, &filter );
253 	}
254 
255 	rs->sr_err = ldap_pvt_search( lc->lc_ld, op->o_req_dn.bv_val,
256 			op->ors_scope, filter.bv_val,
257 			attrs, op->ors_attrsonly, ctrls, NULL,
258 			tv.tv_sec ? &tv : NULL,
259 			op->ors_slimit, op->ors_deref, &msgid );
260 
261 	ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
262 	ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_SEARCH ], 1 );
263 	ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
264 
265 	if ( rs->sr_err != LDAP_SUCCESS ) {
266 		switch ( rs->sr_err ) {
267 		case LDAP_SERVER_DOWN:
268 			if ( do_retry ) {
269 				do_retry = 0;
270 				if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
271 					goto retry;
272 				}
273 			}
274 
275 			if ( lc == NULL ) {
276 				/* reset by ldap_back_retry ... */
277 				rs->sr_err = slap_map_api2result( rs );
278 
279 			} else {
280 				rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_DONTSEND );
281 			}
282 
283 			goto finish;
284 
285 		case LDAP_FILTER_ERROR:
286 			/* first try? */
287 			if ( !filter_undef &&
288 				strstr( filter.bv_val, "(?" ) &&
289 				!LDAP_BACK_NOUNDEFFILTER( li ) )
290 			{
291 				BER_BVZERO( &filter );
292 				filter2bv_undef_x( op, op->ors_filter, 1, &filter );
293 				filter_undef = 1;
294 				goto retry;
295 			}
296 
297 			/* invalid filters return success with no data */
298 			rs->sr_err = LDAP_SUCCESS;
299 			rs->sr_text = NULL;
300 			goto finish;
301 
302 		default:
303 			rs->sr_err = slap_map_api2result( rs );
304 			rs->sr_text = NULL;
305 			goto finish;
306 		}
307 	}
308 
309 	/* if needed, initialize timeout */
310 	if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
311 		if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) {
312 			tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ];
313 			tv.tv_usec = 0;
314 		}
315 	}
316 
317 	/* We pull apart the ber result, stuff it into a slapd entry, and
318 	 * let send_search_entry stuff it back into ber format. Slow & ugly,
319 	 * but this is necessary for version matching, and for ACL processing.
320 	 */
321 
322 	for ( rc = -2; rc != -1; rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ONE, &tv, &res ) )
323 	{
324 		/* check for abandon */
325 		if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( lc ) ) {
326 			if ( rc > 0 ) {
327 				ldap_msgfree( res );
328 			}
329 			(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
330 			rc = SLAPD_ABANDON;
331 			goto finish;
332 		}
333 
334 		if ( rc == 0 || rc == -2 ) {
335 			ldap_pvt_thread_yield();
336 
337 			/* check timeout */
338 			if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
339 				if ( rc == 0 ) {
340 					(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
341 					rs->sr_text = "Operation timed out";
342 					rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
343 						LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
344 					goto finish;
345 				}
346 
347 			} else {
348 				LDAP_BACK_TV_SET( &tv );
349 			}
350 
351 			/* check time limit */
352 			if ( op->ors_tlimit != SLAP_NO_LIMIT
353 					&& slap_get_time() > stoptime )
354 			{
355 				(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
356 				rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
357 				goto finish;
358 			}
359 			continue;
360 
361 		} else {
362 			/* only touch when activity actually took place... */
363 			if ( li->li_idle_timeout ) {
364 				lc->lc_time = op->o_time;
365 			}
366 
367 			/* don't retry any more */
368 			dont_retry = 1;
369 		}
370 
371 
372 		if ( rc == LDAP_RES_SEARCH_ENTRY ) {
373 			Entry		ent = { 0 };
374 			struct berval	bdn = BER_BVNULL;
375 
376 			do_retry = 0;
377 
378 			e = ldap_first_entry( lc->lc_ld, res );
379 			rc = ldap_build_entry( op, e, &ent, &bdn,
380 						remove_unknown_schema);
381 			if ( rc == LDAP_SUCCESS ) {
382 				ldap_get_entry_controls( lc->lc_ld, res, &rs->sr_ctrls );
383 				rs->sr_entry = &ent;
384 				rs->sr_attrs = op->ors_attrs;
385 				rs->sr_operational_attrs = NULL;
386 				rs->sr_flags = 0;
387 				rs->sr_err = LDAP_SUCCESS;
388 				rc = rs->sr_err = send_search_entry( op, rs );
389 				if ( rs->sr_ctrls ) {
390 					ldap_controls_free( rs->sr_ctrls );
391 					rs->sr_ctrls = NULL;
392 				}
393 				rs->sr_entry = NULL;
394 				rs->sr_flags = 0;
395 				if ( !BER_BVISNULL( &ent.e_name ) ) {
396 					assert( ent.e_name.bv_val != bdn.bv_val );
397 					op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx );
398 					BER_BVZERO( &ent.e_name );
399 				}
400 				if ( !BER_BVISNULL( &ent.e_nname ) ) {
401 					op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx );
402 					BER_BVZERO( &ent.e_nname );
403 				}
404 				entry_clean( &ent );
405 			}
406 			ldap_msgfree( res );
407 			switch ( rc ) {
408 			case LDAP_SUCCESS:
409 			case LDAP_INSUFFICIENT_ACCESS:
410 				break;
411 
412 			default:
413 				if ( rc == LDAP_UNAVAILABLE ) {
414 					rc = rs->sr_err = LDAP_OTHER;
415 				} else {
416 					(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
417 				}
418 				goto finish;
419 			}
420 
421 		} else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
422 			if ( LDAP_BACK_NOREFS( li ) ) {
423 				ldap_msgfree( res );
424 				continue;
425 			}
426 
427 			do_retry = 0;
428 			rc = ldap_parse_reference( lc->lc_ld, res,
429 					&references, &rs->sr_ctrls, 1 );
430 
431 			if ( rc != LDAP_SUCCESS ) {
432 				continue;
433 			}
434 
435 			/* FIXME: there MUST be at least one */
436 			if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) {
437 				int		cnt;
438 
439 				for ( cnt = 0; references[ cnt ]; cnt++ )
440 					/* NO OP */ ;
441 
442 				/* FIXME: there MUST be at least one */
443 				rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
444 					op->o_tmpmemctx );
445 
446 				for ( cnt = 0; references[ cnt ]; cnt++ ) {
447 					ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
448 				}
449 				BER_BVZERO( &rs->sr_ref[ cnt ] );
450 
451 				/* ignore return value by now */
452 				RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
453 				rs->sr_entry = NULL;
454 				( void )send_search_reference( op, rs );
455 
456 			} else {
457 				Debug( LDAP_DEBUG_ANY,
458 					"%s ldap_back_search: "
459 					"got SEARCH_REFERENCE "
460 					"with no referrals\n",
461 					op->o_log_prefix );
462 			}
463 
464 			/* cleanup */
465 			if ( references ) {
466 				ber_memvfree( (void **)references );
467 				op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
468 				rs->sr_ref = NULL;
469 				references = NULL;
470 			}
471 
472 			if ( rs->sr_ctrls ) {
473 				ldap_controls_free( rs->sr_ctrls );
474 				rs->sr_ctrls = NULL;
475 			}
476 
477 		} else if ( rc == LDAP_RES_INTERMEDIATE ) {
478 			/* FIXME: response controls
479 			 * are passed without checks */
480 			rc = ldap_parse_intermediate( lc->lc_ld,
481 				res,
482 				(char **)&rs->sr_rspoid,
483 				&rs->sr_rspdata,
484 				&rs->sr_ctrls,
485 				0 );
486 			if ( rc != LDAP_SUCCESS ) {
487 				continue;
488 			}
489 
490 			slap_send_ldap_intermediate( op, rs );
491 
492 			if ( rs->sr_rspoid != NULL ) {
493 				ber_memfree( (char *)rs->sr_rspoid );
494 				rs->sr_rspoid = NULL;
495 			}
496 
497 			if ( rs->sr_rspdata != NULL ) {
498 				ber_bvfree( rs->sr_rspdata );
499 				rs->sr_rspdata = NULL;
500 			}
501 
502 			if ( rs->sr_ctrls != NULL ) {
503 				ldap_controls_free( rs->sr_ctrls );
504 				rs->sr_ctrls = NULL;
505 			}
506 
507 		} else {
508 			char		*err = NULL;
509 
510 			rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
511 					&match.bv_val, &err,
512 					&references, &rs->sr_ctrls, 1 );
513 			if ( rc == LDAP_SUCCESS ) {
514 				if ( err ) {
515 					rs->sr_text = err;
516 					freetext = 1;
517 				}
518 			} else {
519 				rs->sr_err = rc;
520 			}
521 			rs->sr_err = slap_map_api2result( rs );
522 
523 			/* RFC 4511: referrals can only appear
524 			 * if result code is LDAP_REFERRAL */
525 			if ( references
526 				&& references[ 0 ]
527 				&& references[ 0 ][ 0 ] )
528 			{
529 				if ( rs->sr_err != LDAP_REFERRAL ) {
530 					Debug( LDAP_DEBUG_ANY,
531 						"%s ldap_back_search: "
532 						"got referrals with err=%d\n",
533 						op->o_log_prefix,
534 						rs->sr_err );
535 
536 				} else {
537 					int	cnt;
538 
539 					for ( cnt = 0; references[ cnt ]; cnt++ )
540 						/* NO OP */ ;
541 
542 					rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
543 						op->o_tmpmemctx );
544 
545 					for ( cnt = 0; references[ cnt ]; cnt++ ) {
546 						/* duplicating ...*/
547 						ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
548 					}
549 					BER_BVZERO( &rs->sr_ref[ cnt ] );
550 				}
551 
552 			} else if ( rs->sr_err == LDAP_REFERRAL ) {
553 				Debug( LDAP_DEBUG_ANY,
554 					"%s ldap_back_search: "
555 					"got err=%d with null "
556 					"or empty referrals\n",
557 					op->o_log_prefix,
558 					rs->sr_err );
559 
560 				rs->sr_err = LDAP_NO_SUCH_OBJECT;
561 			}
562 
563 			if ( match.bv_val != NULL ) {
564 				match.bv_len = strlen( match.bv_val );
565 			}
566 
567 			rc = 0;
568 			break;
569 		}
570 
571 		/* if needed, restore timeout */
572 		if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
573 			if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) {
574 				tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ];
575 				tv.tv_usec = 0;
576 			}
577 		}
578 	}
579 
580  	if ( rc == -1 ) {
581 		if ( dont_retry == 0 ) {
582 			if ( do_retry ) {
583 				do_retry = 0;
584 				if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
585 					goto retry;
586 				}
587 			}
588 
589 			rs->sr_err = LDAP_SERVER_DOWN;
590 			rs->sr_err = slap_map_api2result( rs );
591 			goto finish;
592 
593 		} else if ( LDAP_BACK_ONERR_STOP( li ) ) {
594 			/* if onerr == STOP */
595 			rs->sr_err = LDAP_SERVER_DOWN;
596 			rs->sr_err = slap_map_api2result( rs );
597 			goto finish;
598 		}
599 	}
600 
601 	/*
602 	 * Rewrite the matched portion of the search base, if required
603 	 */
604 	if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) {
605 		struct berval	pmatch;
606 
607 		if ( dnPretty( NULL, &match, &pmatch, op->o_tmpmemctx ) != LDAP_SUCCESS ) {
608 			pmatch.bv_val = match.bv_val;
609 			match.bv_val = NULL;
610 		}
611 		rs->sr_matched = pmatch.bv_val;
612 		rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
613 	}
614 
615 finish:;
616 	if ( !BER_BVISNULL( &match ) ) {
617 		ber_memfree( match.bv_val );
618 	}
619 
620 	if ( rs->sr_v2ref ) {
621 		rs->sr_err = LDAP_REFERRAL;
622 	}
623 
624 	if ( LDAP_BACK_QUARANTINE( li ) ) {
625 		ldap_back_quarantine( op, rs );
626 	}
627 
628 	if ( filter.bv_val != op->ors_filterstr.bv_val ) {
629 		op->o_tmpfree( filter.bv_val, op->o_tmpmemctx );
630 	}
631 
632 #if 0
633 	/* let send_ldap_result play cleanup handlers (ITS#4645) */
634 	if ( rc != SLAPD_ABANDON )
635 #endif
636 	{
637 		send_ldap_result( op, rs );
638 	}
639 
640 	(void)ldap_back_controls_free( op, rs, &ctrls );
641 
642 	if ( rs->sr_ctrls ) {
643 		ldap_controls_free( rs->sr_ctrls );
644 		rs->sr_ctrls = NULL;
645 	}
646 
647 	if ( rs->sr_text ) {
648 		if ( freetext ) {
649 			ber_memfree( (char *)rs->sr_text );
650 		}
651 		rs->sr_text = NULL;
652 	}
653 
654 	if ( rs->sr_ref ) {
655 		op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
656 		rs->sr_ref = NULL;
657 	}
658 
659 	if ( references ) {
660 		ber_memvfree( (void **)references );
661 	}
662 
663 	if ( attrs ) {
664 		op->o_tmpfree( attrs, op->o_tmpmemctx );
665 	}
666 
667 	if ( lc != NULL ) {
668 		ldap_back_release_conn( li, lc );
669 	}
670 
671 	if ( rs->sr_err == LDAP_UNAVAILABLE &&
672 		/* if we originally bound and wanted rebind-as-user, must drop
673 		 * the connection now because we just discarded the credentials.
674 		 * ITS#7464, #8142
675 		 */
676 		LDAP_BACK_SAVECRED( li ) && SLAP_IS_AUTHZ_BACKEND( op ) )
677 		rs->sr_err = SLAPD_DISCONNECT;
678 	return rs->sr_err;
679 }
680 
681 static int
ldap_build_entry(Operation * op,LDAPMessage * e,Entry * ent,struct berval * bdn,int remove_unknown_schema)682 ldap_build_entry(
683 		Operation	*op,
684 		LDAPMessage	*e,
685 		Entry		*ent,
686 		struct berval	*bdn,
687 		int remove_unknown_schema)
688 {
689 	struct berval	a;
690 	BerElement	ber = *ldap_get_message_ber( e );
691 	Attribute	*attr, **attrp;
692 	const char	*text;
693 	int		last;
694 	char *lastb;
695 	ber_len_t len;
696 
697 	/* safe assumptions ... */
698 	assert( ent != NULL );
699 	BER_BVZERO( &ent->e_bv );
700 
701 	if ( ber_scanf( &ber, "{m", bdn ) == LBER_ERROR ) {
702 		return LDAP_DECODING_ERROR;
703 	}
704 
705 	/*
706 	 * Note: this may fail if the target host(s) schema differs
707 	 * from the one known to the meta, and a DN with unknown
708 	 * attributes is returned.
709 	 *
710 	 * FIXME: should we log anything, or delegate to dnNormalize?
711 	 */
712 	/* Note: if the distinguished values or the naming attributes
713 	 * change, should we massage them as well?
714 	 */
715 	if ( dnPrettyNormal( NULL, bdn, &ent->e_name, &ent->e_nname,
716 		op->o_tmpmemctx ) != LDAP_SUCCESS )
717 	{
718 		return LDAP_INVALID_DN_SYNTAX;
719 	}
720 
721 	ent->e_attrs = NULL;
722 	if ( ber_first_element( &ber, &len, &lastb ) != LBER_SEQUENCE ) {
723 		return LDAP_SUCCESS;
724 	}
725 
726 	attrp = &ent->e_attrs;
727 	while ( ber_next_element( &ber, &len, lastb ) == LBER_SEQUENCE &&
728 		ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
729 		int				i;
730 		slap_syntax_validate_func	*validate;
731 		slap_syntax_transform_func	*pretty;
732 
733 		attr = attr_alloc( NULL );
734 		if ( attr == NULL ) {
735 			return LDAP_OTHER;
736 		}
737 		if ( slap_bv2ad( &a, &attr->a_desc, &text )
738 				!= LDAP_SUCCESS )
739 		{
740 			if ( slap_bv2undef_ad( &a, &attr->a_desc, &text,
741 				 (remove_unknown_schema ? SLAP_AD_NOINSERT : SLAP_AD_PROXIED )) != LDAP_SUCCESS )
742 			{
743 				Debug( LDAP_DEBUG_ANY,
744 					"%s ldap_build_entry: "
745 					"slap_bv2undef_ad(%s): %s\n",
746 					op->o_log_prefix, a.bv_val, text );
747 
748 				( void )ber_scanf( &ber, "x" /* [W] */ );
749 				attr_free( attr );
750 				continue;
751 			}
752 		}
753 
754 		/* no subschemaSubentry */
755 		if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
756 			|| attr->a_desc == slap_schema.si_ad_entryDN )
757 		{
758 
759 			/*
760 			 * We eat target's subschemaSubentry because
761 			 * a search for this value is likely not
762 			 * to resolve to the appropriate backend;
763 			 * later, the local subschemaSubentry is
764 			 * added.
765 			 *
766 			 * We also eat entryDN because the frontend
767 			 * will reattach it without checking if already
768 			 * present...
769 			 */
770 			( void )ber_scanf( &ber, "x" /* [W] */ );
771 			attr_free( attr );
772 			continue;
773 		}
774 
775 		if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
776 				|| attr->a_vals == NULL )
777 		{
778 			/*
779 			 * Note: attr->a_vals can be null when using
780 			 * values result filter
781 			 */
782 			attr->a_vals = (struct berval *)&slap_dummy_bv;
783 		}
784 
785 		validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
786 		pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
787 
788 		if ( !validate && !pretty ) {
789 			attr->a_nvals = NULL;
790 			attr_free( attr );
791 			goto next_attr;
792 		}
793 
794 		for ( i = 0; !BER_BVISNULL( &attr->a_vals[i] ); i++ ) ;
795 		last = i;
796 
797 		/*
798 		 * check that each value is valid per syntax
799 		 * and pretty if appropriate
800 		 */
801 		for ( i = 0; i<last; i++ ) {
802 			struct berval	pval;
803 			int		rc;
804 
805 			if ( pretty ) {
806 				rc = ordered_value_pretty( attr->a_desc,
807 					&attr->a_vals[i], &pval, NULL );
808 
809 			} else {
810 				rc = ordered_value_validate( attr->a_desc,
811 					&attr->a_vals[i], 0 );
812 			}
813 
814 			if ( rc != LDAP_SUCCESS ) {
815 				ObjectClass *oc;
816 
817 				/* check if, by chance, it's an undefined objectClass */
818 				if ( attr->a_desc == slap_schema.si_ad_objectClass &&
819 						( oc = oc_bvfind_undef_ex( &attr->a_vals[i],
820 								remove_unknown_schema ) ) != NULL )
821 				{
822 					ber_dupbv( &pval, &oc->soc_cname );
823 					rc = LDAP_SUCCESS;
824 
825 				} else {
826 					ber_memfree( attr->a_vals[i].bv_val );
827 					if ( --last == i ) {
828 						BER_BVZERO( &attr->a_vals[i] );
829 						break;
830 					}
831 					attr->a_vals[i] = attr->a_vals[last];
832 					BER_BVZERO( &attr->a_vals[last] );
833 					i--;
834 				}
835 			}
836 
837 			if ( rc == LDAP_SUCCESS && pretty ) {
838 				ber_memfree( attr->a_vals[i].bv_val );
839 				attr->a_vals[i] = pval;
840 			}
841 		}
842 		attr->a_numvals = last = i;
843 		if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
844 			attr->a_nvals = NULL;
845 			attr_free( attr );
846 			goto next_attr;
847 		}
848 
849 		if ( last && attr->a_desc->ad_type->sat_equality &&
850 				attr->a_desc->ad_type->sat_equality->smr_normalize )
851 		{
852 			attr->a_nvals = ch_malloc( ( last + 1 )*sizeof( struct berval ) );
853 			for ( i = 0; i < last; i++ ) {
854 				int		rc;
855 
856 				rc = ordered_value_normalize(
857 					SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
858 					attr->a_desc,
859 					attr->a_desc->ad_type->sat_equality,
860 					&attr->a_vals[i], &attr->a_nvals[i],
861 					NULL );
862 
863 				if ( rc != LDAP_SUCCESS ) {
864 					ber_memfree( attr->a_vals[i].bv_val );
865 					if ( --last == i ) {
866 						BER_BVZERO( &attr->a_vals[i] );
867 						break;
868 					}
869 					attr->a_vals[i] = attr->a_vals[last];
870 					BER_BVZERO( &attr->a_vals[last] );
871 					i--;
872 				}
873 			}
874 			BER_BVZERO( &attr->a_nvals[i] );
875 			if ( last == 0 ) {
876 				attr_free( attr );
877 				goto next_attr;
878 			}
879 
880 		} else {
881 			attr->a_nvals = attr->a_vals;
882 		}
883 
884 		attr->a_numvals = last;
885 
886 		/* Handle sorted vals, strip dups but keep the attr */
887 		if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
888 			while ( attr->a_numvals > 1 ) {
889 				int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
890 				if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
891 					break;
892 
893 				/* Strip duplicate values */
894 				if ( attr->a_nvals != attr->a_vals )
895 					ber_memfree( attr->a_nvals[i].bv_val );
896 				ber_memfree( attr->a_vals[i].bv_val );
897 				attr->a_numvals--;
898 
899 				assert( i >= 0 );
900 				if ( (unsigned)i < attr->a_numvals ) {
901 					attr->a_vals[i] = attr->a_vals[attr->a_numvals];
902 					if ( attr->a_nvals != attr->a_vals )
903 						attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
904 				}
905 				BER_BVZERO(&attr->a_vals[attr->a_numvals]);
906 				if ( attr->a_nvals != attr->a_vals )
907 					BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
908 			}
909 			attr->a_flags |= SLAP_ATTR_SORTED_VALS;
910 		}
911 
912 		*attrp = attr;
913 		attrp = &attr->a_next;
914 
915 next_attr:;
916 	}
917 
918 	return LDAP_SUCCESS;
919 }
920 
921 /* return 0 IFF we can retrieve the entry with ndn
922  */
923 int
ldap_back_entry_get(Operation * op,struct berval * ndn,ObjectClass * oc,AttributeDescription * at,int rw,Entry ** ent)924 ldap_back_entry_get(
925 		Operation		*op,
926 		struct berval		*ndn,
927 		ObjectClass		*oc,
928 		AttributeDescription	*at,
929 		int			rw,
930 		Entry			**ent )
931 {
932 	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;
933 
934 	ldapconn_t	*lc = NULL;
935 	int		rc;
936 	struct berval	bdn;
937 	LDAPMessage	*result = NULL,
938 			*e = NULL;
939 	char		*attr[3], **attrp = NULL;
940 	char		*filter = NULL;
941 	SlapReply	rs;
942 	int		do_retry = 1;
943 	LDAPControl	**ctrls = NULL;
944 	Operation op2 = *op;
945 
946 	int		remove_unknown_schema =
947 				LDAP_BACK_OMIT_UNKNOWN_SCHEMA (li);
948 	*ent = NULL;
949 
950 	/* Tell getconn this is a privileged op */
951 	op2.o_do_not_cache = 1;
952 	/* use rootdn to be doubly explicit this is privileged */
953 	op2.o_dn = op->o_bd->be_rootdn;
954 	op2.o_ndn = op->o_bd->be_rootndn;
955 	/* ldap_back_entry_get() is an entry lookup, so it does not need
956 	 * to know what the entry is being looked up for */
957 	op2.o_tag = LDAP_REQ_SEARCH;
958 	op2.o_ctrls = NULL;
959 	rc = ldap_back_dobind( &lc, &op2, &rs, LDAP_BACK_DONTSEND );
960 	if ( !rc ) {
961 		return rs.sr_err;
962 	}
963 
964 	if ( at ) {
965 		attrp = attr;
966 		if ( oc && at != slap_schema.si_ad_objectClass ) {
967 			attr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val;
968 			attr[1] = at->ad_cname.bv_val;
969 			attr[2] = NULL;
970 
971 		} else {
972 			attr[0] = at->ad_cname.bv_val;
973 			attr[1] = NULL;
974 		}
975 	}
976 
977 	if ( oc ) {
978 		char	*ptr;
979 
980 		filter = op->o_tmpalloc( STRLENOF( "(objectClass=" ")" )
981 				+ oc->soc_cname.bv_len + 1, op->o_tmpmemctx );
982 		ptr = lutil_strcopy( filter, "(objectClass=" );
983 		ptr = lutil_strcopy( ptr, oc->soc_cname.bv_val );
984 		*ptr++ = ')';
985 		*ptr++ = '\0';
986 	}
987 
988 retry:
989 	ctrls = NULL;
990 	rc = ldap_back_controls_add( &op2, &rs, lc, &ctrls );
991 	if ( rc != LDAP_SUCCESS ) {
992 		goto cleanup;
993 	}
994 
995 	/* TODO: timeout? */
996 	rc = ldap_pvt_search_s( lc->lc_ld, ndn->bv_val, LDAP_SCOPE_BASE, filter,
997 				attrp, LDAP_DEREF_NEVER, ctrls, NULL,
998 				NULL, LDAP_NO_LIMIT, 0, &result );
999 	if ( rc != LDAP_SUCCESS ) {
1000 		if ( rc == LDAP_SERVER_DOWN && do_retry ) {
1001 			do_retry = 0;
1002 			if ( ldap_back_retry( &lc, &op2, &rs, LDAP_BACK_DONTSEND ) ) {
1003 				/* if the identity changed, there might be need to re-authz */
1004 				(void)ldap_back_controls_free( &op2, &rs, &ctrls );
1005 				goto retry;
1006 			}
1007 		}
1008 		goto cleanup;
1009 	}
1010 
1011 	e = ldap_first_entry( lc->lc_ld, result );
1012 	if ( e == NULL ) {
1013 		/* the entry exists, but it doesn't match the filter? */
1014 		rc = LDAP_NO_RESULTS_RETURNED;
1015 		goto cleanup;
1016 	}
1017 
1018 	*ent = entry_alloc();
1019 	if ( *ent == NULL ) {
1020 		rc = LDAP_NO_MEMORY;
1021 		goto cleanup;
1022 	}
1023 
1024 	rc = ldap_build_entry( op, e, *ent, &bdn, remove_unknown_schema );
1025 
1026 	if ( rc != LDAP_SUCCESS ) {
1027 		entry_free( *ent );
1028 		*ent = NULL;
1029 	}
1030 
1031 cleanup:
1032 	(void)ldap_back_controls_free( &op2, &rs, &ctrls );
1033 
1034 	if ( result ) {
1035 		ldap_msgfree( result );
1036 	}
1037 
1038 	if ( filter ) {
1039 		op->o_tmpfree( filter, op->o_tmpmemctx );
1040 	}
1041 
1042 	if ( lc != NULL ) {
1043 		ldap_back_release_conn( li, lc );
1044 	}
1045 
1046 	return rc;
1047 }
1048