]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
All text messages to be returned with LDAPv2 search results when
[openldap] / servers / slapd / result.c
1 /* result.c - routines to send ldap results, errors, and referrals */
2 /* $OpenLDAP$ */
3
4 #include "portable.h"
5
6 #include <stdio.h>
7
8 #include <ac/socket.h>
9 #include <ac/errno.h>
10 #include <ac/signal.h>
11 #include <ac/string.h>
12 #include <ac/ctype.h>
13 #include <ac/time.h>
14 #include <ac/unistd.h>
15
16 #include "slap.h"
17
18 /* we need LBER internals */
19 #include "../../libraries/liblber/lber-int.h"
20
21 static char *v2ref( struct berval **ref )
22 {
23         size_t len, i;
24         char *v2;
25
26         if(ref == NULL) return NULL;
27
28         len = sizeof("Referral:");
29         v2 = ch_strdup("Referral:");
30
31         for( i=0; ref[i] != NULL; i++ ) {
32                 v2 = ch_realloc( v2, len + ref[i]->bv_len + 1 );
33                 v2[len-1] = '\n';
34                 memcpy(&v2[len], ref[i]->bv_val, ref[i]->bv_len );
35                 len += ref[i]->bv_len;
36         }
37
38         v2[len-1] = '\0';
39         return v2;
40 }
41
42 static ber_tag_t req2res( ber_tag_t tag )
43 {
44         switch( tag ) {
45         case LDAP_REQ_ADD:
46         case LDAP_REQ_BIND:
47         case LDAP_REQ_COMPARE:
48         case LDAP_REQ_EXTENDED:
49         case LDAP_REQ_MODIFY:
50         case LDAP_REQ_MODRDN:
51                 tag++;
52                 break;
53
54         case LDAP_REQ_DELETE:
55                 tag = LDAP_RES_DELETE;
56                 break;
57
58         case LDAP_REQ_ABANDON:
59         case LDAP_REQ_UNBIND:
60                 tag = LBER_SEQUENCE;
61                 break;
62
63         case LDAP_REQ_SEARCH:
64                 tag = LDAP_RES_SEARCH_RESULT;
65                 break;
66
67         default:
68                 assert( 0 );
69                 tag = LBER_ERROR;
70         }
71         return tag;
72 }
73
74 static void trim_refs_urls(
75         struct berval **refs )
76 {
77         unsigned i;
78
79         if( refs == NULL ) return;
80
81         for( i=0; refs[i] != NULL; i++ ) {
82                 if(     refs[i]->bv_len > sizeof("ldap://")-1 &&
83                         strncasecmp( refs[i]->bv_val, "ldap://",
84                                 sizeof("ldap://")-1 ) == 0 )
85                 {
86                         unsigned j;
87                         for( j=sizeof("ldap://")-1; j<refs[i]->bv_len ; j++ ) {
88                                 if( refs[i]->bv_val[j] == '/' ) {
89                                         refs[i]->bv_val[j] = '\0';
90                                         refs[i]->bv_len = j;
91                                         break;
92                                 }
93                         }
94                 }
95         }
96 }
97
98 struct berval **get_entry_referrals(
99         Backend *be,
100         Connection *conn,
101         Operation *op,
102         Entry *e )
103 {
104         Attribute *attr;
105         struct berval **refs;
106         unsigned i, j;
107
108         attr = attr_find( e->e_attrs, "ref" );
109
110         if( attr == NULL ) return NULL;
111
112         for( i=0; attr->a_vals[i] != NULL; i++ ) {
113                 /* count references */
114         }
115
116         if( i < 1 ) return NULL;
117
118         refs = ch_malloc( i + 1 );
119
120         for( i=0, j=0; attr->a_vals[i] != NULL; i++ ) {
121                 unsigned k;
122                 struct berval *ref = ber_bvdup( attr->a_vals[i] );
123
124                 /* trim the label */
125                 for( k=0; k<ref->bv_len; k++ ) {
126                         if( isspace(ref->bv_val[k]) ) {
127                                 ref->bv_val[k] = '\0';
128                                 ref->bv_len = k;
129                                 break;
130                         }
131                 }
132
133                 if(     ref->bv_len > 0 ) {
134                         refs[j++] = ref;
135
136                 } else {
137                         ber_bvfree( ref );
138                 }
139         }
140
141         refs[j] = NULL;
142
143         if( j == 0 ) {
144                 ber_bvecfree( refs );
145                 refs = NULL;
146         }
147
148         /* we should check that a referral value exists... */
149
150         return refs;
151 }
152
153 static long send_ldap_ber(
154         Connection *conn,
155         BerElement *ber )
156 {
157         ber_len_t bytes = ber_pvt_ber_bytes( ber );
158
159         /* write only one pdu at a time - wait til it's our turn */
160         ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
161
162         /* lock the connection */ 
163         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
164
165         /* write the pdu */
166         while( 1 ) {
167                 int err;
168
169                 if ( connection_state_closing( conn ) ) {
170                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
171                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
172
173                         return 0;
174                 }
175
176                 if ( ber_flush( conn->c_sb, ber, 0 ) == 0 ) {
177                         break;
178                 }
179
180                 err = errno;
181
182                 /*
183                  * we got an error.  if it's ewouldblock, we need to
184                  * wait on the socket being writable.  otherwise, figure
185                  * it's a hard error and return.
186                  */
187
188                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno=%d reason=\"%s\"\n",
189                     err, STRERROR(err), 0 );
190
191                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
192                         connection_closing( conn );
193
194                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
195                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
196
197                         return( -1 );
198                 }
199
200                 /* wait for socket to be write-ready */
201                 conn->c_writewaiter = 1;
202                 slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
203
204                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
205                 conn->c_writewaiter = 0;
206         }
207
208         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
209         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
210
211         return bytes;
212 }
213
214 static void
215 send_ldap_response(
216     Connection  *conn,
217     Operation   *op,
218         ber_tag_t       tag,
219         ber_int_t       msgid,
220     ber_int_t   err,
221     const char  *matched,
222     const char  *text,
223         struct berval   **ref,
224         const char      *resoid,
225         struct berval   *resdata,
226         LDAPControl **ctrls
227 )
228 {
229         BerElement      *ber;
230         int             rc;
231         long    bytes;
232
233         assert( ctrls == NULL ); /* ctrls not implemented */
234
235         ber = ber_alloc_t( LBER_USE_DER );
236
237         Debug( LDAP_DEBUG_TRACE, "send_ldap_response: msgid=%ld tag=%ld err=%ld\n",
238                 (long) msgid, (long) tag, (long) err );
239
240         if ( ber == NULL ) {
241                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
242                 return;
243         }
244
245 #ifdef LDAP_CONNECTIONLESS
246         if ( op->o_cldap ) {
247                 rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
248                     err, matched ? matched : "", text ? text : "" );
249         } else
250 #endif
251         {
252                 rc = ber_printf( ber, "{it{ess",
253                         msgid, tag, err,
254                         matched == NULL ? "" : matched,
255                         text == NULL ? "" : text );
256
257                 if( rc != -1 && ref != NULL ) {
258                         rc = ber_printf( ber, "{V}", ref );
259                 }
260
261                 if( rc != -1 && resoid != NULL ) {
262                         rc = ber_printf( ber, "s", resoid );
263                 }
264
265                 if( rc != -1 && resdata != NULL ) {
266                         rc = ber_printf( ber, "O", resdata );
267
268                 }
269
270                 if( rc != -1 ) {
271                         rc = ber_printf( ber, "}}" );
272                 }
273         }
274
275         if ( rc == -1 ) {
276                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
277                 ber_free( ber, 1 );
278                 return;
279         }
280
281         /* send BER */
282         bytes = send_ldap_ber( conn, ber );
283         ber_free( ber, 1 );
284
285         if ( bytes < 0 ) {
286                 Debug( LDAP_DEBUG_ANY,
287                         "send_ldap_response: ber write failed\n",
288                         0, 0, 0 );
289                 return;
290         }
291
292         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
293         num_bytes_sent += bytes;
294         num_pdu_sent++;
295         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
296         return;
297 }
298
299
300 void
301 send_ldap_disconnect(
302     Connection  *conn,
303     Operation   *op,
304     ber_int_t   err,
305     const char  *text
306 )
307 {
308         ber_tag_t tag;
309         ber_int_t msgid;
310         char *reqoid;
311
312 #define LDAP_UNSOLICITED_ERROR(e) \
313         (  (e) == LDAP_PROTOCOL_ERROR \
314         || (e) == LDAP_STRONG_AUTH_REQUIRED \
315         || (e) == LDAP_UNAVAILABLE )
316
317         assert( LDAP_UNSOLICITED_ERROR( err ) );
318
319         Debug( LDAP_DEBUG_TRACE,
320                 "send_ldap_disconnect %d:%s\n",
321                 err, text ? text : "", NULL );
322
323         if ( op->o_protocol < LDAP_VERSION3 ) {
324                 reqoid = NULL;
325                 tag = req2res( op->o_tag );
326                 msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
327
328         } else {
329                 reqoid = LDAP_NOTICE_DISCONNECT;
330                 tag = LDAP_RES_EXTENDED;
331                 msgid = 0;
332         }
333
334 #ifdef LDAP_CONNECTIONLESS
335         if ( op->o_cldap ) {
336                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
337                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
338                     inet_ntoa(((struct sockaddr_in *)
339                     &op->o_clientaddr)->sin_addr ),
340                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
341                     0 );
342         }
343 #endif
344         send_ldap_response( conn, op, tag, msgid,
345                 err, NULL, text, NULL,
346                 reqoid, NULL, NULL );
347
348         Statslog( LDAP_DEBUG_STATS,
349             "conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n",
350                 (long) op->o_connid, (long) op->o_opid,
351                 (long) tag, (long) err, text ? text : "" );
352 }
353
354 void
355 send_ldap_result(
356     Connection  *conn,
357     Operation   *op,
358     ber_int_t   err,
359     const char  *matched,
360     const char  *text,
361         struct berval **ref,
362         LDAPControl **ctrls
363 )
364 {
365         ber_tag_t tag;
366         ber_int_t msgid;
367         char *tmp = NULL;
368
369         assert( !LDAP_API_ERROR( err ) );
370
371         Debug( LDAP_DEBUG_TRACE, "send_ldap_result: conn=%ld op=%ld p=%d\n",
372                 (long) op->o_connid, (long) op->o_opid, op->o_protocol );
373         Debug( LDAP_DEBUG_ARGS, "send_ldap_result: %d:%s:%s\n",
374                 err, matched ?  matched : "", text ? text : "" );
375
376         assert( err != LDAP_PARTIAL_RESULTS );
377
378         if( op->o_tag != LDAP_REQ_SEARCH ) {
379                 trim_refs_urls( ref );
380         }
381
382         if ( err == LDAP_REFERRAL ) {
383                 if( ref == NULL ) {
384                         err = LDAP_NO_SUCH_OBJECT;
385                 } else if ( op->o_protocol < LDAP_VERSION3 ) {
386                         err = LDAP_PARTIAL_RESULTS;
387                         tmp = v2ref( ref );
388                         text = tmp;
389                         ref = NULL;
390                 }
391         }
392
393         tag = req2res( op->o_tag );
394         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
395
396 #ifdef LDAP_CONNECTIONLESS
397         if ( op->o_cldap ) {
398                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
399                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
400                     inet_ntoa(((struct sockaddr_in *)
401                     &op->o_clientaddr)->sin_addr ),
402                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
403                     0 );
404         }
405 #endif
406
407         send_ldap_response( conn, op, tag, msgid,
408                 err, matched, text, ref,
409                 NULL, NULL, ctrls );
410
411         Statslog( LDAP_DEBUG_STATS,
412             "conn=%ld op=%ld RESULT tag=%lu err=%ld text=%s\n",
413                 (long) op->o_connid, (long) op->o_opid,
414                 (long) tag, (long) err, text ? text : "" );
415
416         if( tmp != NULL ) {
417                 free(tmp);
418         }
419 }
420
421
422 void
423 send_search_result(
424     Connection  *conn,
425     Operation   *op,
426     ber_int_t   err,
427     const char  *matched,
428         const char      *text,
429     struct berval **refs,
430         LDAPControl **ctrls,
431     int         nentries
432 )
433 {
434         ber_tag_t tag;
435         ber_int_t msgid;
436         char *tmp = NULL;
437         assert( !LDAP_API_ERROR( err ) );
438
439         Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
440                 err, matched ?  matched : "", text ? text : "" );
441
442         assert( err != LDAP_PARTIAL_RESULTS );
443
444         trim_refs_urls( refs );
445
446         if( op->o_protocol < LDAP_VERSION3 ) {
447                 /* send references in search results */
448                 if( err == LDAP_REFERRAL ) {
449                         err = LDAP_PARTIAL_RESULTS;
450                 }
451
452                 tmp = v2ref( refs );
453                 refs = NULL;
454
455                 if( tmp != NULL ) text = tmp;
456
457         } else {
458                 /* don't send references in search results */
459                 assert( refs == NULL );
460                 refs = NULL;
461
462                 if( err == LDAP_REFERRAL ) {
463                         err = LDAP_SUCCESS;
464                 }
465         }
466
467         tag = req2res( op->o_tag );
468         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
469
470 #ifdef LDAP_CONNECTIONLESS
471         if ( op->o_cldap ) {
472                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
473                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
474                     inet_ntoa(((struct sockaddr_in *)
475                     &op->o_clientaddr)->sin_addr ),
476                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
477                     0 );
478         }
479 #endif
480
481         send_ldap_response( conn, op, tag, msgid,
482                 err, matched, text, refs,
483                 NULL, NULL, ctrls );
484
485         Statslog( LDAP_DEBUG_STATS,
486             "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
487                 (long) op->o_connid, (long) op->o_opid,
488                 (long) tag, (long) err, text ? text : "" );
489
490 }
491
492
493 int
494 send_search_entry(
495     Backend     *be,
496     Connection  *conn,
497     Operation   *op,
498     Entry       *e,
499     char        **attrs,
500     int         attrsonly,
501         LDAPControl **ctrls
502 )
503 {
504         BerElement      *ber;
505         Attribute       *a;
506         int             i, rc=-1, bytes;
507         char            *edn;
508         int             userattrs;
509         int             opattrs;
510
511         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: \"%s\"\n", e->e_dn, 0, 0 );
512
513         if ( ! access_allowed( be, conn, op, e,
514                 "entry", NULL, ACL_READ ) )
515         {
516                 Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
517                     0, 0, 0 );
518                 return( 1 );
519         }
520
521         edn = e->e_ndn;
522
523         ber = ber_alloc_t( LBER_USE_DER );
524
525         if ( ber == NULL ) {
526                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
527                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
528                         NULL, "allocating BER error", NULL, NULL );
529                 goto error_return;
530         }
531
532         rc = ber_printf( ber, "{it{s{", op->o_msgid,
533                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
534
535         if ( rc == -1 ) {
536                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
537                 ber_free( ber, 1 );
538                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
539                     NULL, "encoding dn error", NULL, NULL );
540                 goto error_return;
541         }
542
543         /* check for special all user attributes ("*") type */
544         userattrs = ( attrs == NULL ) ? 1
545                 : charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES );
546
547         /* check for special all operational attributes ("+") type */
548         opattrs = ( attrs == NULL ) ? 0
549                 : charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
550
551         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
552                 if ( attrs == NULL ) {
553                         /* all addrs request, skip operational attributes */
554                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
555                                 continue;
556                         }
557
558                 } else {
559                         /* specific addrs requested */
560                         if (  oc_check_operational_attr( a->a_type ) ) {
561                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
562                                 {
563                                         continue;
564                                 }
565                         } else {
566                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
567                                 {
568                                         continue;
569                                 }
570                         }
571                 }
572
573                 if ( ! access_allowed( be, conn, op, e,
574                         a->a_type, NULL, ACL_READ ) )
575                 {
576                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
577                             a->a_type, 0, 0 );
578                         continue;
579                 }
580
581                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
582                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
583                         ber_free( ber, 1 );
584                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
585                             NULL, "encoding type error", NULL, NULL );
586                         goto error_return;
587                 }
588
589                 if ( ! attrsonly ) {
590                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
591                                 if ( ! access_allowed( be, conn, op, e,
592                                         a->a_type, a->a_vals[i], ACL_READ ) )
593                                 {
594                                         Debug( LDAP_DEBUG_ACL,
595                                                 "acl: access to attribute %s, value %d not allowed\n",
596                                         a->a_type, i, 0 );
597                                         continue;
598                                 }
599
600                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
601                                         Debug( LDAP_DEBUG_ANY,
602                                             "ber_printf failed\n", 0, 0, 0 );
603                                         ber_free( ber, 1 );
604                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
605                                                 NULL, "encoding value error", NULL, NULL );
606                                         goto error_return;
607                                 }
608                         }
609                 }
610
611                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
612                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
613                         ber_free( ber, 1 );
614                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
615                             NULL, "encode end error", NULL, NULL );
616                         goto error_return;
617                 }
618         }
619
620 #ifdef SLAPD_SCHEMA_DN
621         /* eventually will loop through generated operational attributes */
622         /* only have subschemaSubentry implemented */
623         a = backend_subschemasubentry( be );
624         
625         do {
626                 if ( attrs == NULL ) {
627                         /* all addrs request, skip operational attributes */
628                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
629                                 continue;
630                         }
631
632                 } else {
633                         /* specific addrs requested */
634                         if (  oc_check_operational_attr( a->a_type ) ) {
635                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
636                                 {
637                                         continue;
638                                 }
639                         } else {
640                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
641                                 {
642                                         continue;
643                                 }
644                         }
645                 }
646
647                 if ( ! access_allowed( be, conn, op, e,
648                         a->a_type, NULL, ACL_READ ) )
649                 {
650                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
651                             a->a_type, 0, 0 );
652                         continue;
653                 }
654
655                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
656                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
657                         ber_free( ber, 1 );
658                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
659                             NULL, "encoding type error", NULL, NULL );
660                         goto error_return;
661                 }
662
663                 if ( ! attrsonly ) {
664                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
665                                 if ( ! access_allowed( be, conn, op, e,
666                                         a->a_type, a->a_vals[i], ACL_READ ) )
667                                 {
668                                         Debug( LDAP_DEBUG_ACL,
669                                                 "acl: access to attribute %s, value %d not allowed\n",
670                                         a->a_type, i, 0 );
671                                         continue;
672                                 }
673
674
675                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
676                                         Debug( LDAP_DEBUG_ANY,
677                                             "ber_printf failed\n", 0, 0, 0 );
678                                         ber_free( ber, 1 );
679                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
680                                                 NULL, "encoding value error", NULL, NULL );
681                                         goto error_return;
682                                 }
683                         }
684                 }
685
686                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
687                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
688                         ber_free( ber, 1 );
689                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
690                             NULL, "encode end error", NULL, NULL );
691                         goto error_return;
692                 }
693         } while (0);
694 #endif
695
696         rc = ber_printf( ber, /*{{{*/ "}}}" );
697
698         if ( rc == -1 ) {
699                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
700                 ber_free( ber, 1 );
701                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
702                         NULL, "encode entry end error", NULL, NULL );
703                 return( 1 );
704         }
705
706         bytes = send_ldap_ber( conn, ber );
707         ber_free( ber, 1 );
708
709         if ( bytes < 0 ) {
710                 Debug( LDAP_DEBUG_ANY,
711                         "send_ldap_response: ber write failed\n",
712                         0, 0, 0 );
713                 return -1;
714         }
715
716         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
717         num_bytes_sent += bytes;
718         num_entries_sent++;
719         num_pdu_sent++;
720         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
721
722         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
723             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
724
725         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
726
727         rc = 0;
728
729 error_return:;
730         return( rc );
731 }
732
733 int
734 send_search_reference(
735     Backend     *be,
736     Connection  *conn,
737     Operation   *op,
738     Entry       *e,
739         struct berval **refs,
740         int scope,
741         LDAPControl **ctrls,
742     struct berval ***v2refs
743 )
744 {
745         BerElement      *ber;
746         int rc;
747         int bytes;
748
749         Debug( LDAP_DEBUG_TRACE, "=> send_search_reference (%s)\n", e->e_dn, 0, 0 );
750
751         if ( ! access_allowed( be, conn, op, e,
752                 "entry", NULL, ACL_READ ) )
753         {
754                 Debug( LDAP_DEBUG_ACL,
755                         "send_search_reference: access to entry not allowed\n",
756                     0, 0, 0 );
757                 return( 1 );
758         }
759
760         if ( ! access_allowed( be, conn, op, e,
761                 "ref", NULL, ACL_READ ) )
762         {
763                 Debug( LDAP_DEBUG_ACL,
764                         "send_search_reference: access to reference not allowed\n",
765                     0, 0, 0 );
766                 return( 1 );
767         }
768
769         if( refs == NULL ) {
770                 Debug( LDAP_DEBUG_ANY,
771                         "send_search_reference: null ref in (%s)\n", 
772                         e->e_dn, 0, 0 );
773                 return( 1 );
774         }
775
776         if( op->o_protocol < LDAP_VERSION3 ) {
777                 /* save the references for the result */
778                 if( *refs == NULL ) {
779                         value_add( v2refs, refs );
780                 }
781                 return 0;
782         }
783
784         ber = ber_alloc_t( LBER_USE_DER );
785
786         if ( ber == NULL ) {
787                 Debug( LDAP_DEBUG_ANY,
788                         "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
789                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
790                         NULL, "alloc BER error", NULL, NULL );
791                 return -1;
792         }
793
794         rc = ber_printf( ber, "{it{V}}", op->o_msgid,
795                 LDAP_RES_SEARCH_REFERENCE, refs );
796
797         if ( rc == -1 ) {
798                 Debug( LDAP_DEBUG_ANY,
799                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
800                 ber_free( ber, 1 );
801                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
802                         NULL, "encode dn error", NULL, NULL );
803                 return -1;
804         }
805
806         bytes = send_ldap_ber( conn, ber );
807         ber_free( ber, 1 );
808
809         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
810         num_bytes_sent += bytes;
811         num_refs_sent++;
812         num_pdu_sent++;
813         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
814
815         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
816             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
817
818         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
819
820         return 0;
821 }
822
823
824 int
825 str2result(
826     char        *s,
827     int         *code,
828     char        **matched,
829     char        **info
830 )
831 {
832         int     rc;
833         char    *c;
834
835         *code = LDAP_SUCCESS;
836         *matched = NULL;
837         *info = NULL;
838
839         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
840                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
841                     s, 0, 0 );
842
843                 return( -1 );
844         }
845
846         rc = 0;
847         while ( (s = strchr( s, '\n' )) != NULL ) {
848                 *s++ = '\0';
849                 if ( *s == '\0' ) {
850                         break;
851                 }
852                 if ( (c = strchr( s, ':' )) != NULL ) {
853                         c++;
854                 }
855
856                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
857                         if ( c != NULL ) {
858                                 *code = atoi( c );
859                         }
860                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
861                         if ( c != NULL ) {
862                                 *matched = c;
863                         }
864                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
865                         if ( c != NULL ) {
866                                 *info = c;
867                         }
868                 } else {
869                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
870                             s, 0, 0 );
871                         rc = -1;
872                 }
873         }
874
875         return( rc );
876 }