Home | History | Annotate | Line # | Download | only in back-ldap
search.c revision 1.1.1.7
      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