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 = &sc; *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 = &sc; *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