OpenLDAP 2.3 Change Log
OpenLDAP 2.3.33 Engineering
+ Fixed slapd-ldap/meta privileged conn caching (ITS#4547)
+ Fixed slapd-ldap chase-referrals switch (ITS#4557)
+ Fixed slapd-ldap bind behavior when idassert is always used (ITS#4781)
+ Fixed slapd-ldap response handling bugs (ITS#4782)
+ Fixed slapd-ldap/meta privileged connections handling (ITS#4791)
+ Fixed slapd-meta retrying (ITS#4594, 4762)
+ Fixed slapo-chain referral DN use (ITS#4776)
OpenLDAP 2.3.32 Release (2007/01/04)
Fixed slapd add redundant duplicate value check (ITS#4600)
LDAP_LUTIL_F (int)
lutil_unparse_time( char *buf, size_t buflen, unsigned long t );
+#ifdef timerdiv
+#define lutil_timerdiv timerdiv
+#else /* ! timerdiv */
+/* works inplace (x == t) */
+#define lutil_timerdiv(t,d,x) \
+ do { \
+ time_t s = (t)->tv_sec; \
+ assert( d > 0 ); \
+ (x)->tv_sec = s / d; \
+ (x)->tv_usec = ( (t)->tv_usec + 1000000 * ( s % d ) ) / d; \
+ } while ( 0 )
+#endif /* ! timerdiv */
+
+#ifdef timermul
+#define lutil_timermul timermul
+#else /* ! timermul */
+/* works inplace (x == t) */
+#define lutil_timermul(t,m,x) \
+ do { \
+ time_t u = (t)->tv_usec * m; \
+ assert( m > 0 ); \
+ (x)->tv_sec = (t)->tv_sec * m + u / 1000000; \
+ (x)->tv_usec = u % 1000000; \
+ } while ( 0 );
+#endif /* ! timermul */
+
LDAP_END_DECL
#endif /* _LUTIL_H */
Operation *op,
SlapReply *rs )
{
- ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
-
- ldapconn_t *lc;
- int i = 0,
- j = 0;
- Attribute *a;
- LDAPMod **attrs = NULL,
- *attrs2 = NULL;
- ber_int_t msgid;
- int isupdate;
- int do_retry = 1;
- LDAPControl **ctrls = NULL;
+ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+
+ ldapconn_t *lc = NULL;
+ int i = 0,
+ j = 0;
+ Attribute *a;
+ LDAPMod **attrs = NULL,
+ *attrs2 = NULL;
+ ber_int_t msgid;
+ int isupdate;
+ ldap_back_send_t retrying = LDAP_BACK_RETRYING;
+ LDAPControl **ctrls = NULL;
rs->sr_err = LDAP_SUCCESS;
Debug( LDAP_DEBUG_ARGS, "==> ldap_back_add(\"%s\")\n",
op->o_req_dn.bv_val, 0, 0 );
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
lc = NULL;
goto cleanup;
}
retry:
ctrls = op->o_ctrls;
- rs->sr_err = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
+ rs->sr_err = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn,
+ li->li_version, &li->li_idassert, op, rs, &ctrls );
if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto cleanup;
rs->sr_err = ldap_add_ext( lc->lc_ld, op->o_req_dn.bv_val, attrs,
ctrls, NULL, &msgid );
rs->sr_err = ldap_back_op_result( lc, op, rs, msgid,
- li->li_timeout[ LDAP_BACK_OP_ADD ], LDAP_BACK_SENDRESULT );
- if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
- do_retry = 0;
+ li->li_timeout[ SLAP_OP_ADD ],
+ ( LDAP_BACK_SENDRESULT | retrying ) );
+ if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
+ retrying &= ~LDAP_BACK_RETRYING;
if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
/* if the identity changed, there might be need to re-authz */
(void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
LDAP_BEGIN_DECL
+struct ldapinfo_t;
+
+enum {
+ /* even numbers are connection types */
+ LDAP_BACK_PCONN_FIRST = 0,
+ LDAP_BACK_PCONN_ROOTDN = LDAP_BACK_PCONN_FIRST,
+ LDAP_BACK_PCONN_ANON = 2,
+ LDAP_BACK_PCONN_BIND = 4,
+
+ /* add the TLS bit */
+ LDAP_BACK_PCONN_TLS = 0x1U,
+
+ LDAP_BACK_PCONN_ROOTDN_TLS = (LDAP_BACK_PCONN_ROOTDN|LDAP_BACK_PCONN_TLS),
+ LDAP_BACK_PCONN_ANON_TLS = (LDAP_BACK_PCONN_ANON|LDAP_BACK_PCONN_TLS),
+ LDAP_BACK_PCONN_BIND_TLS = (LDAP_BACK_PCONN_BIND|LDAP_BACK_PCONN_TLS),
+
+ LDAP_BACK_PCONN_LAST
+};
+
typedef struct ldapconn_t {
Connection *lc_conn;
-#define LDAP_BACK_PCONN ((void *)0x0)
-#define LDAP_BACK_PCONN_TLS ((void *)0x1)
-#define LDAP_BACK_PCONN_ID(c) ((void *)(c) > LDAP_BACK_PCONN_TLS ? (c)->c_connid : -1)
+#define LDAP_BACK_CONN2PRIV(lc) ((unsigned long)(lc)->lc_conn)
+#define LDAP_BACK_PCONN_ISPRIV(lc) ((void *)(lc)->lc_conn >= (void *)LDAP_BACK_PCONN_FIRST \
+ && (void *)(lc)->lc_conn < (void *)LDAP_BACK_PCONN_LAST)
+#define LDAP_BACK_PCONN_ISROOTDN(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
+ && (LDAP_BACK_CONN2PRIV((lc)) < LDAP_BACK_PCONN_ANON))
+#define LDAP_BACK_PCONN_ISANON(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
+ && (LDAP_BACK_CONN2PRIV((lc)) < LDAP_BACK_PCONN_BIND) \
+ && (LDAP_BACK_CONN2PRIV((lc)) >= LDAP_BACK_PCONN_ANON))
+#define LDAP_BACK_PCONN_ISBIND(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
+ && (LDAP_BACK_CONN2PRIV((lc)) >= LDAP_BACK_PCONN_BIND))
+#define LDAP_BACK_PCONN_ISTLS(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
+ && (LDAP_BACK_CONN2PRIV((lc)) & LDAP_BACK_PCONN_TLS))
+#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_ROOTDN_SET(lc, op) \
+ ((lc)->lc_conn = (void *)((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_ROOTDN_TLS : LDAP_BACK_PCONN_ROOTDN))
+#define LDAP_BACK_PCONN_ANON_SET(lc, op) \
+ ((lc)->lc_conn = (void *)((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_ANON_TLS : LDAP_BACK_PCONN_ANON))
+#define LDAP_BACK_PCONN_BIND_SET(lc, op) \
+ ((lc)->lc_conn = (void *)((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_ROOTDN_SET(lc, op) \
+ ((lc)->lc_conn = (void *)LDAP_BACK_PCONN_ROOTDN)
+#define LDAP_BACK_PCONN_ANON_SET(lc, op) \
+ ((lc)->lc_conn = (void *)LDAP_BACK_PCONN_ANON)
+#define LDAP_BACK_PCONN_BIND_SET(lc, op) \
+ ((lc)->lc_conn = (void *)LDAP_BACK_PCONN_BIND)
#endif /* ! HAVE_TLS */
+#define LDAP_BACK_PCONN_SET(lc, op) \
+ (BER_BVISEMPTY(&(op)->o_ndn) ? \
+ LDAP_BACK_PCONN_ANON_SET((lc), (op)) : LDAP_BACK_PCONN_ROOTDN_SET((lc), (op)))
LDAP *lc_ld;
struct berval lc_cred;
struct berval lc_bound_ndn;
struct berval lc_local_ndn;
unsigned lc_lcflags;
-#define LDAP_BACK_CONN_ISSET(lc,f) ((lc)->lc_lcflags & (f))
-#define LDAP_BACK_CONN_SET(lc,f) ((lc)->lc_lcflags |= (f))
-#define LDAP_BACK_CONN_CLEAR(lc,f) ((lc)->lc_lcflags &= ~(f))
-#define LDAP_BACK_CONN_CPY(lc,f,mlc) \
+#define LDAP_BACK_CONN_ISSET_F(fp,f) (*(fp) & (f))
+#define LDAP_BACK_CONN_SET_F(fp,f) (*(fp) |= (f))
+#define LDAP_BACK_CONN_CLEAR_F(fp,f) (*(fp) &= ~(f))
+#define LDAP_BACK_CONN_CPY_F(fp,f,mfp) \
do { \
- if ( ((f) & (mlc)->lc_lcflags) == (f) ) { \
- (lc)->lc_lcflags |= (f); \
+ if ( ((f) & *(mfp)) == (f) ) { \
+ *(fp) |= (f); \
} else { \
- (lc)->lc_lcflags &= ~(f); \
+ *(fp) &= ~(f); \
} \
} while ( 0 )
-#define LDAP_BACK_FCONN_ISBOUND (0x01)
-#define LDAP_BACK_FCONN_ISANON (0x02)
+#define LDAP_BACK_CONN_ISSET(lc,f) LDAP_BACK_CONN_ISSET_F(&(lc)->lc_lcflags, (f))
+#define LDAP_BACK_CONN_SET(lc,f) LDAP_BACK_CONN_SET_F(&(lc)->lc_lcflags, (f))
+#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_ISPRIV (0x04)
-#define LDAP_BACK_FCONN_ISTLS (0x08)
-#define LDAP_BACK_FCONN_BINDING (0x10)
-#define LDAP_BACK_FCONN_TAINTED (0x20)
+#define LDAP_BACK_FCONN_ISPRIV (0x00000004U)
+#define LDAP_BACK_FCONN_ISTLS (0x00000008U)
+#define LDAP_BACK_FCONN_BINDING (0x00000010U)
+#define LDAP_BACK_FCONN_TAINTED (0x00000020U)
+#define LDAP_BACK_FCONN_ISIDASR (0x00000040U)
+#define LDAP_BACK_FCONN_CACHED (0x00000080U)
#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_TAINTED(lc) LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_TAINTED)
#define LDAP_BACK_CONN_TAINTED_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_TAINTED)
#define LDAP_BACK_CONN_TAINTED_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_TAINTED)
+#define LDAP_BACK_CONN_ISIDASSERT(lc) LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_ISIDASR)
+#define LDAP_BACK_CONN_ISIDASSERT_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_ISIDASR)
+#define LDAP_BACK_CONN_ISIDASSERT_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_ISIDASR)
+#define LDAP_BACK_CONN_ISIDASSERT_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), LDAP_BACK_FCONN_ISIDASR, (mlc))
+#define LDAP_BACK_CONN_CACHED(lc) LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_CACHED)
+#define LDAP_BACK_CONN_CACHED_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_CACHED)
+#define LDAP_BACK_CONN_CACHED_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_CACHED)
unsigned lc_refcnt;
unsigned lc_binding;
unsigned lc_flags;
time_t lc_create_time;
time_t lc_time;
+
+ LDAP_TAILQ_ENTRY(ldapconn_t) lc_q;
} ldapconn_t;
+typedef struct ldap_avl_info_t {
+ ldap_pvt_thread_mutex_t lai_mutex;
+ Avlnode *lai_tree;
+} ldap_avl_info_t;
+
+typedef struct slap_retry_info_t {
+ time_t *ri_interval;
+ int *ri_num;
+ int ri_idx;
+ int ri_count;
+ time_t ri_last;
+
+#define SLAP_RETRYNUM_FOREVER (-1) /* retry forever */
+#define SLAP_RETRYNUM_TAIL (-2) /* end of retrynum array */
+#define SLAP_RETRYNUM_VALID(n) ((n) >= SLAP_RETRYNUM_FOREVER) /* valid retrynum */
+#define SLAP_RETRYNUM_FINITE(n) ((n) > SLAP_RETRYNUM_FOREVER) /* not forever */
+} slap_retry_info_t;
+
/*
* identity assertion modes
*/
-enum {
+typedef enum {
LDAP_BACK_IDASSERT_LEGACY = 1,
LDAP_BACK_IDASSERT_NOASSERT,
LDAP_BACK_IDASSERT_ANONYMOUS,
LDAP_BACK_IDASSERT_SELF,
LDAP_BACK_IDASSERT_OTHERDN,
LDAP_BACK_IDASSERT_OTHERID
-};
+} slap_idassert_mode_t;
+
+/* ID assert stuff */
+typedef struct slap_idassert_t {
+ slap_idassert_mode_t si_mode;
+#define li_idassert_mode li_idassert.si_mode
+
+ slap_bindconf si_bc;
+#define li_idassert_authcID li_idassert.si_bc.sb_authcId
+#define li_idassert_authcDN li_idassert.si_bc.sb_binddn
+#define li_idassert_passwd li_idassert.si_bc.sb_cred
+#define li_idassert_authzID li_idassert.si_bc.sb_authzId
+#define li_idassert_authmethod li_idassert.si_bc.sb_method
+#define li_idassert_sasl_mech li_idassert.si_bc.sb_saslmech
+#define li_idassert_sasl_realm li_idassert.si_bc.sb_realm
+#define li_idassert_secprops li_idassert.si_bc.sb_secprops
+#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_AUTHZ_ALL (0x20U)
+#define li_idassert_flags li_idassert.si_flags
+
+ BerVarray si_authz;
+#define li_idassert_authz li_idassert.si_authz
+} slap_idassert_t;
/*
- * operation enumeration for timeouts
+ * Hook to allow mucking with ldapinfo_t when quarantine is over
*/
-enum {
- LDAP_BACK_OP_ADD = 0,
- LDAP_BACK_OP_DELETE,
- LDAP_BACK_OP_MODIFY,
- LDAP_BACK_OP_MODRDN,
- LDAP_BACK_OP_LAST
-};
-
-typedef struct ldap_avl_info_t {
- ldap_pvt_thread_mutex_t lai_mutex;
- Avlnode *lai_tree;
-} ldap_avl_info_t;
+typedef int (*ldap_back_quarantine_f)( struct ldapinfo_t *, void * );
typedef struct ldapinfo_t {
/* li_uri: the string that goes into ldap_initialize()
* TODO: use li_acl.sb_uri instead */
- char *li_uri;
+ char *li_uri;
/* li_bvuri: an array of each single URI that is equivalent;
* to be checked for the presence of a certain item */
- BerVarray li_bvuri;
+ BerVarray li_bvuri;
+ ldap_pvt_thread_mutex_t li_uri_mutex;
+
+ LDAP_REBIND_PROC *li_rebind_f;
+ void *li_urllist_p;
- slap_bindconf li_acl;
-#define li_acl_authcID li_acl.sb_authcId
-#define li_acl_authcDN li_acl.sb_binddn
-#define li_acl_passwd li_acl.sb_cred
-#define li_acl_authzID li_acl.sb_authzId
+ slap_bindconf li_acl;
+#define li_acl_authcID li_acl.sb_authcId
+#define li_acl_authcDN li_acl.sb_binddn
+#define li_acl_passwd li_acl.sb_cred
+#define li_acl_authzID li_acl.sb_authzId
#define li_acl_authmethod li_acl.sb_method
#define li_acl_sasl_mech li_acl.sb_saslmech
#define li_acl_sasl_realm li_acl.sb_realm
-#define li_acl_secprops li_acl.sb_secprops
+#define li_acl_secprops li_acl.sb_secprops
/* ID assert stuff */
- int li_idassert_mode;
-
- slap_bindconf li_idassert;
-#define li_idassert_authcID li_idassert.sb_authcId
-#define li_idassert_authcDN li_idassert.sb_binddn
-#define li_idassert_passwd li_idassert.sb_cred
-#define li_idassert_authzID li_idassert.sb_authzId
-#define li_idassert_authmethod li_idassert.sb_method
-#define li_idassert_sasl_mech li_idassert.sb_saslmech
-#define li_idassert_sasl_realm li_idassert.sb_realm
-#define li_idassert_secprops li_idassert.sb_secprops
-
- unsigned li_idassert_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
-
- BerVarray li_idassert_authz;
+ slap_idassert_t li_idassert;
/* end of ID assert stuff */
- int li_nretries;
+ int li_nretries;
#define LDAP_BACK_RETRY_UNDEFINED (-2)
#define LDAP_BACK_RETRY_FOREVER (-1)
#define LDAP_BACK_RETRY_NEVER (0)
#define LDAP_BACK_RETRY_DEFAULT (3)
- unsigned li_flags;
-#define LDAP_BACK_F_NONE 0x00U
-#define LDAP_BACK_F_SAVECRED 0x01U
-#define LDAP_BACK_F_USE_TLS 0x02U
-#define LDAP_BACK_F_PROPAGATE_TLS 0x04U
-#define LDAP_BACK_F_TLS_CRITICAL 0x08U
+ unsigned li_flags;
+
+/* 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 0x10U
-#define LDAP_BACK_F_PROXY_WHOAMI 0x20U
+#define LDAP_BACK_F_CHASE_REFERRALS (0x00000010U)
+#define LDAP_BACK_F_PROXY_WHOAMI (0x00000020U)
+
+#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 (0x00000100U)
+#define LDAP_BACK_F_SINGLECONN (0x00000200U)
+#define LDAP_BACK_F_USE_TEMPORARIES (0x00000400U)
+
+#define LDAP_BACK_F_ISOPEN (0x00000800U)
+
+#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_F_SUPPORT_T_F 0x80U
-#define LDAP_BACK_F_SUPPORT_T_F_DISCOVER 0x40U
-#define LDAP_BACK_F_SUPPORT_T_F_MASK (LDAP_BACK_F_SUPPORT_T_F|LDAP_BACK_F_SUPPORT_T_F_DISCOVER)
+#define LDAP_BACK_ISSET_F(ff,f) ( ( (ff) & (f) ) == (f) )
+#define LDAP_BACK_ISMASK_F(ff,m,f) ( ( (ff) & (m) ) == (f) )
+
+#define LDAP_BACK_ISSET(li,f) LDAP_BACK_ISSET_F( (li)->li_flags, (f) )
+#define LDAP_BACK_ISMASK(li,m,f) LDAP_BACK_ISMASK_F( (li)->li_flags, (m), (f) )
-#define LDAP_BACK_ISSET(li,f) ( ( (li)->li_flags & (f) ) == (f) )
#define LDAP_BACK_SAVECRED(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_SAVECRED )
#define LDAP_BACK_USE_TLS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_USE_TLS )
#define LDAP_BACK_PROPAGATE_TLS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_PROPAGATE_TLS )
#define LDAP_BACK_CHASE_REFERRALS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_CHASE_REFERRALS )
#define LDAP_BACK_PROXY_WHOAMI(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_PROXY_WHOAMI )
- int li_version;
+#define LDAP_BACK_USE_TLS_F(ff) LDAP_BACK_ISSET_F( (ff), LDAP_BACK_F_USE_TLS )
+#define LDAP_BACK_PROPAGATE_TLS_F(ff) LDAP_BACK_ISSET_F( (ff), LDAP_BACK_F_PROPAGATE_TLS )
+#define LDAP_BACK_TLS_CRITICAL_F(ff) LDAP_BACK_ISSET_F( (ff), LDAP_BACK_F_TLS_CRITICAL )
+
+#define LDAP_BACK_T_F(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_T_F_MASK, LDAP_BACK_F_T_F )
+#define LDAP_BACK_T_F_DISCOVER(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_T_F_MASK2, LDAP_BACK_F_T_F_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 )
+
+#define LDAP_BACK_ABANDON(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_CANCEL_MASK, LDAP_BACK_F_CANCEL_ABANDON )
+#define LDAP_BACK_IGNORE(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_CANCEL_MASK, LDAP_BACK_F_CANCEL_IGNORE )
+#define LDAP_BACK_CANCEL(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_CANCEL_MASK, LDAP_BACK_F_CANCEL_EXOP )
+#define LDAP_BACK_CANCEL_DISCOVER(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_CANCEL_MASK2, LDAP_BACK_F_CANCEL_EXOP_DISCOVER )
+
+ int li_version;
- ldap_avl_info_t li_conninfo;
+ /* cached connections;
+ * special conns are in tailq rather than in tree */
+ ldap_avl_info_t li_conninfo;
+ struct {
+ int lic_num;
+ LDAP_TAILQ_HEAD(lc_conn_priv_q, ldapconn_t) lic_priv;
+ } li_conn_priv[ LDAP_BACK_PCONN_LAST ];
+ int li_conn_priv_max;
+#define LDAP_BACK_CONN_PRIV_MIN (1)
+#define LDAP_BACK_CONN_PRIV_MAX (256)
+ /* must be between LDAP_BACK_CONN_PRIV_MIN
+ * and LDAP_BACK_CONN_PRIV_MAX ! */
+#define LDAP_BACK_CONN_PRIV_DEFAULT (16)
- time_t li_network_timeout;
- time_t li_conn_ttl;
- time_t li_idle_timeout;
- time_t li_timeout[ LDAP_BACK_OP_LAST ];
+ sig_atomic_t li_isquarantined;
+#define LDAP_BACK_FQ_NO (0)
+#define LDAP_BACK_FQ_YES (1)
+#define LDAP_BACK_FQ_RETRYING (2)
+
+ slap_retry_info_t li_quarantine;
+#define LDAP_BACK_QUARANTINE(li) ( (li)->li_quarantine.ri_num != NULL )
+ ldap_pvt_thread_mutex_t li_quarantine_mutex;
+ ldap_back_quarantine_f li_quarantine_f;
+ void *li_quarantine_p;
+
+ time_t li_network_timeout;
+ time_t li_conn_ttl;
+ time_t li_idle_timeout;
+ time_t li_timeout[ SLAP_OP_LAST ];
} ldapinfo_t;
typedef enum ldap_back_send_t {
LDAP_BACK_SENDERR = 0x02,
LDAP_BACK_SENDRESULT = (LDAP_BACK_SENDOK|LDAP_BACK_SENDERR),
LDAP_BACK_BINDING = 0x04,
+
LDAP_BACK_BIND_DONTSEND = (LDAP_BACK_BINDING),
LDAP_BACK_BIND_SOK = (LDAP_BACK_BINDING|LDAP_BACK_SENDOK),
LDAP_BACK_BIND_SERR = (LDAP_BACK_BINDING|LDAP_BACK_SENDERR),
- LDAP_BACK_BIND_SRES = (LDAP_BACK_BINDING|LDAP_BACK_SENDRESULT)
+ LDAP_BACK_BIND_SRES = (LDAP_BACK_BINDING|LDAP_BACK_SENDRESULT),
+
+ LDAP_BACK_RETRYING = 0x08,
+ LDAP_BACK_RETRY_DONTSEND = (LDAP_BACK_RETRYING),
+ LDAP_BACK_RETRY_SOK = (LDAP_BACK_RETRYING|LDAP_BACK_SENDOK),
+ LDAP_BACK_RETRY_SERR = (LDAP_BACK_RETRYING|LDAP_BACK_SENDERR),
+ LDAP_BACK_RETRY_SRES = (LDAP_BACK_RETRYING|LDAP_BACK_SENDRESULT),
+
+ LDAP_BACK_GETCONN = 0x10
} ldap_back_send_t;
/* define to use asynchronous StartTLS */
(tv)->tv_usec = LDAP_BACK_RESULT_UTIMEOUT; \
} while ( 0 )
+#ifndef LDAP_BACK_PRINT_CONNTREE
+#define LDAP_BACK_PRINT_CONNTREE 0
+#endif /* !LDAP_BACK_PRINT_CONNTREE */
+
LDAP_END_DECL
#include "proto-ldap.h"
#define AVL_INTERNAL
#include "slap.h"
#include "back-ldap.h"
+#undef ldap_debug /* silence a warning in ldap-int.h */
+#include "../../../libraries/libldap/ldap-int.h"
-#include <lutil_ldap.h>
-
-#ifndef PRINT_CONNTREE
-#define PRINT_CONNTREE 0
-#endif /* !PRINT_CONNTREE */
+#include "lutil_ldap.h"
#define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ "2.16.840.1.113730.3.4.12"
-static LDAP_REBIND_PROC ldap_back_default_rebind;
+#if LDAP_BACK_PRINT_CONNTREE > 0
+static void
+ldap_back_ravl_print( Avlnode *root, int depth )
+{
+ int i;
+ ldapconn_t *lc;
+
+ if ( root == 0 ) {
+ return;
+ }
+
+ ldap_back_ravl_print( root->avl_right, depth+1 );
+
+ for ( i = 0; i < depth; i++ ) {
+ fprintf( stderr, "-" );
+ }
+
+ lc = root->avl_data;
+ fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d flags=0x%08x\n",
+ (void *)lc,
+ lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
+ (void *)lc->lc_conn,
+ avl_bf2str( root->avl_bf ), lc->lc_refcnt, lc->lc_lcflags );
+
+ ldap_back_ravl_print( root->avl_left, depth+1 );
+}
+
+static char* priv2str[] = {
+ "privileged",
+ "privileged/TLS",
+ "anonymous",
+ "anonymous/TLS",
+ "bind",
+ "bind/TLS",
+ NULL
+};
+
+void
+ldap_back_print_conntree( ldapinfo_t *li, char *msg )
+{
+ int c;
+
+ fprintf( stderr, "========> %s\n", msg );
+
+ for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
+ int i = 0;
+ ldapconn_t *lc;
+
+ fprintf( stderr, " %s[%d]\n", priv2str[ c ], li->li_conn_priv[ c ].lic_num );
+
+ LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )
+ {
+ fprintf( stderr, " [%d] lc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",
+ i,
+ (void *)lc,
+ lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
+ (void *)lc->lc_conn, lc->lc_refcnt, lc->lc_lcflags );
+ i++;
+ }
+ }
+
+ if ( li->li_conninfo.lai_tree == 0 ) {
+ fprintf( stderr, "\t(empty)\n" );
+
+ } else {
+ ldap_back_ravl_print( li->li_conninfo.lai_tree, 0 );
+ }
+
+ fprintf( stderr, "<======== %s\n", msg );
+}
+#endif /* LDAP_BACK_PRINT_CONNTREE */
+
+static int
+ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock );
+
+static ldapconn_t *
+ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
+ struct berval *binddn, struct berval *bindcred );
-LDAP_REBIND_PROC *ldap_back_rebind_f = ldap_back_default_rebind;
+static int
+ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
+ struct berval *binddn, struct berval *bindcred );
static int
-ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
+ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs,
+ ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred );
static int
-ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
+ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs,
+ ldap_back_send_t sendok );
static int
ldap_back_conndnlc_cmp( const void *c1, const void *c2 );
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 );
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
if ( !lc ) {
return rs->sr_err;
}
+ /* we can do (almost) whatever we want with this conn,
+ * because either it's temporary, or it's marked as binding */
if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
ch_free( lc->lc_bound_ndn.bv_val );
BER_BVZERO( &lc->lc_bound_ndn );
}
+ if ( !BER_BVISNULL( &lc->lc_cred ) ) {
+ memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len );
+ ch_free( lc->lc_cred.bv_val );
+ BER_BVZERO( &lc->lc_cred );
+ }
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 );
- rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDERR );
+ /* 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 | 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, a successful bind is followed by a
- * bind with the configured identity assertion */
+ * purpose, after a successful bind the connection
+ * 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_proxy_authz_bind( lc, op, rs, LDAP_BACK_SENDERR );
- if ( !LDAP_BACK_CONN_ISBOUND( lc ) ) {
- rc = 1;
- goto done;
- }
+ assert( lc->lc_binding == 1 );
+ lc->lc_binding = 0;
+ ldap_back_release_conn( op, rs, lc );
+ return( rc );
}
+ /* rebind is now done inside ldap_back_proxy_authz_bind()
+ * in case of success */
LDAP_BACK_CONN_ISBOUND_SET( lc );
ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
+ if ( !BER_BVISNULL( &lc->lc_cred ) ) {
+ memset( lc->lc_cred.bv_val, 0,
+ lc->lc_cred.bv_len );
+ }
+
if ( LDAP_BACK_SAVECRED( li ) ) {
- if ( !BER_BVISNULL( &lc->lc_cred ) ) {
- memset( lc->lc_cred.bv_val, 0,
- lc->lc_cred.bv_len );
- }
ber_bvreplace( &lc->lc_cred, &op->orb_cred );
- ldap_set_rebind_proc( lc->lc_ld, ldap_back_rebind_f, lc );
+ ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
+
+ } else {
+ lc->lc_cred.bv_len = 0;
}
}
-done:;
assert( lc->lc_binding == 1 );
lc->lc_binding = 0;
/* must re-insert if local DN changed as result of bind */
if ( !LDAP_BACK_CONN_ISBOUND( lc )
- || ( LDAP_BACK_CONN_ISBOUND( lc )
- && !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) ) )
+ || ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
+ && !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
{
int lerr = -1;
ldapconn_t *tmplc;
goto retry_lock;
}
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, ">>> ldap_back_bind" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
+
assert( lc->lc_refcnt == 1 );
- tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conndnlc_cmp );
- assert( tmplc == NULL || lc == tmplc );
+ if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ /* this can happen, for example, if the bind fails
+ * for some reason... */
+ if ( lc->lc_q.tqe_prev != NULL ) {
+ assert( LDAP_BACK_CONN_CACHED( lc ) );
+ assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
+ li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
+
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( lc ) );
+ }
+
+ } else {
+ tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+ ldap_back_conndnlc_cmp );
+ assert( ( LDAP_BACK_CONN_TAINTED( lc ) && tmplc == NULL ) || lc == tmplc );
+ }
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+
+ /* delete all cached connections with the current connection */
+ if ( LDAP_BACK_SINGLECONN( li ) ) {
+ while ( ( tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
+ {
+ Debug( LDAP_DEBUG_TRACE,
+ "=>ldap_back_bind: destroying conn %ld (refcnt=%u)\n",
+ LDAP_BACK_PCONN_ID( lc ), lc->lc_refcnt, 0 );
+
+ if ( tmplc->lc_refcnt != 0 ) {
+ /* taint it */
+ LDAP_BACK_CONN_TAINTED_SET( tmplc );
+ LDAP_BACK_CONN_CACHED_CLEAR( tmplc );
+
+ } else {
+ /*
+ * Needs a test because the handler may be corrupted,
+ * and calling ldap_unbind on a corrupted header results
+ * in a segmentation fault
+ */
+ ldap_back_conn_free( tmplc );
+ }
+ }
+ }
if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
+ if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
+ LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
+ }
lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndn_cmp, ldap_back_conndn_dup );
}
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, "<<< ldap_back_bind" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
+
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
switch ( lerr ) {
case 0:
+ LDAP_BACK_CONN_CACHED_SET( lc );
break;
case -1:
return 0;
}
-#if PRINT_CONNTREE > 0
-static void
-ravl_print( Avlnode *root, int depth )
+static int
+ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock )
{
- int i;
- ldapconn_t *lc;
-
- if ( root == 0 ) {
- return;
- }
-
- ravl_print( root->avl_right, depth+1 );
-
- for ( i = 0; i < depth; i++ ) {
- fprintf( stderr, "-" );
+ ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
+
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
}
- lc = root->avl_data;
- fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d\n",
- (void *)lc, lc->lc_local_ndn.bv_val, (void *)lc->lc_conn,
- avl_bf2str( root->avl_bf ), lc->lc_refcnt );
-
- ravl_print( root->avl_left, depth+1 );
-}
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
-static void
-myprint( Avlnode *root )
-{
- fprintf( stderr, "========>\n" );
-
- if ( root == 0 ) {
- fprintf( stderr, "\tNULL\n" );
+ if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ if ( lc->lc_q.tqe_prev != NULL ) {
+ assert( LDAP_BACK_CONN_CACHED( lc ) );
+ assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
+ li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
- } else {
- ravl_print( root, 0 );
- }
-
- fprintf( stderr, "<========\n" );
-}
-#endif /* PRINT_CONNTREE */
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( lc ) );
+ }
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
-int
-ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock )
-{
- ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
- ldapconn_t *tmplc;
+ } else {
+ ldapconn_t *tmplc = NULL;
- if ( dolock ) {
- ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ if ( LDAP_BACK_CONN_CACHED( lc ) ) {
+ tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+ ldap_back_conndnlc_cmp );
+ assert( tmplc == lc );
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+ }
+ assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
}
- tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conndnlc_cmp );
- assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
if ( lc->lc_refcnt == 0 ) {
ldap_back_conn_free( (void *)lc );
}
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
+
if ( dolock ) {
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
const char **text )
{
int rc = LDAP_SUCCESS;
- ldapinfo_t dummy;
-
- /* this is ridiculous... */
- dummy.li_flags = flags;
/* start TLS ("tls-[try-]{start,propagate}" statements) */
- if ( ( LDAP_BACK_USE_TLS( &dummy ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS( &dummy ) ) )
+ if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
&& !ldap_is_ldaps_url( url ) )
{
#ifdef SLAP_STARTTLS_ASYNCHRONOUS
}
if ( protocol < LDAP_VERSION3 ) {
- protocol = LDAP_VERSION3;
- /* Set LDAP version */
- ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
- (const void *)&protocol );
+ /* we should rather bail out... */
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ *text = "invalid protocol version";
+ }
+
+ if ( rc == LDAP_SUCCESS ) {
+ rc = ldap_start_tls( ld, NULL, NULL, &msgid );
}
- rc = ldap_start_tls( ld, NULL, NULL, &msgid );
if ( rc == LDAP_SUCCESS ) {
LDAPMessage *res = NULL;
struct timeval tv;
break;
default:
- if ( LDAP_BACK_TLS_CRITICAL( &dummy ) ) {
+ if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
*text = "could not start TLS";
break;
}
ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- int vers = op->o_protocol;
+ int version;
LDAP *ld = NULL;
#ifdef HAVE_TLS
int is_tls = op->o_conn->c_is_tls;
+ time_t lc_time = (time_t)(-1);
#endif /* HAVE_TLS */
assert( lcp != NULL );
+ ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
rs->sr_err = ldap_initialize( &ld, li->li_uri );
+ ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
if ( rs->sr_err != LDAP_SUCCESS ) {
goto error_return;
}
/* Set LDAP version. This will always succeed: If the client
* bound with a particular version, then so can we.
*/
- if ( vers == 0 ) {
+ if ( li->li_version != 0 ) {
+ version = li->li_version;
+
+ } else if ( op->o_protocol != 0 ) {
+ version = op->o_protocol;
+
+ } else {
/* assume it's an internal op; set to LDAPv3 */
- vers = LDAP_VERSION3;
+ version = LDAP_VERSION3;
}
- ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
+ ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version );
/* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
ldap_set_option( ld, LDAP_OPT_REFERRALS,
}
#ifdef HAVE_TLS
+ ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
li->li_uri, li->li_flags, li->li_nretries, &rs->sr_text );
+ ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
if ( rs->sr_err != LDAP_SUCCESS ) {
ldap_unbind_ext( ld, NULL, NULL );
goto error_return;
+
+ } else if ( li->li_idle_timeout ) {
+ /* only touch when activity actually took place... */
+ lc_time = op->o_time;
}
#endif /* HAVE_TLS */
if ( *lcp == NULL ) {
*lcp = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) );
- (*lcp)->lc_flags= li->li_flags;
+ (*lcp)->lc_flags = li->li_flags;
}
(*lcp)->lc_ld = ld;
(*lcp)->lc_refcnt = 1;
} else {
LDAP_BACK_CONN_ISTLS_CLEAR( *lcp );
}
+ if ( lc_time != (time_t)(-1) ) {
+ (*lcp)->lc_time = lc_time;
+ }
#endif /* HAVE_TLS */
error_return:;
return rs->sr_err;
}
-ldapconn_t *
-ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
+static ldapconn_t *
+ldap_back_getconn(
+ Operation *op,
+ SlapReply *rs,
+ ldap_back_send_t sendok,
+ struct berval *binddn,
+ struct berval *bindcred )
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
ldapconn_t *lc = NULL,
lc_curr = { 0 };
- int refcnt = 1, binding = 1;
+ int refcnt = 1,
+ binding = 1,
+ lookupconn = !( sendok & LDAP_BACK_BINDING );
+
+ /* if the server is quarantined, and
+ * - the current interval did not expire yet, or
+ * - no more retries should occur,
+ * don't return the connection */
+ if ( li->li_isquarantined ) {
+ slap_retry_info_t *ri = &li->li_quarantine;
+ int dont_retry = 1;
+
+ if ( li->li_quarantine.ri_interval ) {
+ ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
+ if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
+ dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
+ || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
+ if ( !dont_retry ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: ldap_back_getconn quarantine "
+ "retry block #%d try #%d.\n",
+ op->o_log_prefix, ri->ri_idx, ri->ri_count );
+ li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
+ }
+ }
+ ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
+ }
+
+ if ( dont_retry ) {
+ rs->sr_err = LDAP_UNAVAILABLE;
+ if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
+ send_ldap_result( op, rs );
+ }
+ return NULL;
+ }
+ }
/* Internal searches are privileged and shared. So is root. */
if ( op->o_do_not_cache || be_isroot( op ) ) {
LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
- lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
} else {
+ 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 ( isproxyauthz == -1 ) {
+ return NULL;
+ }
+ 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 */
- if ( op->o_tag == LDAP_REQ_BIND || SLAP_IS_AUTHZ_BACKEND( op ) ) {
+ /* 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 {
- lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
+ if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
+ lc_curr.lc_local_ndn = *binddn;
+ LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, 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;
+ LDAP_BACK_PCONN_BIND_SET( &lc_curr, op );
+ LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
+ lookupconn = 1;
+
+ } else if ( SLAP_IS_AUTHZ_BACKEND( op ) ) {
+ lc_curr.lc_conn = op->o_conn;
+
+ } else {
+ LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
+ }
}
}
/* Explicit Bind requests always get their own conn */
- if ( !( sendok & LDAP_BACK_BINDING ) ) {
- /* Searches for a ldapconn in the avl tree */
+ if ( lookupconn ) {
retry_lock:
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) {
+ /* lookup a conn that's not binding */
+ LDAP_TAILQ_FOREACH( lc,
+ &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv,
+ lc_q )
+ {
+ if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) {
+ break;
+ }
+ }
+
+ if ( lc != NULL ) {
+ if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
+ ldapconn_t, lc_q ) )
+ {
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
+ lc, lc_q );
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
+ LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
+ lc, lc_q );
+ }
+
+ } else if ( !LDAP_BACK_USE_TEMPORARIES( li )
+ && li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max )
+ {
+ lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv );
+ }
+
+ } else {
+
+ /* Searches for a ldapconn in the avl tree */
+ lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
+ (caddr_t)&lc_curr, ldap_back_conndn_cmp );
+ }
- lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
- (caddr_t)&lc_curr, ldap_back_conndn_cmp );
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;
+ }
+
+ if ( lc != NULL ) {
+ 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 );
}
if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) {
return NULL;
}
+
if ( sendok & LDAP_BACK_BINDING ) {
LDAP_BACK_CONN_BINDING_SET( lc );
}
+
lc->lc_conn = lc_curr.lc_conn;
ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
+ /*
+ * the rationale is: connections as the rootdn are privileged,
+ * so acl_authcDN is to be used; however, in some cases
+ * one already configured identity assertion with a highly
+ * privileged idassert_authcDN, so if acl_authcDN is NULL
+ * and idassert_authcDN is not, use the second instead.
+ *
+ * might change in the future, because it's preferable
+ * to make clear what identity is being used, since
+ * the only drawback is that one risks to configure
+ * the same identity twice...
+ */
if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) {
- ber_dupbv( &lc->lc_cred, &li->li_acl_passwd );
- ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN );
+ if ( BER_BVISNULL( &li->li_acl_authcDN ) && !BER_BVISNULL( &li->li_idassert_authcDN ) ) {
+ ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
+ ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
+
+ } else {
+ ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN );
+ ber_dupbv( &lc->lc_cred, &li->li_acl_passwd );
+ }
LDAP_BACK_CONN_ISPRIV_SET( lc );
+ } else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) {
+ if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) {
+ ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
+ ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
+ }
+ LDAP_BACK_CONN_ISIDASSERT_SET( lc );
+
} else {
BER_BVZERO( &lc->lc_cred );
BER_BVZERO( &lc->lc_bound_ndn );
-#if 0
- /* FIXME: if we set lc_bound_ndn = o_ndn
- * we end up with a bind with DN but no password! */
if ( !BER_BVISEMPTY( &op->o_ndn )
&& SLAP_IS_AUTHZ_BACKEND( op ) )
{
ber_dupbv( &lc->lc_bound_ndn, &op->o_ndn );
}
-#endif
}
#ifdef HAVE_TLS
* check if the non-TLS connection was already
* in cache; in case, destroy the newly created
* connection and use the existing one */
- if ( lc->lc_conn == LDAP_BACK_PCONN_TLS
+ if ( LDAP_BACK_PCONN_ISTLS( lc )
&& !ldap_tls_inplace( lc->lc_ld ) )
{
- ldapconn_t *tmplc;
+ ldapconn_t *tmplc = NULL;
+ int idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1;
- lc_curr.lc_conn = LDAP_BACK_PCONN;
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
- tmplc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
- (caddr_t)&lc_curr, ldap_back_conndn_cmp );
+ LDAP_TAILQ_FOREACH( tmplc,
+ &li->li_conn_priv[ idx ].lic_priv,
+ lc_q )
+ {
+ if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) {
+ break;
+ }
+ }
+
if ( tmplc != NULL ) {
refcnt = ++tmplc->lc_refcnt;
binding = ++tmplc->lc_binding;
}
#endif /* HAVE_TLS */
- LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
-
/* Inserts the newly created ldapconn in the avl tree */
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+
assert( lc->lc_refcnt == 1 );
assert( lc->lc_binding == 1 );
- rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conndn_cmp, ldap_back_conndn_dup );
-#if PRINT_CONNTREE > 0
- myprint( li->li_conninfo.lai_tree );
-#endif /* PRINT_CONNTREE */
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
+
+ if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) {
+ LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
+ li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++;
+ LDAP_BACK_CONN_CACHED_SET( lc );
+
+ } else {
+ LDAP_BACK_CONN_TAINTED_SET( lc );
+ }
+ rs->sr_err = 0;
+
+ } else {
+ rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
+ ldap_back_conndn_cmp, ldap_back_conndn_dup );
+ LDAP_BACK_CONN_CACHED_SET( lc );
+ }
+
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
- Debug( LDAP_DEBUG_TRACE,
- "=>ldap_back_getconn: conn %p inserted refcnt=%u binding=%u\n",
- (void *)lc, refcnt, binding );
+ if ( StatslogTest( LDAP_DEBUG_TRACE ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "lc=%p inserted refcnt=%u binding=%u rc=%d",
+ (void *)lc, refcnt, binding, rs->sr_err );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=>ldap_back_getconn: %s: %s\n",
+ op->o_log_prefix, buf, 0 );
+ }
- /* Err could be -1 in case a duplicate ldapconn is inserted */
- switch ( rs->sr_err ) {
- case 0:
- break;
+ if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ /* Err could be -1 in case a duplicate ldapconn is inserted */
+ switch ( rs->sr_err ) {
+ case 0:
+ break;
- case -1:
- if ( !( sendok & LDAP_BACK_BINDING ) ) {
- /* duplicate: free and try to get the newly created one */
- goto retry_lock;
- }
- /* taint connection, so that it'll be freed when released */
- ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
- (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conndnlc_cmp );
- ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
- LDAP_BACK_CONN_TAINTED_SET( lc );
- break;
+ case -1:
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+ 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;
+ }
- default:
- ldap_back_conn_free( lc );
- rs->sr_err = LDAP_OTHER;
- rs->sr_text = "proxy bind collision";
- if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
- send_ldap_result( op, rs );
- rs->sr_text = NULL;
+ /* taint connection, so that it'll be freed when released */
+ LDAP_BACK_CONN_TAINTED_SET( lc );
+ break;
+
+ default:
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+ ldap_back_conn_free( lc );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "proxy bind collision";
+ if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
+ send_ldap_result( op, rs );
+ rs->sr_text = NULL;
+ }
+ return NULL;
}
- return NULL;
}
} else {
- char buf[ SLAP_TEXT_BUFLEN ];
int expiring = 0;
if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout )
/* let it be used, but taint/delete it so that
* no-one else can look it up any further */
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
- (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
+
+ if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ if ( lc->lc_q.tqe_prev != NULL ) {
+ assert( LDAP_BACK_CONN_CACHED( lc ) );
+ assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
+ lc, lc_q );
+ li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
+
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( lc ) );
+ }
+
+ } else {
+ (void)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndnlc_cmp );
- ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
LDAP_BACK_CONN_TAINTED_SET( lc );
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
+
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
- {
+ if ( StatslogTest( LDAP_DEBUG_TRACE ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
snprintf( buf, sizeof( buf ),
"conn %p fetched refcnt=%u binding=%u%s",
(void *)lc, refcnt, binding, expiring ? " expiring" : "" );
Debug( LDAP_DEBUG_TRACE,
"=>ldap_back_getconn: %s.\n", buf, 0, 0 );
}
-
}
#ifdef HAVE_TLS
done:;
#endif /* HAVE_TLS */
- if ( li->li_idle_timeout && lc ) {
- lc->lc_time = op->o_time;
- }
return lc;
}
ldap_back_release_conn_lock(
Operation *op,
SlapReply *rs,
- ldapconn_t *lc,
+ ldapconn_t **lcp,
int dolock )
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+ ldapconn_t *lc = *lcp;
+
if ( dolock ) {
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
}
lc->lc_refcnt--;
if ( LDAP_BACK_CONN_TAINTED( lc ) ) {
ldap_back_freeconn( op, lc, 0 );
+ *lcp = NULL;
}
if ( dolock ) {
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
}
+void
+ldap_back_quarantine(
+ Operation *op,
+ SlapReply *rs )
+{
+ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+
+ slap_retry_info_t *ri = &li->li_quarantine;
+
+ ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
+
+ if ( rs->sr_err == LDAP_UNAVAILABLE ) {
+ time_t new_last = slap_get_time();
+
+ switch ( li->li_isquarantined ) {
+ case LDAP_BACK_FQ_NO:
+ if ( ri->ri_last == new_last ) {
+ goto done;
+ }
+
+ Debug( LDAP_DEBUG_ANY,
+ "%s: ldap_back_quarantine enter.\n",
+ op->o_log_prefix, 0, 0 );
+
+ ri->ri_idx = 0;
+ ri->ri_count = 0;
+ break;
+
+ case LDAP_BACK_FQ_RETRYING:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: ldap_back_quarantine block #%d try #%d failed.\n",
+ op->o_log_prefix, ri->ri_idx, ri->ri_count );
+
+ ++ri->ri_count;
+ if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER
+ && ri->ri_count == ri->ri_num[ ri->ri_idx ] )
+ {
+ ri->ri_count = 0;
+ ++ri->ri_idx;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ li->li_isquarantined = LDAP_BACK_FQ_YES;
+ 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 (%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 );
+ }
+
+ ri->ri_count = 0;
+ ri->ri_idx = 0;
+ li->li_isquarantined = LDAP_BACK_FQ_NO;
+ }
+
+done:;
+ ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
+}
+
/*
- * ldap_back_dobind
- *
- * Note: as the check for the value of lc->lc_bound was already here, I removed
- * it from all the callers, and I made the function return the flag, so
- * it can be used to simplify the check.
+ * ldap_back_dobind_int
*
* Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
*/
static int
ldap_back_dobind_int(
- ldapconn_t *lc,
+ ldapconn_t **lcp,
Operation *op,
SlapReply *rs,
ldap_back_send_t sendok,
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- int rc, binding = 0;
+ ldapconn_t *lc;
+ struct berval binddn = slap_empty_bv,
+ bindcred = slap_empty_bv;
+
+ int rc = 0,
+ isbound,
+ binding = 0;
ber_int_t msgid;
+ assert( lcp != NULL );
assert( retries >= 0 );
+ if ( sendok & LDAP_BACK_GETCONN ) {
+ assert( *lcp == NULL );
+
+ lc = ldap_back_getconn( op, rs, sendok, &binddn, &bindcred );
+ if ( lc == NULL ) {
+ return 0;
+ }
+ *lcp = lc;
+
+ } else {
+ lc = *lcp;
+ }
+
+ assert( lc != NULL );
+
retry_lock:;
if ( dolock ) {
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
if ( binding == 0 ) {
/* check if already bound */
- rc = LDAP_BACK_CONN_ISBOUND( lc );
- if ( rc ) {
+ rc = isbound = LDAP_BACK_CONN_ISBOUND( lc );
+ if ( isbound ) {
lc->lc_binding--;
if ( dolock ) {
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
-#if 0
- while ( lc->lc_refcnt > 1 ) {
- ldap_pvt_thread_yield();
- rc = LDAP_BACK_CONN_ISBOUND( lc );
- if ( rc ) {
- return rc;
- }
- }
-
- if ( dolock ) {
- ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
- }
- LDAP_BACK_CONN_BINDING_SET( lc );
- if ( dolock ) {
- ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
- }
-#endif
-
/*
* FIXME: we need to let clients use proxyAuthz
* otherwise we cannot do symmetric pools of servers;
* but the "override" flag is given to idassert.
* It allows to use SASL bind and yet proxyAuthz users
*/
- if ( op->o_conn != NULL &&
- !op->o_do_not_cache &&
- ( BER_BVISNULL( &lc->lc_bound_ndn ) ||
- ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
- {
- (void)ldap_back_proxy_authz_bind( lc, op, rs, sendok );
+ if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
+ if ( BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &bindcred ) ) {
+ /* if we got here, it shouldn't return result */
+ rc = ldap_back_is_proxy_authz( op, rs,
+ LDAP_BACK_DONTSEND, &binddn, &bindcred );
+ assert( rc == 1 );
+ }
+ rc = ldap_back_proxy_authz_bind( lc, op, rs, sendok, &binddn, &bindcred );
goto done;
}
if ( li->li_acl_secprops != NULL ) {
rc = ldap_set_option( lc->lc_ld,
- LDAP_OPT_X_SASL_SECPROPS, li->li_acl_secprops);
+ LDAP_OPT_X_SASL_SECPROPS, li->li_acl_secprops );
if ( rc != LDAP_OPT_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
- "(%s,SECPROPS,\"%s\") failed!\n",
- li->li_uri, li->li_acl_secprops, 0 );
+ "(SECPROPS,\"%s\") failed!\n",
+ li->li_acl_secprops, 0, 0 );
goto done;
}
}
rs->sr_err = slap_map_api2result( rs );
if ( rs->sr_err != LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
- send_ldap_result( op, rs );
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
} else {
LDAP_BACK_CONN_ISBOUND_SET( lc );
}
+
+ if ( LDAP_BACK_QUARANTINE( li ) ) {
+ ldap_back_quarantine( op, rs );
+ }
+
goto done;
}
#endif /* HAVE_CYRUS_SASL */
retry:;
rs->sr_err = ldap_sasl_bind( lc->lc_ld,
- lc->lc_bound_ndn.bv_val,
+ BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val,
LDAP_SASL_SIMPLE, &lc->lc_cred,
NULL, NULL, &msgid );
}
}
+ /* FIXME: one binding-- too many? */
+ lc->lc_binding--;
+ assert( lc->lc_refcnt == 1 );
+ lc->lc_refcnt = 0;
ldap_back_freeconn( op, lc, dolock );
+ *lcp = NULL;
rs->sr_err = slap_map_api2result( rs );
+ if ( LDAP_BACK_QUARANTINE( li ) ) {
+ ldap_back_quarantine( op, rs );
+ }
+
+ if ( rs->sr_err != LDAP_SUCCESS &&
+ ( sendok & LDAP_BACK_SENDERR ) )
+ {
+ send_ldap_result( op, rs );
+ }
+
return 0;
}
- rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
+ rc = ldap_back_op_result( lc, op, rs, msgid,
+ -1, (sendok|LDAP_BACK_BINDING) );
if ( rc == LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_SET( lc );
}
LDAP_BACK_CONN_BINDING_CLEAR( lc );
rc = LDAP_BACK_CONN_ISBOUND( lc );
if ( !rc ) {
- ldap_back_release_conn_lock( op, rs, lc, dolock );
+ ldap_back_release_conn_lock( op, rs, lcp, dolock );
+
+ } else if ( LDAP_BACK_SAVECRED( li ) ) {
+ ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
}
return rc;
}
+/*
+ * ldap_back_dobind
+ *
+ * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
+ */
int
-ldap_back_dobind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
+ldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- return ldap_back_dobind_int( lc, op, rs, sendok, li->li_nretries, 1 );
+ return ldap_back_dobind_int( lcp, op, rs,
+ ( sendok | LDAP_BACK_GETCONN ), li->li_nretries, 1 );
}
/*
* This is a callback used for chasing referrals using the same
* credentials as the original user on this session.
*/
-static int
+int
ldap_back_default_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
ber_int_t msgid, void *params )
{
/* FIXME: add checks on the URL/identity? */
- return ldap_sasl_bind_s( ld, lc->lc_bound_ndn.bv_val,
+ return ldap_sasl_bind_s( ld,
+ BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val,
LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL );
}
+int
+ldap_back_cancel(
+ ldapconn_t *lc,
+ Operation *op,
+ SlapReply *rs,
+ ber_int_t msgid,
+ ldap_back_send_t sendok )
+{
+ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+
+ /* default behavior */
+ if ( LDAP_BACK_ABANDON( li ) ) {
+ return ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
+ }
+
+ if ( LDAP_BACK_CANCEL( li ) ) {
+ /* FIXME: asynchronous? */
+ return ldap_cancel_s( lc->lc_ld, msgid, NULL, NULL );
+ }
+
+ assert( 0 );
+
+ return LDAP_OTHER;
+}
+
int
ldap_back_op_result(
ldapconn_t *lc,
time_t timeout,
ldap_back_send_t sendok )
{
+ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+
char *match = NULL;
- LDAPMessage *res = NULL;
char *text = NULL;
+ char **refs = NULL;
+ LDAPControl **ctrls = NULL;
#define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE)
rs->sr_text = NULL;
rs->sr_matched = NULL;
+ rs->sr_ref = NULL;
+ rs->sr_ctrls = NULL;
/* if the error recorded in the reply corresponds
* to a successful state, get the error from the
if ( ERR_OK( rs->sr_err ) ) {
int rc;
struct timeval tv;
+ LDAPMessage *res = NULL;
+ time_t stoptime = (time_t)(-1);
+ int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ const char *timeout_text = "Operation timed out";
- if ( timeout ) {
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
+ /* if timeout is not specified, compute and use
+ * the one specific to the ongoing operation */
+ if ( timeout == (time_t)(-1) ) {
+ slap_op_t opidx = slap_req2op( op->o_tag );
- } else {
- LDAP_BACK_TV_SET( &tv );
+ if ( opidx == SLAP_OP_SEARCH ) {
+ if ( op->ors_tlimit <= 0 ) {
+ timeout = 0;
+
+ } else {
+ timeout = op->ors_tlimit;
+ timeout_err = LDAP_TIMELIMIT_EXCEEDED;
+ timeout_text = NULL;
+ }
+
+ } else {
+ timeout = li->li_timeout[ opidx ];
+ }
+ }
+
+ /* better than nothing :) */
+ if ( timeout == 0 ) {
+ if ( li->li_idle_timeout ) {
+ timeout = li->li_idle_timeout;
+
+ } else if ( li->li_conn_ttl ) {
+ timeout = li->li_conn_ttl;
+ }
+ }
+
+ if ( timeout ) {
+ stoptime = op->o_time + timeout;
}
+ LDAP_BACK_TV_SET( &tv );
+
retry:;
/* if result parsing fails, note the failure reason */
rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
switch ( rc ) {
case 0:
- if ( timeout ) {
- (void)ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
- rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
- LDAP_ADMINLIMIT_EXCEEDED : LDAP_OPERATIONS_ERROR;
- rs->sr_text = "Operation timed out";
+ if ( timeout && slap_get_time() > stoptime ) {
+ if ( sendok & LDAP_BACK_BINDING ) {
+ ldap_unbind_ext( lc->lc_ld, NULL, NULL );
+ lc->lc_ld = NULL;
+ LDAP_BACK_CONN_TAINTED_SET( lc );
+
+ } else {
+ (void)ldap_back_cancel( lc, op, rs, msgid, sendok );
+ }
+ rs->sr_err = timeout_err;
+ rs->sr_text = timeout_text;
break;
}
+ /* timeout == 0 */
LDAP_BACK_TV_SET( &tv );
ldap_pvt_thread_yield();
goto retry;
* structure (this includes
* LDAP_COMPARE_{TRUE|FALSE}) */
default:
- rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
- &match, &text, NULL, NULL, 1 );
-#ifndef LDAP_NULL_IS_NULL
- if ( match != NULL && match[ 0 ] == '\0' ) {
- ldap_memfree( match );
- match = NULL;
- }
- if ( text != NULL && text[ 0 ] == '\0' ) {
- ldap_memfree( text );
- text = NULL;
+ /* only touch when activity actually took place... */
+ if ( li->li_idle_timeout && lc ) {
+ lc->lc_time = op->o_time;
}
-#endif /* LDAP_NULL_IS_NULL */
+
+ rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
+ &match, &text, &refs, &ctrls, 1 );
rs->sr_text = text;
if ( rc != LDAP_SUCCESS ) {
rs->sr_err = rc;
}
+ if ( refs != NULL ) {
+ int i;
+
+ for ( i = 0; refs[ i ] != NULL; i++ )
+ /* count */ ;
+ rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
+ op->o_tmpmemctx );
+ for ( i = 0; refs[ i ] != NULL; i++ ) {
+ ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
+ }
+ BER_BVZERO( &rs->sr_ref[ i ] );
+ }
+ if ( ctrls != NULL ) {
+ rs->sr_ctrls = ctrls;
+ }
}
}
rs->sr_matched = match;
}
}
- if ( op->o_conn &&
- ( ( sendok & LDAP_BACK_SENDOK )
- || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) )
+
+ if ( rs->sr_err == LDAP_UNAVAILABLE ) {
+ if ( !( sendok & LDAP_BACK_RETRYING ) ) {
+ if ( LDAP_BACK_QUARANTINE( li ) ) {
+ ldap_back_quarantine( op, rs );
+ }
+ if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
+ send_ldap_result( op, rs );
+ }
+ }
+
+ } else if ( op->o_conn &&
+ ( ( ( sendok & LDAP_BACK_SENDOK ) && ERR_OK( rs->sr_err ) )
+ || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) )
{
send_ldap_result( op, rs );
}
+
if ( match ) {
if ( rs->sr_matched != match ) {
free( (char *)rs->sr_matched );
rs->sr_matched = NULL;
ldap_memfree( match );
}
+
if ( text ) {
ldap_memfree( text );
}
rs->sr_text = NULL;
+
+ if ( rs->sr_ref ) {
+ assert( refs != NULL );
+ ber_memvfree( (void **)refs );
+ op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
+ rs->sr_ref = NULL;
+ }
+
+ if ( ctrls ) {
+ assert( rs->sr_ctrls != NULL );
+ ldap_controls_free( ctrls );
+ rs->sr_ctrls = NULL;
+ }
+
return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
}
int
ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
{
- int rc = 0;
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+ int rc = 0,
+ binding;
assert( lcp != NULL );
assert( *lcp != NULL );
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
if ( (*lcp)->lc_refcnt == 1 ) {
+ binding = LDAP_BACK_CONN_BINDING( *lcp );
+
+ ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
Debug( LDAP_DEBUG_ANY,
"%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
op->o_log_prefix, li->li_uri,
BER_BVISNULL( &(*lcp)->lc_bound_ndn ) ?
"" : (*lcp)->lc_bound_ndn.bv_val );
+ ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
ldap_unbind_ext( (*lcp)->lc_ld, NULL, NULL );
(*lcp)->lc_ld = NULL;
/* lc here must be the regular lc, reset and ready for init */
rc = ldap_back_prepare_conn( lcp, op, rs, sendok );
if ( rc != LDAP_SUCCESS ) {
- rc = 0;
+ /* freeit, because lc_refcnt == 1 */
+ (*lcp)->lc_refcnt = 0;
+ (void)ldap_back_freeconn( op, *lcp, 0 );
*lcp = NULL;
+ rc = 0;
+
+ } else if ( ( sendok & LDAP_BACK_BINDING ) ) {
+ if ( binding ) {
+ LDAP_BACK_CONN_BINDING_SET( *lcp );
+ }
+ rc = 1;
} else {
- rc = ldap_back_dobind_int( *lcp, op, rs, sendok, 0, 0 );
- if ( rc == 0 ) {
+ rc = ldap_back_dobind_int( lcp, op, rs, sendok, 0, 0 );
+ if ( rc == 0 && *lcp != NULL ) {
+ /* freeit, because lc_refcnt == 1 */
+ (*lcp)->lc_refcnt = 0;
+ LDAP_BACK_CONN_TAINTED_SET( *lcp );
+ (void)ldap_back_freeconn( op, *lcp, 0 );
*lcp = NULL;
}
}
"ldap_back_retry: conn %p refcnt=%u unable to retry.\n",
(void *)(*lcp), (*lcp)->lc_refcnt, 0 );
- ldap_back_release_conn_lock( op, rs, *lcp, 0 );
- *lcp = NULL;
+ LDAP_BACK_CONN_TAINTED_SET( *lcp );
+ ldap_back_release_conn_lock( op, rs, lcp, 0 );
+ assert( *lcp == NULL );
if ( sendok ) {
rs->sr_err = LDAP_UNAVAILABLE;
}
static int
-ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
+ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
+ struct berval *binddn, struct berval *bindcred )
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- struct berval binddn = slap_empty_bv;
- struct berval bindcred = slap_empty_bv;
struct berval ndn;
int dobind = 0;
- int msgid;
- int rc;
+
+ if ( op->o_conn == NULL || op->o_do_not_cache ) {
+ goto done;
+ }
+
+ /* don't proxyAuthz if protocol is not LDAPv3 */
+ switch ( li->li_version ) {
+ case LDAP_VERSION3:
+ break;
+
+ case 0:
+ if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
+ break;
+ }
+ /* fall thru */
+
+ default:
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ dobind = -1;
+ }
+ goto done;
+ }
+
+ /* safe default */
+ *binddn = slap_empty_bv;
+ *bindcred = slap_empty_bv;
if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
ndn = op->o_conn->c_ndn;
ndn = op->o_ndn;
}
- /*
- * FIXME: we need to let clients use proxyAuthz
- * otherwise we cannot do symmetric pools of servers;
- * we have to live with the fact that a user can
- * authorize itself as any ID that is allowed
- * by the authzTo directive of the "proxyauthzdn".
- */
- /*
- * NOTE: current Proxy Authorization specification
- * and implementation do not allow proxy authorization
- * control to be provided with Bind requests
- */
- /*
- * if no bind took place yet, but the connection is bound
- * and the "proxyauthzdn" is set, then bind as
- * "proxyauthzdn" and explicitly add the proxyAuthz
- * control to every operation with the dn bound
- * to the connection as control value.
- */
-
- /* bind as proxyauthzdn only if no idassert mode
- * is requested, or if the client's identity
- * is authorized */
switch ( li->li_idassert_mode ) {
case LDAP_BACK_IDASSERT_LEGACY:
if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) )
{
- binddn = li->li_idassert_authcDN;
- bindcred = li->li_idassert_passwd;
+ *binddn = li->li_idassert_authcDN;
+ *bindcred = li->li_idassert_passwd;
dobind = 1;
}
}
rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
if ( sendok & LDAP_BACK_SENDERR ) {
send_ldap_result( op, rs );
+ dobind = -1;
}
- LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
} else {
rs->sr_err = LDAP_SUCCESS;
- binddn = slap_empty_bv;
- bindcred = slap_empty_bv;
+ *binddn = slap_empty_bv;
+ *bindcred = slap_empty_bv;
break;
}
if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
if ( sendok & LDAP_BACK_SENDERR ) {
send_ldap_result( op, rs );
+ dobind = -1;
}
- LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
} else {
rs->sr_err = LDAP_SUCCESS;
- binddn = slap_empty_bv;
- bindcred = slap_empty_bv;
+ *binddn = slap_empty_bv;
+ *bindcred = slap_empty_bv;
break;
}
}
}
- binddn = li->li_idassert_authcDN;
- bindcred = li->li_idassert_passwd;
+ *binddn = li->li_idassert_authcDN;
+ *bindcred = li->li_idassert_passwd;
dobind = 1;
break;
}
- if ( dobind && li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
+done:;
+ return dobind;
+}
+
+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 )
+{
+ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+ struct berval ndn;
+ int msgid;
+ int rc;
+
+ if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ ndn = op->o_conn->c_ndn;
+
+ } else {
+ ndn = op->o_ndn;
+ }
+
+ if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
#ifdef HAVE_CYRUS_SASL
void *defaults = NULL;
struct berval authzID = BER_BVNULL;
li->li_idassert_passwd.bv_val,
authzID.bv_val );
- rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, binddn.bv_val,
+ rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, binddn->bv_val,
li->li_idassert_sasl_mech.bv_val, NULL, NULL,
LDAP_SASL_QUIET, lutil_sasl_interact,
defaults );
switch ( li->li_idassert_authmethod ) {
case LDAP_AUTH_NONE:
- LDAP_BACK_CONN_ISBOUND_SET( lc );
- goto done;
+ /* FIXME: do we really need this? */
+ BER_BVSTR( binddn, "" );
+ BER_BVSTR( bindcred, "" );
+ /* fallthru */
case LDAP_AUTH_SIMPLE:
rs->sr_err = ldap_sasl_bind( lc->lc_ld,
- binddn.bv_val, LDAP_SASL_SIMPLE,
- &bindcred, NULL, NULL, &msgid );
+ binddn->bv_val, LDAP_SASL_SIMPLE,
+ bindcred, NULL, NULL, &msgid );
+ rc = ldap_back_op_result( lc, op, rs, msgid,
+ -1, (sendok|LDAP_BACK_BINDING) );
break;
default:
goto done;
}
- rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
if ( rc == LDAP_SUCCESS ) {
+ /* set rebind stuff in case of successful proxyAuthz bind,
+ * so that referral chasing is attempted using the right
+ * identity */
LDAP_BACK_CONN_ISBOUND_SET( lc );
+ ber_bvreplace( &lc->lc_bound_ndn, binddn );
+
+ if ( !BER_BVISNULL( &lc->lc_cred ) ) {
+ memset( lc->lc_cred.bv_val, 0,
+ lc->lc_cred.bv_len );
+ }
+
+ if ( LDAP_BACK_SAVECRED( li ) ) {
+ ber_bvreplace( &lc->lc_cred, bindcred );
+ ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
+
+ } else {
+ lc->lc_cred.bv_len = 0;
+ }
}
done:;
return LDAP_BACK_CONN_ISBOUND( lc );
*/
int
ldap_back_proxy_authz_ctrl(
- ldapconn_t *lc,
+ struct berval *bound_ndn,
+ int version,
+ slap_idassert_t *si,
Operation *op,
SlapReply *rs,
LDAPControl ***pctrls )
{
- ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
- LDAPControl **ctrls = NULL;
- int i = 0,
- mode;
- struct berval assertedID,
- ndn;
+ LDAPControl **ctrls = NULL;
+ int i = 0;
+ slap_idassert_mode_t mode;
+ struct berval assertedID,
+ ndn;
*pctrls = NULL;
rs->sr_err = LDAP_SUCCESS;
+ /* don't proxyAuthz if protocol is not LDAPv3 */
+ switch ( version ) {
+ case LDAP_VERSION3:
+ break;
+
+ case 0:
+ if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
+ break;
+ }
+ /* fall thru */
+
+ default:
+ goto done;
+ }
+
/* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
* but if it is not set this test fails. We need a different
* means to detect if idassert is enabled */
- if ( ( BER_BVISNULL( &li->li_idassert_authcID ) || BER_BVISEMPTY( &li->li_idassert_authcID ) )
- && ( BER_BVISNULL( &li->li_idassert_authcDN ) || BER_BVISEMPTY( &li->li_idassert_authcDN ) ) )
+ if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) )
+ && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) ) )
{
goto done;
}
ndn = op->o_ndn;
}
- if ( li->li_idassert_mode == LDAP_BACK_IDASSERT_LEGACY ) {
+ if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) {
if ( op->o_proxy_authz ) {
/*
* FIXME: we do not want to perform proxyAuthz
goto done;
}
- if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
+ if ( !BER_BVISNULL( bound_ndn ) ) {
goto done;
}
goto done;
}
- if ( BER_BVISNULL( &li->li_idassert_authcDN ) ) {
+ if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) {
goto done;
}
- } else if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
- if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ )
- /* && ( !BER_BVISNULL( &ndn )
- || LDAP_BACK_CONN_ISBOUND( lc ) ) */ )
+ } else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) {
+ if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
{
/* already asserted in SASL via native authz */
- /* NOTE: the test on lc->lc_bound is used to trap
- * native authorization of anonymous users,
- * since in that case ndn is NULL */
goto done;
}
- } else if ( li->li_idassert_authz && !be_isroot( op ) ) {
+ } else if ( si->si_authz && !be_isroot( op ) ) {
int rc;
struct berval authcDN;
} else {
authcDN = ndn;
}
- rc = slap_sasl_matches( op, li->li_idassert_authz,
+ rc = slap_sasl_matches( op, si->si_authz,
&authcDN, & authcDN );
if ( rc != LDAP_SUCCESS ) {
- if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE )
- {
+ if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
/* ndn is not authorized
* to use idassert */
rs->sr_err = rc;
mode = LDAP_BACK_IDASSERT_NOASSERT;
} else {
- mode = li->li_idassert_mode;
+ mode = si->si_mode;
}
switch ( mode ) {
case LDAP_BACK_IDASSERT_OTHERID:
case LDAP_BACK_IDASSERT_OTHERDN:
/* assert idassert DN */
- assertedID = li->li_idassert_authzID;
+ assertedID = si->si_bc.sb_authzId;
break;
default:
}
/* don't idassert the bound DN (ITS#4497) */
- if ( dn_match( &assertedID, &lc->lc_bound_ndn ) ) {
+ if ( dn_match( &assertedID, bound_ndn ) ) {
goto done;
}
ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
ctrls[ 0 ]->ldctl_iscritical = 1;
- switch ( li->li_idassert_mode ) {
+ switch ( si->si_mode ) {
/* already in u:ID or dn:DN form */
case LDAP_BACK_IDASSERT_OTHERID:
case LDAP_BACK_IDASSERT_OTHERDN:
break;
}
+ /* Older versions of <draft-weltman-ldapv3-proxy> required
+ * to encode the value of the authzID (and called it proxyDN);
+ * this hack provides compatibility with those DSAs that
+ * implement it this way */
+ if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
+ struct berval authzID = ctrls[ 0 ]->ldctl_value;
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+ ber_tag_t tag;
+
+ ber_init2( ber, 0, LBER_USE_DER );
+ ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+
+ tag = ber_printf( ber, "O", &authzID );
+ if ( tag == LBER_ERROR ) {
+ rs->sr_err = LDAP_OTHER;
+ goto free_ber;
+ }
+
+ if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) {
+ rs->sr_err = LDAP_OTHER;
+ goto free_ber;
+ }
+
+free_ber:;
+ op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
+ ber_free_buf( ber );
+
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ op->o_tmpfree( ctrls, op->o_tmpmemctx );
+ ctrls = NULL;
+ goto done;
+ }
+
+ } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
+ struct berval authzID = ctrls[ 0 ]->ldctl_value,
+ tmp;
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+ ber_tag_t tag;
+
+ if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) {
+ op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx );
+ op->o_tmpfree( ctrls, op->o_tmpmemctx );
+ ctrls = NULL;
+ rs->sr_err = LDAP_PROTOCOL_ERROR;
+ goto done;
+ }
+
+ tmp = authzID;
+ tmp.bv_val += STRLENOF( "dn:" );
+ tmp.bv_len -= STRLENOF( "dn:" );
+
+ ber_init2( ber, 0, LBER_USE_DER );
+ ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+
+ /* apparently, Mozilla API encodes this
+ * as "SEQUENCE { LDAPDN }" */
+ tag = ber_printf( ber, "{O}", &tmp );
+ if ( tag == LBER_ERROR ) {
+ rs->sr_err = LDAP_OTHER;
+ goto free_ber2;
+ }
+
+ if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) {
+ rs->sr_err = LDAP_OTHER;
+ goto free_ber2;
+ }
+
+free_ber2:;
+ op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
+ ber_free_buf( ber );
+
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ op->o_tmpfree( ctrls, op->o_tmpmemctx );
+ ctrls = NULL;
+ goto done;
+ }
+
+ ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
+ }
+
if ( op->o_ctrls ) {
for ( i = 0; op->o_ctrls[ i ]; i++ ) {
ctrls[ i + 1 ] = op->o_ctrls[ i ];
#include <ac/string.h>
#include <ac/socket.h>
+#include "lutil.h"
#include "slap.h"
#include "back-ldap.h"
-
#include "config.h"
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
static int sc_chainingBehavior;
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
-#define LDAP_CH_NONE ((void *)(0))
-#define LDAP_CH_RES ((void *)(1))
-#define LDAP_CH_ERR ((void *)(2))
-
+typedef enum {
+ LDAP_CH_NONE = 0,
+ LDAP_CH_RES,
+ LDAP_CH_ERR
+} ldap_chain_status_t;
static BackendInfo *lback;
typedef struct ldap_chain_t {
/* tree of configured[/generated?] "uri" info */
ldap_avl_info_t lc_lai;
+ /* max depth in nested referrals chaining */
+ int lc_max_depth;
+
unsigned lc_flags;
#define LDAP_CHAIN_F_NONE (0x00U)
#define LDAP_CHAIN_F_CHAINING (0x01U)
-#define LDAP_CHAIN_F_CACHE_URI (0x10U)
+#define LDAP_CHAIN_F_CACHE_URI (0x02U)
+#define LDAP_CHAIN_F_RETURN_ERR (0x04U)
-#define LDAP_CHAIN_CHAINING( lc ) ( ( (lc)->lc_flags & LDAP_CHAIN_F_CHAINING ) == LDAP_CHAIN_F_CHAINING )
-#define LDAP_CHAIN_CACHE_URI( lc ) ( ( (lc)->lc_flags & LDAP_CHAIN_F_CACHE_URI ) == LDAP_CHAIN_F_CACHE_URI )
+#define LDAP_CHAIN_ISSET(lc, f) ( ( (lc)->lc_flags & (f) ) == (f) )
+#define LDAP_CHAIN_CHAINING( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING )
+#define LDAP_CHAIN_CACHE_URI( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI )
+#define LDAP_CHAIN_RETURN_ERR( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR )
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
LDAPControl lc_chaining_ctrl;
static int ldap_chain_db_init_common( BackendDB *be );
static int ldap_chain_db_init_one( BackendDB *be );
-#define ldap_chain_db_open_one(be) (lback)->bi_db_open( (be) )
+static int ldap_chain_db_open_one( BackendDB *be );
#define ldap_chain_db_close_one(be) (0)
#define ldap_chain_db_destroy_one(be) (lback)->bi_db_destroy( (be) )
+typedef struct ldap_chain_cb_t {
+ ldap_chain_status_t lb_status;
+ ldap_chain_t *lb_lc;
+ BI_op_func *lb_op_f;
+ int lb_depth;
+} ldap_chain_cb_t;
+
+static int
+ldap_chain_op(
+ Operation *op,
+ SlapReply *rs,
+ BI_op_func *op_f,
+ BerVarray ref,
+ int depth );
+
+static int
+ldap_chain_search(
+ Operation *op,
+ SlapReply *rs,
+ BerVarray ref,
+ int depth );
+
+static slap_overinst ldapchain;
+
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
static int
chaining_control_add(
static int
ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
{
+ ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
+
assert( op->o_tag == LDAP_REQ_SEARCH );
/* if in error, don't proceed any further */
- if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
+ if ( lb->lb_status == LDAP_CH_ERR ) {
return 0;
}
} else if ( rs->sr_type == REP_SEARCHREF ) {
/* if we get it here, it means the library was unable
* to chase the referral... */
+ if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
+ rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth );
+ }
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
- if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
+ if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
switch ( get_continuationBehavior( op ) ) {
case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
- op->o_callback->sc_private = LDAP_CH_ERR;
+ lb->lb_status = LDAP_CH_ERR;
return rs->sr_err = LDAP_X_CANNOT_CHAIN;
default:
return SLAP_CB_CONTINUE;
} else if ( rs->sr_type == REP_RESULT ) {
+ if ( rs->sr_err == LDAP_REFERRAL
+ && lb->lb_depth < lb->lb_lc->lc_max_depth
+ && rs->sr_ref != NULL )
+ {
+ rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
+ }
+
/* back-ldap tried to send result */
- op->o_callback->sc_private = LDAP_CH_RES;
+ lb->lb_status = LDAP_CH_RES;
}
return 0;
static int
ldap_chain_cb_response( Operation *op, SlapReply *rs )
{
+ ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
+
/* if in error, don't proceed any further */
- if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
+ if ( lb->lb_status == LDAP_CH_ERR ) {
return 0;
}
if ( rs->sr_type == REP_RESULT ) {
+retry:;
switch ( rs->sr_err ) {
case LDAP_COMPARE_TRUE:
case LDAP_COMPARE_FALSE:
/* fallthru */
case LDAP_SUCCESS:
- op->o_callback->sc_private = LDAP_CH_RES;
+ lb->lb_status = LDAP_CH_RES;
break;
case LDAP_REFERRAL:
+ if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
+ rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
+ goto retry;
+ }
+
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
switch ( get_continuationBehavior( op ) ) {
case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
- op->o_callback->sc_private = LDAP_CH_ERR;
+ lb->lb_status = LDAP_CH_ERR;
return rs->sr_err = LDAP_X_CANNOT_CHAIN;
default:
Operation *op,
SlapReply *rs,
BI_op_func *op_f,
- BerVarray ref )
+ BerVarray ref,
+ int depth )
{
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
ldapinfo_t li = { 0 }, *lip = NULL;
struct berval bvuri[ 2 ] = { { 0 } };
/* NOTE: returned if ref is empty... */
- int rc = LDAP_OTHER;
+ int rc = LDAP_OTHER,
+ first_rc;
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
LDAPControl **ctrls = NULL;
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
li.li_bvuri = bvuri;
+ first_rc = -1;
for ( ; !BER_BVISNULL( ref ); ref++ ) {
- LDAPURLDesc *srv;
- char *save_dn;
+ LDAPURLDesc *srv = NULL;
+ struct berval save_req_dn = op->o_req_dn,
+ save_req_ndn = op->o_req_ndn,
+ dn,
+ pdn = BER_BVNULL,
+ ndn = BER_BVNULL;
int temporary = 0;
/* We're setting the URI of the first referral;
* what if there are more?
-Document: draft-ietf-ldapbis-protocol-27.txt
+Document: RFC 4511
4.1.10. Referral
...
continue;
}
- /* remove DN essentially because later on
- * ldap_initialize() will parse the URL
- * as a comma-separated URL list */
- save_dn = srv->lud_dn;
- srv->lud_dn = "";
- srv->lud_scope = LDAP_SCOPE_DEFAULT;
- li.li_uri = ldap_url_desc2str( srv );
- srv->lud_dn = save_dn;
+ /* normalize DN */
+ ber_str2bv( srv->lud_dn, 0, 0, &dn );
+ rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
+ if ( rc == LDAP_SUCCESS ) {
+ /* remove DN essentially because later on
+ * ldap_initialize() will parse the URL
+ * as a comma-separated URL list */
+ srv->lud_dn = "";
+ srv->lud_scope = LDAP_SCOPE_DEFAULT;
+ li.li_uri = ldap_url_desc2str( srv );
+ srv->lud_dn = dn.bv_val;
+ }
ldap_free_urldesc( srv );
- if ( li.li_uri == NULL ) {
+ if ( rc != LDAP_SUCCESS ) {
/* try next */
rc = LDAP_OTHER;
continue;
}
+ if ( li.li_uri == NULL ) {
+ /* try next */
+ rc = LDAP_OTHER;
+ goto further_cleanup;
+ }
+
+ op->o_req_dn = pdn;
+ op->o_req_ndn = ndn;
+
ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
/* Searches for a ldapinfo in the avl tree */
lip->li_bvuri = bvuri;
rc = ldap_chain_db_open_one( op->o_bd );
if ( rc != 0 ) {
+ lip->li_uri = NULL;
+ lip->li_bvuri = NULL;
(void)ldap_chain_db_destroy_one( op->o_bd );
goto cleanup;
}
}
}
+ lb->lb_op_f = op_f;
+ lb->lb_depth = depth + 1;
+
rc = op_f( op, rs );
+ /* note the first error */
+ if ( first_rc == -1 ) {
+ first_rc = rc;
+ }
+
cleanup:;
ldap_memfree( li.li_uri );
li.li_uri = NULL;
(void)ldap_chain_db_close_one( op->o_bd );
(void)ldap_chain_db_destroy_one( op->o_bd );
}
+
+further_cleanup:;
+ if ( !BER_BVISNULL( &pdn ) ) {
+ op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
+ }
+ op->o_req_dn = save_req_dn;
+
+ if ( !BER_BVISNULL( &ndn ) ) {
+ op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
+ }
+ op->o_req_ndn = save_req_ndn;
if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
break;
(void)chaining_control_remove( op, &ctrls );
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+ if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
+ rc = first_rc;
+ }
+
+ return rc;
+}
+
+static int
+ldap_chain_search(
+ Operation *op,
+ SlapReply *rs,
+ BerVarray ref,
+ int depth )
+
+{
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
+ ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
+ ldapinfo_t li = { 0 }, *lip = NULL;
+ struct berval bvuri[ 2 ] = { { 0 } };
+
+ struct berval odn = op->o_req_dn,
+ ondn = op->o_req_ndn;
+ slap_response *save_response = op->o_callback->sc_response;
+
+ int rc = LDAP_OTHER,
+ first_rc = -1;
+
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+ LDAPControl **ctrls = NULL;
+
+ (void)chaining_control_add( lc, op, &ctrls );
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+
+ rs->sr_type = REP_SEARCH;
+
+ op->o_callback->sc_response = ldap_chain_cb_search_response;
+
+ /* if we parse the URI then by no means
+ * we can cache stuff or reuse connections,
+ * because in back-ldap there's no caching
+ * based on the URI value, which is supposed
+ * to be set once for all (correct?) */
+ li.li_bvuri = bvuri;
+ for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
+ LDAPURLDesc *srv;
+ struct berval save_req_dn = op->o_req_dn,
+ save_req_ndn = op->o_req_ndn,
+ dn,
+ pdn = BER_BVNULL,
+ ndn = BER_BVNULL;
+ int temporary = 0;
+
+ /* parse reference and use
+ * proto://[host][:port]/ only */
+ rc = ldap_url_parse_ext( ref[0].bv_val, &srv );
+ if ( rc != LDAP_URL_SUCCESS ) {
+ /* try next */
+ rs->sr_err = LDAP_OTHER;
+ continue;
+ }
+
+ /* normalize DN */
+ ber_str2bv( srv->lud_dn, 0, 0, &dn );
+ rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
+ if ( rc == LDAP_SUCCESS ) {
+ /* remove DN essentially because later on
+ * ldap_initialize() will parse the URL
+ * as a comma-separated URL list */
+ srv->lud_dn = "";
+ srv->lud_scope = LDAP_SCOPE_DEFAULT;
+ li.li_uri = ldap_url_desc2str( srv );
+ srv->lud_dn = dn.bv_val;
+ }
+ ldap_free_urldesc( srv );
+
+ if ( rc != LDAP_SUCCESS ) {
+ /* try next */
+ rc = LDAP_OTHER;
+ continue;
+ }
+
+ if ( li.li_uri == NULL ) {
+ /* try next */
+ rc = LDAP_OTHER;
+ goto further_cleanup;
+ }
+
+ op->o_req_dn = pdn;
+ op->o_req_ndn = ndn;
+
+ ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
+
+ /* Searches for a ldapinfo in the avl tree */
+ ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
+ lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
+ (caddr_t)&li, ldap_chain_uri_cmp );
+ ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
+
+ if ( lip != NULL ) {
+ op->o_bd->be_private = (void *)lip;
+
+ } else {
+ /* if none is found, create a temporary... */
+ rc = ldap_chain_db_init_one( op->o_bd );
+ if ( rc != 0 ) {
+ goto cleanup;
+ }
+ lip = (ldapinfo_t *)op->o_bd->be_private;
+ lip->li_uri = li.li_uri;
+ lip->li_bvuri = bvuri;
+ rc = ldap_chain_db_open_one( op->o_bd );
+ if ( rc != 0 ) {
+ lip->li_uri = NULL;
+ lip->li_bvuri = NULL;
+ (void)ldap_chain_db_destroy_one( op->o_bd );
+ goto cleanup;
+ }
+
+ if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
+ ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
+ if ( avl_insert( &lc->lc_lai.lai_tree,
+ (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
+ {
+ /* someone just inserted another;
+ * don't bother, use this and then
+ * just free it */
+ temporary = 1;
+ }
+ ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
+
+ } else {
+ temporary = 1;
+ }
+ }
+
+ lb->lb_op_f = lback->bi_op_search;
+ lb->lb_depth = depth + 1;
+
+ /* FIXME: should we also copy filter and scope?
+ * according to RFC3296, no */
+ rc = lback->bi_op_search( op, rs );
+ if ( first_rc == -1 ) {
+ first_rc = rc;
+ }
+
+cleanup:;
+ ldap_memfree( li.li_uri );
+ li.li_uri = NULL;
+
+ op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
+ op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
+
+ if ( temporary ) {
+ lip->li_uri = NULL;
+ lip->li_bvuri = NULL;
+ (void)ldap_chain_db_close_one( op->o_bd );
+ (void)ldap_chain_db_destroy_one( op->o_bd );
+ }
+
+further_cleanup:;
+ if ( !BER_BVISNULL( &pdn ) ) {
+ op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
+ }
+ op->o_req_dn = save_req_dn;
+
+ if ( !BER_BVISNULL( &ndn ) ) {
+ op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
+ }
+ op->o_req_ndn = save_req_ndn;
+
+ if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
+ break;
+ }
+
+ rc = rs->sr_err;
+ }
+
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+ (void)chaining_control_remove( op, &ctrls );
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+
+ op->o_req_dn = odn;
+ op->o_req_ndn = ondn;
+ op->o_callback->sc_response = save_response;
+ rs->sr_type = REP_SEARCHREF;
+ rs->sr_entry = NULL;
+
+ if ( rc != LDAP_SUCCESS ) {
+ /* couldn't chase any of the referrals */
+ if ( first_rc != -1 ) {
+ rc = first_rc;
+
+ } else {
+ rc = SLAP_CB_CONTINUE;
+ }
+ }
+
return rc;
}
ldap_chain_response( Operation *op, SlapReply *rs )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
- void *private = op->o_bd->be_private;
+ ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
+ BackendDB db, *bd = op->o_bd;
+ ldap_chain_cb_t lb = { 0 };
slap_callback *sc = op->o_callback,
sc2 = { 0 };
int rc = 0;
* e) what ssf
*/
+ db = *op->o_bd;
+ op->o_bd = &db;
+
matched = rs->sr_matched;
rs->sr_matched = NULL;
ref = rs->sr_ref;
rs->sr_ref = NULL;
/* we need this to know if back-ldap returned any result */
+ lb.lb_lc = lc;
+ sc2.sc_private = &lb;
sc2.sc_response = ldap_chain_cb_response;
op->o_callback = &sc2;
/* FIXME: can we really get a referral for binds? */
op->o_req_ndn = slap_empty_bv;
op->o_conn = NULL;
- rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref );
+ rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
op->o_req_ndn = rndn;
op->o_conn = conn;
}
break;
case LDAP_REQ_ADD:
- rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );
+ rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
break;
case LDAP_REQ_DELETE:
- rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref );
+ rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
break;
case LDAP_REQ_MODRDN:
- rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref );
+ rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
break;
case LDAP_REQ_MODIFY:
- rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref );
+ rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
break;
case LDAP_REQ_COMPARE:
- rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref );
+ rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
rc = LDAP_SUCCESS;
}
case LDAP_REQ_SEARCH:
if ( rs->sr_type == REP_SEARCHREF ) {
- ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
- ldapinfo_t li = { 0 }, *lip = NULL;
- struct berval bvuri[ 2 ] = { { 0 } };
-
- struct berval *curr = ref,
- odn = op->o_req_dn,
- ondn = op->o_req_ndn;
-
-#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
- LDAPControl **ctrls = NULL;
-
- (void)chaining_control_add( lc, op, &ctrls );
-#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
-
- rs->sr_type = REP_SEARCH;
-
- sc2.sc_response = ldap_chain_cb_search_response;
-
- /* if we parse the URI then by no means
- * we can cache stuff or reuse connections,
- * because in back-ldap there's no caching
- * based on the URI value, which is supposed
- * to be set once for all (correct?) */
- li.li_bvuri = bvuri;
- for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {
- LDAPURLDesc *srv;
- char *save_dn;
- int temporary = 0;
-
- /* parse reference and use
- * proto://[host][:port]/ only */
- rc = ldap_url_parse_ext( curr[0].bv_val, &srv );
- if ( rc != LDAP_URL_SUCCESS ) {
- /* try next */
- rs->sr_err = LDAP_OTHER;
- continue;
- }
-
- /* remove DN essentially because later on
- * ldap_initialize() will parse the URL
- * as a comma-separated URL list */
- save_dn = srv->lud_dn;
- srv->lud_dn = "";
- srv->lud_scope = LDAP_SCOPE_DEFAULT;
- li.li_uri = ldap_url_desc2str( srv );
- if ( li.li_uri != NULL ) {
- ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
- op->o_tmpmemctx );
- ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
- op->o_tmpmemctx );
- }
-
- srv->lud_dn = save_dn;
- ldap_free_urldesc( srv );
-
- if ( li.li_uri == NULL ) {
- /* try next */
- rs->sr_err = LDAP_OTHER;
- continue;
- }
-
- ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
-
- /* Searches for a ldapinfo in the avl tree */
- ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
- lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
- (caddr_t)&li, ldap_chain_uri_cmp );
- ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
-
- if ( lip != NULL ) {
- op->o_bd->be_private = (void *)lip;
-
- } else {
- /* if none is found, create a temporary... */
- rc = ldap_chain_db_init_one( op->o_bd );
- if ( rc != 0 ) {
- goto cleanup;
- }
- lip = (ldapinfo_t *)op->o_bd->be_private;
- lip->li_uri = li.li_uri;
- lip->li_bvuri = bvuri;
- rc = ldap_chain_db_open_one( op->o_bd );
- if ( rc != 0 ) {
- (void)ldap_chain_db_destroy_one( op->o_bd );
- goto cleanup;
- }
-
- if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
- ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
- if ( avl_insert( &lc->lc_lai.lai_tree,
- (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
- {
- /* someone just inserted another;
- * don't bother, use this and then
- * just free it */
- temporary = 1;
- }
- ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
-
- } else {
- temporary = 1;
- }
- }
-
- /* FIXME: should we also copy filter and scope?
- * according to RFC3296, no */
- rc = lback->bi_op_search( op, rs );
-
-cleanup:;
- ldap_memfree( li.li_uri );
- li.li_uri = NULL;
-
- op->o_tmpfree( op->o_req_dn.bv_val,
- op->o_tmpmemctx );
- op->o_tmpfree( op->o_req_ndn.bv_val,
- op->o_tmpmemctx );
-
- if ( temporary ) {
- lip->li_uri = NULL;
- lip->li_bvuri = NULL;
- (void)ldap_chain_db_close_one( op->o_bd );
- (void)ldap_chain_db_destroy_one( op->o_bd );
- }
-
- if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
- break;
- }
-
- rc = rs->sr_err;
- }
-
-#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
- (void)chaining_control_remove( op, &ctrls );
-#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
-
- op->o_req_dn = odn;
- op->o_req_ndn = ondn;
- rs->sr_type = REP_SEARCHREF;
- rs->sr_entry = NULL;
-
- if ( rc != LDAP_SUCCESS ) {
- /* couldn't chase any of the referrals */
- rc = SLAP_CB_CONTINUE;
- }
+ rc = ldap_chain_search( op, rs, ref, 0 );
} else {
/* we might get here before any database actually
* to check limits, to make sure safe defaults
* are in place */
if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
- rc = ldap_chain_op( op, rs, lback->bi_op_search, ref );
+ rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
} else {
rc = SLAP_CB_CONTINUE;
break;
case LDAP_REQ_EXTENDED:
- rc = ldap_chain_op( op, rs, lback->bi_extended, ref );
+ rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
/* FIXME: ldap_back_extended() by design
* doesn't send result; frontend is expected
* to send it... */
send_ldap_extended( op, rs );
rc = LDAP_SUCCESS;
}
- sc2.sc_private = LDAP_CH_RES;
+ lb.lb_status = LDAP_CH_RES;
break;
default:
case LDAP_SUCCESS:
case LDAP_REFERRAL:
/* slapd-ldap sent response */
- if ( !op->o_abandon && sc2.sc_private != LDAP_CH_RES ) {
+ if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
/* FIXME: should we send response? */
Debug( LDAP_DEBUG_ANY,
"%s: ldap_chain_response: "
default:
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
- if ( sc2.sc_private == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
+ if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
goto cannot_chain;
}
default:
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
- rc = SLAP_CB_CONTINUE;
- rs->sr_err = sr_err;
- rs->sr_type = sr_type;
- rs->sr_matched = matched;
- rs->sr_ref = ref;
+ if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
+ rs->sr_err = rc;
+ rs->sr_type = sr_type;
+
+ } else {
+ rc = SLAP_CB_CONTINUE;
+ rs->sr_err = sr_err;
+ rs->sr_type = sr_type;
+ rs->sr_matched = matched;
+ rs->sr_ref = ref;
+ }
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
break;
}
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
}
- if ( sc2.sc_private == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
+ if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
op->o_callback = NULL;
rc = rs->sr_err = slap_map_api2result( rs );
send_ldap_result( op, rs );
rs->sr_type = sr_type;
rs->sr_matched = matched;
rs->sr_ref = ref;
- op->o_bd->be_private = private;
+ op->o_bd = bd;
op->o_callback = sc;
op->o_ndn = ndn;
enum {
CH_CHAINING = 1,
- CH_CACHE_URI = 2,
+ CH_CACHE_URI,
+ CH_MAX_DEPTH,
+ CH_RETURN_ERR,
CH_LAST
};
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
{ "chain-cache-uri", "TRUE/FALSE",
2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
- "( OLcfgOvAt:3.2 NAME 'olcCacheURI' "
+ "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
"DESC 'Enables caching of URIs not present in configuration' "
"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
+ { "chain-max-depth", "args",
+ 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
+ "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
+ "DESC 'max referral depth' "
+ "SYNTAX OMsInteger "
+ "EQUALITY integerMatch "
+ "SINGLE-VALUE )", NULL, NULL },
+ { "chain-return-error", "TRUE/FALSE",
+ 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
+ "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
+ "DESC 'Errors are returned instead of the original referral' "
+ "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
"olcChainingBehavior $ "
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
- "olcCacheURI "
+ "olcChainCacheURI $ "
+ "olcChainMaxReferralDepth $ "
+ "olcChainReturnError "
") )",
Cft_Overlay, chaincfg, NULL, chain_cfadd },
{ "( OLcfgOvOc:3.2 "
if ( lc->lc_common_li == NULL ) {
lc->lc_common_li = li;
- } else if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
- ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
- {
- Debug( LDAP_DEBUG_ANY, "slapd-chain: "
- "database \"%s\" insert failed.\n",
- e->e_name.bv_val, 0, 0 );
- rc = LDAP_CONSTRAINT_VIOLATION;
- goto done;
+ } else {
+ li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
+ value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
+ if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
+ ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
+ {
+ Debug( LDAP_DEBUG_ANY, "slapd-chain: "
+ "database \"%s\" insert failed.\n",
+ e->e_name.bv_val, 0, 0 );
+ rc = LDAP_CONSTRAINT_VIOLATION;
+ goto done;
+ }
}
done:;
c->value_int = LDAP_CHAIN_CACHE_URI( lc );
break;
+ case CH_MAX_DEPTH:
+ c->value_int = lc->lc_max_depth;
+ break;
+
+ case CH_RETURN_ERR:
+ c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
+ break;
+
default:
assert( 0 );
rc = 1;
lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
break;
+ case CH_MAX_DEPTH:
+ c->value_int = 0;
+ break;
+
+ case CH_RETURN_ERR:
+ lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
+ break;
+
default:
return 1;
}
}
break;
+ case CH_MAX_DEPTH:
+ if ( c->value_int < 0 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "<%s> invalid max referral depth %d",
+ c->argv[0], c->value_int );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
+ c->log, c->msg, 0 );
+ rc = 1;
+ break;
+ }
+ lc->lc_max_depth = c->value_int;
+
+ case CH_RETURN_ERR:
+ if ( c->value_int ) {
+ lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
+ } else {
+ lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
+ }
+ break;
+
default:
assert( 0 );
return 1;
ldap_chain_t *lc = NULL;
if ( lback == NULL ) {
+ static BackendInfo lback2;
+
lback = backend_info( "ldap" );
if ( lback == NULL ) {
return 1;
}
+
+ lback2 = *lback;
+ lback2.bi_type = ldapchain.on_bi.bi_type;
+ lback = &lback2;
}
lc = ch_malloc( sizeof( ldap_chain_t ) );
return 1;
}
memset( lc, 0, sizeof( ldap_chain_t ) );
+ lc->lc_max_depth = 1;
ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
on->on_bi.bi_private = (void *)lc;
{
slap_overinst *on = (slap_overinst *) be->bd_info;
ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
+ int rc = 0;
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
- int rc = 0;
-
rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
if ( rc != 0 ) {
return rc;
be->be_private = be_private;
}
- return ldap_chain_db_func( be, db_open );
+ /* filter out and restore monitoring */
+ rc = ldap_chain_db_func( be, db_open );
+
+ return rc;
}
static int
BackendDB *be )
{
BackendInfo *bi = be->bd_info;
- int t;
+ ldapinfo_t *li;
+ int rc;
be->bd_info = lback;
be->be_private = NULL;
- t = lback->bi_db_init( be );
- if ( t != 0 ) {
- return t;
+ rc = lback->bi_db_init( be );
+ if ( rc != 0 ) {
+ return rc;
}
+ li = (ldapinfo_t *)be->be_private;
+
be->bd_info = bi;
return 0;
BackendInfo *bi = be->bd_info;
ldapinfo_t *li;
- int t;
+ slap_op_t t;
be->bd_info = lback;
be->be_private = NULL;
li->li_nretries = lc->lc_common_li->li_nretries;
li->li_flags = lc->lc_common_li->li_flags;
li->li_version = lc->lc_common_li->li_version;
- for ( t = 0; t < LDAP_BACK_OP_LAST; t++ ) {
+ for ( t = 0; t < SLAP_OP_LAST; t++ ) {
li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
}
be->bd_info = bi;
return 0;
}
+static int
+ldap_chain_db_open_one(
+ BackendDB *be )
+{
+ return lback->bi_db_open( be );
+}
+
typedef struct ldap_chain_conn_apply_t {
BackendDB *be;
Connection *conn;
Operation *op,
SlapReply *rs )
{
- ldapconn_t *lc;
- ber_int_t msgid;
- int do_retry = 1;
- LDAPControl **ctrls = NULL;
- int rc = LDAP_SUCCESS;
+ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ ldapconn_t *lc = NULL;
+ ber_int_t msgid;
+ ldap_back_send_t retrying = LDAP_BACK_RETRYING;
+ LDAPControl **ctrls = NULL;
+ int rc = LDAP_SUCCESS;
+
+ if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
lc = NULL;
goto cleanup;
}
retry:
ctrls = op->o_ctrls;
- rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
+ rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn,
+ li->li_version, &li->li_idassert, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
goto cleanup;
op->orc_ava->aa_desc->ad_cname.bv_val,
&op->orc_ava->aa_value,
ctrls, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDRESULT );
- if ( rc == LDAP_UNAVAILABLE && do_retry ) {
- do_retry = 0;
+ rc = ldap_back_op_result( lc, op, rs, msgid,
+ li->li_timeout[ SLAP_OP_COMPARE ],
+ ( LDAP_BACK_SENDRESULT | retrying ) );
+ if ( rc == LDAP_UNAVAILABLE && retrying ) {
+ retrying &= ~LDAP_BACK_RETRYING;
if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
/* if the identity changed, there might be need to re-authz */
(void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
LDAP_BACK_CFG_CONN_TTL,
LDAP_BACK_CFG_NETWORK_TIMEOUT,
LDAP_BACK_CFG_VERSION,
+ LDAP_BACK_CFG_SINGLECONN,
+ LDAP_BACK_CFG_USETEMP,
+ LDAP_BACK_CFG_CONNPOOLMAX,
+ LDAP_BACK_CFG_CANCEL,
+ LDAP_BACK_CFG_QUARANTINE,
LDAP_BACK_CFG_REWRITE,
LDAP_BACK_CFG_LAST
"SYNTAX OMsInteger "
"SINGLE-VALUE )",
NULL, NULL },
+ { "single-conn", "TRUE/FALSE", 2, 0, 0,
+ ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_SINGLECONN,
+ ldap_back_cf_gen, "( OLcfgDbAt:3.19 "
+ "NAME 'olcDbSingleConn' "
+ "DESC 'cache a single connection per identity' "
+ "SYNTAX OMsBoolean "
+ "SINGLE-VALUE )",
+ NULL, NULL },
+ { "cancel", "ABANDON|ignore|exop", 2, 0, 0,
+ ARG_MAGIC|LDAP_BACK_CFG_CANCEL,
+ ldap_back_cf_gen, "( OLcfgDbAt:3.20 "
+ "NAME 'olcDbCancel' "
+ "DESC 'abandon/ignore/exop operations when appropriate' "
+ "SYNTAX OMsDirectoryString "
+ "SINGLE-VALUE )",
+ NULL, NULL },
+ { "quarantine", "retrylist", 2, 0, 0,
+ ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE,
+ ldap_back_cf_gen, "( OLcfgDbAt:3.21 "
+ "NAME 'olcDbQuarantine' "
+ "DESC 'Quarantine database if connection fails and retry according to rule' "
+ "SYNTAX OMsDirectoryString "
+ "SINGLE-VALUE )",
+ NULL, NULL },
+ { "use-temporary-conn", "TRUE/FALSE", 2, 0, 0,
+ ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_USETEMP,
+ ldap_back_cf_gen, "( OLcfgDbAt:3.22 "
+ "NAME 'olcDbUseTemporaryConn' "
+ "DESC 'Use temporary connections if the cached one is busy' "
+ "SYNTAX OMsBoolean "
+ "SINGLE-VALUE )",
+ NULL, NULL },
+ { "conn-pool-max", "<n>", 2, 0, 0,
+ ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX,
+ ldap_back_cf_gen, "( OLcfgDbAt:3.23 "
+ "NAME 'olcDbConnectionPoolMax' "
+ "DESC 'Max size of privileged connections pool' "
+ "SYNTAX OMsInteger "
+ "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 },
"NAME 'olcLDAPConfig' "
"DESC 'LDAP backend configuration' "
"SUP olcDatabaseConfig "
- "MUST olcDbURI "
- "MAY ( olcDbStartTLS "
+ "MAY ( olcDbURI "
+ "$ olcDbStartTLS "
"$ olcDbACLAuthcDn "
"$ olcDbACLPasswd "
"$ olcDbACLBind "
"$ olcDbProxyWhoAmI "
"$ olcDbTimeout "
"$ olcDbIdleTimeout "
+ "$ olcDbSingleConn "
+ "$ olcDbCancel "
+ "$ olcDbQuarantine "
+ "$ olcDbUseTemporaryConn "
+ "$ olcDbConnectionPoolMax "
") )",
Cft_Database, ldapcfg},
{ NULL, 0, NULL }
};
static slap_verbmasks t_f_mode[] = {
- { BER_BVC( "yes" ), LDAP_BACK_F_SUPPORT_T_F },
- { BER_BVC( "discover" ), LDAP_BACK_F_SUPPORT_T_F_DISCOVER },
+ { BER_BVC( "yes" ), LDAP_BACK_F_T_F },
+ { BER_BVC( "discover" ), LDAP_BACK_F_T_F_DISCOVER },
{ BER_BVC( "no" ), LDAP_BACK_F_NONE },
{ BER_BVNULL, 0 }
};
+static slap_verbmasks cancel_mode[] = {
+#if 0 /* needs ldap_int_discard(), 2.4 */
+ { BER_BVC( "ignore" ), LDAP_BACK_F_CANCEL_IGNORE },
+#endif
+ { BER_BVC( "exop" ), LDAP_BACK_F_CANCEL_EXOP },
+ { BER_BVC( "exop-discover" ), LDAP_BACK_F_CANCEL_EXOP_DISCOVER },
+ { BER_BVC( "abandon" ), LDAP_BACK_F_CANCEL_ABANDON },
+ { BER_BVNULL, 0 }
+};
+
+/* see enum in slap.h */
static slap_cf_aux_table timeout_table[] = {
- { BER_BVC("add="), 0 * sizeof( time_t ), 'u', 0, NULL },
- { BER_BVC("delete="), 1 * sizeof( time_t ), 'u', 0, NULL },
- { BER_BVC("modify="), 2 * sizeof( time_t ), 'u', 0, NULL },
- { BER_BVC("modrdn="), 3 * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("bind="), SLAP_OP_BIND * sizeof( time_t ), 'u', 0, NULL },
+ /* unbind makes no sense */
+ { BER_BVC("add="), SLAP_OP_ADD * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("delete="), SLAP_OP_DELETE * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("modrdn="), SLAP_OP_MODRDN * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("modify="), SLAP_OP_MODIFY * sizeof( time_t ), 'u', 0, NULL },
+ { BER_BVC("compare="), SLAP_OP_COMPARE * sizeof( time_t ), 'u', 0, NULL },
+#if 0 /* uses timelimit instead */
+ { BER_BVC("search="), SLAP_OP_SEARCH * sizeof( time_t ), 'u', 0, NULL },
+#endif
+ /* abandon makes little sense */
+#if 0 /* not implemented yet */
+ { BER_BVC("extended="), SLAP_OP_EXTENDED * sizeof( time_t ), 'u', 0, NULL },
+#endif
{ BER_BVNULL, 0, 0, 0, NULL }
};
+int
+slap_retry_info_parse(
+ char *in,
+ slap_retry_info_t *ri,
+ char *buf,
+ ber_len_t buflen )
+{
+ char **retrylist = NULL;
+ int rc = 0;
+ int i;
+
+ slap_str2clist( &retrylist, in, " ;" );
+ if ( retrylist == NULL ) {
+ return 1;
+ }
+
+ for ( i = 0; retrylist[ i ] != NULL; i++ )
+ /* count */ ;
+
+ ri->ri_interval = ch_calloc( sizeof( time_t ), i + 1 );
+ ri->ri_num = ch_calloc( sizeof( int ), i + 1 );
+
+ for ( i = 0; retrylist[ i ] != NULL; i++ ) {
+ unsigned long t;
+ char *sep = strchr( retrylist[ i ], ',' );
+
+ if ( sep == NULL ) {
+ snprintf( buf, buflen,
+ "missing comma in retry pattern #%d \"%s\"",
+ i, retrylist[ i ] );
+ rc = 1;
+ goto done;
+ }
+
+ *sep++ = '\0';
+
+ if ( lutil_parse_time( retrylist[ i ], &t ) ) {
+ snprintf( buf, buflen,
+ "unable to parse interval #%d \"%s\"",
+ i, retrylist[ i ] );
+ rc = 1;
+ goto done;
+ }
+ ri->ri_interval[ i ] = (time_t)t;
+
+ if ( strcmp( sep, "+" ) == 0 ) {
+ if ( retrylist[ i + 1 ] != NULL ) {
+ snprintf( buf, buflen,
+ "extra cruft after retry pattern "
+ "#%d \"%s,+\" with \"forever\" mark",
+ i, retrylist[ i ] );
+ rc = 1;
+ goto done;
+ }
+ ri->ri_num[ i ] = SLAP_RETRYNUM_FOREVER;
+
+ } else if ( lutil_atoi( &ri->ri_num[ i ], sep ) ) {
+ snprintf( buf, buflen,
+ "unable to parse retry num #%d \"%s\"",
+ i, sep );
+ rc = 1;
+ goto done;
+ }
+ }
+
+ ri->ri_num[ i ] = SLAP_RETRYNUM_TAIL;
+
+ ri->ri_idx = 0;
+ ri->ri_count = 0;
+ ri->ri_last = (time_t)(-1);
+
+done:;
+ ldap_charray_free( retrylist );
+
+ if ( rc ) {
+ slap_retry_info_destroy( ri );
+ }
+
+ return rc;
+}
+
+int
+slap_retry_info_unparse(
+ slap_retry_info_t *ri,
+ struct berval *bvout )
+{
+ int i;
+ char buf[ BUFSIZ * 2 ],
+ *ptr = buf;
+ struct berval bv = BER_BVNULL;
+
+ assert( ri != NULL );
+ assert( bvout != NULL );
+
+ BER_BVZERO( bvout );
+
+#define WHATSLEFT ( sizeof( buf ) - ( ptr - buf ) )
+
+ for ( i = 0; ri->ri_num[ i ] != SLAP_RETRYNUM_TAIL; i++ ) {
+ if ( i > 0 ) {
+ if ( WHATSLEFT <= 1 ) {
+ return 1;
+ }
+ *ptr++ = ';';
+ }
+
+ if ( lutil_unparse_time( ptr, WHATSLEFT, (long)ri->ri_interval[i] ) ) {
+ return 1;
+ }
+ ptr += strlen( ptr );
+
+ if ( WHATSLEFT <= 1 ) {
+ return 1;
+ }
+ *ptr++ = ',';
+
+ if ( ri->ri_num[i] == SLAP_RETRYNUM_FOREVER ) {
+ if ( WHATSLEFT <= 1 ) {
+ return 1;
+ }
+ *ptr++ = '+';
+
+ } else {
+ ptr += snprintf( ptr, WHATSLEFT, "%d", ri->ri_num[i] );
+ if ( WHATSLEFT <= 0 ) {
+ return 1;
+ }
+ }
+ }
+
+ bv.bv_val = buf;
+ bv.bv_len = ptr - buf;
+
+ ber_dupbv( bvout, &bv );
+
+ return 0;
+}
+
+void
+slap_retry_info_destroy(
+ slap_retry_info_t *ri )
+{
+ assert( ri != NULL );
+
+ assert( ri->ri_interval != NULL );
+ ch_free( ri->ri_interval );
+ ri->ri_interval = NULL;
+
+ assert( ri->ri_num != NULL );
+ ch_free( ri->ri_num );
+ ri->ri_num = NULL;
+}
+
+static int
+slap_idassert_authzfrom_parse( ConfigArgs *c, slap_idassert_t *si )
+{
+ struct berval bv;
+
+ 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;
+ }
+
+#ifdef SLAP_AUTHZ_SYNTAX
+ {
+ 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;
+ }
+ }
+#else /* !SLAP_AUTHZ_SYNTAX */
+ ber_str2bv( c->argv[ 1 ], 0, 1, &bv );
+#endif /* !SLAP_AUTHZ_SYNTAX */
+
+ ber_bvarray_add( &si->si_authz, &bv );
+
+ return 0;
+}
+
+static int
+slap_idassert_parse( ConfigArgs *c, slap_idassert_t *si )
+{
+ int i;
+
+ for ( i = 1; i < c->argc; i++ ) {
+ if ( strncasecmp( c->argv[ i ], "mode=", STRLENOF( "mode=" ) ) == 0 ) {
+ char *argvi = c->argv[ i ] + STRLENOF( "mode=" );
+ int j;
+
+ j = verb_to_mask( argvi, idassert_mode );
+ if ( BER_BVISNULL( &idassert_mode[ j ].word ) ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "unknown mode \"%s\"",
+ argvi );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ si->si_mode = idassert_mode[ j ].mask;
+
+ } else if ( strncasecmp( c->argv[ i ], "authz=", STRLENOF( "authz=" ) ) == 0 ) {
+ char *argvi = c->argv[ i ] + STRLENOF( "authz=" );
+
+ if ( strcasecmp( argvi, "native" ) == 0 ) {
+ if ( si->si_bc.sb_method != LDAP_AUTH_SASL ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "authz=\"native\" incompatible "
+ "with auth method" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+ si->si_flags |= LDAP_BACK_AUTH_NATIVE_AUTHZ;
+
+ } else if ( strcasecmp( argvi, "proxyAuthz" ) == 0 ) {
+ si->si_flags &= ~LDAP_BACK_AUTH_NATIVE_AUTHZ;
+
+ } else {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "unknown authz \"%s\"",
+ argvi );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ } else if ( strncasecmp( c->argv[ i ], "flags=", STRLENOF( "flags=" ) ) == 0 ) {
+ char *argvi = c->argv[ i ] + STRLENOF( "flags=" );
+ char **flags = ldap_str2charray( argvi, "," );
+ int j, err = 0;
+
+ if ( flags == NULL ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "unable to parse flags \"%s\"",
+ argvi );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ for ( j = 0; flags[ j ] != NULL; j++ ) {
+
+ if ( strcasecmp( flags[ j ], "override" ) == 0 ) {
+ si->si_flags |= LDAP_BACK_AUTH_OVERRIDE;
+
+ } else if ( strcasecmp( flags[ j ], "prescriptive" ) == 0 ) {
+ si->si_flags |= LDAP_BACK_AUTH_PRESCRIPTIVE;
+
+ } else if ( strcasecmp( flags[ j ], "non-prescriptive" ) == 0 ) {
+ si->si_flags &= ( ~LDAP_BACK_AUTH_PRESCRIPTIVE );
+
+ } else if ( strcasecmp( flags[ j ], "obsolete-proxy-authz" ) == 0 ) {
+ if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: \"obsolete-proxy-authz\" flag "
+ "in \"idassert-mode <args>\" "
+ "incompatible with previously issued \"obsolete-encoding-workaround\" flag.\n",
+ c->log, 0, 0 );
+ err = 1;
+ break;
+
+ } else {
+ si->si_flags |= LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ;
+ }
+
+ } else if ( strcasecmp( flags[ j ], "obsolete-encoding-workaround" ) == 0 ) {
+ if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: \"obsolete-encoding-workaround\" flag "
+ "in \"idassert-mode <args>\" "
+ "incompatible with previously issued \"obsolete-proxy-authz\" flag.\n",
+ c->log, 0, 0 );
+ err = 1;
+ break;
+
+ } else {
+ si->si_flags |= LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND;
+ }
+
+ } else {
+ snprintf( c->msg, sizeof( c->msg ),
+ "\"idassert-bind <args>\": "
+ "unknown flag \"%s\"",
+ flags[ j ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ err = 1;
+ break;
+ }
+ }
+
+ ldap_charray_free( flags );
+ if ( err ) {
+ return 1;
+ }
+
+ } else if ( bindconf_parse( c->argv[ i ], &si->si_bc ) ) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* NOTE: temporary, until back-meta is ported to back-config */
+int
+slap_idassert_authzfrom_parse_cf( const char *fname, int lineno, const char *arg, slap_idassert_t *si )
+{
+ ConfigArgs c = { 0 };
+ char *argv[ 3 ];
+
+ snprintf( c.log, sizeof( c.log ), "%s: line %d", fname, lineno );
+ c.argc = 2;
+ c.argv = argv;
+ argv[ 0 ] = "idassert-authzFrom";
+ argv[ 1 ] = (char *)arg;
+ argv[ 2 ] = NULL;
+
+ return slap_idassert_authzfrom_parse( &c, si );
+}
+
+int
+slap_idassert_parse_cf( const char *fname, int lineno, int argc, char *argv[], slap_idassert_t *si )
+{
+ ConfigArgs c = { 0 };
+
+ snprintf( c.log, sizeof( c.log ), "%s: line %d", fname, lineno );
+ c.argc = argc;
+ c.argv = argv;
+
+ return slap_idassert_parse( &c, si );
+}
+
static int
ldap_back_cf_gen( ConfigArgs *c )
{
ldapinfo_t *li = ( ldapinfo_t * )c->be->be_private;
- int rc;
+ int rc = 0;
int i;
if ( c->op == SLAP_CONFIG_EMIT ) {
struct berval bv = BER_BVNULL;
- rc = 0;
if ( li == NULL ) {
return 1;
switch( c->type ) {
case LDAP_BACK_CFG_URI:
if ( li->li_uri != NULL ) {
- struct berval bv;
+ struct berval bv, bv2;
ber_str2bv( li->li_uri, 0, 0, &bv );
- value_add_one( &c->rvalue_vals, &bv );
+ bv2.bv_len = bv.bv_len + STRLENOF( "\"\"" );
+ bv2.bv_val = ch_malloc( bv2.bv_len + 1 );
+ snprintf( bv2.bv_val, bv2.bv_len + 1,
+ "\"%s\"", bv.bv_val );
+ ber_bvarray_add( &c->rvalue_vals, &bv2 );
} else {
rc = 1;
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;
}
(void)lutil_strcopy( ptr, "authz=native" );
}
- len = bv.bv_len + STRLENOF( "flags=non-prescriptive,override" );
+ len = bv.bv_len + STRLENOF( "flags=non-prescriptive,override,obsolete-encoding-workaround" );
/* flags */
if ( !BER_BVISEMPTY( &bv ) ) {
len += STRLENOF( " " );
ptr = lutil_strcopy( ptr, ",override" );
}
+ if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
+ ptr = lutil_strcopy( ptr, ",obsolete-proxy-authz" );
+
+ } else if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
+ ptr = lutil_strcopy( ptr, ",obsolete-encoding-workaround" );
+ }
+
bv.bv_len = ( ptr - bv.bv_val );
/* end-of-flags */
}
- bindconf_unparse( &li->li_idassert, &bc );
+ bindconf_unparse( &li->li_idassert.si_bc, &bc );
if ( !BER_BVISNULL( &bv ) ) {
ber_len_t len = bv.bv_len + bc.bv_len;
break;
case LDAP_BACK_CFG_T_F:
- enum_to_verb( t_f_mode, (li->li_flags & LDAP_BACK_F_SUPPORT_T_F_MASK), &bv );
+ enum_to_verb( t_f_mode, (li->li_flags & LDAP_BACK_F_T_F_MASK2), &bv );
if ( BER_BVISNULL( &bv ) ) {
/* there's something wrong... */
assert( 0 );
case LDAP_BACK_CFG_TIMEOUT:
BER_BVZERO( &bv );
- for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) {
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
if ( li->li_timeout[ i ] != 0 ) {
break;
}
}
- if ( i == LDAP_BACK_OP_LAST ) {
+ if ( i == SLAP_OP_LAST ) {
return 1;
}
c->value_int = li->li_version;
break;
+ case LDAP_BACK_CFG_SINGLECONN:
+ 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_CONNPOOLMAX:
+ c->value_int = li->li_conn_priv_max;
+ break;
+
+ case LDAP_BACK_CFG_CANCEL: {
+ slap_mask_t mask = LDAP_BACK_F_CANCEL_MASK2;
+
+ if ( LDAP_BACK_CANCEL_DISCOVER( li ) ) {
+ mask &= ~LDAP_BACK_F_CANCEL_EXOP;
+ }
+ enum_to_verb( cancel_mode, (li->li_flags & mask), &bv );
+ if ( BER_BVISNULL( &bv ) ) {
+ /* there's something wrong... */
+ assert( 0 );
+ rc = 1;
+
+ } else {
+ value_add_one( &c->rvalue_vals, &bv );
+ }
+ } break;
+
+ case LDAP_BACK_CFG_QUARANTINE:
+ if ( !LDAP_BACK_QUARANTINE( li ) ) {
+ rc = 1;
+ break;
+ }
+
+ rc = slap_retry_info_unparse( &li->li_quarantine, &bv );
+ if ( rc == 0 ) {
+ ber_bvarray_add( &c->rvalue_vals, &bv );
+ }
+ break;
+
default:
/* FIXME: we need to handle all... */
assert( 0 );
return rc;
} else if ( c->op == LDAP_MOD_DELETE ) {
- rc = 0;
switch( c->type ) {
case LDAP_BACK_CFG_URI:
if ( li->li_uri != NULL ) {
break;
case LDAP_BACK_CFG_IDASSERT_BIND:
- bindconf_free( &li->li_idassert );
+ bindconf_free( &li->li_idassert.si_bc );
break;
case LDAP_BACK_CFG_REBIND:
case LDAP_BACK_CFG_CHASE:
case LDAP_BACK_CFG_T_F:
case LDAP_BACK_CFG_WHOAMI:
+ case LDAP_BACK_CFG_CANCEL:
rc = 1;
break;
case LDAP_BACK_CFG_TIMEOUT:
- for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) {
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
li->li_timeout[ i ] = 0;
}
break;
li->li_version = 0;
break;
+ case LDAP_BACK_CFG_SINGLECONN:
+ 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_CONNPOOLMAX:
+ li->li_conn_priv_max = LDAP_BACK_CONN_PRIV_MIN;
+ break;
+
+ case LDAP_BACK_CFG_QUARANTINE:
+ if ( !LDAP_BACK_QUARANTINE( li ) ) {
+ break;
+ }
+
+ slap_retry_info_destroy( &li->li_quarantine );
+ ldap_pvt_thread_mutex_destroy( &li->li_quarantine_mutex );
+ li->li_isquarantined = 0;
+ break;
+
default:
/* FIXME: we need to handle all... */
assert( 0 );
} else if ( strcasecmp( c->argv[ i ], "non-prescriptive" ) == 0 ) {
li->li_idassert_flags &= ( ~LDAP_BACK_AUTH_PRESCRIPTIVE );
+ } else if ( strcasecmp( c->argv[ i ], "obsolete-proxy-authz" ) == 0 ) {
+ if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"obsolete-proxy-authz\" flag "
+ "in \"idassert-mode <args>\" "
+ "incompatible with previously issued \"obsolete-encoding-workaround\" flag.\n",
+ c->fname, c->lineno, 0 );
+ return 1;
+ }
+ li->li_idassert_flags |= LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ;
+
+ } else if ( strcasecmp( c->argv[ i ], "obsolete-encoding-workaround" ) == 0 ) {
+ if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"obsolete-encoding-workaround\" flag "
+ "in \"idassert-mode <args>\" "
+ "incompatible with previously issued \"obsolete-proxy-authz\" flag.\n",
+ c->fname, c->lineno, 0 );
+ return 1;
+ }
+ li->li_idassert_flags |= LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND;
+
} else {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: unknown flag #%d "
ber_str2bv( c->argv[ 1 ], 0, 1, &li->li_idassert_passwd );
break;
- case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: {
- struct berval bv;
-#ifdef SLAP_AUTHZ_SYNTAX
- 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;
- }
-#else /* !SLAP_AUTHZ_SYNTAX */
- ber_str2bv( c->argv[ 1 ], 0, 1, &bv );
-#endif /* !SLAP_AUTHZ_SYNTAX */
- ber_bvarray_add( &li->li_idassert_authz, &bv );
- } break;
+ case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
+ rc = slap_idassert_authzfrom_parse( c, &li->li_idassert );
+ break;
case LDAP_BACK_CFG_IDASSERT_METHOD:
/* no longer supported */
return 1;
case LDAP_BACK_CFG_IDASSERT_BIND:
- for ( i = 1; i < c->argc; i++ ) {
- if ( strncasecmp( c->argv[ i ], "mode=", STRLENOF( "mode=" ) ) == 0 ) {
- char *argvi = c->argv[ i ] + STRLENOF( "mode=" );
- int j;
-
- j = verb_to_mask( argvi, idassert_mode );
- if ( BER_BVISNULL( &idassert_mode[ j ].word ) ) {
- snprintf( c->msg, sizeof( c->msg ),
- "\"idassert-bind <args>\": "
- "unknown mode \"%s\"",
- argvi );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
- return 1;
- }
-
- li->li_idassert_mode = idassert_mode[ j ].mask;
-
- } else if ( strncasecmp( c->argv[ i ], "authz=", STRLENOF( "authz=" ) ) == 0 ) {
- char *argvi = c->argv[ i ] + STRLENOF( "authz=" );
-
- if ( strcasecmp( argvi, "native" ) == 0 ) {
- if ( li->li_idassert_authmethod != LDAP_AUTH_SASL ) {
- snprintf( c->msg, sizeof( c->msg ),
- "\"idassert-bind <args>\": "
- "authz=\"native\" incompatible "
- "with auth method" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
- return 1;
- }
- li->li_idassert_flags |= LDAP_BACK_AUTH_NATIVE_AUTHZ;
-
- } else if ( strcasecmp( argvi, "proxyAuthz" ) == 0 ) {
- li->li_idassert_flags &= ~LDAP_BACK_AUTH_NATIVE_AUTHZ;
-
- } else {
- snprintf( c->msg, sizeof( c->msg ),
- "\"idassert-bind <args>\": "
- "unknown authz \"%s\"",
- argvi );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
- return 1;
- }
-
- } else if ( strncasecmp( c->argv[ i ], "flags=", STRLENOF( "flags=" ) ) == 0 ) {
- char *argvi = c->argv[ i ] + STRLENOF( "flags=" );
- char **flags = ldap_str2charray( argvi, "," );
- int j;
-
- if ( flags == NULL ) {
- snprintf( c->msg, sizeof( c->msg ),
- "\"idassert-bind <args>\": "
- "unable to parse flags \"%s\"",
- argvi );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
- return 1;
- }
-
- for ( j = 0; flags[ j ] != NULL; j++ ) {
- if ( strcasecmp( flags[ j ], "override" ) == 0 ) {
- li->li_idassert_flags |= LDAP_BACK_AUTH_OVERRIDE;
-
- } else if ( strcasecmp( flags[ j ], "prescriptive" ) == 0 ) {
- li->li_idassert_flags |= LDAP_BACK_AUTH_PRESCRIPTIVE;
-
- } else if ( strcasecmp( flags[ j ], "non-prescriptive" ) == 0 ) {
- li->li_idassert_flags &= ( ~LDAP_BACK_AUTH_PRESCRIPTIVE );
-
- } else {
- snprintf( c->msg, sizeof( c->msg ),
- "\"idassert-bind <args>\": "
- "unknown flag \"%s\"",
- flags[ j ] );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
- ldap_charray_free( flags );
- return 1;
- }
- }
-
- ldap_charray_free( flags );
-
- } else if ( bindconf_parse( c->argv[ i ], &li->li_idassert ) ) {
- return 1;
- }
- }
+ rc = slap_idassert_parse( c, &li->li_idassert );
break;
case LDAP_BACK_CFG_REBIND:
}
break;
- case LDAP_BACK_CFG_T_F:
+ case LDAP_BACK_CFG_T_F: {
+ slap_mask_t mask;
+
i = verb_to_mask( c->argv[1], t_f_mode );
if ( BER_BVISNULL( &t_f_mode[i].word ) ) {
return 1;
}
- li->li_flags &= ~LDAP_BACK_F_SUPPORT_T_F_MASK;
- li->li_flags |= t_f_mode[i].mask;
- break;
+
+ mask = t_f_mode[i].mask;
+
+ if ( LDAP_BACK_ISOPEN( li )
+ && mask == LDAP_BACK_F_T_F_DISCOVER
+ && !LDAP_BACK_T_F( li ) )
+ {
+ int rc;
+
+ if ( li->li_uri == NULL ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "need URI to discover \"cancel\" support "
+ "in \"cancel exop-discover\"" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ rc = slap_discover_feature( li->li_uri, li->li_version,
+ slap_schema.si_ad_supportedFeatures->ad_cname.bv_val,
+ LDAP_FEATURE_ABSOLUTE_FILTERS );
+ if ( rc == LDAP_COMPARE_TRUE ) {
+ mask |= LDAP_BACK_F_T_F;
+ }
+ }
+
+ li->li_flags &= ~LDAP_BACK_F_T_F_MASK2;
+ li->li_flags |= mask;
+ } break;
case LDAP_BACK_CFG_WHOAMI:
if ( c->argc == 1 || c->value_int ) {
unsigned u;
if ( lutil_atoux( &u, c->argv[ i ], 0 ) != 0 ) {
+ snprintf( c->msg, sizeof( c->msg),
+ "unable to parse timeout \"%s\"",
+ c->argv[ i ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
return 1;
}
- for ( j = 0; j < LDAP_BACK_OP_LAST; j++ ) {
+ for ( j = 0; j < SLAP_OP_LAST; j++ ) {
li->li_timeout[ j ] = u;
}
}
if ( slap_cf_aux_table_parse( c->argv[ i ], li->li_timeout, timeout_table, "slapd-ldap timeout" ) ) {
+ snprintf( c->msg, sizeof( c->msg),
+ "unable to parse timeout \"%s\"",
+ c->argv[ i ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
return 1;
}
}
} break;
case LDAP_BACK_CFG_VERSION:
- switch ( c->value_int ) {
- case 0:
- case LDAP_VERSION2:
- case LDAP_VERSION3:
- li->li_version = c->value_int;
- break;
+ if ( c->value_int != 0 && ( c->value_int < LDAP_VERSION_MIN || c->value_int > LDAP_VERSION_MAX ) ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "unsupported version \"%s\" "
+ "in \"protocol-version <version>\"",
+ c->argv[ 1 ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
- default:
+ li->li_version = c->value_int;
+ break;
+
+ case LDAP_BACK_CFG_SINGLECONN:
+ if ( c->value_int ) {
+ li->li_flags |= LDAP_BACK_F_SINGLECONN;
+
+ } else {
+ li->li_flags &= ~LDAP_BACK_F_SINGLECONN;
+ }
+ 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_CONNPOOLMAX:
+ if ( c->value_int < LDAP_BACK_CONN_PRIV_MIN
+ || c->value_int > LDAP_BACK_CONN_PRIV_MAX )
+ {
+ snprintf( c->msg, sizeof( c->msg ),
+ "invalid max size " "of privileged "
+ "connections pool \"%s\" "
+ "in \"conn-pool-max <n> "
+ "(must be between %d and %d)\"",
+ c->argv[ 1 ],
+ LDAP_BACK_CONN_PRIV_MIN,
+ LDAP_BACK_CONN_PRIV_MAX );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+ li->li_conn_priv_max = c->value_int;
+ break;
+
+ case LDAP_BACK_CFG_CANCEL: {
+ slap_mask_t mask;
+
+ i = verb_to_mask( c->argv[1], cancel_mode );
+ if ( BER_BVISNULL( &cancel_mode[i].word ) ) {
+ return 1;
+ }
+
+ mask = cancel_mode[i].mask;
+
+ if ( LDAP_BACK_ISOPEN( li )
+ && mask == LDAP_BACK_F_CANCEL_EXOP_DISCOVER
+ && !LDAP_BACK_CANCEL( li ) )
+ {
+ int rc;
+
+ if ( li->li_uri == NULL ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "need URI to discover \"cancel\" support "
+ "in \"cancel exop-discover\"" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+
+ rc = slap_discover_feature( li->li_uri, li->li_version,
+ slap_schema.si_ad_supportedExtension->ad_cname.bv_val,
+ LDAP_EXOP_CANCEL );
+ if ( rc == LDAP_COMPARE_TRUE ) {
+ mask |= LDAP_BACK_F_CANCEL_EXOP;
+ }
+ }
+
+ li->li_flags &= ~LDAP_BACK_F_CANCEL_MASK2;
+ li->li_flags |= mask;
+ } break;
+
+ case LDAP_BACK_CFG_QUARANTINE:
+ if ( LDAP_BACK_QUARANTINE( li ) ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "quarantine already defined" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
return 1;
}
+ rc = slap_retry_info_parse( c->argv[1], &li->li_quarantine,
+ c->msg, sizeof( c->msg ) );
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+
+ } else {
+ ldap_pvt_thread_mutex_init( &li->li_quarantine_mutex );
+ /* give it a chance to retry if the pattern gets reset
+ * via back-config */
+ li->li_isquarantined = 0;
+ }
break;
case LDAP_BACK_CFG_REWRITE:
break;
}
- return 0;
+ return rc;
}
int
&& !strcmp( op->o_conn->c_authz_backend->be_type, "ldap" )
&& !dn_match( &op->o_ndn, &op->o_conn->c_ndn ) )
{
- ldapconn_t *lc;
+ ldapconn_t *lc = NULL;
LDAPControl c, *ctrls[2] = {NULL, NULL};
LDAPMessage *res;
Operation op2 = *op;
ctrls[0] = &c;
op2.o_ndn = op->o_conn->c_ndn;
- lc = ldap_back_getconn(&op2, rs, LDAP_BACK_SENDERR);
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ if ( !ldap_back_dobind( &lc, &op2, rs, LDAP_BACK_SENDERR ) ) {
return -1;
}
c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- ldapconn_t *lc;
- ber_int_t msgid;
- LDAPControl **ctrls = NULL;
- int do_retry = 1;
- int rc = LDAP_SUCCESS;
+ ldapconn_t *lc = NULL;
+ ber_int_t msgid;
+ LDAPControl **ctrls = NULL;
+ ldap_back_send_t retrying = LDAP_BACK_RETRYING;
+ int rc = LDAP_SUCCESS;
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
-
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
return rs->sr_err;
}
retry:
ctrls = op->o_ctrls;
- rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
+ rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn,
+ li->li_version, &li->li_idassert, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
rc = rs->sr_err;
rs->sr_err = ldap_delete_ext( lc->lc_ld, op->o_req_dn.bv_val,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid,
- li->li_timeout[ LDAP_BACK_OP_DELETE], LDAP_BACK_SENDRESULT );
- if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) {
- do_retry = 0;
+ li->li_timeout[ SLAP_OP_DELETE ],
+ ( LDAP_BACK_SENDRESULT | retrying ) );
+ if ( rs->sr_err == LDAP_SERVER_DOWN && retrying ) {
+ retrying &= ~LDAP_BACK_RETRYING;
if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
/* if the identity changed, there might be need to re-authz */
(void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
static int
ldap_back_extended_one( Operation *op, SlapReply *rs, BI_op_extended exop )
{
- ldapconn_t *lc;
+ ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
+
+ ldapconn_t *lc = NULL;
LDAPControl **oldctrls = NULL;
int rc;
* called twice; maybe we could avoid the
* ldap_back_dobind() call inside each extended()
* call ... */
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
return -1;
}
oldctrls = op->o_ctrls;
- if ( ldap_back_proxy_authz_ctrl( lc, op, rs, &op->o_ctrls ) ) {
+ if ( ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn,
+ li->li_version, &li->li_idassert, op, rs, &op->o_ctrls ) )
+ {
op->o_ctrls = oldctrls;
send_ldap_extended( op, rs );
rs->sr_text = NULL;
Operation *op,
SlapReply *rs )
{
- ldapconn_t *lc;
+ ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
+
+ ldapconn_t *lc = NULL;
req_pwdexop_s *qpw = &op->oq_pwdexop;
LDAPMessage *res;
ber_int_t msgid;
int do_retry = 1;
char *text = NULL;
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
return -1;
}
rs->sr_err = rc;
} else {
+ /* only touch when activity actually took place... */
+ if ( li->li_idle_timeout && lc ) {
+ lc->lc_time = op->o_time;
+ }
+
/* sigh. parse twice, because parse_passwd
* doesn't give us the err / match / msg info.
*/
goto retry;
}
}
+
+ if ( LDAP_BACK_QUARANTINE( li ) ) {
+ ldap_back_quarantine( op, rs );
+ }
+
if ( text ) rs->sr_text = text;
send_ldap_extended( op, rs );
/* otherwise frontend resends result */
rc = rs->sr_err = SLAPD_ABANDON;
+
+ } else if ( LDAP_BACK_QUARANTINE( li ) ) {
+ ldap_back_quarantine( op, rs );
}
/* these have to be freed anyway... */
Operation *op,
SlapReply *rs )
{
- ldapconn_t *lc;
+ ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
+
+ ldapconn_t *lc = NULL;
LDAPMessage *res;
ber_int_t msgid;
int rc;
int do_retry = 1;
char *text = NULL;
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
return -1;
}
rs->sr_err = rc;
} else {
+ /* only touch when activity actually took place... */
+ if ( li->li_idle_timeout && lc ) {
+ lc->lc_time = op->o_time;
+ }
+
/* sigh. parse twice, because parse_passwd
* doesn't give us the err / match / msg info.
*/
goto retry;
}
}
+
+ if ( LDAP_BACK_QUARANTINE( li ) ) {
+ ldap_back_quarantine( op, rs );
+ }
+
if ( text ) rs->sr_text = text;
send_ldap_extended( op, rs );
/* otherwise frontend resends result */
rc = rs->sr_err = SLAPD_ABANDON;
+
+ } else if ( LDAP_BACK_QUARANTINE( li ) ) {
+ ldap_back_quarantine( op, rs );
}
/* these have to be freed anyway... */
ldap_back_db_init( Backend *be )
{
ldapinfo_t *li;
+ unsigned i;
li = (ldapinfo_t *)ch_calloc( 1, sizeof( ldapinfo_t ) );
if ( li == NULL ) {
return -1;
}
+ li->li_rebind_f = ldap_back_default_rebind;
+ ldap_pvt_thread_mutex_init( &li->li_uri_mutex );
+
BER_BVZERO( &li->li_acl_authcID );
BER_BVZERO( &li->li_acl_authcDN );
BER_BVZERO( &li->li_acl_passwd );
li->li_idassert_authmethod = LDAP_AUTH_NONE;
BER_BVZERO( &li->li_idassert_sasl_mech );
- li->li_idassert.sb_tls = SB_TLS_DEFAULT;
+ li->li_idassert_tls = SB_TLS_DEFAULT;
/* by default, use proxyAuthz control on each operation */
li->li_idassert_flags = LDAP_BACK_AUTH_PRESCRIPTIVE;
ldap_pvt_thread_mutex_init( &li->li_conninfo.lai_mutex );
+ for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
+ li->li_conn_priv[ i ].lic_num = 0;
+ LDAP_TAILQ_INIT( &li->li_conn_priv[ i ].lic_priv );
+ }
+ li->li_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
+
be->be_private = li;
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_NOLASTMOD;
break;
}
-#if 0 && defined(SLAPD_MONITOR)
- {
- /* FIXME: disabled because namingContexts doesn't have
- * a matching rule, and using an MRA filter doesn't work
- * because the normalized assertion is compared to the
- * non-normalized value, which in general differs from
- * the normalized one. See ITS#3406 */
- struct berval filter,
- base = BER_BVC( "cn=Databases," SLAPD_MONITOR );
- Attribute a = { 0 };
-
- filter.bv_len = STRLENOF( "(&(namingContexts:distinguishedNameMatch:=)(monitoredInfo=ldap))" )
- + be->be_nsuffix[ 0 ].bv_len;
- filter.bv_val = ch_malloc( filter.bv_len + 1 );
- snprintf( filter.bv_val, filter.bv_len + 1,
- "(&(namingContexts:distinguishedNameMatch:=%s)(monitoredInfo=ldap))",
- be->be_nsuffix[ 0 ].bv_val );
-
- a.a_desc = slap_schema.si_ad_labeledURI;
- a.a_vals = li->li_bvuri;
- a.a_nvals = li->li_bvuri;
- if ( monitor_back_register_entry_attrs( NULL, &a, NULL, &base, LDAP_SCOPE_SUBTREE, &filter ) ) {
- /* error */
- }
+ if ( LDAP_BACK_T_F_DISCOVER( li ) && !LDAP_BACK_T_F( li ) ) {
+ int rc;
- ch_free( filter.bv_val );
+ rc = slap_discover_feature( li->li_uri, li->li_version,
+ slap_schema.si_ad_supportedFeatures->ad_cname.bv_val,
+ LDAP_FEATURE_ABSOLUTE_FILTERS );
+ if ( rc == LDAP_COMPARE_TRUE ) {
+ li->li_flags |= LDAP_BACK_F_T_F;
+ }
}
-#endif /* SLAPD_MONITOR */
- if ( li->li_flags & LDAP_BACK_F_SUPPORT_T_F_DISCOVER ) {
+ if ( LDAP_BACK_CANCEL_DISCOVER( li ) && !LDAP_BACK_CANCEL( li ) ) {
int rc;
- li->li_flags &= ~LDAP_BACK_F_SUPPORT_T_F_DISCOVER;
-
rc = slap_discover_feature( li->li_uri, li->li_version,
- slap_schema.si_ad_supportedFeatures->ad_cname.bv_val,
- LDAP_FEATURE_ABSOLUTE_FILTERS );
+ slap_schema.si_ad_supportedExtension->ad_cname.bv_val,
+ LDAP_EXOP_CANCEL );
if ( rc == LDAP_COMPARE_TRUE ) {
- li->li_flags |= LDAP_BACK_F_SUPPORT_T_F;
+ li->li_flags |= LDAP_BACK_F_CANCEL_EXOP;
}
}
+ li->li_flags |= LDAP_BACK_F_ISOPEN;
+
return 0;
}
if ( !BER_BVISNULL( &lc->lc_local_ndn ) ) {
ch_free( lc->lc_local_ndn.bv_val );
}
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
ch_free( lc );
}
int
-ldap_back_db_destroy(
- Backend *be
-)
+ldap_back_db_destroy( Backend *be )
{
if ( be->be_private ) {
ldapinfo_t *li = ( ldapinfo_t * )be->be_private;
+ unsigned i;
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
if ( li->li_conninfo.lai_tree ) {
avl_free( li->li_conninfo.lai_tree, ldap_back_conn_free );
}
+ for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
+ while ( !LDAP_TAILQ_EMPTY( &li->li_conn_priv[ i ].lic_priv ) ) {
+ ldapconn_t *lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ i ].lic_priv );
+
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ i ].lic_priv, lc, lc_q );
+ ldap_back_conn_free( lc );
+ }
+ }
+ if ( LDAP_BACK_QUARANTINE( li ) ) {
+ slap_retry_info_destroy( &li->li_quarantine );
+ ldap_pvt_thread_mutex_destroy( &li->li_quarantine_mutex );
+ }
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
ldap_pvt_thread_mutex_destroy( &li->li_conninfo.lai_mutex );
+ ldap_pvt_thread_mutex_destroy( &li->li_uri_mutex );
}
ch_free( be->be_private );
Operation *op,
SlapReply *rs )
{
- ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
-
- ldapconn_t *lc;
- LDAPMod **modv = NULL,
- *mods = NULL;
- Modifications *ml;
- int i, j, rc;
- ber_int_t msgid;
- int isupdate;
- int do_retry = 1;
- LDAPControl **ctrls = NULL;
-
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+
+ ldapconn_t *lc = NULL;
+ LDAPMod **modv = NULL,
+ *mods = NULL;
+ Modifications *ml;
+ int i, j, rc;
+ ber_int_t msgid;
+ int isupdate;
+ ldap_back_send_t retrying = LDAP_BACK_RETRYING;
+ LDAPControl **ctrls = NULL;
+
+ if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
return rs->sr_err;
}
retry:;
ctrls = op->o_ctrls;
- rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
+ rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn,
+ li->li_version, &li->li_idassert, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
rc = -1;
rs->sr_err = ldap_modify_ext( lc->lc_ld, op->o_req_dn.bv_val, modv,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid,
- li->li_timeout[ LDAP_BACK_OP_MODIFY], LDAP_BACK_SENDRESULT );
- if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
- do_retry = 0;
+ li->li_timeout[ SLAP_OP_MODIFY ],
+ ( LDAP_BACK_SENDRESULT | retrying ) );
+ if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
+ retrying &= ~LDAP_BACK_RETRYING;
if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
/* if the identity changed, there might be need to re-authz */
(void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
Operation *op,
SlapReply *rs )
{
- ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- ldapconn_t *lc;
- ber_int_t msgid;
- LDAPControl **ctrls = NULL;
- int do_retry = 1;
- int rc = LDAP_SUCCESS;
- char *newSup = NULL;
+ ldapconn_t *lc = NULL;
+ ber_int_t msgid;
+ LDAPControl **ctrls = NULL;
+ ldap_back_send_t retrying = LDAP_BACK_RETRYING;
+ int rc = LDAP_SUCCESS;
+ char *newSup = NULL;
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
return rs->sr_err;
}
retry:
ctrls = op->o_ctrls;
- rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
+ rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn,
+ li->li_version, &li->li_idassert, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
rc = -1;
op->orr_newrdn.bv_val, newSup,
op->orr_deleteoldrdn, ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid,
- li->li_timeout[ LDAP_BACK_OP_MODRDN ], LDAP_BACK_SENDRESULT );
- if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) {
- do_retry = 0;
+ li->li_timeout[ SLAP_OP_MODRDN ],
+ ( LDAP_BACK_SENDRESULT | retrying ) );
+ if ( rs->sr_err == LDAP_SERVER_DOWN && retrying ) {
+ retrying &= ~LDAP_BACK_RETRYING;
if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
/* if the identity changed, there might be need to re-authz */
(void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
extern BI_entry_get_rw ldap_back_entry_get;
-int ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock );
-ldapconn_t *ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok );
-void ldap_back_release_conn_lock( Operation *op, SlapReply *rs, ldapconn_t *lc, int dolock );
-#define ldap_back_release_conn(op, rs, lc) ldap_back_release_conn_lock((op), (rs), (lc), 1)
-int ldap_back_dobind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
+void ldap_back_release_conn_lock( Operation *op, SlapReply *rs, ldapconn_t **lcp, int dolock );
+#define ldap_back_release_conn(op, rs, lc) ldap_back_release_conn_lock((op), (rs), &(lc), 1)
+int ldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
int ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
int ldap_back_map_result( SlapReply *rs );
int ldap_back_op_result( ldapconn_t *lc, Operation *op, SlapReply *rs,
ber_int_t msgid, time_t timeout, ldap_back_send_t sendok );
+int ldap_back_cancel( ldapconn_t *lc, Operation *op, SlapReply *rs, ber_int_t msgid, ldap_back_send_t sendok );
int ldap_back_init_cf( BackendInfo *bi );
extern int
ldap_back_proxy_authz_ctrl(
- ldapconn_t *lc,
+ struct berval *bound_ndn,
+ int version,
+ slap_idassert_t *si,
Operation *op,
SlapReply *rs,
LDAPControl ***pctrls );
Operation *op,
LDAPControl ***pctrls );
+extern void
+ldap_back_quarantine(
+ Operation *op,
+ SlapReply *rs );
+
+#ifdef LDAP_BACK_PRINT_CONNTREE
+extern void
+ldap_back_print_conntree( ldapinfo_t *li, char *msg );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
+
+extern void slap_retry_info_destroy( slap_retry_info_t *ri );
+extern int slap_retry_info_parse( char *in, slap_retry_info_t *ri,
+ char *buf, ber_len_t buflen );
+extern int slap_retry_info_unparse( slap_retry_info_t *ri, struct berval *bvout );
+
+extern int slap_idassert_authzfrom_parse_cf( const char *fname, int lineno, const char *arg, slap_idassert_t *si );
+extern int slap_idassert_parse_cf( const char *fname, int lineno, int argc, char *argv[], slap_idassert_t *si );
+
extern int chain_init( void );
-extern LDAP_REBIND_PROC *ldap_back_rebind_f;
+extern LDAP_REBIND_PROC ldap_back_default_rebind;
LDAP_END_DECL
if ( strncmp( ptr, bv_true.bv_val, bv_true.bv_len ) == 0 ) {
oldbv = &bv_true;
- if ( li->li_flags & LDAP_BACK_F_SUPPORT_T_F ) {
+ if ( LDAP_BACK_T_F( li ) ) {
newbv = &bv_t;
} else {
} else if ( strncmp( ptr, bv_false.bv_val, bv_false.bv_len ) == 0 )
{
oldbv = &bv_false;
- if ( li->li_flags & LDAP_BACK_F_SUPPORT_T_F ) {
+ if ( LDAP_BACK_T_F( li ) ) {
newbv = &bv_f;
} else {
Operation *op,
SlapReply *rs )
{
- ldapconn_t *lc;
+ ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
+
+ ldapconn_t *lc = NULL;
struct timeval tv;
- time_t stoptime = (time_t)-1;
+ time_t stoptime = (time_t)(-1);
LDAPMessage *res,
*e;
int rc = 0,
/* FIXME: shouldn't this be null? */
const char *save_matched = rs->sr_matched;
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
- if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
return rs->sr_err;
}
}
ctrls = op->o_ctrls;
- rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
+ rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn,
+ li->li_version, &li->li_idassert, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
goto finish;
}
if ( rc > 0 ) {
ldap_msgfree( res );
}
- ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
+ (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
rc = SLAPD_ABANDON;
goto finish;
}
if ( op->ors_tlimit != SLAP_NO_LIMIT
&& slap_get_time() > stoptime )
{
- ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
+ (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
goto finish;
}
continue;
} else {
+ /* only touch when activity actually took place... */
+ if ( li->li_idle_timeout && lc ) {
+ lc->lc_time = op->o_time;
+ }
+
/* don't retry any more */
dont_retry = 1;
}
if ( rc == LDAP_UNAVAILABLE ) {
rc = rs->sr_err = LDAP_OTHER;
} else {
- ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
+ (void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
}
goto finish;
}
/* NO OP */ ;
/* FIXME: there MUST be at least one */
- rs->sr_ref = ch_malloc( ( cnt + 1 ) * sizeof( struct berval ) );
+ rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
+ op->o_tmpmemctx );
for ( cnt = 0; references[ cnt ]; cnt++ ) {
ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
/* cleanup */
if ( references ) {
ber_memvfree( (void **)references );
- ch_free( rs->sr_ref );
+ op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
rs->sr_ref = NULL;
}
for ( cnt = 0; references[ cnt ]; cnt++ )
/* NO OP */ ;
- rs->sr_ref = ch_malloc( ( cnt + 1 ) * sizeof( struct berval ) );
+ rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
+ op->o_tmpmemctx );
for ( cnt = 0; references[ cnt ]; cnt++ ) {
/* duplicating ...*/
}
finish:;
- if ( rc != SLAPD_ABANDON ) {
+ if ( LDAP_BACK_QUARANTINE( li ) ) {
+ ldap_back_quarantine( op, rs );
+ }
+
+#if 0
+ /* let send_ldap_result play cleanup handlers (ITS#4645) */
+ if ( rc != SLAPD_ABANDON )
+#endif
+ {
send_ldap_result( op, rs );
}
}
if ( rs->sr_ref ) {
- ber_bvarray_free( rs->sr_ref );
+ ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx );
rs->sr_ref = NULL;
}
ObjectClass *oc,
AttributeDescription *at,
int rw,
- Entry **ent
-)
+ Entry **ent )
{
- ldapconn_t *lc;
+ ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
+
+ ldapconn_t *lc = NULL;
int rc = 1,
do_not_cache;
struct berval bdn;
/* Tell getconn this is a privileged op */
do_not_cache = op->o_do_not_cache;
op->o_do_not_cache = 1;
- lc = ldap_back_getconn( op, &rs, LDAP_BACK_DONTSEND );
- if ( !lc || !ldap_back_dobind( lc, op, &rs, LDAP_BACK_DONTSEND ) ) {
+ if ( !ldap_back_dobind( &lc, op, &rs, LDAP_BACK_DONTSEND ) ) {
op->o_do_not_cache = do_not_cache;
return rs.sr_err;
}
retry:
ctrls = op->o_ctrls;
- rc = ldap_back_proxy_authz_ctrl( lc, op, &rs, &ctrls );
+ rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn,
+ li->li_version, &li->li_idassert, op, &rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
goto cleanup;
}
lc_curr.lc_conn = conn;
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, ">>> ldap_back_conn_destroy" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
while ( ( lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)&lc_curr, ldap_back_conn_cmp ) ) != NULL )
{
Debug( LDAP_DEBUG_TRACE,
"=>ldap_back_conn_destroy: destroying conn %ld (refcnt=%u)\n",
- LDAP_BACK_PCONN_ID( lc->lc_conn ), lc->lc_refcnt, 0 );
+ LDAP_BACK_PCONN_ID( lc ), lc->lc_refcnt, 0 );
assert( lc->lc_refcnt == 0 );
*/
ldap_back_conn_free( lc );
}
+#if LDAP_BACK_PRINT_CONNTREE > 0
+ ldap_back_print_conntree( li, "<<< ldap_back_conn_destroy" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
return 0;
meta_back_add( Operation *op, SlapReply *rs )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metatarget_t *mt;
metaconn_t *mc;
int i, candidate = -1;
int isupdate;
dncookie dc;
int msgid;
int do_retry = 1;
- int maperr = 1;
+ LDAPControl **ctrls = NULL;
Debug(LDAP_DEBUG_ARGS, "==> meta_back_add: %s\n",
op->o_req_dn.bv_val, 0, 0 );
/*
* Rewrite the add dn, if needed
*/
- dc.target = &mi->mi_targets[ candidate ];
+ mt = mi->mi_targets[ candidate ];
+ dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
dc.ctx = "addDN";
mapped = a->a_desc->ad_cname;
} else {
- ldap_back_map( &mi->mi_targets[ candidate ].mt_rwmap.rwm_at,
+ ldap_back_map( &mt->mt_rwmap.rwm_at,
&a->a_desc->ad_cname, &mapped, BACKLDAP_MAP );
if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
continue;
for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); ) {
struct ldapmapping *mapping;
- ldap_back_mapping( &mi->mi_targets[ candidate ].mt_rwmap.rwm_oc,
+ ldap_back_mapping( &mt->mt_rwmap.rwm_oc,
&a->a_vals[ j ], &mapping, BACKLDAP_MAP );
if ( mapping == NULL ) {
- if ( mi->mi_targets[ candidate ].mt_rwmap.rwm_oc.drop_missing ) {
+ if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
continue;
}
attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];
attrs[ i ] = NULL;
retry:;
+ ctrls = op->o_ctrls;
+ if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn,
+ mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS )
+ {
+ send_ldap_result( op, rs );
+ goto cleanup;
+ }
+
rs->sr_err = ldap_add_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val,
- attrs, op->o_ctrls, NULL, &msgid );
+ attrs, ctrls, NULL, &msgid );
+ rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
+ mt->mt_timeout[ SLAP_OP_ADD ], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
+ /* if the identity changed, there might be need to re-authz */
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
goto retry;
}
- goto cleanup;
-
- } else if ( rs->sr_err == LDAP_SUCCESS ) {
- struct timeval tv, *tvp = NULL;
- LDAPMessage *res = NULL;
- int rc;
-
- if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_ADD ] != 0 ) {
- tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_ADD ];
- tv.tv_usec = 0;
- tvp = &tv;
- }
-
- rs->sr_err = LDAP_OTHER;
- maperr = 0;
- rc = ldap_result( mc->mc_conns[ candidate ].msc_ld,
- msgid, LDAP_MSG_ALL, tvp, &res );
- switch ( rc ) {
- case -1:
- break;
-
- case 0:
- ldap_abandon_ext( mc->mc_conns[ candidate ].msc_ld,
- msgid, NULL, NULL );
- rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
- LDAP_ADMINLIMIT_EXCEEDED : LDAP_OPERATIONS_ERROR;
- break;
-
- case LDAP_RES_ADD:
- rc = ldap_parse_result( mc->mc_conns[ candidate ].msc_ld,
- res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 );
- if ( rc != LDAP_SUCCESS ) {
- rs->sr_err = rc;
- }
- maperr = 1;
- break;
-
- default:
- ldap_msgfree( res );
- break;
- }
- }
-
- if ( maperr ) {
- rs->sr_err = meta_back_op_result( mc, op, rs, candidate );
-
- } else {
- send_ldap_result( op, rs );
}
cleanup:;
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
+
for ( --i; i >= 0; --i ) {
free( attrs[ i ]->mod_bvalues );
free( attrs[ i ] );
#include "rewrite.h"
LDAP_BEGIN_DECL
+/*
+ * Set META_BACK_PRINT_CONNTREE larger than 0 to dump the connection tree (debug only)
+ */
+#ifndef META_BACK_PRINT_CONNTREE
+#define META_BACK_PRINT_CONNTREE 0
+#endif /* !META_BACK_PRINT_CONNTREE */
+
struct slap_conn;
struct slap_op;
/* (end of) from back-ldap.h before rwm removal */
+/*
+ * A metasingleconn_t can be in the following, mutually exclusive states:
+ *
+ * - none (0x0U)
+ * - creating META_BACK_FCONN_CREATING
+ * - initialized META_BACK_FCONN_INITED
+ * - binding LDAP_BACK_FCONN_BINDING
+ * - bound/anonymous LDAP_BACK_FCONN_ISBOUND/LDAP_BACK_FCONN_ISANON
+ *
+ * possible modifiers are:
+ *
+ * - privileged LDAP_BACK_FCONN_ISPRIV
+ * - privileged, TLS LDAP_BACK_FCONN_ISTLS
+ * - subjected to idassert LDAP_BACK_FCONN_ISIDASR
+ * - tainted LDAP_BACK_FCONN_TAINTED
+ */
+
+#define META_BACK_FCONN_INITED (0x00100000U)
+#define META_BACK_FCONN_CREATING (0x00200000U)
+
+#define META_BACK_CONN_INITED(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INITED)
+#define META_BACK_CONN_INITED_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INITED)
+#define META_BACK_CONN_INITED_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_INITED)
+#define META_BACK_CONN_INITED_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_INITED, (mlc))
+#define META_BACK_CONN_CREATING(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_CREATING)
+#define META_BACK_CONN_CREATING_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_CREATING)
+#define META_BACK_CONN_CREATING_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_CREATING)
+#define META_BACK_CONN_CREATING_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_CREATING, (mlc))
+
struct metainfo_t;
+#define META_NOT_CANDIDATE ((ber_tag_t)0x0)
+#define META_CANDIDATE ((ber_tag_t)0x1)
+#define META_BINDING ((ber_tag_t)0x2)
+
typedef struct metasingleconn_t {
- int msc_candidate;
-#define META_NOT_CANDIDATE ((ber_tag_t)0)
-#define META_CANDIDATE ((ber_tag_t)1)
+#define META_CND_ISSET(rs,f) ( ( (rs)->sr_tag & (f) ) == (f) )
+#define META_CND_SET(rs,f) ( (rs)->sr_tag |= (f) )
+#define META_CND_CLEAR(rs,f) ( (rs)->sr_tag &= ~(f) )
+
+#define META_CANDIDATE_RESET(rs) ( (rs)->sr_tag = 0 )
+#define META_IS_CANDIDATE(rs) META_CND_ISSET( (rs), META_CANDIDATE )
+#define META_CANDIDATE_SET(rs) META_CND_SET( (rs), META_CANDIDATE )
+#define META_CANDIDATE_CLEAR(rs) META_CND_CLEAR( (rs), META_CANDIDATE )
+#define META_IS_BINDING(rs) META_CND_ISSET( (rs), META_BINDING )
+#define META_BINDING_SET(rs) META_CND_SET( (rs), META_BINDING )
+#define META_BINDING_CLEAR(rs) META_CND_CLEAR( (rs), META_BINDING )
LDAP *msc_ld;
+ time_t msc_time;
struct berval msc_bound_ndn;
struct berval msc_cred;
unsigned msc_mscflags;
/* NOTE: lc_lcflags is redefined to msc_mscflags to reuse the macros
* defined for back-ldap */
#define lc_lcflags msc_mscflags
-
- struct metainfo_t *msc_info;
} metasingleconn_t;
typedef struct metaconn_t {
struct slap_conn *mc_conn;
+#define lc_conn mc_conn
unsigned mc_refcnt;
time_t mc_create_time;
int mc_authz_target;
#define META_BOUND_NONE (-1)
#define META_BOUND_ALL (-2)
+
+ struct metainfo_t *mc_info;
+
+ LDAP_TAILQ_ENTRY(metaconn_t) mc_q;
+
/* supersedes the connection stuff */
metasingleconn_t mc_conns[ 1 ];
/* NOTE: mc_conns must be last, because
typedef struct metatarget_t {
char *mt_uri;
+ ldap_pvt_thread_mutex_t mt_uri_mutex;
+
+ /* TODO: we might want to enable different strategies
+ * for different targets */
+ LDAP_REBIND_PROC *mt_rebind_f;
+ void *mt_urllist_p;
+
BerVarray mt_subtree_exclude;
int mt_scope;
struct berval mt_binddn;
struct berval mt_bindpw;
- struct berval mt_pseudorootdn;
- struct berval mt_pseudorootpw;
+ slap_idassert_t mt_idassert;
+#define mt_idassert_mode mt_idassert.si_mode
+#define mt_idassert_authcID mt_idassert.si_bc.sb_authcId
+#define mt_idassert_authcDN mt_idassert.si_bc.sb_binddn
+#define mt_idassert_passwd mt_idassert.si_bc.sb_cred
+#define mt_idassert_authzID mt_idassert.si_bc.sb_authzId
+#define mt_idassert_authmethod mt_idassert.si_bc.sb_method
+#define mt_idassert_sasl_mech mt_idassert.si_bc.sb_saslmech
+#define mt_idassert_sasl_realm mt_idassert.si_bc.sb_realm
+#define mt_idassert_secprops mt_idassert.si_bc.sb_secprops
+#define mt_idassert_tls mt_idassert.si_bc.sb_tls
+#define mt_idassert_flags mt_idassert.si_flags
+#define mt_idassert_authz mt_idassert.si_authz
int mt_nretries;
#define META_RETRY_UNDEFINED (-2)
#define META_RETRY_FOREVER (-1)
#define META_RETRY_NEVER (0)
-#define META_RETRY_DEFAULT (3)
+#define META_RETRY_DEFAULT (10)
struct ldaprwmap mt_rwmap;
+ sig_atomic_t mt_isquarantined;
+ slap_retry_info_t mt_quarantine;
+ ldap_pvt_thread_mutex_t mt_quarantine_mutex;
+#define META_BACK_TGT_QUARANTINE(mt) ( (mt)->mt_quarantine.ri_num != NULL )
+
unsigned mt_flags;
+#define META_BACK_TGT_ISSET(mt,f) ( ( (mt)->mt_flags & (f) ) == (f) )
+#define META_BACK_TGT_ISMASK(mt,m,f) ( ( (mt)->mt_flags & (m) ) == (f) )
+
+#define META_BACK_TGT_T_F(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_T_F_MASK, LDAP_BACK_F_T_F )
+#define META_BACK_TGT_T_F_DISCOVER(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_T_F_MASK2, LDAP_BACK_F_T_F_DISCOVER )
+
+#define META_BACK_TGT_ABANDON(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_CANCEL_MASK, LDAP_BACK_F_CANCEL_ABANDON )
+#define META_BACK_TGT_IGNORE(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_CANCEL_MASK, LDAP_BACK_F_CANCEL_IGNORE )
+#define META_BACK_TGT_CANCEL(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_CANCEL_MASK, LDAP_BACK_F_CANCEL_EXOP )
+#define META_BACK_TGT_CANCEL_DISCOVER(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_CANCEL_MASK2, LDAP_BACK_F_CANCEL_EXOP_DISCOVER )
+
int mt_version;
time_t mt_network_timeout;
struct timeval mt_bind_timeout;
#define META_BIND_TIMEOUT LDAP_BACK_RESULT_UTIMEOUT
- time_t mt_timeout[ LDAP_BACK_OP_LAST ];
+ time_t mt_timeout[ SLAP_OP_LAST ];
} metatarget_t;
typedef struct metadncache_t {
SlapReply *mc_candidates;
} metacandidates_t;
+/*
+ * Hook to allow mucking with metainfo_t/metatarget_t when quarantine is over
+ */
+typedef int (*meta_back_quarantine_f)( struct metainfo_t *, int target, void * );
+
typedef struct metainfo_t {
int mi_ntargets;
int mi_defaulttarget;
#define META_DEFAULT_TARGET_NONE (-1)
int mi_nretries;
- metatarget_t *mi_targets;
+ metatarget_t **mi_targets;
metacandidates_t *mi_candidates;
+ LDAP_REBIND_PROC *mi_rebind_f;
+
metadncache_t mi_cache;
+ /* cached connections;
+ * special conns are in tailq rather than in tree */
ldap_avl_info_t mi_conninfo;
+ struct {
+ int mic_num;
+ LDAP_TAILQ_HEAD(mc_conn_priv_q, metaconn_t) mic_priv;
+ } mi_conn_priv[ LDAP_BACK_PCONN_LAST ];
+ int mi_conn_priv_max;
+
+ /* NOTE: quarantine uses the connection mutex */
+ slap_retry_info_t mi_quarantine;
+
+#define META_BACK_QUARANTINE(mi) ( (mi)->mi_quarantine.ri_num != NULL )
+ meta_back_quarantine_f mi_quarantine_f;
+ void *mi_quarantine_p;
unsigned mi_flags;
#define li_flags mi_flags
/* uses flags as defined in <back-ldap/back-ldap.h> */
-#define META_BACK_F_ONERR_STOP 0x00010000U
-#define META_BACK_F_DEFER_ROOTDN_BIND 0x00020000U
+#define META_BACK_F_ONERR_STOP (0x00100000U)
+#define META_BACK_F_ONERR_REPORT (0x00200000U)
+#define META_BACK_F_ONERR_MASK (META_BACK_F_ONERR_STOP|META_BACK_F_ONERR_REPORT)
+#define META_BACK_F_DEFER_ROOTDN_BIND (0x00400000U)
+#define META_BACK_F_PROXYAUTHZ_ALWAYS (0x00800000U)
#define META_BACK_ONERR_STOP(mi) ( (mi)->mi_flags & META_BACK_F_ONERR_STOP )
-#define META_BACK_ONERR_CONTINUE(mi) ( !META_BACK_ONERR_CONTINUE( (mi) ) )
+#define META_BACK_ONERR_REPORT(mi) ( (mi)->mi_flags & META_BACK_F_ONERR_REPORT )
+#define META_BACK_ONERR_CONTINUE(mi) ( !( (mi)->mi_flags & META_BACK_F_ONERR_MASK ) )
#define META_BACK_DEFER_ROOTDN_BIND(mi) ( (mi)->mi_flags & META_BACK_F_DEFER_ROOTDN_BIND )
+#define META_BACK_PROXYAUTHZ_ALWAYS(mi) ( (mi)->mi_flags & META_BACK_F_PROXYAUTHZ_ALWAYS )
int mi_version;
time_t mi_network_timeout;
time_t mi_conn_ttl;
time_t mi_idle_timeout;
struct timeval mi_bind_timeout;
- time_t mi_timeout[ LDAP_BACK_OP_LAST ];
+ time_t mi_timeout[ SLAP_OP_LAST ];
} metainfo_t;
typedef enum meta_op_type {
meta_back_release_conn_lock(
Operation *op,
metaconn_t *mc,
- int dofree,
int dolock );
-#define meta_back_release_conn(op, mc) meta_back_release_conn_lock( (op), (mc), 0, 1 )
+#define meta_back_release_conn(op, mc) meta_back_release_conn_lock( (op), (mc), 1 )
extern int
meta_back_retry(
meta_back_conn_free(
void *v_mc );
+#if META_BACK_PRINT_CONNTREE > 0
+extern void
+meta_back_print_conntree(
+ metainfo_t *mi,
+ char *msg );
+#endif
+
extern int
meta_back_init_one_conn(
Operation *op,
SlapReply *rs,
- metatarget_t *mt,
metaconn_t *mc,
int candidate,
int ispriv,
- ldap_back_send_t sendok );
+ ldap_back_send_t sendok,
+ int dolock );
-extern int
-meta_back_single_bind(
+extern void
+meta_back_quarantine(
Operation *op,
SlapReply *rs,
- metaconn_t *mc,
- int candidate,
- int massage );
+ int candidate );
extern int
meta_back_dobind(
int retries,
int dolock );
+extern int
+meta_back_proxy_authz_cred(
+ metaconn_t *mc,
+ int candidate,
+ Operation *op,
+ SlapReply *rs,
+ ldap_back_send_t sendok,
+ struct berval *binddn,
+ struct berval *bindcred,
+ int *method );
+
+extern int
+meta_back_cancel(
+ metaconn_t *mc,
+ Operation *op,
+ SlapReply *rs,
+ ber_int_t msgid,
+ int candidate,
+ ldap_back_send_t sendok );
+
extern int
meta_back_op_result(
metaconn_t *mc,
Operation *op,
SlapReply *rs,
- int candidate );
+ int candidate,
+ ber_int_t msgid,
+ time_t timeout,
+ ldap_back_send_t sendok );
extern int
back_meta_LTX_init_module(
*/
extern int
meta_back_is_candidate(
- struct berval *nsuffix,
- int suffixscope,
- BerVarray subtree_exclude,
+ metatarget_t *mt,
struct berval *ndn,
int scope );
extern int
meta_clear_one_candidate(
- metasingleconn_t *mc );
-
-extern int
-meta_clear_candidates(
Operation *op,
- metaconn_t *mc );
+ metaconn_t *mc,
+ int candidate );
/*
* Dn cache stuff (experimental)
extern void
meta_dncache_free( void *entry );
-extern LDAP_REBIND_PROC *meta_back_rebind_f;
+extern LDAP_REBIND_PROC meta_back_default_rebind;
LDAP_END_DECL
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-meta.h"
+#undef ldap_debug /* silence a warning in ldap-int.h */
+#include "../../../libraries/libldap/ldap-int.h"
-static LDAP_REBIND_PROC meta_back_default_rebind;
+#include "lutil_ldap.h"
-/*
- * a module could register a replacement for this function
- */
-LDAP_REBIND_PROC *meta_back_rebind_f = meta_back_default_rebind;
+static int
+meta_back_proxy_authz_bind(
+ metaconn_t *mc,
+ int candidate,
+ Operation *op,
+ SlapReply *rs,
+ ldap_back_send_t sendok );
+
+static int
+meta_back_single_bind(
+ Operation *op,
+ SlapReply *rs,
+ metaconn_t *mc,
+ int candidate );
int
meta_back_bind( Operation *op, SlapReply *rs )
* invalidCredentials */
mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND );
if ( !mc ) {
- char buf[ SLAP_TEXT_BUFLEN ];
-
- snprintf( buf, sizeof( buf ),
- "meta_back_bind: no target "
- "for dn \"%s\" (%d%s%s).",
- op->o_req_dn.bv_val, rs->sr_err,
- rs->sr_text ? ". " : "",
- rs->sr_text ? rs->sr_text : "" );
- Debug( LDAP_DEBUG_ANY,
- "%s %s\n",
- op->o_log_prefix, buf, 0 );
+ if ( StatslogTest( LDAP_DEBUG_ANY ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "meta_back_bind: no target "
+ "for dn \"%s\" (%d%s%s).",
+ op->o_req_dn.bv_val, rs->sr_err,
+ rs->sr_text ? ". " : "",
+ rs->sr_text ? rs->sr_text : "" );
+ Debug( LDAP_DEBUG_ANY,
+ "%s %s\n",
+ op->o_log_prefix, buf, 0 );
+ }
/* FIXME: there might be cases where we don't want
* to map the error onto invalidCredentials */
*/
mc->mc_authz_target = META_BOUND_NONE;
for ( i = 0; i < mi->mi_ntargets; i++ ) {
+ metatarget_t *mt = mi->mi_targets[ i ];
int lerr;
- Operation op2 = *op;
- int massage = 1;
/*
* Skip non-candidates
*/
- if ( candidates[ i ].sr_tag != META_CANDIDATE ) {
+ if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
continue;
}
}
if ( isroot ) {
- if ( BER_BVISNULL( &mi->mi_targets[ i ].mt_pseudorootdn ) )
+ if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE
+ || BER_BVISNULL( &mt->mt_idassert_authcDN ) )
{
metasingleconn_t *msc = &mc->mc_conns[ i ];
BER_BVZERO( &msc->msc_bound_ndn );
}
- if ( LDAP_BACK_SAVECRED( mi ) &&
- !BER_BVISNULL( &msc->msc_cred ) )
- {
+ if ( !BER_BVISNULL( &msc->msc_cred ) ) {
/* destroy sensitive data */
memset( msc->msc_cred.bv_val, 0,
msc->msc_cred.bv_len );
continue;
}
- op2.o_req_dn = mi->mi_targets[ i ].mt_pseudorootdn;
- op2.o_req_ndn = mi->mi_targets[ i ].mt_pseudorootdn;
- op2.orb_cred = mi->mi_targets[ i ].mt_pseudorootpw;
- op2.orb_method = LDAP_AUTH_SIMPLE;
+
+ (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND );
+ lerr = rs->sr_err;
- massage = 0;
+ } else {
+ lerr = meta_back_single_bind( op, rs, mc, i );
}
-
- lerr = meta_back_single_bind( &op2, rs, mc, i, massage );
if ( lerr != LDAP_SUCCESS ) {
rc = rs->sr_err = lerr;
* do not assume it's not candidate; rather
* mark this as an error to be eventually
* reported to client */
- candidates[ i ].sr_tag = META_NOT_CANDIDATE;
+ META_CANDIDATE_CLEAR( &candidates[ i ] );
break;
}
}
}
assert( mc->mc_refcnt == 1 );
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, ">>> meta_back_bind" );
+#endif /* META_BACK_PRINT_CONNTREE */
tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
meta_back_conndn_cmp );
assert( tmpmc == mc );
+ /* delete all cached connections with the current connection */
+ if ( LDAP_BACK_SINGLECONN( mi ) ) {
+ while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
+ {
+ Debug( LDAP_DEBUG_TRACE,
+ "=>meta_back_bind: destroying conn %ld (refcnt=%u)\n",
+ LDAP_BACK_PCONN_ID( mc ), mc->mc_refcnt, 0 );
+
+ if ( tmpmc->mc_refcnt != 0 ) {
+ /* taint it */
+ LDAP_BACK_CONN_TAINTED_SET( tmpmc );
+
+ } else {
+ /*
+ * Needs a test because the handler may be corrupted,
+ * and calling ldap_unbind on a corrupted header results
+ * in a segmentation fault
+ */
+ meta_back_conn_free( tmpmc );
+ }
+ }
+ }
+
ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
+ if ( isroot ) {
+ LDAP_BACK_CONN_ISPRIV_SET( mc );
+ LDAP_BACK_PCONN_SET( mc, op );
+ }
lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
meta_back_conndn_cmp, meta_back_conndn_dup );
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, "<<< meta_back_bind" );
+#endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
if ( lerr == -1 ) {
- meta_clear_candidates( op, mc );
-
/* we can do this because mc_refcnt == 1 */
+ assert( mc->mc_refcnt == 1 );
mc->mc_refcnt = 0;
meta_back_conn_free( mc );
mc = NULL;
return LDAP_SUCCESS;
}
-/*
- * meta_back_single_bind
- *
- * attempts to perform a bind with creds
- */
-int
-meta_back_single_bind(
+static int
+meta_back_bind_op_result(
Operation *op,
SlapReply *rs,
metaconn_t *mc,
int candidate,
- int massage )
+ int msgid,
+ ldap_back_send_t sendok )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
- metatarget_t *mt = &mi->mi_targets[ candidate ];
- struct berval mdn = BER_BVNULL;
+ metatarget_t *mt = mi->mi_targets[ candidate ];
metasingleconn_t *msc = &mc->mc_conns[ candidate ];
- int msgid,
- rebinding = 0;
+ LDAPMessage *res;
+ struct timeval tv;
+ int rc;
+ int nretries = mt->mt_nretries;
+ char buf[ SLAP_TEXT_BUFLEN ];
-
- if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
- ch_free( msc->msc_bound_ndn.bv_val );
- BER_BVZERO( &msc->msc_bound_ndn );
- }
+ Debug( LDAP_DEBUG_TRACE,
+ ">>> %s meta_back_bind_op_result[%d]\n",
+ op->o_log_prefix, candidate, 0 );
- if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &msc->msc_cred ) ) {
- /* destroy sensitive data */
- memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
- ch_free( msc->msc_cred.bv_val );
- BER_BVZERO( &msc->msc_cred );
- }
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ time_t stoptime = (time_t)(-1),
+ timeout;
+ int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ const char *timeout_text = "Operation timed out";
+ slap_op_t opidx = slap_req2op( op->o_tag );
+
+ /* since timeout is not specified, compute and use
+ * the one specific to the ongoing operation */
+ if ( opidx == LDAP_REQ_SEARCH ) {
+ if ( op->ors_tlimit <= 0 ) {
+ timeout = 0;
+
+ } else {
+ timeout = op->ors_tlimit;
+ timeout_err = LDAP_TIMELIMIT_EXCEEDED;
+ timeout_text = NULL;
+ }
- /*
- * Rewrite the bind dn if needed
- */
- if ( massage ) {
- dncookie dc;
+ } else {
+ timeout = mt->mt_timeout[ opidx ];
+ }
- dc.target = mt;
- dc.conn = op->o_conn;
- dc.rs = rs;
- dc.ctx = "bindDN";
+ /* better than nothing :) */
+ if ( timeout == 0 ) {
+ if ( mi->mi_idle_timeout ) {
+ timeout = mi->mi_idle_timeout;
- if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
- rs->sr_text = "DN rewrite error";
- rs->sr_err = LDAP_OTHER;
- return rs->sr_err;
+ } else if ( mi->mi_conn_ttl ) {
+ timeout = mi->mi_conn_ttl;
+ }
}
- } else {
- mdn = op->o_req_dn;
- }
-
- /* FIXME: this fixes the bind problem right now; we need
- * to use the asynchronous version to get the "matched"
- * and more in case of failure ... */
- /* FIXME: should we check if at least some of the op->o_ctrls
- * can/should be passed? */
-rebind:;
- rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
- LDAP_SASL_SIMPLE, &op->orb_cred,
- op->o_ctrls, NULL, &msgid );
- if ( rs->sr_err == LDAP_SUCCESS ) {
- LDAPMessage *res;
- struct timeval tv;
- int rc;
- int nretries = mt->mt_nretries;
- char buf[ SLAP_TEXT_BUFLEN ];
+ if ( timeout ) {
+ stoptime = op->o_time + timeout;
+ }
LDAP_BACK_TV_SET( &tv );
* handle response!!!
*/
retry:;
- switch ( ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
+ rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
+ switch ( rc ) {
case 0:
- snprintf( buf, sizeof( buf ),
- "ldap_result=0 nretries=%d%s",
- nretries, rebinding ? " rebinding" : "" );
+#if 0
Debug( LDAP_DEBUG_ANY,
- "%s meta_back_single_bind[%d]: %s.\n",
- op->o_log_prefix, candidate, buf );
+ "%s meta_back_bind_op_result[%d]: ldap_result=0 nretries=%d.\n",
+ op->o_log_prefix, candidate, nretries );
+#endif
- if ( nretries != META_RETRY_NEVER ) {
+ if ( nretries != META_RETRY_NEVER
+ || ( timeout && slap_get_time() <= stoptime ) )
+ {
ldap_pvt_thread_yield();
if ( nretries > 0 ) {
nretries--;
goto retry;
}
- rs->sr_err = LDAP_BUSY;
- if ( rebinding ) {
- ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
- break;
- }
+ /* don't let anyone else use this handler,
+ * because there's a pending bind that will not
+ * be acknowledged */
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ assert( LDAP_BACK_CONN_BINDING( msc ) );
- /* FIXME: some times the request times out
- * while the other party is not willing to
- * send a response any more. Give it a second
- * chance with a freshly bound connection */
- rebinding = 1;
- nretries = mt->mt_nretries;
- /* fallthru */
+#ifdef DEBUG_205
+ Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n",
+ op->o_log_prefix, candidate, (void *)msc->msc_ld );
+#endif /* DEBUG_205 */
+
+ meta_clear_one_candidate( op, mc, candidate );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+
+ rs->sr_err = timeout_err;
+ rs->sr_text = timeout_text;
+ break;
case -1:
- ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
+ ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
&rs->sr_err );
- if ( rebinding ) {
- ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
- }
-
snprintf( buf, sizeof( buf ),
"err=%d (%s) nretries=%d",
rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
Debug( LDAP_DEBUG_ANY,
- "### %s meta_back_single_bind[%d]: %s.\n",
+ "### %s meta_back_bind_op_result[%d]: %s.\n",
op->o_log_prefix, candidate, buf );
-
- rc = slap_map_api2result( rs );
- if ( rs->sr_err == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
- rc = meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND );
- if ( rc ) {
- if ( nretries > 0 ) {
- nretries--;
- }
- ldap_pvt_thread_yield();
- goto rebind;
- }
- goto return_results;
- }
break;
default:
+ /* only touch when activity actually took place... */
+ if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
+ msc->msc_time = op->o_time;
+ }
+
+ /* FIXME: matched? referrals? response controls? */
rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
NULL, NULL, NULL, NULL, 1 );
if ( rc != LDAP_SUCCESS ) {
}
}
+ rs->sr_err = slap_map_api2result( rs );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "<<< %s meta_back_bind_op_result[%d] err=%d\n",
+ op->o_log_prefix, candidate, rs->sr_err );
+
+ return rs->sr_err;
+}
+
+/*
+ * meta_back_single_bind
+ *
+ * attempts to perform a bind with creds
+ */
+static int
+meta_back_single_bind(
+ Operation *op,
+ SlapReply *rs,
+ metaconn_t *mc,
+ int candidate )
+{
+ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metatarget_t *mt = mi->mi_targets[ candidate ];
+ struct berval mdn = BER_BVNULL;
+ metasingleconn_t *msc = &mc->mc_conns[ candidate ];
+ int msgid;
+ dncookie dc;
+
+ if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
+ ch_free( msc->msc_bound_ndn.bv_val );
+ BER_BVZERO( &msc->msc_bound_ndn );
+ }
+
+ if ( !BER_BVISNULL( &msc->msc_cred ) ) {
+ /* destroy sensitive data */
+ memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
+ ch_free( msc->msc_cred.bv_val );
+ BER_BVZERO( &msc->msc_cred );
+ }
+
+ /*
+ * Rewrite the bind dn if needed
+ */
+ dc.target = mt;
+ dc.conn = op->o_conn;
+ dc.rs = rs;
+ dc.ctx = "bindDN";
+
+ if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
+ rs->sr_text = "DN rewrite error";
+ rs->sr_err = LDAP_OTHER;
+ return rs->sr_err;
+ }
+
+ /* FIXME: this fixes the bind problem right now; we need
+ * to use the asynchronous version to get the "matched"
+ * and more in case of failure ... */
+ /* FIXME: should we check if at least some of the op->o_ctrls
+ * can/should be passed? */
+ rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
+ LDAP_SASL_SIMPLE, &op->orb_cred,
+ op->o_ctrls, NULL, &msgid );
+ meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND );
if ( rs->sr_err != LDAP_SUCCESS ) {
- rs->sr_err = slap_map_api2result( rs );
goto return_results;
}
- ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_dn );
+ /* If defined, proxyAuthz will be used also when
+ * back-ldap is the authorizing backend; for this
+ * purpose, a successful bind is followed by a
+ * bind with the configured identity assertion */
+ /* NOTE: use with care */
+ if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
+ meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR );
+ if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) {
+ goto return_results;
+ }
+ goto cache_refresh;
+ }
+
+ ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_ndn );
LDAP_BACK_CONN_ISBOUND_SET( msc );
mc->mc_authz_target = candidate;
if ( LDAP_BACK_SAVECRED( mi ) ) {
+ if ( !BER_BVISNULL( &msc->msc_cred ) ) {
+ memset( msc->msc_cred.bv_val, 0,
+ msc->msc_cred.bv_len );
+ }
ber_bvreplace( &msc->msc_cred, &op->orb_cred );
- ldap_set_rebind_proc( msc->msc_ld, meta_back_rebind_f, msc );
+ ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
}
+cache_refresh:;
if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED
- && op->o_req_ndn.bv_len != 0 )
+ && !BER_BVISEMPTY( &op->o_req_ndn ) )
{
( void )meta_dncache_update_entry( &mi->mi_cache,
&op->o_req_ndn, candidate );
free( mdn.bv_val );
}
+ if ( META_BACK_TGT_QUARANTINE( mt ) ) {
+ meta_back_quarantine( op, rs, candidate );
+ }
+
return rs->sr_err;
}
int dolock )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
- metatarget_t *mt = &mi->mi_targets[ candidate ];
+ metatarget_t *mt = mi->mi_targets[ candidate ];
metaconn_t *mc = *mcp;
metasingleconn_t *msc = &mc->mc_conns[ candidate ];
int rc;
static struct berval cred = BER_BVC( "" );
- int msgid,
- rebinding = 0,
- save_nretries = nretries;
+ int msgid;
assert( !LDAP_BACK_CONN_ISBOUND( msc ) );
- /*
- * meta_back_single_dobind() calls meta_back_single_bind()
- * if required.
- */
- if ( be_isroot( op ) && !BER_BVISNULL( &mi->mi_targets[ candidate ].mt_pseudorootdn ) )
+ /* NOTE: this obsoletes pseudorootdn */
+ if ( op->o_conn != NULL &&
+ !op->o_do_not_cache &&
+ ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
+ BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
+ ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) ||
+ ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
{
- Operation op2 = *op;
-
- op2.o_tag = LDAP_REQ_BIND;
- op2.o_req_dn = mi->mi_targets[ candidate ].mt_pseudorootdn;
- op2.o_req_ndn = mi->mi_targets[ candidate ].mt_pseudorootdn;
- op2.orb_cred = mi->mi_targets[ candidate ].mt_pseudorootpw;
- op2.orb_method = LDAP_AUTH_SIMPLE;
-
- rc = meta_back_single_bind( &op2, rs, *mcp, candidate, 0 );
+ (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok );
+ rc = rs->sr_err;
goto done;
}
- /*
- * Otherwise an anonymous bind is performed
- * (note: if the target was already bound, the anonymous
- * bind clears the previous bind).
- */
- if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
- ber_memfree( msc->msc_bound_ndn.bv_val );
- BER_BVZERO( &msc->msc_bound_ndn );
- }
-
- if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &msc->msc_cred ) ) {
- /* destroy sensitive data */
- memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
- ber_memfree( msc->msc_cred.bv_val );
- BER_BVZERO( &msc->msc_cred );
- }
-
/* FIXME: should we check if at least some of the op->o_ctrls
* can/should be passed? */
-rebind:;
- rc = ldap_sasl_bind( msc->msc_ld, "", LDAP_SASL_SIMPLE, &cred,
+ rs->sr_err = ldap_sasl_bind( msc->msc_ld, "", LDAP_SASL_SIMPLE, &cred,
NULL, NULL, &msgid );
- if ( rc == LDAP_SUCCESS ) {
- LDAPMessage *res;
- struct timeval tv;
- char buf[ SLAP_TEXT_BUFLEN ];
-
- LDAP_BACK_TV_SET( &tv );
-
- /*
- * handle response!!!
- */
-retry:;
- switch ( ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
- case 0:
- snprintf( buf, sizeof( buf ),
- "ldap_result=0 nretries=%d%s",
- nretries, rebinding ? " rebinding" : "" );
- Debug( LDAP_DEBUG_ANY,
- "%s meta_back_single_dobind[%d]: %s.\n",
- op->o_log_prefix, candidate, buf );
-
- if ( nretries != META_RETRY_NEVER ) {
- ldap_pvt_thread_yield();
- if ( nretries > 0 ) {
- nretries--;
- }
- tv = mt->mt_bind_timeout;
- goto retry;
- }
-
- rc = LDAP_BUSY;
- if ( rebinding ) {
- ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
- break;
- }
-
- /* FIXME: some times the request times out
- * while the other party is not willing to
- * send a response any more. Give it a second
- * chance with a freshly bound connection */
- rebinding = 1;
- nretries = save_nretries;
- /* fallthru */
-
- case -1:
- ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
- &rs->sr_err );
-
- if ( rebinding ) {
- ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
- }
-
- snprintf( buf, sizeof( buf ),
- "err=%d (%s) nretries=%d",
- rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
- Debug( LDAP_DEBUG_ANY,
- "### %s meta_back_single_dobind[%d]: %s.\n",
- op->o_log_prefix, candidate, buf );
-
- rc = slap_map_api2result( rs );
- if ( rc == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
- if ( dolock ) {
- ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
- }
-
- if ( mc->mc_refcnt == 1 ) {
- meta_clear_one_candidate( msc );
- LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
-
- ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
-
- /* mc here must be the regular mc,
- * reset and ready for init */
- rc = meta_back_init_one_conn( op, rs,
- mt, mc, candidate,
- LDAP_BACK_CONN_ISPRIV( mc ),
- LDAP_BACK_DONTSEND );
- LDAP_BACK_CONN_BINDING_SET( msc );
-
- } else {
- /* can't do anything about it */
- rc = LDAP_UNAVAILABLE;
- }
-
- if ( dolock ) {
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- }
-
- if ( rc == LDAP_SUCCESS ) {
- ldap_pvt_thread_yield();
- if ( nretries > 0 ) {
- nretries--;
- }
- goto rebind;
- }
- }
- break;
-
- default:
- rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
- NULL, NULL, NULL, NULL, 1 );
- if ( rc == LDAP_SUCCESS ) {
- rc = slap_map_api2result( rs );
- }
- break;
- }
-
- } else {
- rs->sr_err = rc;
- rc = slap_map_api2result( rs );
- }
+ rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok );
done:;
rs->sr_err = rc;
- if ( rc != LDAP_SUCCESS && META_BACK_ONERR_STOP( mi ) ) {
+ if ( rc != LDAP_SUCCESS ) {
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ }
LDAP_BACK_CONN_BINDING_CLEAR( msc );
- meta_back_release_conn_lock( op, mc, 1, dolock );
- *mcp = NULL;
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ LDAP_BACK_CONN_TAINTED_SET( mc );
+ meta_back_release_conn_lock( op, mc, 0 );
+ *mcp = NULL;
+ }
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ }
- if ( sendok & LDAP_BACK_SENDERR ) {
+ if ( META_BACK_ONERR_STOP( mi ) && ( sendok & LDAP_BACK_SENDERR ) ) {
send_ldap_result( op, rs );
}
}
+ if ( META_BACK_TGT_QUARANTINE( mt ) ) {
+ meta_back_quarantine( op, rs, candidate );
+ }
+
return rc;
}
Debug( LDAP_DEBUG_TRACE,
"%s meta_back_dobind: conn=%ld%s\n",
op->o_log_prefix,
- LDAP_BACK_PCONN_ID( mc->mc_conn ),
+ LDAP_BACK_PCONN_ID( mc ),
isroot ? " (isroot)" : "" );
/*
}
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- metatarget_t *mt = &mi->mi_targets[ i ];
+ metatarget_t *mt = mi->mi_targets[ i ];
metasingleconn_t *msc = &mc->mc_conns[ i ];
- int rc, do_retry = 1;
- char *rootdn = NULL;
+ int rc;
/*
* Not a candidate
*/
- if ( candidates[ i ].sr_tag != META_CANDIDATE ) {
+ if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
continue;
}
retry_binding:;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
- if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
+ if ( LDAP_BACK_CONN_ISBOUND( msc )
+ || ( LDAP_BACK_CONN_ISANON( msc )
+ && mt->mt_idassert_authmethod == LDAP_AUTH_NONE ) )
+ {
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
++bound;
continue;
- } else if ( LDAP_BACK_CONN_BINDING( msc ) ) {
+ } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) )
+ {
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
ldap_pvt_thread_yield();
goto retry_binding;
- } else {
- LDAP_BACK_CONN_BINDING_SET( msc );
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- }
+ }
+
+ LDAP_BACK_CONN_BINDING_SET( msc );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
-retry:;
rc = meta_back_single_dobind( op, rs, &mc, i,
LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
/*
}
- if ( rc == LDAP_UNAVAILABLE && do_retry ) {
- do_retry = 0;
+ if ( rc == LDAP_UNAVAILABLE ) {
+ /* FIXME: meta_back_retry() already re-calls
+ * meta_back_single_dobind() */
if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
- goto retry;
+ goto retry_ok;
+ }
+
+ if ( mc != NULL ) {
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ meta_back_release_conn( op, mc );
}
- ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
- LDAP_BACK_CONN_BINDING_CLEAR( msc );
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
return 0;
}
snprintf( buf, sizeof( buf ),
"meta_back_dobind[%d]: (%s) err=%d (%s).",
- i, rootdn ? rootdn : "anonymous",
+ i, isroot ? op->o_bd->be_rootdn.bv_val : "anonymous",
rc, ldap_err2string( rc ) );
Debug( LDAP_DEBUG_ANY,
"%s %s\n",
continue;
} /* else */
-
+
+retry_ok:;
Debug( LDAP_DEBUG_TRACE,
"%s meta_back_dobind[%d]: "
"(%s)\n",
op->o_log_prefix, i,
- rootdn ? rootdn : "anonymous" );
+ isroot ? op->o_bd->be_rootdn.bv_val : "anonymous" );
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
LDAP_BACK_CONN_BINDING_CLEAR( msc );
- if ( rootdn ) {
+ if ( isroot ) {
LDAP_BACK_CONN_ISBOUND_SET( msc );
} else {
LDAP_BACK_CONN_ISANON_SET( msc );
done:;
Debug( LDAP_DEBUG_TRACE,
"%s meta_back_dobind: conn=%ld bound=%d\n",
- op->o_log_prefix, LDAP_BACK_PCONN_ID( mc->mc_conn ), bound );
+ op->o_log_prefix, LDAP_BACK_PCONN_ID( mc ), bound );
if ( bound == 0 ) {
meta_back_release_conn( op, mc );
* This is a callback used for chasing referrals using the same
* credentials as the original user on this session.
*/
-static int
+int
meta_back_default_rebind(
LDAP *ld,
LDAP_CONST char *url,
NULL, NULL, NULL );
}
+int
+meta_back_cancel(
+ metaconn_t *mc,
+ Operation *op,
+ SlapReply *rs,
+ ber_int_t msgid,
+ int candidate,
+ ldap_back_send_t sendok )
+{
+ metainfo_t *mi = (metainfo_t *)op->o_bd->be_private;
+
+ metatarget_t *mt = mi->mi_targets[ candidate ];
+ metasingleconn_t *msc = &mc->mc_conns[ candidate ];
+
+ int rc = LDAP_OTHER;
+
+ Debug( LDAP_DEBUG_TRACE, ">>> %s meta_back_cancel[%d] msgid=%d\n",
+ op->o_log_prefix, candidate, msgid );
+
+ /* default behavior */
+ if ( META_BACK_TGT_ABANDON( mt ) ) {
+ rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
+
+ } else if ( META_BACK_TGT_CANCEL( mt ) ) {
+ rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL );
+
+ } else {
+ assert( 0 );
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<<< %s meta_back_cancel[%d] err=%d\n",
+ op->o_log_prefix, candidate, rc );
+
+ return rc;
+}
+
+
+
/*
* FIXME: error return must be handled in a cleaner way ...
*/
int
meta_back_op_result(
- metaconn_t *mc,
- Operation *op,
- SlapReply *rs,
- int candidate )
+ metaconn_t *mc,
+ Operation *op,
+ SlapReply *rs,
+ int candidate,
+ ber_int_t msgid,
+ time_t timeout,
+ ldap_back_send_t sendok )
{
- metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+
+ const char *save_text = rs->sr_text,
+ *save_matched = rs->sr_matched;
+ BerVarray save_ref = rs->sr_ref;
+ LDAPControl **save_ctrls = rs->sr_ctrls;
+ void *matched_ctx = NULL;
+
+ char *matched = NULL;
+ char *text = NULL;
+ char **refs = NULL;
+ LDAPControl **ctrls = NULL;
+
+ assert( mc != NULL );
- int i,
- rerr = LDAP_SUCCESS;
- char *rmsg = NULL,
- *rmatch = NULL;
- const char *save_rmsg = NULL,
- *save_rmatch = NULL;
- void *rmatch_ctx = NULL;
+ rs->sr_text = NULL;
+ rs->sr_matched = NULL;
+ rs->sr_ref = NULL;
+ rs->sr_ctrls = NULL;
if ( candidate != META_TARGET_NONE ) {
+ metatarget_t *mt = mi->mi_targets[ candidate ];
metasingleconn_t *msc = &mc->mc_conns[ candidate ];
- rs->sr_err = LDAP_SUCCESS;
+#define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE)
+
+ if ( ERR_OK( rs->sr_err ) ) {
+ int rc;
+ struct timeval tv;
+ LDAPMessage *res = NULL;
+ time_t stoptime = (time_t)(-1);
+ int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ const char *timeout_text = "Operation timed out";
+
+ /* if timeout is not specified, compute and use
+ * the one specific to the ongoing operation */
+ if ( timeout == (time_t)(-1) ) {
+ slap_op_t opidx = slap_req2op( op->o_tag );
+
+ if ( opidx == SLAP_OP_SEARCH ) {
+ if ( op->ors_tlimit <= 0 ) {
+ timeout = 0;
+
+ } else {
+ timeout = op->ors_tlimit;
+ timeout_err = LDAP_TIMELIMIT_EXCEEDED;
+ timeout_text = NULL;
+ }
- ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err );
- if ( rs->sr_err != LDAP_SUCCESS ) {
- /*
- * better check the type of error. In some cases
- * (search ?) it might be better to return a
- * success if at least one of the targets gave
- * positive result ...
- */
- ldap_get_option( msc->msc_ld,
- LDAP_OPT_ERROR_STRING, &rmsg );
- if ( rmsg != NULL && rmsg[ 0 ] == '\0' ) {
- ldap_memfree( rmsg );
- rmsg = NULL;
+ } else {
+ timeout = mt->mt_timeout[ opidx ];
+ }
+ }
+
+ /* better than nothing :) */
+ if ( timeout == 0 ) {
+ if ( mi->mi_idle_timeout ) {
+ timeout = mi->mi_idle_timeout;
+
+ } else if ( mi->mi_conn_ttl ) {
+ timeout = mi->mi_conn_ttl;
+ }
}
- ldap_get_option( msc->msc_ld,
- LDAP_OPT_MATCHED_DN, &rmatch );
- if ( rmatch != NULL && rmatch[ 0 ] == '\0' ) {
- ldap_memfree( rmatch );
- rmatch = NULL;
+ if ( timeout ) {
+ stoptime = op->o_time + timeout;
+ }
+
+ LDAP_BACK_TV_SET( &tv );
+
+retry:;
+ rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
+ switch ( rc ) {
+ case 0:
+ if ( timeout && slap_get_time() > stoptime ) {
+ (void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok );
+ rs->sr_err = timeout_err;
+ rs->sr_text = timeout_text;
+ break;
+ }
+
+ LDAP_BACK_TV_SET( &tv );
+ ldap_pvt_thread_yield();
+ goto retry;
+
+ case -1:
+ ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
+ &rs->sr_err );
+ break;
+
+
+ /* otherwise get the result; if it is not
+ * LDAP_SUCCESS, record it in the reply
+ * structure (this includes
+ * LDAP_COMPARE_{TRUE|FALSE}) */
+ default:
+ /* only touch when activity actually took place... */
+ if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
+ msc->msc_time = op->o_time;
+ }
+
+ rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
+ &matched, &text, &refs, &ctrls, 1 );
+ res = NULL;
+ rs->sr_text = text;
+ if ( rc != LDAP_SUCCESS ) {
+ rs->sr_err = rc;
+ }
+ if ( refs != NULL ) {
+ int i;
+
+ for ( i = 0; refs[ i ] != NULL; i++ )
+ /* count */ ;
+ rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
+ op->o_tmpmemctx );
+ for ( i = 0; refs[ i ] != NULL; i++ ) {
+ ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
+ }
+ BER_BVZERO( &rs->sr_ref[ i ] );
+ }
+ if ( ctrls != NULL ) {
+ rs->sr_ctrls = ctrls;
+ }
}
- rerr = rs->sr_err = slap_map_api2result( rs );
+ assert( res == NULL );
+ }
+
+ /* if the error in the reply structure is not
+ * LDAP_SUCCESS, try to map it from client
+ * to server error */
+ if ( !ERR_OK( rs->sr_err ) ) {
+ rs->sr_err = slap_map_api2result( rs );
+
+ /* internal ops ( op->o_conn == NULL )
+ * must not reply to client */
+ if ( op->o_conn && !op->o_do_not_cache && matched ) {
- Debug(LDAP_DEBUG_ANY,
- "==> meta_back_op_result: target"
- " <%d> sending msg \"%s\""
- " (matched \"%s\")\n",
- candidate, ( rmsg ? rmsg : "" ),
- ( rmatch ? rmatch : "" ) );
+ /* record the (massaged) matched
+ * DN into the reply structure */
+ rs->sr_matched = matched;
+ }
+ }
+
+ if ( META_BACK_TGT_QUARANTINE( mt ) ) {
+ meta_back_quarantine( op, rs, candidate );
}
} else {
+ int i,
+ err = rs->sr_err;
+
for ( i = 0; i < mi->mi_ntargets; i++ ) {
metasingleconn_t *msc = &mc->mc_conns[ i ];
- char *msg = NULL;
- char *match = NULL;
+ char *xtext = NULL;
+ char *xmatched = NULL;
rs->sr_err = LDAP_SUCCESS;
* positive result ...
*/
ldap_get_option( msc->msc_ld,
- LDAP_OPT_ERROR_STRING, &msg );
- if ( msg != NULL && msg[ 0 ] == '\0' ) {
- ldap_memfree( msg );
- msg = NULL;
+ LDAP_OPT_ERROR_STRING, &xtext );
+ if ( xtext != NULL && xtext [ 0 ] == '\0' ) {
+ ldap_memfree( xtext );
+ xtext = NULL;
}
ldap_get_option( msc->msc_ld,
- LDAP_OPT_MATCHED_DN, &match );
- if ( match != NULL && match[ 0 ] == '\0' ) {
- ldap_memfree( match );
- match = NULL;
+ LDAP_OPT_MATCHED_DN, &xmatched );
+ if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) {
+ ldap_memfree( xmatched );
+ xmatched = NULL;
}
rs->sr_err = slap_map_api2result( rs );
- Debug(LDAP_DEBUG_ANY,
- "==> meta_back_op_result: target"
- " <%d> sending msg \"%s\""
- " (matched \"%s\")\n",
- i, ( msg ? msg : "" ),
- ( match ? match : "" ) );
-
+ if ( StatslogTest( LDAP_DEBUG_ANY ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "meta_back_op_result[%d] "
+ "err=%d text=\"%s\" matched=\"%s\"",
+ i, rs->sr_err,
+ ( xtext ? xtext : "" ),
+ ( xmatched ? xmatched : "" ) );
+ Debug( LDAP_DEBUG_ANY, "%s %s.\n",
+ op->o_log_prefix, buf, 0 );
+ }
+
/*
* FIXME: need to rewrite "match" (need rwinfo)
*/
switch ( rs->sr_err ) {
default:
- rerr = rs->sr_err;
- if ( msg != NULL ) {
- if ( rmsg ) {
- ldap_memfree( rmsg );
+ err = rs->sr_err;
+ if ( xtext != NULL ) {
+ if ( text ) {
+ ldap_memfree( text );
}
- rmsg = msg;
- msg = NULL;
+ text = xtext;
+ xtext = NULL;
}
- if ( match != NULL ) {
- if ( rmatch ) {
- ldap_memfree( rmatch );
+ if ( xmatched != NULL ) {
+ if ( matched ) {
+ ldap_memfree( matched );
}
- rmatch = match;
- match = NULL;
+ matched = xmatched;
+ xmatched = NULL;
}
break;
}
- if ( msg ) {
- ldap_memfree( msg );
+ if ( xtext ) {
+ ldap_memfree( xtext );
}
- if ( match ) {
- ldap_memfree( match );
+ if ( xmatched ) {
+ ldap_memfree( xmatched );
}
}
+
+ if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
+ meta_back_quarantine( op, rs, i );
+ }
+ }
+
+ if ( err != LDAP_SUCCESS ) {
+ rs->sr_err = err;
}
}
-
- rs->sr_err = rerr;
- if ( rmsg != NULL ) {
- save_rmsg = rs->sr_text;
- rs->sr_text = rmsg;
- }
- if ( rmatch != NULL ) {
+
+ if ( matched != NULL ) {
struct berval dn, pdn;
- ber_str2bv( rmatch, 0, 0, &dn );
+ ber_str2bv( matched, 0, 0, &dn );
if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
- ldap_memfree( rmatch );
- rmatch_ctx = op->o_tmpmemctx;
- rmatch = pdn.bv_val;
+ ldap_memfree( matched );
+ matched_ctx = op->o_tmpmemctx;
+ matched = pdn.bv_val;
}
- save_rmatch = rs->sr_matched;
- rs->sr_matched = rmatch;
+ rs->sr_matched = matched;
+ }
+
+ if ( op->o_conn &&
+ ( ( sendok & LDAP_BACK_SENDOK )
+ || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) )
+ {
+ send_ldap_result( op, rs );
}
- send_ldap_result( op, rs );
- if ( rmsg != NULL ) {
- ber_memfree( rmsg );
- rs->sr_text = save_rmsg;
+ if ( matched ) {
+ op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
}
- if ( rmatch != NULL ) {
- ber_memfree_x( rmatch, rmatch_ctx );
- rs->sr_matched = save_rmatch;
+ if ( text ) {
+ ldap_memfree( text );
+ }
+ if ( rs->sr_ref ) {
+ assert( refs != NULL );
+ ber_memvfree( (void **)refs );
+ op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
+ }
+ if ( ctrls ) {
+ assert( rs->sr_ctrls != NULL );
+ ldap_controls_free( ctrls );
}
- return ( ( rerr == LDAP_SUCCESS ) ? 0 : -1 );
+ rs->sr_text = save_text;
+ rs->sr_matched = save_matched;
+ rs->sr_ref = save_ref;
+ rs->sr_ctrls = save_ctrls;
+
+ return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
}
+/*
+ * meta_back_proxy_authz_cred()
+ *
+ * prepares credentials & method for meta_back_proxy_authz_bind();
+ * or, if method is SASL, performs the SASL bind directly.
+ */
+int
+meta_back_proxy_authz_cred(
+ metaconn_t *mc,
+ int candidate,
+ Operation *op,
+ SlapReply *rs,
+ ldap_back_send_t sendok,
+ struct berval *binddn,
+ struct berval *bindcred,
+ int *method )
+{
+ metainfo_t *mi = (metainfo_t *)op->o_bd->be_private;
+ metatarget_t *mt = mi->mi_targets[ candidate ];
+ metasingleconn_t *msc = &mc->mc_conns[ candidate ];
+ struct berval ndn;
+ int dobind = 0;
+
+ /* don't proxyAuthz if protocol is not LDAPv3 */
+ switch ( mt->mt_version ) {
+ case LDAP_VERSION3:
+ break;
+
+ case 0:
+ if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
+ break;
+ }
+ /* fall thru */
+
+ default:
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
+ LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
+ goto done;
+ }
+
+ if ( op->o_tag == LDAP_REQ_BIND ) {
+ ndn = op->o_req_ndn;
+
+ } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ ndn = op->o_conn->c_ndn;
+
+ } else {
+ ndn = op->o_ndn;
+ }
+
+ /*
+ * FIXME: we need to let clients use proxyAuthz
+ * otherwise we cannot do symmetric pools of servers;
+ * we have to live with the fact that a user can
+ * authorize itself as any ID that is allowed
+ * by the authzTo directive of the "proxyauthzdn".
+ */
+ /*
+ * NOTE: current Proxy Authorization specification
+ * and implementation do not allow proxy authorization
+ * control to be provided with Bind requests
+ */
+ /*
+ * if no bind took place yet, but the connection is bound
+ * and the "proxyauthzdn" is set, then bind as
+ * "proxyauthzdn" and explicitly add the proxyAuthz
+ * control to every operation with the dn bound
+ * to the connection as control value.
+ */
+
+ /* bind as proxyauthzdn only if no idassert mode
+ * is requested, or if the client's identity
+ * is authorized */
+ switch ( mt->mt_idassert_mode ) {
+ case LDAP_BACK_IDASSERT_LEGACY:
+ if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
+ if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) && !BER_BVISEMPTY( &mt->mt_idassert_authcDN ) )
+ {
+ *binddn = mt->mt_idassert_authcDN;
+ *bindcred = mt->mt_idassert_passwd;
+ dobind = 1;
+ }
+ }
+ break;
+
+ default:
+ /* NOTE: rootdn can always idassert */
+ if ( BER_BVISNULL( &ndn ) && mt->mt_idassert_authz == NULL ) {
+ if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+ rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
+ LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
+
+ } else {
+ rs->sr_err = LDAP_SUCCESS;
+ *binddn = slap_empty_bv;
+ *bindcred = slap_empty_bv;
+ break;
+ }
+
+ goto done;
+
+ } else if ( mt->mt_idassert_authz && !be_isroot( op ) ) {
+ struct berval authcDN;
+
+ if ( BER_BVISNULL( &ndn ) ) {
+ authcDN = slap_empty_bv;
+
+ } else {
+ authcDN = ndn;
+ }
+ rs->sr_err = slap_sasl_matches( op, mt->mt_idassert_authz,
+ &authcDN, &authcDN );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
+ LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
+
+ } else {
+ rs->sr_err = LDAP_SUCCESS;
+ *binddn = slap_empty_bv;
+ *bindcred = slap_empty_bv;
+ break;
+ }
+
+ goto done;
+ }
+ }
+
+ *binddn = mt->mt_idassert_authcDN;
+ *bindcred = mt->mt_idassert_passwd;
+ dobind = 1;
+ break;
+ }
+
+ if ( dobind && mt->mt_idassert_authmethod == LDAP_AUTH_SASL ) {
+#ifdef HAVE_CYRUS_SASL
+ void *defaults = NULL;
+ struct berval authzID = BER_BVNULL;
+ int freeauthz = 0;
+
+ /* if SASL supports native authz, prepare for it */
+ if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
+ ( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
+ {
+ switch ( mt->mt_idassert_mode ) {
+ case LDAP_BACK_IDASSERT_OTHERID:
+ case LDAP_BACK_IDASSERT_OTHERDN:
+ authzID = mt->mt_idassert_authzID;
+ break;
+
+ case LDAP_BACK_IDASSERT_ANONYMOUS:
+ BER_BVSTR( &authzID, "dn:" );
+ break;
+
+ case LDAP_BACK_IDASSERT_SELF:
+ if ( BER_BVISNULL( &ndn ) ) {
+ /* connection is not authc'd, so don't idassert */
+ BER_BVSTR( &authzID, "dn:" );
+ break;
+ }
+ authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
+ authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
+ AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
+ AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
+ ndn.bv_val, ndn.bv_len + 1 );
+ freeauthz = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ( mt->mt_idassert_secprops != NULL ) {
+ rs->sr_err = ldap_set_option( msc->msc_ld,
+ LDAP_OPT_X_SASL_SECPROPS,
+ (void *)mt->mt_idassert_secprops );
+
+ if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
+ rs->sr_err = LDAP_OTHER;
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
+ LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
+ goto done;
+ }
+ }
+
+ defaults = lutil_sasl_defaults( msc->msc_ld,
+ mt->mt_idassert_sasl_mech.bv_val,
+ mt->mt_idassert_sasl_realm.bv_val,
+ mt->mt_idassert_authcID.bv_val,
+ mt->mt_idassert_passwd.bv_val,
+ authzID.bv_val );
+
+ rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val,
+ mt->mt_idassert_sasl_mech.bv_val, NULL, NULL,
+ LDAP_SASL_QUIET, lutil_sasl_interact,
+ defaults );
+
+ rs->sr_err = slap_map_api2result( rs );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
+
+ } else {
+ LDAP_BACK_CONN_ISBOUND_SET( msc );
+ }
+
+ lutil_sasl_freedefs( defaults );
+ if ( freeauthz ) {
+ slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
+ }
+
+ goto done;
+#endif /* HAVE_CYRUS_SASL */
+ }
+
+ *method = mt->mt_idassert_authmethod;
+ switch ( mt->mt_idassert_authmethod ) {
+ case LDAP_AUTH_NONE:
+ BER_BVSTR( binddn, "" );
+ BER_BVSTR( bindcred, "" );
+ /* fallthru */
+
+ case LDAP_AUTH_SIMPLE:
+ break;
+
+ default:
+ /* unsupported! */
+ LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
+ rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
+ break;
+ }
+
+done:;
+ return rs->sr_err;
+}
+
+static int
+meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
+{
+ metainfo_t *mi = (metainfo_t *)op->o_bd->be_private;
+ metatarget_t *mt = mi->mi_targets[ candidate ];
+ metasingleconn_t *msc = &mc->mc_conns[ candidate ];
+ struct berval binddn = BER_BVC( "" ),
+ cred = BER_BVC( "" );
+ int method = LDAP_AUTH_NONE,
+ rc;
+
+ rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, sendok, &binddn, &cred, &method );
+ if ( rc == LDAP_SUCCESS && !LDAP_BACK_CONN_ISBOUND( msc ) ) {
+ int msgid;
+
+ switch ( method ) {
+ case LDAP_AUTH_NONE:
+ case LDAP_AUTH_SIMPLE:
+ rs->sr_err = ldap_sasl_bind( msc->msc_ld,
+ binddn.bv_val, LDAP_SASL_SIMPLE,
+ &cred, NULL, NULL, &msgid );
+ rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok );
+ if ( rc == LDAP_SUCCESS ) {
+ /* set rebind stuff in case of successful proxyAuthz bind,
+ * so that referral chasing is attempted using the right
+ * identity */
+ LDAP_BACK_CONN_ISBOUND_SET( msc );
+ ber_bvreplace( &msc->msc_bound_ndn, &binddn );
+
+ if ( LDAP_BACK_SAVECRED( mi ) ) {
+ if ( !BER_BVISNULL( &msc->msc_cred ) ) {
+ memset( msc->msc_cred.bv_val, 0,
+ msc->msc_cred.bv_len );
+ }
+ ber_bvreplace( &msc->msc_cred, &cred );
+ ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
+ }
+ }
+ break;
+
+ default:
+ assert( 0 );
+ break;
+ }
+ }
+
+ return LDAP_BACK_CONN_ISBOUND( msc );
+}
*/
int
meta_back_is_candidate(
- struct berval *nsuffix,
- int suffixscope,
- BerVarray subtree_exclude,
+ metatarget_t *mt,
struct berval *ndn,
int scope )
{
- if ( dnIsSuffix( ndn, nsuffix ) ) {
- if ( subtree_exclude ) {
+ if ( dnIsSuffix( ndn, &mt->mt_nsuffix ) ) {
+ if ( mt->mt_subtree_exclude ) {
int i;
- for ( i = 0; !BER_BVISNULL( &subtree_exclude[ i ] ); i++ ) {
- if ( dnIsSuffix( ndn, &subtree_exclude[ i ] ) ) {
+ for ( i = 0; !BER_BVISNULL( &mt->mt_subtree_exclude[ i ] ); i++ ) {
+ if ( dnIsSuffix( ndn, &mt->mt_subtree_exclude[ i ] ) ) {
return META_NOT_CANDIDATE;
}
}
}
- switch ( suffixscope ) {
+ switch ( mt->mt_scope ) {
case LDAP_SCOPE_SUBTREE:
default:
return META_CANDIDATE;
case LDAP_SCOPE_SUBORDINATE:
- if ( ndn->bv_len > nsuffix->bv_len ) {
+ if ( ndn->bv_len > mt->mt_nsuffix.bv_len ) {
return META_CANDIDATE;
}
break;
/* nearly useless; not allowed by config */
case LDAP_SCOPE_ONELEVEL:
- if ( ndn->bv_len > nsuffix->bv_len ) {
+ if ( ndn->bv_len > mt->mt_nsuffix.bv_len ) {
struct berval rdn = *ndn;
- rdn.bv_len -= nsuffix->bv_len
+ rdn.bv_len -= mt->mt_nsuffix.bv_len
+ STRLENOF( "," );
if ( dnIsOneLevelRDN( &rdn ) ) {
return META_CANDIDATE;
/* nearly useless; not allowed by config */
case LDAP_SCOPE_BASE:
- if ( ndn->bv_len == nsuffix->bv_len ) {
+ if ( ndn->bv_len == mt->mt_nsuffix.bv_len ) {
return META_CANDIDATE;
}
break;
return META_NOT_CANDIDATE;
}
- if ( scope == LDAP_SCOPE_SUBTREE && dnIsSuffix( nsuffix, ndn ) ) {
+ if ( scope == LDAP_SCOPE_SUBTREE && dnIsSuffix( &mt->mt_nsuffix, ndn ) ) {
/*
* suffix longer than dn, but common part matches
*/
{
int i, candidate = META_TARGET_NONE;
- for ( i = 0; i < mi->mi_ntargets; ++i ) {
- if ( meta_back_is_candidate( &mi->mi_targets[ i ].mt_nsuffix,
- mi->mi_targets[ i ].mt_scope,
- mi->mi_targets[ i ].mt_subtree_exclude,
- ndn, LDAP_SCOPE_BASE ) )
- {
+ for ( i = 0; i < mi->mi_ntargets; i++ ) {
+ metatarget_t *mt = mi->mi_targets[ i ];
+
+ if ( meta_back_is_candidate( mt, ndn, LDAP_SCOPE_BASE ) ) {
if ( candidate == META_TARGET_NONE ) {
candidate = i;
if ( i == candidate ) {
continue;
}
- candidates[ i ].sr_tag = META_NOT_CANDIDATE;
+ META_CANDIDATE_RESET( &candidates[ i ] );
}
return 0;
*/
int
meta_clear_one_candidate(
- metasingleconn_t *msc )
+ Operation *op,
+ metaconn_t *mc,
+ int candidate )
{
- if ( msc->msc_ld ) {
+ metasingleconn_t *msc = &mc->mc_conns[ candidate ];
+
+ if ( msc->msc_ld != NULL ) {
+
+#ifdef DEBUG_205
+ char buf[ BUFSIZ ];
+
+ snprintf( buf, sizeof( buf ), "meta_clear_one_candidate ldap_unbind_ext[%d] mc=%p ld=%p",
+ candidate, (void *)mc, (void *)msc->msc_ld );
+ Debug( LDAP_DEBUG_ANY, "### %s %s\n",
+ op ? op->o_log_prefix : "", buf, 0 );
+#endif /* DEBUG_205 */
+
ldap_unbind_ext( msc->msc_ld, NULL, NULL );
msc->msc_ld = NULL;
}
BER_BVZERO( &msc->msc_cred );
}
- return 0;
-}
-
-/*
- * meta_clear_candidates
- *
- * clears all candidates
- */
-int
-meta_clear_candidates( Operation *op, metaconn_t *mc )
-{
- metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
- int c;
-
- for ( c = 0; c < mi->mi_ntargets; c++ ) {
- if ( mc->mc_conns[ c ].msc_ld != NULL ) {
- meta_clear_one_candidate( &mc->mc_conns[ c ] );
- }
- }
+ msc->msc_mscflags = 0;
return 0;
}
+
int
meta_back_compare( Operation *op, SlapReply *rs )
{
- metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
- metaconn_t *mc = NULL;
- char *match = NULL,
- *err = NULL;
- struct berval mmatch = BER_BVNULL;
- int ncandidates = 0,
- last = 0,
- i,
- count = 0,
- rc,
- cres = LDAP_SUCCESS,
- rres = LDAP_SUCCESS,
- *msgid;
- dncookie dc;
-
- SlapReply *candidates = meta_back_candidates_get( op );
-
- mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_SENDERR );
+ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metatarget_t *mt;
+ metaconn_t *mc;
+ int rc = 0;
+ int candidate = -1;
+ struct berval mdn = BER_BVNULL;
+ dncookie dc;
+ struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname;
+ struct berval mapped_value = op->orc_ava->aa_value;
+ int msgid;
+ int do_retry = 1;
+ LDAPControl **ctrls = NULL;
+
+ mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR );
if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
return rs->sr_err;
}
-
- msgid = ch_calloc( sizeof( int ), mi->mi_ntargets );
- if ( msgid == NULL ) {
- send_ldap_error( op, rs, LDAP_OTHER, NULL );
- rc = LDAP_OTHER;
- goto done;
- }
+
+ assert( mc->mc_conns[ candidate ].msc_ld != NULL );
/*
- * start an asynchronous compare for each candidate target
+ * Rewrite the modify dn, if needed
*/
+ mt = mi->mi_targets[ candidate ];
+ dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
dc.ctx = "compareDN";
- for ( i = 0; i < mi->mi_ntargets; i++ ) {
- struct berval mdn = BER_BVNULL;
- struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname;
- struct berval mapped_value = op->orc_ava->aa_value;
-
- if ( candidates[ i ].sr_tag != META_CANDIDATE ) {
- msgid[ i ] = -1;
- continue;
- }
-
- /*
- * Rewrite the compare dn, if needed
- */
- dc.target = &mi->mi_targets[ i ];
-
- switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
- case LDAP_UNWILLING_TO_PERFORM:
- rc = 1;
- goto finish;
-
- default:
- break;
- }
-
- /*
- * if attr is objectClass, try to remap the value
- */
- if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) {
- ldap_back_map( &mi->mi_targets[ i ].mt_rwmap.rwm_oc,
- &op->orc_ava->aa_value,
- &mapped_value, BACKLDAP_MAP );
-
- if ( BER_BVISNULL( &mapped_value ) || mapped_value.bv_val[0] == '\0' ) {
- continue;
- }
- /*
- * else try to remap the attribute
- */
- } else {
- ldap_back_map( &mi->mi_targets[ i ].mt_rwmap.rwm_at,
- &op->orc_ava->aa_desc->ad_cname,
- &mapped_attr, BACKLDAP_MAP );
- if ( BER_BVISNULL( &mapped_attr ) || mapped_attr.bv_val[0] == '\0' ) {
- continue;
- }
+ switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
+ case LDAP_UNWILLING_TO_PERFORM:
+ rc = 1;
+ goto cleanup;
- if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
- {
- dc.ctx = "compareAttrDN";
-
- switch ( ldap_back_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) )
- {
- case LDAP_UNWILLING_TO_PERFORM:
- rc = 1;
- goto finish;
-
- default:
- break;
- }
- }
- }
-
- /*
- * the compare op is spawned across the targets and the first
- * that returns determines the result; a constraint on unicity
- * of the result ought to be enforced
- */
- rc = ldap_compare_ext( mc->mc_conns[ i ].msc_ld, mdn.bv_val,
- mapped_attr.bv_val, &mapped_value,
- op->o_ctrls, NULL, &msgid[ i ] );
-
- if ( mdn.bv_val != op->o_req_dn.bv_val ) {
- free( mdn.bv_val );
- BER_BVZERO( &mdn );
- }
-
- if ( mapped_attr.bv_val != op->orc_ava->aa_desc->ad_cname.bv_val ) {
- free( mapped_attr.bv_val );
- BER_BVZERO( &mapped_attr );
- }
-
- if ( mapped_value.bv_val != op->orc_ava->aa_value.bv_val ) {
- free( mapped_value.bv_val );
- BER_BVZERO( &mapped_value );
- }
-
- if ( rc != LDAP_SUCCESS ) {
- /* FIXME: what should we do with the error? */
- continue;
- }
-
- ++ncandidates;
+ default:
+ break;
}
/*
- * wait for replies
+ * if attr is objectClass, try to remap the value
*/
- for ( rc = 0, count = 0; ncandidates > 0; ) {
-
- /*
- * FIXME: should we check for abandon?
- */
- for ( i = 0; i < mi->mi_ntargets; i++ ) {
- metasingleconn_t *msc = &mc->mc_conns[ i ];
- int lrc;
- LDAPMessage *res = NULL;
- struct timeval tv;
-
- LDAP_BACK_TV_SET( &tv );
-
- if ( msgid[ i ] == -1 ) {
- continue;
- }
-
- lrc = ldap_result( msc->msc_ld, msgid[ i ],
- LDAP_MSG_ALL, &tv, &res );
-
- if ( lrc == 0 ) {
- assert( res == NULL );
- continue;
-
- } else if ( lrc == -1 ) {
- /* we do not retry in this case;
- * only for unique operations... */
- ldap_get_option( msc->msc_ld,
- LDAP_OPT_ERROR_NUMBER, &rs->sr_err );
- rres = slap_map_api2result( rs );
- rres = rc;
- rc = -1;
- goto finish;
-
- } else if ( lrc == LDAP_RES_COMPARE ) {
- if ( count > 0 ) {
- rres = LDAP_OTHER;
- rc = -1;
- goto finish;
- }
-
- rc = ldap_parse_result( msc->msc_ld, res,
- &rs->sr_err,
- NULL, NULL, NULL, NULL, 1 );
- if ( rc != LDAP_SUCCESS ) {
- rres = rc;
- rc = -1;
- goto finish;
- }
-
- switch ( rs->sr_err ) {
- case LDAP_COMPARE_TRUE:
- case LDAP_COMPARE_FALSE:
-
- /*
- * true or false, got it;
- * sending to cache ...
- */
- if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
- ( void )meta_dncache_update_entry( &mi->mi_cache, &op->o_req_ndn, i );
- }
-
- count++;
- rc = 0;
- break;
-
- default:
- rres = slap_map_api2result( rs );
+ if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) {
+ ldap_back_map( &mt->mt_rwmap.rwm_oc,
+ &op->orc_ava->aa_value,
+ &mapped_value, BACKLDAP_MAP );
- if ( err != NULL ) {
- free( err );
- }
- ldap_get_option( msc->msc_ld,
- LDAP_OPT_ERROR_STRING, &err );
-
- if ( match != NULL ) {
- free( match );
- }
- ldap_get_option( msc->msc_ld,
- LDAP_OPT_MATCHED_DN, &match );
-
- last = i;
- break;
- }
- msgid[ i ] = -1;
- --ncandidates;
-
- } else {
- msgid[ i ] = -1;
- --ncandidates;
- if ( res ) {
- ldap_msgfree( res );
- }
- break;
- }
+ if ( BER_BVISNULL( &mapped_value ) || BER_BVISEMPTY( &mapped_value ) ) {
+ goto cleanup;
}
- }
-
-finish:;
/*
- * Rewrite the matched portion of the search base, if required
- *
- * FIXME: only the last one gets caught!
+ * else try to remap the attribute
*/
- if ( count == 1 ) {
- if ( match != NULL ) {
- free( match );
- match = NULL;
+ } else {
+ ldap_back_map( &mt->mt_rwmap.rwm_at,
+ &op->orc_ava->aa_desc->ad_cname,
+ &mapped_attr, BACKLDAP_MAP );
+ if ( BER_BVISNULL( &mapped_attr ) || BER_BVISEMPTY( &mapped_attr ) ) {
+ goto cleanup;
}
-
- /*
- * the result of the compare is assigned to the res code
- * that will be returned
- */
- rres = cres;
-
- /*
- * At least one compare failed with matched portion,
- * and none was successful
- */
- } else if ( match != NULL && match[ 0 ] != '\0' ) {
- struct berval matched, pmatched;
- ber_str2bv( match, 0, 0, &matched );
+ if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
+ {
+ dc.ctx = "compareAttrDN";
- dc.ctx = "matchedDN";
- ldap_back_dn_massage( &dc, &matched, &mmatch );
- if ( dnPretty( NULL, &mmatch, &pmatched, NULL ) == LDAP_SUCCESS ) {
- if ( mmatch.bv_val != match ) {
- free( mmatch.bv_val );
+ switch ( ldap_back_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) )
+ {
+ case LDAP_UNWILLING_TO_PERFORM:
+ rc = 1;
+ goto cleanup;
+
+ default:
+ break;
}
- mmatch = pmatched;
}
}
- if ( rres != LDAP_SUCCESS ) {
- rs->sr_err = rres;
+retry:;
+ ctrls = op->o_ctrls;
+ rc = ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn,
+ mt->mt_version, &mt->mt_idassert, op, rs, &ctrls );
+ if ( rc != LDAP_SUCCESS ) {
+ send_ldap_result( op, rs );
+ goto cleanup;
}
- rs->sr_matched = mmatch.bv_val;
- send_ldap_result( op, rs );
- rs->sr_matched = NULL;
- if ( match != NULL ) {
- if ( mmatch.bv_val != match ) {
- free( mmatch.bv_val );
+ rs->sr_err = ldap_compare_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val,
+ mapped_attr.bv_val, &mapped_value,
+ ctrls, NULL, &msgid );
+
+ rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
+ mt->mt_timeout[ SLAP_OP_COMPARE ], LDAP_BACK_SENDRESULT );
+ if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
+ do_retry = 0;
+ if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
+ /* if the identity changed, there might be need to re-authz */
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
+ goto retry;
}
- free( match );
}
- if ( msgid ) {
- free( msgid );
+cleanup:;
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
+
+ if ( mdn.bv_val != op->o_req_dn.bv_val ) {
+ free( mdn.bv_val );
+ }
+
+ if ( op->orc_ava->aa_value.bv_val != mapped_value.bv_val ) {
+ free( mapped_value.bv_val );
}
-done:;
- meta_back_release_conn( op, mc );
+ if ( mc ) {
+ meta_back_release_conn( op, mc );
+ }
- return rc;
+ return rs->sr_err;
}
static int
meta_back_new_target(
- metatarget_t *mt )
+ metatarget_t **mtp )
{
- struct ldapmapping *mapping;
char *rargv[ 3 ];
+ metatarget_t *mt;
- memset( mt, 0, sizeof( metatarget_t ) );
+ *mtp = NULL;
+
+ mt = ch_calloc( sizeof( metatarget_t ), 1 );
mt->mt_rwmap.rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
if ( mt->mt_rwmap.rwm_rw == NULL ) {
- return -1;
+ ch_free( mt );
+ return -1;
}
-
/*
* the filter rewrite as a string must be disabled
* by default; it can be re-enabled by adding rules;
rargv[ 2 ] = NULL;
rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv );
- ldap_back_map_init( &mt->mt_rwmap.rwm_at, &mapping );
+ ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex );
+
+ mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY;
+ mt->mt_idassert_authmethod = LDAP_AUTH_NONE;
+ mt->mt_idassert_tls = SB_TLS_DEFAULT;
+
+ /* by default, use proxyAuthz control on each operation */
+ mt->mt_idassert_flags = LDAP_BACK_AUTH_PRESCRIPTIVE;
+
+ *mtp = mt;
return 0;
}
struct berval dn;
int rc;
int c;
+
+ metatarget_t *mt;
switch ( argc ) {
case 1:
++mi->mi_ntargets;
- mi->mi_targets = ( metatarget_t * )ch_realloc( mi->mi_targets,
- sizeof( metatarget_t ) * mi->mi_ntargets );
+ mi->mi_targets = ( metatarget_t ** )ch_realloc( mi->mi_targets,
+ sizeof( metatarget_t * ) * mi->mi_ntargets );
if ( mi->mi_targets == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: out of memory while storing server name"
return 1;
}
- mi->mi_targets[ i ].mt_nretries = mi->mi_nretries;
- mi->mi_targets[ i ].mt_flags = mi->mi_flags;
- mi->mi_targets[ i ].mt_version = mi->mi_version;
- mi->mi_targets[ i ].mt_network_timeout = mi->mi_network_timeout;
- mi->mi_targets[ i ].mt_bind_timeout = mi->mi_bind_timeout;
- for ( c = 0; c < LDAP_BACK_OP_LAST; c++ ) {
- mi->mi_targets[ i ].mt_timeout[ c ] = mi->mi_timeout[ c ];
+ mt = mi->mi_targets[ i ];
+
+ mt->mt_rebind_f = mi->mi_rebind_f;
+ mt->mt_urllist_p = mt;
+
+ mt->mt_nretries = mi->mi_nretries;
+ mt->mt_quarantine = mi->mi_quarantine;
+ if ( META_BACK_QUARANTINE( mi ) ) {
+ ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
+ }
+ mt->mt_flags = mi->mi_flags;
+ mt->mt_version = mi->mi_version;
+ mt->mt_network_timeout = mi->mi_network_timeout;
+ mt->mt_bind_timeout = mi->mi_bind_timeout;
+ for ( c = 0; c < SLAP_OP_LAST; c++ ) {
+ mt->mt_timeout[ c ] = mi->mi_timeout[ c ];
}
/*
* uri MUST be legal!
*/
- if ( ldap_url_parselist_ext( &ludp, argv[ 1 ], "\t" ) != LDAP_SUCCESS ) {
+ if ( ldap_url_parselist_ext( &ludp, argv[ 1 ], "\t" ) != LDAP_SUCCESS )
+ {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: unable to parse URI"
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
* copies and stores uri and suffix
*/
ber_str2bv( ludp->lud_dn, 0, 0, &dn );
- rc = dnPrettyNormal( NULL, &dn, &mi->mi_targets[ i ].mt_psuffix,
- &mi->mi_targets[ i ].mt_nsuffix, NULL );
+ rc = dnPrettyNormal( NULL, &dn, &mt->mt_psuffix,
+ &mt->mt_nsuffix, NULL );
if( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
"target \"%s\" DN is invalid\n",
switch ( ludp->lud_scope ) {
case LDAP_SCOPE_DEFAULT:
- mi->mi_targets[ i ].mt_scope = LDAP_SCOPE_SUBTREE;
+ mt->mt_scope = LDAP_SCOPE_SUBTREE;
break;
case LDAP_SCOPE_SUBTREE:
case LDAP_SCOPE_SUBORDINATE:
- mi->mi_targets[ i ].mt_scope = ludp->lud_scope;
+ mt->mt_scope = ludp->lud_scope;
break;
default:
}
}
- mi->mi_targets[ i ].mt_uri = ldap_url_list2urls( ludp );
+ mt->mt_uri = ldap_url_list2urls( ludp );
ldap_free_urllist( ludp );
- if ( mi->mi_targets[ i ].mt_uri == NULL) {
+ if ( mt->mt_uri == NULL) {
Debug( LDAP_DEBUG_ANY, "%s: line %d: no memory?\n",
fname, lineno, 0 );
return( 1 );
* uri MUST be a branch of suffix!
*/
#if 0 /* too strict a constraint */
- if ( select_backend( &mi->mi_targets[ i ].suffix, 0, 0 ) != be ) {
+ if ( select_backend( &mt->mt_nsuffix, 0, 0 ) != be ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: <naming context> of URI does not refer to current backend"
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
/*
* uri MUST be a branch of a suffix!
*/
- if ( select_backend( &mi->mi_targets[ i ].mt_nsuffix, 0, 0 ) == NULL ) {
+ if ( select_backend( &mt->mt_nsuffix, 0, 0 ) == NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: <naming context> of URI does not resolve to a backend"
" in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
return( 1 );
}
- if ( !dnIsSuffix( &ndn, &mi->mi_targets[ i ].mt_nsuffix ) ) {
+ if ( !dnIsSuffix( &ndn, &mi->mi_targets[ i ]->mt_nsuffix ) ) {
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
"subtree-exclude DN=\"%s\" "
"must be subtree of target\n",
return( 1 );
}
- if ( mi->mi_targets[ i ].mt_subtree_exclude != NULL ) {
+ if ( mi->mi_targets[ i ]->mt_subtree_exclude != NULL ) {
int j;
- for ( j = 0; !BER_BVISNULL( &mi->mi_targets[ i ].mt_subtree_exclude[ j ] ); j++ )
+ for ( j = 0; !BER_BVISNULL( &mi->mi_targets[ i ]->mt_subtree_exclude[ j ] ); j++ )
{
- if ( dnIsSuffix( &mi->mi_targets[ i ].mt_subtree_exclude[ j ], &ndn ) ) {
+ if ( dnIsSuffix( &mi->mi_targets[ i ]->mt_subtree_exclude[ j ], &ndn ) ) {
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
"subtree-exclude DN=\"%s\" "
"is suffix of another subtree-exclude\n",
ber_memfree( ndn.bv_val );
return( 1 );
- } else if ( dnIsSuffix( &ndn, &mi->mi_targets[ i ].mt_subtree_exclude[ j ] ) ) {
+ } else if ( dnIsSuffix( &ndn, &mi->mi_targets[ i ]->mt_subtree_exclude[ j ] ) ) {
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
"another subtree-exclude is suffix of "
"subtree-exclude DN=\"%s\"\n",
}
}
- ber_bvarray_add( &mi->mi_targets[ i ].mt_subtree_exclude, &ndn );
+ ber_bvarray_add( &mi->mi_targets[ i ]->mt_subtree_exclude, &ndn );
/* default target directive */
} else if ( strcasecmp( argv[ 0 ], "default-target" ) == 0 ) {
} else if ( strcasecmp( argv[ 0 ], "network-timeout" ) == 0 ) {
unsigned long t;
time_t *tp = mi->mi_ntargets ?
- &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_network_timeout
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_network_timeout
: &mi->mi_network_timeout;
if ( argc != 2 ) {
} else if ( strcasecmp( argv[ 0 ], "bind-timeout" ) == 0 ) {
unsigned long t;
struct timeval *tp = mi->mi_ntargets ?
- &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_bind_timeout
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_bind_timeout
: &mi->mi_bind_timeout;
switch ( argc ) {
}
ber_str2bv( argv[ 1 ], 0, 0, &dn );
- if ( dnNormalize( 0, NULL, NULL, &dn, &mi->mi_targets[ i ].mt_binddn,
+ if ( dnNormalize( 0, NULL, NULL, &dn, &mi->mi_targets[ i ]->mt_binddn,
NULL ) != LDAP_SUCCESS )
{
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
/* FIXME: some day we'll need to throw an error */
}
- ber_str2bv( argv[ 1 ], 0L, 1, &mi->mi_targets[ i ].mt_bindpw );
+ ber_str2bv( argv[ 1 ], 0L, 1, &mi->mi_targets[ i ]->mt_bindpw );
/* save bind creds for referral rebinds? */
} else if ( strcasecmp( argv[ 0 ], "rebind-as-user" ) == 0 ) {
} else if ( strcasecmp( argv[ 0 ], "chase-referrals" ) == 0 ) {
unsigned *flagsp = mi->mi_ntargets ?
- &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_flags
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
: &mi->mi_flags;
if ( argc != 2 ) {
} else if ( strcasecmp( argv[ 0 ], "tls" ) == 0 ) {
unsigned *flagsp = mi->mi_ntargets ?
- &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_flags
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
: &mi->mi_flags;
if ( argc != 2 ) {
} else if ( strcasecmp( argv[ 0 ], "t-f-support" ) == 0 ) {
unsigned *flagsp = mi->mi_ntargets ?
- &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_flags
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
: &mi->mi_flags;
if ( argc != 2 ) {
switch ( check_true_false( argv[ 1 ] ) ) {
case 0:
- *flagsp &= ~(LDAP_BACK_F_SUPPORT_T_F|LDAP_BACK_F_SUPPORT_T_F_DISCOVER);
+ *flagsp &= ~LDAP_BACK_F_T_F_MASK2;
break;
case 1:
- *flagsp |= LDAP_BACK_F_SUPPORT_T_F;
+ *flagsp |= LDAP_BACK_F_T_F;
break;
default:
if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
- *flagsp |= LDAP_BACK_F_SUPPORT_T_F_DISCOVER;
+ *flagsp |= LDAP_BACK_F_T_F_DISCOVER;
} else {
Debug( LDAP_DEBUG_ANY,
} else if ( strcasecmp( argv[ 0 ], "onerr" ) == 0 ) {
if ( argc != 2 ) {
Debug( LDAP_DEBUG_ANY,
- "%s: line %d: \"onerr {CONTINUE|stop}\" takes 1 argument\n",
+ "%s: line %d: \"onerr {CONTINUE|report|stop}\" takes 1 argument\n",
fname, lineno, 0 );
return( 1 );
}
if ( strcasecmp( argv[ 1 ], "continue" ) == 0 ) {
- mi->mi_flags &= ~META_BACK_F_ONERR_STOP;
+ mi->mi_flags &= ~META_BACK_F_ONERR_MASK;
} else if ( strcasecmp( argv[ 1 ], "stop" ) == 0 ) {
mi->mi_flags |= META_BACK_F_ONERR_STOP;
+ } else if ( strcasecmp( argv[ 1 ], "report" ) == 0 ) {
+ mi->mi_flags |= META_BACK_F_ONERR_REPORT;
+
} else {
Debug( LDAP_DEBUG_ANY,
- "%s: line %d: \"onerr {CONTINUE|stop}\": invalid arg \"%s\".\n",
+ "%s: line %d: \"onerr {CONTINUE|report|stop}\": invalid arg \"%s\".\n",
fname, lineno, argv[ 1 ] );
return 1;
}
/* bind-defer? */
- } else if ( strcasecmp( argv[ 0 ], "pseudoroot-bind-defer" ) == 0 ) {
+ } else if ( strcasecmp( argv[ 0 ], "pseudoroot-bind-defer" ) == 0
+ || strcasecmp( argv[ 0 ], "root-bind-defer" ) == 0 )
+ {
if ( argc != 2 ) {
Debug( LDAP_DEBUG_ANY,
- "%s: line %d: \"pseudoroot-bind-defer {FALSE|true}\" takes 1 argument\n",
+ "%s: line %d: \"[pseudo]root-bind-defer {FALSE|true}\" takes 1 argument\n",
fname, lineno, 0 );
return( 1 );
}
default:
Debug( LDAP_DEBUG_ANY,
- "%s: line %d: \"pseudoroot-bind-defer {FALSE|true}\": invalid arg \"%s\".\n",
+ "%s: line %d: \"[pseudo]root-bind-defer {FALSE|true}\": invalid arg \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ /* single-conn? */
+ } else if ( strcasecmp( argv[ 0 ], "single-conn" ) == 0 ) {
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"single-conn {FALSE|true}\" takes 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( mi->mi_ntargets > 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"single-conn\" must appear before target definitions\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ switch ( check_true_false( argv[ 1 ] ) ) {
+ case 0:
+ mi->mi_flags &= ~LDAP_BACK_F_SINGLECONN;
+ break;
+
+ case 1:
+ mi->mi_flags |= LDAP_BACK_F_SINGLECONN;
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"single-conn {FALSE|true}\": invalid arg \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ /* use-temporaries? */
+ } else if ( strcasecmp( argv[ 0 ], "use-temporary-conn" ) == 0 ) {
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"use-temporary-conn {FALSE|true}\" takes 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( mi->mi_ntargets > 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"use-temporary-conn\" must appear before target definitions\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ switch ( check_true_false( argv[ 1 ] ) ) {
+ case 0:
+ mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
+ break;
+
+ case 1:
+ mi->mi_flags |= LDAP_BACK_F_USE_TEMPORARIES;
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"use-temporary-conn {FALSE|true}\": invalid arg \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
+ /* privileged connections pool max size ? */
+ } else if ( strcasecmp( argv[ 0 ], "conn-pool-max" ) == 0 ) {
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"conn-pool-max <n>\" takes 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( mi->mi_ntargets > 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"conn-pool-max\" must appear before target definitions\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( lutil_atoi( &mi->mi_conn_priv_max, argv[1] )
+ || mi->mi_conn_priv_max < LDAP_BACK_CONN_PRIV_MIN
+ || mi->mi_conn_priv_max > LDAP_BACK_CONN_PRIV_MAX )
+ {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"conn-pool-max <n>\": invalid arg \"%s\".\n",
fname, lineno, argv[ 1 ] );
return 1;
}
+ } else if ( strcasecmp( argv[ 0 ], "cancel" ) == 0 ) {
+ unsigned flag = 0;
+ unsigned *flagsp = mi->mi_ntargets ?
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
+ : &mi->mi_flags;
+
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"cancel {abandon|ignore|exop}\" takes 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( strcasecmp( argv[ 1 ], "abandon" ) == 0 ) {
+ flag = LDAP_BACK_F_CANCEL_ABANDON;
+
+#if 0 /* needs ldap_int_discard(), 2.4 */
+ } else if ( strcasecmp( argv[ 1 ], "ignore" ) == 0 ) {
+ flag = LDAP_BACK_F_CANCEL_IGNORE;
+#endif
+
+ } else if ( strcasecmp( argv[ 1 ], "exop" ) == 0 ) {
+ flag = LDAP_BACK_F_CANCEL_EXOP;
+
+ } else if ( strcasecmp( argv[ 1 ], "exop-discover" ) == 0 ) {
+ flag = LDAP_BACK_F_CANCEL_EXOP_DISCOVER;
+
+ } else {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"cancel {abandon|ignore|exop[-discover]}\": unknown mode \"%s\" \n",
+ fname, lineno, argv[ 1 ] );
+ return( 1 );
+ }
+
+ *flagsp &= ~LDAP_BACK_F_CANCEL_MASK2;
+ *flagsp |= flag;
+
} else if ( strcasecmp( argv[ 0 ], "timeout" ) == 0 ) {
char *sep;
time_t *tv = mi->mi_ntargets ?
- mi->mi_targets[ mi->mi_ntargets - 1 ].mt_timeout
+ mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_timeout
: mi->mi_timeout;
int c;
if ( argc < 2 ) {
Debug( LDAP_DEBUG_ANY,
- "%s: line %d: \"timeout [{add|delete|modify|modrdn}=]<val> [...]\" takes at least 1 argument\n",
+ "%s: line %d: \"timeout [{add|bind|delete|modify|modrdn}=]<val> [...]\" takes at least 1 argument\n",
fname, lineno, 0 );
return( 1 );
}
if ( sep != NULL ) {
size_t len = sep - argv[ c ];
- if ( strncasecmp( argv[ c ], "add", len ) == 0 ) {
- t = &tv[ LDAP_BACK_OP_ADD ];
+ if ( strncasecmp( argv[ c ], "bind", len ) == 0 ) {
+ t = &tv[ SLAP_OP_BIND ];
+ /* unbind makes little sense */
+ } else if ( strncasecmp( argv[ c ], "add", len ) == 0 ) {
+ t = &tv[ SLAP_OP_ADD ];
} else if ( strncasecmp( argv[ c ], "delete", len ) == 0 ) {
- t = &tv[ LDAP_BACK_OP_DELETE ];
- } else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) {
- t = &tv[ LDAP_BACK_OP_MODIFY ];
+ t = &tv[ SLAP_OP_DELETE ];
} else if ( strncasecmp( argv[ c ], "modrdn", len ) == 0 ) {
- t = &tv[ LDAP_BACK_OP_MODRDN ];
+ t = &tv[ SLAP_OP_MODRDN ];
+ } else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) {
+ t = &tv[ SLAP_OP_MODIFY ];
+ } else if ( strncasecmp( argv[ c ], "compare", len ) == 0 ) {
+ t = &tv[ SLAP_OP_COMPARE ];
+#if 0 /* uses timelimit instead */
+ } else if ( strncasecmp( argv[ c ], "search", len ) == 0 ) {
+ t = &tv[ SLAP_OP_SEARCH ];
+#endif
+ /* abandon makes little sense */
+#if 0 /* not implemented yet */
+ } else if ( strncasecmp( argv[ c ], "extended", len ) == 0 ) {
+ t = &tv[ SLAP_OP_EXTENDED ];
+#endif
} else {
char buf[ SLAP_TEXT_BUFLEN ];
snprintf( buf, sizeof( buf ),
- "unknown operation \"%s\" for timeout #%d",
- argv[ c ], c );
+ "unknown/unhandled operation \"%s\" for timeout #%d",
+ argv[ c ], c - 1 );
Debug( LDAP_DEBUG_ANY,
"%s: line %d: %s.\n",
fname, lineno, buf );
} else {
int i;
- for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) {
+ for ( i = 0; i < SLAP_OP_LAST; i++ ) {
tv[ i ] = (time_t)val;
}
}
/* name to use as pseudo-root dn */
} else if ( strcasecmp( argv[ 0 ], "pseudorootdn" ) == 0 ) {
int i = mi->mi_ntargets - 1;
- struct berval dn;
if ( i < 0 ) {
Debug( LDAP_DEBUG_ANY,
return 1;
}
- dn.bv_val = argv[ 1 ];
- dn.bv_len = strlen( argv[ 1 ] );
- if ( dnNormalize( 0, NULL, NULL, &dn,
- &mi->mi_targets[ i ].mt_pseudorootdn, NULL ) != LDAP_SUCCESS )
+ /*
+ * exact replacement:
+ *
+
+idassert-bind bindmethod=simple
+ binddn=<pseudorootdn>
+ credentials=<pseudorootpw>
+ mode=none
+ flags=non-prescriptive
+idassert-authzFrom "dn:<rootdn>"
+
+ * so that only when authc'd as <rootdn> the proxying occurs
+ * rebinding as the <pseudorootdn> without proxyAuthz.
+ */
+
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
+ "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
+ fname, lineno, 0 );
+
{
- Debug( LDAP_DEBUG_ANY, "%s: line %d: "
- "pseudoroot DN '%s' is invalid\n",
- fname, lineno, argv[ 1 ] );
- return( 1 );
+ char binddn[ SLAP_TEXT_BUFLEN ];
+ char *cargv[] = {
+ "idassert-bind",
+ "bindmethod=simple",
+ NULL,
+ "mode=none",
+ "flags=non-prescriptive",
+ NULL
+ };
+ int cargc = 5;
+ int rc;
+
+ if ( BER_BVISNULL( &be->be_rootndn ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootpw\": \"rootdn\" must be defined first.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( snprintf( binddn, sizeof( binddn ), "binddn=%s", argv[ 1 ] ) >= sizeof( binddn ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootdn\" too long.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+ cargv[ 2 ] = binddn;
+
+ rc = slap_idassert_parse_cf( fname, lineno, cargc, cargv, &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert );
+ if ( rc == 0 ) {
+ struct berval bv;
+
+ if ( mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz != NULL ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: \"idassert-authzFrom\" already defined (discarded).\n",
+ fname, lineno, 0 );
+ ber_bvarray_free( mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz );
+ mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz = NULL;
+ }
+
+ assert( !BER_BVISNULL( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authcDN ) );
+
+ bv.bv_len = STRLENOF( "dn:" ) + be->be_rootndn.bv_len;
+ bv.bv_val = ber_memalloc( bv.bv_len + 1 );
+ AC_MEMCPY( bv.bv_val, "dn:", STRLENOF( "dn:" ) );
+ AC_MEMCPY( &bv.bv_val[ STRLENOF( "dn:" ) ], be->be_rootndn.bv_val, be->be_rootndn.bv_len + 1 );
+
+ ber_bvarray_add( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz, &bv );
+ }
+
+ return rc;
}
/* password to use as pseudo-root */
fname, lineno, 0 );
return 1;
}
- ber_str2bv( argv[ 1 ], 0L, 1, &mi->mi_targets[ i ].mt_pseudorootpw );
+
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
+ "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
+ fname, lineno, 0 );
+
+ if ( BER_BVISNULL( &mi->mi_targets[ i ]->mt_idassert_authcDN ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootpw\": \"pseudorootdn\" must be defined first.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( !BER_BVISNULL( &mi->mi_targets[ i ]->mt_idassert_passwd ) ) {
+ memset( mi->mi_targets[ i ]->mt_idassert_passwd.bv_val, 0,
+ mi->mi_targets[ i ]->mt_idassert_passwd.bv_len );
+ ber_memfree( mi->mi_targets[ i ]->mt_idassert_passwd.bv_val );
+ }
+ ber_str2bv( argv[ 1 ], 0, 1, &mi->mi_targets[ i ]->mt_idassert_passwd );
+
+ /* idassert-bind */
+ } else if ( strcasecmp( argv[ 0 ], "idassert-bind" ) == 0 ) {
+ if ( mi->mi_ntargets == 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"idassert-bind\" "
+ "must appear inside a target specification.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ return slap_idassert_parse_cf( fname, lineno, argc, argv, &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert );
+
+ /* idassert-authzFrom */
+ } else if ( strcasecmp( argv[ 0 ], "idassert-authzFrom" ) == 0 ) {
+ if ( mi->mi_ntargets == 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"idassert-bind\" "
+ "must appear inside a target specification.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ switch ( argc ) {
+ case 2:
+ break;
+
+ case 1:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing <id> in \"idassert-authzFrom <id>\".\n",
+ fname, lineno, 0 );
+ return 1;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: extra cruft after <id> in \"idassert-authzFrom <id>\".\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ return slap_idassert_authzfrom_parse_cf( fname, lineno, argv[ 1 ], &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert );
+
+ /* quarantine */
+ } else if ( strcasecmp( argv[ 0 ], "quarantine" ) == 0 ) {
+ char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
+ slap_retry_info_t *ri = mi->mi_ntargets ?
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_quarantine
+ : &mi->mi_quarantine;
+
+ if ( ( mi->mi_ntargets == 0 && META_BACK_QUARANTINE( mi ) )
+ || ( mi->mi_ntargets > 0 && META_BACK_TGT_QUARANTINE( mi->mi_targets[ mi->mi_ntargets - 1 ] ) ) )
+ {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: quarantine already defined.\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ switch ( argc ) {
+ case 2:
+ break;
+
+ case 1:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing arg in \"quarantine <pattern list>\".\n",
+ fname, lineno, 0 );
+ return 1;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: extra cruft after \"quarantine <pattern list>\".\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( ri != &mi->mi_quarantine ) {
+ ri->ri_interval = NULL;
+ ri->ri_num = NULL;
+ }
+
+ if ( mi->mi_ntargets > 0 && !META_BACK_QUARANTINE( mi ) ) {
+ ldap_pvt_thread_mutex_init( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_quarantine_mutex );
+ }
+
+ if ( slap_retry_info_parse( argv[ 1 ], ri, buf, sizeof( buf ) ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s line %d: %s.\n",
+ fname, lineno, buf );
+ return 1;
+ }
/* dn massaging */
} else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) {
* FIXME: no extra rewrite capabilities should be added
* to the database
*/
- rc = suffix_massage_config( mi->mi_targets[ i ].mt_rwmap.rwm_rw,
+ rc = suffix_massage_config( mi->mi_targets[ i ]->mt_rwmap.rwm_rw,
&pvnc, &nvnc, &prnc, &nrnc );
free( pvnc.bv_val );
return 1;
}
- return rewrite_parse( mi->mi_targets[ i ].mt_rwmap.rwm_rw,
+ return rewrite_parse( mi->mi_targets[ i ]->mt_rwmap.rwm_rw,
fname, lineno, argc, argv );
/* objectclass/attribute mapping */
return 1;
}
- return ldap_back_map_config( &mi->mi_targets[ i ].mt_rwmap.rwm_oc,
- &mi->mi_targets[ i ].mt_rwmap.rwm_at,
+ return ldap_back_map_config( &mi->mi_targets[ i ]->mt_rwmap.rwm_oc,
+ &mi->mi_targets[ i ]->mt_rwmap.rwm_at,
fname, lineno, argc, argv );
} else if ( strcasecmp( argv[ 0 ], "nretries" ) == 0 ) {
mi->mi_nretries = nretries;
} else {
- mi->mi_targets[ i ].mt_nretries = nretries;
+ mi->mi_targets[ i ]->mt_nretries = nretries;
}
} else if ( strcasecmp( argv[ 0 ], "protocol-version" ) == 0 ) {
int *version = mi->mi_ntargets ?
- &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_version
+ &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_version
: &mi->mi_version;
if ( argc != 2 ) {
if ( strcmp( argv[ 2 ], "*" ) == 0 ) {
if ( argc < 4 || strcmp( argv[ 3 ], "*" ) == 0 ) {
map->drop_missing = ( argc < 4 );
- return 0;
+ goto success_return;
}
src = dst = argv[ 3 ];
}
if ( ( map == at_map )
- && ( strcasecmp( src, "objectclass" ) == 0
+ && ( strcasecmp( src, "objectclass" ) == 0
|| strcasecmp( dst, "objectclass" ) == 0 ) )
{
Debug( LDAP_DEBUG_ANY,
avl_insert( &map->remap, (caddr_t)&mapping[ 1 ],
mapping_cmp, mapping_dup );
+success_return:;
+ if ( !is_oc && map->map == NULL ) {
+ /* only init if required */
+ ldap_back_map_init( map, &mapping );
+ }
+
return 0;
error_return:;
#include "../back-ldap/back-ldap.h"
#include "back-meta.h"
-/*
- * Set PRINT_CONNTREE larger than 0 to dump the connection tree (debug only)
- */
-#define PRINT_CONNTREE 0
-
/*
* meta_back_conndn_cmp
*
/*
* Debug stuff (got it from libavl)
*/
-#if PRINT_CONNTREE > 0
+#if META_BACK_PRINT_CONNTREE > 0
static void
-ravl_print( Avlnode *root, int depth )
+meta_back_ravl_print( Avlnode *root, int depth )
{
int i;
- metaconn_t *mc = (metaconn_t *)root->avl_data;
+ metaconn_t *mc;
if ( root == 0 ) {
return;
}
- ravl_print( root->avl_right, depth + 1 );
+ meta_back_ravl_print( root->avl_right, depth + 1 );
for ( i = 0; i < depth; i++ ) {
- printf( " " );
+ fprintf( stderr, "-" );
}
- printf( "c(%d%s%s) %d\n",
- LDAP_BACK_PCONN_ID( mc->mc_conn ),
- BER_BVISNULL( &mc->mc_local_ndn ) ? "" : ": ",
- BER_BVISNULL( &mc->mc_local_ndn ) ? "" : mc->mc_local_ndn.bv_val,
- root->avl_bf );
+ mc = (metaconn_t *)root->avl_data;
+ fprintf( stderr, "mc=%p local=\"%s\" conn=%p %s refcnt=%d%s\n",
+ (void *)mc,
+ mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "",
+ (void *)mc->mc_conn,
+ avl_bf2str( root->avl_bf ), mc->mc_refcnt,
+ LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "" );
- ravl_print( root->avl_left, depth + 1 );
+ meta_back_ravl_print( root->avl_left, depth + 1 );
}
-static void
-myprint( Avlnode *root )
+/* NOTE: duplicate from back-ldap/bind.c */
+static char* priv2str[] = {
+ "privileged",
+ "privileged/TLS",
+ "anonymous",
+ "anonymous/TLS",
+ "bind",
+ "bind/TLS",
+ NULL
+};
+
+void
+meta_back_print_conntree( metainfo_t *mi, char *msg )
{
- printf( "********\n" );
+ int c;
+
+ fprintf( stderr, "========> %s\n", msg );
- if ( root == 0 ) {
- printf( "\tNULL\n" );
+ for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
+ int i = 0;
+ metaconn_t *mc;
+
+ fprintf( stderr, " %s[%d]\n", priv2str[ c ], mi->mi_conn_priv[ c ].mic_num );
+
+ LDAP_TAILQ_FOREACH( mc, &mi->mi_conn_priv[ c ].mic_priv, mc_q )
+ {
+ fprintf( stderr, " [%d] mc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",
+ i,
+ (void *)mc,
+ mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "",
+ (void *)mc->mc_conn, mc->mc_refcnt, mc->msc_mscflags );
+ i++;
+ }
+ }
+
+ if ( mi->mi_conninfo.lai_tree == NULL ) {
+ fprintf( stderr, "\t(empty)\n" );
+
} else {
- ravl_print( root, 0 );
+ meta_back_ravl_print( mi->mi_conninfo.lai_tree, 0 );
}
- printf( "********\n" );
+ fprintf( stderr, "<======== %s\n", msg );
}
-#endif /* PRINT_CONNTREE */
+#endif /* META_BACK_PRINT_CONNTREE */
/*
* End of debug stuff
*/
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metaconn_t *mc;
- int i, ntargets = mi->mi_ntargets;
+ int ntargets = mi->mi_ntargets;
assert( ntargets > 0 );
/* malloc all in one */
- mc = ( metaconn_t * )ch_malloc( sizeof( metaconn_t )
- + sizeof( metasingleconn_t ) * ntargets );
+ mc = ( metaconn_t * )ch_calloc( 1, sizeof( metaconn_t )
+ + sizeof( metasingleconn_t ) * ( ntargets - 1 ) );
if ( mc == NULL ) {
return NULL;
}
- for ( i = 0; i < ntargets; i++ ) {
- mc->mc_conns[ i ].msc_ld = NULL;
- BER_BVZERO( &mc->mc_conns[ i ].msc_bound_ndn );
- BER_BVZERO( &mc->mc_conns[ i ].msc_cred );
- mc->mc_conns[ i ].msc_mscflags = 0;
- mc->mc_conns[ i ].msc_info = mi;
- }
+ mc->mc_info = mi;
- BER_BVZERO( &mc->mc_local_ndn );
- mc->msc_mscflags = 0;
mc->mc_authz_target = META_BOUND_NONE;
mc->mc_refcnt = 1;
return mc;
}
-static void
-meta_back_freeconn(
- Operation *op,
- metaconn_t *mc )
-{
- metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
-
- assert( mc != NULL );
-
- ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
-
- if ( --mc->mc_refcnt == 0 ) {
- meta_back_conn_free( mc );
- }
-
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
-}
-
/*
* meta_back_init_one_conn
*
meta_back_init_one_conn(
Operation *op,
SlapReply *rs,
- metatarget_t *mt,
metaconn_t *mc,
int candidate,
int ispriv,
- ldap_back_send_t sendok )
+ ldap_back_send_t sendok,
+ int dolock )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metatarget_t *mt = mi->mi_targets[ candidate ];
metasingleconn_t *msc = &mc->mc_conns[ candidate ];
int version;
dncookie dc;
int isauthz = ( candidate == mc->mc_authz_target );
+ int do_return = 0;
+#ifdef HAVE_TLS
+ int is_ldaps = 0;
+#endif /* HAVE_TLS */
+
+ /* if the server is quarantined, and
+ * - the current interval did not expire yet, or
+ * - no more retries should occur,
+ * don't return the connection */
+ if ( mt->mt_isquarantined ) {
+ slap_retry_info_t *ri = &mt->mt_quarantine;
+ int dont_retry = 1;
+
+ if ( mt->mt_isquarantined == LDAP_BACK_FQ_YES ) {
+ dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
+ || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
+ if ( !dont_retry ) {
+ if ( StatslogTest( LDAP_DEBUG_ANY ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "meta_back_init_one_conn[%d]: quarantine "
+ "retry block #%d try #%d",
+ candidate, ri->ri_idx, ri->ri_count );
+ Debug( LDAP_DEBUG_ANY, "%s %s.\n",
+ op->o_log_prefix, buf, 0 );
+ }
+
+ mt->mt_isquarantined = LDAP_BACK_FQ_RETRYING;
+ }
+ }
+
+ if ( dont_retry ) {
+ rs->sr_err = LDAP_UNAVAILABLE;
+ if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
+ send_ldap_result( op, rs );
+ }
+ return rs->sr_err;
+ }
+ }
+
+retry_lock:;
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ }
/*
* Already init'ed
*/
- if ( msc->msc_ld != NULL ) {
- return rs->sr_err = LDAP_SUCCESS;
+ if ( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc ) )
+ {
+ assert( msc->msc_ld != NULL );
+ rs->sr_err = LDAP_SUCCESS;
+ do_return = 1;
+
+ } else if ( META_BACK_CONN_CREATING( msc )
+ || LDAP_BACK_CONN_BINDING( msc ) )
+ {
+ if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ }
+
+ ldap_pvt_thread_yield();
+ goto retry_lock;
+ }
+
+ /* sounds more appropriate */
+ rs->sr_err = LDAP_BUSY;
+ do_return = 1;
+
+ } else if ( META_BACK_CONN_INITED( msc ) ) {
+ assert( msc->msc_ld != NULL );
+ rs->sr_err = LDAP_SUCCESS;
+ do_return = 1;
+
+ } else {
+ /*
+ * creating...
+ */
+ META_BACK_CONN_CREATING_SET( msc );
+ }
+
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
}
- msc->msc_mscflags = 0;
+ if ( do_return ) {
+ if ( rs->sr_err != LDAP_SUCCESS && op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
+ send_ldap_result( op, rs );
+ }
+
+ return rs->sr_err;
+ }
+
+ assert( msc->msc_ld == NULL );
/*
* Attempts to initialize the connection to the target ds
*/
+ ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
rs->sr_err = ldap_initialize( &msc->msc_ld, mt->mt_uri );
+#ifdef HAVE_TLS
+ is_ldaps = ldap_is_ldaps_url( mt->mt_uri );
+#endif /* HAVE_TLS */
+ ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
if ( rs->sr_err != LDAP_SUCCESS ) {
goto error_return;
}
#ifdef HAVE_TLS
/* start TLS ("tls [try-]{start|propagate}" statement) */
if ( ( LDAP_BACK_USE_TLS( mi ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( mi ) ) )
- && !ldap_is_ldaps_url( mt->mt_uri ) )
+ && !is_ldaps )
{
#ifdef SLAP_STARTTLS_ASYNCHRONOUS
/*
retry:;
rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
- if ( rc < 0 ) {
+ switch ( rc ) {
+ case -1:
rs->sr_err = LDAP_OTHER;
+ break;
- } else if ( rc == 0 ) {
+ case 0:
if ( nretries != 0 ) {
if ( nretries > 0 ) {
nretries--;
goto retry;
}
rs->sr_err = LDAP_OTHER;
+ break;
- } else if ( rc == LDAP_RES_EXTENDED ) {
+ default:
+ /* only touch when activity actually took place... */
+ if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
+ msc->msc_time = op->o_time;
+ }
+ break;
+ }
+
+ if ( rc == LDAP_RES_EXTENDED ) {
struct berval *data = NULL;
+ /* NOTE: right now, data is unused, so don't get it */
rs->sr_err = ldap_parse_extended_result( msc->msc_ld, res,
- NULL, &data, 0 );
+ NULL, NULL /* &data */ , 0 );
if ( rs->sr_err == LDAP_SUCCESS ) {
int err;
+ /* FIXME: matched? referrals? response controls? */
rs->sr_err = ldap_parse_result( msc->msc_ld, res,
&err, NULL, NULL, NULL, NULL, 1 );
res = NULL;
ldap_install_tls( msc->msc_ld );
} else if ( rs->sr_err == LDAP_REFERRAL ) {
+ /* FIXME: LDAP_OPERATIONS_ERROR? */
rs->sr_err = LDAP_OTHER;
rs->sr_text = "unwilling to chase referral returned by Start TLS exop";
}
if ( rs->sr_err == LDAP_SERVER_DOWN
|| ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( mi ) ) )
{
- ldap_unbind_ext_s( msc->msc_ld, NULL, NULL );
+
+#ifdef DEBUG_205
+ Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(TLS) ldap_unbind_ext[%d] ld=%p\n",
+ op->o_log_prefix, candidate, (void *)msc->msc_ld );
+#endif /* DEBUG_205 */
+
+ /* need to trash a failed Start TLS */
+ meta_clear_one_candidate( op, mc, candidate );
goto error_return;
}
}
*/
if ( ispriv ) {
- if ( !BER_BVISNULL( &mt->mt_pseudorootdn ) ) {
- ber_dupbv( &msc->msc_bound_ndn, &mt->mt_pseudorootdn );
- if ( !BER_BVISNULL( &mt->mt_pseudorootpw ) ) {
- ber_dupbv( &msc->msc_cred, &mt->mt_pseudorootpw );
+ if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {
+ ber_bvreplace( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN );
+ if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {
+ if ( !BER_BVISNULL( &msc->msc_cred ) ) {
+ memset( msc->msc_cred.bv_val, 0,
+ msc->msc_cred.bv_len );
+ }
+ ber_bvreplace( &msc->msc_cred, &mt->mt_idassert_passwd );
}
} else {
- ber_str2bv( "", 0, 1, &msc->msc_bound_ndn );
+ ber_bvreplace( &msc->msc_bound_ndn, &slap_empty_bv );
}
- LDAP_BACK_CONN_ISPRIV_SET( msc );
-
} else {
- BER_BVZERO( &msc->msc_cred );
- BER_BVZERO( &msc->msc_bound_ndn );
+ if ( !BER_BVISNULL( &msc->msc_cred ) ) {
+ memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
+ ber_memfree_x( msc->msc_cred.bv_val, NULL );
+ BER_BVZERO( &msc->msc_cred );
+ }
+ if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
+ ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL );
+ BER_BVZERO( &msc->msc_bound_ndn );
+ }
if ( !BER_BVISEMPTY( &op->o_ndn )
&& SLAP_IS_AUTHZ_BACKEND( op )
&& isauthz )
if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn,
&msc->msc_bound_ndn ) )
{
- ldap_unbind_ext_s( msc->msc_ld, NULL, NULL );
+
+#ifdef DEBUG_205
+ Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(rewrite) ldap_unbind_ext[%d] ld=%p\n",
+ op->o_log_prefix, candidate, (void *)msc->msc_ld );
+#endif /* DEBUG_205 */
+
+ /* need to trash a connection not fully established */
+ meta_clear_one_candidate( op, mc, candidate );
goto error_return;
}
- /* copy the DN idf needed */
+ /* copy the DN if needed */
if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) {
ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn );
}
+ assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
+
} else {
- ber_str2bv( "", 0, 1, &msc->msc_bound_ndn );
+ ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv );
}
}
assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
error_return:;
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ }
+ META_BACK_CONN_CREATING_CLEAR( msc );
if ( rs->sr_err == LDAP_SUCCESS ) {
/*
* Sets a cookie for the rewrite session
*/
( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn );
+ META_BACK_CONN_INITED_SET( msc );
+ }
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ }
- } else {
+ if ( rs->sr_err != LDAP_SUCCESS ) {
rs->sr_err = slap_map_api2result( rs );
if ( sendok & LDAP_BACK_SENDERR ) {
send_ldap_result( op, rs );
ldap_back_send_t sendok )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
- metatarget_t *mt = &mi->mi_targets[ candidate ];
+ metatarget_t *mt = mi->mi_targets[ candidate ];
metaconn_t *mc = *mcp;
metasingleconn_t *msc = &mc->mc_conns[ candidate ];
int rc = LDAP_UNAVAILABLE,
- binding = LDAP_BACK_CONN_BINDING( msc );
+ binding;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ assert( !META_BACK_CONN_CREATING( msc ) );
+ binding = LDAP_BACK_CONN_BINDING( msc );
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+
assert( mc->mc_refcnt > 0 );
if ( mc->mc_refcnt == 1 ) {
- char buf[ SLAP_TEXT_BUFLEN ];
+ if ( StatslogTest( LDAP_DEBUG_ANY ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ /* this lock is required; however,
+ * it's invoked only when logging is on */
+ ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
+ snprintf( buf, sizeof( buf ),
+ "retrying URI=\"%s\" DN=\"%s\"",
+ mt->mt_uri,
+ BER_BVISNULL( &msc->msc_bound_ndn ) ?
+ "" : msc->msc_bound_ndn.bv_val );
+ ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
- snprintf( buf, sizeof( buf ),
- "retrying URI=\"%s\" DN=\"%s\"",
- mt->mt_uri,
- BER_BVISNULL( &msc->msc_bound_ndn ) ?
- "" : msc->msc_bound_ndn.bv_val );
- Debug( LDAP_DEBUG_ANY,
- "%s meta_back_retry[%d]: %s.\n",
- op->o_log_prefix, candidate, buf );
+ Debug( LDAP_DEBUG_ANY,
+ "%s meta_back_retry[%d]: %s.\n",
+ op->o_log_prefix, candidate, buf );
+ }
- meta_clear_one_candidate( msc );
+ meta_clear_one_candidate( op, mc, candidate );
LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
/* mc here must be the regular mc, reset and ready for init */
- rc = meta_back_init_one_conn( op, rs, mt, mc, candidate,
- LDAP_BACK_CONN_ISPRIV( mc ), sendok );
+ rc = meta_back_init_one_conn( op, rs, mc, candidate,
+ LDAP_BACK_CONN_ISPRIV( mc ), sendok, 0 );
+
+ /* restore the "binding" flag, in case */
if ( binding ) {
LDAP_BACK_CONN_BINDING_SET( msc );
}
if ( rc == LDAP_SUCCESS ) {
rc = meta_back_single_dobind( op, rs, mcp, candidate,
sendok, mt->mt_nretries, 0 );
+
+ Debug( LDAP_DEBUG_ANY,
+ "%s meta_back_retry[%d]: "
+ "meta_back_single_dobind=%d\n",
+ op->o_log_prefix, candidate, rc );
+ if ( rc == LDAP_SUCCESS ) {
+ if ( !BER_BVISNULL( &msc->msc_bound_ndn ) &&
+ !BER_BVISEMPTY( &msc->msc_bound_ndn ) )
+ {
+ LDAP_BACK_CONN_ISBOUND_SET( msc );
+
+ } else {
+ LDAP_BACK_CONN_ISANON_SET( msc );
+ }
+
+ /* when bound, dispose of the "binding" flag */
+ if ( binding ) {
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ }
+ }
}
+
+ /* don't send twice */
+ sendok &= ~LDAP_BACK_SENDERR;
}
if ( rc != LDAP_SUCCESS ) {
+ SlapReply *candidates = meta_back_candidates_get( op );
+
+ candidates[ candidate ].sr_err = rc;
+
if ( *mcp != NULL ) {
- if ( binding ) {
- LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ if ( mc->mc_refcnt == 1 ) {
+ if ( binding ) {
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ }
+ (void)meta_clear_one_candidate( op, mc, candidate );
+ }
+
+ LDAP_BACK_CONN_TAINTED_SET( mc );
+ /* only release if mandatory; otherwise
+ * let the caller do what's best before
+ * releasing */
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ meta_back_release_conn_lock( op, mc, 0 );
+ *mcp = NULL;
+
+ } else {
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, ">>> meta_back_retry" );
+#endif /* META_BACK_PRINT_CONNTREE */
+
+ /* FIXME: could be done better, reworking meta_back_release_conn_lock() */
+ if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
+ if ( mc->mc_q.tqe_prev != NULL ) {
+ assert( LDAP_BACK_CONN_CACHED( mc ) );
+ assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 );
+ LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
+ mc, mc_q );
+ mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
+ mc->mc_q.tqe_prev = NULL;
+ mc->mc_q.tqe_next = NULL;
+
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( mc ) );
+ }
+
+ } else {
+ /* FIXME: check if in tree, for consistency? */
+ (void)avl_delete( &mi->mi_conninfo.lai_tree,
+ ( caddr_t )mc, meta_back_conndnmc_cmp );
+ }
+ LDAP_BACK_CONN_CACHED_CLEAR( mc );
+
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, "<<< meta_back_retry" );
+#endif /* META_BACK_PRINT_CONNTREE */
}
- meta_back_release_conn_lock( op, mc, 1, 0 );
- *mcp = NULL;
}
- if ( sendok ) {
- rs->sr_err = LDAP_UNAVAILABLE;
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ rs->sr_err = rc;
rs->sr_text = NULL;
send_ldap_result( op, rs );
}
}
+ if ( META_BACK_TGT_QUARANTINE( mt ) ) {
+ meta_back_quarantine( op, rs, candidate );
+ }
+
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
return rc == LDAP_SUCCESS ? 1 : 0;
* and a default target is defined, and it is
* a candidate, try using it (FIXME: YMMV) */
if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE
- && meta_back_is_candidate( &mi->mi_targets[ mi->mi_defaulttarget ].mt_nsuffix,
- mi->mi_targets[ mi->mi_defaulttarget ].mt_scope,
- mi->mi_targets[ mi->mi_defaulttarget ].mt_subtree_exclude,
+ && meta_back_is_candidate( mi->mi_targets[ mi->mi_defaulttarget ],
ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) )
{
candidate = mi->mi_defaulttarget;
} else if ( mc->mc_ntargets < mi->mi_ntargets ) {
/* NOTE: in the future, may want to allow back-config
* to add/remove targets from back-meta... */
- mc->mc_ntargets = mi->mi_ntargets;
mc->mc_candidates = ch_realloc( mc->mc_candidates,
- sizeof( SlapReply ) * mc->mc_ntargets );
+ sizeof( SlapReply ) * mi->mi_ntargets );
+ memset( &mc->mc_candidates[ mc->mc_ntargets ], 0,
+ sizeof( SlapReply ) * ( mi->mi_ntargets - mc->mc_ntargets ) );
+ mc->mc_ntargets = mi->mi_ntargets;
}
return mc->mc_candidates;
META_DNTYPE_ENTRY,
META_DNTYPE_PARENT,
META_DNTYPE_NEWPARENT
- } dn_type = META_DNTYPE_ENTRY;
+ } dn_type = META_DNTYPE_ENTRY;
struct berval ndn = op->o_req_ndn,
pndn;
SlapReply *candidates = meta_back_candidates_get( op );
/* Internal searches are privileged and shared. So is root. */
- /* FIXME: there seem to be concurrency issues */
- if ( op->o_do_not_cache || be_isroot( op ) ) {
+ /* FIXME: there seems to be concurrency issues */
+ if ( META_BACK_PROXYAUTHZ_ALWAYS( mi ) || op->o_do_not_cache || be_isroot( op ) ) {
mc_curr.mc_local_ndn = op->o_bd->be_rootndn;
LDAP_BACK_CONN_ISPRIV_SET( &mc_curr );
- mc_curr.mc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_PCONN_ROOTDN_SET( &mc_curr, op );
} else {
mc_curr.mc_local_ndn = op->o_ndn;
mc_curr.mc_conn = op->o_conn;
} else {
- mc_curr.mc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_CONN_ISANON_SET( &mc_curr );
+ LDAP_BACK_PCONN_ANON_SET( &mc_curr, op );
}
}
/* Explicit Bind requests always get their own conn */
if ( !( sendok & LDAP_BACK_BINDING ) ) {
/* Searches for a metaconn in the avl tree */
-retry_lock:
+retry_lock:;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
- mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree,
- (caddr_t)&mc_curr, meta_back_conndn_cmp );
- if ( mc ) {
- if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
- || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )
+ if ( LDAP_BACK_PCONN_ISPRIV( &mc_curr ) ) {
+ /* lookup a conn that's not binding */
+ LDAP_TAILQ_FOREACH( mc,
+ &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv,
+ mc_q )
{
- /* don't let anyone else use this expired connection */
- (void)avl_delete( &mi->mi_conninfo.lai_tree,
- (caddr_t)mc, meta_back_conndnmc_cmp );
+ if ( !LDAP_BACK_CONN_BINDING( mc ) && mc->mc_refcnt == 0 ) {
+ break;
+ }
+ }
- Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired.\n",
- op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc->mc_conn ) );
+ if ( mc != NULL ) {
+ if ( mc != LDAP_TAILQ_LAST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
+ metaconn_t, mc_q ) )
+ {
+ LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
+ mc, mc_q );
+ mc->mc_q.tqe_prev = NULL;
+ mc->mc_q.tqe_next = NULL;
+ LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
+ mc, mc_q );
+ }
+
+ } else if ( !LDAP_BACK_USE_TEMPORARIES( mi )
+ && mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_num == mi->mi_conn_priv_max )
+ {
+ mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv );
}
+
- /* Don't reuse connections while they're still binding */
+ } else {
+ mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree,
+ (caddr_t)&mc_curr, meta_back_conndn_cmp );
+ }
+
+ if ( mc ) {
+ /* catch taint errors */
+ assert( !LDAP_BACK_CONN_TAINTED( mc ) );
+
+ /* Don't reuse connections while they're still binding
+ * NOTE: only makes sense for binds */
if ( LDAP_BACK_CONN_BINDING( mc ) ) {
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- ldap_pvt_thread_yield();
- goto retry_lock;
- }
+ if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+
+ ldap_pvt_thread_yield();
+ goto retry_lock;
+ }
+
+ /* release conn, and create a temporary */
+ mc = NULL;
+
+ } else {
+ if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
+ || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )
+ {
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi,
+ ">>> meta_back_getconn(expired)" );
+#endif /* META_BACK_PRINT_CONNTREE */
+
+ /* don't let anyone else use this expired connection */
+ if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
+ if ( mc->mc_q.tqe_prev != NULL ) {
+ assert( LDAP_BACK_CONN_CACHED( mc ) );
+ assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 );
+ LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
+ mc, mc_q );
+ mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
+ mc->mc_q.tqe_prev = NULL;
+ mc->mc_q.tqe_next = NULL;
+
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( mc ) );
+ }
- mc->mc_refcnt++;
+ } else {
+ (void)avl_delete( &mi->mi_conninfo.lai_tree,
+ (caddr_t)mc, meta_back_conndnmc_cmp );
+ }
+
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi,
+ "<<< meta_back_getconn(expired)" );
+#endif /* META_BACK_PRINT_CONNTREE */
+ LDAP_BACK_CONN_TAINTED_SET( mc );
+ LDAP_BACK_CONN_CACHED_CLEAR( mc );
+
+ Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired (tainted).\n",
+ op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) );
+ }
+
+ mc->mc_refcnt++;
+ }
}
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
}
}
break;
+ case LDAP_REQ_COMPARE:
case LDAP_REQ_DELETE:
case LDAP_REQ_MODIFY:
/* just a unique candidate */
break;
- case LDAP_REQ_COMPARE:
case LDAP_REQ_SEARCH:
/* allow multiple candidates for the searchBase */
op_type = META_OP_ALLOW_MULTIPLE;
/* Looks like we didn't get a bind. Open a new session... */
if ( mc == NULL ) {
+ assert( new_conn == 0 );
mc = metaconn_alloc( op );
mc->mc_conn = mc_curr.mc_conn;
ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn );
if ( sendok & LDAP_BACK_BINDING ) {
LDAP_BACK_CONN_BINDING_SET( mc );
}
+ if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
+ LDAP_BACK_CONN_ISPRIV_SET( mc );
+
+ } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) {
+ LDAP_BACK_CONN_ISANON_SET( mc );
+ }
+
+ } else if ( 0 ) {
+ /* TODO: if any of the connections is binding,
+ * release mc and create a new one */
}
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- metatarget_t *mt = &mi->mi_targets[ i ];
-
/*
* The target is activated; if needed, it is
* also init'd
*/
candidates[ i ].sr_err = meta_back_init_one_conn( op,
- rs, mt, mc, i,
- LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok );
+ rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ),
+ LDAP_BACK_DONTSEND, !new_conn );
if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
- candidates[ i ].sr_tag = META_CANDIDATE;
+ META_CANDIDATE_SET( &candidates[ i ] );
ncandidates++;
} else {
* be init'd, should the other ones
* be tried?
*/
- candidates[ i ].sr_tag = META_NOT_CANDIDATE;
+ META_CANDIDATE_RESET( &candidates[ i ] );
err = candidates[ i ].sr_err;
continue;
}
if ( ncandidates == 0 ) {
if ( new_conn ) {
- meta_back_freeconn( op, mc );
+ mc->mc_refcnt = 0;
+ meta_back_conn_free( mc );
} else {
meta_back_release_conn( op, mc );
int j;
for ( j = 0; j < mi->mi_ntargets; j++ ) {
- candidates[ j ].sr_tag = META_NOT_CANDIDATE;
+ META_CANDIDATE_RESET( &candidates[ j ] );
}
/*
mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree,
(caddr_t)&mc_curr, meta_back_conndn_cmp );
if ( mc != NULL ) {
+ /* catch taint errors */
+ assert( !LDAP_BACK_CONN_TAINTED( mc ) );
+
/* Don't reuse connections while they're still binding */
- if ( LDAP_BACK_CONN_BINDING( mc ) ) {
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- ldap_pvt_thread_yield();
- goto retry_lock2;
- }
+ if ( META_BACK_CONN_CREATING( &mc->mc_conns[ i ] )
+ || LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) )
+ {
+ if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ ldap_pvt_thread_yield();
+ goto retry_lock2;
+ }
- mc->mc_refcnt++;
+ mc = NULL;
+
+ } else {
+ mc->mc_refcnt++;
+ }
}
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
}
/* Looks like we didn't get a bind. Open a new session... */
if ( mc == NULL ) {
+ assert( new_conn == 0 );
mc = metaconn_alloc( op );
mc->mc_conn = mc_curr.mc_conn;
ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn );
if ( sendok & LDAP_BACK_BINDING ) {
LDAP_BACK_CONN_BINDING_SET( mc );
}
+ if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
+ LDAP_BACK_CONN_ISPRIV_SET( mc );
+
+ } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) {
+ LDAP_BACK_CONN_ISANON_SET( mc );
+ }
}
}
*/
( void )meta_clear_unused_candidates( op, i );
- mt = &mi->mi_targets[ i ];
+ mt = mi->mi_targets[ i ];
msc = &mc->mc_conns[ i ];
/*
* also init'd. In case of error, meta_back_init_one_conn
* sends the appropriate result.
*/
- err = meta_back_init_one_conn( op, rs, mt, mc, i,
- LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok );
+ err = meta_back_init_one_conn( op, rs, mc, i,
+ LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok, !new_conn );
if ( err != LDAP_SUCCESS ) {
/*
* FIXME: in case one target cannot
* be init'd, should the other ones
* be tried?
*/
- candidates[ i ].sr_tag = META_NOT_CANDIDATE;
+ META_CANDIDATE_RESET( &candidates[ i ] );
if ( new_conn ) {
- (void)meta_clear_one_candidate( msc );
- meta_back_freeconn( op, mc );
+ mc->mc_refcnt = 0;
+ meta_back_conn_free( mc );
} else {
meta_back_release_conn( op, mc );
}
candidates[ i ].sr_err = LDAP_SUCCESS;
- candidates[ i ].sr_tag = META_CANDIDATE;
+ META_CANDIDATE_SET( &candidates[ i ] );
ncandidates++;
if ( candidate ) {
/* Looks like we didn't get a bind. Open a new session... */
if ( mc == NULL ) {
+ assert( new_conn == 0 );
mc = metaconn_alloc( op );
mc->mc_conn = mc_curr.mc_conn;
ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn );
new_conn = 1;
- if ( sendok & LDAP_BACK_BINDING ) {
- LDAP_BACK_CONN_BINDING_SET( mc );
+ if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
+ LDAP_BACK_CONN_ISPRIV_SET( mc );
+
+ } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) {
+ LDAP_BACK_CONN_ISANON_SET( mc );
}
}
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- metatarget_t *mt = &mi->mi_targets[ i ];
- metasingleconn_t *msc = &mc->mc_conns[ i ];
+ metatarget_t *mt = mi->mi_targets[ i ];
+
+ META_CANDIDATE_RESET( &candidates[ i ] );
if ( i == cached
- || meta_back_is_candidate( &mt->mt_nsuffix,
- mt->mt_scope,
- mt->mt_subtree_exclude,
- &op->o_req_ndn,
- LDAP_SCOPE_SUBTREE ) )
+ || meta_back_is_candidate( mt, &op->o_req_ndn,
+ LDAP_SCOPE_SUBTREE ) )
{
/*
* The target is activated; if needed, it is
* also init'd
*/
- int lerr = meta_back_init_one_conn( op, rs,
- mt, mc, i,
- LDAP_BACK_CONN_ISPRIV( &mc_curr ),
- sendok );
+ int lerr = meta_back_init_one_conn( op, rs, mc, i,
+ LDAP_BACK_CONN_ISPRIV( &mc_curr ),
+ LDAP_BACK_DONTSEND, !new_conn );
if ( lerr == LDAP_SUCCESS ) {
- candidates[ i ].sr_tag = META_CANDIDATE;
+ META_CANDIDATE_SET( &candidates[ i ] );
candidates[ i ].sr_err = LDAP_SUCCESS;
ncandidates++;
Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d]\n",
op->o_log_prefix, i, 0 );
+ } else if ( lerr == LDAP_UNAVAILABLE && !META_BACK_ONERR_STOP( mi ) ) {
+ META_CANDIDATE_SET( &candidates[ i ] );
+ candidates[ i ].sr_err = LDAP_UNAVAILABLE;
+
+ Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] %s\n",
+ op->o_log_prefix, i,
+ mt->mt_isquarantined != LDAP_BACK_FQ_NO ? "quarantined" : "unavailable" );
+
} else {
/*
* be tried?
*/
if ( new_conn ) {
- ( void )meta_clear_one_candidate( msc );
+ ( void )meta_clear_one_candidate( op, mc, i );
}
/* leave the target candidate, but record the error for later use */
candidates[ i ].sr_err = lerr;
err = lerr;
- Debug( LDAP_DEBUG_ANY, "%s: meta_back_getconn[%d] failed: %d\n",
- op->o_log_prefix, i, lerr );
+ if ( lerr == LDAP_UNAVAILABLE && mt->mt_isquarantined != LDAP_BACK_FQ_NO ) {
+ Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] quarantined err=%d\n",
+ op->o_log_prefix, i, lerr );
+ } else {
+ Debug( LDAP_DEBUG_ANY, "%s: meta_back_getconn[%d] failed err=%d\n",
+ op->o_log_prefix, i, lerr );
+ }
+
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ rs->sr_text = NULL;
+ }
+ if ( new_conn ) {
+ mc->mc_refcnt = 0;
+ meta_back_conn_free( mc );
+
+ } else {
+ meta_back_release_conn( op, mc );
+ }
+
+ return NULL;
+ }
+
+ rs->sr_text = NULL;
continue;
}
} else {
if ( new_conn ) {
- ( void )meta_clear_one_candidate( msc );
+ ( void )meta_clear_one_candidate( op, mc, i );
}
- candidates[ i ].sr_tag = META_NOT_CANDIDATE;
}
}
if ( ncandidates == 0 ) {
if ( new_conn ) {
- meta_back_freeconn( op, mc );
+ mc->mc_refcnt = 0;
+ meta_back_conn_free( mc );
} else {
meta_back_release_conn( op, mc );
}
- rs->sr_err = LDAP_NO_SUCH_OBJECT;
- rs->sr_text = "Unable to select valid candidates";
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ rs->sr_text = "Unable to select valid candidates";
+ }
if ( sendok & LDAP_BACK_SENDERR ) {
if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
}
if ( new_conn ) {
-
if ( mi->mi_conn_ttl ) {
mc->mc_create_time = op->o_time;
}
* Inserts the newly created metaconn in the avl tree
*/
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
- err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, ">>> meta_back_getconn" );
+#endif /* META_BACK_PRINT_CONNTREE */
+
+ if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
+ if ( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num < mi->mi_conn_priv_max ) {
+ LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q );
+ mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num++;
+ LDAP_BACK_CONN_CACHED_SET( mc );
+
+ } else {
+ LDAP_BACK_CONN_TAINTED_SET( mc );
+ }
+ rs->sr_err = 0;
+
+ } else {
+ err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
meta_back_conndn_cmp, meta_back_conndn_dup );
+ LDAP_BACK_CONN_CACHED_SET( mc );
+ }
-#if PRINT_CONNTREE > 0
- myprint( mi->mi_conninfo.lai_tree );
-#endif /* PRINT_CONNTREE */
-
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, ">>> meta_back_getconn" );
+#endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- /*
- * Err could be -1 in case a duplicate metaconn is inserted
- *
- * FIXME: what if the same client issues more than one
- * asynchronous operations?
- */
- if ( err != 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "%s meta_back_getconn: candidates=%d conn=%ld insert failed\n",
- op->o_log_prefix, ncandidates,
- LDAP_BACK_PCONN_ID( mc->mc_conn ) );
-
- rs->sr_err = LDAP_OTHER;
- rs->sr_text = "Internal server error";
- meta_back_freeconn( op, mc );
- if ( sendok & LDAP_BACK_SENDERR ) {
- send_ldap_result( op, rs );
- rs->sr_text = NULL;
+ if ( !LDAP_BACK_PCONN_ISPRIV( mc ) ) {
+ /*
+ * Err could be -1 in case a duplicate metaconn is inserted
+ */
+ switch ( err ) {
+ case 0:
+ break;
+
+ case -1:
+ LDAP_BACK_CONN_CACHED_CLEAR( mc );
+ /* duplicate: free and try to get the newly created one */
+ if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
+ mc->mc_refcnt = 0;
+ meta_back_conn_free( mc );
+
+ new_conn = 0;
+ goto retry_lock;
+ }
+
+ LDAP_BACK_CONN_TAINTED_SET( mc );
+ break;
+
+ default:
+ LDAP_BACK_CONN_CACHED_CLEAR( mc );
+ Debug( LDAP_DEBUG_ANY,
+ "%s meta_back_getconn: candidates=%d conn=%ld insert failed\n",
+ op->o_log_prefix, ncandidates,
+ LDAP_BACK_PCONN_ID( mc ) );
+
+ mc->mc_refcnt = 0;
+ meta_back_conn_free( mc );
+
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "proxy bind collision";
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ rs->sr_text = NULL;
+ }
+ return NULL;
}
- return NULL;
}
Debug( LDAP_DEBUG_TRACE,
"%s meta_back_getconn: candidates=%d conn=%ld inserted\n",
op->o_log_prefix, ncandidates,
- LDAP_BACK_PCONN_ID( mc->mc_conn ) );
+ LDAP_BACK_PCONN_ID( mc ) );
} else {
Debug( LDAP_DEBUG_TRACE,
"%s meta_back_getconn: candidates=%d conn=%ld fetched\n",
op->o_log_prefix, ncandidates,
- LDAP_BACK_PCONN_ID( mc->mc_conn ) );
+ LDAP_BACK_PCONN_ID( mc ) );
}
-
+
return mc;
}
meta_back_release_conn_lock(
Operation *op,
metaconn_t *mc,
- int dofree,
int dolock )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
}
assert( mc->mc_refcnt > 0 );
mc->mc_refcnt--;
- LDAP_BACK_CONN_BINDING_CLEAR( mc );
- if ( dofree
- || ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
- || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )
- {
- Debug( LDAP_DEBUG_TRACE, "%s meta_back_release_conn: mc=%p conn=%ld expired.\n",
- op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc->mc_conn ) );
- (void)avl_delete( &mi->mi_conninfo.lai_tree,
- ( caddr_t )mc, meta_back_conndnmc_cmp );
+ /* NOTE: the connection is removed if either it is tainted
+ * or if it is shared and no one else is using it. This needs
+ * to occur because for intrinsic reasons cached connections
+ * that are not privileged would live forever and pollute
+ * the connection space (and eat up resources). Maybe this
+ * should be configurable... */
+ if ( LDAP_BACK_CONN_TAINTED( mc ) ) {
+ Debug( LDAP_DEBUG_TRACE, "%s meta_back_release_conn: mc=%p conn=%ld tainted.\n",
+ op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) );
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, ">>> meta_back_release_conn" );
+#endif /* META_BACK_PRINT_CONNTREE */
+
+ if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
+ if ( mc->mc_q.tqe_prev != NULL ) {
+ assert( LDAP_BACK_CONN_CACHED( mc ) );
+ assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 );
+ mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
+ LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q );
+
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( mc ) );
+ }
+ mc->mc_q.tqe_prev = NULL;
+ mc->mc_q.tqe_next = NULL;
+
+ } else {
+ metaconn_t *tmpmc;
+
+ tmpmc = avl_delete( &mi->mi_conninfo.lai_tree,
+ ( caddr_t )mc, meta_back_conndnmc_cmp );
+
+ if ( tmpmc == NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "%s: meta_back_release_conn: unable to find mc=%p\n",
+ op->o_log_prefix, (void *)mc, 0 );
+ } else {
+ assert( tmpmc == mc );
+ }
+ }
+
+ LDAP_BACK_CONN_CACHED_CLEAR( mc );
+
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, "<<< meta_back_release_conn" );
+#endif /* META_BACK_PRINT_CONNTREE */
+
if ( mc->mc_refcnt == 0 ) {
- meta_clear_candidates( op, mc );
meta_back_conn_free( mc );
+ mc = NULL;
}
}
+
+ if ( mc != NULL && LDAP_BACK_CONN_BINDING( mc ) ) {
+ LDAP_BACK_CONN_BINDING_CLEAR( mc );
+ }
+
if ( dolock ) {
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
}
}
+
+void
+meta_back_quarantine(
+ Operation *op,
+ SlapReply *rs,
+ int candidate )
+{
+ metainfo_t *mi = (metainfo_t *)op->o_bd->be_private;
+ metatarget_t *mt = mi->mi_targets[ candidate ];
+
+ slap_retry_info_t *ri = &mt->mt_quarantine;
+
+ ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex );
+
+ if ( rs->sr_err == LDAP_UNAVAILABLE ) {
+ time_t new_last = slap_get_time();
+
+ switch ( mt->mt_isquarantined ) {
+ case LDAP_BACK_FQ_NO:
+ if ( ri->ri_last == new_last ) {
+ goto done;
+ }
+
+ Debug( LDAP_DEBUG_ANY,
+ "%s meta_back_quarantine[%d]: enter.\n",
+ op->o_log_prefix, candidate, 0 );
+
+ ri->ri_idx = 0;
+ ri->ri_count = 0;
+ break;
+
+ case LDAP_BACK_FQ_RETRYING:
+ if ( StatslogTest( LDAP_DEBUG_ANY ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "meta_back_quarantine[%d]: block #%d try #%d failed",
+ candidate, ri->ri_idx, ri->ri_count );
+ Debug( LDAP_DEBUG_ANY, "%s %s.\n",
+ op->o_log_prefix, buf, 0 );
+ }
+
+ ++ri->ri_count;
+ if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER
+ && ri->ri_count == ri->ri_num[ ri->ri_idx ] )
+ {
+ ri->ri_count = 0;
+ ++ri->ri_idx;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ mt->mt_isquarantined = LDAP_BACK_FQ_YES;
+ ri->ri_last = new_last;
+
+ } else if ( mt->mt_isquarantined == LDAP_BACK_FQ_RETRYING ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s meta_back_quarantine[%d]: exit.\n",
+ op->o_log_prefix, candidate, 0 );
+
+ if ( mi->mi_quarantine_f ) {
+ (void)mi->mi_quarantine_f( mi, candidate,
+ mi->mi_quarantine_p );
+ }
+
+ ri->ri_count = 0;
+ ri->ri_idx = 0;
+ mt->mt_isquarantined = LDAP_BACK_FQ_NO;
+ }
+
+done:;
+ ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex );
+}
+
meta_back_delete( Operation *op, SlapReply *rs )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metatarget_t *mt;
metaconn_t *mc = NULL;
int candidate = -1;
struct berval mdn = BER_BVNULL;
dncookie dc;
int msgid;
int do_retry = 1;
- int maperr = 1;
+ LDAPControl **ctrls = NULL;
mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR );
if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
/*
* Rewrite the compare dn, if needed
*/
- dc.target = &mi->mi_targets[ candidate ];
+ mt = mi->mi_targets[ candidate ];
+ dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
dc.ctx = "deleteDN";
if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
send_ldap_result( op, rs );
- goto done;
+ goto cleanup;
}
retry:;
+ ctrls = op->o_ctrls;
+ if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn,
+ mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS )
+ {
+ send_ldap_result( op, rs );
+ goto cleanup;
+ }
+
rs->sr_err = ldap_delete_ext( mc->mc_conns[ candidate ].msc_ld,
- mdn.bv_val, op->o_ctrls, NULL, &msgid );
+ mdn.bv_val, ctrls, NULL, &msgid );
+ rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
+ mt->mt_timeout[ SLAP_OP_DELETE ], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
+ /* if the identity changed, there might be need to re-authz */
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
goto retry;
}
- goto cleanup;
-
- } else if ( rs->sr_err == LDAP_SUCCESS ) {
- struct timeval tv, *tvp = NULL;
- LDAPMessage *res = NULL;
- int rc;
-
- if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_DELETE ] != 0 ) {
- tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_DELETE ];
- tv.tv_usec = 0;
- tvp = &tv;
- }
-
- rs->sr_err = LDAP_OTHER;
- maperr = 0;
- rc = ldap_result( mc->mc_conns[ candidate ].msc_ld,
- msgid, LDAP_MSG_ALL, tvp, &res );
- switch ( rc ) {
- case -1:
- rs->sr_err = LDAP_OTHER;
- break;
-
- case 0:
- ldap_abandon_ext( mc->mc_conns[ candidate ].msc_ld,
- msgid, NULL, NULL );
- rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
- LDAP_ADMINLIMIT_EXCEEDED : LDAP_OPERATIONS_ERROR;
- break;
-
- case LDAP_RES_DELETE:
- rc = ldap_parse_result( mc->mc_conns[ candidate ].msc_ld,
- res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 );
- if ( rc != LDAP_SUCCESS ) {
- rs->sr_err = rc;
- }
- maperr = 1;
- break;
-
- default:
- ldap_msgfree( res );
- break;
- }
- }
-
- if ( maperr ) {
- rs->sr_err = meta_back_op_result( mc, op, rs, candidate );
-
- } else {
- send_ldap_result( op, rs );
}
cleanup:;
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
+
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
}
-done:;
if ( mc ) {
meta_back_release_conn( op, mc );
}
Backend *be )
{
metainfo_t *mi;
+ int i;
mi = ch_calloc( 1, sizeof( metainfo_t ) );
if ( mi == NULL ) {
mi->mi_bind_timeout.tv_sec = 0;
mi->mi_bind_timeout.tv_usec = META_BIND_TIMEOUT;
+ mi->mi_rebind_f = meta_back_default_rebind;
+
ldap_pvt_thread_mutex_init( &mi->mi_conninfo.lai_mutex );
ldap_pvt_thread_mutex_init( &mi->mi_cache.mutex );
/* safe default */
mi->mi_nretries = META_RETRY_DEFAULT;
mi->mi_version = LDAP_VERSION3;
+
+ for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
+ mi->mi_conn_priv[ i ].mic_num = 0;
+ LDAP_TAILQ_INIT( &mi->mi_conn_priv[ i ].mic_priv );
+ }
+ mi->mi_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
be->be_private = mi;
{
metainfo_t *mi = (metainfo_t *)be->be_private;
- int i, rc;
+ int i,
+ not_always = 0,
+ rc;
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- if ( mi->mi_targets[ i ].mt_flags & LDAP_BACK_F_SUPPORT_T_F_DISCOVER )
- {
- mi->mi_targets[ i ].mt_flags &= ~LDAP_BACK_F_SUPPORT_T_F_DISCOVER;
- rc = slap_discover_feature( mi->mi_targets[ i ].mt_uri,
- mi->mi_targets[ i ].mt_version,
+ metatarget_t *mt = mi->mi_targets[ i ];
+
+ if ( META_BACK_TGT_T_F_DISCOVER( mt ) ) {
+ rc = slap_discover_feature( mt->mt_uri, mt->mt_version,
slap_schema.si_ad_supportedFeatures->ad_cname.bv_val,
LDAP_FEATURE_ABSOLUTE_FILTERS );
if ( rc == LDAP_COMPARE_TRUE ) {
- mi->mi_targets[ i ].mt_flags |= LDAP_BACK_F_SUPPORT_T_F;
+ mt->mt_flags |= LDAP_BACK_F_T_F;
+ }
+ }
+
+ if ( META_BACK_TGT_CANCEL_DISCOVER( mt ) ) {
+ rc = slap_discover_feature( mt->mt_uri, mt->mt_version,
+ slap_schema.si_ad_supportedExtension->ad_cname.bv_val,
+ LDAP_EXOP_CANCEL );
+ if ( rc == LDAP_COMPARE_TRUE ) {
+ mt->mt_flags |= LDAP_BACK_F_CANCEL_EXOP;
}
}
+
+ if ( not_always == 0 ) {
+ if ( !( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE )
+ || !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
+ {
+ not_always = 1;
+ }
+ }
+ }
+
+ if ( not_always == 0 ) {
+ mi->mi_flags |= META_BACK_F_PROXYAUTHZ_ALWAYS;
}
return 0;
}
+/*
+ * meta_back_conn_free()
+ *
+ * actually frees a connection; the reference count must be 0,
+ * and it must not (or no longer) be in the cache.
+ */
void
meta_back_conn_free(
void *v_mc )
{
metaconn_t *mc = v_mc;
- int i, ntargets;
+ int ntargets;
assert( mc != NULL );
assert( mc->mc_refcnt == 0 );
- if ( !BER_BVISNULL( &mc->mc_local_ndn ) ) {
- free( mc->mc_local_ndn.bv_val );
- }
-
- assert( mc->mc_conns != NULL );
-
/* at least one must be present... */
- ntargets = mc->mc_conns[ 0 ].msc_info->mi_ntargets;
+ ntargets = mc->mc_info->mi_ntargets;
+ assert( ntargets > 0 );
+
+ for ( ; ntargets--; ) {
+ (void)meta_clear_one_candidate( NULL, mc, ntargets );
+ }
- for ( i = 0; i < ntargets; i++ ) {
- (void)meta_clear_one_candidate( &mc->mc_conns[ i ] );
+ if ( !BER_BVISNULL( &mc->mc_local_ndn ) ) {
+ free( mc->mc_local_ndn.bv_val );
}
free( mc );
{
if ( mt->mt_uri ) {
free( mt->mt_uri );
+ ldap_pvt_thread_mutex_destroy( &mt->mt_uri_mutex );
}
if ( mt->mt_subtree_exclude ) {
ber_bvarray_free( mt->mt_subtree_exclude );
if ( !BER_BVISNULL( &mt->mt_bindpw ) ) {
free( mt->mt_bindpw.bv_val );
}
- if ( !BER_BVISNULL( &mt->mt_pseudorootdn ) ) {
- free( mt->mt_pseudorootdn.bv_val );
+ if ( !BER_BVISNULL( &mt->mt_idassert_authcID ) ) {
+ ch_free( mt->mt_idassert_authcID.bv_val );
+ }
+ if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {
+ ch_free( mt->mt_idassert_authcDN.bv_val );
+ }
+ if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {
+ ch_free( mt->mt_idassert_passwd.bv_val );
+ }
+ if ( !BER_BVISNULL( &mt->mt_idassert_authzID ) ) {
+ ch_free( mt->mt_idassert_authzID.bv_val );
+ }
+ if ( !BER_BVISNULL( &mt->mt_idassert_sasl_mech ) ) {
+ ch_free( mt->mt_idassert_sasl_mech.bv_val );
+ }
+ if ( !BER_BVISNULL( &mt->mt_idassert_sasl_realm ) ) {
+ ch_free( mt->mt_idassert_sasl_realm.bv_val );
}
- if ( !BER_BVISNULL( &mt->mt_pseudorootpw ) ) {
- free( mt->mt_pseudorootpw.bv_val );
+ if ( mt->mt_idassert_authz != NULL ) {
+ ber_bvarray_free( mt->mt_idassert_authz );
}
if ( mt->mt_rwmap.rwm_rw ) {
rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
avl_free( mt->mt_rwmap.rwm_oc.map, mapping_free );
avl_free( mt->mt_rwmap.rwm_at.remap, mapping_dst_free );
avl_free( mt->mt_rwmap.rwm_at.map, mapping_free );
+
+ free( mt );
}
int
if ( mi->mi_conninfo.lai_tree ) {
avl_free( mi->mi_conninfo.lai_tree, meta_back_conn_free );
}
+ for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
+ while ( !LDAP_TAILQ_EMPTY( &mi->mi_conn_priv[ i ].mic_priv ) ) {
+ metaconn_t *mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ i ].mic_priv );
+
+ LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ i ].mic_priv, mc, mc_q );
+ meta_back_conn_free( mc );
+ }
+ }
/*
* Destroy the per-target stuff (assuming there's at
*/
if ( mi->mi_targets != NULL ) {
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- target_free( &mi->mi_targets[ i ] );
+ metatarget_t *mt = mi->mi_targets[ i ];
+
+ if ( META_BACK_TGT_QUARANTINE( mt ) ) {
+ if ( mt->mt_quarantine.ri_num != mi->mi_quarantine.ri_num )
+ {
+ slap_retry_info_destroy( &mt->mt_quarantine );
+ }
+
+ ldap_pvt_thread_mutex_destroy( &mt->mt_quarantine_mutex );
+ }
+
+ target_free( mt );
}
free( mi->mi_targets );
if ( mi->mi_candidates != NULL ) {
ber_memfree_x( mi->mi_candidates, NULL );
}
+
+ if ( META_BACK_QUARANTINE( mi ) ) {
+ slap_retry_info_destroy( &mi->mi_quarantine );
+ }
}
free( be->be_private );
assert( m != NULL );
*m = NULL;
-
+
mapping = (struct ldapmapping *)ch_calloc( 2,
sizeof( struct ldapmapping ) );
if ( mapping == NULL ) {
return;
}
- ber_str2bv( "objectclass", sizeof("objectclass")-1, 1, &mapping->src);
- ber_dupbv( &mapping->dst, &mapping->src );
- mapping[1].src = mapping->src;
- mapping[1].dst = mapping->dst;
+ ber_str2bv( "objectclass", STRLENOF("objectclass"), 1, &mapping[0].src);
+ ber_dupbv( &mapping[0].dst, &mapping[0].src );
+ mapping[1].src = mapping[0].src;
+ mapping[1].dst = mapping[0].dst;
- avl_insert( &lm->map, (caddr_t)mapping,
+ avl_insert( &lm->map, (caddr_t)&mapping[0],
mapping_cmp, mapping_dup );
avl_insert( &lm->remap, (caddr_t)&mapping[1],
mapping_cmp, mapping_dup );
if ( remap == BACKLDAP_REMAP ) {
tree = map->remap;
+
} else {
tree = map->map;
}
{
struct ldapmapping *mapping;
+ /* map->map may be NULL when mapping is configured,
+ * but map->remap can't */
+ if ( map->remap == NULL ) {
+ *bv = *s;
+ return;
+ }
+
BER_BVZERO( bv );
( void )ldap_back_mapping( map, s, &mapping, remap );
if ( mapping != NULL ) {
ber_bvnone = BER_BVC( "(?=none)" );
ber_len_t len;
+ assert( fstr != NULL );
+ BER_BVZERO( fstr );
+
if ( f == NULL ) {
ber_dupbv( fstr, &ber_bvnone );
return LDAP_OTHER;
/* FIXME: treat UNDEFINED as FALSE */
case SLAPD_COMPARE_UNDEFINED:
computed:;
- if ( dc->target->mt_flags & LDAP_BACK_F_SUPPORT_T_F ) {
+ if ( META_BACK_TGT_T_F( dc->target ) ) {
tmp = &ber_bvtf_false;
break;
}
break;
case LDAP_COMPARE_TRUE:
- if ( dc->target->mt_flags & LDAP_BACK_F_SUPPORT_T_F ) {
+ if ( META_BACK_TGT_T_F( dc->target ) ) {
tmp = &ber_bvtf_true;
break;
}
meta_back_modify( Operation *op, SlapReply *rs )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metatarget_t *mt;
metaconn_t *mc;
int rc = 0;
- int maperr = 1;
LDAPMod **modv = NULL;
LDAPMod *mods = NULL;
Modifications *ml;
dncookie dc;
int msgid;
int do_retry = 1;
+ LDAPControl **ctrls = NULL;
mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR );
if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
/*
* Rewrite the modify dn, if needed
*/
- dc.target = &mi->mi_targets[ candidate ];
+ mt = mi->mi_targets[ candidate ];
+ dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
dc.ctx = "modifyDN";
if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
- maperr = 0;
+ send_ldap_result( op, rs );
goto cleanup;
}
mods = ch_malloc( sizeof( LDAPMod )*i );
if ( mods == NULL ) {
- rs->sr_err = LDAP_NO_MEMORY;
- maperr = 0;
+ rs->sr_err = LDAP_OTHER;
+ send_ldap_result( op, rs );
goto cleanup;
}
modv = ( LDAPMod ** )ch_malloc( ( i + 1 )*sizeof( LDAPMod * ) );
if ( modv == NULL ) {
- rs->sr_err = LDAP_NO_MEMORY;
- maperr = 0;
+ rs->sr_err = LDAP_OTHER;
+ send_ldap_result( op, rs );
goto cleanup;
}
mapped = ml->sml_desc->ad_cname;
} else {
- ldap_back_map( &mi->mi_targets[ candidate ].mt_rwmap.rwm_at,
+ ldap_back_map( &mt->mt_rwmap.rwm_at,
&ml->sml_desc->ad_cname, &mapped,
BACKLDAP_MAP );
if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); ) {
struct ldapmapping *mapping;
- ldap_back_mapping( &mi->mi_targets[ candidate ].mt_rwmap.rwm_oc,
+ ldap_back_mapping( &mt->mt_rwmap.rwm_oc,
&ml->sml_values[ j ], &mapping, BACKLDAP_MAP );
if ( mapping == NULL ) {
- if ( mi->mi_targets[ candidate ].mt_rwmap.rwm_oc.drop_missing ) {
+ if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
continue;
}
mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
modv[ i ] = 0;
retry:;
+ ctrls = op->o_ctrls;
+ rc = ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn,
+ mt->mt_version, &mt->mt_idassert, op, rs, &ctrls );
+ if ( rc != LDAP_SUCCESS ) {
+ send_ldap_result( op, rs );
+ goto cleanup;
+ }
+
rs->sr_err = ldap_modify_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val,
- modv, op->o_ctrls, NULL, &msgid );
+ modv, ctrls, NULL, &msgid );
+ rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
+ mt->mt_timeout[ SLAP_OP_MODIFY ], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
+ /* if the identity changed, there might be need to re-authz */
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
goto retry;
}
- goto done;
-
- } else if ( rs->sr_err == LDAP_SUCCESS ) {
- struct timeval tv, *tvp = NULL;
- LDAPMessage *res = NULL;
-
- if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODIFY ] != 0 ) {
- tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODIFY ];
- tv.tv_usec = 0;
- tvp = &tv;
- }
-
- rs->sr_err = LDAP_OTHER;
- rc = ldap_result( mc->mc_conns[ candidate ].msc_ld,
- msgid, LDAP_MSG_ALL, tvp, &res );
- switch ( rc ) {
- case -1:
- maperr = 0;
- break;
-
- case 0:
- ldap_abandon_ext( mc->mc_conns[ candidate ].msc_ld,
- msgid, NULL, NULL );
- rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
- LDAP_ADMINLIMIT_EXCEEDED : LDAP_OPERATIONS_ERROR;
- maperr = 0;
- break;
-
- case LDAP_RES_MODIFY:
- rc = ldap_parse_result( mc->mc_conns[ candidate ].msc_ld,
- res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 );
- if ( rc != LDAP_SUCCESS ) {
- rs->sr_err = rc;
- }
- maperr = 1;
- break;
-
- default:
- maperr = 0;
- ldap_msgfree( res );
- break;
- }
}
cleanup:;
- if ( maperr ) {
- rc = meta_back_op_result( mc, op, rs, candidate );
-
- } else {
- send_ldap_result( op, rs );
- }
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
-done:;
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
meta_back_modrdn( Operation *op, SlapReply *rs )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metatarget_t *mt;
metaconn_t *mc;
int candidate = -1;
struct berval mdn = BER_BVNULL,
dncookie dc;
int msgid;
int do_retry = 1;
- int maperr = 1;
+ LDAPControl **ctrls = NULL;
mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR );
if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
assert( mc->mc_conns[ candidate ].msc_ld != NULL );
+ mt = mi->mi_targets[ candidate ];
+ dc.target = mt;
dc.conn = op->o_conn;
dc.rs = rs;
*/
/* needs LDAPv3 */
- switch ( mi->mi_targets[ candidate ].mt_version ) {
+ switch ( mt->mt_version ) {
case LDAP_VERSION3:
break;
/* op->o_protocol cannot be anything but LDAPv3,
* otherwise wouldn't be here */
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- maperr = 0;
+ send_ldap_result( op, rs );
goto cleanup;
}
/*
* Rewrite the new superior, if defined and required
*/
- dc.target = &mi->mi_targets[ candidate ];
dc.ctx = "newSuperiorDN";
if ( ldap_back_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) {
rs->sr_err = LDAP_OTHER;
- maperr = 0;
+ send_ldap_result( op, rs );
goto cleanup;
}
}
/*
* Rewrite the modrdn dn, if required
*/
- dc.target = &mi->mi_targets[ candidate ];
dc.ctx = "modrDN";
if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
rs->sr_err = LDAP_OTHER;
- maperr = 0;
+ send_ldap_result( op, rs );
goto cleanup;
}
retry:;
+ ctrls = op->o_ctrls;
+ if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn,
+ mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS )
+ {
+ send_ldap_result( op, rs );
+ goto cleanup;
+ }
+
rs->sr_err = ldap_rename( mc->mc_conns[ candidate ].msc_ld,
mdn.bv_val, op->orr_newrdn.bv_val,
mnewSuperior.bv_val, op->orr_deleteoldrdn,
- op->o_ctrls, NULL, &msgid );
+ ctrls, NULL, &msgid );
+ rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
+ mt->mt_timeout[ SLAP_OP_MODRDN ], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
+ /* if the identity changed, there might be need to re-authz */
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
goto retry;
}
- goto done;
-
- } else if ( rs->sr_err == LDAP_SUCCESS ) {
- struct timeval tv, *tvp = NULL;
- LDAPMessage *res = NULL;
- int rc;
-
- if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODRDN ] != 0 ) {
- tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODRDN ];
- tv.tv_usec = 0;
- tvp = &tv;
- }
-
- rs->sr_err = LDAP_OTHER;
- rc = ldap_result( mc->mc_conns[ candidate ].msc_ld,
- msgid, LDAP_MSG_ALL, tvp, &res );
- maperr = 0;
- switch ( rc ) {
- case -1:
- break;
-
- case 0:
- ldap_abandon_ext( mc->mc_conns[ candidate ].msc_ld,
- msgid, NULL, NULL );
- rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
- LDAP_ADMINLIMIT_EXCEEDED : LDAP_OPERATIONS_ERROR;
- break;
-
- case LDAP_RES_RENAME:
- rc = ldap_parse_result( mc->mc_conns[ candidate ].msc_ld,
- res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 );
- if ( rc != LDAP_SUCCESS ) {
- rs->sr_err = rc;
- }
- maperr = 1;
- break;
-
- default:
- ldap_msgfree( res );
- break;
- }
}
cleanup:;
- if ( maperr ) {
- meta_back_op_result( mc, op, rs, candidate );
-
- } else {
- send_ldap_result( op, rs );
- }
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
-done:;
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
#include <ac/string.h>
#include <ac/time.h>
+#include "lutil.h"
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-meta.h"
#include "ldap_log.h"
#include "../../../libraries/libldap/ldap-int.h"
+/* IGNORE means that target does not (no longer) participate
+ * in the search;
+ * NOTREADY means the search on that target has not been initialized yet
+ */
+#define META_MSGID_IGNORE (-1)
+#define META_MSGID_NEED_BIND (-2)
+
static int
meta_send_entry(
Operation *op,
typedef enum meta_search_candidate_t {
META_SEARCH_ERR = -1,
META_SEARCH_NOT_CANDIDATE,
- META_SEARCH_CANDIDATE
+ META_SEARCH_CANDIDATE,
+ META_SEARCH_BINDING,
+ META_SEARCH_NEED_BIND
} meta_search_candidate_t;
+/*
+ * meta_search_dobind_init()
+ *
+ * initiates bind for a candidate target of a search.
+ */
static meta_search_candidate_t
-meta_back_search_start(
+meta_search_dobind_init(
Operation *op,
SlapReply *rs,
- dncookie *dc,
- metasingleconn_t *msc,
+ metaconn_t **mcp,
int candidate,
- SlapReply *candidates
-)
+ SlapReply *candidates )
{
- metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
- struct berval realbase = op->o_req_dn;
- int realscope = op->ors_scope;
- ber_len_t suffixlen = 0;
- struct berval mbase = BER_BVNULL;
- struct berval mfilter = BER_BVNULL;
- char **mapped_attrs = NULL;
- int rc;
+ metaconn_t *mc = *mcp;
+ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metatarget_t *mt = mi->mi_targets[ candidate ];
+ metasingleconn_t *msc = &mc->mc_conns[ candidate ];
+
+ struct berval binddn = msc->msc_bound_ndn,
+ cred = msc->msc_cred;
+ int method;
+
+ int rc;
+
meta_search_candidate_t retcode;
- struct timeval tv, *tvp = NULL;
- /* should we check return values? */
- if ( op->ors_deref != -1 ) {
- ldap_set_option( msc->msc_ld, LDAP_OPT_DEREF,
- ( void * )&op->ors_deref );
+ Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n",
+ op->o_log_prefix, candidate, 0 );
+
+ /*
+ * all the targets are already bound as pseudoroot
+ */
+ if ( mc->mc_authz_target == META_BOUND_ALL ) {
+ return META_SEARCH_CANDIDATE;
}
- if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
- tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
- tvp = &tv;
+ retcode = META_SEARCH_BINDING;
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
+ /* already bound (or anonymous) */
+
+#ifdef DEBUG_205
+ char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
+ int bound = 0;
+
+ if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
+ bound = 1;
+ }
+
+ snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
+ (void *)mc, (void *)msc->msc_ld,
+ bound ? " bound" : " anonymous",
+ bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
+ Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
+ op->o_log_prefix, candidate, buf );
+#endif /* DEBUG_205 */
+
+ retcode = META_SEARCH_CANDIDATE;
+
+ } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
+ /* another thread is binding the target for this conn; wait */
+
+#ifdef DEBUG_205
+ char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
+
+ snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
+ (void *)mc, (void *)msc->msc_ld );
+ Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
+ op->o_log_prefix, candidate, buf );
+#endif /* DEBUG_205 */
+
+ candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
+ retcode = META_SEARCH_NEED_BIND;
+
+ } else {
+ /* we'll need to bind the target for this conn */
+
+#ifdef DEBUG_205
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
+ (void *)mc, (void *)msc->msc_ld );
+ Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
+ op->o_log_prefix, candidate, buf );
+#endif /* DEBUG_205 */
+
+ if ( msc->msc_ld == NULL ) {
+ /* for some reason (e.g. because formerly in "binding"
+ * state, with eventual connection expiration or invalidation)
+ * it was not initialized as expected */
+
+ Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n",
+ op->o_log_prefix, candidate, (void *)mc );
+
+ rc = meta_back_init_one_conn( op, rs, *mcp, candidate,
+ LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND, 0 );
+ switch ( rc ) {
+ case LDAP_SUCCESS:
+ assert( msc->msc_ld != NULL );
+ break;
+
+ case LDAP_SERVER_DOWN:
+ case LDAP_UNAVAILABLE:
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ goto down;
+
+ default:
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ goto other;
+ }
+ }
+
+ LDAP_BACK_CONN_BINDING_SET( msc );
+ }
+
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+
+ if ( retcode != META_SEARCH_BINDING ) {
+ return retcode;
+ }
+
+ /* NOTE: this obsoletes pseudorootdn */
+ if ( op->o_conn != NULL &&
+ !op->o_do_not_cache &&
+ ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
+ BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
+ ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
+ {
+ rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
+ if ( rc != LDAP_SUCCESS ) {
+ goto down;
+ }
+
+ /* NOTE: we copy things here, even if bind didn't succeed yet,
+ * because the connection is not shared until bind is over */
+ if ( !BER_BVISNULL( &binddn ) ) {
+ ber_bvreplace( &msc->msc_bound_ndn, &binddn );
+ if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &cred ) ) {
+ if ( !BER_BVISNULL( &msc->msc_cred ) ) {
+ memset( msc->msc_cred.bv_val, 0,
+ msc->msc_cred.bv_len );
+ }
+ ber_bvreplace( &msc->msc_cred, &cred );
+ }
+ }
+
+ if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
+ /* apparently, idassert was configured with SASL bind,
+ * so bind occurred inside meta_back_proxy_authz_cred() */
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ return META_SEARCH_CANDIDATE;
+ }
+
+ /* paranoid */
+ switch ( method ) {
+ case LDAP_AUTH_NONE:
+ case LDAP_AUTH_SIMPLE:
+ /* do a simple bind with binddn, cred */
+ break;
+
+ default:
+ assert( 0 );
+ break;
+ }
+ }
+
+ assert( msc->msc_ld != NULL );
+
+ rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
+ NULL, NULL, &candidates[ candidate ].sr_msgid );
+
+#ifdef DEBUG_205
+ {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ), "meta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
+ candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
+ Debug( LDAP_DEBUG_ANY, "### %s %s\n",
+ op->o_log_prefix, buf, 0 );
+ }
+#endif /* DEBUG_205 */
+
+ switch ( rc ) {
+ case LDAP_SUCCESS:
+ assert( candidates[ candidate ].sr_msgid >= 0 );
+ META_BINDING_SET( &candidates[ candidate ] );
+ return META_SEARCH_BINDING;
+
+ case LDAP_SERVER_DOWN:
+down:;
+ /* This is the worst thing that could happen:
+ * the search will wait until the retry is over. */
+ if ( meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ return META_SEARCH_CANDIDATE;
+ }
+
+ if ( *mcp == NULL ) {
+ retcode = META_SEARCH_ERR;
+ rs->sr_err = LDAP_UNAVAILABLE;
+ break;
+ }
+ /* fall thru */
+
+ default:
+other:;
+ rs->sr_err = rc;
+ rc = slap_map_api2result( rs );
+
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ meta_clear_one_candidate( op, mc, candidate );
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ LDAP_BACK_CONN_TAINTED_SET( mc );
+ meta_back_release_conn_lock( op, mc, 0 );
+ *mcp = NULL;
+
+ retcode = META_SEARCH_ERR;
+
+ } else {
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ candidate ].sr_err = rc;
+ }
+
+ retcode = META_SEARCH_NOT_CANDIDATE;
+ }
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ break;
+ }
+
+ return retcode;
+}
+
+static meta_search_candidate_t
+meta_search_dobind_result(
+ Operation *op,
+ SlapReply *rs,
+ metaconn_t **mcp,
+ int candidate,
+ SlapReply *candidates,
+ LDAPMessage *res )
+{
+ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metaconn_t *mc = *mcp;
+ metasingleconn_t *msc = &mc->mc_conns[ candidate ];
+
+ meta_search_candidate_t retcode = META_SEARCH_NOT_CANDIDATE;
+ int rc;
+
+ assert( msc->msc_ld != NULL );
+
+ /* FIXME: matched? referrals? response controls? */
+ rc = ldap_parse_result( msc->msc_ld, res,
+ &candidates[ candidate ].sr_err,
+ NULL, NULL, NULL, NULL, 0 );
+ if ( rc != LDAP_SUCCESS ) {
+ candidates[ candidate ].sr_err = rc;
+
+ } else {
+ rc = slap_map_api2result( &candidates[ candidate ] );
+ }
+
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ if ( rc != LDAP_SUCCESS ) {
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ LDAP_BACK_CONN_TAINTED_SET( mc );
+ meta_clear_one_candidate( op, mc, candidate );
+ meta_back_release_conn_lock( op, mc, 0 );
+ *mcp = NULL;
+ retcode = META_SEARCH_ERR;
+ rs->sr_err = rc;
+
+ } else if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ candidate ].sr_err = rc;
+ }
+
+ } else {
+ /* FIXME: check if bound as idassert authcDN! */
+ if ( BER_BVISNULL( &msc->msc_bound_ndn )
+ || BER_BVISEMPTY( &msc->msc_bound_ndn ) )
+ {
+ LDAP_BACK_CONN_ISANON_SET( msc );
+
+ } else {
+ LDAP_BACK_CONN_ISBOUND_SET( msc );
+ }
+ retcode = META_SEARCH_CANDIDATE;
+ }
+
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ META_BINDING_CLEAR( &candidates[ candidate ] );
+
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+
+ return retcode;
+}
+
+static meta_search_candidate_t
+meta_back_search_start(
+ Operation *op,
+ SlapReply *rs,
+ dncookie *dc,
+ metaconn_t **mcp,
+ int candidate,
+ SlapReply *candidates )
+{
+ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ metatarget_t *mt = mi->mi_targets[ candidate ];
+ metasingleconn_t *msc = &(*mcp)->mc_conns[ candidate ];
+ struct berval realbase = op->o_req_dn;
+ int realscope = op->ors_scope;
+ struct berval mbase = BER_BVNULL;
+ struct berval mfilter = BER_BVNULL;
+ char **mapped_attrs = NULL;
+ int rc;
+ meta_search_candidate_t retcode;
+ struct timeval tv, *tvp = NULL;
+ int nretries = 1;
+ LDAPControl **ctrls = NULL;
+
+ /* this should not happen; just in case... */
+ if ( msc->msc_ld == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: meta_back_search_start candidate=%d ld=NULL%s.\n",
+ op->o_log_prefix, candidate,
+ META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" );
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ return META_SEARCH_ERR;
+ }
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ candidate ].sr_err = LDAP_OTHER;
+ }
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ return META_SEARCH_NOT_CANDIDATE;
}
- dc->target = &mi->mi_targets[ candidate ];
+ Debug( LDAP_DEBUG_TRACE, "%s >>> meta_back_search_start[%d]\n", op->o_log_prefix, candidate, 0 );
/*
* modifies the base according to the scope, if required
*/
- suffixlen = mi->mi_targets[ candidate ].mt_nsuffix.bv_len;
- if ( suffixlen > op->o_req_ndn.bv_len ) {
+ if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
switch ( op->ors_scope ) {
case LDAP_SCOPE_SUBTREE:
/*
* the requested searchBase already passed
* thru the candidate analyzer...
*/
- if ( dnIsSuffix( &mi->mi_targets[ candidate ].mt_nsuffix,
- &op->o_req_ndn ) )
- {
- realbase = mi->mi_targets[ candidate ].mt_nsuffix;
- if ( mi->mi_targets[ candidate ].mt_scope == LDAP_SCOPE_SUBORDINATE ) {
+ if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
+ realbase = mt->mt_nsuffix;
+ if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
realscope = LDAP_SCOPE_SUBORDINATE;
}
/*
* this target is no longer candidate
*/
- return META_SEARCH_NOT_CANDIDATE;
+ retcode = META_SEARCH_NOT_CANDIDATE;
+ goto doreturn;
}
break;
case LDAP_SCOPE_SUBORDINATE:
case LDAP_SCOPE_ONELEVEL:
{
- struct berval rdn = mi->mi_targets[ candidate ].mt_nsuffix;
+ struct berval rdn = mt->mt_nsuffix;
rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
if ( dnIsOneLevelRDN( &rdn )
- && dnIsSuffix( &mi->mi_targets[ candidate ].mt_nsuffix, &op->o_req_ndn ) )
+ && dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
{
/*
* if there is exactly one level,
* make the target suffix the new
* base, and make scope "base"
*/
- realbase = mi->mi_targets[ candidate ].mt_nsuffix;
+ realbase = mt->mt_nsuffix;
if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
- if ( mi->mi_targets[ candidate ].mt_scope == LDAP_SCOPE_SUBORDINATE ) {
+ if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
realscope = LDAP_SCOPE_SUBORDINATE;
} else {
realscope = LDAP_SCOPE_SUBTREE;
/*
* this target is no longer candidate
*/
- return META_SEARCH_NOT_CANDIDATE;
+ retcode = META_SEARCH_NOT_CANDIDATE;
+ goto doreturn;
}
}
+ /* initiate dobind */
+ retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates );
+
+ Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%d]=%d\n", op->o_log_prefix, candidate, retcode );
+
+ if ( retcode != META_SEARCH_CANDIDATE ) {
+ goto doreturn;
+ }
+
/*
* Rewrite the search base, if required
*/
+ dc->target = mt;
dc->ctx = "searchBase";
switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) {
case LDAP_SUCCESS:
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "Operation not allowed";
send_ldap_result( op, rs );
- return META_SEARCH_ERR;
+ retcode = META_SEARCH_ERR;
+ goto doreturn;
default:
/*
* this target is no longer candidate
*/
- return META_SEARCH_NOT_CANDIDATE;
+ retcode = META_SEARCH_NOT_CANDIDATE;
+ goto doreturn;
}
/*
/*
* Maps required attributes
*/
- rc = ldap_back_map_attrs( &mi->mi_targets[ candidate ].mt_rwmap.rwm_at,
+ rc = ldap_back_map_attrs( &mt->mt_rwmap.rwm_at,
op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
if ( rc != LDAP_SUCCESS ) {
/*
goto done;
}
+ /* should we check return values? */
+ if ( op->ors_deref != -1 ) {
+ assert( msc->msc_ld != NULL );
+ (void)ldap_set_option( msc->msc_ld, LDAP_OPT_DEREF,
+ ( void * )&op->ors_deref );
+ }
+
+ if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
+ tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ }
+
+retry:;
+ ctrls = op->o_ctrls;
+ if ( ldap_back_proxy_authz_ctrl( &msc->msc_bound_ndn,
+ mt->mt_version, &mt->mt_idassert, op, rs, &ctrls )
+ != LDAP_SUCCESS )
+ {
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ retcode = META_SEARCH_NOT_CANDIDATE;
+ goto done;
+ }
+
/*
* Starts the search
*/
+ assert( msc->msc_ld != NULL );
rc = ldap_search_ext( msc->msc_ld,
mbase.bv_val, realscope, mfilter.bv_val,
mapped_attrs, op->ors_attrsonly,
- op->o_ctrls, NULL, tvp, op->ors_slimit,
+ ctrls, NULL, tvp, op->ors_slimit,
&candidates[ candidate ].sr_msgid );
- if ( rc == LDAP_SUCCESS ) {
+ switch ( rc ) {
+ case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
+ break;
+
+ case LDAP_SERVER_DOWN:
+ if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
+ nretries = 0;
+ /* if the identity changed, there might be need to re-authz */
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
+ goto retry;
+ }
- } else {
- candidates[ candidate ].sr_msgid = -1;
+ if ( *mcp == NULL ) {
+ retcode = META_SEARCH_ERR;
+ break;
+ }
+ /* fall thru */
+
+ default:
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_NOT_CANDIDATE;
}
done:;
+ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
+
if ( mapped_attrs ) {
free( mapped_attrs );
}
free( mbase.bv_val );
}
+doreturn:;
+ Debug( LDAP_DEBUG_TRACE, "%s <<< meta_back_search_start[%d]=%d\n", op->o_log_prefix, candidate, retcode );
+
return retcode;
}
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metaconn_t *mc;
- struct timeval tv = { 0, 0 };
+ struct timeval save_tv = { 0, 0 },
+ tv;
time_t stoptime = (time_t)-1;
- LDAPMessage *res = NULL, *e;
int rc = 0, sres = LDAP_SUCCESS;
char *matched = NULL;
int last = 0, ncandidates = 0,
- initial_candidates = 0, candidate_match = 0;
+ initial_candidates = 0, candidate_match = 0,
+ needbind = 0;
+ ldap_back_send_t sendok = LDAP_BACK_SENDERR;
long i;
dncookie dc;
int is_ok = 0;
* FIXME: in case of values return filter, we might want
* to map attrs and maybe rewrite value
*/
- mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_SENDERR );
- if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
+getconn:;
+ mc = meta_back_getconn( op, rs, NULL, sendok );
+ if ( !mc ) {
return rs->sr_err;
}
* Inits searches
*/
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- metasingleconn_t *msc = &mc->mc_conns[ i ];
+ /* reset sr_msgid; it is used in most loops
+ * to check if that target is still to be considered */
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+
+ /* a target is marked as candidate by meta_back_getconn();
+ * if for any reason (an error, it's over or so) it is
+ * no longer active, sr_msgid is set to META_MSGID_IGNORE
+ * but it remains candidate, which means it has been active
+ * at some point during the operation. This allows to
+ * use its response code and more to compute the final
+ * response */
+ if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
+ continue;
+ }
- candidates[ i ].sr_msgid = -1;
candidates[ i ].sr_matched = NULL;
candidates[ i ].sr_text = NULL;
candidates[ i ].sr_ref = NULL;
candidates[ i ].sr_ctrls = NULL;
+ }
- if ( candidates[ i ].sr_tag != META_CANDIDATE
+ for ( i = 0; i < mi->mi_ntargets; i++ ) {
+ if ( !META_IS_CANDIDATE( &candidates[ i ] )
|| candidates[ i ].sr_err != LDAP_SUCCESS )
{
continue;
}
- switch ( meta_back_search_start( op, rs, &dc, msc, i, candidates ) )
+ switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
{
case META_SEARCH_NOT_CANDIDATE:
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
break;
+ case META_SEARCH_NEED_BIND:
+ ++needbind;
+ /* fallthru */
+
case META_SEARCH_CANDIDATE:
+ case META_SEARCH_BINDING:
candidates[ i ].sr_type = REP_INTERMEDIATE;
++ncandidates;
break;
case META_SEARCH_ERR:
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
rc = -1;
goto finish;
}
}
+ if ( ncandidates > 0 && needbind == ncandidates ) {
+ /*
+ * give up the second time...
+ *
+ * NOTE: this should not occur the second time, since a fresh
+ * connection has ben created; however, targets may also
+ * need bind because the bind timed out or so.
+ */
+ if ( sendok & LDAP_BACK_BINDING ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s meta_back_search: unable to initialize conn\n",
+ op->o_log_prefix, 0, 0 );
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "unable to initialize connection to remote targets";
+ send_ldap_result( op, rs );
+ rc = -1;
+ goto finish;
+ }
+
+ /* FIXME: better create a separate connection? */
+ sendok |= LDAP_BACK_BINDING;
+
+#ifdef DEBUG_205
+ Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n",
+ op->o_log_prefix, (void *)mc, 0 );
+#endif /* DEBUG_205 */
+
+ meta_back_release_conn( op, mc );
+ mc = NULL;
+
+ needbind = 0;
+ ncandidates = 0;
+
+ goto getconn;
+ }
+
initial_candidates = ncandidates;
-#if 0
- {
- char cnd[BUFSIZ];
- int i;
+ if ( StatslogTest( LDAP_DEBUG_TRACE ) ) {
+ char cnd[ SLAP_TEXT_BUFLEN ];
+ int c;
- for ( i = 0; i < mi->mi_ntargets; i++ ) {
- if ( candidates[ i ].sr_tag == META_CANDIDATE ) {
- cnd[ i ] = '*';
+ for ( c = 0; c < mi->mi_ntargets; c++ ) {
+ if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
+ cnd[ c ] = '*';
} else {
- cnd[ i ] = ' ';
+ cnd[ c ] = ' ';
}
}
- cnd[ i ] = '\0';
+ cnd[ c ] = '\0';
- Debug( LDAP_DEBUG_ANY, "%s meta_back_search: ncandidates=%d "
+ Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d "
"cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
}
-#endif
if ( initial_candidates == 0 ) {
/* NOTE: here we are not sending any matchedDN;
* maybe we should pick the worst... */
rc = LDAP_NO_SUCH_OBJECT;
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- if ( candidates[ i ].sr_tag == META_CANDIDATE
+ if ( META_IS_CANDIDATE( &candidates[ i ] )
&& candidates[ i ].sr_err != LDAP_SUCCESS )
{
rc = candidates[ i ].sr_err;
* among the candidates
*/
for ( rc = 0; ncandidates > 0; ) {
- int gotit = 0, doabandon = 0;
+ int gotit = 0,
+ doabandon = 0,
+ alreadybound = ncandidates;
+
+ /* check time limit */
+ if ( op->ors_tlimit != SLAP_NO_LIMIT
+ && slap_get_time() > stoptime )
+ {
+ doabandon = 1;
+ rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ goto finish;
+ }
for ( i = 0; i < mi->mi_ntargets; i++ ) {
metasingleconn_t *msc = &mc->mc_conns[ i ];
+ LDAPMessage *res = NULL, *msg;
+
+ /* if msgid is invalid, don't ldap_result() */
+ if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
+ continue;
+ }
+
+ /* if target still needs bind, retry */
+ if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND ) {
+ meta_search_candidate_t retcode;
+
+ /* initiate dobind */
+ retcode = meta_search_dobind_init( op, rs, &mc, i, candidates );
+
+ Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%ld]=%d\n",
+ op->o_log_prefix, i, retcode );
+
+ switch ( retcode ) {
+ case META_SEARCH_NEED_BIND:
+ alreadybound--;
+ /* fallthru */
+
+ case META_SEARCH_BINDING:
+ break;
+
+ case META_SEARCH_ERR:
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ goto finish;
+ }
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ i ].sr_err = rs->sr_err;
+ }
+ /* fallthru */
+
+ case META_SEARCH_NOT_CANDIDATE:
+ /*
+ * When no candidates are left,
+ * the outer cycle finishes
+ */
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ assert( ncandidates > 0 );
+ --ncandidates;
+ break;
+
+ case META_SEARCH_CANDIDATE:
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
+ {
+ case META_SEARCH_CANDIDATE:
+ assert( candidates[ i ].sr_msgid >= 0 );
+ break;
+
+ case META_SEARCH_ERR:
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ goto finish;
+ }
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ i ].sr_err = rs->sr_err;
+ }
+ /* fallthru */
+
+ case META_SEARCH_NOT_CANDIDATE:
+ /* means that meta_back_search_start()
+ * failed but onerr == continue */
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ assert( ncandidates > 0 );
+ --ncandidates;
+ break;
+
+ default:
+ /* impossible */
+ assert( 0 );
+ break;
+ }
+ break;
- if ( candidates[ i ].sr_msgid == -1 ) {
+ default:
+ /* impossible */
+ assert( 0 );
+ break;
+ }
continue;
}
if ( op->o_abandon ) {
break;
}
+
+#ifdef DEBUG_205
+ if ( msc->msc_ld == NULL ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ snprintf( buf, sizeof( buf ),
+ "%s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n",
+ op->o_log_prefix, (long)i, (void *)mc,
+ candidates[ i ].sr_msgid,
+ META_IS_BINDING( &candidates[ i ] ) ? " binding" : "",
+ LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "",
+ META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) ? " conncreating" : "" );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+
+ Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 );
+ }
+#endif /* DEBUG_205 */
/*
* FIXME: handle time limit as well?
* get a LDAP_TIMELIMIT_EXCEEDED from
* one of them ...
*/
-get_result:;
+ tv = save_tv;
rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
- LDAP_MSG_ONE, &tv, &res );
-
- if ( rc == 0 ) {
+ LDAP_MSG_RECEIVED, &tv, &res );
+ switch ( rc ) {
+ case 0:
/* FIXME: res should not need to be freed */
assert( res == NULL );
-
- /* check time limit */
- if ( op->ors_tlimit != SLAP_NO_LIMIT
- && slap_get_time() > stoptime )
- {
- doabandon = 1;
- rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
- savepriv = op->o_private;
- op->o_private = (void *)i;
- send_ldap_result( op, rs );
- op->o_private = savepriv;
- goto finish;
- }
-
continue;
- } else if ( rc == -1 ) {
+ case -1:
really_bad:;
/* something REALLY bad happened! */
if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
candidates[ i ].sr_type = REP_RESULT;
if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
- switch ( meta_back_search_start( op, rs, &dc, msc, i, candidates ) )
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
{
case META_SEARCH_CANDIDATE:
- goto get_result;
+ /* get back into business... */
+ continue;
+
+ /* means that failed but onerr == continue */
+ case META_SEARCH_NOT_CANDIDATE:
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ --ncandidates;
+
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ goto finish;
+ }
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ i ].sr_err = rs->sr_err;
+ }
+ break;
+
+ case META_SEARCH_BINDING:
+ case META_SEARCH_NEED_BIND:
+ assert( 0 );
default:
+ /* unrecoverable error */
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
rc = rs->sr_err = LDAP_OTHER;
goto finish;
}
}
- savepriv = op->o_private;
- op->o_private = (void *)i;
- send_ldap_result( op, rs );
- op->o_private = savepriv;
- goto finish;
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ goto finish;
+ }
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ i ].sr_err = rs->sr_err;
+ }
}
/*
* When no candidates are left,
* the outer cycle finishes
*/
- candidates[ i ].sr_msgid = -1;
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ assert( ncandidates > 0 );
--ncandidates;
- rs->sr_err = candidates[ i ].sr_err = LDAP_OTHER;
- rs->sr_text = "remote server unavailable";
+ rs->sr_err = candidates[ i ].sr_err;
+ continue;
- } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
- if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
- /* don't retry any more... */
- candidates[ i ].sr_type = REP_RESULT;
+ default:
+ /* only touch when activity actually took place... */
+ if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
+ msc->msc_time = op->o_time;
}
+ break;
+ }
+
+ for ( msg = ldap_first_message( msc->msc_ld, res );
+ msg != NULL;
+ msg = ldap_next_message( msc->msc_ld, msg ) )
+ {
+ rc = ldap_msgtype( msg );
+ if ( rc == LDAP_RES_SEARCH_ENTRY ) {
+ LDAPMessage *e;
- is_ok++;
+ if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
+ /* don't retry any more... */
+ candidates[ i ].sr_type = REP_RESULT;
+ }
- e = ldap_first_entry( msc->msc_ld, res );
- savepriv = op->o_private;
- op->o_private = (void *)i;
- rs->sr_err = meta_send_entry( op, rs, mc, i, e );
- ldap_msgfree( res );
- res = NULL;
+ is_ok++;
- switch ( rs->sr_err ) {
- case LDAP_SIZELIMIT_EXCEEDED:
+ e = ldap_first_entry( msc->msc_ld, msg );
savepriv = op->o_private;
op->o_private = (void *)i;
- send_ldap_result( op, rs );
- op->o_private = savepriv;
- rs->sr_err = LDAP_SUCCESS;
- goto finish;
+ rs->sr_err = meta_send_entry( op, rs, mc, i, e );
- case LDAP_UNAVAILABLE:
- rs->sr_err = LDAP_OTHER;
- goto finish;
- }
- op->o_private = savepriv;
-
- /* don't wait any longer... */
- gotit = 1;
- tv.tv_sec = 0;
- tv.tv_usec = 0;
-
-#if 0
- /*
- * If scope is BASE, we need to jump out
- * as soon as one entry is found; if
- * the target pool is properly crafted,
- * this should correspond to the sole
- * entry that has the base DN
- */
- /* FIXME: this defeats the purpose of
- * doing a search with scope == base and
- * sizelimit = 1 to determine if a
- * candidate is actually unique */
- if ( op->ors_scope == LDAP_SCOPE_BASE
- && rs->sr_nentries > 0 )
- {
- doabandon = 1;
- ncandidates = 0;
- sres = LDAP_SUCCESS;
- break;
- }
-#endif
-
- } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
- char **references = NULL;
- int cnt;
-
- if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
- /* don't retry any more... */
- candidates[ i ].sr_type = REP_RESULT;
- }
+ switch ( rs->sr_err ) {
+ case LDAP_SIZELIMIT_EXCEEDED:
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ rs->sr_err = LDAP_SUCCESS;
+ ldap_msgfree( res );
+ res = NULL;
+ goto finish;
- is_ok++;
+ case LDAP_UNAVAILABLE:
+ rs->sr_err = LDAP_OTHER;
+ ldap_msgfree( res );
+ res = NULL;
+ goto finish;
+ }
+ op->o_private = savepriv;
- rc = ldap_parse_reference( msc->msc_ld, res,
- &references, &rs->sr_ctrls, 1 );
- res = NULL;
+ /* don't wait any longer... */
+ gotit = 1;
+ save_tv.tv_sec = 0;
+ save_tv.tv_usec = 0;
- if ( rc != LDAP_SUCCESS ) {
- continue;
- }
+ } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
+ char **references = NULL;
+ int cnt;
- if ( references == NULL ) {
- continue;
- }
+ if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
+ /* don't retry any more... */
+ candidates[ i ].sr_type = REP_RESULT;
+ }
+
+ is_ok++;
+
+ rc = ldap_parse_reference( msc->msc_ld, msg,
+ &references, &rs->sr_ctrls, 0 );
+
+ if ( rc != LDAP_SUCCESS ) {
+ continue;
+ }
+
+ if ( references == NULL ) {
+ continue;
+ }
#ifdef ENABLE_REWRITE
- dc.ctx = "referralDN";
+ dc.ctx = "referralDN";
#else /* ! ENABLE_REWRITE */
- dc.tofrom = 0;
- dc.normalized = 0;
+ dc.tofrom = 0;
+ dc.normalized = 0;
#endif /* ! ENABLE_REWRITE */
- /* FIXME: merge all and return at the end */
-
- for ( cnt = 0; references[ cnt ]; cnt++ )
- ;
-
- rs->sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
-
- for ( cnt = 0; references[ cnt ]; cnt++ ) {
- ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] );
- }
- BER_BVZERO( &rs->sr_ref[ cnt ] );
-
- ( void )ldap_back_referral_result_rewrite( &dc, rs->sr_ref );
-
- if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
- /* ignore return value by now */
- savepriv = op->o_private;
- op->o_private = (void *)i;
- ( void )send_search_reference( op, rs );
- op->o_private = savepriv;
-
- ber_bvarray_free( rs->sr_ref );
- rs->sr_ref = NULL;
- }
+ /* FIXME: merge all and return at the end */
+
+ for ( cnt = 0; references[ cnt ]; cnt++ )
+ ;
+
+ rs->sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
+
+ for ( cnt = 0; references[ cnt ]; cnt++ ) {
+ ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] );
+ }
+ BER_BVZERO( &rs->sr_ref[ cnt ] );
+
+ ( void )ldap_back_referral_result_rewrite( &dc, rs->sr_ref );
- /* cleanup */
- if ( references ) {
- ber_memvfree( (void **)references );
- }
+ if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
+ /* ignore return value by now */
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ ( void )send_search_reference( op, rs );
+ op->o_private = savepriv;
+
+ ber_bvarray_free( rs->sr_ref );
+ rs->sr_ref = NULL;
+ }
- if ( rs->sr_ctrls ) {
- ldap_controls_free( rs->sr_ctrls );
- rs->sr_ctrls = NULL;
- }
+ /* cleanup */
+ if ( references ) {
+ ber_memvfree( (void **)references );
+ }
- } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
- char buf[ SLAP_TEXT_BUFLEN ];
- char **references = NULL;
+ if ( rs->sr_ctrls ) {
+ ldap_controls_free( rs->sr_ctrls );
+ rs->sr_ctrls = NULL;
+ }
- if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
- /* don't retry any more... */
- candidates[ i ].sr_type = REP_RESULT;
- }
+ } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+ char **references = NULL;
- /* NOTE: ignores response controls
- * (and intermediate response controls
- * as well, except for those with search
- * references); this may not be correct,
- * but if they're not ignored then
- * back-meta would need to merge them
- * consistently (think of pagedResults...)
- */
- rs->sr_err = ldap_parse_result( msc->msc_ld,
- res,
- &candidates[ i ].sr_err,
- (char **)&candidates[ i ].sr_matched,
- NULL /* (char **)&candidates[ i ].sr_text */ ,
- &references,
- NULL /* &candidates[ i ].sr_ctrls (unused) */ ,
- 1 );
- res = NULL;
- if ( rs->sr_err != LDAP_SUCCESS ) {
- ldap_get_option( msc->msc_ld,
+ if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
+ /* don't retry any more... */
+ candidates[ i ].sr_type = REP_RESULT;
+ }
+
+ /* NOTE: ignores response controls
+ * (and intermediate response controls
+ * as well, except for those with search
+ * references); this may not be correct,
+ * but if they're not ignored then
+ * back-meta would need to merge them
+ * consistently (think of pagedResults...)
+ */
+ /* FIXME: response controls? */
+ rs->sr_err = ldap_parse_result( msc->msc_ld,
+ msg,
+ &candidates[ i ].sr_err,
+ (char **)&candidates[ i ].sr_matched,
+ NULL /* (char **)&candidates[ i ].sr_text */ ,
+ &references,
+ NULL /* &candidates[ i ].sr_ctrls (unused) */ ,
+ 0 );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ ldap_get_option( msc->msc_ld,
LDAP_OPT_ERROR_NUMBER,
&rs->sr_err );
- sres = slap_map_api2result( rs );
- candidates[ i ].sr_type = REP_RESULT;
- goto really_bad;
- }
-
- /* massage matchedDN if need be */
- if ( candidates[ i ].sr_matched != NULL ) {
-#ifndef LDAP_NULL_IS_NULL
- if ( candidates[ i ].sr_matched[ 0 ] == '\0' ) {
- ldap_memfree( (char *)candidates[ i ].sr_matched );
- candidates[ i ].sr_matched = NULL;
+ sres = slap_map_api2result( rs );
+ candidates[ i ].sr_type = REP_RESULT;
+ ldap_msgfree( res );
+ res = NULL;
+ goto really_bad;
+ }
- } else
-#endif /* LDAP_NULL_IS_NULL */
- {
+ /* massage matchedDN if need be */
+ if ( candidates[ i ].sr_matched != NULL ) {
struct berval match, mmatch;
ber_str2bv( candidates[ i ].sr_matched,
candidates[ i ].sr_matched = NULL;
dc.ctx = "matchedDN";
- dc.target = &mi->mi_targets[ i ];
+ dc.target = mi->mi_targets[ i ];
if ( !ldap_back_dn_massage( &dc, &match, &mmatch ) ) {
if ( mmatch.bv_val == match.bv_val ) {
- candidates[ i ].sr_matched = ch_strdup( mmatch.bv_val );
+ candidates[ i ].sr_matched
+ = ch_strdup( mmatch.bv_val );
} else {
candidates[ i ].sr_matched = mmatch.bv_val;
}
ldap_memfree( match.bv_val );
}
- }
-
-#ifndef LDAP_NULL_IS_NULL
- /* just get rid of the error message, if any */
- if ( candidates[ i ].sr_text && candidates[ i ].sr_text[ 0 ] == '\0' )
- {
- ldap_memfree( (char *)candidates[ i ].sr_text );
- candidates[ i ].sr_text = NULL;
- }
-#endif /* LDAP_NULL_IS_NULL */
-
- /* add references to array */
- if ( references ) {
- BerVarray sr_ref;
- int cnt;
-
- for ( cnt = 0; references[ cnt ]; cnt++ )
- ;
-
- sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
-
- for ( cnt = 0; references[ cnt ]; cnt++ ) {
- ber_str2bv( references[ cnt ], 0, 1, &sr_ref[ cnt ] );
- }
- BER_BVZERO( &sr_ref[ cnt ] );
- ( void )ldap_back_referral_result_rewrite( &dc, sr_ref );
-
- /* cleanup */
- ber_memvfree( (void **)references );
-
- if ( rs->sr_v2ref == NULL ) {
- rs->sr_v2ref = sr_ref;
+ /* add references to array */
+ if ( references ) {
+ BerVarray sr_ref;
+ int cnt;
+
+ for ( cnt = 0; references[ cnt ]; cnt++ )
+ ;
+
+ sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
+
+ for ( cnt = 0; references[ cnt ]; cnt++ ) {
+ ber_str2bv( references[ cnt ], 0, 1, &sr_ref[ cnt ] );
+ }
+ BER_BVZERO( &sr_ref[ cnt ] );
+
+ ( void )ldap_back_referral_result_rewrite( &dc, sr_ref );
+
+ /* cleanup */
+ ber_memvfree( (void **)references );
+
+ if ( rs->sr_v2ref == NULL ) {
+ rs->sr_v2ref = sr_ref;
- } else {
- for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
- ber_bvarray_add( &rs->sr_v2ref, &sr_ref[ cnt ] );
+ } else {
+ for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
+ ber_bvarray_add( &rs->sr_v2ref, &sr_ref[ cnt ] );
+ }
+ ber_memfree( sr_ref );
}
- ber_memfree( sr_ref );
}
- }
-
- rs->sr_err = candidates[ i ].sr_err;
- sres = slap_map_api2result( rs );
-
- if ( StatslogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
- snprintf( buf, sizeof( buf ),
- "%s meta_back_search[%ld] "
- "match=\"%s\" err=%ld",
- op->o_log_prefix, i,
- candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
- (long) candidates[ i ].sr_err );
- if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_TRACE, "%s.\n", buf, 0, 0 );
-
- } else {
- Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
- buf, ldap_err2string( candidates[ i ].sr_err ), 0 );
+
+ rs->sr_err = candidates[ i ].sr_err;
+ sres = slap_map_api2result( rs );
+
+ if ( StatslogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
+ snprintf( buf, sizeof( buf ),
+ "%s meta_back_search[%ld] "
+ "match=\"%s\" err=%ld",
+ op->o_log_prefix, i,
+ candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
+ (long) candidates[ i ].sr_err );
+ if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE, "%s.\n", buf, 0, 0 );
+
+ } else {
+ Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
+ buf, ldap_err2string( candidates[ i ].sr_err ), 0 );
+ }
}
- }
-
- switch ( sres ) {
- case LDAP_NO_SUCH_OBJECT:
- /* is_ok is touched any time a valid
- * (even intermediate) result is
- * returned; as a consequence, if
- * a candidate returns noSuchObject
- * it is ignored and the candidate
- * is simply demoted. */
- if ( is_ok ) {
- sres = LDAP_SUCCESS;
+
+ switch ( sres ) {
+ case LDAP_NO_SUCH_OBJECT:
+ /* is_ok is touched any time a valid
+ * (even intermediate) result is
+ * returned; as a consequence, if
+ * a candidate returns noSuchObject
+ * it is ignored and the candidate
+ * is simply demoted. */
+ if ( is_ok ) {
+ sres = LDAP_SUCCESS;
+ }
+ break;
+
+ case LDAP_SUCCESS:
+ case LDAP_REFERRAL:
+ is_ok++;
+ break;
+
+ case LDAP_SIZELIMIT_EXCEEDED:
+ /* if a target returned sizelimitExceeded
+ * and the entry count is equal to the
+ * proxy's limit, the target would have
+ * returned more, and the error must be
+ * propagated to the client; otherwise,
+ * the target enforced a limit lower
+ * than what requested by the proxy;
+ * ignore it */
+ if ( rs->sr_nentries == op->ors_slimit
+ || META_BACK_ONERR_STOP( mi ) )
+ {
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ ldap_msgfree( res );
+ res = NULL;
+ goto finish;
+ }
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ i ].sr_err = rs->sr_err;
+ }
+ break;
+
+ default:
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ ldap_msgfree( res );
+ res = NULL;
+ goto finish;
+ }
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ i ].sr_err = rs->sr_err;
+ }
+ break;
}
- break;
-
- case LDAP_SUCCESS:
- case LDAP_REFERRAL:
- is_ok++;
- break;
-
- case LDAP_SIZELIMIT_EXCEEDED:
- /* if a target returned sizelimitExceeded
- * and the entry count is equal to the
- * proxy's limit, the target would have
- * returned more, and the error must be
- * propagated to the client; otherwise,
- * the target enforced a limit lower
- * than what requested by the proxy;
- * ignore it */
- if ( rs->sr_nentries == op->ors_slimit
- || META_BACK_ONERR_STOP( mi ) )
- {
- savepriv = op->o_private;
- op->o_private = (void *)i;
- send_ldap_result( op, rs );
- op->o_private = savepriv;
- goto finish;
+
+ last = i;
+ rc = 0;
+
+ /*
+ * When no candidates are left,
+ * the outer cycle finishes
+ */
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ --ncandidates;
+
+ } else if ( rc == LDAP_RES_BIND ) {
+ meta_search_candidate_t retcode;
+
+ retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, msg );
+ if ( retcode == META_SEARCH_CANDIDATE ) {
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates );
}
- break;
-
- default:
- if ( META_BACK_ONERR_STOP( mi ) ) {
- savepriv = op->o_private;
- op->o_private = (void *)i;
- send_ldap_result( op, rs );
- op->o_private = savepriv;
- goto finish;
+
+ switch ( retcode ) {
+ case META_SEARCH_CANDIDATE:
+ break;
+
+ /* means that failed but onerr == continue */
+ case META_SEARCH_NOT_CANDIDATE:
+ case META_SEARCH_ERR:
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ --ncandidates;
+
+ if ( META_BACK_ONERR_STOP( mi ) ) {
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ ldap_msgfree( res );
+ res = NULL;
+ goto finish;
+ }
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ candidates[ i ].sr_err = rs->sr_err;
+ }
+ break;
+
+ default:
+ assert( 0 );
+ break;
}
- break;
+
+ } else {
+ assert( 0 );
+ ldap_msgfree( res );
+ res = NULL;
+ goto really_bad;
}
-
- last = i;
- rc = 0;
-
- /*
- * When no candidates are left,
- * the outer cycle finishes
- */
- candidates[ i ].sr_msgid = -1;
- --ncandidates;
-
- } else {
- assert( 0 );
- goto really_bad;
}
+
+ ldap_msgfree( res );
+ res = NULL;
}
/* check for abandon */
if ( op->o_abandon || doabandon ) {
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- metasingleconn_t *msc = &mc->mc_conns[ i ];
+ if ( candidates[ i ].sr_msgid >= 0 ) {
+ if ( META_IS_BINDING( &candidates[ i ] ) ) {
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
+ /* if still binding, destroy */
- if ( candidates[ i ].sr_msgid != -1 ) {
- ldap_abandon_ext( msc->msc_ld,
- candidates[ i ].sr_msgid,
- NULL, NULL );
- candidates[ i ].sr_msgid = -1;
+#ifdef DEBUG_205
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf), "%s meta_back_search(abandon) "
+ "ldap_unbind_ext[%ld] mc=%p ld=%p",
+ op->o_log_prefix, i, (void *)mc,
+ (void *)mc->mc_conns[i].msc_ld );
+
+ Debug( LDAP_DEBUG_ANY, "### %s\n", buf, 0, 0 );
+#endif /* DEBUG_205 */
+
+ meta_clear_one_candidate( op, mc, i );
+ }
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ META_BINDING_CLEAR( &candidates[ i ] );
+
+ } else {
+ (void)meta_back_cancel( mc, op, rs,
+ candidates[ i ].sr_msgid, i,
+ LDAP_BACK_DONTSEND );
+ }
+
+ candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+ assert( ncandidates > 0 );
+ --ncandidates;
}
}
if ( op->o_abandon ) {
rc = SLAPD_ABANDON;
- goto finish;
+ /* let send_ldap_result play cleanup handlers (ITS#4645) */
+ break;
}
}
/* if no entry was found during this loop,
* set a minimal timeout */
- if ( gotit == 0 ) {
- LDAP_BACK_TV_SET( &tv );
- ldap_pvt_thread_yield();
+ if ( ncandidates > 0 && gotit == 0 ) {
+ if ( save_tv.tv_sec == 0 && save_tv.tv_usec == 0 ) {
+ save_tv.tv_usec = LDAP_BACK_RESULT_UTIMEOUT/initial_candidates;
+
+ /* arbitrarily limit to something between 1 and 2 minutes */
+ } else if ( ( stoptime == -1 && save_tv.tv_sec < 60 )
+ || save_tv.tv_sec < ( stoptime - slap_get_time() ) / ( 2 * ncandidates ) )
+ {
+ /* double the timeout */
+ lutil_timermul( &save_tv, 2, &save_tv );
+ }
+
+#if 0
+ if ( StatslogTest( LDAP_DEBUG_TRACE ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ), "%s %ld.%06ld %d/%d mc=%p",
+ op->o_log_prefix, save_tv.tv_sec, save_tv.tv_usec,
+ ncandidates, initial_candidates, mc );
+ Debug( LDAP_DEBUG_TRACE, "### %s\n", buf, 0, 0 );
+ for ( i = 0; i < mi->mi_ntargets; i++ ) {
+ if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
+ continue;
+ }
+
+ snprintf( buf, sizeof( buf ), "[%ld] ld=%p%s%s\n",
+ i,
+ mc->mc_conns[ i ].msc_ld,
+ ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND ) ? " needbind" : "",
+ META_IS_BINDING( &candidates[ i ] ) ? " binding" : "" );
+ Debug( LDAP_DEBUG_TRACE, "### %s\n", buf, 0, 0 );
+ }
+ }
+#endif
+
+ if ( alreadybound == 0 ) {
+#if 0
+ Debug( LDAP_DEBUG_TRACE, "### %s select(%ld.%06ld)\n",
+ op->o_log_prefix, save_tv.tv_sec, save_tv.tv_usec );
+#endif
+ tv = save_tv;
+ (void)select( 0, NULL, NULL, NULL, &tv );
+
+ } else {
+ ldap_pvt_thread_yield();
+ }
}
}
/*
* FIXME: need a better strategy to handle errors
*/
- rc = meta_back_op_result( mc, op, rs, META_TARGET_NONE );
+ if ( mc ) {
+ rc = meta_back_op_result( mc, op, rs, META_TARGET_NONE,
+ -1, stoptime != -1 ? (stoptime - slap_get_time()) : 0,
+ LDAP_BACK_SENDERR );
+ } else {
+ rc = rs->sr_err;
+ }
goto finish;
}
/* we use the first one */
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- if ( candidates[ i ].sr_tag == META_CANDIDATE
+ if ( META_IS_CANDIDATE( &candidates[ i ] )
&& candidates[ i ].sr_matched != NULL )
{
struct berval bv, pbv;
* ignore the matchedDN */
if ( sres == LDAP_SUCCESS
&& candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
- && op->o_req_ndn.bv_len > mi->mi_targets[ i ].mt_nsuffix.bv_len )
+ && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
{
free( (char *)candidates[ i ].sr_matched );
candidates[ i ].sr_matched = NULL;
#if 0
{
- char buf[BUFSIZ];
- char cnd[BUFSIZ];
+ char buf[ SLAP_TEXT_BUFLEN ];
+ char cnd[ SLAP_TEXT_BUFLEN ];
int i;
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- if ( candidates[ i ].sr_tag == META_CANDIDATE ) {
+ if ( META_IS_CANDIDATE( &candidates[ i ] ) ) {
cnd[ i ] = '*';
} else {
cnd[ i ] = ' ';
/*
* In case we returned at least one entry, we return LDAP_SUCCESS
* otherwise, the latter error code we got
- *
- * FIXME: we should handle error codes and return the more
- * important/reasonable
*/
- if ( sres == LDAP_SUCCESS && rs->sr_v2ref ) {
- sres = LDAP_REFERRAL;
+ if ( sres == LDAP_SUCCESS ) {
+ if ( rs->sr_v2ref ) {
+ sres = LDAP_REFERRAL;
+ }
+
+ if ( META_BACK_ONERR_REPORT( mi ) ) {
+ /*
+ * Report errors, if any
+ *
+ * FIXME: we should handle error codes and return the more
+ * important/reasonable
+ */
+ for ( i = 0; i < mi->mi_ntargets; i++ ) {
+ if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
+ continue;
+ }
+
+ if ( candidates[ i ].sr_err != LDAP_SUCCESS
+ && candidates[ i ].sr_err != LDAP_NO_SUCH_OBJECT )
+ {
+ sres = candidates[ i ].sr_err;
+ break;
+ }
+ }
+ }
}
+
rs->sr_err = sres;
rs->sr_matched = matched;
rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
}
for ( i = 0; i < mi->mi_ntargets; i++ ) {
- if ( candidates[ i ].sr_tag != META_CANDIDATE ) {
+ if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
continue;
}
+ if ( mc && META_IS_BINDING( &candidates[ i ] ) ) {
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
+ assert( candidates[ i ].sr_msgid >= 0 );
+ assert( mc->mc_conns[ i ].msc_ld != NULL );
+
+#ifdef DEBUG_205
+ Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) "
+ "ldap_unbind_ext[%ld] ld=%p\n",
+ op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld );
+#endif /* DEBUG_205 */
+
+ /* if still binding, destroy */
+ meta_clear_one_candidate( op, mc, i );
+ }
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ META_BINDING_CLEAR( &candidates[ i ] );
+ }
+
if ( candidates[ i ].sr_matched ) {
free( (char *)candidates[ i ].sr_matched );
candidates[ i ].sr_matched = NULL;
ldap_controls_free( candidates[ i ].sr_ctrls );
candidates[ i ].sr_ctrls = NULL;
}
+
+ if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
+ meta_back_quarantine( op, &candidates[ i ], i );
+ }
+
+ /* only in case of timelimit exceeded, if the timelimit exceeded because
+ * one contacted target never responded, invalidate the connection
+ * NOTE: should we quarantine the target as well? right now, the connection
+ * is invalidated; the next time it will be recreated and the target
+ * will be quarantined if it cannot be contacted */
+ if ( mi->mi_idle_timeout != 0
+ && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED
+ && op->o_time > mc->mc_conns[ i ].msc_time )
+ {
+ /* don't let anyone else use this expired connection */
+ LDAP_BACK_CONN_TAINTED_SET( mc );
+ }
}
if ( mc ) {
/*
* Rewrite the dn of the result, if needed
*/
- dc.target = &mi->mi_targets[ target ];
+ dc.target = mi->mi_targets[ target ];
dc.conn = op->o_conn;
dc.rs = rs;
dc.ctx = "searchResult";
slap_syntax_validate_func *validate;
slap_syntax_transform_func *pretty;
- ldap_back_map( &mi->mi_targets[ target ].mt_rwmap.rwm_at,
+ ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at,
&a, &mapped, BACKLDAP_REMAP );
if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
( void )ber_scanf( &ber, "x" /* [W] */ );
struct berval *bv;
for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
- ldap_back_map( &mi->mi_targets[ target ].mt_rwmap.rwm_oc,
+ ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
bv, &mapped, BACKLDAP_REMAP );
if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
free( bv->bv_val );
mc_curr.mc_conn = conn;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, ">>> meta_back_conn_destroy" );
+#endif /* META_BACK_PRINT_CONNTREE */
while ( ( mc = avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )&mc_curr, meta_back_conn_cmp ) ) != NULL )
{
Debug( LDAP_DEBUG_TRACE,
"=>meta_back_conn_destroy: destroying conn %ld\n",
- LDAP_BACK_PCONN_ID( mc->mc_conn ), 0, 0 );
+ LDAP_BACK_PCONN_ID( mc ), 0, 0 );
assert( mc->mc_refcnt == 0 );
meta_back_conn_free( mc );
}
+#if META_BACK_PRINT_CONNTREE > 0
+ meta_back_print_conntree( mi, "<<< meta_back_conn_destroy" );
+#endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
/*
* Cleanup rewrite session
*/
for ( i = 0; i < mi->mi_ntargets; ++i ) {
- rewrite_session_delete( mi->mi_targets[ i ].mt_rwmap.rwm_rw, conn );
+ rewrite_session_delete( mi->mi_targets[ i ]->mt_rwmap.rwm_rw, conn );
}
return 0;
int t;
for ( t = 0; t < mi->mi_ntargets; t++ ) {
- char **urls = ldap_str2charray( mi->mi_targets[ t ].mt_uri, " " );
+ char **urls = ldap_str2charray( mi->mi_targets[ t ]->mt_uri, " " );
int u;
for ( u = 0; urls[ u ] != NULL; u++ ) {
return roc;
}
+
static int
rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
rwm_op_state *ros )
BackendDB *be )
{
slap_overinst *on = (slap_overinst *) be->bd_info;
- struct ldapmapping *mapping = NULL;
struct ldaprwmap *rwmap;
#ifdef ENABLE_REWRITE
char *rargv[ 3 ];
rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
#endif /* ENABLE_REWRITE */
- if ( rwm_map_init( &rwmap->rwm_oc, &mapping ) != LDAP_SUCCESS ||
- rwm_map_init( &rwmap->rwm_at, &mapping ) != LDAP_SUCCESS )
- {
- rc = 1;
- goto error_return;
- }
-
error_return:;
on->on_bi.bi_private = (void *)rwmap;
struct ldapmapping *mapping;
char *src, *dst;
int is_oc = 0;
+ int rc = 0;
if ( argc < 3 || argc > 4 ) {
fprintf( stderr,
if ( strcmp( argv[2], "*" ) == 0 ) {
if ( argc < 4 || strcmp( argv[3], "*" ) == 0 ) {
map->drop_missing = ( argc < 4 );
- return 0;
+ goto success_return;
}
src = dst = argv[3];
avl_insert( &map->remap, (caddr_t)&mapping[1],
rwm_mapping_cmp, rwm_mapping_dup );
- return 0;
+success_return:;
+ if ( !is_oc && map->map == NULL ) {
+ /* only init if required */
+ rc = rwm_map_init( map, &mapping ) != LDAP_SUCCESS;
+ }
+
+ return rc;
error_return:;
if ( mapping ) {
/* FIXME: I don't think this is needed any more... */
rc = slap_str2ad( "objectClass", &mapping[0].m_src_ad, &text );
if ( rc != LDAP_SUCCESS ) {
+ ch_free( mapping );
return rc;
}
Avlnode *tree;
struct ldapmapping fmapping;
+ if ( map == NULL ) {
+ return 0;
+ }
+
assert( m != NULL );
if ( remap == RWM_REMAP ) {
{
struct ldapmapping *mapping;
+ /* map->map may be NULL when mapping is configured,
+ * but map->remap can't */
+ if ( map->remap == NULL ) {
+ *bv = *s;
+ return;
+ }
+
BER_BVZERO( bv );
( void )rwm_mapping( map, s, &mapping, remap );
if ( mapping != NULL ) {