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