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