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