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