From 3ebb40c4ddfc5ec2d3445a831a35096b48a7862f Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Thu, 15 Jun 2006 23:12:38 +0000 Subject: [PATCH] port identity assertion to back-meta; share as much code as possible with back-ldap; misc cleanup --- servers/slapd/back-ldap/add.c | 3 +- servers/slapd/back-ldap/back-ldap.h | 94 ++++--- servers/slapd/back-ldap/bind.c | 62 ++--- servers/slapd/back-ldap/compare.c | 5 +- servers/slapd/back-ldap/config.c | 315 ++++++++++++--------- servers/slapd/back-ldap/delete.c | 3 +- servers/slapd/back-ldap/extended.c | 6 +- servers/slapd/back-ldap/init.c | 2 +- servers/slapd/back-ldap/modify.c | 3 +- servers/slapd/back-ldap/modrdn.c | 3 +- servers/slapd/back-ldap/proto-ldap.h | 4 + servers/slapd/back-ldap/search.c | 11 +- servers/slapd/back-meta/add.c | 31 ++- servers/slapd/back-meta/back-meta.h | 26 +- servers/slapd/back-meta/bind.c | 403 ++++++++++++++++++++++++--- servers/slapd/back-meta/candidates.c | 4 +- servers/slapd/back-meta/compare.c | 20 +- servers/slapd/back-meta/config.c | 143 +++++++++- servers/slapd/back-meta/conn.c | 24 +- servers/slapd/back-meta/delete.c | 25 +- servers/slapd/back-meta/init.c | 23 +- servers/slapd/back-meta/modify.c | 30 +- servers/slapd/back-meta/modrdn.c | 27 +- servers/slapd/back-meta/search.c | 94 +++++-- 24 files changed, 999 insertions(+), 362 deletions(-) diff --git a/servers/slapd/back-ldap/add.c b/servers/slapd/back-ldap/add.c index 260b57aea7..cb46b16f35 100644 --- a/servers/slapd/back-ldap/add.c +++ b/servers/slapd/back-ldap/add.c @@ -93,7 +93,8 @@ ldap_back_add( attrs[ i ] = NULL; ctrls = op->o_ctrls; - rs->sr_err = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, 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; diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index 3df8356d15..26528bcd6d 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -44,18 +44,23 @@ typedef struct ldapconn_t { 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_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) + #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) @@ -96,18 +101,6 @@ typedef struct ldapconn_t { time_t lc_time; } ldapconn_t; -/* - * identity assertion modes - */ -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 -}; - /* * operation enumeration for timeouts */ @@ -137,6 +130,47 @@ typedef struct slap_retry_info_t { #define SLAP_RETRYNUM_FINITE(n) ((n) > SLAP_RETRYNUM_FOREVER) /* not forever */ } slap_retry_info_t; +/* + * identity assertion modes + */ +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 li_idassert_flags li_idassert.si_flags + + BerVarray si_authz; +#define li_idassert_authz li_idassert.si_authz +} slap_idassert_t; + /* * Hook to allow mucking with ldapinfo_t when quarantine is over */ @@ -166,27 +200,7 @@ typedef struct ldapinfo_t { #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 -#define LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ 0x08U -#define LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND 0x10U - - BerVarray li_idassert_authz; + slap_idassert_t li_idassert; /* end of ID assert stuff */ int li_nretries; diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index c05e0ee777..bd33fd5dab 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -971,24 +971,6 @@ retry_lock:; 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; @@ -1743,23 +1725,24 @@ done:; int ldap_back_proxy_authz_ctrl( 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 ( li->li_version ) { + switch ( version ) { case LDAP_VERSION3: break; @@ -1776,8 +1759,8 @@ ldap_back_proxy_authz_ctrl( /* 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; } @@ -1796,7 +1779,7 @@ ldap_back_proxy_authz_ctrl( 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 @@ -1823,18 +1806,18 @@ ldap_back_proxy_authz_ctrl( 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 ) ) + } 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 */ goto done; } - } else if ( li->li_idassert_authz && !be_isroot( op ) ) { + } else if ( si->si_authz && !be_isroot( op ) ) { int rc; struct berval authcDN; @@ -1843,11 +1826,10 @@ ldap_back_proxy_authz_ctrl( } 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; @@ -1882,7 +1864,7 @@ ldap_back_proxy_authz_ctrl( mode = LDAP_BACK_IDASSERT_NOASSERT; } else { - mode = li->li_idassert_mode; + mode = si->si_mode; } switch ( mode ) { @@ -1915,7 +1897,7 @@ ldap_back_proxy_authz_ctrl( 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: @@ -1943,7 +1925,7 @@ ldap_back_proxy_authz_ctrl( 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: @@ -1965,7 +1947,7 @@ ldap_back_proxy_authz_ctrl( * to encode the value of the authzID (and called it proxyDN); * this hack provides compatibility with those DSAs that * implement it this way */ - if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) { + if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) { struct berval authzID = ctrls[ 0 ]->ldctl_value; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; @@ -1995,7 +1977,7 @@ free_ber:; goto done; } - } else if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) { + } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) { struct berval authzID = ctrls[ 0 ]->ldctl_value, tmp; BerElementBuffer berbuf; diff --git a/servers/slapd/back-ldap/compare.c b/servers/slapd/back-ldap/compare.c index e37e986bc3..b14de0d68d 100644 --- a/servers/slapd/back-ldap/compare.c +++ b/servers/slapd/back-ldap/compare.c @@ -36,6 +36,8 @@ ldap_back_compare( Operation *op, SlapReply *rs ) { + ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; + ldapconn_t *lc; ber_int_t msgid; int do_retry = 1; @@ -49,7 +51,8 @@ ldap_back_compare( } ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, 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; diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index 14a44a51ed..05846e015e 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -512,6 +512,181 @@ slap_retry_info_destroy( ri->ri_num = NULL; } +static int +slap_idassert_authzfrom_parse( ConfigArgs *c, slap_idassert_t *si ) +{ + ldapinfo_t *li = ( ldapinfo_t * )c->be->be_private; + struct berval bv; + 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 \": " + "invalid syntax" ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + return 1; + } + ber_bvarray_add( &li->li_idassert_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 \": " + "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 \": " + "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 \": " + "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 \": " + "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 \" " + "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 \" " + "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 \": " + "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[ 2 ]; + + snprintf( c.log, sizeof( c.log ), "%s: line %d", fname, lineno ); + c.argc = 2; + c.argv = argv; + argv[ 0 ] = arg; + argv[ 1 ] = 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 ) { @@ -689,7 +864,7 @@ ldap_back_cf_gen( ConfigArgs *c ) /* 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; @@ -912,7 +1087,7 @@ ldap_back_cf_gen( ConfigArgs *c ) 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: @@ -1315,22 +1490,9 @@ done_url:; ber_str2bv( c->argv[ 1 ], 0, 1, &li->li_idassert_passwd ); break; - case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: { - struct berval bv; - 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 \": " - "invalid syntax" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); - return 1; - } - 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 */ @@ -1341,122 +1503,7 @@ done_url:; 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 \": " - "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 \": " - "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 \": " - "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 \": " - "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 if ( strcasecmp( flags[ j ], "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 \" " - "incompatible with previously issued \"obsolete-encoding-workaround\" flag.\n", - c->fname, c->lineno, 0 ); - err = 1; - break; - - } else { - li->li_idassert_flags |= LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ; - } - - } else if ( strcasecmp( flags[ j ], "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 \" " - "incompatible with previously issued \"obsolete-proxy-authz\" flag.\n", - c->fname, c->lineno, 0 ); - err = 1; - break; - - } else { - li->li_idassert_flags |= LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND; - } - - } else { - snprintf( c->msg, sizeof( c->msg ), - "\"idassert-bind \": " - "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 ], &li->li_idassert ) ) { - return 1; - } - } + rc = slap_idassert_parse( c, &li->li_idassert ); break; case LDAP_BACK_CFG_REBIND: diff --git a/servers/slapd/back-ldap/delete.c b/servers/slapd/back-ldap/delete.c index 3394a5aeba..43e88540b4 100644 --- a/servers/slapd/back-ldap/delete.c +++ b/servers/slapd/back-ldap/delete.c @@ -51,7 +51,8 @@ ldap_back_delete( } ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, 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; diff --git a/servers/slapd/back-ldap/extended.c b/servers/slapd/back-ldap/extended.c index 2bf37c49e3..9af2738a8b 100644 --- a/servers/slapd/back-ldap/extended.c +++ b/servers/slapd/back-ldap/extended.c @@ -42,6 +42,8 @@ static struct exop { static int ldap_back_extended_one( Operation *op, SlapReply *rs, BI_op_extended exop ) { + ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private; + ldapconn_t *lc; LDAPControl **oldctrls = NULL; int rc; @@ -56,7 +58,9 @@ ldap_back_extended_one( Operation *op, SlapReply *rs, BI_op_extended exop ) } oldctrls = op->o_ctrls; - if ( ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, 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; diff --git a/servers/slapd/back-ldap/init.c b/servers/slapd/back-ldap/init.c index 396eb912e5..74ef0b6b44 100644 --- a/servers/slapd/back-ldap/init.c +++ b/servers/slapd/back-ldap/init.c @@ -126,7 +126,7 @@ ldap_back_db_init( Backend *be ) 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; diff --git a/servers/slapd/back-ldap/modify.c b/servers/slapd/back-ldap/modify.c index e3ad3d5aba..60ccc51687 100644 --- a/servers/slapd/back-ldap/modify.c +++ b/servers/slapd/back-ldap/modify.c @@ -99,7 +99,8 @@ ldap_back_modify( modv[ i ] = 0; ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, 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; diff --git a/servers/slapd/back-ldap/modrdn.c b/servers/slapd/back-ldap/modrdn.c index 304482922f..2f92a0003d 100644 --- a/servers/slapd/back-ldap/modrdn.c +++ b/servers/slapd/back-ldap/modrdn.c @@ -74,7 +74,8 @@ ldap_back_modrdn( } ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, 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; diff --git a/servers/slapd/back-ldap/proto-ldap.h b/servers/slapd/back-ldap/proto-ldap.h index 72dd5f359b..10539d1d35 100644 --- a/servers/slapd/back-ldap/proto-ldap.h +++ b/servers/slapd/back-ldap/proto-ldap.h @@ -68,6 +68,8 @@ extern void ldap_back_conn_free( void *c ); extern int ldap_back_proxy_authz_ctrl( struct berval *bound_ndn, + int version, + slap_idassert_t *si, Operation *op, SlapReply *rs, LDAPControl ***pctrls ); @@ -87,6 +89,8 @@ 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_initialize( void ); #ifdef LDAP_DEVEL diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index cc17bc06af..175341bc1e 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -203,7 +203,8 @@ ldap_back_search( } ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, 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; } @@ -708,9 +709,10 @@ ldap_back_entry_get( ObjectClass *oc, AttributeDescription *at, int rw, - Entry **ent -) + Entry **ent ) { + ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private; + ldapconn_t *lc; int rc = 1, do_not_cache; @@ -760,7 +762,8 @@ ldap_back_entry_get( } ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, 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; } diff --git a/servers/slapd/back-meta/add.c b/servers/slapd/back-meta/add.c index af2663549f..1b56d7ed8c 100644 --- a/servers/slapd/back-meta/add.c +++ b/servers/slapd/back-meta/add.c @@ -36,6 +36,7 @@ int 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; @@ -45,6 +46,7 @@ meta_back_add( Operation *op, SlapReply *rs ) dncookie dc; int msgid; int do_retry = 1; + LDAPControl **ctrls = NULL; int maperr = 1; Debug(LDAP_DEBUG_ARGS, "==> meta_back_add: %s\n", @@ -63,7 +65,8 @@ meta_back_add( Operation *op, SlapReply *rs ) /* * 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"; @@ -96,7 +99,7 @@ meta_back_add( Operation *op, SlapReply *rs ) 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; @@ -121,11 +124,11 @@ meta_back_add( Operation *op, SlapReply *rs ) 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 ]; @@ -165,9 +168,17 @@ meta_back_add( Operation *op, SlapReply *rs ) } attrs[ i ] = NULL; + 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 ) + { + maperr = 0; + goto sendres; + } + retry:; 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 ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { @@ -180,8 +191,8 @@ retry:; 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 ]; + if ( mt->mt_timeout[ LDAP_BACK_OP_ADD ] != 0 ) { + tv.tv_sec = mt->mt_timeout[ LDAP_BACK_OP_ADD ]; tv.tv_usec = 0; tvp = &tv; } @@ -201,6 +212,7 @@ retry:; break; case LDAP_RES_ADD: + /* FIXME: matched? referrals? response controls? */ rc = ldap_parse_result( mc->mc_conns[ candidate ].msc_ld, res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 ); if ( rc != LDAP_SUCCESS ) { @@ -215,13 +227,16 @@ retry:; } } +sendres:; + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + if ( maperr ) { rs->sr_err = meta_back_op_result( mc, op, rs, candidate ); } else { send_ldap_result( op, rs ); - if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ candidate ] ) ) { + if ( META_BACK_TGT_QUARANTINE( mt ) ) { meta_back_quarantine( op, rs, candidate ); } } diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index c5a4ee4c1f..9d42fae474 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -229,8 +229,19 @@ typedef struct metatarget_t { 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) @@ -400,6 +411,17 @@ meta_back_single_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, diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index b5df2a52fd..9f5c009229 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -34,6 +34,16 @@ #include "../back-ldap/back-ldap.h" #include "back-meta.h" +#include "lutil_ldap.h" + +static int +meta_back_proxy_authz_bind( + metaconn_t *mc, + int candidate, + Operation *op, + SlapReply *rs, + ldap_back_send_t sendok ); + int meta_back_bind( Operation *op, SlapReply *rs ) { @@ -140,7 +150,8 @@ meta_back_bind( Operation *op, SlapReply *rs ) } if ( isroot ) { - if ( BER_BVISNULL( &mt->mt_pseudorootdn ) ) + if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE + || BER_BVISNULL( &mt->mt_idassert_authcDN ) ) { metasingleconn_t *msc = &mc->mc_conns[ i ]; @@ -163,9 +174,14 @@ meta_back_bind( Operation *op, SlapReply *rs ) continue; } - op2.o_req_dn = mt->mt_pseudorootdn; - op2.o_req_ndn = mt->mt_pseudorootdn; - op2.orb_cred = mt->mt_pseudorootpw; + /* FIXME: if sb_method == LDAP_AUTH_SASL things differ a bit */ + if ( mt->mt_idassert_authmethod == LDAP_AUTH_SASL ) { + /* ### */ + } + + op2.o_req_dn = mt->mt_idassert_authcDN; + op2.o_req_ndn = mt->mt_idassert_authcDN; + op2.orb_cred = mt->mt_idassert_passwd; op2.orb_method = LDAP_AUTH_SIMPLE; massage = 0; @@ -233,7 +249,7 @@ retry_lock:; } ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn ); - if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { + if ( isroot ) { mc->mc_conn = LDAP_BACK_PCONN_SET( op ); } lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc, @@ -310,7 +326,7 @@ retry:; switch ( ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) { case 0: Debug( LDAP_DEBUG_ANY, - "%s meta_back_single_bind[%d]: ldap_result=0 nretries=%d.\n", + "%s meta_back_bind_op_result[%d]: ldap_result=0 nretries=%d.\n", op->o_log_prefix, candidate, nretries ); if ( nretries != META_RETRY_NEVER ) { @@ -334,11 +350,12 @@ retry:; "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 ); break; default: + /* 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 ) { @@ -416,7 +433,20 @@ meta_back_single_bind( 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; @@ -468,41 +498,18 @@ meta_back_single_dobind( assert( !LDAP_BACK_CONN_ISBOUND( msc ) ); - /* - * meta_back_single_dobind() calls meta_back_single_bind() - * if required. - */ - if ( be_isroot( op ) && !BER_BVISNULL( &mt->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 ) || + ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) { - Operation op2 = *op; - - op2.o_tag = LDAP_REQ_BIND; - op2.o_req_dn = mt->mt_pseudorootdn; - op2.o_req_ndn = mt->mt_pseudorootdn; - op2.orb_cred = mt->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? */ rs->sr_err = ldap_sasl_bind( msc->msc_ld, "", LDAP_SASL_SIMPLE, &cred, @@ -576,7 +583,7 @@ meta_back_dobind( for ( i = 0; i < mi->mi_ntargets; i++ ) { metatarget_t *mt = mi->mi_targets[ i ]; metasingleconn_t *msc = &mc->mc_conns[ i ]; - int rc, do_retry = 1; + int rc; /* * Not a candidate @@ -593,7 +600,10 @@ meta_back_dobind( 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; @@ -608,7 +618,6 @@ retry_binding:; 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 ); /* @@ -625,10 +634,11 @@ retry:; } - if ( rc == LDAP_UNAVAILABLE && do_retry ) { - do_retry = 0; + if ( rc == LDAP_UNAVAILABLE ) { + /* FIXME: meta_back_retry() already calls + * meta_back_single_dobind() */ if ( meta_back_retry( op, rs, &mc, i, sendok ) ) { - goto retry; + goto retry_ok; } if ( mc != NULL ) { @@ -668,7 +678,8 @@ retry:; continue; } /* else */ - + +retry_ok:; Debug( LDAP_DEBUG_TRACE, "%s meta_back_dobind[%d]: " "(%s)\n", @@ -983,3 +994,303 @@ meta_back_op_result( return ( ( rerr == LDAP_SUCCESS ) ? 0 : -1 ); } +/* + * 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 ); +} diff --git a/servers/slapd/back-meta/candidates.c b/servers/slapd/back-meta/candidates.c index a3c3732c92..64b56cc8ad 100644 --- a/servers/slapd/back-meta/candidates.c +++ b/servers/slapd/back-meta/candidates.c @@ -214,9 +214,7 @@ meta_clear_candidates( Operation *op, metaconn_t *mc ) 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 ] ); - } + meta_clear_one_candidate( &mc->mc_conns[ c ] ); } return 0; diff --git a/servers/slapd/back-meta/compare.c b/servers/slapd/back-meta/compare.c index 75272d6744..7b9ab02430 100644 --- a/servers/slapd/back-meta/compare.c +++ b/servers/slapd/back-meta/compare.c @@ -74,6 +74,8 @@ meta_back_compare( Operation *op, SlapReply *rs ) 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; + metatarget_t *mt = mi->mi_targets[ i ]; + LDAPControl **ctrls = NULL; if ( ! META_IS_CANDIDATE( &candidates[ i ] ) ) { msgid[ i ] = -1; @@ -83,7 +85,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) /* * Rewrite the compare dn, if needed */ - dc.target = mi->mi_targets[ i ]; + dc.target = mt; switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { case LDAP_UNWILLING_TO_PERFORM: @@ -98,7 +100,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) * 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, + ldap_back_map( &mt->mt_rwmap.rwm_oc, &op->orc_ava->aa_value, &mapped_value, BACKLDAP_MAP ); @@ -109,7 +111,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) * else try to remap the attribute */ } else { - ldap_back_map( &mi->mi_targets[ i ]->mt_rwmap.rwm_at, + ldap_back_map( &mt->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' ) { @@ -132,6 +134,13 @@ meta_back_compare( Operation *op, SlapReply *rs ) } } + ctrls = op->o_ctrls; + if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ i ].msc_bound_ndn, + mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS ) + { + continue; + } + /* * the compare op is spawned across the targets and the first * that returns determines the result; a constraint on unicity @@ -139,7 +148,9 @@ meta_back_compare( Operation *op, SlapReply *rs ) */ 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 ] ); + ctrls, NULL, &msgid[ i ] ); + + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { free( mdn.bv_val ); @@ -208,6 +219,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) goto finish; } + /* FIXME: matched? referrals? response controls? */ rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 ); diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index 555d51b7e6..e5230859e8 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -781,10 +781,12 @@ meta_back_db_config( } /* 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 ); } @@ -800,7 +802,7 @@ meta_back_db_config( 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; } @@ -956,15 +958,74 @@ meta_back_db_config( 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= + credentials= + mode=none + flags=non-prescriptive +idassert-authzFrom "dn:" + + * so that only when authc'd as the proxying occurs + * rebinding as the 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 */ @@ -984,7 +1045,65 @@ meta_back_db_config( 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 in \"idassert-authzFrom \".\n", + fname, lineno, 0 ); + return 1; + + default: + Debug( LDAP_DEBUG_ANY, + "%s: line %d: extra cruft after in \"idassert-authzFrom \".\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 ) { diff --git a/servers/slapd/back-meta/conn.c b/servers/slapd/back-meta/conn.c index 3be9cacb40..82cb41b403 100644 --- a/servers/slapd/back-meta/conn.c +++ b/servers/slapd/back-meta/conn.c @@ -368,6 +368,7 @@ retry:; 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; @@ -443,21 +444,28 @@ retry:; */ 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 ) ) { + 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 ) @@ -484,7 +492,7 @@ retry:; } } else { - ber_str2bv( "", 0, 1, &msc->msc_bound_ndn ); + ber_dupbv( &msc->msc_bound_ndn, &slap_empty_bv ); } } diff --git a/servers/slapd/back-meta/delete.c b/servers/slapd/back-meta/delete.c index bb29bcb177..dd105b0756 100644 --- a/servers/slapd/back-meta/delete.c +++ b/servers/slapd/back-meta/delete.c @@ -35,6 +35,7 @@ int 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; @@ -42,6 +43,7 @@ meta_back_delete( Operation *op, SlapReply *rs ) 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 ) ) { @@ -53,7 +55,8 @@ meta_back_delete( Operation *op, SlapReply *rs ) /* * 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"; @@ -63,9 +66,17 @@ meta_back_delete( Operation *op, SlapReply *rs ) goto done; } + 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 ) + { + maperr = 0; + goto sendres; + } + retry:; 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 ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { @@ -78,8 +89,8 @@ retry:; 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 ]; + if ( mt->mt_timeout[ LDAP_BACK_OP_DELETE ] != 0 ) { + tv.tv_sec = mt->mt_timeout[ LDAP_BACK_OP_DELETE ]; tv.tv_usec = 0; tvp = &tv; } @@ -100,6 +111,7 @@ retry:; break; case LDAP_RES_DELETE: + /* FIXME: matched? referrals? response controls? */ rc = ldap_parse_result( mc->mc_conns[ candidate ].msc_ld, res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 ); if ( rc != LDAP_SUCCESS ) { @@ -114,13 +126,16 @@ retry:; } } +sendres:; + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + if ( maperr ) { rs->sr_err = meta_back_op_result( mc, op, rs, candidate ); } else { send_ldap_result( op, rs ); - if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ candidate ] ) ) { + if ( META_BACK_TGT_QUARANTINE( mt ) ) { meta_back_quarantine( op, rs, candidate ); } } diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index c06fbd277b..7fee4d1c3f 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -230,11 +230,26 @@ target_free( 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_pseudorootpw ) ) { - free( mt->mt_pseudorootpw.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 ( 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 ); diff --git a/servers/slapd/back-meta/modify.c b/servers/slapd/back-meta/modify.c index 00c1d62977..61796fe2d2 100644 --- a/servers/slapd/back-meta/modify.c +++ b/servers/slapd/back-meta/modify.c @@ -35,6 +35,7 @@ int 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; @@ -48,6 +49,7 @@ meta_back_modify( Operation *op, SlapReply *rs ) 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 ) ) { @@ -59,7 +61,8 @@ meta_back_modify( Operation *op, SlapReply *rs ) /* * 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"; @@ -102,7 +105,7 @@ meta_back_modify( Operation *op, SlapReply *rs ) 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 ) ) { @@ -129,11 +132,11 @@ meta_back_modify( Operation *op, SlapReply *rs ) 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 ]; @@ -174,9 +177,17 @@ meta_back_modify( Operation *op, SlapReply *rs ) } modv[ i ] = 0; + 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 ) { + maperr = 0; + goto cleanup; + } + retry:; 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 ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { @@ -188,8 +199,8 @@ retry:; 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 ]; + if ( mt->mt_timeout[ LDAP_BACK_OP_MODIFY ] != 0 ) { + tv.tv_sec = mt->mt_timeout[ LDAP_BACK_OP_MODIFY ]; tv.tv_usec = 0; tvp = &tv; } @@ -210,6 +221,7 @@ retry:; break; case LDAP_RES_MODIFY: + /* FIXME: matched? referrals? response controls? */ rc = ldap_parse_result( mc->mc_conns[ candidate ].msc_ld, res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 ); if ( rc != LDAP_SUCCESS ) { @@ -226,13 +238,15 @@ retry:; } cleanup:; + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + if ( maperr ) { rc = meta_back_op_result( mc, op, rs, candidate ); } else { send_ldap_result( op, rs ); - if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ candidate ] ) ) { + if ( META_BACK_TGT_QUARANTINE( mt ) ) { meta_back_quarantine( op, rs, candidate ); } } diff --git a/servers/slapd/back-meta/modrdn.c b/servers/slapd/back-meta/modrdn.c index 16a3f1320d..d9db0df771 100644 --- a/servers/slapd/back-meta/modrdn.c +++ b/servers/slapd/back-meta/modrdn.c @@ -35,6 +35,7 @@ int 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, @@ -43,6 +44,7 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) 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 ) ) { @@ -51,6 +53,8 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) assert( mc->mc_conns[ candidate ].msc_ld != NULL ); + mt = mi->mi_targets[ candidate ]; + dc.target = mt; dc.conn = op->o_conn; dc.rs = rs; @@ -76,7 +80,7 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) */ /* needs LDAPv3 */ - switch ( mi->mi_targets[ candidate ]->mt_version ) { + switch ( mt->mt_version ) { case LDAP_VERSION3: break; @@ -97,7 +101,6 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) /* * 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; @@ -109,7 +112,6 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) /* * 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; @@ -117,11 +119,19 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) goto cleanup; } + 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 ) + { + maperr = 0; + goto cleanup; + } + retry:; 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 ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { @@ -134,8 +144,8 @@ retry:; 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 ]; + if ( mt->mt_timeout[ LDAP_BACK_OP_MODRDN ] != 0 ) { + tv.tv_sec = mt->mt_timeout[ LDAP_BACK_OP_MODRDN ]; tv.tv_usec = 0; tvp = &tv; } @@ -155,6 +165,7 @@ retry:; break; case LDAP_RES_RENAME: + /* FIXME: matched? referrals? response controls? */ rc = ldap_parse_result( mc->mc_conns[ candidate ].msc_ld, res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 ); if ( rc != LDAP_SUCCESS ) { @@ -170,13 +181,15 @@ retry:; } cleanup:; + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + if ( maperr ) { meta_back_op_result( mc, op, rs, candidate ); } else { send_ldap_result( op, rs ); - if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ candidate ] ) ) { + if ( META_BACK_TGT_QUARANTINE( mt ) ) { meta_back_quarantine( op, rs, candidate ); } } diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index 17493f2391..554d921f11 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -76,11 +76,11 @@ meta_search_dobind_init( metatarget_t *mt = mi->mi_targets[ candidate ]; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; - char *binddn = ""; - struct berval cred = BER_BVC( "" ); + struct berval binddn = BER_BVC( "" ), + cred = BER_BVC( "" ); + int method; int rc; - int nretries = 1; meta_search_candidate_t retcode; @@ -108,42 +108,61 @@ meta_search_dobind_init( LDAP_BACK_CONN_BINDING_SET( msc ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - if ( be_isroot( op ) && !BER_BVISNULL( &mt->mt_pseudorootdn ) ) { - binddn = mt->mt_pseudorootdn.bv_val; - cred = mt->mt_pseudorootpw; - } + /* 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; + } - /* - * 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 ); + /* 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 ) ) { + ber_dupbv( &msc->msc_cred, &cred ); + } + } + + if ( LDAP_BACK_CONN_ISBOUND( msc ) ) { + /* idassert ws configured with SASL bind */ + 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; + } } -retry:; assert( msc->msc_ld != NULL ); - rc = ldap_sasl_bind( msc->msc_ld, binddn, LDAP_SASL_SIMPLE, &cred, + rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &candidates[ candidate ].sr_msgid ); switch ( rc ) { case LDAP_SUCCESS: META_BINDING_SET( &candidates[ candidate ] ); return META_SEARCH_BINDING; +down:; case LDAP_SERVER_DOWN: - if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) { - nretries = 0; - goto retry; + if ( meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) { + return META_SEARCH_CANDIDATE; } if ( *mcp == NULL ) { @@ -195,12 +214,14 @@ meta_search_dobind_result( 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, 1 ); - if ( rc == LDAP_SUCCESS ) { - rc = slap_map_api2result( &candidates[ candidate ] ); + if ( rc != LDAP_SUCCESS ) { + candidates[ candidate ].sr_err = rc; } + rc = slap_map_api2result( &candidates[ candidate ] ); ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); LDAP_BACK_CONN_BINDING_CLEAR( msc ); @@ -248,6 +269,7 @@ meta_back_search_start( 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 ) { @@ -402,6 +424,15 @@ meta_back_search_start( tvp = &tv; } + 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 */ @@ -410,7 +441,7 @@ retry:; 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 ); switch ( rc ) { case LDAP_SUCCESS: @@ -435,6 +466,8 @@ retry:; } done:; + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + if ( mapped_attrs ) { free( mapped_attrs ); } @@ -892,6 +925,7 @@ really_bad:; * back-meta would need to merge them * consistently (think of pagedResults...) */ + /* FIXME: response controls? */ rs->sr_err = ldap_parse_result( msc->msc_ld, res, &candidates[ i ].sr_err, -- 2.39.5