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