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