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