1 /*        $NetBSD: bind.c,v 1.3 2021/08/14 16:14:59 christos Exp $    */
2 
3 /* bind.c - ldap backend bind function */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1999-2021 The OpenLDAP Foundation.
8  * Portions Copyright 2000-2003 Pierangelo Masarati.
9  * Portions Copyright 1999-2003 Howard Chu.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* ACKNOWLEDGEMENTS:
21  * This work was initially developed by Howard Chu for inclusion
22  * in OpenLDAP Software and subsequently enhanced by Pierangelo
23  * Masarati.
24  */
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: bind.c,v 1.3 2021/08/14 16:14:59 christos Exp $");
28 
29 #include "portable.h"
30 
31 #include <stdio.h>
32 
33 #include <ac/errno.h>
34 #include <ac/socket.h>
35 #include <ac/string.h>
36 
37 #define AVL_INTERNAL
38 #include "slap.h"
39 #include "back-ldap.h"
40 #include "lutil.h"
41 #include "lutil_ldap.h"
42 #include "ldap_rq.h"
43 
44 #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ         "2.16.840.1.113730.3.4.12"
45 
46 #ifdef LDAP_DEVEL
47 #define SLAP_AUTH_DN 1
48 #endif
49 
50 #if LDAP_BACK_PRINT_CONNTREE > 0
51 
52 static const struct {
53           slap_mask_t         f;
54           char                c;
55 } flagsmap[] = {
56           { LDAP_BACK_FCONN_ISBOUND,    'B' },
57           { LDAP_BACK_FCONN_ISANON,     'A' },
58           { LDAP_BACK_FCONN_ISPRIV,     'P' },
59           { LDAP_BACK_FCONN_ISTLS,      'T' },
60           { LDAP_BACK_FCONN_BINDING,    'X' },
61           { LDAP_BACK_FCONN_TAINTED,    'E' },
62           { LDAP_BACK_FCONN_ABANDON,    'N' },
63           { LDAP_BACK_FCONN_ISIDASR,    'S' },
64           { LDAP_BACK_FCONN_CACHED,     'C' },
65           { 0,                                    '\0' }
66 };
67 
68 static void
ldap_back_conn_print(ldapconn_t * lc)69 ldap_back_conn_print( ldapconn_t *lc )
70 {
71           char buf[ SLAP_TEXT_BUFLEN ];
72           char fbuf[ sizeof("BAPTIENSC") ];
73           int i;
74 
75           ldap_back_conn2str( &lc->lc_base, buf, sizeof( buf ) );
76           for ( i = 0; flagsmap[ i ].c != '\0'; i++ ) {
77                     if ( lc->lc_lcflags & flagsmap[i].f ) {
78                               fbuf[i] = flagsmap[i].c;
79 
80                     } else {
81                               fbuf[i] = '.';
82                     }
83           }
84           fbuf[i] = '\0';
85 
86           fprintf( stderr, "lc=%p %s flags=0x%08x (%s)\n",
87                     (void *)lc, buf, lc->lc_lcflags, fbuf );
88 }
89 
90 
91 static char* priv2str[] = {
92           "privileged",
93           "privileged/TLS",
94           "anonymous",
95           "anonymous/TLS",
96           "bind",
97           "bind/TLS",
98           NULL
99 };
100 
101 void
ldap_back_print_conntree(ldapinfo_t * li,char * msg)102 ldap_back_print_conntree( ldapinfo_t *li, char *msg )
103 {
104           int       c;
105 
106           fprintf( stderr, "========> %s\n", msg );
107 
108           for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
109                     int                 i = 0;
110                     ldapconn_t          *lc;
111 
112                     fprintf( stderr, "  %s[%d]\n", priv2str[ c ], li->li_conn_priv[ c ].lic_num );
113 
114                     LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )
115                     {
116                               fprintf( stderr, "    [%d] ", i );
117                               ldap_back_conn_print( lc );
118                               i++;
119                     }
120           }
121 
122           if ( li->li_conninfo.lai_tree == 0 ) {
123                     fprintf( stderr, "\t(empty)\n" );
124 
125           } else {
126                     TAvlnode *edge = ldap_tavl_end( li->li_conninfo.lai_tree, TAVL_DIR_LEFT );
127                     while ( edge ) {
128                               ldap_back_conn_print( (ldapconn_t *)edge->avl_data );
129                               edge = ldap_tavl_next( edge, TAVL_DIR_RIGHT );
130                     }
131           }
132 
133           fprintf( stderr, "<======== %s\n", msg );
134 }
135 #endif /* LDAP_BACK_PRINT_CONNTREE */
136 
137 static int
138 ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock );
139 
140 static ldapconn_t *
141 ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
142           struct berval *binddn, struct berval *bindcred );
143 
144 static int
145 ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
146           struct berval *binddn, struct berval *bindcred );
147 
148 static int
149 ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs,
150           ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred );
151 
152 static int
153 ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs,
154           ldap_back_send_t sendok );
155 
156 static int
157 ldap_back_conndnlc_cmp( const void *c1, const void *c2 );
158 
159 static void
160 ldap_back_conn_prune( ldapinfo_t *li );
161 
162 static void
163 ldap_back_schedule_conn_expiry( ldapinfo_t *li, ldapconn_t *lc );
164 
165 ldapconn_t *
ldap_back_conn_delete(ldapinfo_t * li,ldapconn_t * lc)166 ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc )
167 {
168           if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
169                     if ( LDAP_BACK_CONN_CACHED( lc ) ) {
170                               assert( lc->lc_q.tqe_prev != NULL );
171                               assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
172                               li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
173                               LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
174                               LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
175                               LDAP_BACK_CONN_CACHED_CLEAR( lc );
176 
177                     } else {
178                               assert( LDAP_BACK_CONN_TAINTED( lc ) );
179                               assert( lc->lc_q.tqe_prev == NULL );
180                     }
181 
182           } else {
183                     ldapconn_t          *tmplc = NULL;
184 
185                     if ( LDAP_BACK_CONN_CACHED( lc ) ) {
186                               assert( !LDAP_BACK_CONN_TAINTED( lc ) );
187                               tmplc = ldap_tavl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
188                                         ldap_back_conndnlc_cmp );
189                               assert( tmplc == lc );
190                               LDAP_BACK_CONN_CACHED_CLEAR( lc );
191                     }
192 
193                     assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
194           }
195 
196           return lc;
197 }
198 
199 int
ldap_back_bind(Operation * op,SlapReply * rs)200 ldap_back_bind( Operation *op, SlapReply *rs )
201 {
202           ldapinfo_t                    *li = (ldapinfo_t *) op->o_bd->be_private;
203           ldapconn_t                    *lc;
204 
205           LDAPControl                   **ctrls = NULL;
206           struct berval                 save_o_dn;
207           int                           save_o_do_not_cache,
208                                         rc = 0;
209           ber_int_t           msgid;
210           ldap_back_send_t    retrying = LDAP_BACK_RETRYING;
211 
212           /* allow rootdn as a means to auth without the need to actually
213            * contact the proxied DSA */
214           switch ( be_rootdn_bind( op, rs ) ) {
215           case SLAP_CB_CONTINUE:
216                     break;
217 
218           default:
219                     return rs->sr_err;
220           }
221 
222           lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
223           if ( !lc ) {
224                     return rs->sr_err;
225           }
226 
227           /* we can do (almost) whatever we want with this conn,
228            * because either it's temporary, or it's marked as binding */
229           if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
230                     ch_free( lc->lc_bound_ndn.bv_val );
231                     BER_BVZERO( &lc->lc_bound_ndn );
232           }
233           if ( !BER_BVISNULL( &lc->lc_cred ) ) {
234                     memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len );
235                     ch_free( lc->lc_cred.bv_val );
236                     BER_BVZERO( &lc->lc_cred );
237           }
238           LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
239 
240           /* don't add proxyAuthz; set the bindDN */
241           save_o_dn = op->o_dn;
242           save_o_do_not_cache = op->o_do_not_cache;
243           op->o_dn = op->o_req_dn;
244           op->o_do_not_cache = 1;
245 
246           ctrls = op->o_ctrls;
247           rc = ldap_back_controls_add( op, rs, lc, &ctrls );
248           op->o_dn = save_o_dn;
249           op->o_do_not_cache = save_o_do_not_cache;
250           if ( rc != LDAP_SUCCESS ) {
251                     send_ldap_result( op, rs );
252                     ldap_back_release_conn( li, lc );
253                     return( rc );
254           }
255 
256 retry:;
257           /* method is always LDAP_AUTH_SIMPLE if we got here */
258           rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
259                               LDAP_SASL_SIMPLE,
260                               &op->orb_cred, ctrls, NULL, &msgid );
261           /* FIXME: should we always retry, or only when piping the bind
262            * in the "override" connection pool? */
263           rc = ldap_back_op_result( lc, op, rs, msgid,
264                     li->li_timeout[ SLAP_OP_BIND ],
265                     LDAP_BACK_BIND_SERR | retrying );
266           if ( rc == LDAP_UNAVAILABLE && retrying ) {
267                     retrying &= ~LDAP_BACK_RETRYING;
268                     if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_BIND_SERR ) ) {
269                               goto retry;
270                     }
271                     if ( !lc )
272                               return( rc );
273           }
274 
275           ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
276           ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
277           ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
278 
279           ldap_back_controls_free( op, rs, &ctrls );
280 
281           if ( rc == LDAP_SUCCESS ) {
282                     op->o_conn->c_authz_cookie = op->o_bd->be_private;
283 
284                     /* If defined, proxyAuthz will be used also when
285                      * back-ldap is the authorizing backend; for this
286                      * purpose, after a successful bind the connection
287                      * is left for further binds, and further operations
288                      * on this client connection will use a default
289                      * connection with identity assertion */
290                     /* NOTE: use with care */
291                     if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
292                               ldap_back_release_conn( li, lc );
293                               return( rc );
294                     }
295 
296                     /* rebind is now done inside ldap_back_proxy_authz_bind()
297                      * in case of success */
298                     LDAP_BACK_CONN_ISBOUND_SET( lc );
299                     ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
300 
301                     if ( !BER_BVISNULL( &lc->lc_cred ) ) {
302                               memset( lc->lc_cred.bv_val, 0,
303                                                   lc->lc_cred.bv_len );
304                     }
305 
306                     if ( LDAP_BACK_SAVECRED( li ) ) {
307                               ber_bvreplace( &lc->lc_cred, &op->orb_cred );
308                               ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
309 
310                     } else {
311                               lc->lc_cred.bv_len = 0;
312                     }
313           }
314 
315           /* must re-insert if local DN changed as result of bind */
316           if ( !LDAP_BACK_CONN_ISBOUND( lc )
317                     || ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
318                               && !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
319           {
320                     int                 lerr = -1;
321                     ldapconn_t          *tmplc;
322 
323                     /* wait for all other ops to release the connection */
324 retry_lock:;
325                     ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
326                     if ( lc->lc_refcnt > 1 ) {
327                               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
328                               ldap_pvt_thread_yield();
329                               goto retry_lock;
330                     }
331 
332 #if LDAP_BACK_PRINT_CONNTREE > 0
333                     ldap_back_print_conntree( li, ">>> ldap_back_bind" );
334 #endif /* LDAP_BACK_PRINT_CONNTREE */
335 
336                     assert( lc->lc_refcnt == 1 );
337                     ldap_back_conn_delete( li, lc );
338 
339                     /* delete all cached connections with the current connection */
340                     if ( LDAP_BACK_SINGLECONN( li ) ) {
341                               while ( ( tmplc = ldap_tavl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
342                               {
343                                         assert( !LDAP_BACK_PCONN_ISPRIV( lc ) );
344                                         Debug( LDAP_DEBUG_TRACE,
345                                                   "=>ldap_back_bind: destroying conn %lu (refcnt=%u)\n",
346                                                   lc->lc_conn->c_connid, lc->lc_refcnt );
347 
348                                         if ( tmplc->lc_refcnt != 0 ) {
349                                                   /* taint it */
350                                                   LDAP_BACK_CONN_TAINTED_SET( tmplc );
351                                                   LDAP_BACK_CONN_CACHED_CLEAR( tmplc );
352 
353                                         } else {
354                                                   /*
355                                                    * Needs a test because the handler may be corrupted,
356                                                    * and calling ldap_unbind on a corrupted header results
357                                                    * in a segmentation fault
358                                                    */
359                                                   ldap_back_conn_free( tmplc );
360                                         }
361                               }
362                     }
363 
364                     if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
365                               ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
366                               if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
367                                         LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
368                               }
369                               lerr = ldap_tavl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
370                                         ldap_back_conndn_cmp, ldap_back_conndn_dup );
371                     }
372 
373 #if LDAP_BACK_PRINT_CONNTREE > 0
374                     ldap_back_print_conntree( li, "<<< ldap_back_bind" );
375 #endif /* LDAP_BACK_PRINT_CONNTREE */
376 
377                     ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
378                     switch ( lerr ) {
379                     case 0:
380                               LDAP_BACK_CONN_CACHED_SET( lc );
381                               break;
382 
383                     case -1:
384                               /* duplicate; someone else successfully bound
385                                * on the same connection with the same identity;
386                                * we can do this because lc_refcnt == 1 */
387                               ldap_back_conn_free( lc );
388                               lc = NULL;
389                     }
390           }
391 
392           if ( lc != NULL ) {
393                     ldap_back_release_conn( li, lc );
394           }
395 
396           return( rc );
397 }
398 
399 /*
400  * ldap_back_conndn_cmp
401  *
402  * compares two ldapconn_t based on the value of the conn pointer
403  * and of the local DN; used by avl stuff for insert, lookup
404  * and direct delete
405  */
406 int
ldap_back_conndn_cmp(const void * c1,const void * c2)407 ldap_back_conndn_cmp( const void *c1, const void *c2 )
408 {
409           const ldapconn_t    *lc1 = (const ldapconn_t *)c1;
410           const ldapconn_t    *lc2 = (const ldapconn_t *)c2;
411           int rc;
412 
413           /* If local DNs don't match, it is definitely not a match */
414           /* For shared sessions, conn is NULL. Only explicitly
415            * bound sessions will have non-NULL conn.
416            */
417           rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
418           if ( rc == 0 ) {
419                     rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
420           }
421 
422           return rc;
423 }
424 
425 /*
426  * ldap_back_conndnlc_cmp
427  *
428  * compares two ldapconn_t based on the value of the conn pointer,
429  * the local DN and the lc pointer; used by avl stuff for insert, lookup
430  * and direct delete
431  */
432 static int
ldap_back_conndnlc_cmp(const void * c1,const void * c2)433 ldap_back_conndnlc_cmp( const void *c1, const void *c2 )
434 {
435           const ldapconn_t    *lc1 = (const ldapconn_t *)c1;
436           const ldapconn_t    *lc2 = (const ldapconn_t *)c2;
437           int rc;
438 
439           /* If local DNs don't match, it is definitely not a match */
440           /* For shared sessions, conn is NULL. Only explicitly
441            * bound sessions will have non-NULL conn.
442            */
443           rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
444           if ( rc == 0 ) {
445                     rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
446                     if ( rc == 0 ) {
447                               rc = SLAP_PTRCMP( lc1, lc2 );
448                     }
449           }
450 
451           return rc;
452 }
453 
454 /*
455  * ldap_back_conn_cmp
456  *
457  * compares two ldapconn_t based on the value of the conn pointer;
458  * used by avl stuff for delete of all conns with the same connid
459  */
460 int
ldap_back_conn_cmp(const void * c1,const void * c2)461 ldap_back_conn_cmp( const void *c1, const void *c2 )
462 {
463           const ldapconn_t    *lc1 = (const ldapconn_t *)c1;
464           const ldapconn_t    *lc2 = (const ldapconn_t *)c2;
465 
466           /* For shared sessions, conn is NULL. Only explicitly
467            * bound sessions will have non-NULL conn.
468            */
469           return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
470 }
471 
472 /*
473  * ldap_back_conndn_dup
474  *
475  * returns -1 in case a duplicate ldapconn_t has been inserted;
476  * used by avl stuff
477  */
478 int
ldap_back_conndn_dup(void * c1,void * c2)479 ldap_back_conndn_dup( void *c1, void *c2 )
480 {
481           ldapconn_t          *lc1 = (ldapconn_t *)c1;
482           ldapconn_t          *lc2 = (ldapconn_t *)c2;
483 
484           /* Cannot have more than one shared session with same DN */
485           if ( lc1->lc_conn == lc2->lc_conn &&
486                     dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )
487           {
488                     return -1;
489           }
490 
491           return 0;
492 }
493 
494 static int
ldap_back_freeconn(ldapinfo_t * li,ldapconn_t * lc,int dolock)495 ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock )
496 {
497           if ( dolock ) {
498                     ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
499           }
500 
501 #if LDAP_BACK_PRINT_CONNTREE > 0
502           ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
503 #endif /* LDAP_BACK_PRINT_CONNTREE */
504 
505           (void)ldap_back_conn_delete( li, lc );
506 
507           if ( lc->lc_refcnt == 0 ) {
508                     ldap_back_conn_free( (void *)lc );
509           }
510 
511 #if LDAP_BACK_PRINT_CONNTREE > 0
512           ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );
513 #endif /* LDAP_BACK_PRINT_CONNTREE */
514 
515           if ( dolock ) {
516                     ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
517           }
518 
519           return 0;
520 }
521 
522 #ifdef HAVE_TLS
523 static int
ldap_back_start_tls(LDAP * ld,int protocol,int * is_tls,const char * url,unsigned flags,int timeout,const char ** text)524 ldap_back_start_tls(
525           LDAP                *ld,
526           int                 protocol,
527           int                 *is_tls,
528           const char          *url,
529           unsigned  flags,
530           int                 timeout,
531           const char          **text )
532 {
533           int                 rc = LDAP_SUCCESS;
534 
535           /* start TLS ("tls-[try-]{start,propagate}" statements) */
536           if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
537                                         && !ldap_is_ldaps_url( url ) )
538           {
539 #ifdef SLAP_STARTTLS_ASYNCHRONOUS
540                     /*
541                      * use asynchronous StartTLS
542                      * in case, chase referral (not implemented yet)
543                      */
544                     int                 msgid;
545 
546                     if ( protocol == 0 ) {
547                               ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,
548                                                   (void *)&protocol );
549                     }
550 
551                     if ( protocol < LDAP_VERSION3 ) {
552                               /* we should rather bail out... */
553                               rc = LDAP_UNWILLING_TO_PERFORM;
554                               *text = "invalid protocol version";
555                     }
556 
557                     if ( rc == LDAP_SUCCESS ) {
558                               rc = ldap_start_tls( ld, NULL, NULL, &msgid );
559                     }
560 
561                     if ( rc == LDAP_SUCCESS ) {
562                               LDAPMessage         *res = NULL;
563                               struct timeval      tv;
564 
565                               if ( timeout ) {
566                                         tv.tv_sec = timeout;
567                                         tv.tv_usec = 0;
568                               } else {
569                                         LDAP_BACK_TV_SET( &tv );
570                               }
571                               rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
572                               if ( rc <= 0 ) {
573                                         rc = LDAP_UNAVAILABLE;
574 
575                               } else if ( rc == LDAP_RES_EXTENDED ) {
576                                         struct berval       *data = NULL;
577 
578                                         rc = ldap_parse_extended_result( ld, res,
579                                                             NULL, &data, 0 );
580                                         if ( rc == LDAP_SUCCESS ) {
581                                                   SlapReply rs;
582                                                   rc = ldap_parse_result( ld, res, &rs.sr_err,
583                                                             NULL, NULL, NULL, NULL, 1 );
584                                                   if ( rc != LDAP_SUCCESS ) {
585                                                             rs.sr_err = rc;
586                                                   }
587                                                   rc = slap_map_api2result( &rs );
588                                                   res = NULL;
589 
590                                                   /* FIXME: in case a referral
591                                                    * is returned, should we try
592                                                    * using it instead of the
593                                                    * configured URI? */
594                                                   if ( rc == LDAP_SUCCESS ) {
595                                                             rc = ldap_install_tls( ld );
596 
597                                                   } else if ( rc == LDAP_REFERRAL ) {
598                                                             rc = LDAP_UNWILLING_TO_PERFORM;
599                                                             *text = "unwilling to chase referral returned by Start TLS exop";
600                                                   }
601 
602                                                   if ( data ) {
603                                                             if ( data->bv_val ) {
604                                                                       ber_memfree( data->bv_val );
605                                                             }
606                                                             ber_memfree( data );
607                                                   }
608                                         }
609 
610                               } else {
611                                         rc = LDAP_OTHER;
612                               }
613 
614                               if ( res != NULL ) {
615                                         ldap_msgfree( res );
616                               }
617                     }
618 #else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
619                     /*
620                      * use synchronous StartTLS
621                      */
622                     rc = ldap_start_tls_s( ld, NULL, NULL );
623 #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
624 
625                     /* if StartTLS is requested, only attempt it if the URL
626                      * is not "ldaps://"; this may occur not only in case
627                      * of misconfiguration, but also when used in the chain
628                      * overlay, where the "uri" can be parsed out of a referral */
629                     switch ( rc ) {
630                     case LDAP_SUCCESS:
631                               *is_tls = 1;
632                               break;
633 
634                     case LDAP_SERVER_DOWN:
635                               break;
636 
637                     default:
638                               if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
639                                         *text = "could not start TLS";
640                                         break;
641                               }
642 
643                               /* in case Start TLS is not critical */
644                               *is_tls = 0;
645                               rc = LDAP_SUCCESS;
646                               break;
647                     }
648 
649           } else {
650                     *is_tls = 0;
651           }
652 
653           return rc;
654 }
655 #endif /* HAVE_TLS */
656 
657 static int
ldap_back_prepare_conn(ldapconn_t * lc,Operation * op,SlapReply * rs,ldap_back_send_t sendok)658 ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
659 {
660           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
661           int                 version;
662           LDAP                *ld = NULL;
663 #ifdef HAVE_TLS
664           int                 is_tls = op->o_conn->c_is_tls;
665           int                 flags = li->li_flags;
666           time_t              lctime = (time_t)(-1);
667           slap_bindconf *sb;
668 #endif /* HAVE_TLS */
669 
670           ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
671           rs->sr_err = ldap_initialize( &ld, li->li_uri );
672           ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
673           if ( rs->sr_err != LDAP_SUCCESS ) {
674                     goto error_return;
675           }
676 
677           if ( li->li_urllist_f ) {
678                     ldap_set_urllist_proc( ld, li->li_urllist_f, li->li_urllist_p );
679           }
680 
681           /* Set LDAP version. This will always succeed: If the client
682            * bound with a particular version, then so can we.
683            */
684           if ( li->li_version != 0 ) {
685                     version = li->li_version;
686 
687           } else if ( op->o_protocol != 0 ) {
688                     version = op->o_protocol;
689 
690           } else {
691                     /* assume it's an internal op; set to LDAPv3 */
692                     version = LDAP_VERSION3;
693           }
694           ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version );
695 
696           /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
697           ldap_set_option( ld, LDAP_OPT_REFERRALS,
698                     LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
699 
700           if ( li->li_network_timeout > 0 ) {
701                     struct timeval                tv;
702 
703                     tv.tv_sec = li->li_network_timeout;
704                     tv.tv_usec = 0;
705                     ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv );
706           }
707 
708           /* turn on network keepalive, if configured so */
709           slap_client_keepalive(ld, &li->li_tls.sb_keepalive);
710 
711           if ( li->li_tls.sb_tcp_user_timeout > 0 ) {
712                     ldap_set_option( ld, LDAP_OPT_TCP_USER_TIMEOUT,
713                                         &li->li_tls.sb_tcp_user_timeout );
714           }
715 
716 #ifdef HAVE_TLS
717           if ( LDAP_BACK_CONN_ISPRIV( lc ) ) {
718                     /* See "rationale" comment in ldap_back_getconn() */
719                     if ( li->li_acl_authmethod == LDAP_AUTH_NONE &&
720                                li->li_idassert_authmethod != LDAP_AUTH_NONE )
721                               sb = &li->li_idassert.si_bc;
722                     else
723                               sb = &li->li_acl;
724 
725           } else if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
726                     sb = &li->li_idassert.si_bc;
727 
728           } else {
729                     sb = &li->li_tls;
730           }
731 
732           bindconf_tls_set( sb, ld );
733 
734           /* if required by the bindconf configuration, force TLS */
735           if ( ( sb == &li->li_acl || sb == &li->li_idassert.si_bc ) &&
736                     sb->sb_tls_ctx )
737           {
738                     flags |= LDAP_BACK_F_USE_TLS;
739           }
740 
741           ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
742           assert( li->li_uri_mutex_do_not_lock == 0 );
743           li->li_uri_mutex_do_not_lock = 1;
744           rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
745                               li->li_uri, flags, li->li_timeout[ SLAP_OP_BIND ], &rs->sr_text );
746           li->li_uri_mutex_do_not_lock = 0;
747           ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
748           if ( rs->sr_err != LDAP_SUCCESS ) {
749                     ldap_unbind_ext( ld, NULL, NULL );
750                     rs->sr_text = "Start TLS failed";
751                     goto error_return;
752 
753           } else if ( li->li_idle_timeout ) {
754                     /* only touch when activity actually took place... */
755                     lctime = op->o_time;
756           }
757 #endif /* HAVE_TLS */
758 
759           lc->lc_ld = ld;
760           lc->lc_refcnt = 1;
761 #ifdef HAVE_TLS
762           if ( is_tls ) {
763                     LDAP_BACK_CONN_ISTLS_SET( lc );
764           } else {
765                     LDAP_BACK_CONN_ISTLS_CLEAR( lc );
766           }
767           if ( lctime != (time_t)(-1) ) {
768                     lc->lc_time = lctime;
769           }
770 #endif /* HAVE_TLS */
771 
772 error_return:;
773           if ( rs->sr_err != LDAP_SUCCESS ) {
774                     rs->sr_err = slap_map_api2result( rs );
775                     if ( sendok & LDAP_BACK_SENDERR ) {
776                               if ( rs->sr_text == NULL ) {
777                                         rs->sr_text = "Proxy connection initialization failed";
778                               }
779                               send_ldap_result( op, rs );
780                     }
781 
782           } else {
783                     if ( li->li_conn_ttl > 0 ) {
784                               lc->lc_create_time = op->o_time;
785                     }
786           }
787 
788           return rs->sr_err;
789 }
790 
791 static ldapconn_t *
ldap_back_getconn(Operation * op,SlapReply * rs,ldap_back_send_t sendok,struct berval * binddn,struct berval * bindcred)792 ldap_back_getconn(
793           Operation           *op,
794           SlapReply           *rs,
795           ldap_back_send_t    sendok,
796           struct berval                 *binddn,
797           struct berval                 *bindcred )
798 {
799           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
800           ldapconn_t          *lc = NULL,
801                               lc_curr = {{ 0 }};
802           int                 refcnt = 1,
803                               lookupconn = !( sendok & LDAP_BACK_BINDING );
804 
805           /* if the server is quarantined, and
806            * - the current interval did not expire yet, or
807            * - no more retries should occur,
808            * don't return the connection */
809           if ( li->li_isquarantined ) {
810                     slap_retry_info_t   *ri = &li->li_quarantine;
811                     int                           dont_retry = 1;
812 
813                     if ( li->li_quarantine.ri_interval ) {
814                               ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
815                               if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
816                                         dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
817                                                   || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
818                                         if ( !dont_retry ) {
819                                                   Debug( LDAP_DEBUG_ANY,
820                                                             "%s: ldap_back_getconn quarantine "
821                                                             "retry block #%d try #%d.\n",
822                                                             op->o_log_prefix, ri->ri_idx, ri->ri_count );
823                                                   li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
824                                         }
825                               }
826                               ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
827                     }
828 
829                     if ( dont_retry ) {
830                               rs->sr_err = LDAP_UNAVAILABLE;
831                               if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
832                                         rs->sr_text = "Target is quarantined";
833                                         send_ldap_result( op, rs );
834                               }
835                               return NULL;
836                     }
837           }
838 
839           /* Internal searches are privileged and shared. So is root. */
840           if ( op->o_do_not_cache || be_isroot( op ) ) {
841                     LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
842                     lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
843                     LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
844 
845           } else {
846                     struct berval       tmpbinddn,
847                                         tmpbindcred,
848                                         save_o_dn,
849                                         save_o_ndn;
850                     int                 isproxyauthz;
851 
852                     /* need cleanup */
853                     if ( binddn == NULL ) {
854                               binddn = &tmpbinddn;
855                     }
856                     if ( bindcred == NULL ) {
857                               bindcred = &tmpbindcred;
858                     }
859                     if ( op->o_tag == LDAP_REQ_BIND ) {
860                               save_o_dn = op->o_dn;
861                               save_o_ndn = op->o_ndn;
862                               op->o_dn = op->o_req_dn;
863                               op->o_ndn = op->o_req_ndn;
864                     }
865                     isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred );
866                     if ( op->o_tag == LDAP_REQ_BIND ) {
867                               op->o_dn = save_o_dn;
868                               op->o_ndn = save_o_ndn;
869                     }
870                     if ( isproxyauthz == -1 ) {
871                               return NULL;
872                     }
873 
874                     lc_curr.lc_local_ndn = op->o_ndn;
875                     /* Explicit binds must not be shared;
876                      * however, explicit binds are piped in a special connection
877                      * when idassert is to occur with "override" set */
878                     if ( op->o_tag == LDAP_REQ_BIND && !isproxyauthz ) {
879                               lc_curr.lc_conn = op->o_conn;
880 
881                     } else {
882                               if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
883                                         lc_curr.lc_local_ndn = *binddn;
884                                         LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
885                                         LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
886 
887                               } else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) {
888                                         lc_curr.lc_local_ndn = slap_empty_bv;
889                                         LDAP_BACK_PCONN_BIND_SET( &lc_curr, op );
890                                         LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
891                                         lookupconn = 1;
892 
893                               } else if ( SLAP_IS_AUTHZ_BACKEND( op ) ) {
894                                         lc_curr.lc_conn = op->o_conn;
895 
896                               } else {
897                                         LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
898                               }
899                     }
900           }
901 
902           /* Explicit Bind requests always get their own conn */
903           if ( lookupconn ) {
904 retry_lock:
905                     ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
906                     if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) {
907                               /* lookup a conn that's not binding */
908                               LDAP_TAILQ_FOREACH( lc,
909                                         &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv,
910                                         lc_q )
911                               {
912                                         if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) {
913                                                   break;
914                                         }
915                               }
916 
917                               if ( lc != NULL ) {
918                                         if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
919                                                   lc_conn_priv_q ) )
920                                         {
921                                                   LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
922                                                             lc, lc_q );
923                                                   LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
924                                                   LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
925                                                             lc, lc_q );
926                                         }
927 
928                               } else if ( !LDAP_BACK_USE_TEMPORARIES( li )
929                                         && li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max )
930                               {
931                                         lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv );
932                               }
933 
934                     } else {
935 
936                               /* Searches for a ldapconn in the avl tree */
937                               lc = (ldapconn_t *)ldap_tavl_find( li->li_conninfo.lai_tree,
938                                                   (caddr_t)&lc_curr, ldap_back_conndn_cmp );
939                     }
940 
941                     if ( lc != NULL ) {
942                               /* Don't reuse connections while they're still binding */
943                               if ( LDAP_BACK_CONN_BINDING( lc ) ) {
944                                         if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) {
945                                                   ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
946 
947                                                   ldap_pvt_thread_yield();
948                                                   goto retry_lock;
949                                         }
950                                         lc = NULL;
951                               }
952 
953                               if ( lc != NULL ) {
954                                         if ( op->o_tag == LDAP_REQ_BIND ) {
955                                                   /* right now, this is the only possible case */
956                                                   assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) );
957                                                   LDAP_BACK_CONN_BINDING_SET( lc );
958                                         }
959 
960                                         refcnt = ++lc->lc_refcnt;
961                               }
962                     }
963                     ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
964           }
965 
966           /* Looks like we didn't get a bind. Open a new session... */
967           if ( lc == NULL ) {
968                     lc = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) );
969                     lc->lc_flags = li->li_flags;
970                     lc->lc_lcflags = lc_curr.lc_lcflags;
971                     lc->lc_ldapinfo = li;
972                     if ( ldap_back_prepare_conn( lc, op, rs, sendok ) != LDAP_SUCCESS ) {
973                               ch_free( lc );
974                               return NULL;
975                     }
976 
977                     if ( sendok & LDAP_BACK_BINDING ) {
978                               LDAP_BACK_CONN_BINDING_SET( lc );
979                     }
980 
981                     lc->lc_conn = lc_curr.lc_conn;
982                     ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
983 
984                     /*
985                      * the rationale is: connections as the rootdn are privileged,
986                      * so li_acl is to be used; however, in some cases
987                      * one already configured identity assertion with a highly
988                      * privileged idassert_authcDN, so if li_acl is not configured
989                      * and idassert is, use idassert instead.
990                      *
991                      * might change in the future, because it's preferable
992                      * to make clear what identity is being used, since
993                      * the only drawback is that one risks to configure
994                      * the same identity twice...
995                      */
996                     if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) {
997                               if ( li->li_acl_authmethod == LDAP_AUTH_NONE &&
998                                          li->li_idassert_authmethod != LDAP_AUTH_NONE ) {
999                                         ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
1000                                         ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
1001 
1002                               } else {
1003                                         ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN );
1004                                         ber_dupbv( &lc->lc_cred, &li->li_acl_passwd );
1005                               }
1006                               LDAP_BACK_CONN_ISPRIV_SET( lc );
1007 
1008                     } else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) {
1009                               if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) {
1010                                         ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
1011                                         ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
1012                               }
1013                               LDAP_BACK_CONN_ISIDASSERT_SET( lc );
1014 
1015                     } else {
1016                               BER_BVZERO( &lc->lc_cred );
1017                               BER_BVZERO( &lc->lc_bound_ndn );
1018                               if ( !BER_BVISEMPTY( &op->o_ndn )
1019                                         && SLAP_IS_AUTHZ_BACKEND( op ) )
1020                               {
1021                                         ber_dupbv( &lc->lc_bound_ndn, &op->o_ndn );
1022                               }
1023                     }
1024 
1025 #ifdef HAVE_TLS
1026                     /* if start TLS failed but it was not mandatory,
1027                      * check if the non-TLS connection was already
1028                      * in cache; in case, destroy the newly created
1029                      * connection and use the existing one */
1030                     if ( LDAP_BACK_PCONN_ISTLS( lc )
1031                                         && !ldap_tls_inplace( lc->lc_ld ) )
1032                     {
1033                               ldapconn_t          *tmplc = NULL;
1034                               int                 idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1;
1035 
1036                               ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1037                               LDAP_TAILQ_FOREACH( tmplc,
1038                                         &li->li_conn_priv[ idx ].lic_priv,
1039                                         lc_q )
1040                               {
1041                                         if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) {
1042                                                   break;
1043                                         }
1044                               }
1045 
1046                               if ( tmplc != NULL ) {
1047                                         refcnt = ++tmplc->lc_refcnt;
1048                                         ldap_back_conn_free( lc );
1049                                         lc = tmplc;
1050                               }
1051                               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1052 
1053                               if ( tmplc != NULL ) {
1054                                         goto done;
1055                               }
1056                     }
1057 #endif /* HAVE_TLS */
1058 
1059                     /* Inserts the newly created ldapconn in the avl tree */
1060                     ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1061 
1062                     LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
1063                     lc->lc_connid = li->li_conn_nextid++;
1064 
1065                     assert( lc->lc_refcnt == 1 );
1066 
1067 #if LDAP_BACK_PRINT_CONNTREE > 0
1068                     ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" );
1069 #endif /* LDAP_BACK_PRINT_CONNTREE */
1070 
1071                     if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
1072                               if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) {
1073                                         LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
1074                                         li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++;
1075                                         LDAP_BACK_CONN_CACHED_SET( lc );
1076 
1077                               } else {
1078                                         LDAP_BACK_CONN_TAINTED_SET( lc );
1079                               }
1080                               rs->sr_err = 0;
1081 
1082                     } else {
1083                               rs->sr_err = ldap_tavl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
1084                                         ldap_back_conndn_cmp, ldap_back_conndn_dup );
1085                               LDAP_BACK_CONN_CACHED_SET( lc );
1086                     }
1087 
1088 #if LDAP_BACK_PRINT_CONNTREE > 0
1089                     ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" );
1090 #endif /* LDAP_BACK_PRINT_CONNTREE */
1091 
1092                     ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1093 
1094                     Debug(LDAP_DEBUG_TRACE,
1095                           "=>ldap_back_getconn: %s: lc=%p inserted refcnt=%u rc=%d\n",
1096                           op->o_log_prefix, (void *)lc, refcnt,
1097                           rs->sr_err );
1098 
1099                     if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) {
1100                               /* Err could be -1 in case a duplicate ldapconn is inserted */
1101                               switch ( rs->sr_err ) {
1102                               case 0:
1103                                         break;
1104 
1105                               case -1:
1106                                         LDAP_BACK_CONN_CACHED_CLEAR( lc );
1107                                         if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
1108                                                   /* duplicate: free and try to get the newly created one */
1109                                                   ldap_back_conn_free( lc );
1110                                                   lc = NULL;
1111                                                   goto retry_lock;
1112                                         }
1113 
1114                                         /* taint connection, so that it'll be freed when released */
1115                                         LDAP_BACK_CONN_TAINTED_SET( lc );
1116                                         break;
1117 
1118                               default:
1119                                         LDAP_BACK_CONN_CACHED_CLEAR( lc );
1120                                         ldap_back_conn_free( lc );
1121                                         rs->sr_err = LDAP_OTHER;
1122                                         rs->sr_text = "Proxy bind collision";
1123                                         if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1124                                                   send_ldap_result( op, rs );
1125                                         }
1126                                         return NULL;
1127                               }
1128                     }
1129                     ldap_back_schedule_conn_expiry( li, lc );
1130 
1131           } else {
1132                     int       expiring = 0;
1133 
1134                     if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout )
1135                               || ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) )
1136                     {
1137                               expiring = 1;
1138 
1139                               /* let it be used, but taint/delete it so that
1140                                * no-one else can look it up any further */
1141                               ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1142 
1143 #if LDAP_BACK_PRINT_CONNTREE > 0
1144                               ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
1145 #endif /* LDAP_BACK_PRINT_CONNTREE */
1146 
1147                               (void)ldap_back_conn_delete( li, lc );
1148                               LDAP_BACK_CONN_TAINTED_SET( lc );
1149 
1150 #if LDAP_BACK_PRINT_CONNTREE > 0
1151                               ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
1152 #endif /* LDAP_BACK_PRINT_CONNTREE */
1153 
1154                               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1155                     }
1156 
1157                     Debug(LDAP_DEBUG_TRACE,
1158                           "=>ldap_back_getconn: conn %p fetched refcnt=%u%s.\n",
1159                           (void *)lc, refcnt, expiring ? " expiring" : "" );
1160           }
1161 
1162 #ifdef HAVE_TLS
1163 done:;
1164 #endif /* HAVE_TLS */
1165 
1166           return lc;
1167 }
1168 
1169 void
ldap_back_release_conn_lock(ldapinfo_t * li,ldapconn_t ** lcp,int dolock)1170 ldap_back_release_conn_lock(
1171           ldapinfo_t                    *li,
1172           ldapconn_t                    **lcp,
1173           int                           dolock )
1174 {
1175 
1176           ldapconn_t          *lc = *lcp;
1177 
1178           if ( dolock ) {
1179                     ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1180           }
1181           assert( lc->lc_refcnt > 0 );
1182           LDAP_BACK_CONN_BINDING_CLEAR( lc );
1183           lc->lc_refcnt--;
1184           if ( LDAP_BACK_CONN_TAINTED( lc ) ) {
1185                     ldap_back_freeconn( li, lc, 0 );
1186                     *lcp = NULL;
1187           }
1188           if ( dolock ) {
1189                     ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1190           }
1191 }
1192 
1193 void
ldap_back_quarantine(Operation * op,SlapReply * rs)1194 ldap_back_quarantine(
1195           Operation *op,
1196           SlapReply *rs )
1197 {
1198           ldapinfo_t                    *li = (ldapinfo_t *)op->o_bd->be_private;
1199 
1200           slap_retry_info_t   *ri = &li->li_quarantine;
1201 
1202           ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
1203 
1204           if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1205                     time_t              new_last = slap_get_time();
1206 
1207                     switch ( li->li_isquarantined ) {
1208                     case LDAP_BACK_FQ_NO:
1209                               if ( ri->ri_last == new_last ) {
1210                                         goto done;
1211                               }
1212 
1213                               Debug( LDAP_DEBUG_ANY,
1214                                         "%s: ldap_back_quarantine enter.\n",
1215                                         op->o_log_prefix );
1216 
1217                               ri->ri_idx = 0;
1218                               ri->ri_count = 0;
1219                               break;
1220 
1221                     case LDAP_BACK_FQ_RETRYING:
1222                               Debug( LDAP_DEBUG_ANY,
1223                                         "%s: ldap_back_quarantine block #%d try #%d failed.\n",
1224                                         op->o_log_prefix, ri->ri_idx, ri->ri_count );
1225 
1226                               ++ri->ri_count;
1227                               if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER
1228                                         && ri->ri_count == ri->ri_num[ ri->ri_idx ] )
1229                               {
1230                                         ri->ri_count = 0;
1231                                         ++ri->ri_idx;
1232                               }
1233                               break;
1234 
1235                     default:
1236                               goto done;
1237                     }
1238 
1239                     li->li_isquarantined = LDAP_BACK_FQ_YES;
1240                     ri->ri_last = new_last;
1241 
1242           } else if ( li->li_isquarantined != LDAP_BACK_FQ_NO ) {
1243                     if ( ri->ri_last == slap_get_time() ) {
1244                               goto done;
1245                     }
1246 
1247                     Debug( LDAP_DEBUG_ANY,
1248                               "%s: ldap_back_quarantine exit (%d) err=%d.\n",
1249                               op->o_log_prefix, li->li_isquarantined, rs->sr_err );
1250 
1251                     if ( li->li_quarantine_f ) {
1252                               (void)li->li_quarantine_f( li, li->li_quarantine_p );
1253                     }
1254 
1255                     ri->ri_count = 0;
1256                     ri->ri_idx = 0;
1257                     li->li_isquarantined = LDAP_BACK_FQ_NO;
1258           }
1259 
1260 done:;
1261           ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
1262 }
1263 
1264 static int
ldap_back_dobind_cb(Operation * op,SlapReply * rs)1265 ldap_back_dobind_cb(
1266           Operation *op,
1267           SlapReply *rs
1268 )
1269 {
1270           ber_tag_t *tptr = op->o_callback->sc_private;
1271           op->o_tag = *tptr;
1272           rs->sr_tag = slap_req2res( op->o_tag );
1273 
1274           return SLAP_CB_CONTINUE;
1275 }
1276 
1277 /*
1278  * ldap_back_dobind_int
1279  *
1280  * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
1281  */
1282 static int
ldap_back_dobind_int(ldapconn_t ** lcp,Operation * op,SlapReply * rs,ldap_back_send_t sendok,int retries,int dolock)1283 ldap_back_dobind_int(
1284           ldapconn_t                    **lcp,
1285           Operation           *op,
1286           SlapReply           *rs,
1287           ldap_back_send_t    sendok,
1288           int                           retries,
1289           int                           dolock )
1290 {
1291           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
1292 
1293           ldapconn_t          *lc;
1294           struct berval       binddn = slap_empty_bv,
1295                               bindcred = slap_empty_bv;
1296 
1297           int                 rc = 0,
1298                               isbound,
1299                               binding = 0;
1300           ber_int_t msgid;
1301           ber_tag_t o_tag = op->o_tag;
1302           slap_callback cb = {0};
1303           char                *tmp_dn;
1304 
1305           assert( lcp != NULL );
1306           assert( retries >= 0 );
1307 
1308           if ( sendok & LDAP_BACK_GETCONN ) {
1309                     assert( *lcp == NULL );
1310 
1311                     lc = ldap_back_getconn( op, rs, sendok, &binddn, &bindcred );
1312                     if ( lc == NULL ) {
1313                               return 0;
1314                     }
1315                     *lcp = lc;
1316 
1317           } else {
1318                     lc = *lcp;
1319           }
1320 
1321           assert( lc != NULL );
1322 
1323 retry_lock:;
1324           if ( dolock ) {
1325                     ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1326           }
1327 
1328           if ( binding == 0 ) {
1329                     /* check if already bound */
1330                     rc = isbound = LDAP_BACK_CONN_ISBOUND( lc );
1331                     if ( isbound ) {
1332                               if ( dolock ) {
1333                                         ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1334                               }
1335                               return rc;
1336                     }
1337 
1338                     if ( LDAP_BACK_CONN_BINDING( lc ) ) {
1339                               /* if someone else is about to bind it, give up and retry */
1340                               if ( dolock ) {
1341                                         ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1342                               }
1343                               ldap_pvt_thread_yield();
1344                               goto retry_lock;
1345 
1346                     } else {
1347                               /* otherwise this thread will bind it */
1348                               LDAP_BACK_CONN_BINDING_SET( lc );
1349                               binding = 1;
1350                     }
1351           }
1352 
1353           if ( dolock ) {
1354                     ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1355           }
1356 
1357           /*
1358            * FIXME: we need to let clients use proxyAuthz
1359            * otherwise we cannot do symmetric pools of servers;
1360            * we have to live with the fact that a user can
1361            * authorize itself as any ID that is allowed
1362            * by the authzTo directive of the "proxyauthzdn".
1363            */
1364           /*
1365            * NOTE: current Proxy Authorization specification
1366            * and implementation do not allow proxy authorization
1367            * control to be provided with Bind requests
1368            */
1369           /*
1370            * if no bind took place yet, but the connection is bound
1371            * and the "idassert-authcDN" (or other ID) is set,
1372            * then bind as the asserting identity and explicitly
1373            * add the proxyAuthz control to every operation with the
1374            * dn bound to the connection as control value.
1375            * This is done also if this is the authorizing backend,
1376            * but the "override" flag is given to idassert.
1377            * It allows to use SASL bind and yet proxyAuthz users
1378            */
1379           op->o_tag = LDAP_REQ_BIND;
1380           cb.sc_next = op->o_callback;
1381           cb.sc_private = &o_tag;
1382           cb.sc_response = ldap_back_dobind_cb;
1383           op->o_callback = &cb;
1384 
1385           if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
1386                     if ( BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &bindcred ) ) {
1387                               /* if we got here, it shouldn't return result */
1388                               rc = ldap_back_is_proxy_authz( op, rs,
1389                                         LDAP_BACK_DONTSEND, &binddn, &bindcred );
1390                               if ( rc != 1 ) {
1391                                         Debug( LDAP_DEBUG_ANY, "Error: ldap_back_is_proxy_authz "
1392                                                   "returned %d, misconfigured URI?\n", rc );
1393                                         rs->sr_err = LDAP_OTHER;
1394                                         rs->sr_text = "misconfigured URI?";
1395                                         LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
1396                                         if ( sendok & LDAP_BACK_SENDERR ) {
1397                                                   send_ldap_result( op, rs );
1398                                         }
1399                                         goto done;
1400                               }
1401                     }
1402                     rc = ldap_back_proxy_authz_bind( lc, op, rs, sendok, &binddn, &bindcred );
1403                     goto done;
1404           }
1405 
1406 #ifdef HAVE_CYRUS_SASL
1407           if ( LDAP_BACK_CONN_ISPRIV( lc )) {
1408           slap_bindconf *sb;
1409           if ( li->li_acl_authmethod != LDAP_AUTH_NONE )
1410                     sb = &li->li_acl;
1411           else
1412                     sb = &li->li_idassert.si_bc;
1413 
1414           if ( sb->sb_method == LDAP_AUTH_SASL ) {
1415                     void                *defaults = NULL;
1416 
1417                     if ( sb->sb_secprops != NULL ) {
1418                               rc = ldap_set_option( lc->lc_ld,
1419                                         LDAP_OPT_X_SASL_SECPROPS, sb->sb_secprops );
1420 
1421                               if ( rc != LDAP_OPT_SUCCESS ) {
1422                                         Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
1423                                                   "(SECPROPS,\"%s\") failed!\n",
1424                                                   sb->sb_secprops );
1425                                         goto done;
1426                               }
1427                     }
1428 
1429                     defaults = lutil_sasl_defaults( lc->lc_ld,
1430                                         sb->sb_saslmech.bv_val,
1431                                         sb->sb_realm.bv_val,
1432                                         sb->sb_authcId.bv_val,
1433                                         sb->sb_cred.bv_val,
1434                                         NULL );
1435                     if ( defaults == NULL ) {
1436                               rs->sr_err = LDAP_OTHER;
1437                               LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
1438                               if ( sendok & LDAP_BACK_SENDERR ) {
1439                                         send_ldap_result( op, rs );
1440                               }
1441                               goto done;
1442                     }
1443 
1444                     rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld,
1445                                         sb->sb_binddn.bv_val,
1446                                         sb->sb_saslmech.bv_val, NULL, NULL,
1447                                         LDAP_SASL_QUIET, lutil_sasl_interact,
1448                                         defaults );
1449 
1450                     ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
1451                     ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
1452                     ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
1453 
1454                     lutil_sasl_freedefs( defaults );
1455 
1456                     switch ( rs->sr_err ) {
1457                     case LDAP_SUCCESS:
1458                               LDAP_BACK_CONN_ISBOUND_SET( lc );
1459                               break;
1460 
1461                     case LDAP_LOCAL_ERROR:
1462                               /* list client API error codes that require
1463                                * to taint the connection */
1464                               /* FIXME: should actually retry? */
1465                               LDAP_BACK_CONN_TAINTED_SET( lc );
1466 
1467                               /* fallthru */
1468 
1469                     default:
1470                               LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
1471                               rs->sr_err = slap_map_api2result( rs );
1472                               if ( sendok & LDAP_BACK_SENDERR ) {
1473                                         send_ldap_result( op, rs );
1474                               }
1475                               break;
1476                     }
1477 
1478                     if ( LDAP_BACK_QUARANTINE( li ) ) {
1479                               ldap_back_quarantine( op, rs );
1480                     }
1481 
1482                     goto done;
1483           }
1484           }
1485 #endif /* HAVE_CYRUS_SASL */
1486 
1487 retry:;
1488           if ( BER_BVISNULL( &lc->lc_cred ) ) {
1489                     tmp_dn = "";
1490                     if ( !BER_BVISNULL( &lc->lc_bound_ndn ) && !BER_BVISEMPTY( &lc->lc_bound_ndn ) ) {
1491                               Debug( LDAP_DEBUG_ANY, "%s ldap_back_dobind_int: DN=\"%s\" without creds, binding anonymously",
1492                                         op->o_log_prefix, lc->lc_bound_ndn.bv_val );
1493                     }
1494 
1495           } else {
1496                     tmp_dn = lc->lc_bound_ndn.bv_val;
1497           }
1498           rs->sr_err = ldap_sasl_bind( lc->lc_ld,
1499                               tmp_dn,
1500                               LDAP_SASL_SIMPLE, &lc->lc_cred,
1501                               NULL, NULL, &msgid );
1502 
1503           ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
1504           ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
1505           ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
1506 
1507           if ( rs->sr_err == LDAP_SERVER_DOWN ) {
1508                     if ( retries != LDAP_BACK_RETRY_NEVER ) {
1509                               if ( dolock ) {
1510                                         ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1511                               }
1512 
1513                               assert( lc->lc_refcnt > 0 );
1514                               if ( lc->lc_refcnt == 1 ) {
1515                                         ldap_unbind_ext( lc->lc_ld, NULL, NULL );
1516                                         lc->lc_ld = NULL;
1517 
1518                                         /* lc here must be the regular lc, reset and ready for init */
1519                                         rs->sr_err = ldap_back_prepare_conn( lc, op, rs, sendok );
1520                                         if ( rs->sr_err != LDAP_SUCCESS ) {
1521                                                   sendok &= ~LDAP_BACK_SENDERR;
1522                                                   lc->lc_refcnt = 0;
1523                                         }
1524                               }
1525 
1526                               if ( dolock ) {
1527                                         ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1528                               }
1529 
1530                               if ( rs->sr_err == LDAP_SUCCESS ) {
1531                                         if ( retries > 0 ) {
1532                                                   retries--;
1533                                         }
1534                                         goto retry;
1535                               }
1536                     }
1537 
1538                     assert( lc->lc_refcnt == 1 );
1539                     lc->lc_refcnt = 0;
1540                     ldap_back_freeconn( li, lc, dolock );
1541                     *lcp = NULL;
1542                     rs->sr_err = slap_map_api2result( rs );
1543 
1544                     if ( LDAP_BACK_QUARANTINE( li ) ) {
1545                               ldap_back_quarantine( op, rs );
1546                     }
1547 
1548                     if ( rs->sr_err != LDAP_SUCCESS &&
1549                               ( sendok & LDAP_BACK_SENDERR ) )
1550                     {
1551                               if ( op->o_callback == &cb )
1552                                         op->o_callback = cb.sc_next;
1553                               op->o_tag = o_tag;
1554                               rs->sr_text = "Proxy can't contact remote server";
1555                               send_ldap_result( op, rs );
1556                               /* if we originally bound and wanted rebind-as-user, must drop
1557                                * the connection now because we just discarded the credentials.
1558                                * ITS#7464, #8142
1559                                */
1560                               if ( LDAP_BACK_SAVECRED( li ) && SLAP_IS_AUTHZ_BACKEND( op ) )
1561                                         rs->sr_err = SLAPD_DISCONNECT;
1562                     }
1563 
1564                     rc = 0;
1565                     goto func_leave;
1566           }
1567 
1568           rc = ldap_back_op_result( lc, op, rs, msgid,
1569                     -1, ( sendok | LDAP_BACK_BINDING ) );
1570           if ( rc == LDAP_SUCCESS ) {
1571                     LDAP_BACK_CONN_ISBOUND_SET( lc );
1572           }
1573 
1574 done:;
1575           LDAP_BACK_CONN_BINDING_CLEAR( lc );
1576           rc = LDAP_BACK_CONN_ISBOUND( lc );
1577           if ( !rc ) {
1578                     ldap_back_release_conn_lock( li, lcp, dolock );
1579 
1580           } else if ( LDAP_BACK_SAVECRED( li ) ) {
1581                     ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
1582           }
1583 
1584 func_leave:;
1585           if ( op->o_callback == &cb )
1586                     op->o_callback = cb.sc_next;
1587           op->o_tag = o_tag;
1588 
1589           return rc;
1590 }
1591 
1592 /*
1593  * ldap_back_dobind
1594  *
1595  * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
1596  */
1597 int
ldap_back_dobind(ldapconn_t ** lcp,Operation * op,SlapReply * rs,ldap_back_send_t sendok)1598 ldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
1599 {
1600           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
1601 
1602           return ldap_back_dobind_int( lcp, op, rs,
1603                     ( sendok | LDAP_BACK_GETCONN ), li->li_nretries, 1 );
1604 }
1605 
1606 /*
1607  * ldap_back_default_rebind
1608  *
1609  * This is a callback used for chasing referrals using the same
1610  * credentials as the original user on this session.
1611  */
1612 int
ldap_back_default_rebind(LDAP * ld,LDAP_CONST char * url,ber_tag_t request,ber_int_t msgid,void * params)1613 ldap_back_default_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
1614           ber_int_t msgid, void *params )
1615 {
1616           ldapconn_t          *lc = (ldapconn_t *)params;
1617 
1618 #ifdef HAVE_TLS
1619           /* ... otherwise we couldn't get here */
1620           assert( lc != NULL );
1621 
1622           if ( !ldap_tls_inplace( ld ) ) {
1623                     int                 is_tls = LDAP_BACK_CONN_ISTLS( lc ),
1624                                         rc;
1625                     const char          *text = NULL;
1626 
1627                     rc = ldap_back_start_tls( ld, 0, &is_tls, url, lc->lc_flags,
1628                               lc->lc_ldapinfo->li_timeout[ SLAP_OP_BIND ], &text );
1629                     if ( rc != LDAP_SUCCESS ) {
1630                               return rc;
1631                     }
1632           }
1633 #endif /* HAVE_TLS */
1634 
1635           /* FIXME: add checks on the URL/identity? */
1636           /* TODO: would like to count this bind operation for monitoring
1637            * too, but where do we get the ldapinfo_t? */
1638 
1639           return ldap_sasl_bind_s( ld,
1640                               BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val,
1641                               LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL );
1642 }
1643 
1644 /*
1645  * ldap_back_default_urllist
1646  */
1647 int
ldap_back_default_urllist(LDAP * ld,LDAPURLDesc ** urllist,LDAPURLDesc ** url,void * params)1648 ldap_back_default_urllist(
1649           LDAP                *ld,
1650           LDAPURLDesc         **urllist,
1651           LDAPURLDesc         **url,
1652           void                *params )
1653 {
1654           ldapinfo_t          *li = (ldapinfo_t *)params;
1655           LDAPURLDesc         **urltail;
1656 
1657           if ( urllist == url ) {
1658                     return LDAP_SUCCESS;
1659           }
1660 
1661           for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
1662                     /* count */ ;
1663 
1664           *urltail = *urllist;
1665           *urllist = *url;
1666           *url = NULL;
1667 
1668           if ( !li->li_uri_mutex_do_not_lock ) {
1669                     ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
1670           }
1671 
1672           if ( li->li_uri ) {
1673                     ch_free( li->li_uri );
1674           }
1675 
1676           ldap_get_option( ld, LDAP_OPT_URI, (void *)&li->li_uri );
1677 
1678           if ( !li->li_uri_mutex_do_not_lock ) {
1679                     ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
1680           }
1681 
1682           return LDAP_SUCCESS;
1683 }
1684 
1685 int
ldap_back_cancel(ldapconn_t * lc,Operation * op,SlapReply * rs,ber_int_t msgid,ldap_back_send_t sendok)1686 ldap_back_cancel(
1687                     ldapconn_t                    *lc,
1688                     Operation           *op,
1689                     SlapReply           *rs,
1690                     ber_int_t           msgid,
1691                     ldap_back_send_t    sendok )
1692 {
1693           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
1694 
1695           /* default behavior */
1696           if ( LDAP_BACK_ABANDON( li ) ) {
1697                     return ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
1698           }
1699 
1700           if ( LDAP_BACK_IGNORE( li ) ) {
1701                     return ldap_pvt_discard( lc->lc_ld, msgid );
1702           }
1703 
1704           if ( LDAP_BACK_CANCEL( li ) ) {
1705                     /* FIXME: asynchronous? */
1706                     return ldap_cancel_s( lc->lc_ld, msgid, NULL, NULL );
1707           }
1708 
1709           assert( 0 );
1710 
1711           return LDAP_OTHER;
1712 }
1713 
1714 int
ldap_back_op_result(ldapconn_t * lc,Operation * op,SlapReply * rs,ber_int_t msgid,time_t timeout,ldap_back_send_t sendok)1715 ldap_back_op_result(
1716                     ldapconn_t                    *lc,
1717                     Operation           *op,
1718                     SlapReply           *rs,
1719                     ber_int_t           msgid,
1720                     time_t                        timeout,
1721                     ldap_back_send_t    sendok )
1722 {
1723           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
1724 
1725           char                *match = NULL;
1726           char                *text = NULL;
1727           char                **refs = NULL;
1728           LDAPControl         **ctrls = NULL;
1729 
1730           rs->sr_text = NULL;
1731           rs->sr_matched = NULL;
1732           rs->sr_ref = NULL;
1733           rs->sr_ctrls = NULL;
1734 
1735           /* if the error recorded in the reply corresponds
1736            * to a successful state, get the error from the
1737            * remote server response */
1738           if ( LDAP_ERR_OK( rs->sr_err ) ) {
1739                     int                 rc;
1740                     struct timeval      tv;
1741                     LDAPMessage         *res = NULL;
1742                     time_t              stoptime = (time_t)(-1);
1743                     int                 timeout_err = op->o_protocol >= LDAP_VERSION3 ?
1744                                                   LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
1745                     const char          *timeout_text = "Operation timed out";
1746 
1747                     /* if timeout is not specified, compute and use
1748                      * the one specific to the ongoing operation */
1749                     if ( timeout == (time_t)(-1) ) {
1750                               slap_op_t opidx = slap_req2op( op->o_tag );
1751 
1752                               if ( opidx == SLAP_OP_SEARCH ) {
1753                                         if ( op->ors_tlimit <= 0 ) {
1754                                                   timeout = 0;
1755 
1756                                         } else {
1757                                                   timeout = op->ors_tlimit;
1758                                                   timeout_err = LDAP_TIMELIMIT_EXCEEDED;
1759                                                   timeout_text = NULL;
1760                                         }
1761 
1762                               } else {
1763                                         timeout = li->li_timeout[ opidx ];
1764                               }
1765                     }
1766 
1767                     /* better than nothing :) */
1768                     if ( timeout == 0 ) {
1769                               if ( li->li_idle_timeout ) {
1770                                         timeout = li->li_idle_timeout;
1771 
1772                               } else if ( li->li_conn_ttl ) {
1773                                         timeout = li->li_conn_ttl;
1774                               }
1775                     }
1776 
1777                     if ( timeout ) {
1778                               stoptime = op->o_time + timeout;
1779                     }
1780 
1781                     LDAP_BACK_TV_SET( &tv );
1782 
1783 retry:;
1784                     /* if result parsing fails, note the failure reason */
1785                     rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
1786                     switch ( rc ) {
1787                     case 0:
1788                               if ( timeout && slap_get_time() > stoptime ) {
1789                                         if ( sendok & LDAP_BACK_BINDING ) {
1790                                                   ldap_unbind_ext( lc->lc_ld, NULL, NULL );
1791                                                   lc->lc_ld = NULL;
1792 
1793                                                   /* let it be used, but taint/delete it so that
1794                                                    * no-one else can look it up any further */
1795                                                   ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1796 
1797 #if LDAP_BACK_PRINT_CONNTREE > 0
1798                                                   ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
1799 #endif /* LDAP_BACK_PRINT_CONNTREE */
1800 
1801                                                   (void)ldap_back_conn_delete( li, lc );
1802                                                   LDAP_BACK_CONN_TAINTED_SET( lc );
1803 
1804 #if LDAP_BACK_PRINT_CONNTREE > 0
1805                                                   ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
1806 #endif /* LDAP_BACK_PRINT_CONNTREE */
1807                                                   ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1808 
1809                                         } else {
1810                                                   (void)ldap_back_cancel( lc, op, rs, msgid, sendok );
1811                                         }
1812                                         rs->sr_err = timeout_err;
1813                                         rs->sr_text = timeout_text;
1814                                         break;
1815                               }
1816 
1817                               /* timeout == 0 */
1818                               LDAP_BACK_TV_SET( &tv );
1819                               ldap_pvt_thread_yield();
1820                               goto retry;
1821 
1822                     case -1:
1823                               ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER,
1824                                                   &rs->sr_err );
1825                               break;
1826 
1827 
1828                     /* otherwise get the result; if it is not
1829                      * LDAP_SUCCESS, record it in the reply
1830                      * structure (this includes
1831                      * LDAP_COMPARE_{TRUE|FALSE}) */
1832                     default:
1833                               /* only touch when activity actually took place... */
1834                               if ( li->li_idle_timeout ) {
1835                                         lc->lc_time = op->o_time;
1836                               }
1837 
1838                               rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
1839                                                   &match, &text, &refs, &ctrls, 1 );
1840                               if ( rc == LDAP_SUCCESS ) {
1841                                         rs->sr_text = text;
1842                               } else {
1843                                         rs->sr_err = rc;
1844                               }
1845                               rs->sr_err = slap_map_api2result( rs );
1846 
1847                               /* RFC 4511: referrals can only appear
1848                                * if result code is LDAP_REFERRAL */
1849                               if ( refs != NULL
1850                                         && refs[ 0 ] != NULL
1851                                         && refs[ 0 ][ 0 ] != '\0' )
1852                               {
1853                                         if ( rs->sr_err != LDAP_REFERRAL ) {
1854                                                   Debug( LDAP_DEBUG_ANY,
1855                                                             "%s ldap_back_op_result: "
1856                                                             "got referrals with err=%d\n",
1857                                                             op->o_log_prefix,
1858                                                             rs->sr_err );
1859 
1860                                         } else {
1861                                                   int       i;
1862 
1863                                                   for ( i = 0; refs[ i ] != NULL; i++ )
1864                                                             /* count */ ;
1865                                                   rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
1866                                                             op->o_tmpmemctx );
1867                                                   for ( i = 0; refs[ i ] != NULL; i++ ) {
1868                                                             ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
1869                                                   }
1870                                                   BER_BVZERO( &rs->sr_ref[ i ] );
1871                                         }
1872 
1873                               } else if ( rs->sr_err == LDAP_REFERRAL ) {
1874                                         Debug( LDAP_DEBUG_ANY,
1875                                                   "%s ldap_back_op_result: "
1876                                                   "got err=%d with null "
1877                                                   "or empty referrals\n",
1878                                                   op->o_log_prefix,
1879                                                   rs->sr_err );
1880 
1881                                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
1882                               }
1883 
1884                               if ( ctrls != NULL ) {
1885                                         rs->sr_ctrls = ctrls;
1886                               }
1887                     }
1888           }
1889 
1890           /* if the error in the reply structure is not
1891            * LDAP_SUCCESS, try to map it from client
1892            * to server error */
1893           if ( !LDAP_ERR_OK( rs->sr_err ) ) {
1894                     rs->sr_err = slap_map_api2result( rs );
1895 
1896                     /* internal ops ( op->o_conn == NULL )
1897                      * must not reply to client */
1898                     if ( op->o_conn && !op->o_do_not_cache && match ) {
1899 
1900                               /* record the (massaged) matched
1901                                * DN into the reply structure */
1902                               rs->sr_matched = match;
1903                     }
1904           }
1905 
1906           if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1907                     if ( !( sendok & LDAP_BACK_RETRYING ) ) {
1908                               if ( LDAP_BACK_QUARANTINE( li ) ) {
1909                                         ldap_back_quarantine( op, rs );
1910                               }
1911                               if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1912                                         if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
1913                                         send_ldap_result( op, rs );
1914                               }
1915                     }
1916 
1917           } else if ( op->o_conn &&
1918                     ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
1919                               || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
1920           {
1921                     send_ldap_result( op, rs );
1922           }
1923 
1924           if ( text ) {
1925                     ldap_memfree( text );
1926           }
1927           rs->sr_text = NULL;
1928 
1929           /* there can't be refs with a (successful) bind */
1930           if ( rs->sr_ref ) {
1931                     op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
1932                     rs->sr_ref = NULL;
1933           }
1934 
1935           if ( refs ) {
1936                     ber_memvfree( (void **)refs );
1937           }
1938 
1939           /* match should not be possible with a successful bind */
1940           if ( match ) {
1941                     if ( rs->sr_matched != match ) {
1942                               free( (char *)rs->sr_matched );
1943                     }
1944                     rs->sr_matched = NULL;
1945                     ldap_memfree( match );
1946           }
1947 
1948           if ( ctrls != NULL ) {
1949                     if ( op->o_tag == LDAP_REQ_BIND && rs->sr_err == LDAP_SUCCESS ) {
1950                               int i;
1951 
1952                               for ( i = 0; ctrls[i] != NULL; i++ );
1953 
1954                               rs->sr_ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( i + 1 ),
1955                                         op->o_tmpmemctx );
1956                               for ( i = 0; ctrls[ i ] != NULL; i++ ) {
1957                                         char *ptr;
1958                                         ber_len_t oidlen = strlen( ctrls[i]->ldctl_oid );
1959                                         ber_len_t size = sizeof( LDAPControl )
1960                                                   + oidlen + 1
1961                                                   + ctrls[i]->ldctl_value.bv_len + 1;
1962 
1963                                         rs->sr_ctrls[ i ] = op->o_tmpalloc( size, op->o_tmpmemctx );
1964                                         rs->sr_ctrls[ i ]->ldctl_oid = (char *)&rs->sr_ctrls[ i ][ 1 ];
1965                                         lutil_strcopy( rs->sr_ctrls[ i ]->ldctl_oid, ctrls[i]->ldctl_oid );
1966                                         rs->sr_ctrls[ i ]->ldctl_value.bv_val
1967                                                             = (char *)&rs->sr_ctrls[ i ]->ldctl_oid[oidlen + 1];
1968                                         rs->sr_ctrls[ i ]->ldctl_value.bv_len
1969                                                   = ctrls[i]->ldctl_value.bv_len;
1970                                         ptr = lutil_memcopy( rs->sr_ctrls[ i ]->ldctl_value.bv_val,
1971                                                   ctrls[i]->ldctl_value.bv_val, ctrls[i]->ldctl_value.bv_len );
1972                                         *ptr = '\0';
1973                               }
1974                               rs->sr_ctrls[ i ] = NULL;
1975                               rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
1976 
1977                     } else {
1978                               assert( rs->sr_ctrls != NULL );
1979                               rs->sr_ctrls = NULL;
1980                     }
1981 
1982                     ldap_controls_free( ctrls );
1983           }
1984 
1985           return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
1986 }
1987 
1988 /* return true if bound, false if failed */
1989 int
ldap_back_retry(ldapconn_t ** lcp,Operation * op,SlapReply * rs,ldap_back_send_t sendok)1990 ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
1991 {
1992           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
1993           int                 rc = 0;
1994 
1995           assert( lcp != NULL );
1996           assert( *lcp != NULL );
1997 
1998           ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1999 
2000           if ( (*lcp)->lc_refcnt == 1 ) {
2001                     int binding = LDAP_BACK_CONN_BINDING( *lcp );
2002 
2003                     ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
2004                     Debug( LDAP_DEBUG_ANY,
2005                               "%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
2006                               op->o_log_prefix, li->li_uri,
2007                               BER_BVISNULL( &(*lcp)->lc_bound_ndn ) ?
2008                                         "" : (*lcp)->lc_bound_ndn.bv_val );
2009                     ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
2010 
2011                     ldap_unbind_ext( (*lcp)->lc_ld, NULL, NULL );
2012                     (*lcp)->lc_ld = NULL;
2013                     LDAP_BACK_CONN_ISBOUND_CLEAR( (*lcp) );
2014 
2015                     /* lc here must be the regular lc, reset and ready for init */
2016                     rc = ldap_back_prepare_conn( *lcp, op, rs, sendok );
2017                     if ( rc != LDAP_SUCCESS ) {
2018                               /* freeit, because lc_refcnt == 1 */
2019                               (*lcp)->lc_refcnt = 0;
2020                               (void)ldap_back_freeconn( li, *lcp, 0 );
2021                               *lcp = NULL;
2022                               rc = 0;
2023 
2024                     } else if ( ( sendok & LDAP_BACK_BINDING ) ) {
2025                               if ( binding ) {
2026                                         LDAP_BACK_CONN_BINDING_SET( *lcp );
2027                               }
2028                               rc = 1;
2029 
2030                     } else {
2031                               rc = ldap_back_dobind_int( lcp, op, rs, sendok, 0, 0 );
2032                               if ( rc == 0 && *lcp != NULL ) {
2033                                         /* freeit, because lc_refcnt == 1 */
2034                                         (*lcp)->lc_refcnt = 0;
2035                                         (void)ldap_back_freeconn( li, *lcp, 0 );
2036                                         *lcp = NULL;
2037                               }
2038                     }
2039 
2040           } else {
2041                     Debug( LDAP_DEBUG_TRACE,
2042                               "ldap_back_retry: conn %p refcnt=%u unable to retry.\n",
2043                               (void *)(*lcp), (*lcp)->lc_refcnt );
2044 
2045                     LDAP_BACK_CONN_TAINTED_SET( *lcp );
2046                     ldap_back_release_conn_lock( li, lcp, 0 );
2047                     assert( *lcp == NULL );
2048 
2049                     if ( sendok & LDAP_BACK_SENDERR ) {
2050                               rs->sr_err = LDAP_UNAVAILABLE;
2051                               rs->sr_text = "Unable to retry";
2052                               send_ldap_result( op, rs );
2053                     }
2054           }
2055 
2056           ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
2057 
2058           return rc;
2059 }
2060 
2061 static int
ldap_back_is_proxy_authz(Operation * op,SlapReply * rs,ldap_back_send_t sendok,struct berval * binddn,struct berval * bindcred)2062 ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
2063           struct berval *binddn, struct berval *bindcred )
2064 {
2065           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
2066           struct berval       ndn;
2067           int                 dobind = 0;
2068 
2069           if ( op->o_conn == NULL || op->o_do_not_cache ) {
2070                     goto done;
2071           }
2072 
2073           /* don't proxyAuthz if protocol is not LDAPv3 */
2074           switch ( li->li_version ) {
2075           case LDAP_VERSION3:
2076                     break;
2077 
2078           case 0:
2079                     if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
2080                               break;
2081                     }
2082                     /* fall thru */
2083 
2084           default:
2085                     rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
2086                     if ( sendok & LDAP_BACK_SENDERR ) {
2087                               send_ldap_result( op, rs );
2088                               dobind = -1;
2089                     }
2090                     goto done;
2091           }
2092 
2093           /* safe default */
2094           *binddn = slap_empty_bv;
2095           *bindcred = slap_empty_bv;
2096 
2097           if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
2098                     ndn = op->o_conn->c_ndn;
2099 
2100           } else {
2101                     ndn = op->o_ndn;
2102           }
2103 
2104           if ( !( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE )) {
2105                     if ( op->o_tag == LDAP_REQ_BIND && ( sendok & LDAP_BACK_SENDERR )) {
2106                               if ( !BER_BVISEMPTY( &ndn )) {
2107                                         dobind = 0;
2108                                         goto done;
2109                               }
2110                     } else if ( SLAP_IS_AUTHZ_BACKEND( op )) {
2111                               dobind = 0;
2112                               goto done;
2113                     }
2114           }
2115 
2116           switch ( li->li_idassert_mode ) {
2117           case LDAP_BACK_IDASSERT_LEGACY:
2118                     if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
2119                               if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) )
2120                               {
2121                                         *binddn = li->li_idassert_authcDN;
2122                                         *bindcred = li->li_idassert_passwd;
2123                                         dobind = 1;
2124                               }
2125                     }
2126                     break;
2127 
2128           default:
2129                     /* NOTE: rootdn can always idassert */
2130                     if ( BER_BVISNULL( &ndn )
2131                               && li->li_idassert_authz == NULL
2132                               && !( li->li_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
2133                     {
2134                               if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
2135                                         rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
2136                                         if ( sendok & LDAP_BACK_SENDERR ) {
2137                                                   send_ldap_result( op, rs );
2138                                                   dobind = -1;
2139                                         }
2140 
2141                               } else {
2142                                         rs->sr_err = LDAP_SUCCESS;
2143                                         *binddn = slap_empty_bv;
2144                                         *bindcred = slap_empty_bv;
2145                                         break;
2146                               }
2147 
2148                               goto done;
2149 
2150                     } else if ( !be_isroot( op ) ) {
2151                               if ( li->li_idassert_passthru ) {
2152                                         struct berval authcDN;
2153 
2154                                         if ( BER_BVISNULL( &ndn ) ) {
2155                                                   authcDN = slap_empty_bv;
2156 
2157                                         } else {
2158                                                   authcDN = ndn;
2159                                         }
2160                                         rs->sr_err = slap_sasl_matches( op, li->li_idassert_passthru,
2161                                                             &authcDN, &authcDN );
2162                                         if ( rs->sr_err == LDAP_SUCCESS ) {
2163                                                   dobind = 0;
2164                                                   break;
2165                                         }
2166                               }
2167 
2168                               if ( li->li_idassert_authz ) {
2169                                         struct berval authcDN;
2170 
2171                                         if ( BER_BVISNULL( &ndn ) ) {
2172                                                   authcDN = slap_empty_bv;
2173 
2174                                         } else {
2175                                                   authcDN = ndn;
2176                                         }
2177                                         rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz,
2178                                                             &authcDN, &authcDN );
2179                                         if ( rs->sr_err != LDAP_SUCCESS ) {
2180                                                   if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
2181                                                             if ( sendok & LDAP_BACK_SENDERR ) {
2182                                                                       send_ldap_result( op, rs );
2183                                                                       dobind = -1;
2184                                                             }
2185 
2186                                                   } else {
2187                                                             rs->sr_err = LDAP_SUCCESS;
2188                                                             *binddn = slap_empty_bv;
2189                                                             *bindcred = slap_empty_bv;
2190                                                             break;
2191                                                   }
2192 
2193                                                   goto done;
2194                                         }
2195                               }
2196                     }
2197 
2198                     *binddn = li->li_idassert_authcDN;
2199                     *bindcred = li->li_idassert_passwd;
2200                     dobind = 1;
2201                     break;
2202           }
2203 
2204 done:;
2205           return dobind;
2206 }
2207 
2208 static int
ldap_back_proxy_authz_bind(ldapconn_t * lc,Operation * op,SlapReply * rs,ldap_back_send_t sendok,struct berval * binddn,struct berval * bindcred)2209 ldap_back_proxy_authz_bind(
2210           ldapconn_t                    *lc,
2211           Operation           *op,
2212           SlapReply           *rs,
2213           ldap_back_send_t    sendok,
2214           struct berval                 *binddn,
2215           struct berval                 *bindcred )
2216 {
2217           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
2218           struct berval       ndn;
2219           int                 msgid;
2220           int                 rc;
2221 
2222           if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
2223                     ndn = op->o_conn->c_ndn;
2224 
2225           } else {
2226                     ndn = op->o_ndn;
2227           }
2228 
2229           if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
2230 #ifdef HAVE_CYRUS_SASL
2231                     void                *defaults = NULL;
2232                     struct berval       authzID = BER_BVNULL;
2233                     int                 freeauthz = 0;
2234                     LDAPControl **ctrlsp = NULL;
2235                     LDAPMessage *result = NULL;
2236                     const char *rmech = NULL;
2237                     const char *save_text = rs->sr_text;
2238 
2239 #ifdef SLAP_AUTH_DN
2240                     LDAPControl ctrl, *ctrls[2];
2241                     int msgid;
2242 #endif /* SLAP_AUTH_DN */
2243 
2244                     /* if SASL supports native authz, prepare for it */
2245                     if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
2246                                         ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
2247                     {
2248                               switch ( li->li_idassert_mode ) {
2249                               case LDAP_BACK_IDASSERT_OTHERID:
2250                               case LDAP_BACK_IDASSERT_OTHERDN:
2251                                         authzID = li->li_idassert_authzID;
2252                                         break;
2253 
2254                               case LDAP_BACK_IDASSERT_ANONYMOUS:
2255                                         BER_BVSTR( &authzID, "dn:" );
2256                                         break;
2257 
2258                               case LDAP_BACK_IDASSERT_SELF:
2259                                         if ( BER_BVISNULL( &ndn ) ) {
2260                                                   /* connection is not authc'd, so don't idassert */
2261                                                   BER_BVSTR( &authzID, "dn:" );
2262                                                   break;
2263                                         }
2264                                         authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
2265                                         authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
2266                                         AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
2267                                         AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
2268                                                             ndn.bv_val, ndn.bv_len + 1 );
2269                                         freeauthz = 1;
2270                                         break;
2271 
2272                               default:
2273                                         break;
2274                               }
2275                     }
2276 
2277                     if ( li->li_idassert_secprops != NULL ) {
2278                               rs->sr_err = ldap_set_option( lc->lc_ld,
2279                                         LDAP_OPT_X_SASL_SECPROPS,
2280                                         (void *)li->li_idassert_secprops );
2281 
2282                               if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
2283                                         rs->sr_err = LDAP_OTHER;
2284                                         if ( sendok & LDAP_BACK_SENDERR ) {
2285                                                   send_ldap_result( op, rs );
2286                                         }
2287                                         LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2288                                         goto done;
2289                               }
2290                     }
2291 
2292                     defaults = lutil_sasl_defaults( lc->lc_ld,
2293                                         li->li_idassert_sasl_mech.bv_val,
2294                                         li->li_idassert_sasl_realm.bv_val,
2295                                         li->li_idassert_authcID.bv_val,
2296                                         li->li_idassert_passwd.bv_val,
2297                                         authzID.bv_val );
2298                     if ( defaults == NULL ) {
2299                               rs->sr_err = LDAP_OTHER;
2300                               LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2301                               if ( sendok & LDAP_BACK_SENDERR ) {
2302                                         send_ldap_result( op, rs );
2303                               }
2304                               goto done;
2305                     }
2306 
2307 #ifdef SLAP_AUTH_DN
2308                     if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) {
2309                               assert( BER_BVISNULL( binddn ) );
2310 
2311                               ctrl.ldctl_oid = LDAP_CONTROL_AUTHZID_REQUEST;
2312                               ctrl.ldctl_iscritical = 0;
2313                               BER_BVZERO( &ctrl.ldctl_value );
2314                               ctrls[0] = &ctrl;
2315                               ctrls[1] = NULL;
2316                               ctrlsp = ctrls;
2317                     }
2318 #endif /* SLAP_AUTH_DN */
2319 
2320                     do {
2321                               rs->sr_err = ldap_sasl_interactive_bind( lc->lc_ld, binddn->bv_val,
2322                                         li->li_idassert_sasl_mech.bv_val,
2323                                         ctrlsp, NULL, LDAP_SASL_QUIET, lutil_sasl_interact, defaults,
2324                                         result, &rmech, &msgid );
2325 
2326                               if ( rs->sr_err != LDAP_SASL_BIND_IN_PROGRESS )
2327                                         break;
2328 
2329                               ldap_msgfree( result );
2330 
2331                               if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
2332                                         ldap_get_option( lc->lc_ld, LDAP_OPT_RESULT_CODE, (void*)&rs->sr_err );
2333                                         ldap_get_option( lc->lc_ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&rs->sr_text );
2334                                         break;
2335                               }
2336                     } while ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS );
2337 
2338                     ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
2339                     ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
2340                     ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
2341 
2342                     switch ( rs->sr_err ) {
2343                     case LDAP_SUCCESS:
2344 #ifdef SLAP_AUTH_DN
2345                               /* FIXME: right now, the only reason to check
2346                                * response controls is RFC 3829 authzid */
2347                               if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) {
2348                                         ctrlsp = NULL;
2349                                         rc = ldap_parse_result( lc->lc_ld, result, NULL, NULL, NULL, NULL,
2350                                                   &ctrlsp, 0 );
2351                                         if ( rc == LDAP_SUCCESS && ctrlsp ) {
2352                                                   LDAPControl *ctrl;
2353 
2354                                                   ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE,
2355                                                             ctrlsp, NULL );
2356                                                   if ( ctrl ) {
2357                                                             Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (authzid)\n",
2358                                                                       op->o_log_prefix, ctrl->ldctl_value.bv_val );
2359                                                             if ( ctrl->ldctl_value.bv_len > STRLENOF("dn:") &&
2360                                                                       strncasecmp( ctrl->ldctl_value.bv_val, "dn:", STRLENOF("dn:") ) == 0 )
2361                                                             {
2362                                                                       struct berval bv;
2363                                                                       bv.bv_val = &ctrl->ldctl_value.bv_val[STRLENOF("dn:")];
2364                                                                       bv.bv_len = ctrl->ldctl_value.bv_len - STRLENOF("dn:");
2365                                                                       ber_bvreplace( &lc->lc_bound_ndn, &bv );
2366                                                             }
2367                                                   }
2368                                         }
2369 
2370                                         ldap_controls_free( ctrlsp );
2371 
2372                               } else if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_WHOAMI ) {
2373                                         struct berval *val = NULL;
2374                                         rc = ldap_whoami_s( lc->lc_ld, &val, NULL, NULL );
2375                                         if ( rc == LDAP_SUCCESS && val != NULL ) {
2376                                                   Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (whoami)\n",
2377                                                             op->o_log_prefix, val->bv_val );
2378                                                   if ( val->bv_len > STRLENOF("dn:") &&
2379                                                             strncasecmp( val->bv_val, "dn:", STRLENOF("dn:") ) == 0 )
2380                                                   {
2381                                                             struct berval bv;
2382                                                             bv.bv_val = &val->bv_val[STRLENOF("dn:")];
2383                                                             bv.bv_len = val->bv_len - STRLENOF("dn:");
2384                                                             ber_bvreplace( &lc->lc_bound_ndn, &bv );
2385                                                   }
2386                                                   ber_bvfree( val );
2387                                         }
2388                               }
2389 
2390                               if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_MASK ) &&
2391                                         BER_BVISNULL( &lc->lc_bound_ndn ) )
2392                               {
2393                                         /* all in all, we only need it to be non-null */
2394                                         /* FIXME: should this be configurable? */
2395                                         static struct berval bv = BER_BVC("cn=authzdn");
2396                                         ber_bvreplace( &lc->lc_bound_ndn, &bv );
2397                               }
2398 #endif /* SLAP_AUTH_DN */
2399                               LDAP_BACK_CONN_ISBOUND_SET( lc );
2400                               break;
2401 
2402                     case LDAP_LOCAL_ERROR:
2403                               /* list client API error codes that require
2404                                * to taint the connection */
2405                               /* FIXME: should actually retry? */
2406                               LDAP_BACK_CONN_TAINTED_SET( lc );
2407 
2408                               /* fallthru */
2409 
2410                     default:
2411                               LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2412                               rs->sr_err = slap_map_api2result( rs );
2413                               if ( sendok & LDAP_BACK_SENDERR ) {
2414                                         send_ldap_result( op, rs );
2415                               }
2416                               break;
2417                     }
2418 
2419                     if ( save_text != rs->sr_text ) {
2420                               ldap_memfree( (char *)rs->sr_text );
2421                               rs->sr_text = save_text;
2422                     }
2423 
2424                     ldap_msgfree( result );
2425 
2426                     lutil_sasl_freedefs( defaults );
2427                     if ( freeauthz ) {
2428                               slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
2429                     }
2430 
2431                     goto done;
2432 #endif /* HAVE_CYRUS_SASL */
2433           }
2434 
2435           switch ( li->li_idassert_authmethod ) {
2436           case LDAP_AUTH_NONE:
2437                     /* FIXME: do we really need this? */
2438                     BER_BVSTR( binddn, "" );
2439                     BER_BVSTR( bindcred, "" );
2440                     /* fallthru */
2441 
2442           case LDAP_AUTH_SIMPLE:
2443                     rs->sr_err = ldap_sasl_bind( lc->lc_ld,
2444                                         binddn->bv_val, LDAP_SASL_SIMPLE,
2445                                         bindcred, NULL, NULL, &msgid );
2446                     rc = ldap_back_op_result( lc, op, rs, msgid,
2447                               -1, ( sendok | LDAP_BACK_BINDING ) );
2448 
2449                     ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
2450                     ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
2451                     ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );
2452                     break;
2453 
2454           default:
2455                     /* unsupported! */
2456                     LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
2457                     rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
2458                     if ( sendok & LDAP_BACK_SENDERR ) {
2459                               send_ldap_result( op, rs );
2460                     }
2461                     goto done;
2462           }
2463 
2464           if ( rc == LDAP_SUCCESS ) {
2465                     /* set rebind stuff in case of successful proxyAuthz bind,
2466                      * so that referral chasing is attempted using the right
2467                      * identity */
2468                     LDAP_BACK_CONN_ISBOUND_SET( lc );
2469                     if ( !BER_BVISNULL( binddn ) ) {
2470                               ber_bvreplace( &lc->lc_bound_ndn, binddn );
2471                     }
2472 
2473                     if ( !BER_BVISNULL( &lc->lc_cred ) ) {
2474                               memset( lc->lc_cred.bv_val, 0,
2475                                                   lc->lc_cred.bv_len );
2476                     }
2477 
2478                     if ( LDAP_BACK_SAVECRED( li ) ) {
2479                               if ( !BER_BVISNULL( bindcred ) ) {
2480                                         ber_bvreplace( &lc->lc_cred, bindcred );
2481                                         ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
2482                               }
2483 
2484                     } else {
2485                               lc->lc_cred.bv_len = 0;
2486                     }
2487           }
2488 
2489 done:;
2490           return LDAP_BACK_CONN_ISBOUND( lc );
2491 }
2492 
2493 /*
2494  * ldap_back_proxy_authz_ctrl() prepends a proxyAuthz control
2495  * to existing server-side controls if required; if not,
2496  * the existing server-side controls are placed in *pctrls.
2497  * The caller, after using the controls in client API
2498  * operations, if ( *pctrls != op->o_ctrls ), should
2499  * free( (*pctrls)[ 0 ] ) and free( *pctrls ).
2500  * The function returns success if the control could
2501  * be added if required, or if it did nothing; in the future,
2502  * it might return some error if it failed.
2503  *
2504  * if no bind took place yet, but the connection is bound
2505  * and the "proxyauthzdn" is set, then bind as "proxyauthzdn"
2506  * and explicitly add proxyAuthz the control to every operation
2507  * with the dn bound to the connection as control value.
2508  *
2509  * If no server-side controls are defined for the operation,
2510  * simply add the proxyAuthz control; otherwise, if the
2511  * proxyAuthz control is not already set, add it as
2512  * the first one
2513  *
2514  * FIXME: is controls order significant for security?
2515  * ANSWER: controls ordering and interoperability
2516  * must be indicated by the specs of each control; if none
2517  * is specified, the order is irrelevant.
2518  */
2519 int
ldap_back_proxy_authz_ctrl(Operation * op,SlapReply * rs,struct berval * bound_ndn,int version,slap_idassert_t * si,LDAPControl * ctrl)2520 ldap_back_proxy_authz_ctrl(
2521                     Operation *op,
2522                     SlapReply *rs,
2523                     struct berval       *bound_ndn,
2524                     int                 version,
2525                     slap_idassert_t     *si,
2526                     LDAPControl         *ctrl )
2527 {
2528           slap_idassert_mode_t          mode;
2529           struct berval                 assertedID,
2530                                         ndn;
2531           int                           isroot = 0;
2532 
2533           rs->sr_err = SLAP_CB_CONTINUE;
2534 
2535           /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
2536            * but if it is not set this test fails.  We need a different
2537            * means to detect if idassert is enabled */
2538           if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) )
2539                     && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) )
2540                     && BER_BVISNULL( &si->si_bc.sb_saslmech ) )
2541           {
2542                     goto done;
2543           }
2544 
2545           if ( !op->o_conn || op->o_do_not_cache || ( isroot = be_isroot( op ) ) ) {
2546                     goto done;
2547           }
2548 
2549           if ( op->o_tag == LDAP_REQ_BIND ) {
2550                     ndn = op->o_req_ndn;
2551           } else {
2552                     ndn = op->o_ndn;
2553           }
2554 
2555           if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) {
2556                     if ( op->o_proxy_authz ) {
2557                               /*
2558                                * FIXME: we do not want to perform proxyAuthz
2559                                * on behalf of the client, because this would
2560                                * be performed with "proxyauthzdn" privileges.
2561                                *
2562                                * This might actually be too strict, since
2563                                * the "proxyauthzdn" authzTo, and each entry's
2564                                * authzFrom attributes may be crafted
2565                                * to avoid unwanted proxyAuthz to take place.
2566                                */
2567 #if 0
2568                               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
2569                               rs->sr_text = "proxyAuthz not allowed within namingContext";
2570 #endif
2571                               goto done;
2572                     }
2573 
2574                     if ( !BER_BVISNULL( bound_ndn ) ) {
2575                               goto done;
2576                     }
2577 
2578                     if ( BER_BVISNULL( &ndn ) ) {
2579                               goto done;
2580                     }
2581 
2582                     if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) {
2583                               goto done;
2584                     }
2585 
2586           } else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) {
2587                     if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
2588                     {
2589                               /* already asserted in SASL via native authz */
2590                               goto done;
2591                     }
2592 
2593           } else if ( si->si_authz && !isroot ) {
2594                     int                 rc;
2595                     struct berval authcDN;
2596 
2597                     if ( BER_BVISNULL( &ndn ) ) {
2598                               authcDN = slap_empty_bv;
2599                     } else {
2600                               authcDN = ndn;
2601                     }
2602                     rc = slap_sasl_matches( op, si->si_authz,
2603                                         &authcDN, &authcDN );
2604                     if ( rc != LDAP_SUCCESS ) {
2605                               if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
2606                                         /* ndn is not authorized
2607                                          * to use idassert */
2608                                         rs->sr_err = rc;
2609                               }
2610                               goto done;
2611                     }
2612           }
2613 
2614           if ( op->o_proxy_authz ) {
2615                     /*
2616                      * FIXME: we can:
2617                      * 1) ignore the already set proxyAuthz control
2618                      * 2) leave it in place, and don't set ours
2619                      * 3) add both
2620                      * 4) reject the operation
2621                      *
2622                      * option (4) is very drastic
2623                      * option (3) will make the remote server reject
2624                      * the operation, thus being equivalent to (4)
2625                      * option (2) will likely break the idassert
2626                      * assumptions, so we cannot accept it;
2627                      * option (1) means that we are contradicting
2628                      * the client's request.
2629                      *
2630                      * I think (4) is the only correct choice.
2631                      */
2632                     rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
2633                     rs->sr_text = "proxyAuthz not allowed within namingContext";
2634           }
2635 
2636           if ( op->o_is_auth_check ) {
2637                     mode = LDAP_BACK_IDASSERT_NOASSERT;
2638 
2639           } else {
2640                     mode = si->si_mode;
2641           }
2642 
2643           switch ( mode ) {
2644           case LDAP_BACK_IDASSERT_LEGACY:
2645                     /* original behavior:
2646                      * assert the client's identity */
2647           case LDAP_BACK_IDASSERT_SELF:
2648                     assertedID = ndn;
2649                     break;
2650 
2651           case LDAP_BACK_IDASSERT_ANONYMOUS:
2652                     /* assert "anonymous" */
2653                     assertedID = slap_empty_bv;
2654                     break;
2655 
2656           case LDAP_BACK_IDASSERT_NOASSERT:
2657                     /* don't assert; bind as proxyauthzdn */
2658                     goto done;
2659 
2660           case LDAP_BACK_IDASSERT_OTHERID:
2661           case LDAP_BACK_IDASSERT_OTHERDN:
2662                     /* assert idassert DN */
2663                     assertedID = si->si_bc.sb_authzId;
2664                     break;
2665 
2666           default:
2667                     assert( 0 );
2668           }
2669 
2670           /* if we got here, "" is allowed to proxyAuthz */
2671           if ( BER_BVISNULL( &assertedID ) ) {
2672                     assertedID = slap_empty_bv;
2673           }
2674 
2675           /* don't idassert the bound DN (ITS#4497) */
2676           if ( dn_match( &assertedID, bound_ndn ) ) {
2677                     goto done;
2678           }
2679 
2680           ctrl->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
2681           ctrl->ldctl_iscritical = ( ( si->si_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) == LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL );
2682 
2683           switch ( si->si_mode ) {
2684           /* already in u:ID or dn:DN form */
2685           case LDAP_BACK_IDASSERT_OTHERID:
2686           case LDAP_BACK_IDASSERT_OTHERDN:
2687                     ber_dupbv_x( &ctrl->ldctl_value, &assertedID, op->o_tmpmemctx );
2688                     rs->sr_err = LDAP_SUCCESS;
2689                     break;
2690 
2691           /* needs the dn: prefix */
2692           default:
2693                     ctrl->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
2694                     ctrl->ldctl_value.bv_val = op->o_tmpalloc( ctrl->ldctl_value.bv_len + 1,
2695                                         op->o_tmpmemctx );
2696                     AC_MEMCPY( ctrl->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
2697                     AC_MEMCPY( &ctrl->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
2698                                         assertedID.bv_val, assertedID.bv_len + 1 );
2699                     rs->sr_err = LDAP_SUCCESS;
2700                     break;
2701           }
2702 
2703           /* Older versions of <draft-weltman-ldapv3-proxy> required
2704            * to encode the value of the authzID (and called it proxyDN);
2705            * this hack provides compatibility with those DSAs that
2706            * implement it this way */
2707           if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
2708                     struct berval                 authzID = ctrl->ldctl_value;
2709                     BerElementBuffer    berbuf;
2710                     BerElement                    *ber = (BerElement *)&berbuf;
2711                     ber_tag_t           tag;
2712 
2713                     ber_init2( ber, 0, LBER_USE_DER );
2714                     ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
2715 
2716                     tag = ber_printf( ber, "O", &authzID );
2717                     if ( tag == LBER_ERROR ) {
2718                               rs->sr_err = LDAP_OTHER;
2719                               goto free_ber;
2720                     }
2721 
2722                     if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
2723                               rs->sr_err = LDAP_OTHER;
2724                               goto free_ber;
2725                     }
2726 
2727                     rs->sr_err = LDAP_SUCCESS;
2728 
2729 free_ber:;
2730                     op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
2731                     ber_free_buf( ber );
2732 
2733                     if ( rs->sr_err != LDAP_SUCCESS ) {
2734                               goto done;
2735                     }
2736 
2737           } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
2738                     struct berval                 authzID = ctrl->ldctl_value,
2739                                                   tmp;
2740                     BerElementBuffer    berbuf;
2741                     BerElement                    *ber = (BerElement *)&berbuf;
2742                     ber_tag_t           tag;
2743 
2744                     if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) {
2745                               rs->sr_err = LDAP_PROTOCOL_ERROR;
2746                               goto done;
2747                     }
2748 
2749                     tmp = authzID;
2750                     tmp.bv_val += STRLENOF( "dn:" );
2751                     tmp.bv_len -= STRLENOF( "dn:" );
2752 
2753                     ber_init2( ber, 0, LBER_USE_DER );
2754                     ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
2755 
2756                     /* apparently, Mozilla API encodes this
2757                      * as "SEQUENCE { LDAPDN }" */
2758                     tag = ber_printf( ber, "{O}", &tmp );
2759                     if ( tag == LBER_ERROR ) {
2760                               rs->sr_err = LDAP_OTHER;
2761                               goto free_ber2;
2762                     }
2763 
2764                     if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
2765                               rs->sr_err = LDAP_OTHER;
2766                               goto free_ber2;
2767                     }
2768 
2769                     ctrl->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
2770                     rs->sr_err = LDAP_SUCCESS;
2771 
2772 free_ber2:;
2773                     op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
2774                     ber_free_buf( ber );
2775 
2776                     if ( rs->sr_err != LDAP_SUCCESS ) {
2777                               goto done;
2778                     }
2779           }
2780 
2781 done:;
2782 
2783           return rs->sr_err;
2784 }
2785 
2786 /*
2787  * Add controls;
2788  *
2789  * if any needs to be added, it is prepended to existing ones,
2790  * in a newly allocated array.  The companion function
2791  * ldap_back_controls_free() must be used to restore the original
2792  * status of op->o_ctrls.
2793  */
2794 int
ldap_back_controls_add(Operation * op,SlapReply * rs,ldapconn_t * lc,LDAPControl *** pctrls)2795 ldap_back_controls_add(
2796                     Operation *op,
2797                     SlapReply *rs,
2798                     ldapconn_t          *lc,
2799                     LDAPControl         ***pctrls )
2800 {
2801           ldapinfo_t          *li = (ldapinfo_t *)op->o_bd->be_private;
2802 
2803           LDAPControl         **ctrls = NULL;
2804           /* set to the maximum number of controls this backend can add */
2805           LDAPControl         c[ 2 ] = { { 0 } };
2806           int                 n = 0, i, j1 = 0, j2 = 0, skipped = 0;
2807 
2808           *pctrls = NULL;
2809 
2810           rs->sr_err = LDAP_SUCCESS;
2811 
2812           /* don't add controls if protocol is not LDAPv3 */
2813           switch ( li->li_version ) {
2814           case LDAP_VERSION3:
2815                     break;
2816 
2817           case 0:
2818                     if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
2819                               break;
2820                     }
2821                     /* fall thru */
2822 
2823           default:
2824                     goto done;
2825           }
2826 
2827           /* put controls that go __before__ existing ones here */
2828 
2829           /* proxyAuthz for identity assertion */
2830           switch ( ldap_back_proxy_authz_ctrl( op, rs, &lc->lc_bound_ndn,
2831                     li->li_version, &li->li_idassert, &c[ j1 ] ) )
2832           {
2833           case SLAP_CB_CONTINUE:
2834                     break;
2835 
2836           case LDAP_SUCCESS:
2837                     j1++;
2838                     break;
2839 
2840           default:
2841                     goto done;
2842           }
2843 
2844           /* put controls that go __after__ existing ones here */
2845 
2846 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
2847           /* FIXME: according to <draft-wahl-ldap-session>,
2848            * the server should check if the control can be added
2849            * based on the identity of the client and so */
2850 
2851           /* session tracking */
2852           if ( LDAP_BACK_ST_REQUEST( li ) ) {
2853                     switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
2854                     case SLAP_CB_CONTINUE:
2855                               break;
2856 
2857                     case LDAP_SUCCESS:
2858                               j2++;
2859                               break;
2860 
2861                     default:
2862                               goto done;
2863                     }
2864           }
2865 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
2866 
2867           if ( rs->sr_err == SLAP_CB_CONTINUE ) {
2868                     rs->sr_err = LDAP_SUCCESS;
2869           }
2870 
2871           /* if nothing to do, just bail out */
2872           if ( j1 == 0 && j2 == 0 ) {
2873                     goto done;
2874           }
2875 
2876           assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
2877 
2878           if ( op->o_ctrls ) {
2879                     for ( n = 0; op->o_ctrls[ n ]; n++ )
2880                               /* just count ctrls */ ;
2881           }
2882 
2883           ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
2884                               op->o_tmpmemctx );
2885           if ( j1 ) {
2886                     ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
2887                     *ctrls[ 0 ] = c[ 0 ];
2888                     for ( i = 1; i < j1; i++ ) {
2889                               ctrls[ i ] = &ctrls[ 0 ][ i ];
2890                               *ctrls[ i ] = c[ i ];
2891                     }
2892           }
2893 
2894           i = 0;
2895           if ( op->o_ctrls ) {
2896                     LDAPControl *proxyauthz = ldap_control_find(
2897                                         LDAP_CONTROL_PROXY_AUTHZ, op->o_ctrls, NULL );
2898 
2899                     for ( i = 0; op->o_ctrls[ i ]; i++ ) {
2900                               /* Only replace it if we generated one */
2901                               if ( j1 && proxyauthz && proxyauthz == op->o_ctrls[ i ] ) {
2902                                         /* Frontend has already checked only one is present */
2903                                         assert( skipped == 0 );
2904                                         skipped++;
2905                                         continue;
2906                               }
2907                               ctrls[ i + j1 - skipped ] = op->o_ctrls[ i ];
2908                     }
2909           }
2910 
2911           n += j1 - skipped;
2912           if ( j2 ) {
2913                     ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
2914                     *ctrls[ n ] = c[ j1 ];
2915                     for ( i = 1; i < j2; i++ ) {
2916                               ctrls[ n + i ] = &ctrls[ n ][ i ];
2917                               *ctrls[ n + i ] = c[ i ];
2918                     }
2919           }
2920 
2921           ctrls[ n + j2 ] = NULL;
2922 
2923 done:;
2924           if ( ctrls == NULL ) {
2925                     ctrls = op->o_ctrls;
2926           }
2927 
2928           *pctrls = ctrls;
2929 
2930           return rs->sr_err;
2931 }
2932 
2933 int
ldap_back_controls_free(Operation * op,SlapReply * rs,LDAPControl *** pctrls)2934 ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls )
2935 {
2936           LDAPControl         **ctrls = *pctrls;
2937 
2938           /* we assume that the controls added by the proxy come first,
2939            * so as soon as we find op->o_ctrls[ 0 ] we can stop */
2940           if ( ctrls && ctrls != op->o_ctrls ) {
2941                     int                 i = 0, n = 0, n_added;
2942                     LDAPControl         *lower, *upper;
2943 
2944                     assert( ctrls[ 0 ] != NULL );
2945 
2946                     for ( n = 0; ctrls[ n ] != NULL; n++ )
2947                               /* count 'em */ ;
2948 
2949                     if ( op->o_ctrls ) {
2950                               for ( i = 0; op->o_ctrls[ i ] != NULL; i++ )
2951                                         /* count 'em */ ;
2952                     }
2953 
2954                     n_added = n - i;
2955                     lower = (LDAPControl *)&ctrls[ n ];
2956                     upper = &lower[ n_added ];
2957 
2958                     for ( i = 0; ctrls[ i ] != NULL; i++ ) {
2959                               if ( ctrls[ i ] < lower || ctrls[ i ] >= upper ) {
2960                                         /* original; don't touch */
2961                                         continue;
2962                               }
2963 
2964                               if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) {
2965                                         op->o_tmpfree( ctrls[ i ]->ldctl_value.bv_val, op->o_tmpmemctx );
2966                               }
2967                     }
2968 
2969                     op->o_tmpfree( ctrls, op->o_tmpmemctx );
2970           }
2971 
2972           *pctrls = NULL;
2973 
2974           return 0;
2975 }
2976 
2977 int
ldap_back_conn2str(const ldapconn_base_t * lc,char * buf,ber_len_t buflen)2978 ldap_back_conn2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen )
2979 {
2980           char tbuf[ SLAP_TEXT_BUFLEN ];
2981           char *ptr = buf, *end = buf + buflen;
2982           int len;
2983 
2984           if ( ptr + sizeof("conn=") > end ) return -1;
2985           ptr = lutil_strcopy( ptr, "conn=" );
2986 
2987           len = ldap_back_connid2str( lc, ptr, (ber_len_t)(end - ptr) );
2988           ptr += len;
2989           if ( ptr >= end ) return -1;
2990 
2991           if ( !BER_BVISNULL( &lc->lcb_local_ndn ) ) {
2992                     if ( ptr + sizeof(" DN=\"\"") + lc->lcb_local_ndn.bv_len > end ) return -1;
2993                     ptr = lutil_strcopy( ptr, " DN=\"" );
2994                     ptr = lutil_strncopy( ptr, lc->lcb_local_ndn.bv_val, lc->lcb_local_ndn.bv_len );
2995                     *ptr++ = '"';
2996           }
2997 
2998           if ( lc->lcb_create_time != 0 ) {
2999                     len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_create_time );
3000                     if ( ptr + sizeof(" created=") + len >= end ) return -1;
3001                     ptr = lutil_strcopy( ptr, " created=" );
3002                     ptr = lutil_strcopy( ptr, tbuf );
3003           }
3004 
3005           if ( lc->lcb_time != 0 ) {
3006                     len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_time );
3007                     if ( ptr + sizeof(" modified=") + len >= end ) return -1;
3008                     ptr = lutil_strcopy( ptr, " modified=" );
3009                     ptr = lutil_strcopy( ptr, tbuf );
3010           }
3011 
3012           len = snprintf( tbuf, sizeof(tbuf), "%u", lc->lcb_refcnt );
3013           if ( ptr + sizeof(" refcnt=") + len >= end ) return -1;
3014           ptr = lutil_strcopy( ptr, " refcnt=" );
3015           ptr = lutil_strcopy( ptr, tbuf );
3016 
3017           return ptr - buf;
3018 }
3019 
3020 int
ldap_back_connid2str(const ldapconn_base_t * lc,char * buf,ber_len_t buflen)3021 ldap_back_connid2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen )
3022 {
3023           static struct berval conns[] = {
3024                     BER_BVC("ROOTDN"),
3025                     BER_BVC("ROOTDN-TLS"),
3026                     BER_BVC("ANON"),
3027                     BER_BVC("ANON-TLS"),
3028                     BER_BVC("BIND"),
3029                     BER_BVC("BIND-TLS"),
3030                     BER_BVNULL
3031           };
3032 
3033           int len = 0;
3034 
3035           if ( LDAP_BACK_PCONN_ISPRIV( (const ldapconn_t *)lc ) ) {
3036                     long cid;
3037                     struct berval *bv;
3038 
3039                     cid = (long)lc->lcb_conn;
3040                     assert( cid >= LDAP_BACK_PCONN_FIRST && cid < LDAP_BACK_PCONN_LAST );
3041 
3042                     bv = &conns[ cid ];
3043 
3044                     if ( bv->bv_len >= buflen ) {
3045                               return bv->bv_len + 1;
3046                     }
3047 
3048                     len = bv->bv_len;
3049                     lutil_strncopy( buf, bv->bv_val, bv->bv_len + 1 );
3050 
3051           } else {
3052                     len = snprintf( buf, buflen, "%lu", lc->lcb_conn->c_connid );
3053           }
3054 
3055           return len;
3056 }
3057 
3058 void *
ldap_back_conn_expire_fn(void * ctx,void * arg)3059 ldap_back_conn_expire_fn( void *ctx, void *arg )
3060 {
3061           struct re_s *rtask = arg;
3062           ldapinfo_t *li = (ldapinfo_t *)rtask->arg;
3063           ldap_back_conn_prune( li );
3064 
3065           return NULL;
3066 }
3067 
3068 /* Pick which expires first: connection TTL or idle timeout */
3069 static time_t
ldap_back_conn_expire_time(ldapinfo_t * li,ldapconn_t * lc)3070 ldap_back_conn_expire_time( ldapinfo_t *li, ldapconn_t *lc) {
3071           if ( li->li_conn_ttl != 0 && li->li_idle_timeout != 0 ) {
3072                     return ( lc->lc_create_time + li->li_conn_ttl ) < ( lc->lc_time + li->li_idle_timeout ) ?
3073                               ( lc->lc_create_time + li->li_conn_ttl ) : ( lc->lc_time + li->li_idle_timeout );
3074           } else if ( li->li_conn_ttl != 0 ) {
3075                     return lc->lc_create_time + li->li_conn_ttl;
3076           } else if ( li->li_idle_timeout != 0 ) {
3077                     return lc->lc_time + li->li_idle_timeout;
3078           }
3079           return -1;
3080 }
3081 
3082 static void
ldap_back_conn_prune(ldapinfo_t * li)3083 ldap_back_conn_prune( ldapinfo_t *li )
3084 {
3085           time_t              now = slap_get_time();
3086           time_t              next_timeout = -1; /* -1 means uninitialized */
3087           TAvlnode  *edge;
3088           int                 c;
3089 
3090           /*
3091            * Iterate though connections and close those that are pass the expiry time.
3092            * Also calculate the time for next connection to to expire.
3093            */
3094           ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
3095 
3096           for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
3097                     ldapconn_t *lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ c ].lic_priv );
3098 
3099                     while ( lc ) {
3100                               ldapconn_t *next = LDAP_TAILQ_NEXT( lc, lc_q );
3101                               time_t conn_expires = ldap_back_conn_expire_time( li, lc );
3102 
3103                               if ( now >= conn_expires ) {
3104                                         if ( lc->lc_refcnt == 0 ) {
3105                                                   Debug( LDAP_DEBUG_TRACE,
3106                                                             "ldap_back_conn_prune: closing expired connection lc=%p\n",
3107                                                             lc );
3108                                                   ldap_back_freeconn( li, lc, 0 );
3109                                         } else {
3110                                                   Debug( LDAP_DEBUG_TRACE,
3111                                                             "ldap_back_conn_prune: tainting expired connection lc=%p\n",
3112                                                             lc );
3113                                                   LDAP_BACK_CONN_TAINTED_SET( lc );
3114                                         }
3115                               } else if ( next_timeout == -1 || conn_expires < next_timeout ) {
3116                                         /* next_timeout was not yet initialized or current connection expires sooner */
3117                                         next_timeout = conn_expires;
3118                               }
3119 
3120                               lc = next;
3121                     }
3122           }
3123 
3124           edge = ldap_tavl_end( li->li_conninfo.lai_tree, TAVL_DIR_LEFT );
3125           while ( edge ) {
3126                     TAvlnode *next = ldap_tavl_next( edge, TAVL_DIR_RIGHT );
3127                     ldapconn_t *lc = (ldapconn_t *)edge->avl_data;
3128                     time_t conn_expires = ldap_back_conn_expire_time( li, lc );
3129 
3130                     if ( now >= conn_expires ) {
3131                               if ( lc->lc_refcnt == 0 ) {
3132                                         Debug( LDAP_DEBUG_TRACE,
3133                                                   "ldap_back_conn_prune: closing expired connection lc=%p\n",
3134                                                   lc );
3135                                         ldap_back_freeconn( li, lc, 0 );
3136                               } else {
3137                                         Debug( LDAP_DEBUG_TRACE,
3138                                                   "ldap_back_conn_prune: tainting expired connection lc=%p\n",
3139                                                   lc );
3140                                         LDAP_BACK_CONN_TAINTED_SET( lc );
3141                               }
3142                     } else if ( next_timeout == -1 || conn_expires < next_timeout ) {
3143                               next_timeout = conn_expires;
3144                     }
3145 
3146                     edge = next;
3147           }
3148 
3149           ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
3150 
3151           /* Reschedule for next timeout or cancel the task */
3152           ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
3153           if ( next_timeout > 0 ) {
3154                     if ( ldap_pvt_runqueue_isrunning( &slapd_rq, li->li_conn_expire_task ) ) {
3155                               ldap_pvt_runqueue_stoptask( &slapd_rq, li->li_conn_expire_task );
3156                     }
3157                     li->li_conn_expire_task->interval.tv_sec = next_timeout - now;
3158                     ldap_pvt_runqueue_resched( &slapd_rq, li->li_conn_expire_task, 0 );
3159 
3160                     /*
3161                      * The thread that handles runqueue might have already processed all tasks
3162                      * before we insertered new task or rescheduled the existing task with new
3163                      * timeout period. Wake it up to ensure that the task will be picked up.
3164                      */
3165                     slap_wake_listener();
3166                     Debug( LDAP_DEBUG_TRACE,
3167                               "ldap_back_conn_prune: scheduled connection expiry timer to %ld sec\n",
3168                               li->li_conn_expire_task->interval.tv_sec );
3169           } else if ( next_timeout == -1 && li->li_conn_expire_task != NULL ) {
3170                     if ( ldap_pvt_runqueue_isrunning( &slapd_rq, li->li_conn_expire_task ) ) {
3171                               ldap_pvt_runqueue_stoptask( &slapd_rq, li->li_conn_expire_task );
3172                     }
3173                     ldap_pvt_runqueue_remove( &slapd_rq, li->li_conn_expire_task );
3174                     li->li_conn_expire_task = NULL;
3175           }
3176           ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
3177 
3178           return;
3179 }
3180 
3181 static void
ldap_back_schedule_conn_expiry(ldapinfo_t * li,ldapconn_t * lc)3182 ldap_back_schedule_conn_expiry( ldapinfo_t *li, ldapconn_t *lc ) {
3183           /* Do nothing if timeouts are not set. */
3184           if ( li->li_conn_ttl == 0 && li->li_idle_timeout == 0 ) {
3185                     return;
3186           }
3187 
3188           /*
3189            * If connection expire task is not running, create it and schedule for
3190            * timeout of this connection.
3191            *
3192            * If the task is already running, this connection cannot be next one
3193            * to expire and therefore timeout does not need to be re-calculated.
3194            */
3195           ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
3196           if ( li->li_conn_expire_task == NULL ) {
3197                     li->li_conn_expire_task = ldap_pvt_runqueue_insert( &slapd_rq,
3198                               ldap_back_conn_expire_time( li, lc ) - slap_get_time(),
3199                               ldap_back_conn_expire_fn, li, "ldap_back_conn_expire_fn",
3200                               "ldap_back_conn_expire_timer" );
3201                     slap_wake_listener();
3202                     Debug( LDAP_DEBUG_TRACE,
3203                               "ldap_back_conn_prune: scheduled connection expiry timer to %ld sec\n",
3204                               li->li_conn_expire_task->interval.tv_sec );
3205           }
3206           ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
3207 
3208           return;
3209 }