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