]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
Fix - v2ref returned a pointer that it did not allocate, and send_ldap_result
[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 = ber_pvt_ber_bytes( ber );
175
176         /* write only one pdu at a time - wait til it's our turn */
177         ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
178
179         /* lock the connection */ 
180         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
181
182         /* write the pdu */
183         while( 1 ) {
184                 int err;
185
186                 if ( connection_state_closing( conn ) ) {
187                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
188                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
189
190                         return 0;
191                 }
192
193                 if ( ber_flush( conn->c_sb, ber, 0 ) == 0 ) {
194                         break;
195                 }
196
197                 err = errno;
198
199                 /*
200                  * we got an error.  if it's ewouldblock, we need to
201                  * wait on the socket being writable.  otherwise, figure
202                  * it's a hard error and return.
203                  */
204
205                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno=%d reason=\"%s\"\n",
206                     err, STRERROR(err), 0 );
207
208                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
209                         connection_closing( conn );
210
211                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
212                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
213
214                         return( -1 );
215                 }
216
217                 /* wait for socket to be write-ready */
218                 conn->c_writewaiter = 1;
219                 slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
220
221                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
222                 conn->c_writewaiter = 0;
223         }
224
225         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
226         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
227
228         return bytes;
229 }
230
231 static void
232 send_ldap_response(
233     Connection  *conn,
234     Operation   *op,
235         ber_tag_t       tag,
236         ber_int_t       msgid,
237     ber_int_t   err,
238     const char  *matched,
239     const char  *text,
240         struct berval   **ref,
241         const char      *resoid,
242         struct berval   *resdata,
243         LDAPControl **ctrls
244 )
245 {
246         BerElement      *ber;
247         int             rc;
248         long    bytes;
249
250         assert( ctrls == NULL ); /* ctrls not implemented */
251
252         ber = ber_alloc_t( LBER_USE_DER );
253
254         Debug( LDAP_DEBUG_TRACE, "send_ldap_response: msgid=%ld tag=%ld err=%ld\n",
255                 (long) msgid, (long) tag, (long) err );
256
257         if ( ber == NULL ) {
258                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
259                 return;
260         }
261
262 #ifdef LDAP_CONNECTIONLESS
263         if ( op->o_cldap ) {
264                 rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
265                     err, matched ? matched : "", text ? text : "" );
266         } else
267 #endif
268         {
269                 rc = ber_printf( ber, "{it{ess",
270                         msgid, tag, err,
271                         matched == NULL ? "" : matched,
272                         text == NULL ? "" : text );
273
274                 if( rc != -1 && ref != NULL ) {
275                         rc = ber_printf( ber, "{V}", ref );
276                 }
277
278                 if( rc != -1 && resoid != NULL ) {
279                         rc = ber_printf( ber, "s", resoid );
280                 }
281
282                 if( rc != -1 && resdata != NULL ) {
283                         rc = ber_printf( ber, "O", resdata );
284
285                 }
286
287                 if( rc != -1 ) {
288                         rc = ber_printf( ber, "}}" );
289                 }
290         }
291
292         if ( rc == -1 ) {
293                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
294                 ber_free( ber, 1 );
295                 return;
296         }
297
298         /* send BER */
299         bytes = send_ldap_ber( conn, ber );
300         ber_free( ber, 1 );
301
302         if ( bytes < 0 ) {
303                 Debug( LDAP_DEBUG_ANY,
304                         "send_ldap_response: ber write failed\n",
305                         0, 0, 0 );
306                 return;
307         }
308
309         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
310         num_bytes_sent += bytes;
311         num_pdu_sent++;
312         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
313         return;
314 }
315
316
317 void
318 send_ldap_disconnect(
319     Connection  *conn,
320     Operation   *op,
321     ber_int_t   err,
322     const char  *text
323 )
324 {
325         ber_tag_t tag;
326         ber_int_t msgid;
327         char *reqoid;
328
329 #define LDAP_UNSOLICITED_ERROR(e) \
330         (  (e) == LDAP_PROTOCOL_ERROR \
331         || (e) == LDAP_STRONG_AUTH_REQUIRED \
332         || (e) == LDAP_UNAVAILABLE )
333
334         assert( LDAP_UNSOLICITED_ERROR( err ) );
335
336         Debug( LDAP_DEBUG_TRACE,
337                 "send_ldap_disconnect %d:%s\n",
338                 err, text ? text : "", NULL );
339
340         if ( op->o_protocol < LDAP_VERSION3 ) {
341                 reqoid = NULL;
342                 tag = req2res( op->o_tag );
343                 msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
344
345         } else {
346                 reqoid = LDAP_NOTICE_DISCONNECT;
347                 tag = LDAP_RES_EXTENDED;
348                 msgid = 0;
349         }
350
351 #ifdef LDAP_CONNECTIONLESS
352         if ( op->o_cldap ) {
353                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
354                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
355                     inet_ntoa(((struct sockaddr_in *)
356                     &op->o_clientaddr)->sin_addr ),
357                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
358                     0 );
359         }
360 #endif
361         send_ldap_response( conn, op, tag, msgid,
362                 err, NULL, text, NULL,
363                 reqoid, NULL, NULL );
364
365         Statslog( LDAP_DEBUG_STATS,
366             "conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n",
367                 (long) op->o_connid, (long) op->o_opid,
368                 (long) tag, (long) err, text ? text : "" );
369 }
370
371 void
372 send_ldap_result(
373     Connection  *conn,
374     Operation   *op,
375     ber_int_t   err,
376     const char  *matched,
377     const char  *text,
378         struct berval **ref,
379         LDAPControl **ctrls
380 )
381 {
382         ber_tag_t tag;
383         ber_int_t msgid;
384         char *tmp = NULL;
385
386         assert( !LDAP_API_ERROR( err ) );
387
388         Debug( LDAP_DEBUG_TRACE, "send_ldap_result: conn=%ld op=%ld p=%d\n",
389                 (long) op->o_connid, (long) op->o_opid, op->o_protocol );
390         Debug( LDAP_DEBUG_ARGS, "send_ldap_result: %d:%s:%s\n",
391                 err, matched ?  matched : "", text ? text : "" );
392
393         assert( err != LDAP_PARTIAL_RESULTS );
394
395         if( op->o_tag != LDAP_REQ_SEARCH ) {
396                 trim_refs_urls( ref );
397         }
398
399         if ( err == LDAP_REFERRAL ) {
400                 if( ref == NULL ) {
401                         err = LDAP_NO_SUCH_OBJECT;
402                 } else if ( op->o_protocol < LDAP_VERSION3 ) {
403                         err = LDAP_PARTIAL_RESULTS;
404                 }
405         }
406
407         if ( op->o_protocol < LDAP_VERSION3 ) {
408                 tmp = v2ref( ref, text );
409                 text = tmp;
410                 ref = NULL;
411         }
412
413         tag = req2res( op->o_tag );
414         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
415
416 #ifdef LDAP_CONNECTIONLESS
417         if ( op->o_cldap ) {
418                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
419                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
420                     inet_ntoa(((struct sockaddr_in *)
421                     &op->o_clientaddr)->sin_addr ),
422                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
423                     0 );
424         }
425 #endif
426
427         send_ldap_response( conn, op, tag, msgid,
428                 err, matched, text, ref,
429                 NULL, NULL, ctrls );
430
431         Statslog( LDAP_DEBUG_STATS,
432             "conn=%ld op=%ld RESULT tag=%lu err=%ld text=%s\n",
433                 (long) op->o_connid, (long) op->o_opid,
434                 (long) tag, (long) err, text ? text : "" );
435
436         if( tmp != NULL ) {
437                 ch_free(tmp);
438         }
439 }
440
441
442 void
443 send_search_result(
444     Connection  *conn,
445     Operation   *op,
446     ber_int_t   err,
447     const char  *matched,
448         const char      *text,
449     struct berval **refs,
450         LDAPControl **ctrls,
451     int         nentries
452 )
453 {
454         ber_tag_t tag;
455         ber_int_t msgid;
456         char *tmp = NULL;
457         assert( !LDAP_API_ERROR( err ) );
458
459         Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
460                 err, matched ?  matched : "", text ? text : "" );
461
462         assert( err != LDAP_PARTIAL_RESULTS );
463
464         trim_refs_urls( refs );
465
466         if( op->o_protocol < LDAP_VERSION3 ) {
467                 /* send references in search results */
468                 if( err == LDAP_REFERRAL ) {
469                         err = LDAP_PARTIAL_RESULTS;
470                 }
471
472                 tmp = v2ref( refs, text );
473                 text = tmp;
474                 refs = NULL;
475         } else {
476                 /* don't send references in search results */
477                 assert( refs == NULL );
478                 refs = NULL;
479
480                 if( err == LDAP_REFERRAL ) {
481                         err = LDAP_SUCCESS;
482                 }
483         }
484
485         tag = req2res( op->o_tag );
486         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
487
488 #ifdef LDAP_CONNECTIONLESS
489         if ( op->o_cldap ) {
490                 ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
491                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
492                     inet_ntoa(((struct sockaddr_in *)
493                     &op->o_clientaddr)->sin_addr ),
494                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
495                     0 );
496         }
497 #endif
498
499         send_ldap_response( conn, op, tag, msgid,
500                 err, matched, text, refs,
501                 NULL, NULL, ctrls );
502
503         Statslog( LDAP_DEBUG_STATS,
504             "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
505                 (long) op->o_connid, (long) op->o_opid,
506                 (long) tag, (long) err, text ? text : "" );
507
508         if (tmp != NULL)
509             ch_free(tmp);
510 }
511
512
513 int
514 send_search_entry(
515     Backend     *be,
516     Connection  *conn,
517     Operation   *op,
518     Entry       *e,
519     char        **attrs,
520     int         attrsonly,
521         LDAPControl **ctrls
522 )
523 {
524         BerElement      *ber;
525         Attribute       *a;
526         int             i, rc=-1, bytes;
527         char            *edn;
528         int             userattrs;
529         int             opattrs;
530
531         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: \"%s\"\n", e->e_dn, 0, 0 );
532
533         if ( ! access_allowed( be, conn, op, e,
534                 "entry", NULL, ACL_READ ) )
535         {
536                 Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
537                     0, 0, 0 );
538                 return( 1 );
539         }
540
541         edn = e->e_ndn;
542
543         ber = ber_alloc_t( LBER_USE_DER );
544
545         if ( ber == NULL ) {
546                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
547                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
548                         NULL, "allocating BER error", NULL, NULL );
549                 goto error_return;
550         }
551
552         rc = ber_printf( ber, "{it{s{", op->o_msgid,
553                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
554
555         if ( rc == -1 ) {
556                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
557                 ber_free( ber, 1 );
558                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
559                     NULL, "encoding dn error", NULL, NULL );
560                 goto error_return;
561         }
562
563         /* check for special all user attributes ("*") type */
564         userattrs = ( attrs == NULL ) ? 1
565                 : charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES );
566
567         /* check for special all operational attributes ("+") type */
568         opattrs = ( attrs == NULL ) ? 0
569                 : charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
570
571         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
572                 if ( attrs == NULL ) {
573                         /* all addrs request, skip operational attributes */
574                         if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
575                                 continue;
576                         }
577
578                 } else {
579                         /* specific addrs requested */
580                         if (  oc_check_operational_attr( a->a_type ) ) {
581                                 if( !opattrs && !charray_inlist( attrs, a->a_type ) )
582                                 {
583                                         continue;
584                                 }
585                         } else {
586                                 if (!userattrs && !charray_inlist( attrs, a->a_type ) )
587                                 {
588                                         continue;
589                                 }
590                         }
591                 }
592
593                 if ( ! access_allowed( be, conn, op, e,
594                         a->a_type, NULL, ACL_READ ) )
595                 {
596                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
597                             a->a_type, 0, 0 );
598                         continue;
599                 }
600
601                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
602                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
603                         ber_free( ber, 1 );
604                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
605                             NULL, "encoding type error", NULL, NULL );
606                         goto error_return;
607                 }
608
609                 if ( ! attrsonly ) {
610                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
611                                 if ( ! access_allowed( be, conn, op, e,
612                                         a->a_type, a->a_vals[i], ACL_READ ) )
613                                 {
614                                         Debug( LDAP_DEBUG_ACL,
615                                                 "acl: access to attribute %s, value %d not allowed\n",
616                                         a->a_type, i, 0 );
617                                         continue;
618                                 }
619
620                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
621                                         Debug( LDAP_DEBUG_ANY,
622                                             "ber_printf failed\n", 0, 0, 0 );
623                                         ber_free( ber, 1 );
624                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
625                                                 NULL, "encoding value error", NULL, NULL );
626                                         goto error_return;
627                                 }
628                         }
629                 }
630
631                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
632                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
633                         ber_free( ber, 1 );
634                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
635                             NULL, "encode end error", NULL, NULL );
636                         goto error_return;
637                 }
638         }
639
640 #ifdef SLAPD_SCHEMA_DN
641         /* eventually will loop through generated operational attributes */
642         /* only have subschemaSubentry implemented */
643         a = backend_subschemasubentry( be );
644         
645         do {
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
695                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
696                                         Debug( LDAP_DEBUG_ANY,
697                                             "ber_printf failed\n", 0, 0, 0 );
698                                         ber_free( ber, 1 );
699                                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
700                                                 NULL, "encoding value error", NULL, NULL );
701                                         goto error_return;
702                                 }
703                         }
704                 }
705
706                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
707                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
708                         ber_free( ber, 1 );
709                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
710                             NULL, "encode end error", NULL, NULL );
711                         goto error_return;
712                 }
713         } while (0);
714 #endif
715
716         rc = ber_printf( ber, /*{{{*/ "}}}" );
717
718         if ( rc == -1 ) {
719                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
720                 ber_free( ber, 1 );
721                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
722                         NULL, "encode entry end error", NULL, NULL );
723                 return( 1 );
724         }
725
726         bytes = send_ldap_ber( conn, ber );
727         ber_free( ber, 1 );
728
729         if ( bytes < 0 ) {
730                 Debug( LDAP_DEBUG_ANY,
731                         "send_ldap_response: ber write failed\n",
732                         0, 0, 0 );
733                 return -1;
734         }
735
736         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
737         num_bytes_sent += bytes;
738         num_entries_sent++;
739         num_pdu_sent++;
740         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
741
742         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
743             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
744
745         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
746
747         rc = 0;
748
749 error_return:;
750         return( rc );
751 }
752
753 int
754 send_search_reference(
755     Backend     *be,
756     Connection  *conn,
757     Operation   *op,
758     Entry       *e,
759         struct berval **refs,
760         int scope,
761         LDAPControl **ctrls,
762     struct berval ***v2refs
763 )
764 {
765         BerElement      *ber;
766         int rc;
767         int bytes;
768
769         Debug( LDAP_DEBUG_TRACE, "=> send_search_reference (%s)\n", e->e_dn, 0, 0 );
770
771         if ( ! access_allowed( be, conn, op, e,
772                 "entry", NULL, ACL_READ ) )
773         {
774                 Debug( LDAP_DEBUG_ACL,
775                         "send_search_reference: access to entry not allowed\n",
776                     0, 0, 0 );
777                 return( 1 );
778         }
779
780         if ( ! access_allowed( be, conn, op, e,
781                 "ref", NULL, ACL_READ ) )
782         {
783                 Debug( LDAP_DEBUG_ACL,
784                         "send_search_reference: access to reference not allowed\n",
785                     0, 0, 0 );
786                 return( 1 );
787         }
788
789         if( refs == NULL ) {
790                 Debug( LDAP_DEBUG_ANY,
791                         "send_search_reference: null ref in (%s)\n", 
792                         e->e_dn, 0, 0 );
793                 return( 1 );
794         }
795
796         if( op->o_protocol < LDAP_VERSION3 ) {
797                 /* save the references for the result */
798                 if( *refs == NULL ) {
799                         value_add( v2refs, refs );
800                 }
801                 return 0;
802         }
803
804         ber = ber_alloc_t( LBER_USE_DER );
805
806         if ( ber == NULL ) {
807                 Debug( LDAP_DEBUG_ANY,
808                         "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
809                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
810                         NULL, "alloc BER error", NULL, NULL );
811                 return -1;
812         }
813
814         rc = ber_printf( ber, "{it{V}}", op->o_msgid,
815                 LDAP_RES_SEARCH_REFERENCE, refs );
816
817         if ( rc == -1 ) {
818                 Debug( LDAP_DEBUG_ANY,
819                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
820                 ber_free( ber, 1 );
821                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
822                         NULL, "encode dn error", NULL, NULL );
823                 return -1;
824         }
825
826         bytes = send_ldap_ber( conn, ber );
827         ber_free( ber, 1 );
828
829         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
830         num_bytes_sent += bytes;
831         num_refs_sent++;
832         num_pdu_sent++;
833         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
834
835         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
836             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
837
838         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
839
840         return 0;
841 }
842
843
844 int
845 str2result(
846     char        *s,
847     int         *code,
848     char        **matched,
849     char        **info
850 )
851 {
852         int     rc;
853         char    *c;
854
855         *code = LDAP_SUCCESS;
856         *matched = NULL;
857         *info = NULL;
858
859         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
860                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
861                     s, 0, 0 );
862
863                 return( -1 );
864         }
865
866         rc = 0;
867         while ( (s = strchr( s, '\n' )) != NULL ) {
868                 *s++ = '\0';
869                 if ( *s == '\0' ) {
870                         break;
871                 }
872                 if ( (c = strchr( s, ':' )) != NULL ) {
873                         c++;
874                 }
875
876                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
877                         if ( c != NULL ) {
878                                 *code = atoi( c );
879                         }
880                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
881                         if ( c != NULL ) {
882                                 *matched = c;
883                         }
884                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
885                         if ( c != NULL ) {
886                                 *info = c;
887                         }
888                 } else {
889                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
890                             s, 0, 0 );
891                         rc = -1;
892                 }
893         }
894
895         return( rc );
896 }