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