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