]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
Berkeley DB 4.2 support (DB 4.2 required by default)
[openldap] / servers / slapd / result.c
1 /* result.c - routines to send ldap results, errors, and referrals */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/socket.h>
13 #include <ac/errno.h>
14 #include <ac/string.h>
15 #include <ac/ctype.h>
16 #include <ac/time.h>
17 #include <ac/unistd.h>
18
19 #include "slap.h"
20
21 #ifdef LDAP_SLAPI
22 #include "slapi.h"
23 #endif
24
25 static char *v2ref( BerVarray ref, const char *text )
26 {
27         size_t len = 0, i = 0;
28         char *v2;
29
30         if(ref == NULL) {
31                 if (text) {
32                         return ch_strdup(text);
33                 } else {
34                         return NULL;
35                 }
36         }
37         
38         if ( text != NULL ) {
39                 len = strlen( text );
40                 if (text[len-1] != '\n') {
41                     i = 1;
42                 }
43         }
44
45         v2 = SLAP_MALLOC( len+i+sizeof("Referral:") );
46         if( v2 == NULL ) {
47 #ifdef NEW_LOGGING
48                 LDAP_LOG( OPERATION, ERR, "v2ref: SLAP_MALLOC failed", 0, 0, 0 );
49 #else
50                 Debug( LDAP_DEBUG_ANY, "v2ref: SLAP_MALLOC failed", 0, 0, 0 );
51 #endif
52                 return NULL;
53         }
54
55         if( text != NULL ) {
56                 strcpy(v2, text);
57                 if( i ) {
58                         v2[len++] = '\n';
59                 }
60         }
61         strcpy( v2+len, "Referral:" );
62         len += sizeof("Referral:");
63
64         for( i=0; ref[i].bv_val != NULL; i++ ) {
65                 v2 = SLAP_REALLOC( v2, len + ref[i].bv_len + 1 );
66                 if( v2 == NULL ) {
67 #ifdef NEW_LOGGING
68                         LDAP_LOG( OPERATION, ERR, "v2ref: SLAP_MALLOC failed", 0, 0, 0 );
69 #else
70                         Debug( LDAP_DEBUG_ANY, "v2ref: SLAP_MALLOC failed", 0, 0, 0 );
71 #endif
72                         return NULL;
73                 }
74                 v2[len-1] = '\n';
75                 AC_MEMCPY(&v2[len], ref[i].bv_val, ref[i].bv_len );
76                 len += ref[i].bv_len;
77                 if (ref[i].bv_val[ref[i].bv_len-1] != '/') {
78                         ++len;
79                 }
80         }
81
82         v2[len-1] = '\0';
83         return v2;
84 }
85
86 static ber_tag_t req2res( ber_tag_t tag )
87 {
88         switch( tag ) {
89         case LDAP_REQ_ADD:
90         case LDAP_REQ_BIND:
91         case LDAP_REQ_COMPARE:
92         case LDAP_REQ_EXTENDED:
93         case LDAP_REQ_MODIFY:
94         case LDAP_REQ_MODRDN:
95                 tag++;
96                 break;
97
98         case LDAP_REQ_DELETE:
99                 tag = LDAP_RES_DELETE;
100                 break;
101
102         case LDAP_REQ_ABANDON:
103         case LDAP_REQ_UNBIND:
104                 tag = LBER_SEQUENCE;
105                 break;
106
107         case LDAP_REQ_SEARCH:
108                 tag = LDAP_RES_SEARCH_RESULT;
109                 break;
110
111         default:
112                 tag = LBER_SEQUENCE;
113         }
114
115         return tag;
116 }
117
118 static long send_ldap_ber(
119         Connection *conn,
120         BerElement *ber )
121 {
122         ber_len_t bytes;
123
124         ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes );
125
126         /* write only one pdu at a time - wait til it's our turn */
127         ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
128
129         /* lock the connection */ 
130         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
131
132         /* write the pdu */
133         while( 1 ) {
134                 int err;
135                 ber_socket_t    sd;
136
137                 if ( connection_state_closing( conn ) ) {
138                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
139                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
140
141                         return 0;
142                 }
143
144                 if ( ber_flush( conn->c_sb, ber, 0 ) == 0 ) {
145                         break;
146                 }
147
148                 err = errno;
149
150                 /*
151                  * we got an error.  if it's ewouldblock, we need to
152                  * wait on the socket being writable.  otherwise, figure
153                  * it's a hard error and return.
154                  */
155
156 #ifdef NEW_LOGGING
157                 LDAP_LOG( OPERATION, ERR, 
158                         "send_ldap_ber: conn %lu  ber_flush failed err=%d (%s)\n",
159                         conn ? conn->c_connid : 0, err, sock_errstr(err) );
160 #else
161                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno=%d reason=\"%s\"\n",
162                     err, sock_errstr(err), 0 );
163 #endif
164
165                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
166                         connection_closing( conn );
167
168                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
169                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
170
171                         return( -1 );
172                 }
173
174                 /* wait for socket to be write-ready */
175                 conn->c_writewaiter = 1;
176                 ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd );
177                 slapd_set_write( sd, 1 );
178
179                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
180                 conn->c_writewaiter = 0;
181         }
182
183         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
184         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
185
186         return bytes;
187 }
188
189 static int
190 send_ldap_controls( BerElement *ber, LDAPControl **c )
191 {
192         int rc;
193         if( c == NULL ) return 0;
194
195         rc = ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS );
196         if( rc == -1 ) return rc;
197
198         for( ; *c != NULL; c++) {
199                 rc = ber_printf( ber, "{s" /*}*/, (*c)->ldctl_oid );
200
201                 if( (*c)->ldctl_iscritical ) {
202                         rc = ber_printf( ber, "b",
203                                 (ber_int_t) (*c)->ldctl_iscritical ) ;
204                         if( rc == -1 ) return rc;
205                 }
206
207                 if( (*c)->ldctl_value.bv_val != NULL ) {
208                         rc = ber_printf( ber, "O", &((*c)->ldctl_value)); 
209                         if( rc == -1 ) return rc;
210                 }
211
212                 rc = ber_printf( ber, /*{*/"N}" );
213                 if( rc == -1 ) return rc;
214         }
215
216         rc = ber_printf( ber, /*{*/"N}" );
217
218         return rc;
219 }
220
221 void
222 send_ldap_response(
223         Operation *op,
224         SlapReply *rs )
225 {
226         BerElementBuffer berbuf;
227         BerElement      *ber = (BerElement *) &berbuf;
228         int             rc;
229         long    bytes;
230
231         if (op->o_callback && op->o_callback->sc_response) {
232                 rc = op->o_callback->sc_response( op, rs );
233                 if ( rc != SLAP_CB_CONTINUE ) return;
234         }
235                 
236 #ifdef LDAP_CONNECTIONLESS
237         if (op->o_conn && op->o_conn->c_is_udp)
238                 ber = op->o_res_ber;
239         else
240 #endif
241         {
242                 ber_init_w_nullc( ber, LBER_USE_DER );
243                 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
244         }
245
246 #ifdef NEW_LOGGING
247         LDAP_LOG( OPERATION, ENTRY, 
248                 "send_ldap_response:  msgid=%d tag=%lu err=%d\n",
249                 rs->sr_msgid, rs->sr_tag, rs->sr_err );
250 #else
251         Debug( LDAP_DEBUG_TRACE,
252                 "send_ldap_response: msgid=%d tag=%lu err=%d\n",
253                 rs->sr_msgid, rs->sr_tag, rs->sr_err );
254 #endif
255
256         if( rs->sr_ref ) {
257 #ifdef NEW_LOGGING
258                 LDAP_LOG( OPERATION, ARGS, 
259                         "send_ldap_response: conn %lu  ref=\"%s\"\n",
260                         op->o_connid,
261                         rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL" , 0 );
262 #else
263                 Debug( LDAP_DEBUG_ARGS, "send_ldap_response: ref=\"%s\"\n",
264                         rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL",
265                         NULL, NULL );
266 #endif
267         }
268
269 #ifdef LDAP_CONNECTIONLESS
270         if (op->o_conn && op->o_conn->c_is_udp &&
271                 op->o_protocol == LDAP_VERSION2 )
272         {
273                 rc = ber_printf( ber, "t{ess" /*"}}"*/,
274                         rs->sr_tag, rs->sr_err,
275                 rs->sr_matched == NULL ? "" : rs->sr_matched,
276                 rs->sr_text == NULL ? "" : rs->sr_text );
277         } else 
278 #endif
279         if ( rs->sr_type == REP_INTERMEDIATE ) {
280             rc = ber_printf( ber, "{it{" /*"}}"*/,
281                         rs->sr_msgid, rs->sr_tag );
282
283         } else {
284             rc = ber_printf( ber, "{it{ess" /*"}}"*/,
285                 rs->sr_msgid, rs->sr_tag, rs->sr_err,
286                 rs->sr_matched == NULL ? "" : rs->sr_matched,
287                 rs->sr_text == NULL ? "" : rs->sr_text );
288         }
289
290         if( rc != -1 ) {
291                 if ( rs->sr_ref != NULL ) {
292                         assert( rs->sr_err == LDAP_REFERRAL );
293                         rc = ber_printf( ber, "t{W}",
294                                 LDAP_TAG_REFERRAL, rs->sr_ref );
295                 } else {
296                         assert( rs->sr_err != LDAP_REFERRAL );
297                 }
298         }
299
300         if( rc != -1 && rs->sr_type == REP_SASL && rs->sr_sasldata != NULL ) {
301                 rc = ber_printf( ber, "tO",
302                         LDAP_TAG_SASL_RES_CREDS, rs->sr_sasldata );
303         }
304
305         if( rc != -1 &&
306                 ( rs->sr_type == REP_EXTENDED || rs->sr_type == REP_INTERMEDIATE ))
307         {
308                 if ( rs->sr_rspoid != NULL ) {
309                         rc = ber_printf( ber, "ts",
310                                 LDAP_TAG_EXOP_RES_OID, rs->sr_rspoid );
311                 }
312                 if( rc != -1 && rs->sr_rspdata != NULL ) {
313                         rc = ber_printf( ber, "tO",
314                                 LDAP_TAG_EXOP_RES_VALUE, rs->sr_rspdata );
315                 }
316         }
317
318         if( rc != -1 ) {
319                 rc = ber_printf( ber, /*"{"*/ "N}" );
320         }
321
322         if( rc != -1 && rs->sr_ctrls != NULL ) {
323                 rc = send_ldap_controls( ber, rs->sr_ctrls );
324         }
325
326         if( rc != -1 ) {
327                 rc = ber_printf( ber, /*"{"*/ "N}" );
328         }
329
330 #ifdef LDAP_CONNECTIONLESS
331         if( op->o_conn && op->o_conn->c_is_udp && op->o_protocol == LDAP_VERSION2 && rc != -1 ) {
332                 rc = ber_printf( ber, /*"{"*/ "N}" );
333         }
334 #endif
335                 
336         if ( rc == -1 ) {
337 #ifdef NEW_LOGGING
338                 LDAP_LOG( OPERATION, ERR, 
339                         "send_ldap_response: conn %lu  ber_printf failed\n",
340                         op->o_connid, 0, 0 );
341 #else
342                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
343 #endif
344
345 #ifdef LDAP_CONNECTIONLESS
346                 if (!op->o_conn || op->o_conn->c_is_udp == 0)
347 #endif
348                 ber_free_buf( ber );
349                 return;
350         }
351
352         /* send BER */
353         bytes = send_ldap_ber( op->o_conn, ber );
354 #ifdef LDAP_CONNECTIONLESS
355         if (!op->o_conn || op->o_conn->c_is_udp == 0)
356 #endif
357         ber_free_buf( ber );
358
359         if ( bytes < 0 ) {
360 #ifdef NEW_LOGGING
361                 LDAP_LOG( OPERATION, ERR, 
362                         "send_ldap_response: conn %lu ber write failed\n",
363                         op->o_connid ? op->o_connid : 0, 0, 0 );
364 #else
365                 Debug( LDAP_DEBUG_ANY,
366                         "send_ldap_response: ber write failed\n",
367                         0, 0, 0 );
368 #endif
369
370                 return;
371         }
372
373 #ifdef LDAP_SLAPI
374         if ( op->o_pb ) {
375                 slapi_pblock_set( op->o_pb, SLAPI_RESULT_CODE, (void *)rs->sr_err );
376                 slapi_pblock_set( op->o_pb, SLAPI_RESULT_MATCHED, (void *)rs->sr_matched );
377                 slapi_pblock_set( op->o_pb, SLAPI_RESULT_TEXT, (void *)rs->sr_text );
378         }
379 #endif /* LDAP_SLAPI */
380
381         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
382         num_bytes_sent += bytes;
383         num_pdu_sent++;
384         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
385         return;
386 }
387
388
389 void
390 send_ldap_disconnect( Operation *op, SlapReply *rs )
391 {
392 #define LDAP_UNSOLICITED_ERROR(e) \
393         (  (e) == LDAP_PROTOCOL_ERROR \
394         || (e) == LDAP_STRONG_AUTH_REQUIRED \
395         || (e) == LDAP_UNAVAILABLE )
396
397         assert( LDAP_UNSOLICITED_ERROR( rs->sr_err ) );
398
399         rs->sr_type = REP_EXTENDED;
400
401 #ifdef NEW_LOGGING
402         LDAP_LOG( OPERATION, ENTRY, 
403                 "send_ldap_disconnect: conn %lu  %d:%s\n",
404                 op->o_connid, rs->sr_err, rs->sr_text ? rs->sr_text : "" );
405 #else
406         Debug( LDAP_DEBUG_TRACE,
407                 "send_ldap_disconnect %d:%s\n",
408                 rs->sr_err, rs->sr_text ? rs->sr_text : "", NULL );
409 #endif
410
411
412         if ( op->o_protocol < LDAP_VERSION3 ) {
413                 rs->sr_rspoid = NULL;
414                 rs->sr_tag = req2res( op->o_tag );
415                 rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
416
417         } else {
418                 rs->sr_rspoid = LDAP_NOTICE_DISCONNECT;
419                 rs->sr_tag = LDAP_RES_EXTENDED;
420                 rs->sr_msgid = 0;
421         }
422
423         send_ldap_response( op, rs );
424
425         Statslog( LDAP_DEBUG_STATS,
426             "conn=%lu op=%lu DISCONNECT tag=%lu err=%d text=%s\n",
427                 op->o_connid, op->o_opid, rs->sr_tag, rs->sr_err, rs->sr_text ? rs->sr_text : "" );
428 }
429
430 void
431 slap_send_ldap_result( Operation *op, SlapReply *rs )
432 {
433         char *tmp = NULL;
434         const char *otext = rs->sr_text;
435         BerVarray oref = rs->sr_ref;
436
437         rs->sr_type = REP_RESULT;
438
439         assert( !LDAP_API_ERROR( rs->sr_err ) && ( rs->sr_err >= 0 ));
440
441 #ifdef NEW_LOGGING
442         LDAP_LOG( OPERATION, ENTRY, 
443                 "send_ldap_result: conn %lu op=%lu p=%d\n",
444                 op->o_connid, op->o_opid, op->o_protocol );
445 #else
446         Debug( LDAP_DEBUG_TRACE,
447                 "send_ldap_result: conn=%lu op=%lu p=%d\n",
448                 op->o_connid, op->o_opid, op->o_protocol );
449 #endif
450
451 #ifdef NEW_LOGGING
452         LDAP_LOG( OPERATION, ARGS, 
453                 "send_ldap_result: err=%d matched=\"%s\" text=\"%s\"\n",
454                 rs->sr_err, rs->sr_matched ? rs->sr_matched : "",
455                 rs->sr_text ? rs->sr_text : "" );
456 #else
457         Debug( LDAP_DEBUG_ARGS,
458                 "send_ldap_result: err=%d matched=\"%s\" text=\"%s\"\n",
459                 rs->sr_err, rs->sr_matched ? rs->sr_matched : "",
460                 rs->sr_text ? rs->sr_text : "" );
461 #endif
462
463
464         if( rs->sr_ref ) {
465 #ifdef NEW_LOGGING
466                 LDAP_LOG( OPERATION, ARGS, 
467                         "send_ldap_result: referral=\"%s\"\n",
468                         rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL", 0, 0 );
469 #else
470                 Debug( LDAP_DEBUG_ARGS,
471                         "send_ldap_result: referral=\"%s\"\n",
472                         rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL",
473                         NULL, NULL );
474 #endif
475         }
476
477         assert( rs->sr_err != LDAP_PARTIAL_RESULTS );
478
479         if ( rs->sr_err == LDAP_REFERRAL ) {
480 #ifdef LDAP_CONTROL_X_DOMAIN_SCOPE
481                 if( op->o_domain_scope ) {
482                         rs->sr_ref = NULL;
483                 }
484 #endif
485                 if( rs->sr_ref == NULL ) {
486                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
487                 } else if ( op->o_protocol < LDAP_VERSION3 ) {
488                         rs->sr_err = LDAP_PARTIAL_RESULTS;
489                 }
490         }
491
492 #ifdef LDAP_SLAPI
493         /*
494          * Call pre-result plugins. To avoid infinite recursion plugins
495          * should just set SLAPI_RESULT_CODE rather than sending a
496          * result if they wish to change the result.
497          */
498         if ( op->o_pb ) {
499                 slapi_x_pblock_set_operation( op->o_pb, op );
500                 slapi_pblock_set( op->o_pb, SLAPI_RESULT_CODE, (void *)rs->sr_err );
501                 slapi_pblock_set( op->o_pb, SLAPI_RESULT_TEXT, (void *)rs->sr_text );
502                 slapi_pblock_set( op->o_pb, SLAPI_RESULT_MATCHED, (void *)rs->sr_matched );
503
504                 (void) doPluginFNs( op->o_bd, SLAPI_PLUGIN_PRE_RESULT_FN, op->o_pb );
505         }
506 #endif /* LDAP_SLAPI */
507
508         if ( op->o_protocol < LDAP_VERSION3 ) {
509                 tmp = v2ref( rs->sr_ref, rs->sr_text );
510                 rs->sr_text = tmp;
511                 rs->sr_ref = NULL;
512         }
513
514         rs->sr_tag = req2res( op->o_tag );
515         rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
516
517         send_ldap_response( op, rs );
518
519         if ( op->o_tag == LDAP_REQ_SEARCH ) {
520                 char nbuf[64];
521                 snprintf( nbuf, sizeof nbuf, "%d nentries=%d",
522                         rs->sr_err, rs->sr_nentries );
523
524                 Statslog( LDAP_DEBUG_STATS,
525                 "conn=%lu op=%lu SEARCH RESULT tag=%lu err=%s text=%s\n",
526                         op->o_connid, op->o_opid, rs->sr_tag, nbuf,
527                         rs->sr_text ? rs->sr_text : "" );
528         } else {
529                 Statslog( LDAP_DEBUG_STATS,
530                         "conn=%lu op=%lu RESULT tag=%lu err=%d text=%s\n",
531                         op->o_connid, op->o_opid, rs->sr_tag, rs->sr_err,
532                         rs->sr_text ? rs->sr_text : "" );
533         }
534
535         if( tmp != NULL ) ch_free(tmp);
536         rs->sr_text = otext;
537         rs->sr_ref = oref;
538 }
539
540 void
541 send_ldap_sasl( Operation *op, SlapReply *rs )
542 {
543         rs->sr_type = REP_SASL;
544 #ifdef NEW_LOGGING
545         LDAP_LOG( OPERATION, ENTRY, 
546                 "send_ldap_sasl: conn %lu err=%d len=%lu\n",
547                 op->o_connid, rs->sr_err,
548                 rs->sr_sasldata ? rs->sr_sasldata->bv_len : -1 );
549 #else
550         Debug( LDAP_DEBUG_TRACE, "send_ldap_sasl: err=%d len=%ld\n",
551                 rs->sr_err,
552                 rs->sr_sasldata ? (long) rs->sr_sasldata->bv_len : -1, NULL );
553 #endif
554
555         rs->sr_tag = req2res( op->o_tag );
556         rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
557
558         send_ldap_response( op, rs );
559 }
560
561 void
562 slap_send_ldap_extended( Operation *op, SlapReply *rs )
563 {
564         rs->sr_type = REP_EXTENDED;
565
566 #ifdef NEW_LOGGING
567         LDAP_LOG( OPERATION, ENTRY, 
568                 "send_ldap_extended: err=%d oid=%s len=%ld\n",
569                 rs->sr_err, rs->sr_rspoid ? rs->sr_rspoid : "",
570                 rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 );
571 #else
572         Debug( LDAP_DEBUG_TRACE,
573                 "send_ldap_extended: err=%d oid=%s len=%ld\n",
574                 rs->sr_err,
575                 rs->sr_rspoid ? rs->sr_rspoid : "",
576                 rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 );
577 #endif
578
579         rs->sr_tag = req2res( op->o_tag );
580         rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
581
582         send_ldap_response( op, rs );
583 }
584
585 void
586 slap_send_ldap_intermediate( Operation *op, SlapReply *rs )
587 {
588         rs->sr_type = REP_INTERMEDIATE;
589 #ifdef NEW_LOGGING
590         LDAP_LOG( OPERATION, ENTRY,
591                 "send_ldap_intermediate: err=%d oid=%s len=%ld\n",
592                 rs->sr_err, rs->sr_rspoid ? rs->sr_rspoid : "",
593                 rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 );
594 #else
595         Debug( LDAP_DEBUG_TRACE,
596                 "send_ldap_intermediate: err=%d oid=%s len=%ld\n",
597                 rs->sr_err,
598                 rs->sr_rspoid ? rs->sr_rspoid : "",
599                 rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 );
600 #endif
601         rs->sr_tag = LDAP_RES_INTERMEDIATE;
602         rs->sr_msgid = op->o_msgid;
603         send_ldap_response( op, rs );
604 }
605
606 int
607 slap_send_search_entry( Operation *op, SlapReply *rs )
608 {
609         BerElementBuffer berbuf;
610         BerElement      *ber = (BerElement *) &berbuf;
611         Attribute       *a, *aa;
612         int             i, j, rc=-1, bytes;
613         char            *edn;
614         int             userattrs;
615         int             opattrs;
616         AccessControlState acl_state = ACL_STATE_INIT;
617 #ifdef LDAP_SLAPI
618         /* Support for computed attribute plugins */
619         computed_attr_context    ctx;
620         AttributeName   *anp;
621 #endif
622         void            *mark = NULL;
623
624         AttributeDescription *ad_entry = slap_schema.si_ad_entry;
625
626         /* a_flags: array of flags telling if the i-th element will be
627          *          returned or filtered out
628          * e_flags: array of a_flags
629          */
630         char **e_flags = NULL;
631
632         rs->sr_type = REP_SEARCH;
633         if (op->o_callback && op->o_callback->sc_response) {
634                 rc = op->o_callback->sc_response( op, rs );
635                 if ( rc != SLAP_CB_CONTINUE ) return rc;
636         }
637
638 #ifdef NEW_LOGGING
639         LDAP_LOG( OPERATION, ENTRY, "send_search_entry: conn %lu        dn=\"%s\"%s\n",
640                 op->o_connid, rs->sr_entry->e_name.bv_val,
641                 op->ors_attrsonly ? " (attrsOnly)" : "" );
642 #else
643         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: dn=\"%s\"%s\n",
644                 rs->sr_entry->e_name.bv_val,
645                 op->ors_attrsonly ? " (attrsOnly)" : "", 0 );
646 #endif
647
648         mark = sl_mark( op->o_tmpmemctx );
649
650         if ( !access_allowed( op, rs->sr_entry, ad_entry, NULL, ACL_READ, NULL )) {
651 #ifdef NEW_LOGGING
652                 LDAP_LOG( ACL, INFO, 
653                         "send_search_entry: conn %lu access to entry (%s) not allowed\n", 
654                         op->o_connid, rs->sr_entry->e_name.bv_val, 0 );
655 #else
656                 Debug( LDAP_DEBUG_ACL,
657                         "send_search_entry: access to entry not allowed\n",
658                     0, 0, 0 );
659 #endif
660
661                 sl_release( mark, op->o_tmpmemctx );
662                 return( 1 );
663         }
664
665         edn = rs->sr_entry->e_nname.bv_val;
666
667         if ( op->o_res_ber ) {
668                 /* read back control or LDAP_CONNECTIONLESS */
669             ber = op->o_res_ber;
670         } else {
671                 ber_len_t       siz, len;
672                 struct berval   bv;
673
674                 entry_flatsize( rs->sr_entry, &siz, &len, 0 );
675                 bv.bv_len = siz + len;
676                 bv.bv_val = op->o_tmpalloc(bv.bv_len, op->o_tmpmemctx );
677
678                 ber_init2( ber, &bv, LBER_USE_DER );
679                 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
680         }
681
682 #ifdef LDAP_CONNECTIONLESS
683         if ( op->o_conn && op->o_conn->c_is_udp ) {
684                 /* CONNECTIONLESS */
685                 if ( op->o_protocol == LDAP_VERSION2 ) {
686                 rc = ber_printf(ber, "t{O{" /*}}*/,
687                                 LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
688                 } else {
689                 rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
690                                 LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
691                 }
692         } else
693 #endif
694         if ( op->o_res_ber ) {
695                 /* read back control */
696             rc = ber_printf( ber, "{O{" /*}}*/, &rs->sr_entry->e_name );
697         } else {
698             rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
699                         LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
700         }
701
702         if ( rc == -1 ) {
703 #ifdef NEW_LOGGING
704                 LDAP_LOG( OPERATION, ERR, 
705                         "send_search_entry: conn %lu  ber_printf failed\n", 
706                         op->o_connid, 0, 0 );
707 #else
708                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
709 #endif
710
711                 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
712                 send_ldap_error( op, rs, LDAP_OTHER, "encoding DN error" );
713                 goto error_return;
714         }
715
716         /* check for special all user attributes ("*") type */
717         userattrs = ( rs->sr_attrs == NULL ) ? 1
718                 : an_find( rs->sr_attrs, &AllUser );
719
720         /* check for special all operational attributes ("+") type */
721         opattrs = ( rs->sr_attrs == NULL ) ? 0
722                 : an_find( rs->sr_attrs, &AllOper );
723
724         /* create an array of arrays of flags. Each flag corresponds
725          * to particular value of attribute and equals 1 if value matches
726          * to ValuesReturnFilter or 0 if not
727          */     
728         if ( op->o_vrFilter != NULL ) {
729                 int     k = 0;
730                 size_t  size;
731
732                 for ( a = rs->sr_entry->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
733                         for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
734                 }
735
736                 size = i * sizeof(char *) + k;
737                 if ( size > 0 ) {
738                         char    *a_flags;
739                         e_flags = sl_calloc ( 1, i * sizeof(char *) + k, op->o_tmpmemctx );
740                         if( e_flags == NULL ) {
741 #ifdef NEW_LOGGING
742                                 LDAP_LOG( OPERATION, ERR, 
743                                         "send_search_entry: conn %lu sl_calloc failed\n",
744                                         op->o_connid ? op->o_connid : 0, 0, 0 );
745 #else
746                         Debug( LDAP_DEBUG_ANY, 
747                                         "send_search_entry: sl_calloc failed\n", 0, 0, 0 );
748 #endif
749                                 ber_free( ber, 1 );
750         
751                                 send_ldap_error( op, rs, LDAP_OTHER, "out of memory" );
752                                 goto error_return;
753                         }
754                         a_flags = (char *)(e_flags + i);
755                         memset( a_flags, 0, k );
756                         for ( a=rs->sr_entry->e_attrs, i=0; a != NULL; a=a->a_next, i++ ) {
757                                 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
758                                 e_flags[i] = a_flags;
759                                 a_flags += j;
760                         }
761         
762                         rc = filter_matched_values(op, rs->sr_entry->e_attrs, &e_flags) ; 
763                         if ( rc == -1 ) {
764 #ifdef NEW_LOGGING
765                                 LDAP_LOG( OPERATION, ERR, "send_search_entry: "
766                                         "conn %lu matched values filtering failed\n",
767                                         op->o_connid ? op->o_connid : 0, 0, 0 );
768 #else
769                         Debug( LDAP_DEBUG_ANY,
770                                         "matched values filtering failed\n", 0, 0, 0 );
771 #endif
772                                 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
773                                 send_ldap_error( op, rs, LDAP_OTHER,
774                                         "matched values filtering error" );
775                                 goto error_return;
776                         }
777                 }
778         }
779
780         for ( a = rs->sr_entry->e_attrs, j = 0; a != NULL; a = a->a_next, j++ ) {
781                 AttributeDescription *desc = a->a_desc;
782
783                 if ( rs->sr_attrs == NULL ) {
784                         /* all attrs request, skip operational attributes */
785                         if( is_at_operational( desc->ad_type ) ) {
786                                 continue;
787                         }
788
789                 } else {
790                         /* specific attrs requested */
791                         if ( is_at_operational( desc->ad_type ) ) {
792                                 if( !opattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
793                                         continue;
794                                 }
795
796                         } else {
797                                 if (!userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
798                                         continue;
799                                 }
800                         }
801                 }
802
803                 if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
804                         ACL_READ, &acl_state ) )
805                 {
806 #ifdef NEW_LOGGING
807                         LDAP_LOG( ACL, INFO, 
808                                 "send_search_entry: conn %lu  access to attribute %s not "
809                                 "allowed\n", op->o_connid, desc->ad_cname.bv_val, 0 );
810 #else
811                         Debug( LDAP_DEBUG_ACL, "acl: "
812                                 "access to attribute %s not allowed\n",
813                             desc->ad_cname.bv_val, 0, 0 );
814 #endif
815                         continue;
816                 }
817
818                 if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) {
819 #ifdef NEW_LOGGING
820                         LDAP_LOG( OPERATION, ERR, 
821                                 "send_search_entry: conn %lu  ber_printf failed\n", 
822                                 op->o_connid, 0, 0 );
823 #else
824                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
825 #endif
826
827                         if ( op->o_res_ber == NULL ) ber_free_buf( ber );
828                         send_ldap_error( op, rs, LDAP_OTHER, "encoding description error");
829                         goto error_return;
830                 }
831
832                 if ( ! op->ors_attrsonly ) {
833                         for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) {
834                                 if ( ! access_allowed( op, rs->sr_entry,
835                                         desc, &a->a_vals[i], ACL_READ, &acl_state ) )
836                                 {
837 #ifdef NEW_LOGGING
838                                         LDAP_LOG( ACL, INFO, 
839                                                 "send_search_entry: conn %lu "
840                                                 "access to attribute %s, value %d not allowed\n",
841                                                 op->o_connid, desc->ad_cname.bv_val, i );
842 #else
843                                         Debug( LDAP_DEBUG_ACL,
844                                                 "acl: access to attribute %s, "
845                                                 "value %d not allowed\n",
846                                                 desc->ad_cname.bv_val, i, 0 );
847 #endif
848
849                                         continue;
850                                 }
851
852                                 if ( op->o_vrFilter && e_flags[j][i] == 0 ){
853                                         continue;
854                                 }
855
856                                 if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
857 #ifdef NEW_LOGGING
858                                         LDAP_LOG( OPERATION, ERR, 
859                                                 "send_search_entry: conn %lu  "
860                                                 "ber_printf failed.\n", op->o_connid, 0, 0 );
861 #else
862                                         Debug( LDAP_DEBUG_ANY,
863                                             "ber_printf failed\n", 0, 0, 0 );
864 #endif
865
866                                         if ( op->o_res_ber == NULL ) ber_free_buf( ber );
867                                         send_ldap_error( op, rs, LDAP_OTHER,
868                                                 "encoding values error" );
869                                         goto error_return;
870                                 }
871                         }
872                 }
873
874                 if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
875 #ifdef NEW_LOGGING
876                         LDAP_LOG( OPERATION, ERR, 
877                                 "send_search_entry: conn %lu ber_printf failed\n", 
878                                 op->o_connid, 0, 0 );
879 #else
880                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
881 #endif
882
883                         if ( op->o_res_ber == NULL ) ber_free_buf( ber );
884                         send_ldap_error( op, rs, LDAP_OTHER, "encode end error" );
885                         goto error_return;
886                 }
887         }
888
889         /* eventually will loop through generated operational attributes */
890         /* only have subschemaSubentry and numSubordinates are implemented */
891         aa = backend_operational( op, rs, opattrs );
892
893         if ( aa != NULL && op->o_vrFilter != NULL ) {
894                 int     k = 0;
895                 size_t  size;
896
897                 for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) {
898                         for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
899                 }
900
901                 size = i * sizeof(char *) + k;
902                 if ( size > 0 ) {
903                         char    *a_flags, **tmp;
904                 
905                         /*
906                          * Reuse previous memory - we likely need less space
907                          * for operational attributes
908                          */
909                         tmp = sl_realloc( e_flags, i * sizeof(char *) + k,
910                                 op->o_tmpmemctx );
911                         if ( tmp == NULL ) {
912 #ifdef NEW_LOGGING
913                                 LDAP_LOG( OPERATION, ERR, 
914                                         "send_search_entry: conn %lu "
915                                         "not enough memory "
916                                         "for matched values filtering\n", 
917                                         op->o_connid, 0, 0);
918 #else
919                                 Debug( LDAP_DEBUG_ANY,
920                                         "send_search_entry: conn %lu "
921                                         "not enough memory "
922                                         "for matched values filtering\n",
923                                         op->o_connid, 0, 0 );
924 #endif
925                                 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
926                                 send_ldap_error( op, rs, LDAP_OTHER,
927                                         "not enough memory for matched values filtering" );
928                                 goto error_return;
929                         }
930                         e_flags = tmp;
931                         a_flags = (char *)(e_flags + i);
932                         memset( a_flags, 0, k );
933                         for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) {
934                                 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
935                                 e_flags[i] = a_flags;
936                                 a_flags += j;
937                         }
938                         rc = filter_matched_values(op, aa, &e_flags) ; 
939                     
940                         if ( rc == -1 ) {
941 #ifdef NEW_LOGGING
942                                 LDAP_LOG( OPERATION, ERR, 
943                                         "send_search_entry: conn %lu "
944                                         "matched values filtering failed\n", 
945                                         op->o_connid ? op->o_connid : 0, 0, 0);
946 #else
947                                 Debug( LDAP_DEBUG_ANY,
948                                         "matched values filtering failed\n", 0, 0, 0 );
949 #endif
950                                 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
951                                 send_ldap_error( op, rs, LDAP_OTHER,
952                                         "matched values filtering error" );
953                                 goto error_return;
954                         }
955                 }
956         }
957
958         for (a = aa, j=0; a != NULL; a = a->a_next, j++ ) {
959                 AttributeDescription *desc = a->a_desc;
960
961                 if ( rs->sr_attrs == NULL ) {
962                         /* all attrs request, skip operational attributes */
963                         if( is_at_operational( desc->ad_type ) ) {
964                                 continue;
965                         }
966
967                 } else {
968                         /* specific attrs requested */
969                         if( is_at_operational( desc->ad_type ) ) {
970                                 if( !opattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
971                                         continue;
972                                 }
973                         } else {
974                                 if (!userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
975                                         continue;
976                                 }
977                         }
978                 }
979
980                 if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
981                         ACL_READ, &acl_state ) )
982                 {
983 #ifdef NEW_LOGGING
984                         LDAP_LOG( ACL, INFO, 
985                                 "send_search_entry: conn %lu "
986                                 "access to attribute %s not allowed\n",
987                                 op->o_connid, desc->ad_cname.bv_val, 0 );
988 #else
989                         Debug( LDAP_DEBUG_ACL, "send_search_entry: access to attribute %s "
990                                 "not allowed\n", desc->ad_cname.bv_val, 0, 0 );
991 #endif
992
993                         continue;
994                 }
995
996                 rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname );
997                 if ( rc == -1 ) {
998 #ifdef NEW_LOGGING
999                         LDAP_LOG( OPERATION, ERR, 
1000                                 "send_search_entry: conn %lu  "
1001                                 "ber_printf failed\n", op->o_connid, 0, 0 );
1002 #else
1003                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
1004 #endif
1005
1006                         if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1007                         send_ldap_error( op, rs, LDAP_OTHER, "encoding description error" );
1008                         attrs_free( aa );
1009                         goto error_return;
1010                 }
1011
1012                 if ( ! op->ors_attrsonly ) {
1013                         for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) {
1014                                 if ( ! access_allowed( op, rs->sr_entry,
1015                                         desc, &a->a_vals[i], ACL_READ, &acl_state ) )
1016                                 {
1017 #ifdef NEW_LOGGING
1018                                         LDAP_LOG( ACL, INFO, 
1019                                                 "send_search_entry: conn %lu "
1020                                                 "access to %s, value %d not allowed\n",
1021                                                 op->o_connid, desc->ad_cname.bv_val, i );
1022 #else
1023                                         Debug( LDAP_DEBUG_ACL,
1024                                                 "send_search_entry: access to attribute %s, "
1025                                                 "value %d not allowed\n",
1026                                                 desc->ad_cname.bv_val, i, 0 );
1027 #endif
1028
1029                                         continue;
1030                                 }
1031
1032                                 if ( op->o_vrFilter && e_flags[j][i] == 0 ){
1033                                         continue;
1034                                 }
1035
1036                                 if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
1037 #ifdef NEW_LOGGING
1038                                         LDAP_LOG( OPERATION, ERR, 
1039                                                 "send_search_entry: conn %lu  ber_printf failed\n", 
1040                                                 op->o_connid, 0, 0 );
1041 #else
1042                                         Debug( LDAP_DEBUG_ANY,
1043                                             "ber_printf failed\n", 0, 0, 0 );
1044 #endif
1045
1046                                         if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1047                                         send_ldap_error( op, rs, LDAP_OTHER,
1048                                                 "encoding values error" );
1049                                         attrs_free( aa );
1050                                         goto error_return;
1051                                 }
1052                         }
1053                 }
1054
1055                 if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
1056 #ifdef NEW_LOGGING
1057                         LDAP_LOG( OPERATION, ERR, 
1058                                 "send_search_entry: conn %lu  ber_printf failed\n",
1059                                 op->o_connid, 0, 0 );
1060 #else
1061                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
1062 #endif
1063
1064                         if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1065                         send_ldap_error( op, rs, LDAP_OTHER, "encode end error" );
1066                         attrs_free( aa );
1067                         goto error_return;
1068                 }
1069         }
1070
1071 #ifdef LDAP_SLAPI
1072         /*
1073          * First, setup the computed attribute context that is
1074          * passed to all plugins.
1075          */
1076         if ( op->o_pb ) {
1077                 ctx.cac_pb = op->o_pb;
1078                 ctx.cac_attrs = rs->sr_attrs;
1079                 ctx.cac_attrsonly = op->ors_attrsonly;
1080                 ctx.cac_userattrs = userattrs;
1081                 ctx.cac_opattrs = opattrs;
1082                 ctx.cac_acl_state = acl_state;
1083                 ctx.cac_private = (void *)ber;
1084
1085                 /*
1086                  * For each client requested attribute, call the plugins.
1087                  */
1088                 if ( rs->sr_attrs != NULL ) {
1089                         for ( anp = rs->sr_attrs; anp->an_name.bv_val != NULL; anp++ ) {
1090                                 rc = compute_evaluator( &ctx, anp->an_name.bv_val,
1091                                         rs->sr_entry, slapi_x_compute_output_ber );
1092                                 if ( rc == 1 ) {
1093                                         break;
1094                                 }
1095                         }
1096                 } else {
1097                         /*
1098                          * Technically we shouldn't be returning operational attributes
1099                          * when the user requested only user attributes. We'll let the
1100                          * plugin decide whether to be naughty or not.
1101                          */
1102                         rc = compute_evaluator( &ctx, "*",
1103                                 rs->sr_entry, slapi_x_compute_output_ber );
1104                 }
1105                 if ( rc == 1 ) {
1106                         if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1107                         send_ldap_error( op, rs, LDAP_OTHER, "computed attribute error" );
1108                         goto error_return;
1109                 }
1110         }
1111 #endif /* LDAP_SLAPI */
1112
1113         /* free e_flags */
1114         if ( e_flags ) {
1115                 sl_free( e_flags, op->o_tmpmemctx );
1116                 e_flags = NULL;
1117         }
1118
1119         attrs_free( aa );
1120         rc = ber_printf( ber, /*{{*/ "}N}" );
1121
1122         if( rc != -1 && rs->sr_ctrls != NULL ) {
1123                 rc = send_ldap_controls( ber, rs->sr_ctrls );
1124         }
1125
1126         if( rc != -1 ) {
1127 #ifdef LDAP_CONNECTIONLESS
1128                 if( op->o_conn && op->o_conn->c_is_udp ) {
1129                         if ( op->o_protocol != LDAP_VERSION2 ) {
1130                                 rc = ber_printf( ber, /*{*/ "N}" );
1131                         }
1132                 } else
1133 #endif
1134                 if ( op->o_res_ber == NULL ) {
1135                         rc = ber_printf( ber, /*{*/ "N}" );
1136                 }
1137         }
1138
1139         if ( rc == -1 ) {
1140 #ifdef NEW_LOGGING
1141                 LDAP_LOG( OPERATION, ERR, 
1142                         "send_search_entry: conn %lu ber_printf failed\n", 
1143                         op->o_connid, 0, 0 );
1144 #else
1145                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
1146 #endif
1147
1148                 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1149                 send_ldap_error( op, rs, LDAP_OTHER, "encode entry end error" );
1150                 sl_release( mark, op->o_tmpmemctx );
1151                 return( 1 );
1152         }
1153
1154         if ( op->o_res_ber == NULL ) {
1155                 bytes = op->o_noop ? 0 : send_ldap_ber( op->o_conn, ber );
1156                 ber_free_buf( ber );
1157
1158                 if ( bytes < 0 ) {
1159 #ifdef NEW_LOGGING
1160                         LDAP_LOG( OPERATION, ERR, 
1161                                 "send_search_entry: conn %lu  ber write failed.\n", 
1162                                 op->o_connid, 0, 0 );
1163 #else
1164                         Debug( LDAP_DEBUG_ANY,
1165                                 "send_search_entry: ber write failed\n",
1166                                 0, 0, 0 );
1167 #endif
1168
1169                         sl_release( mark, op->o_tmpmemctx );
1170                         return -1;
1171                 }
1172                 rs->sr_nentries++;
1173
1174                 ldap_pvt_thread_mutex_lock( &num_sent_mutex );
1175                 num_bytes_sent += bytes;
1176                 num_entries_sent++;
1177                 num_pdu_sent++;
1178                 ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
1179         }
1180
1181         Statslog( LDAP_DEBUG_STATS2, "conn=%lu op=%lu ENTRY dn=\"%s\"\n",
1182             op->o_connid, op->o_opid, rs->sr_entry->e_dn, 0, 0 );
1183
1184 #ifdef NEW_LOGGING
1185         LDAP_LOG( OPERATION, ENTRY, 
1186                 "send_search_entry: conn %lu exit.\n", op->o_connid, 0, 0 );
1187 #else
1188         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
1189 #endif
1190
1191         rc = 0;
1192
1193 error_return:;
1194         sl_release( mark, op->o_tmpmemctx );
1195         if ( e_flags ) sl_free( e_flags, op->o_tmpmemctx );
1196         return( rc );
1197 }
1198
1199 int
1200 slap_send_search_reference( Operation *op, SlapReply *rs )
1201 {
1202         BerElementBuffer berbuf;
1203         BerElement      *ber = (BerElement *) &berbuf;
1204         int rc = 0;
1205         int bytes;
1206         void *mark;
1207
1208         AttributeDescription *ad_ref = slap_schema.si_ad_ref;
1209         AttributeDescription *ad_entry = slap_schema.si_ad_entry;
1210
1211         rs->sr_type = REP_SEARCHREF;
1212         if (op->o_callback && op->o_callback->sc_response) {
1213                 rc = op->o_callback->sc_response( op, rs );
1214                 if ( rc != SLAP_CB_CONTINUE ) return rc;
1215         }
1216
1217         mark = sl_mark( op->o_tmpmemctx );
1218
1219 #ifdef NEW_LOGGING
1220         LDAP_LOG( OPERATION, ENTRY, 
1221                 "send_search_reference: conn %lu  dn=\"%s\"\n", 
1222                 op->o_connid,
1223                 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "(null)", 0 );
1224 #else
1225         Debug( LDAP_DEBUG_TRACE,
1226                 "=> send_search_reference: dn=\"%s\"\n",
1227                 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "(null)", 0, 0 );
1228 #endif
1229
1230         if (  rs->sr_entry && ! access_allowed( op, rs->sr_entry,
1231                 ad_entry, NULL, ACL_READ, NULL ) )
1232         {
1233 #ifdef NEW_LOGGING
1234                 LDAP_LOG( ACL, INFO, 
1235                         "send_search_reference: conn %lu        "
1236                         "access to entry %s not allowed\n",
1237                         op->o_connid, rs->sr_entry->e_dn, 0 );
1238 #else
1239                 Debug( LDAP_DEBUG_ACL,
1240                         "send_search_reference: access to entry not allowed\n",
1241                     0, 0, 0 );
1242 #endif
1243                 rc = 1;
1244                 goto rel;
1245         }
1246
1247         if ( rs->sr_entry && ! access_allowed( op, rs->sr_entry,
1248                 ad_ref, NULL, ACL_READ, NULL ) )
1249         {
1250 #ifdef NEW_LOGGING
1251                 LDAP_LOG( ACL, INFO, 
1252                         "send_search_reference: conn %lu access "
1253                         "to reference not allowed.\n", op->o_connid, 0, 0 );
1254 #else
1255                 Debug( LDAP_DEBUG_ACL,
1256                         "send_search_reference: access "
1257                         "to reference not allowed\n",
1258                     0, 0, 0 );
1259 #endif
1260                 rc = 1;
1261                 goto rel;
1262         }
1263
1264 #ifdef LDAP_CONTROL_X_DOMAIN_SCOPE
1265         if( op->o_domain_scope ) {
1266 #ifdef NEW_LOGGING
1267                 LDAP_LOG( OPERATION, ERR, 
1268                         "send_search_reference: conn %lu domainScope control in (%s).\n",
1269                         op->o_connid, rs->sr_entry->e_dn, 0 );
1270 #else
1271                 Debug( LDAP_DEBUG_ANY,
1272                         "send_search_reference: domainScope control in (%s)\n", 
1273                         rs->sr_entry->e_dn, 0, 0 );
1274 #endif
1275                 rc = 0;
1276                 goto rel;
1277         }
1278 #endif
1279
1280         if( rs->sr_ref == NULL ) {
1281 #ifdef NEW_LOGGING
1282                 LDAP_LOG( OPERATION, ERR, 
1283                         "send_search_reference: conn %lu null ref in (%s).\n",
1284                         op->o_connid, rs->sr_entry ? rs->sr_entry->e_dn : "(null)", 0 );
1285 #else
1286                 Debug( LDAP_DEBUG_ANY,
1287                         "send_search_reference: null ref in (%s)\n", 
1288                         rs->sr_entry ? rs->sr_entry->e_dn : "(null)", 0, 0 );
1289 #endif
1290                 rc = 1;
1291                 goto rel;
1292         }
1293
1294         if( op->o_protocol < LDAP_VERSION3 ) {
1295                 /* save the references for the result */
1296                 if( rs->sr_ref[0].bv_val != NULL ) {
1297                         if( value_add( &rs->sr_v2ref, rs->sr_ref ) )
1298                                 return LDAP_OTHER;
1299                 }
1300                 rc = 0;
1301                 goto rel;
1302         }
1303
1304 #ifdef LDAP_CONNECTIONLESS
1305         if( op->o_conn && op->o_conn->c_is_udp ) {
1306                 ber = op->o_res_ber;
1307         } else
1308 #endif
1309         {
1310                 ber_init_w_nullc( ber, LBER_USE_DER );
1311                 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
1312         }
1313
1314         rc = ber_printf( ber, "{it{W}" /*"}"*/ , op->o_msgid,
1315                 LDAP_RES_SEARCH_REFERENCE, rs->sr_ref );
1316
1317         if( rc != -1 && rs->sr_ctrls != NULL ) {
1318                 rc = send_ldap_controls( ber, rs->sr_ctrls );
1319         }
1320
1321         if( rc != -1 ) {
1322                 rc = ber_printf( ber, /*"{"*/ "N}" );
1323         }
1324
1325         if ( rc == -1 ) {
1326 #ifdef NEW_LOGGING
1327                 LDAP_LOG( OPERATION, ERR, 
1328                         "send_search_reference: conn %lu        "
1329                         "ber_printf failed.\n", op->o_connid, 0, 0 );
1330 #else
1331                 Debug( LDAP_DEBUG_ANY,
1332                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
1333 #endif
1334
1335 #ifdef LDAP_CONNECTIONLESS
1336                 if (!op->o_conn || op->o_conn->c_is_udp == 0)
1337 #endif
1338                 ber_free_buf( ber );
1339                 send_ldap_error( op, rs, LDAP_OTHER, "encode DN error" );
1340                 goto rel;
1341         }
1342
1343 #ifdef LDAP_CONNECTIONLESS
1344         if (!op->o_conn || op->o_conn->c_is_udp == 0) {
1345 #endif
1346         bytes = op->o_noop ? 0 : send_ldap_ber( op->o_conn, ber );
1347         ber_free_buf( ber );
1348
1349         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
1350         num_bytes_sent += bytes;
1351         num_refs_sent++;
1352         num_pdu_sent++;
1353         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
1354 #ifdef LDAP_CONNECTIONLESS
1355         }
1356 #endif
1357
1358         Statslog( LDAP_DEBUG_STATS2, "conn=%lu op=%lu REF dn=\"%s\"\n",
1359                 op->o_connid, op->o_opid, rs->sr_entry ? rs->sr_entry->e_dn : "(null)", 0, 0 );
1360
1361 #ifdef NEW_LOGGING
1362         LDAP_LOG( OPERATION, ENTRY, 
1363                 "send_search_reference: conn %lu exit.\n", op->o_connid, 0, 0 );
1364 #else
1365         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
1366 #endif
1367
1368 rel:
1369         sl_release( mark, op->o_tmpmemctx );
1370         return rc;
1371 }
1372
1373 int
1374 str2result(
1375     char        *s,
1376     int         *code,
1377     char        **matched,
1378     char        **info
1379 )
1380 {
1381         int     rc;
1382         char    *c;
1383
1384         *code = LDAP_SUCCESS;
1385         *matched = NULL;
1386         *info = NULL;
1387
1388         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
1389 #ifdef NEW_LOGGING
1390                 LDAP_LOG( OPERATION, INFO, 
1391                         "str2result: (%s), expecting \"RESULT\"\n", s, 0, 0 );
1392 #else
1393                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
1394                     s, 0, 0 );
1395 #endif
1396
1397                 return( -1 );
1398         }
1399
1400         rc = 0;
1401         while ( (s = strchr( s, '\n' )) != NULL ) {
1402                 *s++ = '\0';
1403                 if ( *s == '\0' ) {
1404                         break;
1405                 }
1406                 if ( (c = strchr( s, ':' )) != NULL ) {
1407                         c++;
1408                 }
1409
1410                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
1411                         if ( c != NULL ) {
1412                                 *code = atoi( c );
1413                         }
1414                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
1415                         if ( c != NULL ) {
1416                                 *matched = c;
1417                         }
1418                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
1419                         if ( c != NULL ) {
1420                                 *info = c;
1421                         }
1422                 } else {
1423 #ifdef NEW_LOGGING
1424                         LDAP_LOG( OPERATION, INFO, "str2result: (%s) unknown.\n", s, 0, 0 );
1425 #else
1426                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
1427                             s, 0, 0 );
1428 #endif
1429
1430                         rc = -1;
1431                 }
1432         }
1433
1434         return( rc );
1435 }
1436
1437 int slap_read_controls(
1438         Operation *op,
1439         SlapReply *rs,
1440         Entry *e,
1441         const struct berval *oid,
1442         LDAPControl **ctrl )
1443 {
1444         int rc;
1445         struct berval bv;
1446         BerElementBuffer berbuf;
1447         BerElement *ber = (BerElement *) &berbuf;
1448         LDAPControl c;
1449         ber_len_t       siz, len;
1450         Operation myop;
1451
1452 #ifdef NEW_LOGGING
1453         LDAP_LOG( OPERATION, INFO, "slap_read_controls: (%s) %s\n",
1454                 oid->bv_val, e->e_dn, 0 );
1455 #else
1456         Debug( LDAP_DEBUG_ANY, "slap_read_controls: (%s) %s\n",
1457                 oid->bv_val, e->e_dn, 0 );
1458 #endif
1459
1460         rs->sr_entry = e;
1461         rs->sr_attrs = ( oid == &slap_pre_read_bv ) ?
1462                 op->o_preread_attrs : op->o_postread_attrs; 
1463
1464         entry_flatsize( rs->sr_entry, &siz, &len, 0 );
1465         bv.bv_len = siz + len;
1466         bv.bv_val = op->o_tmpalloc(bv.bv_len, op->o_tmpmemctx );
1467
1468         ber_init2( ber, &bv, LBER_USE_DER );
1469         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
1470
1471         /* create new operation */
1472         myop = *op;
1473         myop.o_bd = NULL;
1474         myop.o_res_ber = ber;
1475
1476         rc = slap_send_search_entry( &myop, rs );
1477         if( rc ) return rc;
1478
1479         rc = ber_flatten2( ber, &c.ldctl_value, 0 );
1480
1481         if( rc == LBER_ERROR ) return LDAP_OTHER;
1482
1483         c.ldctl_oid = oid->bv_val;
1484         c.ldctl_iscritical = 0;
1485
1486         *ctrl = sl_calloc( 1, sizeof(LDAPControl), NULL );
1487         **ctrl = c;
1488         return LDAP_SUCCESS;
1489 }