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