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