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