]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
ACIs from Mark Valence <kurash@sassafras.com> (ITS#261)
[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 reason=\"%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     const char  *matched,
221     const char  *text,
222         struct berval   **ref,
223         const 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     const 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 ? text : "" );
349 }
350
351 void
352 send_ldap_result(
353     Connection  *conn,
354     Operation   *op,
355     ber_int_t   err,
356     const char  *matched,
357     const 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 = v2ref( ref );
385                         text = tmp;
386                         ref = NULL;
387                 }
388         }
389
390         tag = req2res( op->o_tag );
391         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
392
393 #ifdef LDAP_CONNECTIONLESS
394         if ( op->o_cldap ) {
395                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
396                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
397                     inet_ntoa(((struct sockaddr_in *)
398                     &op->o_clientaddr)->sin_addr ),
399                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
400                     0 );
401         }
402 #endif
403
404         send_ldap_response( conn, op, tag, msgid,
405                 err, matched, text, ref,
406                 NULL, NULL, ctrls );
407
408         Statslog( LDAP_DEBUG_STATS,
409             "conn=%ld op=%ld RESULT tag=%lu err=%ld text=%s\n",
410                 (long) op->o_connid, (long) op->o_opid,
411                 (long) tag, (long) err, text ? text : "" );
412
413         if( tmp != NULL ) {
414                 free(tmp);
415         }
416 }
417
418
419 void
420 send_search_result(
421     Connection  *conn,
422     Operation   *op,
423     ber_int_t   err,
424     const char  *matched,
425         const char      *text,
426     struct berval **refs,
427         LDAPControl **ctrls,
428     int         nentries
429 )
430 {
431         ber_tag_t tag;
432         ber_int_t msgid;
433         char *tmp = NULL;
434         assert( !LDAP_API_ERROR( err ) );
435
436         Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
437                 err, matched ?  matched : "", text ? text : "" );
438
439         assert( err != LDAP_PARTIAL_RESULTS );
440
441         trim_refs_urls( refs );
442
443         if( op->o_protocol < LDAP_VERSION3 ) {
444                 /* send references in search results */
445                 if( err == LDAP_REFERRAL ) {
446                         err = LDAP_PARTIAL_RESULTS;
447                 }
448
449                 tmp = v2ref( refs );
450                 text = tmp;
451                 refs = NULL;
452
453         } else {
454                 /* don't send references in search results */
455                 assert( refs == NULL );
456                 refs = NULL;
457
458                 if( err == LDAP_REFERRAL ) {
459                         err = LDAP_SUCCESS;
460                 }
461         }
462
463         tag = req2res( op->o_tag );
464         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
465
466 #ifdef LDAP_CONNECTIONLESS
467         if ( op->o_cldap ) {
468                 ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
469                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
470                     inet_ntoa(((struct sockaddr_in *)
471                     &op->o_clientaddr)->sin_addr ),
472                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
473                     0 );
474         }
475 #endif
476
477         send_ldap_response( conn, op, tag, msgid,
478                 err, matched, text, refs,
479                 NULL, NULL, ctrls );
480
481         Statslog( LDAP_DEBUG_STATS,
482             "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
483                 (long) op->o_connid, (long) op->o_opid,
484                 (long) tag, (long) err, text ? text : "" );
485
486 }
487
488
489 int
490 send_search_entry(
491     Backend     *be,
492     Connection  *conn,
493     Operation   *op,
494     Entry       *e,
495     char        **attrs,
496     int         attrsonly,
497         LDAPControl **ctrls
498 )
499 {
500         BerElement      *ber;
501         Attribute       *a;
502         int             i, rc=-1, bytes;
503         AccessControl   *acl;
504         char            *edn;
505         int             userattrs;
506         int             opattrs;
507
508         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: \"%s\"\n", e->e_dn, 0, 0 );
509
510         if ( ! access_allowed( be, conn, op, e,
511                 "entry", NULL, ACL_READ ) )
512         {
513                 Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
514                     0, 0, 0 );
515                 return( 1 );
516         }
517
518         edn = e->e_ndn;
519
520         ber = ber_alloc_t( LBER_USE_DER );
521
522         if ( ber == NULL ) {
523                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
524                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
525                         NULL, "allocating BER error", NULL, NULL );
526                 goto error_return;
527         }
528
529         rc = ber_printf( ber, "{it{s{", op->o_msgid,
530                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
531
532         if ( rc == -1 ) {
533                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
534                 ber_free( ber, 1 );
535                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
536                     NULL, "encoding dn error", NULL, NULL );
537                 goto error_return;
538         }
539
540         /* check for special all user attributes ("*") type */
541         userattrs = ( attrs == NULL ) ? 1
542                 : charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES );
543
544         /* check for special all operational attributes ("+") type */
545         opattrs = ( attrs == NULL ) ? 0
546                 : charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
547
548         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
549                 regmatch_t       matches[MAXREMATCHES];
550
551                 if ( attrs == NULL ) {
552                         /* all addrs request, skip operational attributes */
553                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
554                                 continue;
555                         }
556
557                 } else {
558                         /* specific addrs requested */
559                         if (  oc_check_operational_attr( a->a_type ) ) {
560                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
561                                 {
562                                         continue;
563                                 }
564                         } else {
565                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
566                                 {
567                                         continue;
568                                 }
569                         }
570                 }
571
572                 acl = acl_get_applicable( be, op, e, a->a_type,
573                         MAXREMATCHES, matches );
574
575                 if ( ! acl_access_allowed( acl, a->a_type, be, conn, e,
576                         NULL, op, ACL_READ, edn, matches ) ) 
577                 {
578                         continue;
579                 }
580
581                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
582                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
583                         ber_free( ber, 1 );
584                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
585                             NULL, "encoding type error", NULL, NULL );
586                         goto error_return;
587                 }
588
589                 if ( ! attrsonly ) {
590                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
591                                 if ( a->a_syntax & SYNTAX_DN && 
592                                         ! acl_access_allowed( acl, a->a_type, be, conn, e, a->a_vals[i], op,
593                                                 ACL_READ, edn, matches) )
594                                 {
595                                         continue;
596                                 }
597
598                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
599                                         Debug( LDAP_DEBUG_ANY,
600                                             "ber_printf failed\n", 0, 0, 0 );
601                                         ber_free( ber, 1 );
602                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
603                                                 NULL, "encoding value error", NULL, NULL );
604                                         goto error_return;
605                                 }
606                         }
607                 }
608
609                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
610                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
611                         ber_free( ber, 1 );
612                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
613                             NULL, "encode end error", NULL, NULL );
614                         goto error_return;
615                 }
616         }
617
618 #ifdef SLAPD_SCHEMA_DN
619         /* eventually will loop through generated operational attributes */
620         /* only have subschemaSubentry implemented */
621         a = backend_subschemasubentry( be );
622         
623         do {
624                 regmatch_t       matches[MAXREMATCHES];
625
626                 if ( attrs == NULL ) {
627                         /* all addrs request, skip operational attributes */
628                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
629                                 continue;
630                         }
631
632                 } else {
633                         /* specific addrs requested */
634                         if (  oc_check_operational_attr( a->a_type ) ) {
635                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
636                                 {
637                                         continue;
638                                 }
639                         } else {
640                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
641                                 {
642                                         continue;
643                                 }
644                         }
645                 }
646
647                 acl = acl_get_applicable( be, op, e, a->a_type,
648                         MAXREMATCHES, matches );
649
650                 if ( ! acl_access_allowed( acl, a->a_type, be, conn, e,
651                         NULL, op, ACL_READ, edn, matches ) ) 
652                 {
653                         continue;
654                 }
655
656                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
657                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
658                         ber_free( ber, 1 );
659                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
660                             NULL, "encoding type error", NULL, NULL );
661                         goto error_return;
662                 }
663
664                 if ( ! attrsonly ) {
665                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
666                                 if ( a->a_syntax & SYNTAX_DN && 
667                                         ! acl_access_allowed( acl, a->a_type, be, conn, e, a->a_vals[i], op,
668                                                 ACL_READ, edn, matches) )
669                                 {
670                                         continue;
671                                 }
672
673                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
674                                         Debug( LDAP_DEBUG_ANY,
675                                             "ber_printf failed\n", 0, 0, 0 );
676                                         ber_free( ber, 1 );
677                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
678                                                 NULL, "encoding value error", NULL, NULL );
679                                         goto error_return;
680                                 }
681                         }
682                 }
683
684                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
685                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
686                         ber_free( ber, 1 );
687                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
688                             NULL, "encode end error", NULL, NULL );
689                         goto error_return;
690                 }
691         } while (0);
692 #endif
693
694         rc = ber_printf( ber, /*{{{*/ "}}}" );
695
696         if ( rc == -1 ) {
697                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
698                 ber_free( ber, 1 );
699                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
700                         NULL, "encode entry end error", NULL, NULL );
701                 return( 1 );
702         }
703
704         bytes = send_ldap_ber( conn, ber );
705
706         if ( bytes < 0 ) {
707                 Debug( LDAP_DEBUG_ANY,
708                         "send_ldap_response: ber write failed\n",
709                         0, 0, 0 );
710                 return -1;
711         }
712
713         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
714         num_bytes_sent += bytes;
715         num_entries_sent++;
716         num_pdu_sent++;
717         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
718
719         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
720             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
721
722         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
723
724         rc = 0;
725
726 error_return:;
727         return( rc );
728 }
729
730 int
731 send_search_reference(
732     Backend     *be,
733     Connection  *conn,
734     Operation   *op,
735     Entry       *e,
736         struct berval **refs,
737         int scope,
738         LDAPControl **ctrls,
739     struct berval ***v2refs
740 )
741 {
742         BerElement      *ber;
743         int rc;
744         int bytes;
745
746         Debug( LDAP_DEBUG_TRACE, "=> send_search_reference (%s)\n", e->e_dn, 0, 0 );
747
748         if ( ! access_allowed( be, conn, op, e,
749                 "entry", NULL, ACL_READ ) )
750         {
751                 Debug( LDAP_DEBUG_ACL,
752                         "send_search_reference: access to entry not allowed\n",
753                     0, 0, 0 );
754                 return( 1 );
755         }
756
757         if ( ! access_allowed( be, conn, op, e,
758                 "ref", NULL, ACL_READ ) )
759         {
760                 Debug( LDAP_DEBUG_ACL,
761                         "send_search_reference: access to reference not allowed\n",
762                     0, 0, 0 );
763                 return( 1 );
764         }
765
766         if( refs == NULL ) {
767                 Debug( LDAP_DEBUG_ANY,
768                         "send_search_reference: null ref in (%s)\n", 
769                         e->e_dn, 0, 0 );
770                 return( 1 );
771         }
772
773         if( op->o_protocol < LDAP_VERSION3 ) {
774                 /* save the references for the result */
775                 if( *refs == NULL ) {
776                         value_add( v2refs, refs );
777                 }
778                 return 0;
779         }
780
781         ber = ber_alloc_t( LBER_USE_DER );
782
783         if ( ber == NULL ) {
784                 Debug( LDAP_DEBUG_ANY,
785                         "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
786                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
787                         NULL, "alloc BER error", NULL, NULL );
788                 return -1;
789         }
790
791         rc = ber_printf( ber, "{it{V}}", op->o_msgid,
792                 LDAP_RES_SEARCH_REFERENCE, refs );
793
794         if ( rc == -1 ) {
795                 Debug( LDAP_DEBUG_ANY,
796                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
797                 ber_free( ber, 1 );
798                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
799                         NULL, "encode dn error", NULL, NULL );
800                 return -1;
801         }
802
803         bytes = send_ldap_ber( conn, ber );
804
805         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
806         num_bytes_sent += bytes;
807         num_refs_sent++;
808         num_pdu_sent++;
809         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
810
811         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
812             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
813
814         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
815
816         return 0;
817 }
818
819
820 int
821 str2result(
822     char        *s,
823     int         *code,
824     char        **matched,
825     char        **info
826 )
827 {
828         int     rc;
829         char    *c;
830
831         *code = LDAP_SUCCESS;
832         *matched = NULL;
833         *info = NULL;
834
835         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
836                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
837                     s, 0, 0 );
838
839                 return( -1 );
840         }
841
842         rc = 0;
843         while ( (s = strchr( s, '\n' )) != NULL ) {
844                 *s++ = '\0';
845                 if ( *s == '\0' ) {
846                         break;
847                 }
848                 if ( (c = strchr( s, ':' )) != NULL ) {
849                         c++;
850                 }
851
852                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
853                         if ( c != NULL ) {
854                                 *code = atoi( c );
855                         }
856                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
857                         if ( c != NULL ) {
858                                 *matched = c;
859                         }
860                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
861                         if ( c != NULL ) {
862                                 *info = c;
863                         }
864                 } else {
865                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
866                             s, 0, 0 );
867                         rc = -1;
868                 }
869         }
870
871         return( rc );
872 }