]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
Fix = vs == bug
[openldap] / servers / slapd / result.c
1 /* result.c - routines to send ldap results, errors, and referrals */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/socket.h>
8 #include <ac/errno.h>
9 #include <ac/signal.h>
10 #include <ac/string.h>
11 #include <ac/ctype.h>
12 #include <ac/time.h>
13 #include <ac/unistd.h>
14
15 #include "slap.h"
16
17 /* we need LBER internals */
18 #include "../../libraries/liblber/lber-int.h"
19
20 static char *v2ref( struct berval **ref )
21 {
22         size_t len, i;
23         char *v2;
24
25         if(ref == NULL) return NULL;
26
27         len = sizeof("Referral:");
28         v2 = ch_strdup("Referral:");
29
30         for( i=0; ref[i] != NULL; i++ ) {
31                 v2 = ch_realloc( v2, len + ref[i]->bv_len + 1 );
32                 v2[len-1] = '\n';
33                 memcpy(&v2[len], ref[i]->bv_val, ref[i]->bv_len );
34                 len += ref[i]->bv_len;
35         }
36
37         v2[len-1] = '\0';
38         return v2;
39 }
40
41 static ber_tag_t req2res( ber_tag_t tag )
42 {
43         switch( tag ) {
44         case LDAP_REQ_ADD:
45         case LDAP_REQ_BIND:
46         case LDAP_REQ_COMPARE:
47         case LDAP_REQ_EXTENDED:
48         case LDAP_REQ_MODIFY:
49         case LDAP_REQ_MODRDN:
50                 tag++;
51                 break;
52
53         case LDAP_REQ_DELETE:
54                 tag = LDAP_RES_DELETE;
55                 break;
56
57         case LDAP_REQ_ABANDON:
58         case LDAP_REQ_UNBIND:
59                 tag = LBER_SEQUENCE;
60                 break;
61
62         case LDAP_REQ_SEARCH:
63                 tag = LDAP_RES_SEARCH_RESULT;
64                 break;
65
66         default:
67                 assert( 0 );
68                 tag = LBER_ERROR;
69         }
70         return tag;
71 }
72
73 static void trim_refs_urls(
74         struct berval **refs )
75 {
76         unsigned i;
77
78         if( refs == NULL ) return;
79
80         for( i=0; refs[i] != NULL; i++ ) {
81                 if(     refs[i]->bv_len > sizeof("ldap://") &&
82                         strncasecmp( refs[i]->bv_val, "ldap://",
83                                 sizeof("ldap://")-1 ) == 0 )
84                 {
85                         unsigned j;
86                         for( j=sizeof("ldap://"); j<refs[i]->bv_len ; j++ ) {
87                                 if( refs[i]->bv_val[j] == '/' ) {
88                                         refs[i]->bv_val[j] = '\0';
89                                         refs[i]->bv_len = j;
90                                         break;
91                                 }
92                         }
93                 }
94         }
95 }
96
97 struct berval **get_entry_referrals(
98         Backend *be,
99         Connection *conn,
100         Operation *op,
101         Entry *e )
102 {
103         Attribute *attr;
104         struct berval **refs;
105         unsigned i, j;
106
107         attr = attr_find( e->e_attrs, "ref" );
108
109         if( attr == NULL ) return NULL;
110
111         for( i=0; attr->a_vals[i] != NULL; i++ ) {
112                 /* count references */
113         }
114
115         if( i < 1 ) return NULL;
116
117         refs = ch_malloc( i + 1 );
118
119         for( i=0, j=0; attr->a_vals[i] != NULL; i++ ) {
120                 unsigned k;
121                 struct berval *ref = ber_bvdup( attr->a_vals[i] );
122
123                 /* trim the label */
124                 for( k=0; k<ref->bv_len; k++ ) {
125                         if( isspace(ref->bv_val[k]) ) {
126                                 ref->bv_val[k] = '\0';
127                                 ref->bv_len = k;
128                                 break;
129                         }
130                 }
131
132                 if(     ref->bv_len > 0 ) {
133                         refs[j++] = ref;
134
135                 } else {
136                         ber_bvfree( ref );
137                 }
138         }
139
140         refs[j] = NULL;
141
142         if( j == 0 ) {
143                 ber_bvecfree( refs );
144                 refs = NULL;
145         }
146
147         /* we should check that a referral value exists... */
148
149         return refs;
150 }
151
152 static long send_ldap_ber(
153         Connection *conn,
154         BerElement *ber )
155 {
156         ber_len_t bytes = ber_pvt_ber_bytes( ber );
157
158         /* write only one pdu at a time - wait til it's our turn */
159         ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
160
161         /* lock the connection */ 
162         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
163
164         /* write the pdu */
165         while( 1 ) {
166                 int err;
167
168                 if ( connection_state_closing( conn ) ) {
169                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
170                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
171
172                         return 0;
173                 }
174
175                 if ( ber_flush( conn->c_sb, ber, 0 ) == 0 ) {
176                         break;
177                 }
178
179                 err = errno;
180
181                 /*
182                  * we got an error.  if it's ewouldblock, we need to
183                  * wait on the socket being writable.  otherwise, figure
184                  * it's a hard error and return.
185                  */
186
187                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno=%d reason=\"%s\"\n",
188                     err, STRERROR(err), 0 );
189
190                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
191                         connection_closing( conn );
192
193                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
194                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
195
196                         return( -1 );
197                 }
198
199                 /* wait for socket to be write-ready */
200                 conn->c_writewaiter = 1;
201                 slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
202
203                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
204                 conn->c_writewaiter = 0;
205         }
206
207         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
208         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
209
210         return bytes;
211 }
212
213 static void
214 send_ldap_response(
215     Connection  *conn,
216     Operation   *op,
217         ber_tag_t       tag,
218         ber_int_t       msgid,
219     ber_int_t   err,
220     const char  *matched,
221     const char  *text,
222         struct berval   **ref,
223         const char      *resoid,
224         struct berval   *resdata,
225         LDAPControl **ctrls
226 )
227 {
228         BerElement      *ber;
229         int             rc;
230         long    bytes;
231
232         assert( ctrls == NULL ); /* ctrls not implemented */
233
234         ber = ber_alloc_t( LBER_USE_DER );
235
236         Debug( LDAP_DEBUG_TRACE, "send_ldap_response: msgid=%ld tag=%ld err=%ld\n",
237                 (long) msgid, (long) tag, (long) err );
238
239         if ( ber == NULL ) {
240                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
241                 return;
242         }
243
244 #ifdef LDAP_CONNECTIONLESS
245         if ( op->o_cldap ) {
246                 rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
247                     err, matched ? matched : "", text ? text : "" );
248         } else
249 #endif
250         {
251                 rc = ber_printf( ber, "{it{ess",
252                         msgid, tag, err,
253                         matched == NULL ? "" : matched,
254                         text == NULL ? "" : text );
255
256                 if( rc != -1 && ref != NULL ) {
257                         rc = ber_printf( ber, "{V}", ref );
258                 }
259
260                 if( rc != -1 && resoid != NULL ) {
261                         rc = ber_printf( ber, "s", resoid );
262                 }
263
264                 if( rc != -1 && resdata != NULL ) {
265                         rc = ber_printf( ber, "O", resdata );
266
267                 }
268
269                 if( rc != -1 ) {
270                         rc = ber_printf( ber, "}}" );
271                 }
272         }
273
274         if ( rc == -1 ) {
275                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
276                 ber_free( ber, 1 );
277                 return;
278         }
279
280         /* send BER */
281         bytes = send_ldap_ber( conn, ber );
282         ber_free( ber, 1 );
283
284         if ( bytes < 0 ) {
285                 Debug( LDAP_DEBUG_ANY,
286                         "send_ldap_response: ber write failed\n",
287                         0, 0, 0 );
288                 return;
289         }
290
291         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
292         num_bytes_sent += bytes;
293         num_pdu_sent++;
294         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
295         return;
296 }
297
298
299 void
300 send_ldap_disconnect(
301     Connection  *conn,
302     Operation   *op,
303     ber_int_t   err,
304     const char  *text
305 )
306 {
307         ber_tag_t tag;
308         ber_int_t msgid;
309         char *reqoid;
310
311 #define LDAP_UNSOLICITED_ERROR(e) \
312         (  (e) == LDAP_PROTOCOL_ERROR \
313         || (e) == LDAP_STRONG_AUTH_REQUIRED \
314         || (e) == LDAP_UNAVAILABLE )
315
316         assert( LDAP_UNSOLICITED_ERROR( err ) );
317
318         Debug( LDAP_DEBUG_TRACE,
319                 "send_ldap_disconnect %d:%s\n",
320                 err, text ? text : "", NULL );
321
322         if ( op->o_protocol < LDAP_VERSION3 ) {
323                 reqoid = NULL;
324                 tag = req2res( op->o_tag );
325                 msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
326
327         } else {
328                 reqoid = LDAP_NOTICE_DISCONNECT;
329                 tag = LDAP_RES_EXTENDED;
330                 msgid = 0;
331         }
332
333 #ifdef LDAP_CONNECTIONLESS
334         if ( op->o_cldap ) {
335                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
336                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
337                     inet_ntoa(((struct sockaddr_in *)
338                     &op->o_clientaddr)->sin_addr ),
339                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
340                     0 );
341         }
342 #endif
343         send_ldap_response( conn, op, tag, msgid,
344                 err, NULL, text, NULL,
345                 reqoid, NULL, NULL );
346
347         Statslog( LDAP_DEBUG_STATS,
348             "conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n",
349                 (long) op->o_connid, (long) op->o_opid,
350                 (long) tag, (long) err, text ? text : "" );
351 }
352
353 void
354 send_ldap_result(
355     Connection  *conn,
356     Operation   *op,
357     ber_int_t   err,
358     const char  *matched,
359     const char  *text,
360         struct berval **ref,
361         LDAPControl **ctrls
362 )
363 {
364         ber_tag_t tag;
365         ber_int_t msgid;
366         char *tmp = NULL;
367
368         assert( !LDAP_API_ERROR( err ) );
369
370         Debug( LDAP_DEBUG_TRACE, "send_ldap_result: conn=%ld op=%ld p=%d\n",
371                 (long) op->o_connid, (long) op->o_opid, op->o_protocol );
372         Debug( LDAP_DEBUG_ARGS, "send_ldap_result: %d:%s:%s\n",
373                 err, matched ?  matched : "", text ? text : "" );
374
375         assert( err != LDAP_PARTIAL_RESULTS );
376
377         if( op->o_tag != LDAP_REQ_SEARCH ) {
378                 trim_refs_urls( ref );
379         }
380
381         if ( err == LDAP_REFERRAL ) {
382                 if( ref == NULL ) {
383                         err = LDAP_NO_SUCH_OBJECT;
384                 } else if ( op->o_protocol < LDAP_VERSION3 ) {
385                         err = LDAP_PARTIAL_RESULTS;
386                         tmp = v2ref( ref );
387                         text = tmp;
388                         ref = NULL;
389                 }
390         }
391
392         tag = req2res( op->o_tag );
393         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
394
395 #ifdef LDAP_CONNECTIONLESS
396         if ( op->o_cldap ) {
397                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
398                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
399                     inet_ntoa(((struct sockaddr_in *)
400                     &op->o_clientaddr)->sin_addr ),
401                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
402                     0 );
403         }
404 #endif
405
406         send_ldap_response( conn, op, tag, msgid,
407                 err, matched, text, ref,
408                 NULL, NULL, ctrls );
409
410         Statslog( LDAP_DEBUG_STATS,
411             "conn=%ld op=%ld RESULT tag=%lu err=%ld text=%s\n",
412                 (long) op->o_connid, (long) op->o_opid,
413                 (long) tag, (long) err, text ? text : "" );
414
415         if( tmp != NULL ) {
416                 free(tmp);
417         }
418 }
419
420
421 void
422 send_search_result(
423     Connection  *conn,
424     Operation   *op,
425     ber_int_t   err,
426     const char  *matched,
427         const char      *text,
428     struct berval **refs,
429         LDAPControl **ctrls,
430     int         nentries
431 )
432 {
433         ber_tag_t tag;
434         ber_int_t msgid;
435         char *tmp = NULL;
436         assert( !LDAP_API_ERROR( err ) );
437
438         Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
439                 err, matched ?  matched : "", text ? text : "" );
440
441         assert( err != LDAP_PARTIAL_RESULTS );
442
443         trim_refs_urls( refs );
444
445         if( op->o_protocol < LDAP_VERSION3 ) {
446                 /* send references in search results */
447                 if( err == LDAP_REFERRAL ) {
448                         err = LDAP_PARTIAL_RESULTS;
449                 }
450
451                 tmp = v2ref( refs );
452                 text = tmp;
453                 refs = NULL;
454
455         } else {
456                 /* don't send references in search results */
457                 assert( refs == NULL );
458                 refs = NULL;
459
460                 if( err == LDAP_REFERRAL ) {
461                         err = LDAP_SUCCESS;
462                 }
463         }
464
465         tag = req2res( op->o_tag );
466         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
467
468 #ifdef LDAP_CONNECTIONLESS
469         if ( op->o_cldap ) {
470                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
471                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
472                     inet_ntoa(((struct sockaddr_in *)
473                     &op->o_clientaddr)->sin_addr ),
474                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
475                     0 );
476         }
477 #endif
478
479         send_ldap_response( conn, op, tag, msgid,
480                 err, matched, text, refs,
481                 NULL, NULL, ctrls );
482
483         Statslog( LDAP_DEBUG_STATS,
484             "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
485                 (long) op->o_connid, (long) op->o_opid,
486                 (long) tag, (long) err, text ? text : "" );
487
488 }
489
490
491 int
492 send_search_entry(
493     Backend     *be,
494     Connection  *conn,
495     Operation   *op,
496     Entry       *e,
497     char        **attrs,
498     int         attrsonly,
499         LDAPControl **ctrls
500 )
501 {
502         BerElement      *ber;
503         Attribute       *a;
504         int             i, rc=-1, bytes;
505         AccessControl   *acl;
506         char            *edn;
507         int             userattrs;
508         int             opattrs;
509
510         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: \"%s\"\n", e->e_dn, 0, 0 );
511
512         if ( ! access_allowed( be, conn, op, e,
513                 "entry", NULL, ACL_READ ) )
514         {
515                 Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
516                     0, 0, 0 );
517                 return( 1 );
518         }
519
520         edn = e->e_ndn;
521
522         ber = ber_alloc_t( LBER_USE_DER );
523
524         if ( ber == NULL ) {
525                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
526                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
527                         NULL, "allocating BER error", NULL, NULL );
528                 goto error_return;
529         }
530
531         rc = ber_printf( ber, "{it{s{", op->o_msgid,
532                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
533
534         if ( rc == -1 ) {
535                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
536                 ber_free( ber, 1 );
537                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
538                     NULL, "encoding dn error", NULL, NULL );
539                 goto error_return;
540         }
541
542         /* check for special all user attributes ("*") type */
543         userattrs = ( attrs == NULL ) ? 1
544                 : charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES );
545
546         /* check for special all operational attributes ("+") type */
547         opattrs = ( attrs == NULL ) ? 0
548                 : charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
549
550         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
551                 regmatch_t       matches[MAXREMATCHES];
552
553                 if ( attrs == NULL ) {
554                         /* all addrs request, skip operational attributes */
555                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
556                                 continue;
557                         }
558
559                 } else {
560                         /* specific addrs requested */
561                         if (  oc_check_operational_attr( a->a_type ) ) {
562                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
563                                 {
564                                         continue;
565                                 }
566                         } else {
567                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
568                                 {
569                                         continue;
570                                 }
571                         }
572                 }
573
574                 acl = acl_get_applicable( be, op, e, a->a_type,
575                         MAXREMATCHES, matches );
576
577                 if ( ! acl_access_allowed( acl, a->a_type, be, conn, e,
578                         NULL, op, ACL_READ, edn, matches ) ) 
579                 {
580                         continue;
581                 }
582
583                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
584                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
585                         ber_free( ber, 1 );
586                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
587                             NULL, "encoding type error", NULL, NULL );
588                         goto error_return;
589                 }
590
591                 if ( ! attrsonly ) {
592                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
593                                 if ( a->a_syntax & SYNTAX_DN && 
594                                         ! acl_access_allowed( acl, a->a_type, be, conn, e, a->a_vals[i], op,
595                                                 ACL_READ, edn, matches) )
596                                 {
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                 regmatch_t       matches[MAXREMATCHES];
627
628                 if ( attrs == NULL ) {
629                         /* all addrs request, skip operational attributes */
630                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
631                                 continue;
632                         }
633
634                 } else {
635                         /* specific addrs requested */
636                         if (  oc_check_operational_attr( a->a_type ) ) {
637                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
638                                 {
639                                         continue;
640                                 }
641                         } else {
642                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
643                                 {
644                                         continue;
645                                 }
646                         }
647                 }
648
649                 acl = acl_get_applicable( be, op, e, a->a_type,
650                         MAXREMATCHES, matches );
651
652                 if ( ! acl_access_allowed( acl, a->a_type, be, conn, e,
653                         NULL, op, ACL_READ, edn, matches ) ) 
654                 {
655                         continue;
656                 }
657
658                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
659                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
660                         ber_free( ber, 1 );
661                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
662                             NULL, "encoding type error", NULL, NULL );
663                         goto error_return;
664                 }
665
666                 if ( ! attrsonly ) {
667                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
668                                 if ( a->a_syntax & SYNTAX_DN && 
669                                         ! acl_access_allowed( acl, a->a_type, be, conn, e, a->a_vals[i], op,
670                                                 ACL_READ, edn, matches) )
671                                 {
672                                         continue;
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 }