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