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