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