]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
Yet another round of SLAPD_SCHEMA_NOT_COMPAT changes, including:
[openldap] / servers / slapd / result.c
1 /* result.c - routines to send ldap results, errors, and referrals */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-1999 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         static AttributeDescription *ref = NULL;
133 #else
134         static const char *ref = "ref";
135 #endif
136
137         attr = attr_find( e->e_attrs, 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 );
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, STRERROR(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     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         static AttributeDescription *entry = NULL;
633 #else
634         static const char *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                 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_OPERATIONS_ERROR,
654                         NULL, "allocating BER 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_OPERATIONS_ERROR,
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 #else
681                 char *desc = a->a_type;
682 #endif
683
684                 if ( attrs == NULL ) {
685                         /* all addrs request, skip operational attributes */
686 #ifdef SLAPD_SCHEMA_NOT_COMPAT
687                         if( is_at_operational( desc->ad_type ) )
688 #else
689                         if( oc_check_op_attr( desc ) )
690 #endif
691                         {
692                                 continue;
693                         }
694
695                 } else {
696                         /* specific addrs requested */
697 #ifdef SLAPD_SCHEMA_NOT_COMPAT
698                         if ( is_at_operational( desc->ad_type ) )
699 #else
700                         if ( oc_check_op_attr( desc ) )
701 #endif
702                         {
703                                 if( !opattrs && !ad_inlist( desc, attrs ) ) {
704                                         continue;
705                                 }
706                         } else {
707                                 if (!userattrs && !ad_inlist( desc, attrs ) ) {
708                                         continue;
709                                 }
710                         }
711                 }
712
713                 if ( ! access_allowed( be, conn, op, e, desc, NULL, ACL_READ ) ) {
714                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
715                             desc, 0, 0 );
716                         continue;
717                 }
718
719                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , desc )) == -1 ) {
720                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
721                         ber_free( ber, 1 );
722                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
723                             NULL, "encoding type error", NULL, NULL );
724                         goto error_return;
725                 }
726
727                 if ( ! attrsonly ) {
728                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
729                                 if ( ! access_allowed( be, conn, op, e,
730                                         desc, a->a_vals[i], ACL_READ ) )
731                                 {
732                                         Debug( LDAP_DEBUG_ACL,
733                                                 "acl: access to attribute %s, value %d not allowed\n",
734                                         desc, i, 0 );
735                                         continue;
736                                 }
737
738                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
739                                         Debug( LDAP_DEBUG_ANY,
740                                             "ber_printf failed\n", 0, 0, 0 );
741                                         ber_free( ber, 1 );
742                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
743                                                 NULL, "encoding value error", NULL, NULL );
744                                         goto error_return;
745                                 }
746                         }
747                 }
748
749                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
750                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
751                         ber_free( ber, 1 );
752                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
753                             NULL, "encode end error", NULL, NULL );
754                         goto error_return;
755                 }
756         }
757
758         /* eventually will loop through generated operational attributes */
759         /* only have subschemaSubentry implemented */
760         aa = backend_operational( be, e );
761         
762         for (a = aa ; a == NULL; a = a->a_next ) {
763 #ifdef SLAPD_SCHEMA_NOT_COMPAT
764                 AttributeDescription *desc = a->a_desc;
765 #else
766                 char *desc = a->a_type;
767 #endif
768
769                 if ( attrs == NULL ) {
770                         /* all addrs request, skip operational attributes */
771 #ifdef SLAPD_SCHEMA_NOT_COMPAT
772                         if( is_at_operational( desc->ad_type ) )
773 #else
774                         if( oc_check_op_attr( desc ) )
775 #endif
776                         {
777                                 continue;
778                         }
779
780                 } else {
781                         /* specific addrs requested */
782 #ifdef SLAPD_SCHEMA_NOT_COMPAT
783                         if( is_at_operational( desc->ad_type ) )
784 #else
785                         if( oc_check_op_attr( desc ) )
786 #endif
787                         {
788                                 if( !opattrs && !ad_inlist( desc, attrs ) )
789                                 {
790                                         continue;
791                                 }
792                         } else {
793                                 if (!userattrs && !ad_inlist( desc, attrs ) )
794                                 {
795                                         continue;
796                                 }
797                         }
798                 }
799
800                 if ( ! access_allowed( be, conn, op, e, desc, NULL, ACL_READ ) ) {
801                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
802                             desc, 0, 0 );
803                         continue;
804                 }
805
806                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , desc )) == -1 ) {
807                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
808                         ber_free( ber, 1 );
809                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
810                             NULL, "encoding type error", NULL, NULL );
811                         goto error_return;
812                 }
813
814                 if ( ! attrsonly ) {
815                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
816                                 if ( ! access_allowed( be, conn, op, e,
817                                         desc, a->a_vals[i], ACL_READ ) )
818                                 {
819                                         Debug( LDAP_DEBUG_ACL,
820                                                 "acl: access to attribute %s, value %d not allowed\n",
821                                         desc, i, 0 );
822                                         continue;
823                                 }
824
825
826                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
827                                         Debug( LDAP_DEBUG_ANY,
828                                             "ber_printf failed\n", 0, 0, 0 );
829                                         ber_free( ber, 1 );
830                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
831                                                 NULL, "encoding value error", NULL, NULL );
832                                         goto error_return;
833                                 }
834                         }
835                 }
836
837                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
838                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
839                         ber_free( ber, 1 );
840                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
841                             NULL, "encode end error", NULL, NULL );
842                         goto error_return;
843                 }
844         }
845
846         attrs_free( aa );
847
848         rc = ber_printf( ber, /*{{{*/ "}}}" );
849
850         if ( rc == -1 ) {
851                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
852                 ber_free( ber, 1 );
853                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
854                         NULL, "encode entry end error", NULL, NULL );
855                 return( 1 );
856         }
857
858         bytes = send_ldap_ber( conn, ber );
859         ber_free( ber, 1 );
860
861         if ( bytes < 0 ) {
862                 Debug( LDAP_DEBUG_ANY,
863                         "send_ldap_response: ber write failed\n",
864                         0, 0, 0 );
865                 return -1;
866         }
867
868         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
869         num_bytes_sent += bytes;
870         num_entries_sent++;
871         num_pdu_sent++;
872         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
873
874         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
875             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
876
877         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
878
879         rc = 0;
880
881 error_return:;
882         return( rc );
883 }
884
885 int
886 send_search_reference(
887     Backend     *be,
888     Connection  *conn,
889     Operation   *op,
890     Entry       *e,
891         struct berval **refs,
892         int scope,
893         LDAPControl **ctrls,
894     struct berval ***v2refs
895 )
896 {
897         BerElement      *ber;
898         int rc;
899         int bytes;
900
901 #ifdef SLAPD_SCHEMA_NOT_COMPAT
902         static AttributeDescription *ref = NULL;
903         static AttributeDescription *entry = NULL;
904 #else
905         static const char *ref = "ref";
906         static const char *entry = "entry";
907 #endif
908
909         Debug( LDAP_DEBUG_TRACE, "=> send_search_reference (%s)\n", e->e_dn, 0, 0 );
910
911         if ( ! access_allowed( be, conn, op, e,
912                 entry, NULL, ACL_READ ) )
913         {
914                 Debug( LDAP_DEBUG_ACL,
915                         "send_search_reference: access to entry not allowed\n",
916                     0, 0, 0 );
917                 return( 1 );
918         }
919
920         if ( ! access_allowed( be, conn, op, e,
921                 ref, NULL, ACL_READ ) )
922         {
923                 Debug( LDAP_DEBUG_ACL,
924                         "send_search_reference: access to reference not allowed\n",
925                     0, 0, 0 );
926                 return( 1 );
927         }
928
929         if( refs == NULL ) {
930                 Debug( LDAP_DEBUG_ANY,
931                         "send_search_reference: null ref in (%s)\n", 
932                         e->e_dn, 0, 0 );
933                 return( 1 );
934         }
935
936         if( op->o_protocol < LDAP_VERSION3 ) {
937                 /* save the references for the result */
938                 if( *refs != NULL ) {
939                         value_add( v2refs, refs );
940                 }
941                 return 0;
942         }
943
944         ber = ber_alloc_t( LBER_USE_DER );
945
946         if ( ber == NULL ) {
947                 Debug( LDAP_DEBUG_ANY,
948                         "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
949                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
950                         NULL, "alloc BER error", NULL, NULL );
951                 return -1;
952         }
953
954         rc = ber_printf( ber, "{it{V}}", op->o_msgid,
955                 LDAP_RES_SEARCH_REFERENCE, refs );
956
957         if ( rc == -1 ) {
958                 Debug( LDAP_DEBUG_ANY,
959                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
960                 ber_free( ber, 1 );
961                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
962                         NULL, "encode dn error", NULL, NULL );
963                 return -1;
964         }
965
966         bytes = send_ldap_ber( conn, ber );
967         ber_free( ber, 1 );
968
969         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
970         num_bytes_sent += bytes;
971         num_refs_sent++;
972         num_pdu_sent++;
973         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
974
975         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
976             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
977
978         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
979
980         return 0;
981 }
982
983
984 int
985 str2result(
986     char        *s,
987     int         *code,
988     char        **matched,
989     char        **info
990 )
991 {
992         int     rc;
993         char    *c;
994
995         *code = LDAP_SUCCESS;
996         *matched = NULL;
997         *info = NULL;
998
999         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
1000                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
1001                     s, 0, 0 );
1002
1003                 return( -1 );
1004         }
1005
1006         rc = 0;
1007         while ( (s = strchr( s, '\n' )) != NULL ) {
1008                 *s++ = '\0';
1009                 if ( *s == '\0' ) {
1010                         break;
1011                 }
1012                 if ( (c = strchr( s, ':' )) != NULL ) {
1013                         c++;
1014                 }
1015
1016                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
1017                         if ( c != NULL ) {
1018                                 *code = atoi( c );
1019                         }
1020                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
1021                         if ( c != NULL ) {
1022                                 *matched = c;
1023                         }
1024                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
1025                         if ( c != NULL ) {
1026                                 *info = c;
1027                         }
1028                 } else {
1029                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
1030                             s, 0, 0 );
1031                         rc = -1;
1032                 }
1033         }
1034
1035         return( rc );
1036 }