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