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