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