Home | History | Annotate | Line # | Download | only in slapd
      1 /*	$NetBSD: result.c,v 1.4 2025/09/05 21:16:25 christos Exp $	*/
      2 
      3 /* result.c - routines to send ldap results, errors, and referrals */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1998-2024 The OpenLDAP Foundation.
      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 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
     19  * All rights reserved.
     20  *
     21  * Redistribution and use in source and binary forms are permitted
     22  * provided that this notice is preserved and that due credit is given
     23  * to the University of Michigan at Ann Arbor. The name of the University
     24  * may not be used to endorse or promote products derived from this
     25  * software without specific prior written permission. This software
     26  * is provided ``as is'' without express or implied warranty.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __RCSID("$NetBSD: result.c,v 1.4 2025/09/05 21:16:25 christos Exp $");
     31 
     32 #include "portable.h"
     33 
     34 #include <stdio.h>
     35 
     36 #include <ac/socket.h>
     37 #include <ac/errno.h>
     38 #include <ac/string.h>
     39 #include <ac/ctype.h>
     40 #include <ac/time.h>
     41 #include <ac/unistd.h>
     42 
     43 #include "slap.h"
     44 
     45 #if SLAP_STATS_ETIME
     46 #define ETIME_SETUP \
     47 	struct timeval now; \
     48 	char timestr[64]; \
     49 	(void) gettimeofday( &now, NULL ); \
     50 	now.tv_sec -= op->o_time; \
     51 	now.tv_usec -= op->o_tusec; \
     52 	if ( now.tv_usec < 0 ) { \
     53 		--now.tv_sec; now.tv_usec += 1000000; \
     54 	} \
     55 	sprintf(timestr, "qtime=%d.%06d etime=%d.%06d", \
     56 		(int)op->o_qtime.tv_sec, (int)op->o_qtime.tv_usec, \
     57 		(int)now.tv_sec, (int)now.tv_usec);
     58 #define ETIME_LOGFMT	"%s "
     59 #define StatslogEtime(lvl,fmt,pfx,tag,err,...) \
     60 	Debug(lvl,fmt,pfx,tag,err,timestr,__VA_ARGS__)
     61 #else
     62 #define ETIME_SETUP
     63 #define ETIME_LOGFMT	""
     64 #define StatslogEtime	Debug
     65 #endif	/* SLAP_STATS_ETIME */
     66 
     67 const struct berval slap_dummy_bv = BER_BVNULL;
     68 
     69 int slap_null_cb( Operation *op, SlapReply *rs )
     70 {
     71 	return 0;
     72 }
     73 
     74 int slap_freeself_cb( Operation *op, SlapReply *rs )
     75 {
     76 	assert( op->o_callback != NULL );
     77 
     78 	op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
     79 	op->o_callback = NULL;
     80 
     81 	return SLAP_CB_CONTINUE;
     82 }
     83 
     84 static char *v2ref( BerVarray ref, const char *text )
     85 {
     86 	size_t len = 0, i = 0;
     87 	char *v2;
     88 
     89 	if(ref == NULL) {
     90 		if (text) {
     91 			return ch_strdup(text);
     92 		} else {
     93 			return NULL;
     94 		}
     95 	}
     96 
     97 	if ( text != NULL ) {
     98 		len = strlen( text );
     99 		if (text[len-1] != '\n') {
    100 		    i = 1;
    101 		}
    102 	}
    103 
    104 	v2 = ch_malloc( len+i+sizeof("Referral:") );
    105 
    106 	if( text != NULL ) {
    107 		strcpy(v2, text);
    108 		if( i ) {
    109 			v2[len++] = '\n';
    110 		}
    111 	}
    112 	strcpy( v2+len, "Referral:" );
    113 	len += sizeof("Referral:");
    114 
    115 	for( i=0; ref[i].bv_val != NULL; i++ ) {
    116 		v2 = ch_realloc( v2, len + ref[i].bv_len + 1 );
    117 		v2[len-1] = '\n';
    118 		AC_MEMCPY(&v2[len], ref[i].bv_val, ref[i].bv_len );
    119 		len += ref[i].bv_len;
    120 		if (ref[i].bv_val[ref[i].bv_len-1] != '/') {
    121 			++len;
    122 		}
    123 	}
    124 
    125 	v2[len-1] = '\0';
    126 	return v2;
    127 }
    128 
    129 ber_tag_t
    130 slap_req2res( ber_tag_t tag )
    131 {
    132 	switch( tag ) {
    133 	case LDAP_REQ_ADD:
    134 	case LDAP_REQ_BIND:
    135 	case LDAP_REQ_COMPARE:
    136 	case LDAP_REQ_EXTENDED:
    137 	case LDAP_REQ_MODIFY:
    138 	case LDAP_REQ_MODRDN:
    139 		tag++;
    140 		break;
    141 
    142 	case LDAP_REQ_DELETE:
    143 		tag = LDAP_RES_DELETE;
    144 		break;
    145 
    146 	case LDAP_REQ_ABANDON:
    147 	case LDAP_REQ_UNBIND:
    148 		tag = LBER_SEQUENCE;
    149 		break;
    150 
    151 	case LDAP_REQ_SEARCH:
    152 		tag = LDAP_RES_SEARCH_RESULT;
    153 		break;
    154 
    155 	default:
    156 		tag = LBER_SEQUENCE;
    157 	}
    158 
    159 	return tag;
    160 }
    161 
    162 /*
    163  * SlapReply debugging enabled by USE_RS_ASSERT.
    164  *
    165  * Disabled by default, but compiled in (but still unused) when
    166  * LDAP_TEST.  #define USE_RS_ASSERT as nonzero to enable some
    167  * assertions which check the SlapReply.  USE_RS_ASSERT = 2 or higher
    168  * check aggressively, currently some code fail these tests.
    169  *
    170  * Environment variable $NO_RS_ASSERT controls how USE_RS_ASSERT handles
    171  * errors.  > 0: ignore errors, 0: abort (the default), < 0: just warn.
    172  *
    173  * Wrap LDAP operation calls in macros SLAP_OP() & co from proto-slap.h
    174  * to check the SlapReply.  contrib/slapd-tools/wrap_slap_ops converts
    175  * source code to use the macros.
    176  */
    177 #if defined(LDAP_TEST) || (defined(USE_RS_ASSERT) && (USE_RS_ASSERT))
    178 
    179 int rs_suppress_assert = 0;
    180 
    181 /* RS_ASSERT() helper function */
    182 void rs_assert_(const char*file, unsigned line, const char*fn, const char*cond)
    183 {
    184 	int no_assert = rs_suppress_assert, save_errno = errno;
    185 	const char *s;
    186 
    187 	if ( no_assert >= 0 ) {
    188 		if ( no_assert == 0 && (s = getenv( "NO_RS_ASSERT" )) && *s ) {
    189 			no_assert = rs_suppress_assert = atoi( s );
    190 		}
    191 		if ( no_assert > 0 ) {
    192 			errno = save_errno;
    193 			return;
    194 		}
    195 	}
    196 
    197 #ifdef rs_assert_	/* proto-slap.h #defined away the fn parameter */
    198 	fprintf( stderr,"%s:%u: "  "RS_ASSERT(%s) failed.\n", file,line,cond );
    199 #else
    200 	fprintf( stderr,"%s:%u: %s: RS_ASSERT(%s) failed.\n", file,line,fn,cond );
    201 #endif
    202 	fflush( stderr );
    203 
    204 	errno = save_errno;
    205 	/* $NO_RS_ASSERT > 0: ignore rs_asserts, 0: abort, < 0: just warn */
    206 	if ( !no_assert /* from $NO_RS_ASSERT */ ) abort();
    207 }
    208 
    209 /* SlapReply is consistent */
    210 void
    211 (rs_assert_ok)( const SlapReply *rs )
    212 {
    213 	const slap_mask_t flags = rs->sr_flags;
    214 
    215 	if ( flags & REP_ENTRY_MASK ) {
    216 		RS_ASSERT( !(flags & REP_ENTRY_MUSTRELEASE)
    217 			|| !(flags & (REP_ENTRY_MASK ^ REP_ENTRY_MUSTRELEASE)) );
    218 		RS_ASSERT( rs->sr_entry != NULL );
    219 		RS_ASSERT( (1 << rs->sr_type) &
    220 			((1 << REP_SEARCH) | (1 << REP_SEARCHREF) |
    221 			 (1 << REP_RESULT) | (1 << REP_GLUE_RESULT)) );
    222 	}
    223 #if defined(USE_RS_ASSERT) && (USE_RS_ASSERT) > 1 /* TODO: Enable when safe */
    224 	if ( (flags & (REP_MATCHED_MASK | REP_REF_MASK | REP_CTRLS_MASK)) ) {
    225 		RS_ASSERT( !(flags & REP_MATCHED_MASK) || rs->sr_matched );
    226 		RS_ASSERT( !(flags & REP_CTRLS_MASK  ) || rs->sr_ctrls   );
    227 		/* Note: LDAP_REFERRAL + !sr_ref is OK, becomes LDAP_NO_SUCH_OBJECT */
    228 	}
    229 #if (USE_RS_ASSERT) > 2
    230 	if ( rs->sr_err == LDAP_SUCCESS ) {
    231 		RS_ASSERT( rs->sr_text == NULL );
    232 		RS_ASSERT( rs->sr_matched == NULL );
    233 	}
    234 #endif
    235 #endif
    236 }
    237 
    238 /* Ready for calling a new backend operation */
    239 void
    240 (rs_assert_ready)( const SlapReply *rs )
    241 {
    242 	RS_ASSERT( !rs->sr_entry   );
    243 #if defined(USE_RS_ASSERT) && (USE_RS_ASSERT) > 1 /* TODO: Enable when safe */
    244 	RS_ASSERT( !rs->sr_text    );
    245 	RS_ASSERT( !rs->sr_ref     );
    246 	RS_ASSERT( !rs->sr_matched );
    247 	RS_ASSERT( !rs->sr_ctrls   );
    248 	RS_ASSERT( !rs->sr_flags   );
    249 #if (USE_RS_ASSERT) > 2
    250 	RS_ASSERT( rs->sr_err == LDAP_SUCCESS );
    251 #endif
    252 #else
    253 	RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
    254 #endif
    255 }
    256 
    257 /* Backend operation done */
    258 void
    259 (rs_assert_done)( const SlapReply *rs )
    260 {
    261 #if defined(USE_RS_ASSERT) && (USE_RS_ASSERT) > 1 /* TODO: Enable when safe */
    262 	RS_ASSERT( !(rs->sr_flags & ~(REP_ENTRY_MODIFIABLE|REP_NO_OPERATIONALS)) );
    263 	rs_assert_ok( rs );
    264 #else
    265 	RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MUSTFLUSH) );
    266 #endif
    267 }
    268 
    269 #endif /* LDAP_TEST || USE_RS_ASSERT */
    270 
    271 /* Reset a used SlapReply whose contents has been flushed (freed/released) */
    272 void
    273 (rs_reinit)( SlapReply *rs, slap_reply_t type )
    274 {
    275 	rs_reinit( rs, type );		/* proto-slap.h macro */
    276 }
    277 
    278 /* Obey and clear rs->sr_flags & REP_ENTRY_MASK.  Clear sr_entry if freed. */
    279 void
    280 rs_flush_entry( Operation *op, SlapReply *rs, slap_overinst *on )
    281 {
    282 	rs_assert_ok( rs );
    283 
    284 	if ( (rs->sr_flags & REP_ENTRY_MUSTFLUSH) && rs->sr_entry != NULL ) {
    285 		if ( !(rs->sr_flags & REP_ENTRY_MUSTRELEASE) ) {
    286 			entry_free( rs->sr_entry );
    287 		} else if ( on != NULL ) {
    288 			overlay_entry_release_ov( op, rs->sr_entry, 0, on );
    289 		} else {
    290 			be_entry_release_rw( op, rs->sr_entry, 0 );
    291 		}
    292 		rs->sr_entry = NULL;
    293 	}
    294 
    295 	rs->sr_flags &= ~REP_ENTRY_MASK;
    296 }
    297 
    298 /* Set rs->sr_entry after obeying and clearing sr_flags & REP_ENTRY_MASK. */
    299 void
    300 rs_replace_entry( Operation *op, SlapReply *rs, slap_overinst *on, Entry *e )
    301 {
    302 	rs_flush_entry( op, rs, on );
    303 	rs->sr_entry = e;
    304 }
    305 
    306 /*
    307  * Ensure rs->sr_entry is modifiable, by duplicating it if necessary.
    308  * Obey sr_flags.  Set REP_ENTRY_<MODIFIABLE, and MUSTBEFREED if duplicated>.
    309  * Return nonzero if rs->sr_entry was replaced.
    310  */
    311 int
    312 rs_entry2modifiable( Operation *op, SlapReply *rs, slap_overinst *on )
    313 {
    314 	if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) {
    315 		rs_assert_ok( rs );
    316 		return 0;
    317 	}
    318 	rs_replace_entry( op, rs, on, entry_dup( rs->sr_entry ));
    319 	rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
    320 	return 1;
    321 }
    322 
    323 /* Check for any callbacks that want to be informed about being blocked
    324  * on output. These callbacks are expected to leave the callback list
    325  * unmodified. Their result is ignored.
    326  */
    327 static void
    328 slap_writewait_play(
    329 	Operation *op )
    330 {
    331 	slap_callback	*sc = op->o_callback;
    332 
    333 	for ( ; sc; sc = sc->sc_next ) {
    334 		if ( sc->sc_writewait )
    335 			sc->sc_writewait( op, sc );
    336 	}
    337 }
    338 
    339 static long send_ldap_ber(
    340 	Operation *op,
    341 	BerElement *ber )
    342 {
    343 	Connection *conn = op->o_conn;
    344 	ber_len_t bytes;
    345 	long ret = 0;
    346 	char *close_reason;
    347 	int do_resume = 0;
    348 
    349 	ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes );
    350 
    351 	/* write only one pdu at a time - wait til it's our turn */
    352 	ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
    353 	if (( op->o_abandon && !op->o_cancel ) || !connection_valid( conn ) ||
    354 		conn->c_writers < 0 ) {
    355 		ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
    356 		return 0;
    357 	}
    358 
    359 	conn->c_writers++;
    360 
    361 	while ( conn->c_writers > 0 && conn->c_writing ) {
    362 		ldap_pvt_thread_cond_wait( &conn->c_write1_cv, &conn->c_write1_mutex );
    363 	}
    364 
    365 	/* connection was closed under us */
    366 	if ( conn->c_writers < 0 ) {
    367 		/* we're the last waiter, let the closer continue */
    368 		if ( conn->c_writers == -1 )
    369 			ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
    370 		conn->c_writers++;
    371 		ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
    372 		return 0;
    373 	}
    374 
    375 	/* Our turn */
    376 	conn->c_writing = 1;
    377 
    378 	/* write the pdu */
    379 	while( 1 ) {
    380 		int err;
    381 		char ebuf[128];
    382 
    383 		if ( ber_flush2( conn->c_sb, ber, LBER_FLUSH_FREE_NEVER ) == 0 ) {
    384 			ret = bytes;
    385 			break;
    386 		}
    387 
    388 		err = sock_errno();
    389 
    390 		/*
    391 		 * we got an error.  if it's ewouldblock, we need to
    392 		 * wait on the socket being writable.  otherwise, figure
    393 		 * it's a hard error and return.
    394 		 */
    395 
    396 		Debug( LDAP_DEBUG_CONNS, "ber_flush2 failed errno=%d reason=\"%s\"\n",
    397 		    err, sock_errstr(err, ebuf, sizeof(ebuf)) );
    398 
    399 		if ( err != EWOULDBLOCK && err != EAGAIN ) {
    400 			close_reason = "connection lost on write";
    401 fail:
    402 			conn->c_writers--;
    403 			conn->c_writing = 0;
    404 			ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
    405 			ldap_pvt_thread_mutex_lock( &conn->c_mutex );
    406 			/* conn may have been reused by the time we get the mutex */
    407 			if ( op->o_connid == conn->c_connid )
    408 				connection_closing( conn, close_reason );
    409 			ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
    410 			return -1;
    411 		}
    412 
    413 		/* if writer is blocked and we're waiting for a pool pause,
    414 		 * just drop this connection.
    415 		 */
    416 		if ( ldap_pvt_thread_pool_pausing( &connection_pool ) > 0 ) {
    417 			close_reason = "writer blocked and pool pause pending";
    418 			goto fail;
    419 		}
    420 
    421 		/* wait for socket to be write-ready */
    422 		do_resume = 1;
    423 		conn->c_writewaiter = 1;
    424 		ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
    425 		slap_writewait_play( op );
    426 		err = slapd_wait_writer( conn->c_sd );
    427 		conn->c_writewaiter = 0;
    428 		ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
    429 		/* 0 is timeout, so we close it.
    430 		 * -1 is an error, close it.
    431 		 */
    432 		if ( err <= 0 ) {
    433 			if ( err == 0 )
    434 				close_reason = "writetimeout";
    435 			else
    436 				close_reason = "connection lost on writewait";
    437 			goto fail;
    438 		}
    439 
    440 		if ( conn->c_writers < 0 ) {
    441 			ret = 0;
    442 			break;
    443 		}
    444 	}
    445 
    446 	conn->c_writing = 0;
    447 	if ( conn->c_writers < 0 ) {
    448 		/* shutting down, don't resume any ops */
    449 		do_resume = 0;
    450 		conn->c_writers++;
    451 		if ( !conn->c_writers )
    452 			ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
    453 	} else {
    454 		conn->c_writers--;
    455 		/* other writers are waiting, don't resume any ops */
    456 		if ( conn->c_writers )
    457 			do_resume = 0;
    458 		ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
    459 	}
    460 	ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
    461 
    462 	/* If there are no more writers, release a pending op */
    463 	if ( do_resume )
    464 		connection_write_resume( conn );
    465 
    466 	return ret;
    467 }
    468 
    469 static int
    470 send_ldap_control( BerElement *ber, LDAPControl *c )
    471 {
    472 	int rc;
    473 
    474 	assert( c != NULL );
    475 
    476 	rc = ber_printf( ber, "{s" /*}*/, c->ldctl_oid );
    477 
    478 	if( c->ldctl_iscritical ) {
    479 		rc = ber_printf( ber, "b",
    480 			(ber_int_t) c->ldctl_iscritical ) ;
    481 		if( rc == -1 ) return rc;
    482 	}
    483 
    484 	if( c->ldctl_value.bv_val != NULL ) {
    485 		rc = ber_printf( ber, "O", &c->ldctl_value );
    486 		if( rc == -1 ) return rc;
    487 	}
    488 
    489 	rc = ber_printf( ber, /*{*/"N}" );
    490 	if( rc == -1 ) return rc;
    491 
    492 	return 0;
    493 }
    494 
    495 static int
    496 send_ldap_controls( Operation *o, BerElement *ber, LDAPControl **c )
    497 {
    498 	int rc;
    499 
    500 	if( c == NULL )
    501 		return 0;
    502 
    503 	rc = ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS );
    504 	if( rc == -1 ) return rc;
    505 
    506 	for( ; *c != NULL; c++) {
    507 		rc = send_ldap_control( ber, *c );
    508 		if( rc == -1 ) return rc;
    509 	}
    510 
    511 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
    512 	/* this is a hack to avoid having to modify op->s_ctrls */
    513 	if( o->o_sortedresults ) {
    514 		BerElementBuffer berbuf;
    515 		BerElement *sber = (BerElement *) &berbuf;
    516 		LDAPControl sorted;
    517 		BER_BVZERO( &sorted.ldctl_value );
    518 		sorted.ldctl_oid = LDAP_CONTROL_SORTRESPONSE;
    519 		sorted.ldctl_iscritical = 0;
    520 
    521 		ber_init2( sber, NULL, LBER_USE_DER );
    522 
    523 		ber_printf( sber, "{e}", LDAP_UNWILLING_TO_PERFORM );
    524 
    525 		if( ber_flatten2( sber, &sorted.ldctl_value, 0 ) == -1 ) {
    526 			return -1;
    527 		}
    528 
    529 		(void) ber_free_buf( sber );
    530 
    531 		rc = send_ldap_control( ber, &sorted );
    532 		if( rc == -1 ) return rc;
    533 	}
    534 #endif
    535 
    536 	rc = ber_printf( ber, /*{*/"N}" );
    537 
    538 	return rc;
    539 }
    540 
    541 /*
    542  * slap_response_play()
    543  *
    544  * plays the callback list; rationale: a callback can
    545  *   - remove itself from the list, by setting op->o_callback = NULL;
    546  *     malloc()'ed callbacks should free themselves from inside the
    547  *     sc_response() function.
    548  *   - replace itself with another (list of) callback(s), by setting
    549  *     op->o_callback = a new (list of) callback(s); in this case, it
    550  *     is the callback's responsibility to to append existing subsequent
    551  *     callbacks to the end of the list that is passed to the sc_response()
    552  *     function.
    553  *   - modify the list of subsequent callbacks by modifying the value
    554  *     of the sc_next field from inside the sc_response() function; this
    555  *     case does not require any handling from inside slap_response_play()
    556  *
    557  * To stop execution of the playlist, the sc_response() function must return
    558  * a value different from SLAP_SC_CONTINUE.
    559  *
    560  * The same applies to slap_cleanup_play(); only, there is no means to stop
    561  * execution of the playlist, since all cleanup functions must be called.
    562  */
    563 static int
    564 slap_response_play(
    565 	Operation *op,
    566 	SlapReply *rs )
    567 {
    568 	int rc;
    569 
    570 	slap_callback	*sc = op->o_callback, **scp;
    571 
    572 	rc = SLAP_CB_CONTINUE;
    573 	for ( scp = &sc; *scp; ) {
    574 		slap_callback *sc_next = (*scp)->sc_next, **sc_nextp = &(*scp)->sc_next;
    575 
    576 		op->o_callback = *scp;
    577 		if ( op->o_callback->sc_response ) {
    578 			rc = op->o_callback->sc_response( op, rs );
    579 			if ( op->o_callback == NULL ) {
    580 				/* the callback has been removed;
    581 				 * repair the list */
    582 				*scp = sc_next;
    583 				sc_nextp = scp;
    584 
    585 			} else if ( op->o_callback != *scp ) {
    586 				/* a new callback has been inserted
    587 				 * in place of the existing one; repair the list */
    588 				*scp = op->o_callback;
    589 				sc_nextp = scp;
    590 			}
    591 			if ( rc != SLAP_CB_CONTINUE ) break;
    592 		}
    593 		scp = sc_nextp;
    594 	}
    595 
    596 	op->o_callback = sc;
    597 	return rc;
    598 }
    599 
    600 static int
    601 slap_cleanup_play(
    602 	Operation *op,
    603 	SlapReply *rs )
    604 {
    605 	slap_callback	*sc = op->o_callback, **scp;
    606 
    607 	for ( scp = &sc; *scp; ) {
    608 		slap_callback *sc_next = (*scp)->sc_next, **sc_nextp = &(*scp)->sc_next;
    609 
    610 		op->o_callback = *scp;
    611 		if ( op->o_callback->sc_cleanup ) {
    612 			(void)op->o_callback->sc_cleanup( op, rs );
    613 			if ( op->o_callback == NULL ) {
    614 				/* the callback has been removed;
    615 				 * repair the list */
    616 				*scp = sc_next;
    617 				sc_nextp = scp;
    618 
    619 			} else if ( op->o_callback != *scp ) {
    620 				/* a new callback has been inserted
    621 				 * after the existing one; repair the list */
    622 				/* a new callback has been inserted
    623 				 * in place of the existing one; repair the list */
    624 				*scp = op->o_callback;
    625 				sc_nextp = scp;
    626 			}
    627 			/* don't care about the result; do all cleanup */
    628 		}
    629 		scp = sc_nextp;
    630 	}
    631 
    632 	op->o_callback = sc;
    633 	return LDAP_SUCCESS;
    634 }
    635 
    636 static int
    637 send_ldap_response(
    638 	Operation *op,
    639 	SlapReply *rs )
    640 {
    641 	BerElementBuffer berbuf;
    642 	BerElement	*ber = (BerElement *) &berbuf;
    643 	int		rc = LDAP_SUCCESS;
    644 	long	bytes;
    645 
    646 	/* op was actually aborted, bypass everything if client didn't Cancel */
    647 	if (( rs->sr_err == SLAPD_ABANDON ) && !op->o_cancel ) {
    648 		rc = SLAPD_ABANDON;
    649 		goto clean2;
    650 	}
    651 
    652 	if ( op->o_callback ) {
    653 		rc = slap_response_play( op, rs );
    654 		if ( rc != SLAP_CB_CONTINUE ) {
    655 			goto clean2;
    656 		}
    657 	}
    658 
    659 	/* op completed, connection aborted, bypass sending response */
    660 	if ( op->o_abandon && !op->o_cancel ) {
    661 		rc = SLAPD_ABANDON;
    662 		goto clean2;
    663 	}
    664 
    665 #ifdef LDAP_CONNECTIONLESS
    666 	if (op->o_conn && op->o_conn->c_is_udp)
    667 		ber = op->o_res_ber;
    668 	else
    669 #endif
    670 	{
    671 		ber_init_w_nullc( ber, LBER_USE_DER );
    672 		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
    673 	}
    674 
    675 	rc = rs->sr_err;
    676 	if ( rc == SLAPD_ABANDON && op->o_cancel )
    677 		rc = LDAP_CANCELLED;
    678 
    679 	Debug( LDAP_DEBUG_TRACE,
    680 		"send_ldap_response: msgid=%d tag=%lu err=%d\n",
    681 		rs->sr_msgid, rs->sr_tag, rc );
    682 
    683 	if( rs->sr_ref ) {
    684 		Debug( LDAP_DEBUG_ARGS, "send_ldap_response: ref=\"%s\"\n",
    685 			rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL" );
    686 	}
    687 
    688 #ifdef LDAP_CONNECTIONLESS
    689 	if (op->o_conn && op->o_conn->c_is_udp &&
    690 		op->o_protocol == LDAP_VERSION2 )
    691 	{
    692 		rc = ber_printf( ber, "t{ess" /*"}"*/,
    693 			rs->sr_tag, rc,
    694 		rs->sr_matched == NULL ? "" : rs->sr_matched,
    695 		rs->sr_text == NULL ? "" : rs->sr_text );
    696 	} else
    697 #endif
    698 	if ( rs->sr_type == REP_INTERMEDIATE ) {
    699 	    rc = ber_printf( ber, "{it{" /*"}}"*/,
    700 			rs->sr_msgid, rs->sr_tag );
    701 
    702 	} else {
    703 	    rc = ber_printf( ber, "{it{ess" /*"}}"*/,
    704 		rs->sr_msgid, rs->sr_tag, rc,
    705 		rs->sr_matched == NULL ? "" : rs->sr_matched,
    706 		rs->sr_text == NULL ? "" : rs->sr_text );
    707 	}
    708 
    709 	if( rc != -1 ) {
    710 		if ( rs->sr_ref != NULL ) {
    711 			assert( rs->sr_err == LDAP_REFERRAL );
    712 			rc = ber_printf( ber, "t{W}",
    713 				LDAP_TAG_REFERRAL, rs->sr_ref );
    714 		} else {
    715 			assert( rs->sr_err != LDAP_REFERRAL );
    716 		}
    717 	}
    718 
    719 	if( rc != -1 && rs->sr_type == REP_SASL && rs->sr_sasldata != NULL ) {
    720 		rc = ber_printf( ber, "tO",
    721 			LDAP_TAG_SASL_RES_CREDS, rs->sr_sasldata );
    722 	}
    723 
    724 	if( rc != -1 &&
    725 		( rs->sr_type == REP_EXTENDED || rs->sr_type == REP_INTERMEDIATE ))
    726 	{
    727 		if ( rs->sr_rspoid != NULL ) {
    728 			rc = ber_printf( ber, "ts",
    729 				rs->sr_type == REP_EXTENDED
    730 					? LDAP_TAG_EXOP_RES_OID : LDAP_TAG_IM_RES_OID,
    731 				rs->sr_rspoid );
    732 		}
    733 		if( rc != -1 && rs->sr_rspdata != NULL ) {
    734 			rc = ber_printf( ber, "tO",
    735 				rs->sr_type == REP_EXTENDED
    736 					? LDAP_TAG_EXOP_RES_VALUE : LDAP_TAG_IM_RES_VALUE,
    737 				rs->sr_rspdata );
    738 		}
    739 	}
    740 
    741 	if( rc != -1 ) {
    742 		rc = ber_printf( ber, /*"{"*/ "N}" );
    743 	}
    744 
    745 	if( rc != -1 ) {
    746 		rc = send_ldap_controls( op, ber, rs->sr_ctrls );
    747 	}
    748 
    749 	if( rc != -1 ) {
    750 		rc = ber_printf( ber, /*"{"*/ "N}" );
    751 	}
    752 
    753 #ifdef LDAP_CONNECTIONLESS
    754 	if( op->o_conn && op->o_conn->c_is_udp && op->o_protocol == LDAP_VERSION2
    755 		&& rc != -1 )
    756 	{
    757 		rc = ber_printf( ber, /*"{"*/ "N}" );
    758 	}
    759 #endif
    760 
    761 	if ( rc == -1 ) {
    762 		Debug( LDAP_DEBUG_ANY, "ber_printf failed\n" );
    763 
    764 #ifdef LDAP_CONNECTIONLESS
    765 		if (!op->o_conn || op->o_conn->c_is_udp == 0)
    766 #endif
    767 		{
    768 			ber_free_buf( ber );
    769 		}
    770 		goto cleanup;
    771 	}
    772 
    773 	/* send BER */
    774 	bytes = send_ldap_ber( op, ber );
    775 #ifdef LDAP_CONNECTIONLESS
    776 	if (!op->o_conn || op->o_conn->c_is_udp == 0)
    777 #endif
    778 	{
    779 		ber_free_buf( ber );
    780 	}
    781 
    782 	if ( bytes < 0 ) {
    783 		Debug( LDAP_DEBUG_ANY,
    784 			"send_ldap_response: ber write failed\n" );
    785 
    786 		goto cleanup;
    787 	}
    788 
    789 	ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
    790 	ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
    791 	ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
    792 	ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
    793 
    794 cleanup:;
    795 	/* Tell caller that we did this for real, as opposed to being
    796 	 * overridden by a callback
    797 	 */
    798 	rc = SLAP_CB_CONTINUE;
    799 
    800 clean2:;
    801 	if ( op->o_callback ) {
    802 		(void)slap_cleanup_play( op, rs );
    803 	}
    804 
    805 	if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
    806 		rs->sr_flags ^= REP_MATCHED_MUSTBEFREED; /* paranoia */
    807 		if ( rs->sr_matched ) {
    808 			free( (char *)rs->sr_matched );
    809 			rs->sr_matched = NULL;
    810 		}
    811 	}
    812 
    813 	if ( rs->sr_flags & REP_REF_MUSTBEFREED ) {
    814 		rs->sr_flags ^= REP_REF_MUSTBEFREED; /* paranoia */
    815 		if ( rs->sr_ref ) {
    816 			ber_bvarray_free( rs->sr_ref );
    817 			rs->sr_ref = NULL;
    818 		}
    819 	}
    820 
    821 	if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
    822 		rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
    823 		if ( rs->sr_ctrls ) {
    824 			slap_free_ctrls( op, rs->sr_ctrls );
    825 			rs->sr_ctrls = NULL;
    826 		}
    827 	}
    828 
    829 	return rc;
    830 }
    831 
    832 
    833 void
    834 send_ldap_disconnect( Operation	*op, SlapReply *rs )
    835 {
    836 #define LDAP_UNSOLICITED_ERROR(e) \
    837 	(  (e) == LDAP_PROTOCOL_ERROR \
    838 	|| (e) == LDAP_STRONG_AUTH_REQUIRED \
    839 	|| (e) == LDAP_UNAVAILABLE )
    840 
    841 	Debug( LDAP_DEBUG_TRACE,
    842 		"send_ldap_disconnect %d:%s\n",
    843 		rs->sr_err, rs->sr_text ? rs->sr_text : "" );
    844 	assert( LDAP_UNSOLICITED_ERROR( rs->sr_err ) );
    845 
    846 	/* TODO: Flush the entry if sr_type == REP_SEARCH/REP_SEARCHREF? */
    847 	RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
    848 	rs->sr_flags &= ~REP_ENTRY_MASK;	/* paranoia */
    849 
    850 	rs->sr_type = REP_EXTENDED;
    851 	rs->sr_rspdata = NULL;
    852 
    853 	if ( op->o_protocol < LDAP_VERSION3 ) {
    854 		rs->sr_rspoid = NULL;
    855 		rs->sr_tag = slap_req2res( op->o_tag );
    856 		rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
    857 
    858 	} else {
    859 		rs->sr_rspoid = LDAP_NOTICE_DISCONNECT;
    860 		rs->sr_tag = LDAP_RES_EXTENDED;
    861 		rs->sr_msgid = LDAP_RES_UNSOLICITED;
    862 	}
    863 
    864 	if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
    865 		ETIME_SETUP;
    866 		StatslogEtime( LDAP_DEBUG_STATS,
    867 			"%s DISCONNECT tag=%lu err=%d "ETIME_LOGFMT"text=%s\n",
    868 			op->o_log_prefix, rs->sr_tag, rs->sr_err,
    869 			rs->sr_text ? rs->sr_text : "" );
    870 	}
    871 }
    872 
    873 void
    874 slap_send_ldap_result( Operation *op, SlapReply *rs )
    875 {
    876 	char *tmp = NULL;
    877 	const char *otext = rs->sr_text;
    878 	BerVarray oref = rs->sr_ref;
    879 
    880 	rs->sr_type = REP_RESULT;
    881 
    882 	/* Propagate Abandons so that cleanup callbacks can be processed */
    883 	if ( rs->sr_err == SLAPD_ABANDON || op->o_abandon )
    884 		goto abandon;
    885 
    886 	Debug( LDAP_DEBUG_TRACE,
    887 		"send_ldap_result: %s p=%d\n",
    888 		op->o_log_prefix, op->o_protocol );
    889 	Debug( LDAP_DEBUG_ARGS,
    890 		"send_ldap_result: err=%d matched=\"%s\" text=\"%s\"\n",
    891 		rs->sr_err, rs->sr_matched ? rs->sr_matched : "",
    892 		rs->sr_text ? rs->sr_text : "" );
    893 	if( rs->sr_ref ) {
    894 		Debug( LDAP_DEBUG_ARGS,
    895 			"send_ldap_result: referral=\"%s\"\n",
    896 			rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL" );
    897 	}
    898 	assert( !LDAP_API_ERROR( rs->sr_err ) );
    899 	assert( rs->sr_err != LDAP_PARTIAL_RESULTS );
    900 
    901 	if ( rs->sr_err == LDAP_REFERRAL ) {
    902 		if( op->o_domain_scope ) rs->sr_ref = NULL;
    903 
    904 		if( rs->sr_ref == NULL ) {
    905 			rs->sr_err = LDAP_NO_SUCH_OBJECT;
    906 		} else if ( op->o_protocol < LDAP_VERSION3 ) {
    907 			rs->sr_err = LDAP_PARTIAL_RESULTS;
    908 		}
    909 	}
    910 
    911 	if ( op->o_protocol < LDAP_VERSION3 ) {
    912 		tmp = v2ref( rs->sr_ref, rs->sr_text );
    913 		rs->sr_text = tmp;
    914 		rs->sr_ref = NULL;
    915 	}
    916 
    917 abandon:
    918 	rs->sr_tag = slap_req2res( op->o_tag );
    919 	rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
    920 
    921 	if ( rs->sr_flags & REP_REF_MUSTBEFREED ) {
    922 		if ( rs->sr_ref == NULL ) {
    923 			rs->sr_flags ^= REP_REF_MUSTBEFREED;
    924 			ber_bvarray_free( oref );
    925 		}
    926 		oref = NULL; /* send_ldap_response() will free rs->sr_ref if != NULL */
    927 	}
    928 
    929 	if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
    930 		ETIME_SETUP;
    931 		if ( op->o_tag == LDAP_REQ_SEARCH ) {
    932 			StatslogEtime( LDAP_DEBUG_STATS,
    933 				"%s SEARCH RESULT tag=%lu err=%d "ETIME_LOGFMT"nentries=%d text=%s\n",
    934 				op->o_log_prefix, rs->sr_tag, rs->sr_err,
    935 				rs->sr_nentries, rs->sr_text ? rs->sr_text : "" );
    936 		} else {
    937 			StatslogEtime( LDAP_DEBUG_STATS,
    938 				"%s RESULT tag=%lu err=%d "ETIME_LOGFMT"text=%s\n",
    939 				op->o_log_prefix, rs->sr_tag, rs->sr_err,
    940 				rs->sr_text ? rs->sr_text : "" );
    941 		}
    942 	}
    943 
    944 	if( tmp != NULL ) ch_free(tmp);
    945 	rs->sr_text = otext;
    946 	rs->sr_ref = oref;
    947 }
    948 
    949 void
    950 send_ldap_sasl( Operation *op, SlapReply *rs )
    951 {
    952 	Debug( LDAP_DEBUG_TRACE, "send_ldap_sasl: err=%d len=%ld\n",
    953 		rs->sr_err,
    954 		rs->sr_sasldata ? (long) rs->sr_sasldata->bv_len : -1 );
    955 
    956 	RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
    957 	rs->sr_flags &= ~REP_ENTRY_MASK;	/* paranoia */
    958 
    959 	rs->sr_type = REP_SASL;
    960 	rs->sr_tag = slap_req2res( op->o_tag );
    961 	rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
    962 
    963 	if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
    964 		ETIME_SETUP;
    965 		StatslogEtime( LDAP_DEBUG_STATS,
    966 			"%s RESULT tag=%lu err=%d "ETIME_LOGFMT"text=%s\n",
    967 			op->o_log_prefix, rs->sr_tag, rs->sr_err,
    968 			rs->sr_text ? rs->sr_text : "" );
    969 	}
    970 }
    971 
    972 void
    973 slap_send_ldap_extended( Operation *op, SlapReply *rs )
    974 {
    975 	Debug( LDAP_DEBUG_TRACE,
    976 		"send_ldap_extended: err=%d oid=%s len=%ld\n",
    977 		rs->sr_err,
    978 		rs->sr_rspoid ? rs->sr_rspoid : "",
    979 		rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 );
    980 
    981 	RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
    982 	rs->sr_flags &= ~REP_ENTRY_MASK;	/* paranoia */
    983 
    984 	rs->sr_type = REP_EXTENDED;
    985 	rs->sr_tag = slap_req2res( op->o_tag );
    986 	rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
    987 
    988 	if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
    989 		ETIME_SETUP;
    990 		StatslogEtime( LDAP_DEBUG_STATS,
    991 			"%s RESULT oid=%s err=%d "ETIME_LOGFMT"text=%s\n",
    992 			op->o_log_prefix, rs->sr_rspoid ? rs->sr_rspoid : "",
    993 			rs->sr_err, rs->sr_text ? rs->sr_text : "" );
    994 	}
    995 }
    996 
    997 void
    998 slap_send_ldap_intermediate( Operation *op, SlapReply *rs )
    999 {
   1000 	Debug( LDAP_DEBUG_TRACE,
   1001 		"send_ldap_intermediate: err=%d oid=%s len=%ld\n",
   1002 		rs->sr_err,
   1003 		rs->sr_rspoid ? rs->sr_rspoid : "",
   1004 		rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 );
   1005 
   1006 	RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
   1007 	rs->sr_flags &= ~REP_ENTRY_MASK;	/* paranoia */
   1008 
   1009 	rs->sr_type = REP_INTERMEDIATE;
   1010 	rs->sr_tag = LDAP_RES_INTERMEDIATE;
   1011 	rs->sr_msgid = op->o_msgid;
   1012 	if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
   1013 		Debug( LDAP_DEBUG_STATS2,
   1014 			"%s INTERMEDIATE oid=%s\n",
   1015 			op->o_log_prefix,
   1016 			rs->sr_rspoid ? rs->sr_rspoid : "" );
   1017 	}
   1018 }
   1019 
   1020 #define set_ldap_error( rs, err, text ) do { \
   1021 		(rs)->sr_err = err; (rs)->sr_text = text; } while(0)
   1022 
   1023 /*
   1024  * returns:
   1025  *
   1026  * LDAP_SUCCESS			entry sent
   1027  * LDAP_OTHER			entry not sent (other)
   1028  * LDAP_INSUFFICIENT_ACCESS	entry not sent (ACL)
   1029  * LDAP_UNAVAILABLE		entry not sent (connection closed)
   1030  * LDAP_SIZELIMIT_EXCEEDED	entry not sent (caller must send sizelimitExceeded)
   1031  */
   1032 
   1033 int
   1034 slap_send_search_entry( Operation *op, SlapReply *rs )
   1035 {
   1036 	BerElementBuffer berbuf;
   1037 	BerElement	*ber = (BerElement *) &berbuf;
   1038 	Attribute	*a;
   1039 	int		i, j, rc = LDAP_UNAVAILABLE, bytes;
   1040 	int		userattrs;
   1041 	AccessControlState acl_state = ACL_STATE_INIT;
   1042 	int			 attrsonly;
   1043 	AttributeDescription *ad_entry = slap_schema.si_ad_entry;
   1044 
   1045 	/* a_flags: array of flags telling if the i-th element will be
   1046 	 *          returned or filtered out
   1047 	 * e_flags: array of a_flags
   1048 	 */
   1049 	char **e_flags = NULL;
   1050 
   1051 	rs->sr_type = REP_SEARCH;
   1052 
   1053 	if ( op->ors_slimit >= 0 && rs->sr_nentries >= op->ors_slimit ) {
   1054 		rc = LDAP_SIZELIMIT_EXCEEDED;
   1055 		goto error_return;
   1056 	}
   1057 
   1058 	/* Every 64 entries, check for thread pool pause */
   1059 	if ( ( ( rs->sr_nentries & 0x3f ) == 0x3f ) &&
   1060 		ldap_pvt_thread_pool_pausing( &connection_pool ) > 0 )
   1061 	{
   1062 		rc = LDAP_BUSY;
   1063 		goto error_return;
   1064 	}
   1065 
   1066 	/* eventually will loop through generated operational attribute types
   1067 	 * currently implemented types include:
   1068 	 *	entryDN, subschemaSubentry, and hasSubordinates */
   1069 	/* NOTE: moved before overlays callback circling because
   1070 	 * they may modify entry and other stuff in rs */
   1071 	/* check for special all operational attributes ("+") type */
   1072 	/* FIXME: maybe we could set this flag at the operation level;
   1073 	 * however, in principle the caller of send_search_entry() may
   1074 	 * change the attribute list at each call */
   1075 	rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs );
   1076 
   1077 	rc = backend_operational( op, rs );
   1078 	if ( rc ) {
   1079 		goto error_return;
   1080 	}
   1081 
   1082 	if ( op->o_callback ) {
   1083 		rc = slap_response_play( op, rs );
   1084 		if ( rc != SLAP_CB_CONTINUE ) {
   1085 			goto error_return;
   1086 		}
   1087 	}
   1088 
   1089 	Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: conn %lu dn=\"%s\"%s\n",
   1090 		op->o_connid, rs->sr_entry->e_name.bv_val,
   1091 		op->ors_attrsonly ? " (attrsOnly)" : "" );
   1092 
   1093 	attrsonly = op->ors_attrsonly;
   1094 
   1095 	if ( !access_allowed( op, rs->sr_entry, ad_entry, NULL, ACL_READ, NULL )) {
   1096 		Debug( LDAP_DEBUG_ACL,
   1097 			"send_search_entry: conn %lu access to entry (%s) not allowed\n",
   1098 			op->o_connid, rs->sr_entry->e_name.bv_val );
   1099 
   1100 		rc = LDAP_INSUFFICIENT_ACCESS;
   1101 		goto error_return;
   1102 	}
   1103 
   1104 	if ( op->o_res_ber ) {
   1105 		/* read back control or LDAP_CONNECTIONLESS */
   1106 	    ber = op->o_res_ber;
   1107 	} else {
   1108 		struct berval	bv;
   1109 
   1110 		bv.bv_len = entry_flatsize( rs->sr_entry, 0 );
   1111 		bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );
   1112 
   1113 		ber_init2( ber, &bv, LBER_USE_DER );
   1114 		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
   1115 	}
   1116 
   1117 #ifdef LDAP_CONNECTIONLESS
   1118 	if ( op->o_conn && op->o_conn->c_is_udp ) {
   1119 		/* CONNECTIONLESS */
   1120 		if ( op->o_protocol == LDAP_VERSION2 ) {
   1121 	    	rc = ber_printf(ber, "t{O{" /*}}*/,
   1122 				LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
   1123 		} else {
   1124 	    	rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
   1125 				LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
   1126 		}
   1127 	} else
   1128 #endif
   1129 	if ( op->o_res_ber ) {
   1130 		/* read back control */
   1131 	    rc = ber_printf( ber, "t{O{" /*}}*/,
   1132 			LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
   1133 	} else {
   1134 	    rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
   1135 			LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
   1136 	}
   1137 
   1138 	if ( rc == -1 ) {
   1139 		Debug( LDAP_DEBUG_ANY,
   1140 			"send_search_entry: conn %lu  ber_printf failed\n",
   1141 			op->o_connid );
   1142 
   1143 		if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1144 		set_ldap_error( rs, LDAP_OTHER, "encoding DN error" );
   1145 		rc = rs->sr_err;
   1146 		goto error_return;
   1147 	}
   1148 
   1149 	/* check for special all user attributes ("*") type */
   1150 	userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
   1151 
   1152 	/* create an array of arrays of flags. Each flag corresponds
   1153 	 * to particular value of attribute and equals 1 if value matches
   1154 	 * to ValuesReturnFilter or 0 if not
   1155 	 */
   1156 	if ( op->o_vrFilter != NULL ) {
   1157 		int	k = 0;
   1158 		size_t	size;
   1159 
   1160 		for ( a = rs->sr_entry->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
   1161 			for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
   1162 		}
   1163 
   1164 		size = i * sizeof(char *) + k;
   1165 		if ( size > 0 ) {
   1166 			char	*a_flags;
   1167 			e_flags = slap_sl_calloc ( 1, i * sizeof(char *) + k, op->o_tmpmemctx );
   1168 			if( e_flags == NULL ) {
   1169 		    	Debug( LDAP_DEBUG_ANY,
   1170 					"send_search_entry: conn %lu slap_sl_calloc failed\n",
   1171 					op->o_connid );
   1172 				ber_free( ber, 1 );
   1173 
   1174 				set_ldap_error( rs, LDAP_OTHER, "out of memory" );
   1175 				goto error_return;
   1176 			}
   1177 			a_flags = (char *)(e_flags + i);
   1178 			memset( a_flags, 0, k );
   1179 			for ( a=rs->sr_entry->e_attrs, i=0; a != NULL; a=a->a_next, i++ ) {
   1180 				for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
   1181 				e_flags[i] = a_flags;
   1182 				a_flags += j;
   1183 			}
   1184 
   1185 			rc = filter_matched_values(op, rs->sr_entry->e_attrs, &e_flags) ;
   1186 			if ( rc == -1 ) {
   1187 			    	Debug( LDAP_DEBUG_ANY, "send_search_entry: "
   1188 					"conn %lu matched values filtering failed\n",
   1189 					op->o_connid );
   1190 				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1191 				set_ldap_error( rs, LDAP_OTHER,
   1192 					"matched values filtering error" );
   1193 				rc = rs->sr_err;
   1194 				goto error_return;
   1195 			}
   1196 		}
   1197 	}
   1198 
   1199 	for ( a = rs->sr_entry->e_attrs, j = 0; a != NULL; a = a->a_next, j++ ) {
   1200 		AttributeDescription *desc = a->a_desc;
   1201 		int finish = 0;
   1202 
   1203 		if ( rs->sr_attrs == NULL ) {
   1204 			/* all user attrs request, skip operational attributes */
   1205 			if( is_at_operational( desc->ad_type ) ) {
   1206 				continue;
   1207 			}
   1208 
   1209 		} else {
   1210 			/* specific attrs requested */
   1211 			if ( is_at_operational( desc->ad_type ) ) {
   1212 				/* if not explicitly requested */
   1213 				if ( !ad_inlist( desc, rs->sr_attrs )) {
   1214 					/* if not all op attrs requested, skip */
   1215 					if ( !SLAP_OPATTRS( rs->sr_attr_flags ))
   1216 						continue;
   1217 					/* if DSA-specific and replicating, skip */
   1218 					if ( op->o_sync != SLAP_CONTROL_NONE &&
   1219 						desc->ad_type->sat_usage == LDAP_SCHEMA_DSA_OPERATION )
   1220 						continue;
   1221 				}
   1222 			} else {
   1223 				if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
   1224 					continue;
   1225 				}
   1226 			}
   1227 		}
   1228 
   1229 		if ( attrsonly ) {
   1230 			if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
   1231 				ACL_READ, &acl_state ) )
   1232 			{
   1233 				Debug( LDAP_DEBUG_ACL, "send_search_entry: "
   1234 					"conn %lu access to attribute %s not allowed\n",
   1235 				        op->o_connid, desc->ad_cname.bv_val );
   1236 				continue;
   1237 			}
   1238 
   1239 			if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) {
   1240 				Debug( LDAP_DEBUG_ANY,
   1241 					"send_search_entry: conn %lu  ber_printf failed\n",
   1242 					op->o_connid );
   1243 
   1244 				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1245 				set_ldap_error( rs, LDAP_OTHER,
   1246 					"encoding description error");
   1247 				rc = rs->sr_err;
   1248 				goto error_return;
   1249 			}
   1250 			finish = 1;
   1251 
   1252 		} else {
   1253 			int first = 1;
   1254 			for ( i = 0; a->a_nvals[i].bv_val != NULL; i++ ) {
   1255 				if ( ! access_allowed( op, rs->sr_entry,
   1256 					desc, &a->a_nvals[i], ACL_READ, &acl_state ) )
   1257 				{
   1258 					Debug( LDAP_DEBUG_ACL,
   1259 						"send_search_entry: conn %lu "
   1260 						"access to attribute %s, value #%d not allowed\n",
   1261 						op->o_connid, desc->ad_cname.bv_val, i );
   1262 
   1263 					continue;
   1264 				}
   1265 
   1266 				if ( op->o_vrFilter && e_flags[j][i] == 0 ){
   1267 					continue;
   1268 				}
   1269 
   1270 				if ( first ) {
   1271 					first = 0;
   1272 					finish = 1;
   1273 					if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) {
   1274 						Debug( LDAP_DEBUG_ANY,
   1275 							"send_search_entry: conn %lu  ber_printf failed\n",
   1276 							op->o_connid );
   1277 
   1278 						if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1279 						set_ldap_error( rs, LDAP_OTHER,
   1280 							"encoding description error");
   1281 						rc = rs->sr_err;
   1282 						goto error_return;
   1283 					}
   1284 				}
   1285 				if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
   1286 					Debug( LDAP_DEBUG_ANY,
   1287 						"send_search_entry: conn %lu  "
   1288 						"ber_printf failed.\n", op->o_connid );
   1289 
   1290 					if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1291 					set_ldap_error( rs, LDAP_OTHER,
   1292 						"encoding values error" );
   1293 					rc = rs->sr_err;
   1294 					goto error_return;
   1295 				}
   1296 			}
   1297 		}
   1298 
   1299 		if ( finish && ( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
   1300 			Debug( LDAP_DEBUG_ANY,
   1301 				"send_search_entry: conn %lu ber_printf failed\n",
   1302 				op->o_connid );
   1303 
   1304 			if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1305 			set_ldap_error( rs, LDAP_OTHER, "encode end error" );
   1306 			rc = rs->sr_err;
   1307 			goto error_return;
   1308 		}
   1309 	}
   1310 
   1311 	/* NOTE: moved before overlays callback circling because
   1312 	 * they may modify entry and other stuff in rs */
   1313 	if ( rs->sr_operational_attrs != NULL && op->o_vrFilter != NULL ) {
   1314 		int	k = 0;
   1315 		size_t	size;
   1316 
   1317 		for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
   1318 			for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
   1319 		}
   1320 
   1321 		size = i * sizeof(char *) + k;
   1322 		if ( size > 0 ) {
   1323 			char	*a_flags, **tmp;
   1324 
   1325 			/*
   1326 			 * Reuse previous memory - we likely need less space
   1327 			 * for operational attributes
   1328 			 */
   1329 			tmp = slap_sl_realloc( e_flags, i * sizeof(char *) + k,
   1330 				op->o_tmpmemctx );
   1331 			if ( tmp == NULL ) {
   1332 			    	Debug( LDAP_DEBUG_ANY,
   1333 					"send_search_entry: conn %lu "
   1334 					"not enough memory "
   1335 					"for matched values filtering\n",
   1336 					op->o_connid );
   1337 				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1338 				set_ldap_error( rs, LDAP_OTHER,
   1339 					"not enough memory for matched values filtering" );
   1340 				goto error_return;
   1341 			}
   1342 			e_flags = tmp;
   1343 			a_flags = (char *)(e_flags + i);
   1344 			memset( a_flags, 0, k );
   1345 			for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
   1346 				for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
   1347 				e_flags[i] = a_flags;
   1348 				a_flags += j;
   1349 			}
   1350 			rc = filter_matched_values(op, rs->sr_operational_attrs, &e_flags) ;
   1351 
   1352 			if ( rc == -1 ) {
   1353 			    	Debug( LDAP_DEBUG_ANY,
   1354 					"send_search_entry: conn %lu "
   1355 					"matched values filtering failed\n",
   1356 					op->o_connid );
   1357 				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1358 				set_ldap_error( rs, LDAP_OTHER,
   1359 					"matched values filtering error" );
   1360 				rc = rs->sr_err;
   1361 				goto error_return;
   1362 			}
   1363 		}
   1364 	}
   1365 
   1366 	for (a = rs->sr_operational_attrs, j=0; a != NULL; a = a->a_next, j++ ) {
   1367 		AttributeDescription *desc = a->a_desc;
   1368 
   1369 		if ( rs->sr_attrs == NULL ) {
   1370 			/* all user attrs request, skip operational attributes */
   1371 			if( is_at_operational( desc->ad_type ) ) {
   1372 				continue;
   1373 			}
   1374 
   1375 		} else {
   1376 			/* specific attrs requested */
   1377 			if( is_at_operational( desc->ad_type ) ) {
   1378 				if ( !SLAP_OPATTRS( rs->sr_attr_flags ) &&
   1379 					!ad_inlist( desc, rs->sr_attrs ) )
   1380 				{
   1381 					continue;
   1382 				}
   1383 				/* if DSA-specific and replicating, skip */
   1384 				if ( op->o_sync != SLAP_CONTROL_NONE &&
   1385 					desc->ad_type->sat_usage == LDAP_SCHEMA_DSA_OPERATION )
   1386 					continue;
   1387 			} else {
   1388 				if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
   1389 					continue;
   1390 				}
   1391 			}
   1392 		}
   1393 
   1394 		if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
   1395 			ACL_READ, &acl_state ) )
   1396 		{
   1397 			Debug( LDAP_DEBUG_ACL,
   1398 				"send_search_entry: conn %lu "
   1399 				"access to attribute %s not allowed\n",
   1400 				op->o_connid, desc->ad_cname.bv_val );
   1401 
   1402 			continue;
   1403 		}
   1404 
   1405 		rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname );
   1406 		if ( rc == -1 ) {
   1407 			Debug( LDAP_DEBUG_ANY,
   1408 				"send_search_entry: conn %lu  "
   1409 				"ber_printf failed\n", op->o_connid );
   1410 
   1411 			if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1412 			set_ldap_error( rs, LDAP_OTHER,
   1413 				"encoding description error" );
   1414 			rc = rs->sr_err;
   1415 			goto error_return;
   1416 		}
   1417 
   1418 		if ( ! attrsonly ) {
   1419 			for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) {
   1420 				if ( ! access_allowed( op, rs->sr_entry,
   1421 					desc, &a->a_vals[i], ACL_READ, &acl_state ) )
   1422 				{
   1423 					Debug( LDAP_DEBUG_ACL,
   1424 						"send_search_entry: conn %lu "
   1425 						"access to %s, value %d not allowed\n",
   1426 						op->o_connid, desc->ad_cname.bv_val, i );
   1427 
   1428 					continue;
   1429 				}
   1430 
   1431 				if ( op->o_vrFilter && e_flags[j][i] == 0 ){
   1432 					continue;
   1433 				}
   1434 
   1435 				if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
   1436 					Debug( LDAP_DEBUG_ANY,
   1437 						"send_search_entry: conn %lu  ber_printf failed\n",
   1438 						op->o_connid );
   1439 
   1440 					if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1441 					set_ldap_error( rs, LDAP_OTHER,
   1442 						"encoding values error" );
   1443 					rc = rs->sr_err;
   1444 					goto error_return;
   1445 				}
   1446 			}
   1447 		}
   1448 
   1449 		if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
   1450 			Debug( LDAP_DEBUG_ANY,
   1451 				"send_search_entry: conn %lu  ber_printf failed\n",
   1452 				op->o_connid );
   1453 
   1454 			if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1455 			set_ldap_error( rs, LDAP_OTHER, "encode end error" );
   1456 			rc = rs->sr_err;
   1457 			goto error_return;
   1458 		}
   1459 	}
   1460 
   1461 	/* free e_flags */
   1462 	if ( e_flags ) {
   1463 		slap_sl_free( e_flags, op->o_tmpmemctx );
   1464 		e_flags = NULL;
   1465 	}
   1466 
   1467 	rc = ber_printf( ber, /*{{*/ "}N}" );
   1468 
   1469 	if( rc != -1 ) {
   1470 		rc = send_ldap_controls( op, ber, rs->sr_ctrls );
   1471 	}
   1472 
   1473 	if( rc != -1 ) {
   1474 #ifdef LDAP_CONNECTIONLESS
   1475 		if( op->o_conn && op->o_conn->c_is_udp ) {
   1476 			if ( op->o_protocol != LDAP_VERSION2 ) {
   1477 				rc = ber_printf( ber, /*{*/ "N}" );
   1478 			}
   1479 		} else
   1480 #endif
   1481 		if ( op->o_res_ber == NULL ) {
   1482 			rc = ber_printf( ber, /*{*/ "N}" );
   1483 		}
   1484 	}
   1485 
   1486 	if ( rc == -1 ) {
   1487 		Debug( LDAP_DEBUG_ANY, "ber_printf failed\n" );
   1488 
   1489 		if ( op->o_res_ber == NULL ) ber_free_buf( ber );
   1490 		set_ldap_error( rs, LDAP_OTHER, "encode entry end error" );
   1491 		rc = rs->sr_err;
   1492 		goto error_return;
   1493 	}
   1494 
   1495 	Debug( LDAP_DEBUG_STATS2, "%s ENTRY dn=\"%s\"\n",
   1496 	    op->o_log_prefix, rs->sr_entry->e_nname.bv_val );
   1497 
   1498 	rs_flush_entry( op, rs, NULL );
   1499 
   1500 	if ( op->o_res_ber == NULL ) {
   1501 		bytes = send_ldap_ber( op, ber );
   1502 		ber_free_buf( ber );
   1503 
   1504 		if ( bytes < 0 ) {
   1505 			Debug( LDAP_DEBUG_ANY,
   1506 				"send_search_entry: conn %lu  ber write failed.\n",
   1507 				op->o_connid );
   1508 
   1509 			rc = LDAP_UNAVAILABLE;
   1510 			goto error_return;
   1511 		}
   1512 		rs->sr_nentries++;
   1513 
   1514 		ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
   1515 		ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
   1516 		ldap_pvt_mp_add_ulong( op->o_counters->sc_entries, 1 );
   1517 		ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
   1518 		ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
   1519 	}
   1520 
   1521 	Debug( LDAP_DEBUG_TRACE,
   1522 		"<= send_search_entry: conn %lu exit.\n", op->o_connid );
   1523 
   1524 	rc = LDAP_SUCCESS;
   1525 
   1526 error_return:;
   1527 	if ( op->o_callback ) {
   1528 		(void)slap_cleanup_play( op, rs );
   1529 	}
   1530 
   1531 	if ( e_flags ) {
   1532 		slap_sl_free( e_flags, op->o_tmpmemctx );
   1533 	}
   1534 
   1535 	/* FIXME: Can break if rs now contains an extended response */
   1536 	if ( rs->sr_operational_attrs ) {
   1537 		attrs_free( rs->sr_operational_attrs );
   1538 		rs->sr_operational_attrs = NULL;
   1539 	}
   1540 	rs->sr_attr_flags = SLAP_ATTRS_UNDEFINED;
   1541 
   1542 	if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
   1543 		rs_flush_entry( op, rs, NULL );
   1544 	} else {
   1545 		RS_ASSERT( (rs->sr_flags & REP_ENTRY_MASK) == 0 );
   1546 	}
   1547 
   1548 	if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
   1549 		rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
   1550 		if ( rs->sr_ctrls ) {
   1551 			slap_free_ctrls( op, rs->sr_ctrls );
   1552 			rs->sr_ctrls = NULL;
   1553 		}
   1554 	}
   1555 
   1556 	return( rc );
   1557 }
   1558 
   1559 int
   1560 slap_send_search_reference( Operation *op, SlapReply *rs )
   1561 {
   1562 	BerElementBuffer berbuf;
   1563 	BerElement	*ber = (BerElement *) &berbuf;
   1564 	int rc = 0;
   1565 	int bytes;
   1566 	char *edn = rs->sr_entry ? rs->sr_entry->e_name.bv_val : "(null)";
   1567 
   1568 	AttributeDescription *ad_ref = slap_schema.si_ad_ref;
   1569 	AttributeDescription *ad_entry = slap_schema.si_ad_entry;
   1570 
   1571 	rs->sr_type = REP_SEARCHREF;
   1572 	if ( op->o_callback ) {
   1573 		rc = slap_response_play( op, rs );
   1574 		if ( rc != SLAP_CB_CONTINUE ) {
   1575 			goto rel;
   1576 		}
   1577 	}
   1578 
   1579 	Debug( LDAP_DEBUG_TRACE,
   1580 		"=> send_search_reference: dn=\"%s\"\n",
   1581 		edn );
   1582 
   1583 	if (  rs->sr_entry && ! access_allowed( op, rs->sr_entry,
   1584 		ad_entry, NULL, ACL_READ, NULL ) )
   1585 	{
   1586 		Debug( LDAP_DEBUG_ACL,
   1587 			"send_search_reference: access to entry not allowed\n" );
   1588 		rc = 1;
   1589 		goto rel;
   1590 	}
   1591 
   1592 	if ( rs->sr_entry && ! access_allowed( op, rs->sr_entry,
   1593 		ad_ref, NULL, ACL_READ, NULL ) )
   1594 	{
   1595 		Debug( LDAP_DEBUG_ACL,
   1596 			"send_search_reference: access "
   1597 			"to reference not allowed\n" );
   1598 		rc = 1;
   1599 		goto rel;
   1600 	}
   1601 
   1602 	if( op->o_domain_scope ) {
   1603 		Debug( LDAP_DEBUG_ANY,
   1604 			"send_search_reference: domainScope control in (%s)\n",
   1605 			edn );
   1606 		rc = 0;
   1607 		goto rel;
   1608 	}
   1609 
   1610 	if( rs->sr_ref == NULL ) {
   1611 		Debug( LDAP_DEBUG_ANY,
   1612 			"send_search_reference: null ref in (%s)\n",
   1613 			edn );
   1614 		rc = 1;
   1615 		goto rel;
   1616 	}
   1617 
   1618 	if( op->o_protocol < LDAP_VERSION3 ) {
   1619 		rc = 0;
   1620 		/* save the references for the result */
   1621 		if( rs->sr_ref[0].bv_val != NULL ) {
   1622 			if( value_add( &rs->sr_v2ref, rs->sr_ref ) )
   1623 				rc = LDAP_OTHER;
   1624 		}
   1625 		goto rel;
   1626 	}
   1627 
   1628 #ifdef LDAP_CONNECTIONLESS
   1629 	if( op->o_conn && op->o_conn->c_is_udp ) {
   1630 		ber = op->o_res_ber;
   1631 	} else
   1632 #endif
   1633 	{
   1634 		ber_init_w_nullc( ber, LBER_USE_DER );
   1635 		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
   1636 	}
   1637 
   1638 	rc = ber_printf( ber, "{it{W}" /*"}"*/ , op->o_msgid,
   1639 		LDAP_RES_SEARCH_REFERENCE, rs->sr_ref );
   1640 
   1641 	if( rc != -1 ) {
   1642 		rc = send_ldap_controls( op, ber, rs->sr_ctrls );
   1643 	}
   1644 
   1645 	if( rc != -1 ) {
   1646 		rc = ber_printf( ber, /*"{"*/ "N}" );
   1647 	}
   1648 
   1649 	if ( rc == -1 ) {
   1650 		Debug( LDAP_DEBUG_ANY,
   1651 			"send_search_reference: ber_printf failed\n" );
   1652 
   1653 #ifdef LDAP_CONNECTIONLESS
   1654 		if (!op->o_conn || op->o_conn->c_is_udp == 0)
   1655 #endif
   1656 		ber_free_buf( ber );
   1657 		set_ldap_error( rs, LDAP_OTHER, "encode DN error" );
   1658 		goto rel;
   1659 	}
   1660 
   1661 	rc = 0;
   1662 	rs_flush_entry( op, rs, NULL );
   1663 
   1664 #ifdef LDAP_CONNECTIONLESS
   1665 	if (!op->o_conn || op->o_conn->c_is_udp == 0) {
   1666 #endif
   1667 	bytes = send_ldap_ber( op, ber );
   1668 	ber_free_buf( ber );
   1669 
   1670 	if ( bytes < 0 ) {
   1671 		rc = LDAP_UNAVAILABLE;
   1672 	} else {
   1673 		ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
   1674 		ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
   1675 		ldap_pvt_mp_add_ulong( op->o_counters->sc_refs, 1 );
   1676 		ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
   1677 		ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
   1678 	}
   1679 #ifdef LDAP_CONNECTIONLESS
   1680 	}
   1681 #endif
   1682 	if ( rs->sr_ref != NULL ) {
   1683 		int	r;
   1684 
   1685 		for ( r = 0; !BER_BVISNULL( &rs->sr_ref[ r ] ); r++ ) {
   1686 			Debug( LDAP_DEBUG_STATS2, "%s REF #%d \"%s\"\n",
   1687 				op->o_log_prefix, r, rs->sr_ref[0].bv_val );
   1688 		}
   1689 
   1690 	} else {
   1691 		Debug( LDAP_DEBUG_STATS2, "%s REF \"(null)\"\n",
   1692 			op->o_log_prefix );
   1693 	}
   1694 
   1695 	Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n" );
   1696 
   1697 	if ( 0 ) {
   1698 rel:
   1699 	    rs_flush_entry( op, rs, NULL );
   1700 	}
   1701 
   1702 	if ( op->o_callback ) {
   1703 		(void)slap_cleanup_play( op, rs );
   1704 	}
   1705 
   1706 	if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
   1707 		rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
   1708 		if ( rs->sr_ctrls ) {
   1709 			slap_free_ctrls( op, rs->sr_ctrls );
   1710 			rs->sr_ctrls = NULL;
   1711 		}
   1712 	}
   1713 
   1714 	return rc;
   1715 }
   1716 
   1717 int
   1718 str2result(
   1719     char	*s,
   1720     int		*code,
   1721     char	**matched,
   1722     char	**info )
   1723 {
   1724 	int	rc;
   1725 	char	*c;
   1726 
   1727 	*code = LDAP_SUCCESS;
   1728 	*matched = NULL;
   1729 	*info = NULL;
   1730 
   1731 	if ( strncasecmp( s, "RESULT", STRLENOF( "RESULT" ) ) != 0 ) {
   1732 		Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
   1733 		    s );
   1734 
   1735 		return( -1 );
   1736 	}
   1737 
   1738 	rc = 0;
   1739 	while ( (s = strchr( s, '\n' )) != NULL ) {
   1740 		*s++ = '\0';
   1741 		if ( *s == '\0' ) {
   1742 			break;
   1743 		}
   1744 		if ( (c = strchr( s, ':' )) != NULL ) {
   1745 			c++;
   1746 		}
   1747 
   1748 		if ( strncasecmp( s, "code", STRLENOF( "code" ) ) == 0 ) {
   1749 			char	*next = NULL;
   1750 			long	retcode;
   1751 
   1752 			if ( c == NULL ) {
   1753 				Debug( LDAP_DEBUG_ANY, "str2result (%s) missing value\n",
   1754 				    s );
   1755 				rc = -1;
   1756 				continue;
   1757 			}
   1758 
   1759 			while ( isspace( (unsigned char) c[ 0 ] ) ) c++;
   1760 			if ( c[ 0 ] == '\0' ) {
   1761 				Debug( LDAP_DEBUG_ANY, "str2result (%s) missing or empty value\n",
   1762 				    s );
   1763 				rc = -1;
   1764 				continue;
   1765 			}
   1766 
   1767 			retcode = strtol( c, &next, 10 );
   1768 			if ( next == NULL || next == c ) {
   1769 				Debug( LDAP_DEBUG_ANY, "str2result (%s) unable to parse value\n",
   1770 				    s );
   1771 				rc = -1;
   1772 				continue;
   1773 			}
   1774 
   1775 			while ( isspace( (unsigned char) next[ 0 ] ) && next[ 0 ] != '\n' )
   1776 				next++;
   1777 			if ( next[ 0 ] != '\0' && next[ 0 ] != '\n' ) {
   1778 				Debug( LDAP_DEBUG_ANY, "str2result (%s) extra cruft after value\n",
   1779 				    s );
   1780 				rc = -1;
   1781 				continue;
   1782 			}
   1783 
   1784 			/* FIXME: what if it's larger than max int? */
   1785 			*code = (int)retcode;
   1786 
   1787 		} else if ( strncasecmp( s, "matched", STRLENOF( "matched" ) ) == 0 ) {
   1788 			if ( c != NULL ) {
   1789 				*matched = c;
   1790 			}
   1791 		} else if ( strncasecmp( s, "info", STRLENOF( "info" ) ) == 0 ) {
   1792 			if ( c != NULL ) {
   1793 				*info = c;
   1794 			}
   1795 		} else {
   1796 			Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
   1797 			    s );
   1798 
   1799 			rc = -1;
   1800 		}
   1801 	}
   1802 
   1803 	return( rc );
   1804 }
   1805 
   1806 int slap_read_controls(
   1807 	Operation *op,
   1808 	SlapReply *rs,
   1809 	Entry *e,
   1810 	const struct berval *oid,
   1811 	LDAPControl **ctrl )
   1812 {
   1813 	int rc;
   1814 	struct berval bv;
   1815 	BerElementBuffer berbuf;
   1816 	BerElement *ber = (BerElement *) &berbuf;
   1817 	LDAPControl c;
   1818 	Operation myop;
   1819 
   1820 	Debug( LDAP_DEBUG_STATS, "%s slap_read_controls: (%s) %s\n",
   1821 		op->o_log_prefix, oid->bv_val, e->e_dn );
   1822 
   1823 	rs->sr_entry = e;
   1824 	rs->sr_attrs = ( oid == &slap_pre_read_bv ) ?
   1825 		op->o_preread_attrs : op->o_postread_attrs;
   1826 
   1827 	bv.bv_len = entry_flatsize( rs->sr_entry, 0 );
   1828 	bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );
   1829 
   1830 	ber_init2( ber, &bv, LBER_USE_DER );
   1831 	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
   1832 
   1833 	/* create new operation */
   1834 	myop = *op;
   1835 	/* FIXME: o_bd needed for ACL */
   1836 	myop.o_bd = op->o_bd;
   1837 	myop.o_res_ber = ber;
   1838 	myop.o_callback = NULL;
   1839 	myop.ors_slimit = 1;
   1840 	myop.ors_attrsonly = 0;
   1841 
   1842 	rc = slap_send_search_entry( &myop, rs );
   1843 	if( rc ) return rc;
   1844 
   1845 	rc = ber_flatten2( ber, &c.ldctl_value, 0 );
   1846 
   1847 	if( rc == -1 ) return LDAP_OTHER;
   1848 
   1849 	c.ldctl_oid = oid->bv_val;
   1850 	c.ldctl_iscritical = 0;
   1851 
   1852 	if ( *ctrl == NULL ) {
   1853 		/* first try */
   1854 		*ctrl = (LDAPControl *) slap_sl_calloc( 1, sizeof(LDAPControl), NULL );
   1855 	} else {
   1856 		/* retry: free previous try */
   1857 		slap_sl_free( (*ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
   1858 	}
   1859 
   1860 	**ctrl = c;
   1861 	return LDAP_SUCCESS;
   1862 }
   1863 
   1864 /* Map API errors to protocol errors... */
   1865 int
   1866 slap_map_api2result( SlapReply *rs )
   1867 {
   1868 	switch(rs->sr_err) {
   1869 	case LDAP_SERVER_DOWN:
   1870 		return LDAP_UNAVAILABLE;
   1871 	case LDAP_LOCAL_ERROR:
   1872 		return LDAP_OTHER;
   1873 	case LDAP_ENCODING_ERROR:
   1874 	case LDAP_DECODING_ERROR:
   1875 		return LDAP_PROTOCOL_ERROR;
   1876 	case LDAP_TIMEOUT:
   1877 		return LDAP_UNAVAILABLE;
   1878 	case LDAP_AUTH_UNKNOWN:
   1879 		return LDAP_AUTH_METHOD_NOT_SUPPORTED;
   1880 	case LDAP_FILTER_ERROR:
   1881 		rs->sr_text = "Filter error";
   1882 		return LDAP_OTHER;
   1883 	case LDAP_USER_CANCELLED:
   1884 		rs->sr_text = "User cancelled";
   1885 		return LDAP_OTHER;
   1886 	case LDAP_PARAM_ERROR:
   1887 		return LDAP_PROTOCOL_ERROR;
   1888 	case LDAP_NO_MEMORY:
   1889 		return LDAP_OTHER;
   1890 	case LDAP_CONNECT_ERROR:
   1891 		return LDAP_UNAVAILABLE;
   1892 	case LDAP_NOT_SUPPORTED:
   1893 		return LDAP_UNWILLING_TO_PERFORM;
   1894 	case LDAP_CONTROL_NOT_FOUND:
   1895 		return LDAP_PROTOCOL_ERROR;
   1896 	case LDAP_NO_RESULTS_RETURNED:
   1897 		return LDAP_NO_SUCH_OBJECT;
   1898 	case LDAP_MORE_RESULTS_TO_RETURN:
   1899 		rs->sr_text = "More results to return";
   1900 		return LDAP_OTHER;
   1901 	case LDAP_CLIENT_LOOP:
   1902 	case LDAP_REFERRAL_LIMIT_EXCEEDED:
   1903 		return LDAP_LOOP_DETECT;
   1904 	default:
   1905 		if ( LDAP_API_ERROR(rs->sr_err) ) return LDAP_OTHER;
   1906 		return rs->sr_err;
   1907 	}
   1908 }
   1909 
   1910 
   1911 slap_mask_t
   1912 slap_attr_flags( AttributeName *an )
   1913 {
   1914 	slap_mask_t	flags = SLAP_ATTRS_UNDEFINED;
   1915 
   1916 	if ( an == NULL ) {
   1917 		flags |= ( SLAP_OPATTRS_NO | SLAP_USERATTRS_YES );
   1918 
   1919 	} else {
   1920 		flags |= an_find( an, slap_bv_all_operational_attrs )
   1921 			? SLAP_OPATTRS_YES : SLAP_OPATTRS_NO;
   1922 		flags |= an_find( an, slap_bv_all_user_attrs )
   1923 			? SLAP_USERATTRS_YES : SLAP_USERATTRS_NO;
   1924 	}
   1925 
   1926 	return flags;
   1927 }
   1928