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