typedef struct ldapconn_t {
Connection *lc_conn;
-#define LDAP_BACK_PCONN ((void *)0x0)
-#define LDAP_BACK_PCONN_TLS ((void *)0x1)
-#define LDAP_BACK_PCONN_PRIV (-1)
-#define LDAP_BACK_PCONN_ISPRIV(lc) ((void *)(lc)->lc_conn <= LDAP_BACK_PCONN_TLS)
-#define LDAP_BACK_PCONN_ID(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) ? LDAP_BACK_PCONN_PRIV : (lc)->lc_conn->c_connid )
+#define LDAP_BACK_PCONN ((void *)0x0)
+#define LDAP_BACK_PCONN_TLS ((void *)0x1)
+#define LDAP_BACK_PCONN_BIND ((void *)0x2)
+#define LDAP_BACK_PCONN_BIND_TLS ((void *)0x3)
+#define LDAP_BACK_PCONN_LAST ((void *)0x4)
+#define LDAP_BACK_PCONN_ISPRIV(lc) ((void *)(lc)->lc_conn < LDAP_BACK_PCONN_LAST)
+#define LDAP_BACK_PCONN_ID(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) ? ( -1 - (long)(lc)->lc_conn ): (lc)->lc_conn->c_connid )
#ifdef HAVE_TLS
-#define LDAP_BACK_PCONN_SET(op) ((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_TLS : LDAP_BACK_PCONN)
+#define LDAP_BACK_PCONN_SET(op) ((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_TLS : LDAP_BACK_PCONN)
+#define LDAP_BACK_PCONN_BIND_SET(op) ((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_BIND_TLS : LDAP_BACK_PCONN_BIND)
#else /* ! HAVE_TLS */
-#define LDAP_BACK_PCONN_SET(op) (LDAP_BACK_PCONN)
+#define LDAP_BACK_PCONN_SET(op) (LDAP_BACK_PCONN)
+#define LDAP_BACK_PCONN_BIND_SET(op) (LDAP_BACK_PCONN_BIND)
#endif /* ! HAVE_TLS */
LDAP *lc_ld;
#define LDAP_BACK_CONN_CLEAR(lc,f) LDAP_BACK_CONN_CLEAR_F(&(lc)->lc_lcflags, (f))
#define LDAP_BACK_CONN_CPY(lc,f,mlc) LDAP_BACK_CONN_CPY_F(&(lc)->lc_lcflags, (f), &(mlc)->lc_lcflags)
+/* 0xFFF00000U are reserved for back-meta */
+
#define LDAP_BACK_FCONN_ISBOUND (0x00000001U)
#define LDAP_BACK_FCONN_ISANON (0x00000002U)
#define LDAP_BACK_FCONN_ISBMASK (LDAP_BACK_FCONN_ISBOUND|LDAP_BACK_FCONN_ISANON)
#define LDAP_BACK_FCONN_TAINTED (0x00000020U)
#define LDAP_BACK_FCONN_ISIDASR (0x00000040U)
-/* 0x00FF0000 are reserved for back-meta */
-
#define LDAP_BACK_CONN_ISBOUND(lc) LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_ISBOUND)
#define LDAP_BACK_CONN_ISBOUND_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_ISBOUND)
#define LDAP_BACK_CONN_ISBOUND_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_ISBMASK)
#define li_idassert_tls li_idassert.si_bc.sb_tls
unsigned si_flags;
-#define LDAP_BACK_AUTH_NONE 0x00U
-#define LDAP_BACK_AUTH_NATIVE_AUTHZ 0x01U
-#define LDAP_BACK_AUTH_OVERRIDE 0x02U
-#define LDAP_BACK_AUTH_PRESCRIPTIVE 0x04U
-#define LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ 0x08U
-#define LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND 0x10U
+#define LDAP_BACK_AUTH_NONE (0x00U)
+#define LDAP_BACK_AUTH_NATIVE_AUTHZ (0x01U)
+#define LDAP_BACK_AUTH_OVERRIDE (0x02U)
+#define LDAP_BACK_AUTH_PRESCRIPTIVE (0x04U)
+#define LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ (0x08U)
+#define LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND (0x10U)
+#define LDAP_BACK_AUTH_AUTHZ_ALL (0x20U)
#define li_idassert_flags li_idassert.si_flags
BerVarray si_authz;
#define LDAP_BACK_RETRY_DEFAULT (3)
unsigned li_flags;
-#define LDAP_BACK_F_NONE (0x0000U)
-#define LDAP_BACK_F_SAVECRED (0x0001U)
-#define LDAP_BACK_F_USE_TLS (0x0002U)
-#define LDAP_BACK_F_PROPAGATE_TLS (0x0004U)
-#define LDAP_BACK_F_TLS_CRITICAL (0x0008U)
+
+/* 0xFFF00000U are reserved for back-meta */
+
+#define LDAP_BACK_F_NONE (0x00000000U)
+#define LDAP_BACK_F_SAVECRED (0x00000001U)
+#define LDAP_BACK_F_USE_TLS (0x00000002U)
+#define LDAP_BACK_F_PROPAGATE_TLS (0x00000004U)
+#define LDAP_BACK_F_TLS_CRITICAL (0x00000008U)
#define LDAP_BACK_F_TLS_USE_MASK (LDAP_BACK_F_USE_TLS|LDAP_BACK_F_TLS_CRITICAL)
#define LDAP_BACK_F_TLS_PROPAGATE_MASK (LDAP_BACK_F_PROPAGATE_TLS|LDAP_BACK_F_TLS_CRITICAL)
#define LDAP_BACK_F_TLS_MASK (LDAP_BACK_F_TLS_USE_MASK|LDAP_BACK_F_TLS_PROPAGATE_MASK)
-#define LDAP_BACK_F_CHASE_REFERRALS (0x0010U)
-#define LDAP_BACK_F_PROXY_WHOAMI (0x0020U)
+#define LDAP_BACK_F_CHASE_REFERRALS (0x00000010U)
+#define LDAP_BACK_F_PROXY_WHOAMI (0x00000020U)
-#define LDAP_BACK_F_T_F (0x0040U)
-#define LDAP_BACK_F_T_F_DISCOVER (0x0080U)
+#define LDAP_BACK_F_T_F (0x00000040U)
+#define LDAP_BACK_F_T_F_DISCOVER (0x00000080U)
#define LDAP_BACK_F_T_F_MASK (LDAP_BACK_F_T_F)
#define LDAP_BACK_F_T_F_MASK2 (LDAP_BACK_F_T_F_MASK|LDAP_BACK_F_T_F_DISCOVER)
-#define LDAP_BACK_F_MONITOR (0x0100U)
-#define LDAP_BACK_F_SINGLECONN (0x0200U)
+#define LDAP_BACK_F_MONITOR (0x00000100U)
+#define LDAP_BACK_F_SINGLECONN (0x00000200U)
+#define LDAP_BACK_F_USE_TEMPORARIES (0x00000400U)
-#define LDAP_BACK_F_ISOPEN (0x0400U)
+#define LDAP_BACK_F_ISOPEN (0x00000800U)
-#define LDAP_BACK_F_CANCEL_ABANDON (0x0000U)
-#define LDAP_BACK_F_CANCEL_IGNORE (0x1000U)
-#define LDAP_BACK_F_CANCEL_EXOP (0x2000U)
-#define LDAP_BACK_F_CANCEL_EXOP_DISCOVER (0x4000U)
+#define LDAP_BACK_F_CANCEL_ABANDON (0x00000000U)
+#define LDAP_BACK_F_CANCEL_IGNORE (0x00001000U)
+#define LDAP_BACK_F_CANCEL_EXOP (0x00002000U)
+#define LDAP_BACK_F_CANCEL_EXOP_DISCOVER (0x00004000U)
#define LDAP_BACK_F_CANCEL_MASK (LDAP_BACK_F_CANCEL_IGNORE|LDAP_BACK_F_CANCEL_EXOP)
#define LDAP_BACK_F_CANCEL_MASK2 (LDAP_BACK_F_CANCEL_MASK|LDAP_BACK_F_CANCEL_EXOP_DISCOVER)
#define LDAP_BACK_MONITOR(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_MONITOR )
#define LDAP_BACK_SINGLECONN(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_SINGLECONN )
+#define LDAP_BACK_USE_TEMPORARIES(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_USE_TEMPORARIES)
#define LDAP_BACK_ISOPEN(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_ISOPEN )
int
ldap_back_bind( Operation *op, SlapReply *rs )
{
- ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
- ldapconn_t *lc;
+ ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
+ ldapconn_t *lc;
- int rc = 0;
- ber_int_t msgid;
+ int rc = 0;
+ ber_int_t msgid;
+ ldap_back_send_t retrying = LDAP_BACK_RETRYING;
lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
if ( !lc ) {
}
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+retry:;
/* method is always LDAP_AUTH_SIMPLE if we got here */
rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
LDAP_SASL_SIMPLE,
&op->orb_cred, op->o_ctrls, NULL, &msgid );
+ /* FIXME: should we always retry, or only when piping the bind
+ * in the "override" connection pool? */
rc = ldap_back_op_result( lc, op, rs, msgid,
li->li_timeout[ SLAP_OP_BIND ],
- LDAP_BACK_BIND_SERR );
+ LDAP_BACK_BIND_SERR | retrying );
+ if ( rc == LDAP_UNAVAILABLE && retrying ) {
+ retrying &= ~LDAP_BACK_RETRYING;
+ if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_BIND_SERR ) ) {
+ goto retry;
+ }
+ }
+
if ( rc == LDAP_SUCCESS ) {
/* If defined, proxyAuthz will be used also when
* back-ldap is the authorizing backend; for this
* purpose, after a successful bind the connection
- * is trashed and further operations will use
- * a default connections with identity assertion */
+ * is left for further binds, and further operations
+ * on this client connection will use a default
+ * connection with identity assertion */
/* NOTE: use with care */
if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
- LDAP_BACK_CONN_TAINTED_SET( lc );
+ assert( lc->lc_binding == 1 );
+ lc->lc_binding = 0;
ldap_back_release_conn( op, rs, lc );
-
return( rc );
}
ldapconn_t *lc = NULL,
lc_curr = { 0 };
int refcnt = 1,
- binding = 1;
+ binding = 1,
+ lookupconn = !( sendok & LDAP_BACK_BINDING );
/* if the server is quarantined, and
* - the current interval did not expire yet, or
lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
} else {
- lc_curr.lc_local_ndn = op->o_ndn;
- /* Explicit binds must not be shared */
+ struct berval tmpbinddn,
+ tmpbindcred,
+ save_o_dn,
+ save_o_ndn;
+ int isproxyauthz;
+
+ /* need cleanup */
+ if ( binddn == NULL ) {
+ binddn = &tmpbinddn;
+ }
+ if ( bindcred == NULL ) {
+ bindcred = &tmpbindcred;
+ }
if ( op->o_tag == LDAP_REQ_BIND ) {
+ save_o_dn = op->o_dn;
+ save_o_ndn = op->o_ndn;
+ op->o_dn = op->o_req_dn;
+ op->o_ndn = op->o_req_ndn;
+ }
+ isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred );
+ if ( op->o_tag == LDAP_REQ_BIND ) {
+ op->o_dn = save_o_dn;
+ op->o_ndn = save_o_ndn;
+ }
+
+ lc_curr.lc_local_ndn = op->o_ndn;
+ /* Explicit binds must not be shared;
+ * however, explicit binds are piped in a special connection
+ * when idassert is to occur with "override" set */
+ if ( op->o_tag == LDAP_REQ_BIND && !isproxyauthz ) {
lc_curr.lc_conn = op->o_conn;
} else {
- if ( !( sendok & LDAP_BACK_BINDING ) &&
- ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred ) )
- {
+ if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
lc_curr.lc_local_ndn = *binddn;
lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
+ } else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) {
+ lc_curr.lc_local_ndn = slap_empty_bv;
+ lc_curr.lc_conn = LDAP_BACK_PCONN_BIND_SET( op );
+ LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
+ lookupconn = 1;
+
} else if ( SLAP_IS_AUTHZ_BACKEND( op ) ) {
lc_curr.lc_conn = op->o_conn;
}
/* Explicit Bind requests always get their own conn */
- if ( !( sendok & LDAP_BACK_BINDING ) ) {
+ if ( lookupconn ) {
/* Searches for a ldapconn in the avl tree */
retry_lock:
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
if ( lc != NULL ) {
/* Don't reuse connections while they're still binding */
if ( LDAP_BACK_CONN_BINDING( lc ) ) {
- ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
- ldap_pvt_thread_yield();
- goto retry_lock;
- }
+ if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+
+ ldap_pvt_thread_yield();
+ goto retry_lock;
+ }
+
+ lc = NULL;
+
+ } else {
+
+ if ( op->o_tag == LDAP_REQ_BIND ) {
+ /* right now, this is the only possible case */
+ assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) );
+ LDAP_BACK_CONN_BINDING_SET( lc );
+ }
- refcnt = ++lc->lc_refcnt;
- binding = ++lc->lc_binding;
+ refcnt = ++lc->lc_refcnt;
+ binding = ++lc->lc_binding;
+ }
}
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
break;
case -1:
- if ( !( sendok & LDAP_BACK_BINDING ) ) {
+ if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
/* duplicate: free and try to get the newly created one */
+ ldap_back_conn_free( lc );
+ lc = NULL;
goto retry_lock;
}
+
/* taint connection, so that it'll be freed when released */
- ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
-#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_getconn(delete)" );
-#endif /* LDAP_BACK_PRINT_CONNTREE */
- (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conndnlc_cmp );
-#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_getconn(delete)" );
-#endif /* LDAP_BACK_PRINT_CONNTREE */
- ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
LDAP_BACK_CONN_TAINTED_SET( lc );
break;
Operation *op,
SlapReply *rs )
{
- ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
slap_retry_info_t *ri = &li->li_quarantine;
ri->ri_last = new_last;
} else if ( li->li_isquarantined != LDAP_BACK_FQ_NO ) {
+ if ( ri->ri_last == slap_get_time() ) {
+ goto done;
+ }
+
Debug( LDAP_DEBUG_ANY,
- "%s: ldap_back_quarantine exit.\n",
- op->o_log_prefix, ri->ri_idx, ri->ri_count );
+ "%s: ldap_back_quarantine exit (%d) err=%d.\n",
+ op->o_log_prefix, li->li_isquarantined, rs->sr_err );
if ( li->li_quarantine_f ) {
(void)li->li_quarantine_f( li, li->li_quarantine_p );
* LDAP_COMPARE_{TRUE|FALSE}) */
default:
/* only touch when activity actually took place... */
- if ( li->li_idle_timeout ) {
+ if ( li->li_idle_timeout && lc ) {
lc->lc_time = op->o_time;
}
*lcp = NULL;
rc = 0;
+ } else if ( ( sendok & LDAP_BACK_BINDING ) ) {
+ rc = 1;
+
} else {
rc = ldap_back_dobind_int( lcp, op, rs, sendok, 0, 0 );
if ( rc == 0 && *lcp != NULL ) {
LDAP_BACK_CFG_NETWORK_TIMEOUT,
LDAP_BACK_CFG_VERSION,
LDAP_BACK_CFG_SINGLECONN,
+ LDAP_BACK_CFG_USETEMP,
LDAP_BACK_CFG_CANCEL,
LDAP_BACK_CFG_QUARANTINE,
LDAP_BACK_CFG_REWRITE,
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
+ { "use-temporaries", "TRUE/FALSE", 2, 0, 0,
+ ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_USETEMP,
+ ldap_back_cf_gen, "( OLcfgDbAt:3.22 "
+ "NAME 'olcDbUseTemporaries' "
+ "DESC 'Use temporary connections if the cached one is busy' "
+ "SYNTAX OMsBoolean "
+ "SINGLE-VALUE )",
+ NULL, NULL },
{ "suffixmassage", "[virtual]> <real", 2, 3, 0,
ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
ldap_back_cf_gen, NULL, NULL, NULL },
"$ olcDbSingleConn "
"$ olcDbCancel "
"$ olcDbQuarantine "
+ "$ olcDbUseTemporaries "
") )",
Cft_Database, ldapcfg},
{ NULL, 0, NULL }
struct berval in;
int rc;
- ber_str2bv( c->argv[ 1 ], 0, 0, &in );
- rc = authzNormalize( 0, NULL, NULL, &in, &bv, NULL );
- if ( rc != LDAP_SUCCESS ) {
- snprintf( c->msg, sizeof( c->msg ),
- "\"idassert-authzFrom <authz>\": "
- "invalid syntax" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
- return 1;
- }
+ if ( strcmp( c->argv[ 1 ], "*" ) == 0
+ || strcmp( c->argv[ 1 ], ".*" ) == 0
+ || strcmp( c->argv[ 1 ], "dn:*" ) == 0
+ || strcasecmp( c->argv[ 1 ], "dn.regex:.*" ) == 0 )
+ {
+ if ( si->si_authz != NULL ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-authzFrom <authz>\": "
+ "\"%s\" conflicts with existing authz rules",
+ c->argv[ 1 ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ si->si_flags |= LDAP_BACK_AUTH_AUTHZ_ALL;
+
+ return 0;
+
+ } else if ( ( si->si_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-authzFrom <authz>\": "
+ "\"<authz>\" conflicts with \"*\"" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ ber_str2bv( c->argv[ 1 ], 0, 0, &in );
+ rc = authzNormalize( 0, NULL, NULL, &in, &bv, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-authzFrom <authz>\": "
+ "invalid syntax" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
ber_bvarray_add( &si->si_authz, &bv );
return 0;
int i;
if ( li->li_idassert_authz == NULL ) {
- rc = 1;
+ if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) {
+ BER_BVSTR( &bv, "*" );
+ value_add_one( &c->rvalue_vals, &bv );
+
+ } else {
+ rc = 1;
+ }
break;
}
c->value_int = LDAP_BACK_SINGLECONN( li );
break;
+ case LDAP_BACK_CFG_USETEMP:
+ c->value_int = LDAP_BACK_USE_TEMPORARIES( li );
+ break;
+
case LDAP_BACK_CFG_CANCEL: {
slap_mask_t mask = LDAP_BACK_F_CANCEL_MASK2;
li->li_flags &= ~LDAP_BACK_F_SINGLECONN;
break;
+ case LDAP_BACK_CFG_USETEMP:
+ li->li_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
+ break;
+
case LDAP_BACK_CFG_QUARANTINE:
if ( !LDAP_BACK_QUARANTINE( li ) ) {
break;
}
break;
+ case LDAP_BACK_CFG_USETEMP:
+ if ( c->value_int ) {
+ li->li_flags |= LDAP_BACK_F_USE_TEMPORARIES;
+
+ } else {
+ li->li_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
+ }
+ break;
+
case LDAP_BACK_CFG_CANCEL: {
slap_mask_t mask;