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