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