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