]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
37faa5181ec71d941b3c11f99f28d5476276b3f8
[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 + 1;
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_sasl(
445     Connection  *conn,
446     Operation   *op,
447     ber_int_t   err,
448     const char  *matched,
449     const char  *text,
450         struct berval *cred
451 )
452 {
453         ber_tag_t tag;
454         ber_int_t msgid;
455
456         Debug( LDAP_DEBUG_TRACE, "send_ldap_sasl %ld\n",
457                 (long) err, NULL, NULL );
458
459         tag = req2res( op->o_tag );
460         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
461
462 #ifdef LDAP_CONNECTIONLESS
463         if ( op->o_cldap ) {
464                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
465                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
466                     inet_ntoa(((struct sockaddr_in *)
467                     &op->o_clientaddr)->sin_addr ),
468                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
469                     0 );
470         }
471 #endif
472
473         send_ldap_response( conn, op, tag, msgid,
474                 err, matched, text, NULL,
475                 NULL, cred, NULL );
476 }
477
478 void
479 send_ldap_extended(
480     Connection  *conn,
481     Operation   *op,
482     ber_int_t   err,
483     const char  *matched,
484     const char  *text,
485     char                *rspoid,
486         struct berval *rspdata
487 )
488 {
489         ber_tag_t tag;
490         ber_int_t msgid;
491
492         Debug( LDAP_DEBUG_TRACE,
493                 "send_ldap_extended %ld:%s\n",
494                 (long) err, rspoid ? rspoid : "", NULL );
495
496         tag = req2res( op->o_tag );
497         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
498
499 #ifdef LDAP_CONNECTIONLESS
500         if ( op->o_cldap ) {
501                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
502                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
503                     inet_ntoa(((struct sockaddr_in *)
504                     &op->o_clientaddr)->sin_addr ),
505                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
506                     0 );
507         }
508 #endif
509         send_ldap_response( conn, op, tag, msgid,
510                 err, matched, text, NULL,
511                 rspoid, rspdata, NULL );
512 }
513
514
515 void
516 send_search_result(
517     Connection  *conn,
518     Operation   *op,
519     ber_int_t   err,
520     const char  *matched,
521         const char      *text,
522     struct berval **refs,
523         LDAPControl **ctrls,
524     int         nentries
525 )
526 {
527         ber_tag_t tag;
528         ber_int_t msgid;
529         char *tmp = NULL;
530         assert( !LDAP_API_ERROR( err ) );
531
532         Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
533                 err, matched ?  matched : "", text ? text : "" );
534
535         assert( err != LDAP_PARTIAL_RESULTS );
536
537         trim_refs_urls( refs );
538
539         if( op->o_protocol < LDAP_VERSION3 ) {
540                 /* send references in search results */
541                 if( err == LDAP_REFERRAL ) {
542                         err = LDAP_PARTIAL_RESULTS;
543                 }
544
545                 tmp = v2ref( refs, text );
546                 text = tmp;
547                 refs = NULL;
548         } else {
549                 /* don't send references in search results */
550                 assert( refs == NULL );
551                 refs = NULL;
552
553                 if( err == LDAP_REFERRAL ) {
554                         err = LDAP_SUCCESS;
555                 }
556         }
557
558         tag = req2res( op->o_tag );
559         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
560
561 #ifdef LDAP_CONNECTIONLESS
562         if ( op->o_cldap ) {
563                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
564                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
565                     inet_ntoa(((struct sockaddr_in *)
566                     &op->o_clientaddr)->sin_addr ),
567                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
568                     0 );
569         }
570 #endif
571
572         send_ldap_response( conn, op, tag, msgid,
573                 err, matched, text, refs,
574                 NULL, NULL, ctrls );
575
576         Statslog( LDAP_DEBUG_STATS,
577             "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
578                 (long) op->o_connid, (long) op->o_opid,
579                 (long) tag, (long) err, text ? text : "" );
580
581         if (tmp != NULL)
582             ch_free(tmp);
583 }
584
585
586 int
587 send_search_entry(
588     Backend     *be,
589     Connection  *conn,
590     Operation   *op,
591     Entry       *e,
592     char        **attrs,
593     int         attrsonly,
594         LDAPControl **ctrls
595 )
596 {
597         BerElement      *ber;
598         Attribute       *a;
599         int             i, rc=-1, bytes;
600         char            *edn;
601         int             userattrs;
602         int             opattrs;
603
604         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: \"%s\"\n", e->e_dn, 0, 0 );
605
606         if ( ! access_allowed( be, conn, op, e,
607                 "entry", NULL, ACL_READ ) )
608         {
609                 Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
610                     0, 0, 0 );
611                 return( 1 );
612         }
613
614         edn = e->e_ndn;
615
616         ber = ber_alloc_t( LBER_USE_DER );
617
618         if ( ber == NULL ) {
619                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
620                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
621                         NULL, "allocating BER error", NULL, NULL );
622                 goto error_return;
623         }
624
625         rc = ber_printf( ber, "{it{s{", op->o_msgid,
626                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
627
628         if ( rc == -1 ) {
629                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
630                 ber_free( ber, 1 );
631                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
632                     NULL, "encoding dn error", NULL, NULL );
633                 goto error_return;
634         }
635
636         /* check for special all user attributes ("*") type */
637         userattrs = ( attrs == NULL ) ? 1
638                 : charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES );
639
640         /* check for special all operational attributes ("+") type */
641         opattrs = ( attrs == NULL ) ? 0
642                 : charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
643
644         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
645                 if ( attrs == NULL ) {
646                         /* all addrs request, skip operational attributes */
647                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
648                                 continue;
649                         }
650
651                 } else {
652                         /* specific addrs requested */
653                         if (  oc_check_operational_attr( a->a_type ) ) {
654                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
655                                 {
656                                         continue;
657                                 }
658                         } else {
659                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
660                                 {
661                                         continue;
662                                 }
663                         }
664                 }
665
666                 if ( ! access_allowed( be, conn, op, e,
667                         a->a_type, NULL, ACL_READ ) )
668                 {
669                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
670                             a->a_type, 0, 0 );
671                         continue;
672                 }
673
674                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
675                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
676                         ber_free( ber, 1 );
677                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
678                             NULL, "encoding type error", NULL, NULL );
679                         goto error_return;
680                 }
681
682                 if ( ! attrsonly ) {
683                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
684                                 if ( ! access_allowed( be, conn, op, e,
685                                         a->a_type, a->a_vals[i], ACL_READ ) )
686                                 {
687                                         Debug( LDAP_DEBUG_ACL,
688                                                 "acl: access to attribute %s, value %d not allowed\n",
689                                         a->a_type, i, 0 );
690                                         continue;
691                                 }
692
693                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
694                                         Debug( LDAP_DEBUG_ANY,
695                                             "ber_printf failed\n", 0, 0, 0 );
696                                         ber_free( ber, 1 );
697                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
698                                                 NULL, "encoding value error", NULL, NULL );
699                                         goto error_return;
700                                 }
701                         }
702                 }
703
704                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
705                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
706                         ber_free( ber, 1 );
707                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
708                             NULL, "encode end error", NULL, NULL );
709                         goto error_return;
710                 }
711         }
712
713 #ifdef SLAPD_SCHEMA_DN
714         /* eventually will loop through generated operational attributes */
715         /* only have subschemaSubentry implemented */
716         a = backend_subschemasubentry( be );
717         
718         do {
719                 if ( attrs == NULL ) {
720                         /* all addrs request, skip operational attributes */
721                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
722                                 continue;
723                         }
724
725                 } else {
726                         /* specific addrs requested */
727                         if (  oc_check_operational_attr( a->a_type ) ) {
728                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
729                                 {
730                                         continue;
731                                 }
732                         } else {
733                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
734                                 {
735                                         continue;
736                                 }
737                         }
738                 }
739
740                 if ( ! access_allowed( be, conn, op, e,
741                         a->a_type, NULL, ACL_READ ) )
742                 {
743                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
744                             a->a_type, 0, 0 );
745                         continue;
746                 }
747
748                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
749                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
750                         ber_free( ber, 1 );
751                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
752                             NULL, "encoding type error", NULL, NULL );
753                         goto error_return;
754                 }
755
756                 if ( ! attrsonly ) {
757                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
758                                 if ( ! access_allowed( be, conn, op, e,
759                                         a->a_type, a->a_vals[i], ACL_READ ) )
760                                 {
761                                         Debug( LDAP_DEBUG_ACL,
762                                                 "acl: access to attribute %s, value %d not allowed\n",
763                                         a->a_type, i, 0 );
764                                         continue;
765                                 }
766
767
768                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
769                                         Debug( LDAP_DEBUG_ANY,
770                                             "ber_printf failed\n", 0, 0, 0 );
771                                         ber_free( ber, 1 );
772                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
773                                                 NULL, "encoding value error", NULL, NULL );
774                                         goto error_return;
775                                 }
776                         }
777                 }
778
779                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
780                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
781                         ber_free( ber, 1 );
782                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
783                             NULL, "encode end error", NULL, NULL );
784                         goto error_return;
785                 }
786         } while (0);
787 #endif
788
789         rc = ber_printf( ber, /*{{{*/ "}}}" );
790
791         if ( rc == -1 ) {
792                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
793                 ber_free( ber, 1 );
794                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
795                         NULL, "encode entry end error", NULL, NULL );
796                 return( 1 );
797         }
798
799         bytes = send_ldap_ber( conn, ber );
800         ber_free( ber, 1 );
801
802         if ( bytes < 0 ) {
803                 Debug( LDAP_DEBUG_ANY,
804                         "send_ldap_response: ber write failed\n",
805                         0, 0, 0 );
806                 return -1;
807         }
808
809         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
810         num_bytes_sent += bytes;
811         num_entries_sent++;
812         num_pdu_sent++;
813         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
814
815         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
816             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
817
818         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
819
820         rc = 0;
821
822 error_return:;
823         return( rc );
824 }
825
826 int
827 send_search_reference(
828     Backend     *be,
829     Connection  *conn,
830     Operation   *op,
831     Entry       *e,
832         struct berval **refs,
833         int scope,
834         LDAPControl **ctrls,
835     struct berval ***v2refs
836 )
837 {
838         BerElement      *ber;
839         int rc;
840         int bytes;
841
842         Debug( LDAP_DEBUG_TRACE, "=> send_search_reference (%s)\n", e->e_dn, 0, 0 );
843
844         if ( ! access_allowed( be, conn, op, e,
845                 "entry", NULL, ACL_READ ) )
846         {
847                 Debug( LDAP_DEBUG_ACL,
848                         "send_search_reference: access to entry not allowed\n",
849                     0, 0, 0 );
850                 return( 1 );
851         }
852
853         if ( ! access_allowed( be, conn, op, e,
854                 "ref", NULL, ACL_READ ) )
855         {
856                 Debug( LDAP_DEBUG_ACL,
857                         "send_search_reference: access to reference not allowed\n",
858                     0, 0, 0 );
859                 return( 1 );
860         }
861
862         if( refs == NULL ) {
863                 Debug( LDAP_DEBUG_ANY,
864                         "send_search_reference: null ref in (%s)\n", 
865                         e->e_dn, 0, 0 );
866                 return( 1 );
867         }
868
869         if( op->o_protocol < LDAP_VERSION3 ) {
870                 /* save the references for the result */
871                 if( *refs == NULL ) {
872                         value_add( v2refs, refs );
873                 }
874                 return 0;
875         }
876
877         ber = ber_alloc_t( LBER_USE_DER );
878
879         if ( ber == NULL ) {
880                 Debug( LDAP_DEBUG_ANY,
881                         "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
882                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
883                         NULL, "alloc BER error", NULL, NULL );
884                 return -1;
885         }
886
887         rc = ber_printf( ber, "{it{V}}", op->o_msgid,
888                 LDAP_RES_SEARCH_REFERENCE, refs );
889
890         if ( rc == -1 ) {
891                 Debug( LDAP_DEBUG_ANY,
892                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
893                 ber_free( ber, 1 );
894                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
895                         NULL, "encode dn error", NULL, NULL );
896                 return -1;
897         }
898
899         bytes = send_ldap_ber( conn, ber );
900         ber_free( ber, 1 );
901
902         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
903         num_bytes_sent += bytes;
904         num_refs_sent++;
905         num_pdu_sent++;
906         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
907
908         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
909             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
910
911         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
912
913         return 0;
914 }
915
916
917 int
918 str2result(
919     char        *s,
920     int         *code,
921     char        **matched,
922     char        **info
923 )
924 {
925         int     rc;
926         char    *c;
927
928         *code = LDAP_SUCCESS;
929         *matched = NULL;
930         *info = NULL;
931
932         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
933                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
934                     s, 0, 0 );
935
936                 return( -1 );
937         }
938
939         rc = 0;
940         while ( (s = strchr( s, '\n' )) != NULL ) {
941                 *s++ = '\0';
942                 if ( *s == '\0' ) {
943                         break;
944                 }
945                 if ( (c = strchr( s, ':' )) != NULL ) {
946                         c++;
947                 }
948
949                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
950                         if ( c != NULL ) {
951                                 *code = atoi( c );
952                         }
953                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
954                         if ( c != NULL ) {
955                                 *matched = c;
956                         }
957                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
958                         if ( c != NULL ) {
959                                 *info = c;
960                         }
961                 } else {
962                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
963                             s, 0, 0 );
964                         rc = -1;
965                 }
966         }
967
968         return( rc );
969 }