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