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