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