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