1 /* $NetBSD: result.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */
2
3 /* result.c - routines to send ldap results, errors, and referrals */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1998-2021 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms are permitted
22 * provided that this notice is preserved and that due credit is given
23 * to the University of Michigan at Ann Arbor. The name of the University
24 * may not be used to endorse or promote products derived from this
25 * software without specific prior written permission. This software
26 * is provided ``as is'' without express or implied warranty.
27 */
28
29 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: result.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
31
32 #include "portable.h"
33
34 #include <stdio.h>
35
36 #include <ac/socket.h>
37 #include <ac/errno.h>
38 #include <ac/string.h>
39 #include <ac/ctype.h>
40 #include <ac/time.h>
41 #include <ac/unistd.h>
42
43 #include "slap.h"
44
45 #if SLAP_STATS_ETIME
46 #define ETIME_SETUP \
47 struct timeval now; \
48 char timestr[64]; \
49 (void) gettimeofday( &now, NULL ); \
50 now.tv_sec -= op->o_time; \
51 now.tv_usec -= op->o_tusec; \
52 if ( now.tv_usec < 0 ) { \
53 --now.tv_sec; now.tv_usec += 1000000; \
54 } \
55 sprintf(timestr, "qtime=%d.%06d etime=%d.%06d", \
56 (int)op->o_qtime.tv_sec, (int)op->o_qtime.tv_usec, \
57 (int)now.tv_sec, (int)now.tv_usec);
58 #define ETIME_LOGFMT "%s "
59 #define StatslogEtime(lvl,fmt,pfx,tag,err,...) \
60 Debug(lvl,fmt,pfx,tag,err,timestr,__VA_ARGS__)
61 #else
62 #define ETIME_SETUP
63 #define ETIME_LOGFMT ""
64 #define StatslogEtime Debug
65 #endif /* SLAP_STATS_ETIME */
66
67 const struct berval slap_dummy_bv = BER_BVNULL;
68
slap_null_cb(Operation * op,SlapReply * rs)69 int slap_null_cb( Operation *op, SlapReply *rs )
70 {
71 return 0;
72 }
73
slap_freeself_cb(Operation * op,SlapReply * rs)74 int slap_freeself_cb( Operation *op, SlapReply *rs )
75 {
76 assert( op->o_callback != NULL );
77
78 op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
79 op->o_callback = NULL;
80
81 return SLAP_CB_CONTINUE;
82 }
83
v2ref(BerVarray ref,const char * text)84 static char *v2ref( BerVarray ref, const char *text )
85 {
86 size_t len = 0, i = 0;
87 char *v2;
88
89 if(ref == NULL) {
90 if (text) {
91 return ch_strdup(text);
92 } else {
93 return NULL;
94 }
95 }
96
97 if ( text != NULL ) {
98 len = strlen( text );
99 if (text[len-1] != '\n') {
100 i = 1;
101 }
102 }
103
104 v2 = ch_malloc( len+i+sizeof("Referral:") );
105
106 if( text != NULL ) {
107 strcpy(v2, text);
108 if( i ) {
109 v2[len++] = '\n';
110 }
111 }
112 strcpy( v2+len, "Referral:" );
113 len += sizeof("Referral:");
114
115 for( i=0; ref[i].bv_val != NULL; i++ ) {
116 v2 = ch_realloc( v2, len + ref[i].bv_len + 1 );
117 v2[len-1] = '\n';
118 AC_MEMCPY(&v2[len], ref[i].bv_val, ref[i].bv_len );
119 len += ref[i].bv_len;
120 if (ref[i].bv_val[ref[i].bv_len-1] != '/') {
121 ++len;
122 }
123 }
124
125 v2[len-1] = '\0';
126 return v2;
127 }
128
129 ber_tag_t
slap_req2res(ber_tag_t tag)130 slap_req2res( ber_tag_t tag )
131 {
132 switch( tag ) {
133 case LDAP_REQ_ADD:
134 case LDAP_REQ_BIND:
135 case LDAP_REQ_COMPARE:
136 case LDAP_REQ_EXTENDED:
137 case LDAP_REQ_MODIFY:
138 case LDAP_REQ_MODRDN:
139 tag++;
140 break;
141
142 case LDAP_REQ_DELETE:
143 tag = LDAP_RES_DELETE;
144 break;
145
146 case LDAP_REQ_ABANDON:
147 case LDAP_REQ_UNBIND:
148 tag = LBER_SEQUENCE;
149 break;
150
151 case LDAP_REQ_SEARCH:
152 tag = LDAP_RES_SEARCH_RESULT;
153 break;
154
155 default:
156 tag = LBER_SEQUENCE;
157 }
158
159 return tag;
160 }
161
162 /*
163 * SlapReply debugging enabled by USE_RS_ASSERT.
164 *
165 * Disabled by default, but compiled in (but still unused) when
166 * LDAP_TEST. #define USE_RS_ASSERT as nonzero to enable some
167 * assertions which check the SlapReply. USE_RS_ASSERT = 2 or higher
168 * check aggressively, currently some code fail these tests.
169 *
170 * Environment variable $NO_RS_ASSERT controls how USE_RS_ASSERT handles
171 * errors. > 0: ignore errors, 0: abort (the default), < 0: just warn.
172 *
173 * Wrap LDAP operation calls in macros SLAP_OP() & co from proto-slap.h
174 * to check the SlapReply. contrib/slapd-tools/wrap_slap_ops converts
175 * source code to use the macros.
176 */
177 #if defined(LDAP_TEST) || (defined(USE_RS_ASSERT) && (USE_RS_ASSERT))
178
179 int rs_suppress_assert = 0;
180
181 /* RS_ASSERT() helper function */
rs_assert_(const char * file,unsigned line,const char * fn,const char * cond)182 void rs_assert_(const char*file, unsigned line, const char*fn, const char*cond)
183 {
184 int no_assert = rs_suppress_assert, save_errno = errno;
185 const char *s;
186
187 if ( no_assert >= 0 ) {
188 if ( no_assert == 0 && (s = getenv( "NO_RS_ASSERT" )) && *s ) {
189 no_assert = rs_suppress_assert = atoi( s );
190 }
191 if ( no_assert > 0 ) {
192 errno = save_errno;
193 return;
194 }
195 }
196
197 #ifdef rs_assert_ /* proto-slap.h #defined away the fn parameter */
198 fprintf( stderr,"%s:%u: " "RS_ASSERT(%s) failed.\n", file,line,cond );
199 #else
200 fprintf( stderr,"%s:%u: %s: RS_ASSERT(%s) failed.\n", file,line,fn,cond );
201 #endif
202 fflush( stderr );
203
204 errno = save_errno;
205 /* $NO_RS_ASSERT > 0: ignore rs_asserts, 0: abort, < 0: just warn */
206 if ( !no_assert /* from $NO_RS_ASSERT */ ) abort();
207 }
208
209 /* SlapReply is consistent */
210 void
211 (rs_assert_ok)( const SlapReply *rs )
212 {
213 const slap_mask_t flags = rs->sr_flags;
214
215 if ( flags & REP_ENTRY_MASK ) {
216 RS_ASSERT( !(flags & REP_ENTRY_MUSTRELEASE)
217 || !(flags & (REP_ENTRY_MASK ^ REP_ENTRY_MUSTRELEASE)) );
218 RS_ASSERT( rs->sr_entry != NULL );
219 RS_ASSERT( (1 << rs->sr_type) &
220 ((1 << REP_SEARCH) | (1 << REP_SEARCHREF) |
221 (1 << REP_RESULT) | (1 << REP_GLUE_RESULT)) );
222 }
223 #if defined(USE_RS_ASSERT) && (USE_RS_ASSERT) > 1 /* TODO: Enable when safe */
224 if ( (flags & (REP_MATCHED_MASK | REP_REF_MASK | REP_CTRLS_MASK)) ) {
225 RS_ASSERT( !(flags & REP_MATCHED_MASK) || rs->sr_matched );
226 RS_ASSERT( !(flags & REP_CTRLS_MASK ) || rs->sr_ctrls );
227 /* Note: LDAP_REFERRAL + !sr_ref is OK, becomes LDAP_NO_SUCH_OBJECT */
228 }
229 #if (USE_RS_ASSERT) > 2
230 if ( rs->sr_err == LDAP_SUCCESS ) {
231 RS_ASSERT( rs->sr_text == NULL );
232 RS_ASSERT( rs->sr_matched == NULL );
233 }
234 #endif
235 #endif
236 }
237
238 /* Ready for calling a new backend operation */
239 void
240 (rs_assert_ready)( const SlapReply *rs )
241 {
242 RS_ASSERT( !rs->sr_entry );
243 #if defined(USE_RS_ASSERT) && (USE_RS_ASSERT) > 1 /* TODO: Enable when safe */
244 RS_ASSERT( !rs->sr_text );
245 RS_ASSERT( !rs->sr_ref );
246 RS_ASSERT( !rs->sr_matched );
247 RS_ASSERT( !rs->sr_ctrls );
248 RS_ASSERT( !rs->sr_flags );
249 #if (USE_RS_ASSERT) > 2
250 RS_ASSERT( rs->sr_err == LDAP_SUCCESS );
251 #endif
252 #else
253 RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
254 #endif
255 }
256
257 /* Backend operation done */
258 void
259 (rs_assert_done)( const SlapReply *rs )
260 {
261 #if defined(USE_RS_ASSERT) && (USE_RS_ASSERT) > 1 /* TODO: Enable when safe */
262 RS_ASSERT( !(rs->sr_flags & ~(REP_ENTRY_MODIFIABLE|REP_NO_OPERATIONALS)) );
263 rs_assert_ok( rs );
264 #else
265 RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MUSTFLUSH) );
266 #endif
267 }
268
269 #endif /* LDAP_TEST || USE_RS_ASSERT */
270
271 /* Reset a used SlapReply whose contents has been flushed (freed/released) */
272 void
273 (rs_reinit)( SlapReply *rs, slap_reply_t type )
274 {
275 rs_reinit( rs, type ); /* proto-slap.h macro */
276 }
277
278 /* Obey and clear rs->sr_flags & REP_ENTRY_MASK. Clear sr_entry if freed. */
279 void
rs_flush_entry(Operation * op,SlapReply * rs,slap_overinst * on)280 rs_flush_entry( Operation *op, SlapReply *rs, slap_overinst *on )
281 {
282 rs_assert_ok( rs );
283
284 if ( (rs->sr_flags & REP_ENTRY_MUSTFLUSH) && rs->sr_entry != NULL ) {
285 if ( !(rs->sr_flags & REP_ENTRY_MUSTRELEASE) ) {
286 entry_free( rs->sr_entry );
287 } else if ( on != NULL ) {
288 overlay_entry_release_ov( op, rs->sr_entry, 0, on );
289 } else {
290 be_entry_release_rw( op, rs->sr_entry, 0 );
291 }
292 rs->sr_entry = NULL;
293 }
294
295 rs->sr_flags &= ~REP_ENTRY_MASK;
296 }
297
298 /* Set rs->sr_entry after obeying and clearing sr_flags & REP_ENTRY_MASK. */
299 void
rs_replace_entry(Operation * op,SlapReply * rs,slap_overinst * on,Entry * e)300 rs_replace_entry( Operation *op, SlapReply *rs, slap_overinst *on, Entry *e )
301 {
302 rs_flush_entry( op, rs, on );
303 rs->sr_entry = e;
304 }
305
306 /*
307 * Ensure rs->sr_entry is modifiable, by duplicating it if necessary.
308 * Obey sr_flags. Set REP_ENTRY_<MODIFIABLE, and MUSTBEFREED if duplicated>.
309 * Return nonzero if rs->sr_entry was replaced.
310 */
311 int
rs_entry2modifiable(Operation * op,SlapReply * rs,slap_overinst * on)312 rs_entry2modifiable( Operation *op, SlapReply *rs, slap_overinst *on )
313 {
314 if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) {
315 rs_assert_ok( rs );
316 return 0;
317 }
318 rs_replace_entry( op, rs, on, entry_dup( rs->sr_entry ));
319 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
320 return 1;
321 }
322
323 /* Check for any callbacks that want to be informed about being blocked
324 * on output. These callbacks are expected to leave the callback list
325 * unmodified. Their result is ignored.
326 */
327 static void
slap_writewait_play(Operation * op)328 slap_writewait_play(
329 Operation *op )
330 {
331 slap_callback *sc = op->o_callback;
332
333 for ( ; sc; sc = sc->sc_next ) {
334 if ( sc->sc_writewait )
335 sc->sc_writewait( op, sc );
336 }
337 }
338
send_ldap_ber(Operation * op,BerElement * ber)339 static long send_ldap_ber(
340 Operation *op,
341 BerElement *ber )
342 {
343 Connection *conn = op->o_conn;
344 ber_len_t bytes;
345 long ret = 0;
346 char *close_reason;
347 int do_resume = 0;
348
349 ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes );
350
351 /* write only one pdu at a time - wait til it's our turn */
352 ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
353 if (( op->o_abandon && !op->o_cancel ) || !connection_valid( conn ) ||
354 conn->c_writers < 0 ) {
355 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
356 return 0;
357 }
358
359 conn->c_writers++;
360
361 while ( conn->c_writers > 0 && conn->c_writing ) {
362 ldap_pvt_thread_pool_idle( &connection_pool );
363 ldap_pvt_thread_cond_wait( &conn->c_write1_cv, &conn->c_write1_mutex );
364 ldap_pvt_thread_pool_unidle( &connection_pool );
365 }
366
367 /* connection was closed under us */
368 if ( conn->c_writers < 0 ) {
369 /* we're the last waiter, let the closer continue */
370 if ( conn->c_writers == -1 )
371 ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
372 conn->c_writers++;
373 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
374 return 0;
375 }
376
377 /* Our turn */
378 conn->c_writing = 1;
379
380 /* write the pdu */
381 while( 1 ) {
382 int err;
383 char ebuf[128];
384
385 if ( ber_flush2( conn->c_sb, ber, LBER_FLUSH_FREE_NEVER ) == 0 ) {
386 ret = bytes;
387 break;
388 }
389
390 err = sock_errno();
391
392 /*
393 * we got an error. if it's ewouldblock, we need to
394 * wait on the socket being writable. otherwise, figure
395 * it's a hard error and return.
396 */
397
398 Debug( LDAP_DEBUG_CONNS, "ber_flush2 failed errno=%d reason=\"%s\"\n",
399 err, sock_errstr(err, ebuf, sizeof(ebuf)) );
400
401 if ( err != EWOULDBLOCK && err != EAGAIN ) {
402 close_reason = "connection lost on write";
403 fail:
404 conn->c_writers--;
405 conn->c_writing = 0;
406 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
407 ldap_pvt_thread_mutex_lock( &conn->c_mutex );
408 connection_closing( conn, close_reason );
409 ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
410 return -1;
411 }
412
413 /* wait for socket to be write-ready */
414 do_resume = 1;
415 conn->c_writewaiter = 1;
416 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
417 ldap_pvt_thread_pool_idle( &connection_pool );
418 slap_writewait_play( op );
419 err = slapd_wait_writer( conn->c_sd );
420 conn->c_writewaiter = 0;
421 ldap_pvt_thread_pool_unidle( &connection_pool );
422 ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
423 /* 0 is timeout, so we close it.
424 * -1 is an error, close it.
425 */
426 if ( err <= 0 ) {
427 if ( err == 0 )
428 close_reason = "writetimeout";
429 else
430 close_reason = "connection lost on writewait";
431 goto fail;
432 }
433
434 if ( conn->c_writers < 0 ) {
435 ret = 0;
436 break;
437 }
438 }
439
440 conn->c_writing = 0;
441 if ( conn->c_writers < 0 ) {
442 /* shutting down, don't resume any ops */
443 do_resume = 0;
444 conn->c_writers++;
445 if ( !conn->c_writers )
446 ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
447 } else {
448 conn->c_writers--;
449 /* other writers are waiting, don't resume any ops */
450 if ( conn->c_writers )
451 do_resume = 0;
452 ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
453 }
454 ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
455
456 /* If there are no more writers, release a pending op */
457 if ( do_resume )
458 connection_write_resume( conn );
459
460 return ret;
461 }
462
463 static int
send_ldap_control(BerElement * ber,LDAPControl * c)464 send_ldap_control( BerElement *ber, LDAPControl *c )
465 {
466 int rc;
467
468 assert( c != NULL );
469
470 rc = ber_printf( ber, "{s" /*}*/, c->ldctl_oid );
471
472 if( c->ldctl_iscritical ) {
473 rc = ber_printf( ber, "b",
474 (ber_int_t) c->ldctl_iscritical ) ;
475 if( rc == -1 ) return rc;
476 }
477
478 if( c->ldctl_value.bv_val != NULL ) {
479 rc = ber_printf( ber, "O", &c->ldctl_value );
480 if( rc == -1 ) return rc;
481 }
482
483 rc = ber_printf( ber, /*{*/"N}" );
484 if( rc == -1 ) return rc;
485
486 return 0;
487 }
488
489 static int
send_ldap_controls(Operation * o,BerElement * ber,LDAPControl ** c)490 send_ldap_controls( Operation *o, BerElement *ber, LDAPControl **c )
491 {
492 int rc;
493
494 if( c == NULL )
495 return 0;
496
497 rc = ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS );
498 if( rc == -1 ) return rc;
499
500 for( ; *c != NULL; c++) {
501 rc = send_ldap_control( ber, *c );
502 if( rc == -1 ) return rc;
503 }
504
505 #ifdef SLAP_CONTROL_X_SORTEDRESULTS
506 /* this is a hack to avoid having to modify op->s_ctrls */
507 if( o->o_sortedresults ) {
508 BerElementBuffer berbuf;
509 BerElement *sber = (BerElement *) &berbuf;
510 LDAPControl sorted;
511 BER_BVZERO( &sorted.ldctl_value );
512 sorted.ldctl_oid = LDAP_CONTROL_SORTRESPONSE;
513 sorted.ldctl_iscritical = 0;
514
515 ber_init2( sber, NULL, LBER_USE_DER );
516
517 ber_printf( sber, "{e}", LDAP_UNWILLING_TO_PERFORM );
518
519 if( ber_flatten2( sber, &sorted.ldctl_value, 0 ) == -1 ) {
520 return -1;
521 }
522
523 (void) ber_free_buf( sber );
524
525 rc = send_ldap_control( ber, &sorted );
526 if( rc == -1 ) return rc;
527 }
528 #endif
529
530 rc = ber_printf( ber, /*{*/"N}" );
531
532 return rc;
533 }
534
535 /*
536 * slap_response_play()
537 *
538 * plays the callback list; rationale: a callback can
539 * - remove itself from the list, by setting op->o_callback = NULL;
540 * malloc()'ed callbacks should free themselves from inside the
541 * sc_response() function.
542 * - replace itself with another (list of) callback(s), by setting
543 * op->o_callback = a new (list of) callback(s); in this case, it
544 * is the callback's responsibility to to append existing subsequent
545 * callbacks to the end of the list that is passed to the sc_response()
546 * function.
547 * - modify the list of subsequent callbacks by modifying the value
548 * of the sc_next field from inside the sc_response() function; this
549 * case does not require any handling from inside slap_response_play()
550 *
551 * To stop execution of the playlist, the sc_response() function must return
552 * a value different from SLAP_SC_CONTINUE.
553 *
554 * The same applies to slap_cleanup_play(); only, there is no means to stop
555 * execution of the playlist, since all cleanup functions must be called.
556 */
557 static int
slap_response_play(Operation * op,SlapReply * rs)558 slap_response_play(
559 Operation *op,
560 SlapReply *rs )
561 {
562 int rc;
563
564 slap_callback *sc = op->o_callback, **scp;
565
566 rc = SLAP_CB_CONTINUE;
567 for ( scp = ≻ *scp; ) {
568 slap_callback *sc_next = (*scp)->sc_next, **sc_nextp = &(*scp)->sc_next;
569
570 op->o_callback = *scp;
571 if ( op->o_callback->sc_response ) {
572 rc = op->o_callback->sc_response( op, rs );
573 if ( op->o_callback == NULL ) {
574 /* the callback has been removed;
575 * repair the list */
576 *scp = sc_next;
577 sc_nextp = scp;
578
579 } else if ( op->o_callback != *scp ) {
580 /* a new callback has been inserted
581 * in place of the existing one; repair the list */
582 *scp = op->o_callback;
583 sc_nextp = scp;
584 }
585 if ( rc != SLAP_CB_CONTINUE ) break;
586 }
587 scp = sc_nextp;
588 }
589
590 op->o_callback = sc;
591 return rc;
592 }
593
594 static int
slap_cleanup_play(Operation * op,SlapReply * rs)595 slap_cleanup_play(
596 Operation *op,
597 SlapReply *rs )
598 {
599 slap_callback *sc = op->o_callback, **scp;
600
601 for ( scp = ≻ *scp; ) {
602 slap_callback *sc_next = (*scp)->sc_next, **sc_nextp = &(*scp)->sc_next;
603
604 op->o_callback = *scp;
605 if ( op->o_callback->sc_cleanup ) {
606 (void)op->o_callback->sc_cleanup( op, rs );
607 if ( op->o_callback == NULL ) {
608 /* the callback has been removed;
609 * repair the list */
610 *scp = sc_next;
611 sc_nextp = scp;
612
613 } else if ( op->o_callback != *scp ) {
614 /* a new callback has been inserted
615 * after the existing one; repair the list */
616 /* a new callback has been inserted
617 * in place of the existing one; repair the list */
618 *scp = op->o_callback;
619 sc_nextp = scp;
620 }
621 /* don't care about the result; do all cleanup */
622 }
623 scp = sc_nextp;
624 }
625
626 op->o_callback = sc;
627 return LDAP_SUCCESS;
628 }
629
630 static int
send_ldap_response(Operation * op,SlapReply * rs)631 send_ldap_response(
632 Operation *op,
633 SlapReply *rs )
634 {
635 BerElementBuffer berbuf;
636 BerElement *ber = (BerElement *) &berbuf;
637 int rc = LDAP_SUCCESS;
638 long bytes;
639
640 /* op was actually aborted, bypass everything if client didn't Cancel */
641 if (( rs->sr_err == SLAPD_ABANDON ) && !op->o_cancel ) {
642 rc = SLAPD_ABANDON;
643 goto clean2;
644 }
645
646 if ( op->o_callback ) {
647 rc = slap_response_play( op, rs );
648 if ( rc != SLAP_CB_CONTINUE ) {
649 goto clean2;
650 }
651 }
652
653 /* op completed, connection aborted, bypass sending response */
654 if ( op->o_abandon && !op->o_cancel ) {
655 rc = SLAPD_ABANDON;
656 goto clean2;
657 }
658
659 #ifdef LDAP_CONNECTIONLESS
660 if (op->o_conn && op->o_conn->c_is_udp)
661 ber = op->o_res_ber;
662 else
663 #endif
664 {
665 ber_init_w_nullc( ber, LBER_USE_DER );
666 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
667 }
668
669 rc = rs->sr_err;
670 if ( rc == SLAPD_ABANDON && op->o_cancel )
671 rc = LDAP_CANCELLED;
672
673 Debug( LDAP_DEBUG_TRACE,
674 "send_ldap_response: msgid=%d tag=%lu err=%d\n",
675 rs->sr_msgid, rs->sr_tag, rc );
676
677 if( rs->sr_ref ) {
678 Debug( LDAP_DEBUG_ARGS, "send_ldap_response: ref=\"%s\"\n",
679 rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL" );
680 }
681
682 #ifdef LDAP_CONNECTIONLESS
683 if (op->o_conn && op->o_conn->c_is_udp &&
684 op->o_protocol == LDAP_VERSION2 )
685 {
686 rc = ber_printf( ber, "t{ess" /*"}"*/,
687 rs->sr_tag, rc,
688 rs->sr_matched == NULL ? "" : rs->sr_matched,
689 rs->sr_text == NULL ? "" : rs->sr_text );
690 } else
691 #endif
692 if ( rs->sr_type == REP_INTERMEDIATE ) {
693 rc = ber_printf( ber, "{it{" /*"}}"*/,
694 rs->sr_msgid, rs->sr_tag );
695
696 } else {
697 rc = ber_printf( ber, "{it{ess" /*"}}"*/,
698 rs->sr_msgid, rs->sr_tag, rc,
699 rs->sr_matched == NULL ? "" : rs->sr_matched,
700 rs->sr_text == NULL ? "" : rs->sr_text );
701 }
702
703 if( rc != -1 ) {
704 if ( rs->sr_ref != NULL ) {
705 assert( rs->sr_err == LDAP_REFERRAL );
706 rc = ber_printf( ber, "t{W}",
707 LDAP_TAG_REFERRAL, rs->sr_ref );
708 } else {
709 assert( rs->sr_err != LDAP_REFERRAL );
710 }
711 }
712
713 if( rc != -1 && rs->sr_type == REP_SASL && rs->sr_sasldata != NULL ) {
714 rc = ber_printf( ber, "tO",
715 LDAP_TAG_SASL_RES_CREDS, rs->sr_sasldata );
716 }
717
718 if( rc != -1 &&
719 ( rs->sr_type == REP_EXTENDED || rs->sr_type == REP_INTERMEDIATE ))
720 {
721 if ( rs->sr_rspoid != NULL ) {
722 rc = ber_printf( ber, "ts",
723 rs->sr_type == REP_EXTENDED
724 ? LDAP_TAG_EXOP_RES_OID : LDAP_TAG_IM_RES_OID,
725 rs->sr_rspoid );
726 }
727 if( rc != -1 && rs->sr_rspdata != NULL ) {
728 rc = ber_printf( ber, "tO",
729 rs->sr_type == REP_EXTENDED
730 ? LDAP_TAG_EXOP_RES_VALUE : LDAP_TAG_IM_RES_VALUE,
731 rs->sr_rspdata );
732 }
733 }
734
735 if( rc != -1 ) {
736 rc = ber_printf( ber, /*"{"*/ "N}" );
737 }
738
739 if( rc != -1 ) {
740 rc = send_ldap_controls( op, ber, rs->sr_ctrls );
741 }
742
743 if( rc != -1 ) {
744 rc = ber_printf( ber, /*"{"*/ "N}" );
745 }
746
747 #ifdef LDAP_CONNECTIONLESS
748 if( op->o_conn && op->o_conn->c_is_udp && op->o_protocol == LDAP_VERSION2
749 && rc != -1 )
750 {
751 rc = ber_printf( ber, /*"{"*/ "N}" );
752 }
753 #endif
754
755 if ( rc == -1 ) {
756 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n" );
757
758 #ifdef LDAP_CONNECTIONLESS
759 if (!op->o_conn || op->o_conn->c_is_udp == 0)
760 #endif
761 {
762 ber_free_buf( ber );
763 }
764 goto cleanup;
765 }
766
767 /* send BER */
768 bytes = send_ldap_ber( op, ber );
769 #ifdef LDAP_CONNECTIONLESS
770 if (!op->o_conn || op->o_conn->c_is_udp == 0)
771 #endif
772 {
773 ber_free_buf( ber );
774 }
775
776 if ( bytes < 0 ) {
777 Debug( LDAP_DEBUG_ANY,
778 "send_ldap_response: ber write failed\n" );
779
780 goto cleanup;
781 }
782
783 ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
784 ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
785 ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
786 ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
787
788 cleanup:;
789 /* Tell caller that we did this for real, as opposed to being
790 * overridden by a callback
791 */
792 rc = SLAP_CB_CONTINUE;
793
794 clean2:;
795 if ( op->o_callback ) {
796 (void)slap_cleanup_play( op, rs );
797 }
798
799 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
800 rs->sr_flags ^= REP_MATCHED_MUSTBEFREED; /* paranoia */
801 if ( rs->sr_matched ) {
802 free( (char *)rs->sr_matched );
803 rs->sr_matched = NULL;
804 }
805 }
806
807 if ( rs->sr_flags & REP_REF_MUSTBEFREED ) {
808 rs->sr_flags ^= REP_REF_MUSTBEFREED; /* paranoia */
809 if ( rs->sr_ref ) {
810 ber_bvarray_free( rs->sr_ref );
811 rs->sr_ref = NULL;
812 }
813 }
814
815 if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
816 rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
817 if ( rs->sr_ctrls ) {
818 slap_free_ctrls( op, rs->sr_ctrls );
819 rs->sr_ctrls = NULL;
820 }
821 }
822
823 return rc;
824 }
825
826
827 void
send_ldap_disconnect(Operation * op,SlapReply * rs)828 send_ldap_disconnect( Operation *op, SlapReply *rs )
829 {
830 #define LDAP_UNSOLICITED_ERROR(e) \
831 ( (e) == LDAP_PROTOCOL_ERROR \
832 || (e) == LDAP_STRONG_AUTH_REQUIRED \
833 || (e) == LDAP_UNAVAILABLE )
834
835 Debug( LDAP_DEBUG_TRACE,
836 "send_ldap_disconnect %d:%s\n",
837 rs->sr_err, rs->sr_text ? rs->sr_text : "" );
838 assert( LDAP_UNSOLICITED_ERROR( rs->sr_err ) );
839
840 /* TODO: Flush the entry if sr_type == REP_SEARCH/REP_SEARCHREF? */
841 RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
842 rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia */
843
844 rs->sr_type = REP_EXTENDED;
845 rs->sr_rspdata = NULL;
846
847 if ( op->o_protocol < LDAP_VERSION3 ) {
848 rs->sr_rspoid = NULL;
849 rs->sr_tag = slap_req2res( op->o_tag );
850 rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
851
852 } else {
853 rs->sr_rspoid = LDAP_NOTICE_DISCONNECT;
854 rs->sr_tag = LDAP_RES_EXTENDED;
855 rs->sr_msgid = LDAP_RES_UNSOLICITED;
856 }
857
858 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
859 ETIME_SETUP;
860 StatslogEtime( LDAP_DEBUG_STATS,
861 "%s DISCONNECT tag=%lu err=%d "ETIME_LOGFMT"text=%s\n",
862 op->o_log_prefix, rs->sr_tag, rs->sr_err,
863 rs->sr_text ? rs->sr_text : "" );
864 }
865 }
866
867 void
slap_send_ldap_result(Operation * op,SlapReply * rs)868 slap_send_ldap_result( Operation *op, SlapReply *rs )
869 {
870 char *tmp = NULL;
871 const char *otext = rs->sr_text;
872 BerVarray oref = rs->sr_ref;
873
874 rs->sr_type = REP_RESULT;
875
876 /* Propagate Abandons so that cleanup callbacks can be processed */
877 if ( rs->sr_err == SLAPD_ABANDON || op->o_abandon )
878 goto abandon;
879
880 Debug( LDAP_DEBUG_TRACE,
881 "send_ldap_result: %s p=%d\n",
882 op->o_log_prefix, op->o_protocol );
883 Debug( LDAP_DEBUG_ARGS,
884 "send_ldap_result: err=%d matched=\"%s\" text=\"%s\"\n",
885 rs->sr_err, rs->sr_matched ? rs->sr_matched : "",
886 rs->sr_text ? rs->sr_text : "" );
887 if( rs->sr_ref ) {
888 Debug( LDAP_DEBUG_ARGS,
889 "send_ldap_result: referral=\"%s\"\n",
890 rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL" );
891 }
892 assert( !LDAP_API_ERROR( rs->sr_err ) );
893 assert( rs->sr_err != LDAP_PARTIAL_RESULTS );
894
895 if ( rs->sr_err == LDAP_REFERRAL ) {
896 if( op->o_domain_scope ) rs->sr_ref = NULL;
897
898 if( rs->sr_ref == NULL ) {
899 rs->sr_err = LDAP_NO_SUCH_OBJECT;
900 } else if ( op->o_protocol < LDAP_VERSION3 ) {
901 rs->sr_err = LDAP_PARTIAL_RESULTS;
902 }
903 }
904
905 if ( op->o_protocol < LDAP_VERSION3 ) {
906 tmp = v2ref( rs->sr_ref, rs->sr_text );
907 rs->sr_text = tmp;
908 rs->sr_ref = NULL;
909 }
910
911 abandon:
912 rs->sr_tag = slap_req2res( op->o_tag );
913 rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
914
915 if ( rs->sr_flags & REP_REF_MUSTBEFREED ) {
916 if ( rs->sr_ref == NULL ) {
917 rs->sr_flags ^= REP_REF_MUSTBEFREED;
918 ber_bvarray_free( oref );
919 }
920 oref = NULL; /* send_ldap_response() will free rs->sr_ref if != NULL */
921 }
922
923 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
924 ETIME_SETUP;
925 if ( op->o_tag == LDAP_REQ_SEARCH ) {
926 StatslogEtime( LDAP_DEBUG_STATS,
927 "%s SEARCH RESULT tag=%lu err=%d "ETIME_LOGFMT"nentries=%d text=%s\n",
928 op->o_log_prefix, rs->sr_tag, rs->sr_err,
929 rs->sr_nentries, rs->sr_text ? rs->sr_text : "" );
930 } else {
931 StatslogEtime( LDAP_DEBUG_STATS,
932 "%s RESULT tag=%lu err=%d "ETIME_LOGFMT"text=%s\n",
933 op->o_log_prefix, rs->sr_tag, rs->sr_err,
934 rs->sr_text ? rs->sr_text : "" );
935 }
936 }
937
938 if( tmp != NULL ) ch_free(tmp);
939 rs->sr_text = otext;
940 rs->sr_ref = oref;
941 }
942
943 void
send_ldap_sasl(Operation * op,SlapReply * rs)944 send_ldap_sasl( Operation *op, SlapReply *rs )
945 {
946 Debug( LDAP_DEBUG_TRACE, "send_ldap_sasl: err=%d len=%ld\n",
947 rs->sr_err,
948 rs->sr_sasldata ? (long) rs->sr_sasldata->bv_len : -1 );
949
950 RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
951 rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia */
952
953 rs->sr_type = REP_SASL;
954 rs->sr_tag = slap_req2res( op->o_tag );
955 rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
956
957 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
958 ETIME_SETUP;
959 StatslogEtime( LDAP_DEBUG_STATS,
960 "%s RESULT tag=%lu err=%d "ETIME_LOGFMT"text=%s\n",
961 op->o_log_prefix, rs->sr_tag, rs->sr_err,
962 rs->sr_text ? rs->sr_text : "" );
963 }
964 }
965
966 void
slap_send_ldap_extended(Operation * op,SlapReply * rs)967 slap_send_ldap_extended( Operation *op, SlapReply *rs )
968 {
969 Debug( LDAP_DEBUG_TRACE,
970 "send_ldap_extended: err=%d oid=%s len=%ld\n",
971 rs->sr_err,
972 rs->sr_rspoid ? rs->sr_rspoid : "",
973 rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 );
974
975 RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
976 rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia */
977
978 rs->sr_type = REP_EXTENDED;
979 rs->sr_tag = slap_req2res( op->o_tag );
980 rs->sr_msgid = (rs->sr_tag != LBER_SEQUENCE) ? op->o_msgid : 0;
981
982 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
983 ETIME_SETUP;
984 StatslogEtime( LDAP_DEBUG_STATS,
985 "%s RESULT oid=%s err=%d "ETIME_LOGFMT"text=%s\n",
986 op->o_log_prefix, rs->sr_rspoid ? rs->sr_rspoid : "",
987 rs->sr_err, rs->sr_text ? rs->sr_text : "" );
988 }
989 }
990
991 void
slap_send_ldap_intermediate(Operation * op,SlapReply * rs)992 slap_send_ldap_intermediate( Operation *op, SlapReply *rs )
993 {
994 Debug( LDAP_DEBUG_TRACE,
995 "send_ldap_intermediate: err=%d oid=%s len=%ld\n",
996 rs->sr_err,
997 rs->sr_rspoid ? rs->sr_rspoid : "",
998 rs->sr_rspdata != NULL ? rs->sr_rspdata->bv_len : 0 );
999
1000 RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
1001 rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia */
1002
1003 rs->sr_type = REP_INTERMEDIATE;
1004 rs->sr_tag = LDAP_RES_INTERMEDIATE;
1005 rs->sr_msgid = op->o_msgid;
1006 if ( send_ldap_response( op, rs ) == SLAP_CB_CONTINUE ) {
1007 Debug( LDAP_DEBUG_STATS2,
1008 "%s INTERMEDIATE oid=%s\n",
1009 op->o_log_prefix,
1010 rs->sr_rspoid ? rs->sr_rspoid : "" );
1011 }
1012 }
1013
1014 #define set_ldap_error( rs, err, text ) do { \
1015 (rs)->sr_err = err; (rs)->sr_text = text; } while(0)
1016
1017 /*
1018 * returns:
1019 *
1020 * LDAP_SUCCESS entry sent
1021 * LDAP_OTHER entry not sent (other)
1022 * LDAP_INSUFFICIENT_ACCESS entry not sent (ACL)
1023 * LDAP_UNAVAILABLE entry not sent (connection closed)
1024 * LDAP_SIZELIMIT_EXCEEDED entry not sent (caller must send sizelimitExceeded)
1025 */
1026
1027 int
slap_send_search_entry(Operation * op,SlapReply * rs)1028 slap_send_search_entry( Operation *op, SlapReply *rs )
1029 {
1030 BerElementBuffer berbuf;
1031 BerElement *ber = (BerElement *) &berbuf;
1032 Attribute *a;
1033 int i, j, rc = LDAP_UNAVAILABLE, bytes;
1034 int userattrs;
1035 AccessControlState acl_state = ACL_STATE_INIT;
1036 int attrsonly;
1037 AttributeDescription *ad_entry = slap_schema.si_ad_entry;
1038
1039 /* a_flags: array of flags telling if the i-th element will be
1040 * returned or filtered out
1041 * e_flags: array of a_flags
1042 */
1043 char **e_flags = NULL;
1044
1045 rs->sr_type = REP_SEARCH;
1046
1047 if ( op->ors_slimit >= 0 && rs->sr_nentries >= op->ors_slimit ) {
1048 rc = LDAP_SIZELIMIT_EXCEEDED;
1049 goto error_return;
1050 }
1051
1052 /* Every 64 entries, check for thread pool pause */
1053 if ( ( ( rs->sr_nentries & 0x3f ) == 0x3f ) &&
1054 ldap_pvt_thread_pool_pausing( &connection_pool ) > 0 )
1055 {
1056 rc = LDAP_BUSY;
1057 goto error_return;
1058 }
1059
1060 /* eventually will loop through generated operational attribute types
1061 * currently implemented types include:
1062 * entryDN, subschemaSubentry, and hasSubordinates */
1063 /* NOTE: moved before overlays callback circling because
1064 * they may modify entry and other stuff in rs */
1065 /* check for special all operational attributes ("+") type */
1066 /* FIXME: maybe we could set this flag at the operation level;
1067 * however, in principle the caller of send_search_entry() may
1068 * change the attribute list at each call */
1069 rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs );
1070
1071 rc = backend_operational( op, rs );
1072 if ( rc ) {
1073 goto error_return;
1074 }
1075
1076 if ( op->o_callback ) {
1077 rc = slap_response_play( op, rs );
1078 if ( rc != SLAP_CB_CONTINUE ) {
1079 goto error_return;
1080 }
1081 }
1082
1083 Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: conn %lu dn=\"%s\"%s\n",
1084 op->o_connid, rs->sr_entry->e_name.bv_val,
1085 op->ors_attrsonly ? " (attrsOnly)" : "" );
1086
1087 attrsonly = op->ors_attrsonly;
1088
1089 if ( !access_allowed( op, rs->sr_entry, ad_entry, NULL, ACL_READ, NULL )) {
1090 Debug( LDAP_DEBUG_ACL,
1091 "send_search_entry: conn %lu access to entry (%s) not allowed\n",
1092 op->o_connid, rs->sr_entry->e_name.bv_val );
1093
1094 rc = LDAP_INSUFFICIENT_ACCESS;
1095 goto error_return;
1096 }
1097
1098 if ( op->o_res_ber ) {
1099 /* read back control or LDAP_CONNECTIONLESS */
1100 ber = op->o_res_ber;
1101 } else {
1102 struct berval bv;
1103
1104 bv.bv_len = entry_flatsize( rs->sr_entry, 0 );
1105 bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );
1106
1107 ber_init2( ber, &bv, LBER_USE_DER );
1108 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
1109 }
1110
1111 #ifdef LDAP_CONNECTIONLESS
1112 if ( op->o_conn && op->o_conn->c_is_udp ) {
1113 /* CONNECTIONLESS */
1114 if ( op->o_protocol == LDAP_VERSION2 ) {
1115 rc = ber_printf(ber, "t{O{" /*}}*/,
1116 LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
1117 } else {
1118 rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
1119 LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
1120 }
1121 } else
1122 #endif
1123 if ( op->o_res_ber ) {
1124 /* read back control */
1125 rc = ber_printf( ber, "t{O{" /*}}*/,
1126 LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
1127 } else {
1128 rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
1129 LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
1130 }
1131
1132 if ( rc == -1 ) {
1133 Debug( LDAP_DEBUG_ANY,
1134 "send_search_entry: conn %lu ber_printf failed\n",
1135 op->o_connid );
1136
1137 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1138 set_ldap_error( rs, LDAP_OTHER, "encoding DN error" );
1139 rc = rs->sr_err;
1140 goto error_return;
1141 }
1142
1143 /* check for special all user attributes ("*") type */
1144 userattrs = SLAP_USERATTRS( rs->sr_attr_flags );
1145
1146 /* create an array of arrays of flags. Each flag corresponds
1147 * to particular value of attribute and equals 1 if value matches
1148 * to ValuesReturnFilter or 0 if not
1149 */
1150 if ( op->o_vrFilter != NULL ) {
1151 int k = 0;
1152 size_t size;
1153
1154 for ( a = rs->sr_entry->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
1155 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
1156 }
1157
1158 size = i * sizeof(char *) + k;
1159 if ( size > 0 ) {
1160 char *a_flags;
1161 e_flags = slap_sl_calloc ( 1, i * sizeof(char *) + k, op->o_tmpmemctx );
1162 if( e_flags == NULL ) {
1163 Debug( LDAP_DEBUG_ANY,
1164 "send_search_entry: conn %lu slap_sl_calloc failed\n",
1165 op->o_connid );
1166 ber_free( ber, 1 );
1167
1168 set_ldap_error( rs, LDAP_OTHER, "out of memory" );
1169 goto error_return;
1170 }
1171 a_flags = (char *)(e_flags + i);
1172 memset( a_flags, 0, k );
1173 for ( a=rs->sr_entry->e_attrs, i=0; a != NULL; a=a->a_next, i++ ) {
1174 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
1175 e_flags[i] = a_flags;
1176 a_flags += j;
1177 }
1178
1179 rc = filter_matched_values(op, rs->sr_entry->e_attrs, &e_flags) ;
1180 if ( rc == -1 ) {
1181 Debug( LDAP_DEBUG_ANY, "send_search_entry: "
1182 "conn %lu matched values filtering failed\n",
1183 op->o_connid );
1184 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1185 set_ldap_error( rs, LDAP_OTHER,
1186 "matched values filtering error" );
1187 rc = rs->sr_err;
1188 goto error_return;
1189 }
1190 }
1191 }
1192
1193 for ( a = rs->sr_entry->e_attrs, j = 0; a != NULL; a = a->a_next, j++ ) {
1194 AttributeDescription *desc = a->a_desc;
1195 int finish = 0;
1196
1197 if ( rs->sr_attrs == NULL ) {
1198 /* all user attrs request, skip operational attributes */
1199 if( is_at_operational( desc->ad_type ) ) {
1200 continue;
1201 }
1202
1203 } else {
1204 /* specific attrs requested */
1205 if ( is_at_operational( desc->ad_type ) ) {
1206 /* if not explicitly requested */
1207 if ( !ad_inlist( desc, rs->sr_attrs )) {
1208 /* if not all op attrs requested, skip */
1209 if ( !SLAP_OPATTRS( rs->sr_attr_flags ))
1210 continue;
1211 /* if DSA-specific and replicating, skip */
1212 if ( op->o_sync != SLAP_CONTROL_NONE &&
1213 desc->ad_type->sat_usage == LDAP_SCHEMA_DSA_OPERATION )
1214 continue;
1215 }
1216 } else {
1217 if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
1218 continue;
1219 }
1220 }
1221 }
1222
1223 if ( attrsonly ) {
1224 if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
1225 ACL_READ, &acl_state ) )
1226 {
1227 Debug( LDAP_DEBUG_ACL, "send_search_entry: "
1228 "conn %lu access to attribute %s not allowed\n",
1229 op->o_connid, desc->ad_cname.bv_val );
1230 continue;
1231 }
1232
1233 if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) {
1234 Debug( LDAP_DEBUG_ANY,
1235 "send_search_entry: conn %lu ber_printf failed\n",
1236 op->o_connid );
1237
1238 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1239 set_ldap_error( rs, LDAP_OTHER,
1240 "encoding description error");
1241 rc = rs->sr_err;
1242 goto error_return;
1243 }
1244 finish = 1;
1245
1246 } else {
1247 int first = 1;
1248 for ( i = 0; a->a_nvals[i].bv_val != NULL; i++ ) {
1249 if ( ! access_allowed( op, rs->sr_entry,
1250 desc, &a->a_nvals[i], ACL_READ, &acl_state ) )
1251 {
1252 Debug( LDAP_DEBUG_ACL,
1253 "send_search_entry: conn %lu "
1254 "access to attribute %s, value #%d not allowed\n",
1255 op->o_connid, desc->ad_cname.bv_val, i );
1256
1257 continue;
1258 }
1259
1260 if ( op->o_vrFilter && e_flags[j][i] == 0 ){
1261 continue;
1262 }
1263
1264 if ( first ) {
1265 first = 0;
1266 finish = 1;
1267 if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) {
1268 Debug( LDAP_DEBUG_ANY,
1269 "send_search_entry: conn %lu ber_printf failed\n",
1270 op->o_connid );
1271
1272 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1273 set_ldap_error( rs, LDAP_OTHER,
1274 "encoding description error");
1275 rc = rs->sr_err;
1276 goto error_return;
1277 }
1278 }
1279 if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
1280 Debug( LDAP_DEBUG_ANY,
1281 "send_search_entry: conn %lu "
1282 "ber_printf failed.\n", op->o_connid );
1283
1284 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1285 set_ldap_error( rs, LDAP_OTHER,
1286 "encoding values error" );
1287 rc = rs->sr_err;
1288 goto error_return;
1289 }
1290 }
1291 }
1292
1293 if ( finish && ( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
1294 Debug( LDAP_DEBUG_ANY,
1295 "send_search_entry: conn %lu ber_printf failed\n",
1296 op->o_connid );
1297
1298 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1299 set_ldap_error( rs, LDAP_OTHER, "encode end error" );
1300 rc = rs->sr_err;
1301 goto error_return;
1302 }
1303 }
1304
1305 /* NOTE: moved before overlays callback circling because
1306 * they may modify entry and other stuff in rs */
1307 if ( rs->sr_operational_attrs != NULL && op->o_vrFilter != NULL ) {
1308 int k = 0;
1309 size_t size;
1310
1311 for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
1312 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
1313 }
1314
1315 size = i * sizeof(char *) + k;
1316 if ( size > 0 ) {
1317 char *a_flags, **tmp;
1318
1319 /*
1320 * Reuse previous memory - we likely need less space
1321 * for operational attributes
1322 */
1323 tmp = slap_sl_realloc( e_flags, i * sizeof(char *) + k,
1324 op->o_tmpmemctx );
1325 if ( tmp == NULL ) {
1326 Debug( LDAP_DEBUG_ANY,
1327 "send_search_entry: conn %lu "
1328 "not enough memory "
1329 "for matched values filtering\n",
1330 op->o_connid );
1331 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1332 set_ldap_error( rs, LDAP_OTHER,
1333 "not enough memory for matched values filtering" );
1334 goto error_return;
1335 }
1336 e_flags = tmp;
1337 a_flags = (char *)(e_flags + i);
1338 memset( a_flags, 0, k );
1339 for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
1340 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
1341 e_flags[i] = a_flags;
1342 a_flags += j;
1343 }
1344 rc = filter_matched_values(op, rs->sr_operational_attrs, &e_flags) ;
1345
1346 if ( rc == -1 ) {
1347 Debug( LDAP_DEBUG_ANY,
1348 "send_search_entry: conn %lu "
1349 "matched values filtering failed\n",
1350 op->o_connid );
1351 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1352 set_ldap_error( rs, LDAP_OTHER,
1353 "matched values filtering error" );
1354 rc = rs->sr_err;
1355 goto error_return;
1356 }
1357 }
1358 }
1359
1360 for (a = rs->sr_operational_attrs, j=0; a != NULL; a = a->a_next, j++ ) {
1361 AttributeDescription *desc = a->a_desc;
1362
1363 if ( rs->sr_attrs == NULL ) {
1364 /* all user attrs request, skip operational attributes */
1365 if( is_at_operational( desc->ad_type ) ) {
1366 continue;
1367 }
1368
1369 } else {
1370 /* specific attrs requested */
1371 if( is_at_operational( desc->ad_type ) ) {
1372 if ( !SLAP_OPATTRS( rs->sr_attr_flags ) &&
1373 !ad_inlist( desc, rs->sr_attrs ) )
1374 {
1375 continue;
1376 }
1377 /* if DSA-specific and replicating, skip */
1378 if ( op->o_sync != SLAP_CONTROL_NONE &&
1379 desc->ad_type->sat_usage == LDAP_SCHEMA_DSA_OPERATION )
1380 continue;
1381 } else {
1382 if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
1383 continue;
1384 }
1385 }
1386 }
1387
1388 if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
1389 ACL_READ, &acl_state ) )
1390 {
1391 Debug( LDAP_DEBUG_ACL,
1392 "send_search_entry: conn %lu "
1393 "access to attribute %s not allowed\n",
1394 op->o_connid, desc->ad_cname.bv_val );
1395
1396 continue;
1397 }
1398
1399 rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname );
1400 if ( rc == -1 ) {
1401 Debug( LDAP_DEBUG_ANY,
1402 "send_search_entry: conn %lu "
1403 "ber_printf failed\n", op->o_connid );
1404
1405 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1406 set_ldap_error( rs, LDAP_OTHER,
1407 "encoding description error" );
1408 rc = rs->sr_err;
1409 goto error_return;
1410 }
1411
1412 if ( ! attrsonly ) {
1413 for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) {
1414 if ( ! access_allowed( op, rs->sr_entry,
1415 desc, &a->a_vals[i], ACL_READ, &acl_state ) )
1416 {
1417 Debug( LDAP_DEBUG_ACL,
1418 "send_search_entry: conn %lu "
1419 "access to %s, value %d not allowed\n",
1420 op->o_connid, desc->ad_cname.bv_val, i );
1421
1422 continue;
1423 }
1424
1425 if ( op->o_vrFilter && e_flags[j][i] == 0 ){
1426 continue;
1427 }
1428
1429 if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
1430 Debug( LDAP_DEBUG_ANY,
1431 "send_search_entry: conn %lu ber_printf failed\n",
1432 op->o_connid );
1433
1434 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1435 set_ldap_error( rs, LDAP_OTHER,
1436 "encoding values error" );
1437 rc = rs->sr_err;
1438 goto error_return;
1439 }
1440 }
1441 }
1442
1443 if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
1444 Debug( LDAP_DEBUG_ANY,
1445 "send_search_entry: conn %lu ber_printf failed\n",
1446 op->o_connid );
1447
1448 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1449 set_ldap_error( rs, LDAP_OTHER, "encode end error" );
1450 rc = rs->sr_err;
1451 goto error_return;
1452 }
1453 }
1454
1455 /* free e_flags */
1456 if ( e_flags ) {
1457 slap_sl_free( e_flags, op->o_tmpmemctx );
1458 e_flags = NULL;
1459 }
1460
1461 rc = ber_printf( ber, /*{{*/ "}N}" );
1462
1463 if( rc != -1 ) {
1464 rc = send_ldap_controls( op, ber, rs->sr_ctrls );
1465 }
1466
1467 if( rc != -1 ) {
1468 #ifdef LDAP_CONNECTIONLESS
1469 if( op->o_conn && op->o_conn->c_is_udp ) {
1470 if ( op->o_protocol != LDAP_VERSION2 ) {
1471 rc = ber_printf( ber, /*{*/ "N}" );
1472 }
1473 } else
1474 #endif
1475 if ( op->o_res_ber == NULL ) {
1476 rc = ber_printf( ber, /*{*/ "N}" );
1477 }
1478 }
1479
1480 if ( rc == -1 ) {
1481 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n" );
1482
1483 if ( op->o_res_ber == NULL ) ber_free_buf( ber );
1484 set_ldap_error( rs, LDAP_OTHER, "encode entry end error" );
1485 rc = rs->sr_err;
1486 goto error_return;
1487 }
1488
1489 Debug( LDAP_DEBUG_STATS2, "%s ENTRY dn=\"%s\"\n",
1490 op->o_log_prefix, rs->sr_entry->e_nname.bv_val );
1491
1492 rs_flush_entry( op, rs, NULL );
1493
1494 if ( op->o_res_ber == NULL ) {
1495 bytes = send_ldap_ber( op, ber );
1496 ber_free_buf( ber );
1497
1498 if ( bytes < 0 ) {
1499 Debug( LDAP_DEBUG_ANY,
1500 "send_search_entry: conn %lu ber write failed.\n",
1501 op->o_connid );
1502
1503 rc = LDAP_UNAVAILABLE;
1504 goto error_return;
1505 }
1506 rs->sr_nentries++;
1507
1508 ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
1509 ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
1510 ldap_pvt_mp_add_ulong( op->o_counters->sc_entries, 1 );
1511 ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
1512 ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
1513 }
1514
1515 Debug( LDAP_DEBUG_TRACE,
1516 "<= send_search_entry: conn %lu exit.\n", op->o_connid );
1517
1518 rc = LDAP_SUCCESS;
1519
1520 error_return:;
1521 if ( op->o_callback ) {
1522 (void)slap_cleanup_play( op, rs );
1523 }
1524
1525 if ( e_flags ) {
1526 slap_sl_free( e_flags, op->o_tmpmemctx );
1527 }
1528
1529 /* FIXME: Can break if rs now contains an extended response */
1530 if ( rs->sr_operational_attrs ) {
1531 attrs_free( rs->sr_operational_attrs );
1532 rs->sr_operational_attrs = NULL;
1533 }
1534 rs->sr_attr_flags = SLAP_ATTRS_UNDEFINED;
1535
1536 if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1537 rs_flush_entry( op, rs, NULL );
1538 } else {
1539 RS_ASSERT( (rs->sr_flags & REP_ENTRY_MASK) == 0 );
1540 }
1541
1542 if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
1543 rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
1544 if ( rs->sr_ctrls ) {
1545 slap_free_ctrls( op, rs->sr_ctrls );
1546 rs->sr_ctrls = NULL;
1547 }
1548 }
1549
1550 return( rc );
1551 }
1552
1553 int
slap_send_search_reference(Operation * op,SlapReply * rs)1554 slap_send_search_reference( Operation *op, SlapReply *rs )
1555 {
1556 BerElementBuffer berbuf;
1557 BerElement *ber = (BerElement *) &berbuf;
1558 int rc = 0;
1559 int bytes;
1560 char *edn = rs->sr_entry ? rs->sr_entry->e_name.bv_val : "(null)";
1561
1562 AttributeDescription *ad_ref = slap_schema.si_ad_ref;
1563 AttributeDescription *ad_entry = slap_schema.si_ad_entry;
1564
1565 rs->sr_type = REP_SEARCHREF;
1566 if ( op->o_callback ) {
1567 rc = slap_response_play( op, rs );
1568 if ( rc != SLAP_CB_CONTINUE ) {
1569 goto rel;
1570 }
1571 }
1572
1573 Debug( LDAP_DEBUG_TRACE,
1574 "=> send_search_reference: dn=\"%s\"\n",
1575 edn );
1576
1577 if ( rs->sr_entry && ! access_allowed( op, rs->sr_entry,
1578 ad_entry, NULL, ACL_READ, NULL ) )
1579 {
1580 Debug( LDAP_DEBUG_ACL,
1581 "send_search_reference: access to entry not allowed\n" );
1582 rc = 1;
1583 goto rel;
1584 }
1585
1586 if ( rs->sr_entry && ! access_allowed( op, rs->sr_entry,
1587 ad_ref, NULL, ACL_READ, NULL ) )
1588 {
1589 Debug( LDAP_DEBUG_ACL,
1590 "send_search_reference: access "
1591 "to reference not allowed\n" );
1592 rc = 1;
1593 goto rel;
1594 }
1595
1596 if( op->o_domain_scope ) {
1597 Debug( LDAP_DEBUG_ANY,
1598 "send_search_reference: domainScope control in (%s)\n",
1599 edn );
1600 rc = 0;
1601 goto rel;
1602 }
1603
1604 if( rs->sr_ref == NULL ) {
1605 Debug( LDAP_DEBUG_ANY,
1606 "send_search_reference: null ref in (%s)\n",
1607 edn );
1608 rc = 1;
1609 goto rel;
1610 }
1611
1612 if( op->o_protocol < LDAP_VERSION3 ) {
1613 rc = 0;
1614 /* save the references for the result */
1615 if( rs->sr_ref[0].bv_val != NULL ) {
1616 if( value_add( &rs->sr_v2ref, rs->sr_ref ) )
1617 rc = LDAP_OTHER;
1618 }
1619 goto rel;
1620 }
1621
1622 #ifdef LDAP_CONNECTIONLESS
1623 if( op->o_conn && op->o_conn->c_is_udp ) {
1624 ber = op->o_res_ber;
1625 } else
1626 #endif
1627 {
1628 ber_init_w_nullc( ber, LBER_USE_DER );
1629 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
1630 }
1631
1632 rc = ber_printf( ber, "{it{W}" /*"}"*/ , op->o_msgid,
1633 LDAP_RES_SEARCH_REFERENCE, rs->sr_ref );
1634
1635 if( rc != -1 ) {
1636 rc = send_ldap_controls( op, ber, rs->sr_ctrls );
1637 }
1638
1639 if( rc != -1 ) {
1640 rc = ber_printf( ber, /*"{"*/ "N}" );
1641 }
1642
1643 if ( rc == -1 ) {
1644 Debug( LDAP_DEBUG_ANY,
1645 "send_search_reference: ber_printf failed\n" );
1646
1647 #ifdef LDAP_CONNECTIONLESS
1648 if (!op->o_conn || op->o_conn->c_is_udp == 0)
1649 #endif
1650 ber_free_buf( ber );
1651 set_ldap_error( rs, LDAP_OTHER, "encode DN error" );
1652 goto rel;
1653 }
1654
1655 rc = 0;
1656 rs_flush_entry( op, rs, NULL );
1657
1658 #ifdef LDAP_CONNECTIONLESS
1659 if (!op->o_conn || op->o_conn->c_is_udp == 0) {
1660 #endif
1661 bytes = send_ldap_ber( op, ber );
1662 ber_free_buf( ber );
1663
1664 if ( bytes < 0 ) {
1665 rc = LDAP_UNAVAILABLE;
1666 } else {
1667 ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
1668 ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
1669 ldap_pvt_mp_add_ulong( op->o_counters->sc_refs, 1 );
1670 ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
1671 ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
1672 }
1673 #ifdef LDAP_CONNECTIONLESS
1674 }
1675 #endif
1676 if ( rs->sr_ref != NULL ) {
1677 int r;
1678
1679 for ( r = 0; !BER_BVISNULL( &rs->sr_ref[ r ] ); r++ ) {
1680 Debug( LDAP_DEBUG_STATS2, "%s REF #%d \"%s\"\n",
1681 op->o_log_prefix, r, rs->sr_ref[0].bv_val );
1682 }
1683
1684 } else {
1685 Debug( LDAP_DEBUG_STATS2, "%s REF \"(null)\"\n",
1686 op->o_log_prefix );
1687 }
1688
1689 Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n" );
1690
1691 if ( 0 ) {
1692 rel:
1693 rs_flush_entry( op, rs, NULL );
1694 }
1695
1696 if ( op->o_callback ) {
1697 (void)slap_cleanup_play( op, rs );
1698 }
1699
1700 if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
1701 rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
1702 if ( rs->sr_ctrls ) {
1703 slap_free_ctrls( op, rs->sr_ctrls );
1704 rs->sr_ctrls = NULL;
1705 }
1706 }
1707
1708 return rc;
1709 }
1710
1711 int
str2result(char * s,int * code,char ** matched,char ** info)1712 str2result(
1713 char *s,
1714 int *code,
1715 char **matched,
1716 char **info )
1717 {
1718 int rc;
1719 char *c;
1720
1721 *code = LDAP_SUCCESS;
1722 *matched = NULL;
1723 *info = NULL;
1724
1725 if ( strncasecmp( s, "RESULT", STRLENOF( "RESULT" ) ) != 0 ) {
1726 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
1727 s );
1728
1729 return( -1 );
1730 }
1731
1732 rc = 0;
1733 while ( (s = strchr( s, '\n' )) != NULL ) {
1734 *s++ = '\0';
1735 if ( *s == '\0' ) {
1736 break;
1737 }
1738 if ( (c = strchr( s, ':' )) != NULL ) {
1739 c++;
1740 }
1741
1742 if ( strncasecmp( s, "code", STRLENOF( "code" ) ) == 0 ) {
1743 char *next = NULL;
1744 long retcode;
1745
1746 if ( c == NULL ) {
1747 Debug( LDAP_DEBUG_ANY, "str2result (%s) missing value\n",
1748 s );
1749 rc = -1;
1750 continue;
1751 }
1752
1753 while ( isspace( (unsigned char) c[ 0 ] ) ) c++;
1754 if ( c[ 0 ] == '\0' ) {
1755 Debug( LDAP_DEBUG_ANY, "str2result (%s) missing or empty value\n",
1756 s );
1757 rc = -1;
1758 continue;
1759 }
1760
1761 retcode = strtol( c, &next, 10 );
1762 if ( next == NULL || next == c ) {
1763 Debug( LDAP_DEBUG_ANY, "str2result (%s) unable to parse value\n",
1764 s );
1765 rc = -1;
1766 continue;
1767 }
1768
1769 while ( isspace( (unsigned char) next[ 0 ] ) && next[ 0 ] != '\n' )
1770 next++;
1771 if ( next[ 0 ] != '\0' && next[ 0 ] != '\n' ) {
1772 Debug( LDAP_DEBUG_ANY, "str2result (%s) extra cruft after value\n",
1773 s );
1774 rc = -1;
1775 continue;
1776 }
1777
1778 /* FIXME: what if it's larger than max int? */
1779 *code = (int)retcode;
1780
1781 } else if ( strncasecmp( s, "matched", STRLENOF( "matched" ) ) == 0 ) {
1782 if ( c != NULL ) {
1783 *matched = c;
1784 }
1785 } else if ( strncasecmp( s, "info", STRLENOF( "info" ) ) == 0 ) {
1786 if ( c != NULL ) {
1787 *info = c;
1788 }
1789 } else {
1790 Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
1791 s );
1792
1793 rc = -1;
1794 }
1795 }
1796
1797 return( rc );
1798 }
1799
slap_read_controls(Operation * op,SlapReply * rs,Entry * e,const struct berval * oid,LDAPControl ** ctrl)1800 int slap_read_controls(
1801 Operation *op,
1802 SlapReply *rs,
1803 Entry *e,
1804 const struct berval *oid,
1805 LDAPControl **ctrl )
1806 {
1807 int rc;
1808 struct berval bv;
1809 BerElementBuffer berbuf;
1810 BerElement *ber = (BerElement *) &berbuf;
1811 LDAPControl c;
1812 Operation myop;
1813
1814 Debug( LDAP_DEBUG_ANY, "%s slap_read_controls: (%s) %s\n",
1815 op->o_log_prefix, oid->bv_val, e->e_dn );
1816
1817 rs->sr_entry = e;
1818 rs->sr_attrs = ( oid == &slap_pre_read_bv ) ?
1819 op->o_preread_attrs : op->o_postread_attrs;
1820
1821 bv.bv_len = entry_flatsize( rs->sr_entry, 0 );
1822 bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );
1823
1824 ber_init2( ber, &bv, LBER_USE_DER );
1825 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
1826
1827 /* create new operation */
1828 myop = *op;
1829 /* FIXME: o_bd needed for ACL */
1830 myop.o_bd = op->o_bd;
1831 myop.o_res_ber = ber;
1832 myop.o_callback = NULL;
1833 myop.ors_slimit = 1;
1834 myop.ors_attrsonly = 0;
1835
1836 rc = slap_send_search_entry( &myop, rs );
1837 if( rc ) return rc;
1838
1839 rc = ber_flatten2( ber, &c.ldctl_value, 0 );
1840
1841 if( rc == -1 ) return LDAP_OTHER;
1842
1843 c.ldctl_oid = oid->bv_val;
1844 c.ldctl_iscritical = 0;
1845
1846 if ( *ctrl == NULL ) {
1847 /* first try */
1848 *ctrl = (LDAPControl *) slap_sl_calloc( 1, sizeof(LDAPControl), NULL );
1849 } else {
1850 /* retry: free previous try */
1851 slap_sl_free( (*ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
1852 }
1853
1854 **ctrl = c;
1855 return LDAP_SUCCESS;
1856 }
1857
1858 /* Map API errors to protocol errors... */
1859 int
slap_map_api2result(SlapReply * rs)1860 slap_map_api2result( SlapReply *rs )
1861 {
1862 switch(rs->sr_err) {
1863 case LDAP_SERVER_DOWN:
1864 return LDAP_UNAVAILABLE;
1865 case LDAP_LOCAL_ERROR:
1866 return LDAP_OTHER;
1867 case LDAP_ENCODING_ERROR:
1868 case LDAP_DECODING_ERROR:
1869 return LDAP_PROTOCOL_ERROR;
1870 case LDAP_TIMEOUT:
1871 return LDAP_UNAVAILABLE;
1872 case LDAP_AUTH_UNKNOWN:
1873 return LDAP_AUTH_METHOD_NOT_SUPPORTED;
1874 case LDAP_FILTER_ERROR:
1875 rs->sr_text = "Filter error";
1876 return LDAP_OTHER;
1877 case LDAP_USER_CANCELLED:
1878 rs->sr_text = "User cancelled";
1879 return LDAP_OTHER;
1880 case LDAP_PARAM_ERROR:
1881 return LDAP_PROTOCOL_ERROR;
1882 case LDAP_NO_MEMORY:
1883 return LDAP_OTHER;
1884 case LDAP_CONNECT_ERROR:
1885 return LDAP_UNAVAILABLE;
1886 case LDAP_NOT_SUPPORTED:
1887 return LDAP_UNWILLING_TO_PERFORM;
1888 case LDAP_CONTROL_NOT_FOUND:
1889 return LDAP_PROTOCOL_ERROR;
1890 case LDAP_NO_RESULTS_RETURNED:
1891 return LDAP_NO_SUCH_OBJECT;
1892 case LDAP_MORE_RESULTS_TO_RETURN:
1893 rs->sr_text = "More results to return";
1894 return LDAP_OTHER;
1895 case LDAP_CLIENT_LOOP:
1896 case LDAP_REFERRAL_LIMIT_EXCEEDED:
1897 return LDAP_LOOP_DETECT;
1898 default:
1899 if ( LDAP_API_ERROR(rs->sr_err) ) return LDAP_OTHER;
1900 return rs->sr_err;
1901 }
1902 }
1903
1904
1905 slap_mask_t
slap_attr_flags(AttributeName * an)1906 slap_attr_flags( AttributeName *an )
1907 {
1908 slap_mask_t flags = SLAP_ATTRS_UNDEFINED;
1909
1910 if ( an == NULL ) {
1911 flags |= ( SLAP_OPATTRS_NO | SLAP_USERATTRS_YES );
1912
1913 } else {
1914 flags |= an_find( an, slap_bv_all_operational_attrs )
1915 ? SLAP_OPATTRS_YES : SLAP_OPATTRS_NO;
1916 flags |= an_find( an, slap_bv_all_user_attrs )
1917 ? SLAP_USERATTRS_YES : SLAP_USERATTRS_NO;
1918 }
1919
1920 return flags;
1921 }
1922