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