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