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