1 /*        $NetBSD: bind.c,v 1.3 2021/08/14 16:15:00 christos Exp $    */
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2021 The OpenLDAP Foundation.
7  * Portions Copyright 2001-2003 Pierangelo Masarati.
8  * Portions Copyright 1999-2003 Howard Chu.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work was initially developed by the Howard Chu for inclusion
21  * in OpenLDAP Software and subsequently enhanced by Pierangelo
22  * Masarati.
23  */
24 
25 #include <sys/cdefs.h>
26 __RCSID("$NetBSD: bind.c,v 1.3 2021/08/14 16:15:00 christos Exp $");
27 
28 #include "portable.h"
29 
30 #include <stdio.h>
31 
32 #include <ac/errno.h>
33 #include <ac/socket.h>
34 #include <ac/string.h>
35 
36 
37 #define AVL_INTERNAL
38 #include "slap.h"
39 #include "../back-ldap/back-ldap.h"
40 #include "back-meta.h"
41 
42 #include "lutil_ldap.h"
43 
44 static int
45 meta_back_proxy_authz_bind(
46           metaconn_t                    *mc,
47           int                           candidate,
48           Operation           *op,
49           SlapReply           *rs,
50           ldap_back_send_t    sendok,
51           int                           dolock );
52 
53 static int
54 meta_back_single_bind(
55           Operation           *op,
56           SlapReply           *rs,
57           metaconn_t                    *mc,
58           int                           candidate );
59 
60 int
meta_back_bind(Operation * op,SlapReply * rs)61 meta_back_bind( Operation *op, SlapReply *rs )
62 {
63           metainfo_t          *mi = ( metainfo_t * )op->o_bd->be_private;
64           metaconn_t          *mc = NULL;
65 
66           int                 rc = LDAP_OTHER,
67                               i,
68                               gotit = 0,
69                               isroot = 0;
70 
71           SlapReply *candidates;
72 
73           rs->sr_err = LDAP_SUCCESS;
74 
75           Debug( LDAP_DEBUG_ARGS, "%s meta_back_bind: dn=\"%s\".\n",
76                     op->o_log_prefix, op->o_req_dn.bv_val );
77 
78           /* the test on the bind method should be superfluous */
79           switch ( be_rootdn_bind( op, rs ) ) {
80           case LDAP_SUCCESS:
81                     if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {
82                               /* frontend will return success */
83                               return rs->sr_err;
84                     }
85 
86                     isroot = 1;
87                     /* fallthru */
88 
89           case SLAP_CB_CONTINUE:
90                     break;
91 
92           default:
93                     /* be_rootdn_bind() sent result */
94                     return rs->sr_err;
95           }
96 
97           /* we need meta_back_getconn() not send result even on error,
98            * because we want to intercept the error and make it
99            * invalidCredentials */
100           mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND );
101           if ( !mc ) {
102                     Debug(LDAP_DEBUG_ANY,
103                           "%s meta_back_bind: no target " "for dn \"%s\" (%d%s%s).\n",
104                           op->o_log_prefix, op->o_req_dn.bv_val,
105                           rs->sr_err, rs->sr_text ? ". " : "",
106                           rs->sr_text ? rs->sr_text : "" );
107 
108                     /* FIXME: there might be cases where we don't want
109                      * to map the error onto invalidCredentials */
110                     switch ( rs->sr_err ) {
111                     case LDAP_NO_SUCH_OBJECT:
112                     case LDAP_UNWILLING_TO_PERFORM:
113                               rs->sr_err = LDAP_INVALID_CREDENTIALS;
114                               rs->sr_text = NULL;
115                               break;
116                     }
117                     send_ldap_result( op, rs );
118                     return rs->sr_err;
119           }
120 
121           candidates = meta_back_candidates_get( op );
122 
123           /*
124            * Each target is scanned ...
125            */
126           mc->mc_authz_target = META_BOUND_NONE;
127           for ( i = 0; i < mi->mi_ntargets; i++ ) {
128                     metatarget_t        *mt = mi->mi_targets[ i ];
129                     int                 lerr;
130 
131                     /*
132                      * Skip non-candidates
133                      */
134                     if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
135                               continue;
136                     }
137 
138                     if ( gotit == 0 ) {
139                               /* set rc to LDAP_SUCCESS only if at least
140                                * one candidate has been tried */
141                               rc = LDAP_SUCCESS;
142                               gotit = 1;
143 
144                     } else if ( !isroot ) {
145                               /*
146                                * A bind operation is expected to have
147                                * ONE CANDIDATE ONLY!
148                                */
149                               Debug( LDAP_DEBUG_ANY,
150                                         "### %s meta_back_bind: more than one"
151                                         " candidate selected...\n",
152                                         op->o_log_prefix );
153                     }
154 
155                     if ( isroot ) {
156                               if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE
157                                         || BER_BVISNULL( &mt->mt_idassert_authcDN ) )
158                               {
159                                         metasingleconn_t    *msc = &mc->mc_conns[ i ];
160 
161                                         /* skip the target if no pseudorootdn is provided */
162                                         if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
163                                                   ch_free( msc->msc_bound_ndn.bv_val );
164                                                   BER_BVZERO( &msc->msc_bound_ndn );
165                                         }
166 
167                                         if ( !BER_BVISNULL( &msc->msc_cred ) ) {
168                                                   /* destroy sensitive data */
169                                                   memset( msc->msc_cred.bv_val, 0,
170                                                             msc->msc_cred.bv_len );
171                                                   ch_free( msc->msc_cred.bv_val );
172                                                   BER_BVZERO( &msc->msc_cred );
173                                         }
174 
175                                         continue;
176                               }
177 
178 
179                               (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND, 1 );
180                               lerr = rs->sr_err;
181 
182                     } else {
183                               lerr = meta_back_single_bind( op, rs, mc, i );
184                     }
185 
186                     if ( lerr != LDAP_SUCCESS ) {
187                               rc = rs->sr_err = lerr;
188 
189                               /* FIXME: in some cases (e.g. unavailable)
190                                * do not assume it's not candidate; rather
191                                * mark this as an error to be eventually
192                                * reported to client */
193                               META_CANDIDATE_CLEAR( &candidates[ i ] );
194                               break;
195                     }
196           }
197 
198           /* must re-insert if local DN changed as result of bind */
199           if ( rc == LDAP_SUCCESS ) {
200                     if ( isroot ) {
201                               mc->mc_authz_target = META_BOUND_ALL;
202                     }
203 
204                     if ( !LDAP_BACK_PCONN_ISPRIV( mc )
205                               && !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) )
206                     {
207                               int                 lerr;
208 
209                               /* wait for all other ops to release the connection */
210                               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
211                               assert( mc->mc_refcnt == 1 );
212 #if META_BACK_PRINT_CONNTREE > 0
213                               meta_back_print_conntree( mi, ">>> meta_back_bind" );
214 #endif /* META_BACK_PRINT_CONNTREE */
215 
216                               /* delete all cached connections with the current connection */
217                               if ( LDAP_BACK_SINGLECONN( mi ) ) {
218                                         metaconn_t          *tmpmc;
219 
220                                         while ( ( tmpmc = ldap_tavl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
221                                         {
222                                                   assert( !LDAP_BACK_PCONN_ISPRIV( mc ) );
223                                                   Debug( LDAP_DEBUG_TRACE,
224                                                             "=>meta_back_bind: destroying conn %lu (refcnt=%u)\n",
225                                                             mc->mc_conn->c_connid, mc->mc_refcnt );
226 
227                                                   if ( tmpmc->mc_refcnt != 0 ) {
228                                                             /* taint it */
229                                                             LDAP_BACK_CONN_TAINTED_SET( tmpmc );
230 
231                                                   } else {
232                                                             /*
233                                                              * Needs a test because the handler may be corrupted,
234                                                              * and calling ldap_unbind on a corrupted header results
235                                                              * in a segmentation fault
236                                                              */
237                                                             meta_back_conn_free( tmpmc );
238                                                   }
239                                         }
240                               }
241 
242                               ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
243                               lerr = ldap_tavl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
244                                         meta_back_conndn_cmp, meta_back_conndn_dup );
245 #if META_BACK_PRINT_CONNTREE > 0
246                               meta_back_print_conntree( mi, "<<< meta_back_bind" );
247 #endif /* META_BACK_PRINT_CONNTREE */
248                               if ( lerr == 0 ) {
249 #if 0
250                                         /* NOTE: a connection cannot be privileged
251                                          * and be in the avl tree at the same time
252                                          */
253                                         if ( isroot ) {
254                                                   LDAP_BACK_CONN_ISPRIV_SET( mc );
255                                                   LDAP_BACK_PCONN_SET( mc, op );
256                                         }
257 #endif
258                                         LDAP_BACK_CONN_CACHED_SET( mc );
259 
260                               } else {
261                                         LDAP_BACK_CONN_CACHED_CLEAR( mc );
262                               }
263                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
264                     }
265           }
266 
267           if ( mc != NULL ) {
268                     meta_back_release_conn( mi, mc );
269           }
270 
271           /*
272            * rc is LDAP_SUCCESS if at least one bind succeeded,
273            * err is the last error that occurred during a bind;
274            * if at least (and at most?) one bind succeeds, fine.
275            */
276           if ( rc != LDAP_SUCCESS ) {
277 
278                     /*
279                      * deal with bind failure ...
280                      */
281 
282                     /*
283                      * no target was found within the naming context,
284                      * so bind must fail with invalid credentials
285                      */
286                     if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
287                               rs->sr_err = LDAP_INVALID_CREDENTIALS;
288                     } else {
289                               rs->sr_err = slap_map_api2result( rs );
290                     }
291                     send_ldap_result( op, rs );
292                     return rs->sr_err;
293 
294           }
295 
296           return LDAP_SUCCESS;
297 }
298 
299 static int
meta_back_bind_op_result(Operation * op,SlapReply * rs,metaconn_t * mc,int candidate,int msgid,ldap_back_send_t sendok,int dolock)300 meta_back_bind_op_result(
301           Operation           *op,
302           SlapReply           *rs,
303           metaconn_t                    *mc,
304           int                           candidate,
305           int                           msgid,
306           ldap_back_send_t    sendok,
307           int                           dolock )
308 {
309           metainfo_t                    *mi = ( metainfo_t * )op->o_bd->be_private;
310           metatarget_t                  *mt = mi->mi_targets[ candidate ];
311           metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
312           LDAPMessage                   *res;
313           struct timeval                tv;
314           int                           rc;
315           int                           nretries = mt->mt_nretries;
316 
317           Debug( LDAP_DEBUG_TRACE,
318                     ">>> %s meta_back_bind_op_result[%d]\n",
319                     op->o_log_prefix, candidate );
320 
321           /* make sure this is clean */
322           assert( rs->sr_ctrls == NULL );
323 
324           if ( rs->sr_err == LDAP_SUCCESS ) {
325                     time_t              stoptime = (time_t)(-1),
326                                         timeout;
327                     int                 timeout_err = op->o_protocol >= LDAP_VERSION3 ?
328                                         LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
329                     const char          *timeout_text = "Operation timed out";
330                     slap_op_t opidx = slap_req2op( op->o_tag );
331 
332                     /* since timeout is not specified, compute and use
333                      * the one specific to the ongoing operation */
334                     if ( opidx == LDAP_REQ_SEARCH ) {
335                               if ( op->ors_tlimit <= 0 ) {
336                                         timeout = 0;
337 
338                               } else {
339                                         timeout = op->ors_tlimit;
340                                         timeout_err = LDAP_TIMELIMIT_EXCEEDED;
341                                         timeout_text = NULL;
342                               }
343 
344                     } else {
345                               timeout = mt->mt_timeout[ opidx ];
346                     }
347 
348                     /* better than nothing :) */
349                     if ( timeout == 0 ) {
350                               if ( mi->mi_idle_timeout ) {
351                                         timeout = mi->mi_idle_timeout;
352 
353                               } else if ( mi->mi_conn_ttl ) {
354                                         timeout = mi->mi_conn_ttl;
355                               }
356                     }
357 
358                     if ( timeout ) {
359                               stoptime = op->o_time + timeout;
360                     }
361 
362                     LDAP_BACK_TV_SET( &tv );
363 
364                     /*
365                      * handle response!!!
366                      */
367 retry:;
368                     rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
369                     switch ( rc ) {
370                     case 0:
371                               if ( nretries != META_RETRY_NEVER
372                                         || ( timeout && slap_get_time() <= stoptime ) )
373                               {
374                                         ldap_pvt_thread_yield();
375                                         if ( nretries > 0 ) {
376                                                   nretries--;
377                                         }
378                                         tv = mt->mt_bind_timeout;
379                                         goto retry;
380                               }
381 
382                               /* don't let anyone else use this handler,
383                                * because there's a pending bind that will not
384                                * be acknowledged */
385                               if ( dolock) {
386                                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
387                               }
388                               assert( LDAP_BACK_CONN_BINDING( msc ) );
389 
390 #ifdef DEBUG_205
391                               Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n",
392                                         op->o_log_prefix, candidate, (void *)msc->msc_ld );
393 #endif /* DEBUG_205 */
394 
395                               meta_clear_one_candidate( op, mc, candidate );
396                               if ( dolock ) {
397                                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
398                               }
399 
400                               rs->sr_err = timeout_err;
401                               rs->sr_text = timeout_text;
402                               break;
403 
404                     case -1:
405                               ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
406                                         &rs->sr_err );
407 
408                               Debug(LDAP_DEBUG_ANY,
409                                     "### %s meta_back_bind_op_result[%d]: err=%d (%s) nretries=%d.\n",
410                                     op->o_log_prefix, candidate, rs->sr_err,
411                                     ldap_err2string(rs->sr_err), nretries );
412                               break;
413 
414                     default:
415                               /* only touch when activity actually took place... */
416                               if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
417                                         msc->msc_time = op->o_time;
418                               }
419 
420                               /* FIXME: matched? referrals? response controls? */
421                               rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
422                                                   NULL, NULL, NULL, NULL, 1 );
423                               if ( rc != LDAP_SUCCESS ) {
424                                         rs->sr_err = rc;
425                               }
426                               rs->sr_err = slap_map_api2result( rs );
427                               break;
428                     }
429           }
430 
431           rs->sr_err = slap_map_api2result( rs );
432 
433           Debug( LDAP_DEBUG_TRACE,
434                     "<<< %s meta_back_bind_op_result[%d] err=%d\n",
435                     op->o_log_prefix, candidate, rs->sr_err );
436 
437           return rs->sr_err;
438 }
439 
440 /*
441  * meta_back_single_bind
442  *
443  * attempts to perform a bind with creds
444  */
445 static int
meta_back_single_bind(Operation * op,SlapReply * rs,metaconn_t * mc,int candidate)446 meta_back_single_bind(
447           Operation           *op,
448           SlapReply           *rs,
449           metaconn_t                    *mc,
450           int                           candidate )
451 {
452           metainfo_t                    *mi = ( metainfo_t * )op->o_bd->be_private;
453           metatarget_t                  *mt = mi->mi_targets[ candidate ];
454           struct berval                 mdn = BER_BVNULL;
455           metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
456           int                           msgid;
457           dncookie            dc;
458           struct berval                 save_o_dn;
459           int                           save_o_do_not_cache;
460           LDAPControl                   **ctrls = NULL;
461 
462           if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
463                     ch_free( msc->msc_bound_ndn.bv_val );
464                     BER_BVZERO( &msc->msc_bound_ndn );
465           }
466 
467           if ( !BER_BVISNULL( &msc->msc_cred ) ) {
468                     /* destroy sensitive data */
469                     memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
470                     ch_free( msc->msc_cred.bv_val );
471                     BER_BVZERO( &msc->msc_cred );
472           }
473 
474           /*
475            * Rewrite the bind dn if needed
476            */
477           dc.target = mt;
478           dc.conn = op->o_conn;
479           dc.rs = rs;
480           dc.ctx = "bindDN";
481 
482           if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
483                     rs->sr_text = "DN rewrite error";
484                     rs->sr_err = LDAP_OTHER;
485                     return rs->sr_err;
486           }
487 
488           /* don't add proxyAuthz; set the bindDN */
489           save_o_dn = op->o_dn;
490           save_o_do_not_cache = op->o_do_not_cache;
491           op->o_do_not_cache = 1;
492           op->o_dn = op->o_req_dn;
493 
494           ctrls = op->o_ctrls;
495           rs->sr_err = meta_back_controls_add( op, rs, mc, candidate, &ctrls );
496           op->o_dn = save_o_dn;
497           op->o_do_not_cache = save_o_do_not_cache;
498           if ( rs->sr_err != LDAP_SUCCESS ) {
499                     goto return_results;
500           }
501 
502           /* FIXME: this fixes the bind problem right now; we need
503            * to use the asynchronous version to get the "matched"
504            * and more in case of failure ... */
505           /* FIXME: should we check if at least some of the op->o_ctrls
506            * can/should be passed? */
507           for (;;) {
508                     rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
509                               LDAP_SASL_SIMPLE, &op->orb_cred,
510                               ctrls, NULL, &msgid );
511                     if ( rs->sr_err != LDAP_X_CONNECTING ) {
512                               break;
513                     }
514                     ldap_pvt_thread_yield();
515           }
516 
517           mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
518 
519           meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND, 1 );
520           if ( rs->sr_err != LDAP_SUCCESS ) {
521                     goto return_results;
522           }
523 
524           /* If defined, proxyAuthz will be used also when
525            * back-ldap is the authorizing backend; for this
526            * purpose, a successful bind is followed by a
527            * bind with the configured identity assertion */
528           /* NOTE: use with care */
529           if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
530                     meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR, 1 );
531                     if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) {
532                               goto return_results;
533                     }
534                     goto cache_refresh;
535           }
536 
537           ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_ndn );
538           LDAP_BACK_CONN_ISBOUND_SET( msc );
539           mc->mc_authz_target = candidate;
540 
541           if ( META_BACK_TGT_SAVECRED( mt ) ) {
542                     if ( !BER_BVISNULL( &msc->msc_cred ) ) {
543                               memset( msc->msc_cred.bv_val, 0,
544                                         msc->msc_cred.bv_len );
545                     }
546                     ber_bvreplace( &msc->msc_cred, &op->orb_cred );
547                     ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
548           }
549 
550 cache_refresh:;
551           if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED
552                               && !BER_BVISEMPTY( &op->o_req_ndn ) )
553           {
554                     ( void )meta_dncache_update_entry( &mi->mi_cache,
555                                         &op->o_req_ndn, candidate );
556           }
557 
558 return_results:;
559           if ( mdn.bv_val != op->o_req_dn.bv_val ) {
560                     free( mdn.bv_val );
561           }
562 
563           if ( META_BACK_TGT_QUARANTINE( mt ) ) {
564                     meta_back_quarantine( op, rs, candidate );
565           }
566 
567           return rs->sr_err;
568 }
569 
570 /*
571  * meta_back_single_dobind
572  */
573 int
meta_back_single_dobind(Operation * op,SlapReply * rs,metaconn_t ** mcp,int candidate,ldap_back_send_t sendok,int nretries,int dolock)574 meta_back_single_dobind(
575           Operation           *op,
576           SlapReply           *rs,
577           metaconn_t                    **mcp,
578           int                           candidate,
579           ldap_back_send_t    sendok,
580           int                           nretries,
581           int                           dolock )
582 {
583           metainfo_t                    *mi = ( metainfo_t * )op->o_bd->be_private;
584           metatarget_t                  *mt = mi->mi_targets[ candidate ];
585           metaconn_t                    *mc = *mcp;
586           metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
587           int                           msgid;
588 
589           assert( !LDAP_BACK_CONN_ISBOUND( msc ) );
590 
591           /* NOTE: this obsoletes pseudorootdn */
592           if ( op->o_conn != NULL &&
593                     !op->o_do_not_cache &&
594                     ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
595                               BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
596                               ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) ||
597                               ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
598           {
599                     (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok, dolock );
600 
601           } else {
602                     char *binddn = "";
603                     struct berval cred = BER_BVC( "" );
604 
605                     /* use credentials if available */
606                     if ( !BER_BVISNULL( &msc->msc_bound_ndn )
607                               && !BER_BVISNULL( &msc->msc_cred ) )
608                     {
609                               binddn = msc->msc_bound_ndn.bv_val;
610                               cred = msc->msc_cred;
611                     }
612 
613                     /* FIXME: should we check if at least some of the op->o_ctrls
614                      * can/should be passed? */
615                     if(!dolock) {
616                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
617                     }
618 
619                     for (;;) {
620                               rs->sr_err = ldap_sasl_bind( msc->msc_ld,
621                                         binddn, LDAP_SASL_SIMPLE, &cred,
622                                         NULL, NULL, &msgid );
623                               if ( rs->sr_err != LDAP_X_CONNECTING ) {
624                                         break;
625                               }
626                               ldap_pvt_thread_yield();
627                     }
628 
629                     if(!dolock) {
630                               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
631                     }
632 
633                     rs->sr_err = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
634 
635                     /* if bind succeeded, but anonymous, clear msc_bound_ndn */
636                     if ( rs->sr_err != LDAP_SUCCESS || binddn[0] == '\0' ) {
637                               if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
638                                         ber_memfree( msc->msc_bound_ndn.bv_val );
639                                         BER_BVZERO( &msc->msc_bound_ndn );
640                               }
641 
642                               if ( !BER_BVISNULL( &msc->msc_cred ) ) {
643                                         memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
644                                         ber_memfree( msc->msc_cred.bv_val );
645                                         BER_BVZERO( &msc->msc_cred );
646                               }
647                     }
648           }
649 
650           if ( rs->sr_err != LDAP_SUCCESS ) {
651                     if ( dolock ) {
652                               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
653                     }
654                     LDAP_BACK_CONN_BINDING_CLEAR( msc );
655                     if ( META_BACK_ONERR_STOP( mi ) ) {
656                               LDAP_BACK_CONN_TAINTED_SET( mc );
657                               meta_back_release_conn_lock( mi, mc, 0 );
658                               *mcp = NULL;
659                     }
660                     if ( dolock ) {
661                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
662                     }
663           }
664 
665           if ( META_BACK_TGT_QUARANTINE( mt ) ) {
666                     meta_back_quarantine( op, rs, candidate );
667           }
668 
669           return rs->sr_err;
670 }
671 
672 /*
673  * meta_back_dobind
674  */
675 int
meta_back_dobind(Operation * op,SlapReply * rs,metaconn_t * mc,ldap_back_send_t sendok)676 meta_back_dobind(
677           Operation           *op,
678           SlapReply           *rs,
679           metaconn_t                    *mc,
680           ldap_back_send_t    sendok )
681 {
682           metainfo_t                    *mi = ( metainfo_t * )op->o_bd->be_private;
683 
684           int                           bound = 0,
685                                         i,
686                                         isroot = 0;
687 
688           SlapReply           *candidates;
689 
690           if ( be_isroot( op ) ) {
691                     isroot = 1;
692           }
693 
694           if ( LogTest( LDAP_DEBUG_TRACE ) ) {
695                     char buf[STRLENOF("4294967295U") + 1] = { 0 };
696                     mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
697 
698                     Debug( LDAP_DEBUG_TRACE,
699                               "%s meta_back_dobind: conn=%s%s\n",
700                               op->o_log_prefix, buf,
701                               isroot ? " (isroot)" : "" );
702           }
703 
704           /*
705            * all the targets are bound as pseudoroot
706            */
707           if ( mc->mc_authz_target == META_BOUND_ALL ) {
708                     bound = 1;
709                     goto done;
710           }
711 
712           candidates = meta_back_candidates_get( op );
713 
714           for ( i = 0; i < mi->mi_ntargets; i++ ) {
715                     metatarget_t                  *mt = mi->mi_targets[ i ];
716                     metasingleconn_t    *msc = &mc->mc_conns[ i ];
717                     int                           rc;
718 
719                     /*
720                      * Not a candidate
721                      */
722                     if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
723                               continue;
724                     }
725 
726                     assert( msc->msc_ld != NULL );
727 
728                     /*
729                      * If the target is already bound it is skipped
730                      */
731 
732 retry_binding:;
733                     ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
734                     if ( LDAP_BACK_CONN_ISBOUND( msc )
735                               || ( LDAP_BACK_CONN_ISANON( msc )
736                                         && mt->mt_idassert_authmethod == LDAP_AUTH_NONE ) )
737                     {
738                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
739                               ++bound;
740                               continue;
741 
742                     } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) )
743                     {
744                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
745                               ldap_pvt_thread_yield();
746                               goto retry_binding;
747 
748                     }
749 
750                     LDAP_BACK_CONN_BINDING_SET( msc );
751                     ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
752 
753                     rc = meta_back_single_dobind( op, rs, &mc, i,
754                               LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
755                     /*
756                      * NOTE: meta_back_single_dobind() already retries;
757                      * in case of failure, it resets mc...
758                      */
759                     if ( rc != LDAP_SUCCESS ) {
760                               if ( mc == NULL ) {
761                                         /* meta_back_single_dobind() already sent
762                                          * response and released connection */
763                                         goto send_err;
764                               }
765 
766                               if ( rc == LDAP_UNAVAILABLE ) {
767                                         /* FIXME: meta_back_retry() already re-calls
768                                          * meta_back_single_dobind() */
769                                         if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
770                                                   goto retry_ok;
771                                         }
772 
773                                         if ( mc != NULL ) {
774                                                   ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
775                                                   LDAP_BACK_CONN_BINDING_CLEAR( msc );
776                                                   meta_back_release_conn_lock( mi, mc, 0 );
777                                                   ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
778                                         }
779 
780                                         return 0;
781                               }
782 
783                               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
784                               LDAP_BACK_CONN_BINDING_CLEAR( msc );
785                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
786 
787                               Debug(LDAP_DEBUG_ANY,
788                                     "%s meta_back_dobind[%d]: (%s) err=%d (%s).\n",
789                                     op->o_log_prefix, i,
790                                     isroot ? op->o_bd->be_rootdn.bv_val : "anonymous",
791                                     rc, ldap_err2string(rc) );
792 
793                               /*
794                                * null cred bind should always succeed
795                                * as anonymous, so a failure means
796                                * the target is no longer candidate possibly
797                                * due to technical reasons (remote host down?)
798                                * so better clear the handle
799                                */
800                               /* leave the target candidate, but record the error for later use */
801                               candidates[ i ].sr_err = rc;
802                               if ( META_BACK_ONERR_STOP( mi ) ) {
803                                         bound = 0;
804                                         goto done;
805                               }
806 
807                               continue;
808                     } /* else */
809 
810 retry_ok:;
811                     Debug( LDAP_DEBUG_TRACE,
812                               "%s meta_back_dobind[%d]: "
813                               "(%s)\n",
814                               op->o_log_prefix, i,
815                               isroot ? op->o_bd->be_rootdn.bv_val : "anonymous" );
816 
817                     ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
818                     LDAP_BACK_CONN_BINDING_CLEAR( msc );
819                     if ( isroot ) {
820                               LDAP_BACK_CONN_ISBOUND_SET( msc );
821                     } else {
822                               LDAP_BACK_CONN_ISANON_SET( msc );
823                     }
824                     ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
825                     ++bound;
826           }
827 
828 done:;
829           if ( LogTest( LDAP_DEBUG_TRACE ) ) {
830                     char buf[STRLENOF("4294967295U") + 1] = { 0 };
831                     mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
832 
833                     Debug( LDAP_DEBUG_TRACE,
834                               "%s meta_back_dobind: conn=%s bound=%d\n",
835                               op->o_log_prefix, buf, bound );
836           }
837 
838           if ( bound == 0 ) {
839                     meta_back_release_conn( mi, mc );
840 
841 send_err:;
842                     if ( sendok & LDAP_BACK_SENDERR ) {
843                               if ( rs->sr_err == LDAP_SUCCESS ) {
844                                         rs->sr_err = LDAP_BUSY;
845                               }
846                               send_ldap_result( op, rs );
847                     }
848 
849                     return 0;
850           }
851 
852           return ( bound > 0 );
853 }
854 
855 /*
856  * meta_back_default_rebind
857  *
858  * This is a callback used for chasing referrals using the same
859  * credentials as the original user on this session.
860  */
861 int
meta_back_default_rebind(LDAP * ld,LDAP_CONST char * url,ber_tag_t request,ber_int_t msgid,void * params)862 meta_back_default_rebind(
863           LDAP                          *ld,
864           LDAP_CONST char               *url,
865           ber_tag_t           request,
866           ber_int_t           msgid,
867           void                          *params )
868 {
869           metasingleconn_t    *msc = ( metasingleconn_t * )params;
870 
871           return ldap_sasl_bind_s( ld, msc->msc_bound_ndn.bv_val,
872                               LDAP_SASL_SIMPLE, &msc->msc_cred,
873                               NULL, NULL, NULL );
874 }
875 
876 /*
877  * meta_back_default_urllist
878  *
879  * This is a callback used for mucking with the urllist
880  */
881 int
meta_back_default_urllist(LDAP * ld,LDAPURLDesc ** urllist,LDAPURLDesc ** url,void * params)882 meta_back_default_urllist(
883           LDAP                *ld,
884           LDAPURLDesc         **urllist,
885           LDAPURLDesc         **url,
886           void                *params )
887 {
888           metatarget_t        *mt = (metatarget_t *)params;
889           LDAPURLDesc         **urltail;
890 
891           if ( urllist == url ) {
892                     return LDAP_SUCCESS;
893           }
894 
895           for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
896                     /* count */ ;
897 
898           *urltail = *urllist;
899           *urllist = *url;
900           *url = NULL;
901 
902           ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
903           if ( mt->mt_uri ) {
904                     ch_free( mt->mt_uri );
905           }
906 
907           ldap_get_option( ld, LDAP_OPT_URI, (void *)&mt->mt_uri );
908           ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
909 
910           return LDAP_SUCCESS;
911 }
912 
913 int
meta_back_cancel(metaconn_t * mc,Operation * op,SlapReply * rs,ber_int_t msgid,int candidate,ldap_back_send_t sendok)914 meta_back_cancel(
915           metaconn_t                    *mc,
916           Operation           *op,
917           SlapReply           *rs,
918           ber_int_t           msgid,
919           int                           candidate,
920           ldap_back_send_t    sendok )
921 {
922           metainfo_t                    *mi = (metainfo_t *)op->o_bd->be_private;
923 
924           metatarget_t                  *mt = mi->mi_targets[ candidate ];
925           metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
926 
927           int                           rc = LDAP_OTHER;
928 
929           Debug( LDAP_DEBUG_TRACE, ">>> %s meta_back_cancel[%d] msgid=%d\n",
930                     op->o_log_prefix, candidate, msgid );
931 
932           /* default behavior */
933           if ( META_BACK_TGT_ABANDON( mt ) ) {
934                     rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
935 
936           } else if ( META_BACK_TGT_IGNORE( mt ) ) {
937                     rc = ldap_pvt_discard( msc->msc_ld, msgid );
938 
939           } else if ( META_BACK_TGT_CANCEL( mt ) ) {
940                     rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL );
941 
942           } else {
943                     assert( 0 );
944           }
945 
946           Debug( LDAP_DEBUG_TRACE, "<<< %s meta_back_cancel[%d] err=%d\n",
947                     op->o_log_prefix, candidate, rc );
948 
949           return rc;
950 }
951 
952 
953 
954 /*
955  * FIXME: error return must be handled in a cleaner way ...
956  */
957 int
meta_back_op_result(metaconn_t * mc,Operation * op,SlapReply * rs,int candidate,ber_int_t msgid,time_t timeout,ldap_back_send_t sendok)958 meta_back_op_result(
959           metaconn_t                    *mc,
960           Operation           *op,
961           SlapReply           *rs,
962           int                           candidate,
963           ber_int_t           msgid,
964           time_t                        timeout,
965           ldap_back_send_t    sendok )
966 {
967           metainfo_t          *mi = ( metainfo_t * )op->o_bd->be_private;
968 
969           const char          *save_text = rs->sr_text,
970                               *save_matched = rs->sr_matched;
971           BerVarray save_ref = rs->sr_ref;
972           LDAPControl         **save_ctrls = rs->sr_ctrls;
973           void                *matched_ctx = NULL;
974 
975           char                *matched = NULL;
976           char                *text = NULL;
977           char                **refs = NULL;
978           LDAPControl         **ctrls = NULL;
979 
980           assert( mc != NULL );
981 
982           rs->sr_text = NULL;
983           rs->sr_matched = NULL;
984           rs->sr_ref = NULL;
985           rs->sr_ctrls = NULL;
986 
987           if ( candidate != META_TARGET_NONE ) {
988                     metatarget_t                  *mt = mi->mi_targets[ candidate ];
989                     metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
990 
991                     if ( LDAP_ERR_OK( rs->sr_err ) ) {
992                               int                 rc;
993                               struct timeval      tv;
994                               LDAPMessage         *res = NULL;
995                               time_t              stoptime = (time_t)(-1);
996                               int                 timeout_err = op->o_protocol >= LDAP_VERSION3 ?
997                                                             LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
998                               const char          *timeout_text = "Operation timed out";
999 
1000                               /* if timeout is not specified, compute and use
1001                                * the one specific to the ongoing operation */
1002                               if ( timeout == (time_t)(-1) ) {
1003                                         slap_op_t opidx = slap_req2op( op->o_tag );
1004 
1005                                         if ( opidx == SLAP_OP_SEARCH ) {
1006                                                   if ( op->ors_tlimit <= 0 ) {
1007                                                             timeout = 0;
1008 
1009                                                   } else {
1010                                                             timeout = op->ors_tlimit;
1011                                                             timeout_err = LDAP_TIMELIMIT_EXCEEDED;
1012                                                             timeout_text = NULL;
1013                                                   }
1014 
1015                                         } else {
1016                                                   timeout = mt->mt_timeout[ opidx ];
1017                                         }
1018                               }
1019 
1020                               /* better than nothing :) */
1021                               if ( timeout == 0 ) {
1022                                         if ( mi->mi_idle_timeout ) {
1023                                                   timeout = mi->mi_idle_timeout;
1024 
1025                                         } else if ( mi->mi_conn_ttl ) {
1026                                                   timeout = mi->mi_conn_ttl;
1027                                         }
1028                               }
1029 
1030                               if ( timeout ) {
1031                                         stoptime = op->o_time + timeout;
1032                               }
1033 
1034                               LDAP_BACK_TV_SET( &tv );
1035 
1036 retry:;
1037                               rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
1038                               switch ( rc ) {
1039                               case 0:
1040                                         if ( timeout && slap_get_time() > stoptime ) {
1041                                                   (void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok );
1042                                                   rs->sr_err = timeout_err;
1043                                                   rs->sr_text = timeout_text;
1044                                                   break;
1045                                         }
1046 
1047                                         LDAP_BACK_TV_SET( &tv );
1048                                         ldap_pvt_thread_yield();
1049                                         goto retry;
1050 
1051                               case -1:
1052                                         ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
1053                                                             &rs->sr_err );
1054                                         break;
1055 
1056 
1057                               /* otherwise get the result; if it is not
1058                                * LDAP_SUCCESS, record it in the reply
1059                                * structure (this includes
1060                                * LDAP_COMPARE_{TRUE|FALSE}) */
1061                               default:
1062                                         /* only touch when activity actually took place... */
1063                                         if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
1064                                                   msc->msc_time = op->o_time;
1065                                         }
1066 
1067                                         rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
1068                                                             &matched, &text, &refs, &ctrls, 1 );
1069                                         res = NULL;
1070                                         if ( rc == LDAP_SUCCESS ) {
1071                                                   rs->sr_text = text;
1072                                         } else {
1073                                                   rs->sr_err = rc;
1074                                         }
1075                                         rs->sr_err = slap_map_api2result( rs );
1076 
1077                                         /* RFC 4511: referrals can only appear
1078                                          * if result code is LDAP_REFERRAL */
1079                                         if ( refs != NULL
1080                                                   && refs[ 0 ] != NULL
1081                                                   && refs[ 0 ][ 0 ] != '\0' )
1082                                         {
1083                                                   if ( rs->sr_err != LDAP_REFERRAL ) {
1084                                                             Debug( LDAP_DEBUG_ANY,
1085                                                                       "%s meta_back_op_result[%d]: "
1086                                                                       "got referrals with err=%d\n",
1087                                                                       op->o_log_prefix,
1088                                                                       candidate, rs->sr_err );
1089 
1090                                                   } else {
1091                                                             int       i;
1092 
1093                                                             for ( i = 0; refs[ i ] != NULL; i++ )
1094                                                                       /* count */ ;
1095                                                             rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
1096                                                                       op->o_tmpmemctx );
1097                                                             for ( i = 0; refs[ i ] != NULL; i++ ) {
1098                                                                       ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
1099                                                             }
1100                                                             BER_BVZERO( &rs->sr_ref[ i ] );
1101                                                   }
1102 
1103                                         } else if ( rs->sr_err == LDAP_REFERRAL ) {
1104                                                   Debug( LDAP_DEBUG_ANY,
1105                                                             "%s meta_back_op_result[%d]: "
1106                                                             "got err=%d with null "
1107                                                             "or empty referrals\n",
1108                                                             op->o_log_prefix,
1109                                                             candidate, rs->sr_err );
1110 
1111                                                   rs->sr_err = LDAP_NO_SUCH_OBJECT;
1112                                         }
1113 
1114                                         if ( ctrls != NULL ) {
1115                                                   rs->sr_ctrls = ctrls;
1116                                         }
1117                               }
1118 
1119                               assert( res == NULL );
1120                     }
1121 
1122                     /* if the error in the reply structure is not
1123                      * LDAP_SUCCESS, try to map it from client
1124                      * to server error */
1125                     if ( !LDAP_ERR_OK( rs->sr_err ) ) {
1126                               rs->sr_err = slap_map_api2result( rs );
1127 
1128                               /* internal ops ( op->o_conn == NULL )
1129                                * must not reply to client */
1130                               if ( op->o_conn && !op->o_do_not_cache && matched ) {
1131 
1132                                         /* record the (massaged) matched
1133                                          * DN into the reply structure */
1134                                         rs->sr_matched = matched;
1135                               }
1136                     }
1137 
1138                     if ( META_BACK_TGT_QUARANTINE( mt ) ) {
1139                               meta_back_quarantine( op, rs, candidate );
1140                     }
1141 
1142           } else {
1143                     int       i,
1144                               err = rs->sr_err;
1145 
1146                     for ( i = 0; i < mi->mi_ntargets; i++ ) {
1147                               metasingleconn_t    *msc = &mc->mc_conns[ i ];
1148                               char                          *xtext = NULL;
1149                               char                          *xmatched = NULL;
1150 
1151                               if ( msc->msc_ld == NULL ) {
1152                                         continue;
1153                               }
1154 
1155                               rs->sr_err = LDAP_SUCCESS;
1156 
1157                               ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err );
1158                               if ( rs->sr_err != LDAP_SUCCESS ) {
1159                                         /*
1160                                          * better check the type of error. In some cases
1161                                          * (search ?) it might be better to return a
1162                                          * success if at least one of the targets gave
1163                                          * positive result ...
1164                                          */
1165                                         ldap_get_option( msc->msc_ld,
1166                                                             LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext );
1167                                         if ( xtext != NULL && xtext [ 0 ] == '\0' ) {
1168                                                   ldap_memfree( xtext );
1169                                                   xtext = NULL;
1170                                         }
1171 
1172                                         ldap_get_option( msc->msc_ld,
1173                                                             LDAP_OPT_MATCHED_DN, &xmatched );
1174                                         if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) {
1175                                                   ldap_memfree( xmatched );
1176                                                   xmatched = NULL;
1177                                         }
1178 
1179                                         rs->sr_err = slap_map_api2result( rs );
1180 
1181                                         Debug(LDAP_DEBUG_ANY,
1182                                               "%s meta_back_op_result[%d] " "err=%d text=\"%s\" matched=\"%s\".\n",
1183                                               op->o_log_prefix, i, rs->sr_err,
1184                                               (xtext ? xtext : ""),
1185                                               (xmatched ? xmatched : "") );
1186 
1187                                         /*
1188                                          * FIXME: need to rewrite "match" (need rwinfo)
1189                                          */
1190                                         switch ( rs->sr_err ) {
1191                                         default:
1192                                                   err = rs->sr_err;
1193                                                   if ( xtext != NULL ) {
1194                                                             if ( text ) {
1195                                                                       ldap_memfree( text );
1196                                                             }
1197                                                             text = xtext;
1198                                                             xtext = NULL;
1199                                                   }
1200                                                   if ( xmatched != NULL ) {
1201                                                             if ( matched ) {
1202                                                                       ldap_memfree( matched );
1203                                                             }
1204                                                             matched = xmatched;
1205                                                             xmatched = NULL;
1206                                                   }
1207                                                   break;
1208                                         }
1209 
1210                                         if ( xtext ) {
1211                                                   ldap_memfree( xtext );
1212                                         }
1213 
1214                                         if ( xmatched ) {
1215                                                   ldap_memfree( xmatched );
1216                                         }
1217                               }
1218 
1219                               if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
1220                                         meta_back_quarantine( op, rs, i );
1221                               }
1222                     }
1223 
1224                     if ( err != LDAP_SUCCESS ) {
1225                               rs->sr_err = err;
1226                     }
1227           }
1228 
1229           if ( matched != NULL ) {
1230                     struct berval       dn, pdn;
1231 
1232                     ber_str2bv( matched, 0, 0, &dn );
1233                     if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
1234                               ldap_memfree( matched );
1235                               matched_ctx = op->o_tmpmemctx;
1236                               matched = pdn.bv_val;
1237                     }
1238                     rs->sr_matched = matched;
1239           }
1240 
1241           if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1242                     if ( !( sendok & LDAP_BACK_RETRYING ) ) {
1243                               if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1244                                         if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
1245                                         send_ldap_result( op, rs );
1246                               }
1247                     }
1248 
1249           } else if ( op->o_conn &&
1250                     ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
1251                               || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
1252           {
1253                     send_ldap_result( op, rs );
1254           }
1255           if ( matched ) {
1256                     op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
1257           }
1258           if ( text ) {
1259                     ldap_memfree( text );
1260           }
1261           if ( rs->sr_ref ) {
1262                     op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
1263                     rs->sr_ref = NULL;
1264           }
1265           if ( refs ) {
1266                     ber_memvfree( (void **)refs );
1267           }
1268           if ( ctrls ) {
1269                     assert( rs->sr_ctrls != NULL );
1270                     ldap_controls_free( ctrls );
1271           }
1272 
1273           rs->sr_text = save_text;
1274           rs->sr_matched = save_matched;
1275           rs->sr_ref = save_ref;
1276           rs->sr_ctrls = save_ctrls;
1277 
1278           return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
1279 }
1280 
1281 /*
1282  * meta_back_proxy_authz_cred()
1283  *
1284  * prepares credentials & method for meta_back_proxy_authz_bind();
1285  * or, if method is SASL, performs the SASL bind directly.
1286  */
1287 int
meta_back_proxy_authz_cred(metaconn_t * mc,int candidate,Operation * op,SlapReply * rs,ldap_back_send_t sendok,struct berval * binddn,struct berval * bindcred,int * method)1288 meta_back_proxy_authz_cred(
1289           metaconn_t                    *mc,
1290           int                           candidate,
1291           Operation           *op,
1292           SlapReply           *rs,
1293           ldap_back_send_t    sendok,
1294           struct berval                 *binddn,
1295           struct berval                 *bindcred,
1296           int                           *method )
1297 {
1298           metainfo_t                    *mi = (metainfo_t *)op->o_bd->be_private;
1299           metatarget_t                  *mt = mi->mi_targets[ candidate ];
1300           metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
1301           struct berval                 ndn;
1302           int                           dobind = 0;
1303 
1304           /* don't proxyAuthz if protocol is not LDAPv3 */
1305           switch ( mt->mt_version ) {
1306           case LDAP_VERSION3:
1307                     break;
1308 
1309           case 0:
1310                     if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1311                               break;
1312                     }
1313                     /* fall thru */
1314 
1315           default:
1316                     rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1317                     if ( sendok & LDAP_BACK_SENDERR ) {
1318                               send_ldap_result( op, rs );
1319                     }
1320                     LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1321                     goto done;
1322           }
1323 
1324           if ( op->o_tag == LDAP_REQ_BIND ) {
1325                     ndn = op->o_req_ndn;
1326 
1327           } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
1328                     ndn = op->o_conn->c_ndn;
1329 
1330           } else {
1331                     ndn = op->o_ndn;
1332           }
1333           rs->sr_err = LDAP_SUCCESS;
1334 
1335           /*
1336            * FIXME: we need to let clients use proxyAuthz
1337            * otherwise we cannot do symmetric pools of servers;
1338            * we have to live with the fact that a user can
1339            * authorize itself as any ID that is allowed
1340            * by the authzTo directive of the "proxyauthzdn".
1341            */
1342           /*
1343            * NOTE: current Proxy Authorization specification
1344            * and implementation do not allow proxy authorization
1345            * control to be provided with Bind requests
1346            */
1347           /*
1348            * if no bind took place yet, but the connection is bound
1349            * and the "proxyauthzdn" is set, then bind as
1350            * "proxyauthzdn" and explicitly add the proxyAuthz
1351            * control to every operation with the dn bound
1352            * to the connection as control value.
1353            */
1354 
1355           /* bind as proxyauthzdn only if no idassert mode
1356            * is requested, or if the client's identity
1357            * is authorized */
1358           switch ( mt->mt_idassert_mode ) {
1359           case LDAP_BACK_IDASSERT_LEGACY:
1360                     if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
1361                               if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) && !BER_BVISEMPTY( &mt->mt_idassert_authcDN ) )
1362                               {
1363                                         *binddn = mt->mt_idassert_authcDN;
1364                                         *bindcred = mt->mt_idassert_passwd;
1365                                         dobind = 1;
1366                               }
1367                     }
1368                     break;
1369 
1370           default:
1371                     /* NOTE: rootdn can always idassert */
1372                     if ( BER_BVISNULL( &ndn )
1373                               && mt->mt_idassert_authz == NULL
1374                               && !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
1375                     {
1376                               if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1377                                         rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1378                                         if ( sendok & LDAP_BACK_SENDERR ) {
1379                                                   send_ldap_result( op, rs );
1380                                         }
1381                                         LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1382                                         goto done;
1383 
1384                               }
1385 
1386                               rs->sr_err = LDAP_SUCCESS;
1387                               *binddn = slap_empty_bv;
1388                               *bindcred = slap_empty_bv;
1389                               break;
1390 
1391                     } else if ( mt->mt_idassert_authz && !be_isroot( op ) ) {
1392                               struct berval authcDN;
1393 
1394                               if ( BER_BVISNULL( &ndn ) ) {
1395                                         authcDN = slap_empty_bv;
1396 
1397                               } else {
1398                                         authcDN = ndn;
1399                               }
1400                               rs->sr_err = slap_sasl_matches( op, mt->mt_idassert_authz,
1401                                                   &authcDN, &authcDN );
1402                               if ( rs->sr_err != LDAP_SUCCESS ) {
1403                                         if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1404                                                   if ( sendok & LDAP_BACK_SENDERR ) {
1405                                                             send_ldap_result( op, rs );
1406                                                   }
1407                                                   LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1408                                                   goto done;
1409                                         }
1410 
1411                                         rs->sr_err = LDAP_SUCCESS;
1412                                         *binddn = slap_empty_bv;
1413                                         *bindcred = slap_empty_bv;
1414                                         break;
1415                               }
1416                     }
1417 
1418                     *binddn = mt->mt_idassert_authcDN;
1419                     *bindcred = mt->mt_idassert_passwd;
1420                     dobind = 1;
1421                     break;
1422           }
1423 
1424           if ( dobind && mt->mt_idassert_authmethod == LDAP_AUTH_SASL ) {
1425 #ifdef HAVE_CYRUS_SASL
1426                     void                *defaults = NULL;
1427                     struct berval       authzID = BER_BVNULL;
1428                     int                 freeauthz = 0;
1429 
1430                     /* if SASL supports native authz, prepare for it */
1431                     if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
1432                                         ( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
1433                     {
1434                               switch ( mt->mt_idassert_mode ) {
1435                               case LDAP_BACK_IDASSERT_OTHERID:
1436                               case LDAP_BACK_IDASSERT_OTHERDN:
1437                                         authzID = mt->mt_idassert_authzID;
1438                                         break;
1439 
1440                               case LDAP_BACK_IDASSERT_ANONYMOUS:
1441                                         BER_BVSTR( &authzID, "dn:" );
1442                                         break;
1443 
1444                               case LDAP_BACK_IDASSERT_SELF:
1445                                         if ( BER_BVISNULL( &ndn ) ) {
1446                                                   /* connection is not authc'd, so don't idassert */
1447                                                   BER_BVSTR( &authzID, "dn:" );
1448                                                   break;
1449                                         }
1450                                         authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
1451                                         authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
1452                                         AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
1453                                         AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
1454                                                             ndn.bv_val, ndn.bv_len + 1 );
1455                                         freeauthz = 1;
1456                                         break;
1457 
1458                               default:
1459                                         break;
1460                               }
1461                     }
1462 
1463                     if ( mt->mt_idassert_secprops != NULL ) {
1464                               rs->sr_err = ldap_set_option( msc->msc_ld,
1465                                         LDAP_OPT_X_SASL_SECPROPS,
1466                                         (void *)mt->mt_idassert_secprops );
1467 
1468                               if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
1469                                         rs->sr_err = LDAP_OTHER;
1470                                         if ( sendok & LDAP_BACK_SENDERR ) {
1471                                                   send_ldap_result( op, rs );
1472                                         }
1473                                         LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1474                                         goto done;
1475                               }
1476                     }
1477 
1478                     defaults = lutil_sasl_defaults( msc->msc_ld,
1479                                         mt->mt_idassert_sasl_mech.bv_val,
1480                                         mt->mt_idassert_sasl_realm.bv_val,
1481                                         mt->mt_idassert_authcID.bv_val,
1482                                         mt->mt_idassert_passwd.bv_val,
1483                                         authzID.bv_val );
1484                     if ( defaults == NULL ) {
1485                               rs->sr_err = LDAP_OTHER;
1486                               LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1487                               if ( sendok & LDAP_BACK_SENDERR ) {
1488                                         send_ldap_result( op, rs );
1489                               }
1490                               goto done;
1491                     }
1492 
1493                     rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val,
1494                                         mt->mt_idassert_sasl_mech.bv_val, NULL, NULL,
1495                                         LDAP_SASL_QUIET, lutil_sasl_interact,
1496                                         defaults );
1497 
1498                     rs->sr_err = slap_map_api2result( rs );
1499                     if ( rs->sr_err != LDAP_SUCCESS ) {
1500                               LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1501                               if ( sendok & LDAP_BACK_SENDERR ) {
1502                                         send_ldap_result( op, rs );
1503                               }
1504 
1505                     } else {
1506                               LDAP_BACK_CONN_ISBOUND_SET( msc );
1507                     }
1508 
1509                     lutil_sasl_freedefs( defaults );
1510                     if ( freeauthz ) {
1511                               slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
1512                     }
1513 
1514                     goto done;
1515 #endif /* HAVE_CYRUS_SASL */
1516           }
1517 
1518           *method = mt->mt_idassert_authmethod;
1519           switch ( mt->mt_idassert_authmethod ) {
1520           case LDAP_AUTH_NONE:
1521                     BER_BVSTR( binddn, "" );
1522                     BER_BVSTR( bindcred, "" );
1523                     /* fallthru */
1524 
1525           case LDAP_AUTH_SIMPLE:
1526                     break;
1527 
1528           default:
1529                     /* unsupported! */
1530                     LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1531                     rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
1532                     if ( sendok & LDAP_BACK_SENDERR ) {
1533                               send_ldap_result( op, rs );
1534                     }
1535                     break;
1536           }
1537 
1538 done:;
1539 
1540           if ( !BER_BVISEMPTY( binddn ) ) {
1541                     LDAP_BACK_CONN_ISIDASSERT_SET( msc );
1542           }
1543 
1544           return rs->sr_err;
1545 }
1546 
1547 static int
meta_back_proxy_authz_bind(metaconn_t * mc,int candidate,Operation * op,SlapReply * rs,ldap_back_send_t sendok,int dolock)1548 meta_back_proxy_authz_bind(
1549           metaconn_t *mc,
1550           int candidate,
1551           Operation *op,
1552           SlapReply *rs,
1553           ldap_back_send_t sendok,
1554           int dolock )
1555 {
1556           metainfo_t                    *mi = (metainfo_t *)op->o_bd->be_private;
1557           metatarget_t                  *mt = mi->mi_targets[ candidate ];
1558           metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
1559           struct berval                 binddn = BER_BVC( "" ),
1560                                         cred = BER_BVC( "" );
1561           int                           method = LDAP_AUTH_NONE,
1562                                         rc;
1563 
1564           rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, sendok, &binddn, &cred, &method );
1565           if ( rc == LDAP_SUCCESS && !LDAP_BACK_CONN_ISBOUND( msc ) ) {
1566                     int       msgid;
1567 
1568                     switch ( method ) {
1569                     case LDAP_AUTH_NONE:
1570                     case LDAP_AUTH_SIMPLE:
1571 
1572                               if(!dolock) {
1573                                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1574                               }
1575 
1576                               for (;;) {
1577                                         rs->sr_err = ldap_sasl_bind( msc->msc_ld,
1578                                                   binddn.bv_val, LDAP_SASL_SIMPLE,
1579                                                   &cred, NULL, NULL, &msgid );
1580                                         if ( rs->sr_err != LDAP_X_CONNECTING ) {
1581                                                   break;
1582                                         }
1583                                         ldap_pvt_thread_yield();
1584                               }
1585 
1586                               if(!dolock) {
1587                                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1588                               }
1589 
1590                               rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
1591                               if ( rc == LDAP_SUCCESS ) {
1592                                         /* set rebind stuff in case of successful proxyAuthz bind,
1593                                          * so that referral chasing is attempted using the right
1594                                          * identity */
1595                                         LDAP_BACK_CONN_ISBOUND_SET( msc );
1596                                         ber_bvreplace( &msc->msc_bound_ndn, &binddn );
1597 
1598                                         if ( META_BACK_TGT_SAVECRED( mt ) ) {
1599                                                   if ( !BER_BVISNULL( &msc->msc_cred ) ) {
1600                                                             memset( msc->msc_cred.bv_val, 0,
1601                                                                       msc->msc_cred.bv_len );
1602                                                   }
1603                                                   ber_bvreplace( &msc->msc_cred, &cred );
1604                                                   ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
1605                                         }
1606                               }
1607                               break;
1608 
1609                     default:
1610                               assert( 0 );
1611                               break;
1612                     }
1613           }
1614 
1615           return LDAP_BACK_CONN_ISBOUND( msc );
1616 }
1617 
1618 /*
1619  * Add controls;
1620  *
1621  * if any needs to be added, it is prepended to existing ones,
1622  * in a newly allocated array.  The companion function
1623  * mi->mi_ldap_extra->controls_free() must be used to restore the original
1624  * status of op->o_ctrls.
1625  */
1626 int
meta_back_controls_add(Operation * op,SlapReply * rs,metaconn_t * mc,int candidate,LDAPControl *** pctrls)1627 meta_back_controls_add(
1628                     Operation *op,
1629                     SlapReply *rs,
1630                     metaconn_t          *mc,
1631                     int                 candidate,
1632                     LDAPControl         ***pctrls )
1633 {
1634           metainfo_t                    *mi = (metainfo_t *)op->o_bd->be_private;
1635           metatarget_t                  *mt = mi->mi_targets[ candidate ];
1636           metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
1637 
1638           LDAPControl                   **ctrls = NULL;
1639           /* set to the maximum number of controls this backend can add */
1640           LDAPControl                   c[ 2 ] = {{ 0 }};
1641           int                           n = 0, i, j1 = 0, j2 = 0, skipped = 0;
1642 
1643           *pctrls = NULL;
1644 
1645           rs->sr_err = LDAP_SUCCESS;
1646 
1647           /* don't add controls if protocol is not LDAPv3 */
1648           switch ( mt->mt_version ) {
1649           case LDAP_VERSION3:
1650                     break;
1651 
1652           case 0:
1653                     if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1654                               break;
1655                     }
1656                     /* fall thru */
1657 
1658           default:
1659                     goto done;
1660           }
1661 
1662           /* put controls that go __before__ existing ones here */
1663 
1664           /* proxyAuthz for identity assertion */
1665           switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn,
1666                     mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) )
1667           {
1668           case SLAP_CB_CONTINUE:
1669                     break;
1670 
1671           case LDAP_SUCCESS:
1672                     j1++;
1673                     break;
1674 
1675           default:
1676                     goto done;
1677           }
1678 
1679           /* put controls that go __after__ existing ones here */
1680 
1681 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1682           /* session tracking */
1683           if ( META_BACK_TGT_ST_REQUEST( mt ) ) {
1684                     switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
1685                     case SLAP_CB_CONTINUE:
1686                               break;
1687 
1688                     case LDAP_SUCCESS:
1689                               j2++;
1690                               break;
1691 
1692                     default:
1693                               goto done;
1694                     }
1695           }
1696 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1697 
1698           if ( rs->sr_err == SLAP_CB_CONTINUE ) {
1699                     rs->sr_err = LDAP_SUCCESS;
1700           }
1701 
1702           /* if nothing to do, just bail out */
1703           if ( j1 == 0 && j2 == 0 ) {
1704                     goto done;
1705           }
1706 
1707           assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
1708 
1709           if ( op->o_ctrls ) {
1710                     for ( n = 0; op->o_ctrls[ n ]; n++ )
1711                               /* just count ctrls */ ;
1712           }
1713 
1714           ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
1715                               op->o_tmpmemctx );
1716           if ( j1 ) {
1717                     ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
1718                     *ctrls[ 0 ] = c[ 0 ];
1719                     for ( i = 1; i < j1; i++ ) {
1720                               ctrls[ i ] = &ctrls[ 0 ][ i ];
1721                               *ctrls[ i ] = c[ i ];
1722                     }
1723           }
1724 
1725           i = 0;
1726           if ( op->o_ctrls ) {
1727                     LDAPControl *proxyauthz = ldap_control_find(
1728                                         LDAP_CONTROL_PROXY_AUTHZ, op->o_ctrls, NULL );
1729 
1730                     for ( i = 0; op->o_ctrls[ i ]; i++ ) {
1731                               /* Only replace it if we generated one */
1732                               if ( j1 && proxyauthz && proxyauthz == op->o_ctrls[ i ] ) {
1733                                         /* Frontend has already checked only one is present */
1734                                         assert( skipped == 0 );
1735                                         skipped++;
1736                                         continue;
1737                               }
1738                               ctrls[ i + j1 - skipped ] = op->o_ctrls[ i ];
1739                     }
1740           }
1741 
1742           n += j1 - skipped;
1743           if ( j2 ) {
1744                     ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
1745                     *ctrls[ n ] = c[ j1 ];
1746                     for ( i = 1; i < j2; i++ ) {
1747                               ctrls[ n + i ] = &ctrls[ n ][ i ];
1748                               *ctrls[ n + i ] = c[ i ];
1749                     }
1750           }
1751 
1752           ctrls[ n + j2 ] = NULL;
1753 
1754 done:;
1755           if ( ctrls == NULL ) {
1756                     ctrls = op->o_ctrls;
1757           }
1758 
1759           *pctrls = ctrls;
1760 
1761           return rs->sr_err;
1762 }
1763 
1764