Home | History | Annotate | Line # | Download | only in back-ldap
search.c revision 1.1
      1 /* search.c - ldap backend search function */
      2 /* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/search.c,v 1.201.2.9 2008/02/11 23:26:46 kurt 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 			do_retry = 0;
    367 			rc = ldap_parse_reference( lc->lc_ld, res,
    368 					&references, &rs->sr_ctrls, 1 );
    369 
    370 			if ( rc != LDAP_SUCCESS ) {
    371 				continue;
    372 			}
    373 
    374 			/* FIXME: there MUST be at least one */
    375 			if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) {
    376 				int		cnt;
    377 
    378 				for ( cnt = 0; references[ cnt ]; cnt++ )
    379 					/* NO OP */ ;
    380 
    381 				/* FIXME: there MUST be at least one */
    382 				rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
    383 					op->o_tmpmemctx );
    384 
    385 				for ( cnt = 0; references[ cnt ]; cnt++ ) {
    386 					ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
    387 				}
    388 				BER_BVZERO( &rs->sr_ref[ cnt ] );
    389 
    390 				/* ignore return value by now */
    391 				rs->sr_entry = NULL;
    392 				( void )send_search_reference( op, rs );
    393 
    394 			} else {
    395 				Debug( LDAP_DEBUG_ANY,
    396 					"%s ldap_back_search: "
    397 					"got SEARCH_REFERENCE "
    398 					"with no referrals\n",
    399 					op->o_log_prefix, 0, 0 );
    400 			}
    401 
    402 			/* cleanup */
    403 			if ( references ) {
    404 				ber_memvfree( (void **)references );
    405 				op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
    406 				rs->sr_ref = NULL;
    407 				references = NULL;
    408 			}
    409 
    410 			if ( rs->sr_ctrls ) {
    411 				ldap_controls_free( rs->sr_ctrls );
    412 				rs->sr_ctrls = NULL;
    413 			}
    414 
    415 		} else {
    416 			char		*err = NULL;
    417 
    418 			rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
    419 					&match.bv_val, &err,
    420 					&references, &rs->sr_ctrls, 1 );
    421 			if ( rc != LDAP_SUCCESS ) {
    422 				rs->sr_err = rc;
    423 			}
    424 			rs->sr_err = slap_map_api2result( rs );
    425 			if ( err ) {
    426 				rs->sr_text = err;
    427 				freetext = 1;
    428 			}
    429 
    430 			/* RFC 4511: referrals can only appear
    431 			 * if result code is LDAP_REFERRAL */
    432 			if ( references
    433 				&& references[ 0 ]
    434 				&& references[ 0 ][ 0 ] )
    435 			{
    436 				if ( rs->sr_err != LDAP_REFERRAL ) {
    437 					Debug( LDAP_DEBUG_ANY,
    438 						"%s ldap_back_search: "
    439 						"got referrals with err=%d\n",
    440 						op->o_log_prefix,
    441 						rs->sr_err, 0 );
    442 
    443 				} else {
    444 					int	cnt;
    445 
    446 					for ( cnt = 0; references[ cnt ]; cnt++ )
    447 						/* NO OP */ ;
    448 
    449 					rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
    450 						op->o_tmpmemctx );
    451 
    452 					for ( cnt = 0; references[ cnt ]; cnt++ ) {
    453 						/* duplicating ...*/
    454 						ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
    455 					}
    456 					BER_BVZERO( &rs->sr_ref[ cnt ] );
    457 				}
    458 
    459 			} else if ( rs->sr_err == LDAP_REFERRAL ) {
    460 				Debug( LDAP_DEBUG_ANY,
    461 					"%s ldap_back_search: "
    462 					"got err=%d with null "
    463 					"or empty referrals\n",
    464 					op->o_log_prefix,
    465 					rs->sr_err, 0 );
    466 
    467 				rs->sr_err = LDAP_NO_SUCH_OBJECT;
    468 			}
    469 
    470 			if ( match.bv_val != NULL ) {
    471 				match.bv_len = strlen( match.bv_val );
    472 			}
    473 
    474 			rc = 0;
    475 			break;
    476 		}
    477 
    478 		/* if needed, restore timeout */
    479 		if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
    480 			if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) {
    481 				tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ];
    482 				tv.tv_usec = 0;
    483 			}
    484 		}
    485 	}
    486 
    487  	if ( rc == -1 && dont_retry == 0 ) {
    488 		if ( do_retry ) {
    489 			do_retry = 0;
    490 			if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
    491 				goto retry;
    492 			}
    493 		}
    494 		rs->sr_err = LDAP_SERVER_DOWN;
    495 		rs->sr_err = slap_map_api2result( rs );
    496 		goto finish;
    497 	}
    498 
    499 	/*
    500 	 * Rewrite the matched portion of the search base, if required
    501 	 */
    502 	if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) {
    503 		struct berval	pmatch;
    504 
    505 		if ( dnPretty( NULL, &match, &pmatch, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
    506 			rs->sr_matched = pmatch.bv_val;
    507 			LDAP_FREE( match.bv_val );
    508 
    509 		} else {
    510 			rs->sr_matched = match.bv_val;
    511 		}
    512 	}
    513 
    514 	if ( rs->sr_v2ref ) {
    515 		rs->sr_err = LDAP_REFERRAL;
    516 	}
    517 
    518 finish:;
    519 	if ( LDAP_BACK_QUARANTINE( li ) ) {
    520 		ldap_back_quarantine( op, rs );
    521 	}
    522 
    523 #if 0
    524 	/* let send_ldap_result play cleanup handlers (ITS#4645) */
    525 	if ( rc != SLAPD_ABANDON )
    526 #endif
    527 	{
    528 		send_ldap_result( op, rs );
    529 	}
    530 
    531 	(void)ldap_back_controls_free( op, rs, &ctrls );
    532 
    533 	if ( rs->sr_ctrls ) {
    534 		ldap_controls_free( rs->sr_ctrls );
    535 		rs->sr_ctrls = NULL;
    536 	}
    537 
    538 	if ( rs->sr_matched != NULL && rs->sr_matched != save_matched ) {
    539 		if ( rs->sr_matched != match.bv_val ) {
    540 			ber_memfree_x( (char *)rs->sr_matched, op->o_tmpmemctx );
    541 
    542 		} else {
    543 			LDAP_FREE( match.bv_val );
    544 		}
    545 		rs->sr_matched = save_matched;
    546 	}
    547 
    548 	if ( free_filter ) {
    549 		op->o_tmpfree( filter.bv_val, op->o_tmpmemctx );
    550 	}
    551 
    552 	if ( rs->sr_text ) {
    553 		if ( freetext ) {
    554 			LDAP_FREE( (char *)rs->sr_text );
    555 		}
    556 		rs->sr_text = NULL;
    557 	}
    558 
    559 	if ( rs->sr_ref ) {
    560 		op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
    561 		rs->sr_ref = NULL;
    562 	}
    563 
    564 	if ( references ) {
    565 		ber_memvfree( (void **)references );
    566 	}
    567 
    568 	if ( attrs ) {
    569 		ch_free( attrs );
    570 	}
    571 
    572 	if ( lc != NULL ) {
    573 		ldap_back_release_conn( li, lc );
    574 	}
    575 
    576 	return rs->sr_err;
    577 }
    578 
    579 static int
    580 ldap_build_entry(
    581 		Operation	*op,
    582 		LDAPMessage	*e,
    583 		Entry		*ent,
    584 		struct berval	*bdn )
    585 {
    586 	struct berval	a;
    587 	BerElement	ber = *e->lm_ber;
    588 	Attribute	*attr, **attrp;
    589 	const char	*text;
    590 	int		last;
    591 	char *lastb;
    592 	ber_len_t len;
    593 
    594 	/* safe assumptions ... */
    595 	assert( ent != NULL );
    596 	BER_BVZERO( &ent->e_bv );
    597 
    598 	if ( ber_scanf( &ber, "{m", bdn ) == LBER_ERROR ) {
    599 		return LDAP_DECODING_ERROR;
    600 	}
    601 
    602 	/*
    603 	 * Note: this may fail if the target host(s) schema differs
    604 	 * from the one known to the meta, and a DN with unknown
    605 	 * attributes is returned.
    606 	 *
    607 	 * FIXME: should we log anything, or delegate to dnNormalize?
    608 	 */
    609 	/* Note: if the distinguished values or the naming attributes
    610 	 * change, should we massage them as well?
    611 	 */
    612 	if ( dnPrettyNormal( NULL, bdn, &ent->e_name, &ent->e_nname,
    613 		op->o_tmpmemctx ) != LDAP_SUCCESS )
    614 	{
    615 		return LDAP_INVALID_DN_SYNTAX;
    616 	}
    617 
    618 	ent->e_attrs = NULL;
    619 	if ( ber_first_element( &ber, &len, &lastb ) != LBER_SEQUENCE ) {
    620 		return LDAP_SUCCESS;
    621 	}
    622 
    623 	attrp = &ent->e_attrs;
    624 	while ( ber_next_element( &ber, &len, lastb ) == LBER_SEQUENCE &&
    625 		ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
    626 		int				i;
    627 		slap_syntax_validate_func	*validate;
    628 		slap_syntax_transform_func	*pretty;
    629 
    630 		attr = attr_alloc( NULL );
    631 		if ( attr == NULL ) {
    632 			continue;
    633 		}
    634 		if ( slap_bv2ad( &a, &attr->a_desc, &text )
    635 				!= LDAP_SUCCESS )
    636 		{
    637 			if ( slap_bv2undef_ad( &a, &attr->a_desc, &text,
    638 				SLAP_AD_PROXIED ) != LDAP_SUCCESS )
    639 			{
    640 				Debug( LDAP_DEBUG_ANY,
    641 					"%s ldap_build_entry: "
    642 					"slap_bv2undef_ad(%s): %s\n",
    643 					op->o_log_prefix, a.bv_val, text );
    644 				attr_free( attr );
    645 				continue;
    646 			}
    647 		}
    648 
    649 		/* no subschemaSubentry */
    650 		if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
    651 			|| attr->a_desc == slap_schema.si_ad_entryDN )
    652 		{
    653 
    654 			/*
    655 			 * We eat target's subschemaSubentry because
    656 			 * a search for this value is likely not
    657 			 * to resolve to the appropriate backend;
    658 			 * later, the local subschemaSubentry is
    659 			 * added.
    660 			 *
    661 			 * We also eat entryDN because the frontend
    662 			 * will reattach it without checking if already
    663 			 * present...
    664 			 */
    665 			( void )ber_scanf( &ber, "x" /* [W] */ );
    666 
    667 			attr_free( attr );
    668 			continue;
    669 		}
    670 
    671 		if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
    672 				|| attr->a_vals == NULL )
    673 		{
    674 			/*
    675 			 * Note: attr->a_vals can be null when using
    676 			 * values result filter
    677 			 */
    678 			attr->a_vals = (struct berval *)&slap_dummy_bv;
    679 		}
    680 
    681 		validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
    682 		pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
    683 
    684 		if ( !validate && !pretty ) {
    685 			attr->a_nvals = NULL;
    686 			attr_free( attr );
    687 			goto next_attr;
    688 		}
    689 
    690 		for ( i = 0; !BER_BVISNULL( &attr->a_vals[i] ); i++ ) {
    691 			struct berval	pval;
    692 			int		rc;
    693 
    694 			if ( pretty ) {
    695 				rc = pretty( attr->a_desc->ad_type->sat_syntax,
    696 					&attr->a_vals[i], &pval, NULL );
    697 
    698 			} else {
    699 				rc = validate( attr->a_desc->ad_type->sat_syntax,
    700 					&attr->a_vals[i] );
    701 			}
    702 
    703 			if ( rc != LDAP_SUCCESS ) {
    704 				/* check if, by chance, it's an undefined objectClass */
    705 				if ( attr->a_desc == slap_schema.si_ad_objectClass &&
    706 						oc_bvfind_undef( &attr->a_vals[i] ) != NULL )
    707 				{
    708 					ber_dupbv( &pval, &attr->a_vals[i] );
    709 
    710 				} else {
    711 					attr->a_nvals = NULL;
    712 					attr_free( attr );
    713 					goto next_attr;
    714 				}
    715 			}
    716 
    717 			if ( pretty ) {
    718 				LBER_FREE( attr->a_vals[i].bv_val );
    719 				attr->a_vals[i] = pval;
    720 			}
    721 		}
    722 		attr->a_numvals = last = i;
    723 
    724 		if ( last && attr->a_desc->ad_type->sat_equality &&
    725 				attr->a_desc->ad_type->sat_equality->smr_normalize )
    726 		{
    727 			attr->a_nvals = ch_malloc( ( last + 1 )*sizeof( struct berval ) );
    728 			for ( i = 0; i < last; i++ ) {
    729 				int		rc;
    730 
    731 				/*
    732 				 * check that each value is valid per syntax
    733 				 * and pretty if appropriate
    734 				 */
    735 				rc = attr->a_desc->ad_type->sat_equality->smr_normalize(
    736 					SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
    737 					attr->a_desc->ad_type->sat_syntax,
    738 					attr->a_desc->ad_type->sat_equality,
    739 					&attr->a_vals[i], &attr->a_nvals[i],
    740 					NULL );
    741 
    742 				if ( rc != LDAP_SUCCESS ) {
    743 					BER_BVZERO( &attr->a_nvals[i] );
    744 					attr_free( attr );
    745 					goto next_attr;
    746 				}
    747 			}
    748 			BER_BVZERO( &attr->a_nvals[i] );
    749 
    750 		} else {
    751 			attr->a_nvals = attr->a_vals;
    752 		}
    753 		*attrp = attr;
    754 		attrp = &attr->a_next;
    755 
    756 next_attr:;
    757 	}
    758 
    759 	return LDAP_SUCCESS;
    760 }
    761 
    762 /* return 0 IFF we can retrieve the entry with ndn
    763  */
    764 int
    765 ldap_back_entry_get(
    766 		Operation		*op,
    767 		struct berval		*ndn,
    768 		ObjectClass		*oc,
    769 		AttributeDescription	*at,
    770 		int			rw,
    771 		Entry			**ent )
    772 {
    773 	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;
    774 
    775 	ldapconn_t	*lc = NULL;
    776 	int		rc = 1,
    777 			do_not_cache;
    778 	struct berval	bdn;
    779 	LDAPMessage	*result = NULL,
    780 			*e = NULL;
    781 	char		*attr[3], **attrp = NULL;
    782 	char		*filter = NULL;
    783 	SlapReply	rs;
    784 	int		do_retry = 1;
    785 	LDAPControl	**ctrls = NULL;
    786 
    787 	*ent = NULL;
    788 
    789 	/* Tell getconn this is a privileged op */
    790 	do_not_cache = op->o_do_not_cache;
    791 	op->o_do_not_cache = 1;
    792 	if ( !ldap_back_dobind( &lc, op, &rs, LDAP_BACK_DONTSEND ) ) {
    793 		op->o_do_not_cache = do_not_cache;
    794 		return rs.sr_err;
    795 	}
    796 	op->o_do_not_cache = do_not_cache;
    797 
    798 	if ( at ) {
    799 		attrp = attr;
    800 		if ( oc && at != slap_schema.si_ad_objectClass ) {
    801 			attr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val;
    802 			attr[1] = at->ad_cname.bv_val;
    803 			attr[2] = NULL;
    804 
    805 		} else {
    806 			attr[0] = at->ad_cname.bv_val;
    807 			attr[1] = NULL;
    808 		}
    809 	}
    810 
    811 	if ( oc ) {
    812 		char	*ptr;
    813 
    814 		filter = op->o_tmpalloc( STRLENOF( "(objectClass=" ")" )
    815 				+ oc->soc_cname.bv_len + 1, op->o_tmpmemctx );
    816 		ptr = lutil_strcopy( filter, "(objectClass=" );
    817 		ptr = lutil_strcopy( ptr, oc->soc_cname.bv_val );
    818 		*ptr++ = ')';
    819 		*ptr++ = '\0';
    820 	}
    821 
    822 retry:
    823 	ctrls = op->o_ctrls;
    824 	rc = ldap_back_controls_add( op, &rs, lc, &ctrls );
    825 	if ( rc != LDAP_SUCCESS ) {
    826 		goto cleanup;
    827 	}
    828 
    829 	/* TODO: timeout? */
    830 	rc = ldap_search_ext_s( lc->lc_ld, ndn->bv_val, LDAP_SCOPE_BASE, filter,
    831 				attrp, 0, ctrls, NULL,
    832 				NULL, LDAP_NO_LIMIT, &result );
    833 	if ( rc != LDAP_SUCCESS ) {
    834 		if ( rc == LDAP_SERVER_DOWN && do_retry ) {
    835 			do_retry = 0;
    836 			if ( ldap_back_retry( &lc, op, &rs, LDAP_BACK_DONTSEND ) ) {
    837 				/* if the identity changed, there might be need to re-authz */
    838 				(void)ldap_back_controls_free( op, &rs, &ctrls );
    839 				goto retry;
    840 			}
    841 		}
    842 		goto cleanup;
    843 	}
    844 
    845 	e = ldap_first_entry( lc->lc_ld, result );
    846 	if ( e == NULL ) {
    847 		/* the entry exists, but it doesn't match the filter? */
    848 		goto cleanup;
    849 	}
    850 
    851 	*ent = entry_alloc();
    852 	if ( *ent == NULL ) {
    853 		rc = LDAP_NO_MEMORY;
    854 		goto cleanup;
    855 	}
    856 
    857 	rc = ldap_build_entry( op, e, *ent, &bdn );
    858 
    859 	if ( rc != LDAP_SUCCESS ) {
    860 		entry_free( *ent );
    861 		*ent = NULL;
    862 	}
    863 
    864 cleanup:
    865 	(void)ldap_back_controls_free( op, &rs, &ctrls );
    866 
    867 	if ( result ) {
    868 		ldap_msgfree( result );
    869 	}
    870 
    871 	if ( filter ) {
    872 		op->o_tmpfree( filter, op->o_tmpmemctx );
    873 	}
    874 
    875 	if ( lc != NULL ) {
    876 		ldap_back_release_conn( li, lc );
    877 	}
    878 
    879 	return rc;
    880 }
    881 
    882