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