]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
Per ITS#419, don't require SLAPD_RLOOKUPS when HAVE_TCPD
[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;
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                 if ( attrs == NULL ) {
663                         /* all addrs request, skip operational attributes */
664                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
665                                 continue;
666                         }
667
668                 } else {
669                         /* specific addrs requested */
670                         if (  oc_check_operational_attr( a->a_type ) ) {
671                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
672                                 {
673                                         continue;
674                                 }
675                         } else {
676                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
677                                 {
678                                         continue;
679                                 }
680                         }
681                 }
682
683                 if ( ! access_allowed( be, conn, op, e,
684                         a->a_type, NULL, ACL_READ ) )
685                 {
686                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
687                             a->a_type, 0, 0 );
688                         continue;
689                 }
690
691                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
692                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
693                         ber_free( ber, 1 );
694                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
695                             NULL, "encoding type error", NULL, NULL );
696                         goto error_return;
697                 }
698
699                 if ( ! attrsonly ) {
700                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
701                                 if ( ! access_allowed( be, conn, op, e,
702                                         a->a_type, a->a_vals[i], ACL_READ ) )
703                                 {
704                                         Debug( LDAP_DEBUG_ACL,
705                                                 "acl: access to attribute %s, value %d not allowed\n",
706                                         a->a_type, i, 0 );
707                                         continue;
708                                 }
709
710                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
711                                         Debug( LDAP_DEBUG_ANY,
712                                             "ber_printf failed\n", 0, 0, 0 );
713                                         ber_free( ber, 1 );
714                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
715                                                 NULL, "encoding value error", NULL, NULL );
716                                         goto error_return;
717                                 }
718                         }
719                 }
720
721                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
722                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
723                         ber_free( ber, 1 );
724                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
725                             NULL, "encode end error", NULL, NULL );
726                         goto error_return;
727                 }
728         }
729
730 #ifdef SLAPD_SCHEMA_DN
731         /* eventually will loop through generated operational attributes */
732         /* only have subschemaSubentry implemented */
733         a = backend_subschemasubentry( be );
734         
735         do {
736                 if ( attrs == NULL ) {
737                         /* all addrs request, skip operational attributes */
738                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
739                                 continue;
740                         }
741
742                 } else {
743                         /* specific addrs requested */
744                         if (  oc_check_operational_attr( a->a_type ) ) {
745                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
746                                 {
747                                         continue;
748                                 }
749                         } else {
750                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
751                                 {
752                                         continue;
753                                 }
754                         }
755                 }
756
757                 if ( ! access_allowed( be, conn, op, e,
758                         a->a_type, NULL, ACL_READ ) )
759                 {
760                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
761                             a->a_type, 0, 0 );
762                         continue;
763                 }
764
765                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
766                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
767                         ber_free( ber, 1 );
768                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
769                             NULL, "encoding type error", NULL, NULL );
770                         goto error_return;
771                 }
772
773                 if ( ! attrsonly ) {
774                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
775                                 if ( ! access_allowed( be, conn, op, e,
776                                         a->a_type, a->a_vals[i], ACL_READ ) )
777                                 {
778                                         Debug( LDAP_DEBUG_ACL,
779                                                 "acl: access to attribute %s, value %d not allowed\n",
780                                         a->a_type, i, 0 );
781                                         continue;
782                                 }
783
784
785                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
786                                         Debug( LDAP_DEBUG_ANY,
787                                             "ber_printf failed\n", 0, 0, 0 );
788                                         ber_free( ber, 1 );
789                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
790                                                 NULL, "encoding value error", NULL, NULL );
791                                         goto error_return;
792                                 }
793                         }
794                 }
795
796                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
797                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
798                         ber_free( ber, 1 );
799                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
800                             NULL, "encode end error", NULL, NULL );
801                         goto error_return;
802                 }
803         } while (0);
804 #endif
805
806         rc = ber_printf( ber, /*{{{*/ "}}}" );
807
808         if ( rc == -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 entry end error", NULL, NULL );
813                 return( 1 );
814         }
815
816         bytes = send_ldap_ber( conn, ber );
817         ber_free( ber, 1 );
818
819         if ( bytes < 0 ) {
820                 Debug( LDAP_DEBUG_ANY,
821                         "send_ldap_response: ber write failed\n",
822                         0, 0, 0 );
823                 return -1;
824         }
825
826         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
827         num_bytes_sent += bytes;
828         num_entries_sent++;
829         num_pdu_sent++;
830         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
831
832         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
833             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
834
835         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
836
837         rc = 0;
838
839 error_return:;
840         return( rc );
841 }
842
843 int
844 send_search_reference(
845     Backend     *be,
846     Connection  *conn,
847     Operation   *op,
848     Entry       *e,
849         struct berval **refs,
850         int scope,
851         LDAPControl **ctrls,
852     struct berval ***v2refs
853 )
854 {
855         BerElement      *ber;
856         int rc;
857         int bytes;
858
859         Debug( LDAP_DEBUG_TRACE, "=> send_search_reference (%s)\n", e->e_dn, 0, 0 );
860
861         if ( ! access_allowed( be, conn, op, e,
862                 "entry", NULL, ACL_READ ) )
863         {
864                 Debug( LDAP_DEBUG_ACL,
865                         "send_search_reference: access to entry not allowed\n",
866                     0, 0, 0 );
867                 return( 1 );
868         }
869
870         if ( ! access_allowed( be, conn, op, e,
871                 "ref", NULL, ACL_READ ) )
872         {
873                 Debug( LDAP_DEBUG_ACL,
874                         "send_search_reference: access to reference not allowed\n",
875                     0, 0, 0 );
876                 return( 1 );
877         }
878
879         if( refs == NULL ) {
880                 Debug( LDAP_DEBUG_ANY,
881                         "send_search_reference: null ref in (%s)\n", 
882                         e->e_dn, 0, 0 );
883                 return( 1 );
884         }
885
886         if( op->o_protocol < LDAP_VERSION3 ) {
887                 /* save the references for the result */
888                 if( *refs != NULL ) {
889                         value_add( v2refs, refs );
890                 }
891                 return 0;
892         }
893
894         ber = ber_alloc_t( LBER_USE_DER );
895
896         if ( ber == NULL ) {
897                 Debug( LDAP_DEBUG_ANY,
898                         "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
899                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
900                         NULL, "alloc BER error", NULL, NULL );
901                 return -1;
902         }
903
904         rc = ber_printf( ber, "{it{V}}", op->o_msgid,
905                 LDAP_RES_SEARCH_REFERENCE, refs );
906
907         if ( rc == -1 ) {
908                 Debug( LDAP_DEBUG_ANY,
909                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
910                 ber_free( ber, 1 );
911                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
912                         NULL, "encode dn error", NULL, NULL );
913                 return -1;
914         }
915
916         bytes = send_ldap_ber( conn, ber );
917         ber_free( ber, 1 );
918
919         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
920         num_bytes_sent += bytes;
921         num_refs_sent++;
922         num_pdu_sent++;
923         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
924
925         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
926             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
927
928         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
929
930         return 0;
931 }
932
933
934 int
935 str2result(
936     char        *s,
937     int         *code,
938     char        **matched,
939     char        **info
940 )
941 {
942         int     rc;
943         char    *c;
944
945         *code = LDAP_SUCCESS;
946         *matched = NULL;
947         *info = NULL;
948
949         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
950                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
951                     s, 0, 0 );
952
953                 return( -1 );
954         }
955
956         rc = 0;
957         while ( (s = strchr( s, '\n' )) != NULL ) {
958                 *s++ = '\0';
959                 if ( *s == '\0' ) {
960                         break;
961                 }
962                 if ( (c = strchr( s, ':' )) != NULL ) {
963                         c++;
964                 }
965
966                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
967                         if ( c != NULL ) {
968                                 *code = atoi( c );
969                         }
970                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
971                         if ( c != NULL ) {
972                                 *matched = c;
973                         }
974                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
975                         if ( c != NULL ) {
976                                 *info = c;
977                         }
978                 } else {
979                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
980                             s, 0, 0 );
981                         rc = -1;
982                 }
983         }
984
985         return( rc );
986 }