]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
c328690a284528f0893048e31a03a9da149faf01
[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, "t{V}",
291                                 LDAP_TAG_REFERRAL, ref );
292                 }
293
294                 if( rc != -1 && sasldata != NULL ) {
295                         rc = ber_printf( ber, "tO",
296                                 LDAP_TAG_SASL_RES_CREDS, sasldata );
297                 }
298
299                 if( rc != -1 && resoid != NULL ) {
300                         rc = ber_printf( ber, "ts",
301                                 LDAP_TAG_EXOP_RES_OID, resoid );
302                 }
303
304                 if( rc != -1 && resdata != NULL ) {
305                         rc = ber_printf( ber, "tO",
306                                 LDAP_TAG_EXOP_RES_VALUE, resdata );
307                 }
308
309                 if( rc != -1 ) {
310                         rc = ber_printf( ber, "}}" );
311                 }
312         }
313
314         if ( rc == -1 ) {
315                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
316                 ber_free( ber, 1 );
317                 return;
318         }
319
320         /* send BER */
321         bytes = send_ldap_ber( conn, ber );
322         ber_free( ber, 1 );
323
324         if ( bytes < 0 ) {
325                 Debug( LDAP_DEBUG_ANY,
326                         "send_ldap_response: ber write failed\n",
327                         0, 0, 0 );
328                 return;
329         }
330
331         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
332         num_bytes_sent += bytes;
333         num_pdu_sent++;
334         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
335         return;
336 }
337
338
339 void
340 send_ldap_disconnect(
341     Connection  *conn,
342     Operation   *op,
343     ber_int_t   err,
344     const char  *text
345 )
346 {
347         ber_tag_t tag;
348         ber_int_t msgid;
349         char *reqoid;
350
351 #define LDAP_UNSOLICITED_ERROR(e) \
352         (  (e) == LDAP_PROTOCOL_ERROR \
353         || (e) == LDAP_STRONG_AUTH_REQUIRED \
354         || (e) == LDAP_UNAVAILABLE )
355
356         assert( LDAP_UNSOLICITED_ERROR( err ) );
357
358         Debug( LDAP_DEBUG_TRACE,
359                 "send_ldap_disconnect %d:%s\n",
360                 err, text ? text : "", NULL );
361
362         if ( op->o_protocol < LDAP_VERSION3 ) {
363                 reqoid = NULL;
364                 tag = req2res( op->o_tag );
365                 msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
366
367         } else {
368                 reqoid = LDAP_NOTICE_DISCONNECT;
369                 tag = LDAP_RES_EXTENDED;
370                 msgid = 0;
371         }
372
373 #ifdef LDAP_CONNECTIONLESS
374         if ( op->o_cldap ) {
375                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
376                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
377                     inet_ntoa(((struct sockaddr_in *)
378                     &op->o_clientaddr)->sin_addr ),
379                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
380                     0 );
381         }
382 #endif
383
384         send_ldap_response( conn, op, tag, msgid,
385                 err, NULL, text, NULL,
386                 reqoid, NULL, NULL, NULL );
387
388         Statslog( LDAP_DEBUG_STATS,
389             "conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n",
390                 (long) op->o_connid, (long) op->o_opid,
391                 (long) tag, (long) err, text ? text : "" );
392 }
393
394 void
395 send_ldap_result(
396     Connection  *conn,
397     Operation   *op,
398     ber_int_t   err,
399     const char  *matched,
400     const char  *text,
401         struct berval **ref,
402         LDAPControl **ctrls
403 )
404 {
405         ber_tag_t tag;
406         ber_int_t msgid;
407         char *tmp = NULL;
408
409         assert( !LDAP_API_ERROR( err ) );
410
411         Debug( LDAP_DEBUG_TRACE, "send_ldap_result: conn=%ld op=%ld p=%d\n",
412                 (long) op->o_connid, (long) op->o_opid, op->o_protocol );
413         Debug( LDAP_DEBUG_ARGS, "send_ldap_result: %d:%s:%s\n",
414                 err, matched ?  matched : "", text ? text : "" );
415
416         assert( err != LDAP_PARTIAL_RESULTS );
417
418         if( op->o_tag != LDAP_REQ_SEARCH ) {
419                 trim_refs_urls( ref );
420         }
421
422         if ( err == LDAP_REFERRAL ) {
423                 if( ref == NULL ) {
424                         err = LDAP_NO_SUCH_OBJECT;
425                 } else if ( op->o_protocol < LDAP_VERSION3 ) {
426                         err = LDAP_PARTIAL_RESULTS;
427                 }
428         }
429
430         if ( op->o_protocol < LDAP_VERSION3 ) {
431                 tmp = v2ref( ref, text );
432                 text = tmp;
433                 ref = NULL;
434         }
435
436         tag = req2res( op->o_tag );
437         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
438
439 #ifdef LDAP_CONNECTIONLESS
440         if ( op->o_cldap ) {
441                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
442                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
443                     inet_ntoa(((struct sockaddr_in *)
444                     &op->o_clientaddr)->sin_addr ),
445                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
446                     0 );
447         }
448 #endif
449
450         send_ldap_response( conn, op, tag, msgid,
451                 err, matched, text, ref,
452                 NULL, NULL, NULL, ctrls );
453
454         Statslog( LDAP_DEBUG_STATS,
455             "conn=%ld op=%ld RESULT tag=%lu err=%ld text=%s\n",
456                 (long) op->o_connid, (long) op->o_opid,
457                 (long) tag, (long) err, text ? text : "" );
458
459         if( tmp != NULL ) {
460                 ch_free(tmp);
461         }
462 }
463
464 void
465 send_ldap_sasl(
466     Connection  *conn,
467     Operation   *op,
468     ber_int_t   err,
469     const char  *matched,
470     const char  *text,
471         struct berval **ref,
472         LDAPControl **ctrls,
473         struct berval *cred
474 )
475 {
476         ber_tag_t tag;
477         ber_int_t msgid;
478
479         Debug( LDAP_DEBUG_TRACE, "send_ldap_sasl %ld\n",
480                 (long) err, NULL, NULL );
481
482         tag = req2res( op->o_tag );
483         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
484
485 #ifdef LDAP_CONNECTIONLESS
486         if ( op->o_cldap ) {
487                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
488                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
489                     inet_ntoa(((struct sockaddr_in *)
490                     &op->o_clientaddr)->sin_addr ),
491                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
492                     0 );
493         }
494 #endif
495
496         send_ldap_response( conn, op, tag, msgid,
497                 err, matched, text, ref,
498                 NULL, NULL, cred, ctrls  );
499 }
500
501 void
502 send_ldap_extended(
503     Connection  *conn,
504     Operation   *op,
505     ber_int_t   err,
506     const char  *matched,
507     const char  *text,
508     struct berval **refs,
509     const char          *rspoid,
510         struct berval *rspdata,
511         LDAPControl **ctrls
512 )
513 {
514         ber_tag_t tag;
515         ber_int_t msgid;
516
517         Debug( LDAP_DEBUG_TRACE,
518                 "send_ldap_extended %ld:%s (%ld)\n",
519                 (long) err,
520                 rspoid ? rspoid : "",
521                 rspdata != NULL ? (long) rspdata->bv_len : (long) 0 );
522
523         tag = req2res( op->o_tag );
524         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
525
526 #ifdef LDAP_CONNECTIONLESS
527         if ( op->o_cldap ) {
528                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
529                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
530                     inet_ntoa(((struct sockaddr_in *)
531                     &op->o_clientaddr)->sin_addr ),
532                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
533                     0 );
534         }
535 #endif
536
537         send_ldap_response( conn, op, tag, msgid,
538                 err, matched, text, refs,
539                 rspoid, rspdata, NULL, ctrls );
540 }
541
542
543 void
544 send_search_result(
545     Connection  *conn,
546     Operation   *op,
547     ber_int_t   err,
548     const char  *matched,
549         const char      *text,
550     struct berval **refs,
551         LDAPControl **ctrls,
552     int         nentries
553 )
554 {
555         ber_tag_t tag;
556         ber_int_t msgid;
557         char *tmp = NULL;
558         assert( !LDAP_API_ERROR( err ) );
559
560         Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
561                 err, matched ?  matched : "", text ? text : "" );
562
563         assert( err != LDAP_PARTIAL_RESULTS );
564
565         trim_refs_urls( refs );
566
567         if( op->o_protocol < LDAP_VERSION3 ) {
568                 /* send references in search results */
569                 if( err == LDAP_REFERRAL ) {
570                         err = LDAP_PARTIAL_RESULTS;
571                 }
572
573                 tmp = v2ref( refs, text );
574                 text = tmp;
575                 refs = NULL;
576         } else {
577                 /* don't send references in search results */
578                 assert( refs == NULL );
579                 refs = NULL;
580
581                 if( err == LDAP_REFERRAL ) {
582                         err = LDAP_SUCCESS;
583                 }
584         }
585
586         tag = req2res( op->o_tag );
587         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
588
589 #ifdef LDAP_CONNECTIONLESS
590         if ( op->o_cldap ) {
591                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
592                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
593                     inet_ntoa(((struct sockaddr_in *)
594                     &op->o_clientaddr)->sin_addr ),
595                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
596                     0 );
597         }
598 #endif
599
600         send_ldap_response( conn, op, tag, msgid,
601                 err, matched, text, refs,
602                 NULL, NULL, NULL, ctrls );
603
604         Statslog( LDAP_DEBUG_STATS,
605             "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
606                 (long) op->o_connid, (long) op->o_opid,
607                 (long) tag, (long) err, text ? text : "" );
608
609         if (tmp != NULL)
610             ch_free(tmp);
611 }
612
613
614 int
615 send_search_entry(
616     Backend     *be,
617     Connection  *conn,
618     Operation   *op,
619     Entry       *e,
620     char        **attrs,
621     int         attrsonly,
622         LDAPControl **ctrls
623 )
624 {
625         BerElement      *ber;
626         Attribute       *a, *aa;
627         int             i, rc=-1, bytes;
628         char            *edn;
629         int             userattrs;
630         int             opattrs;
631
632 #ifdef SLAPD_SCHEMA_NOT_COMPAT
633         AttributeDescription *ad_entry = slap_schema.si_ad_entry;
634 #else
635         static const char *ad_entry = "entry";
636 #endif
637
638         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: \"%s\"\n", e->e_dn, 0, 0 );
639
640         if ( ! access_allowed( be, conn, op, e,
641                 ad_entry, NULL, ACL_READ ) )
642         {
643                 Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
644                     0, 0, 0 );
645                 return( 1 );
646         }
647
648         edn = e->e_ndn;
649
650         ber = ber_alloc_t( LBER_USE_DER );
651
652         if ( ber == NULL ) {
653                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
654                 send_ldap_result( conn, op, LDAP_OTHER,
655                         NULL, "BER allocation error", NULL, NULL );
656                 goto error_return;
657         }
658
659         rc = ber_printf( ber, "{it{s{", op->o_msgid,
660                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
661
662         if ( rc == -1 ) {
663                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
664                 ber_free( ber, 1 );
665                 send_ldap_result( conn, op, LDAP_OTHER,
666                     NULL, "encoding DN error", NULL, NULL );
667                 goto error_return;
668         }
669
670         /* check for special all user attributes ("*") type */
671         userattrs = ( attrs == NULL ) ? 1
672                 : charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES );
673
674         /* check for special all operational attributes ("+") type */
675         opattrs = ( attrs == NULL ) ? 0
676                 : charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
677
678         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
679 #ifdef SLAPD_SCHEMA_NOT_COMPAT
680                 AttributeDescription *desc = a->a_desc;
681                 char *type = desc->ad_cname->bv_val;
682 #else
683                 char *desc = a->a_type;
684                 char *type = a->a_type;
685 #endif
686
687                 if ( attrs == NULL ) {
688                         /* all addrs request, skip operational attributes */
689 #ifdef SLAPD_SCHEMA_NOT_COMPAT
690                         if( is_at_operational( desc->ad_type ) )
691 #else
692                         if( oc_check_op_attr( desc ) )
693 #endif
694                         {
695                                 continue;
696                         }
697
698                 } else {
699                         /* specific addrs requested */
700 #ifdef SLAPD_SCHEMA_NOT_COMPAT
701                         if ( is_at_operational( desc->ad_type ) )
702 #else
703                         if ( oc_check_op_attr( desc ) )
704 #endif
705                         {
706                                 if( !opattrs && !ad_inlist( desc, attrs ) ) {
707                                         continue;
708                                 }
709                         } else {
710                                 if (!userattrs && !ad_inlist( desc, attrs ) ) {
711                                         continue;
712                                 }
713                         }
714                 }
715
716                 if ( ! access_allowed( be, conn, op, e, desc, NULL, ACL_READ ) ) {
717                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
718                             desc, 0, 0 );
719                         continue;
720                 }
721
722                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , type )) == -1 ) {
723                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
724                         ber_free( ber, 1 );
725                         send_ldap_result( conn, op, LDAP_OTHER,
726                             NULL, "encoding description error", NULL, NULL );
727                         goto error_return;
728                 }
729
730                 if ( ! attrsonly ) {
731                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
732                                 if ( ! access_allowed( be, conn, op, e,
733                                         desc, a->a_vals[i], ACL_READ ) )
734                                 {
735                                         Debug( LDAP_DEBUG_ACL,
736                                                 "acl: access to attribute %s, value %d not allowed\n",
737                                         desc, i, 0 );
738                                         continue;
739                                 }
740
741                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
742                                         Debug( LDAP_DEBUG_ANY,
743                                             "ber_printf failed\n", 0, 0, 0 );
744                                         ber_free( ber, 1 );
745                                         send_ldap_result( conn, op, LDAP_OTHER,
746                                                 NULL, "encoding values error", NULL, NULL );
747                                         goto error_return;
748                                 }
749                         }
750                 }
751
752                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
753                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
754                         ber_free( ber, 1 );
755                         send_ldap_result( conn, op, LDAP_OTHER,
756                             NULL, "encode end error", NULL, NULL );
757                         goto error_return;
758                 }
759         }
760
761         /* eventually will loop through generated operational attributes */
762         /* only have subschemaSubentry implemented */
763         aa = backend_operational( be, e );
764         
765         for (a = aa ; a == NULL; a = a->a_next ) {
766 #ifdef SLAPD_SCHEMA_NOT_COMPAT
767                 AttributeDescription *desc = a->a_desc;
768 #else
769                 char *desc = a->a_type;
770 #endif
771
772                 if ( attrs == NULL ) {
773                         /* all addrs request, skip operational attributes */
774 #ifdef SLAPD_SCHEMA_NOT_COMPAT
775                         if( is_at_operational( desc->ad_type ) )
776 #else
777                         if( oc_check_op_attr( desc ) )
778 #endif
779                         {
780                                 continue;
781                         }
782
783                 } else {
784                         /* specific addrs requested */
785 #ifdef SLAPD_SCHEMA_NOT_COMPAT
786                         if( is_at_operational( desc->ad_type ) )
787 #else
788                         if( oc_check_op_attr( desc ) )
789 #endif
790                         {
791                                 if( !opattrs && !ad_inlist( desc, attrs ) )
792                                 {
793                                         continue;
794                                 }
795                         } else {
796                                 if (!userattrs && !ad_inlist( desc, attrs ) )
797                                 {
798                                         continue;
799                                 }
800                         }
801                 }
802
803                 if ( ! access_allowed( be, conn, op, e, desc, NULL, ACL_READ ) ) {
804                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
805                             desc, 0, 0 );
806                         continue;
807                 }
808
809                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , desc )) == -1 ) {
810                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
811                         ber_free( ber, 1 );
812                         send_ldap_result( conn, op, LDAP_OTHER,
813                             NULL, "encoding description error", NULL, NULL );
814                         goto error_return;
815                 }
816
817                 if ( ! attrsonly ) {
818                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
819                                 if ( ! access_allowed( be, conn, op, e,
820                                         desc, a->a_vals[i], ACL_READ ) )
821                                 {
822                                         Debug( LDAP_DEBUG_ACL,
823                                                 "acl: access to attribute %s, value %d not allowed\n",
824                                         desc, i, 0 );
825                                         continue;
826                                 }
827
828
829                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
830                                         Debug( LDAP_DEBUG_ANY,
831                                             "ber_printf failed\n", 0, 0, 0 );
832                                         ber_free( ber, 1 );
833                                         send_ldap_result( conn, op, LDAP_OTHER,
834                                                 NULL, "encoding values error", NULL, NULL );
835                                         goto error_return;
836                                 }
837                         }
838                 }
839
840                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
841                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
842                         ber_free( ber, 1 );
843                         send_ldap_result( conn, op, LDAP_OTHER,
844                             NULL, "encode end error", NULL, NULL );
845                         goto error_return;
846                 }
847         }
848
849         attrs_free( aa );
850
851         rc = ber_printf( ber, /*{{{*/ "}}}" );
852
853         if ( rc == -1 ) {
854                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
855                 ber_free( ber, 1 );
856                 send_ldap_result( conn, op, LDAP_OTHER,
857                         NULL, "encode entry end error", NULL, NULL );
858                 return( 1 );
859         }
860
861         bytes = send_ldap_ber( conn, ber );
862         ber_free( ber, 1 );
863
864         if ( bytes < 0 ) {
865                 Debug( LDAP_DEBUG_ANY,
866                         "send_ldap_response: ber write failed\n",
867                         0, 0, 0 );
868                 return -1;
869         }
870
871         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
872         num_bytes_sent += bytes;
873         num_entries_sent++;
874         num_pdu_sent++;
875         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
876
877         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
878             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
879
880         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
881
882         rc = 0;
883
884 error_return:;
885         return( rc );
886 }
887
888 int
889 send_search_reference(
890     Backend     *be,
891     Connection  *conn,
892     Operation   *op,
893     Entry       *e,
894         struct berval **refs,
895         int scope,
896         LDAPControl **ctrls,
897     struct berval ***v2refs
898 )
899 {
900         BerElement      *ber;
901         int rc;
902         int bytes;
903
904 #ifdef SLAPD_SCHEMA_NOT_COMPAT
905         AttributeDescription *ad_ref = slap_schema.si_ad_ref;
906         AttributeDescription *ad_entry = slap_schema.si_ad_entry;
907 #else
908         static const char *ad_ref = "ref";
909         static const char *ad_entry = "entry";
910 #endif
911
912         Debug( LDAP_DEBUG_TRACE, "=> send_search_reference (%s)\n", e->e_dn, 0, 0 );
913
914         if ( ! access_allowed( be, conn, op, e,
915                 ad_entry, NULL, ACL_READ ) )
916         {
917                 Debug( LDAP_DEBUG_ACL,
918                         "send_search_reference: access to entry not allowed\n",
919                     0, 0, 0 );
920                 return( 1 );
921         }
922
923         if ( ! access_allowed( be, conn, op, e,
924                 ad_ref, NULL, ACL_READ ) )
925         {
926                 Debug( LDAP_DEBUG_ACL,
927                         "send_search_reference: access to reference not allowed\n",
928                     0, 0, 0 );
929                 return( 1 );
930         }
931
932         if( refs == NULL ) {
933                 Debug( LDAP_DEBUG_ANY,
934                         "send_search_reference: null ref in (%s)\n", 
935                         e->e_dn, 0, 0 );
936                 return( 1 );
937         }
938
939         if( op->o_protocol < LDAP_VERSION3 ) {
940                 /* save the references for the result */
941                 if( *refs != NULL ) {
942                         value_add( v2refs, refs );
943                 }
944                 return 0;
945         }
946
947         ber = ber_alloc_t( LBER_USE_DER );
948
949         if ( ber == NULL ) {
950                 Debug( LDAP_DEBUG_ANY,
951                         "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
952                 send_ldap_result( conn, op, LDAP_OTHER,
953                         NULL, "alloc BER error", NULL, NULL );
954                 return -1;
955         }
956
957         rc = ber_printf( ber, "{it{V}}", op->o_msgid,
958                 LDAP_RES_SEARCH_REFERENCE, refs );
959
960         if ( rc == -1 ) {
961                 Debug( LDAP_DEBUG_ANY,
962                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
963                 ber_free( ber, 1 );
964                 send_ldap_result( conn, op, LDAP_OTHER,
965                         NULL, "encode DN error", NULL, NULL );
966                 return -1;
967         }
968
969         bytes = send_ldap_ber( conn, ber );
970         ber_free( ber, 1 );
971
972         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
973         num_bytes_sent += bytes;
974         num_refs_sent++;
975         num_pdu_sent++;
976         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
977
978         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
979             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
980
981         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
982
983         return 0;
984 }
985
986
987 int
988 str2result(
989     char        *s,
990     int         *code,
991     char        **matched,
992     char        **info
993 )
994 {
995         int     rc;
996         char    *c;
997
998         *code = LDAP_SUCCESS;
999         *matched = NULL;
1000         *info = NULL;
1001
1002         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
1003                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
1004                     s, 0, 0 );
1005
1006                 return( -1 );
1007         }
1008
1009         rc = 0;
1010         while ( (s = strchr( s, '\n' )) != NULL ) {
1011                 *s++ = '\0';
1012                 if ( *s == '\0' ) {
1013                         break;
1014                 }
1015                 if ( (c = strchr( s, ':' )) != NULL ) {
1016                         c++;
1017                 }
1018
1019                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
1020                         if ( c != NULL ) {
1021                                 *code = atoi( c );
1022                         }
1023                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
1024                         if ( c != NULL ) {
1025                                 *matched = c;
1026                         }
1027                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
1028                         if ( c != NULL ) {
1029                                 *info = c;
1030                         }
1031                 } else {
1032                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
1033                             s, 0, 0 );
1034                         rc = -1;
1035                 }
1036         }
1037
1038         return( rc );
1039 }