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