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