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