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