From 467a1da79feec26cb17442611740a45c634d1d53 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Thu, 15 Apr 2010 18:13:53 +0000 Subject: [PATCH] add support for don't use copy in SASL auxprops lookup/store (ITS#6475; TODO: document new directives) --- servers/slapd/back-ldap/chain.c | 7 +- servers/slapd/bconfig.c | 134 +++++++++++++++++++++++++++++++- servers/slapd/proto-slap.h | 4 + servers/slapd/sasl.c | 129 +++++++++++++++++++++++++++++- servers/slapd/slap.h | 1 + 5 files changed, 270 insertions(+), 5 deletions(-) diff --git a/servers/slapd/back-ldap/chain.c b/servers/slapd/back-ldap/chain.c index c517f15a10..6b7036a833 100644 --- a/servers/slapd/back-ldap/chain.c +++ b/servers/slapd/back-ldap/chain.c @@ -854,6 +854,7 @@ ldap_chain_response( Operation *op, SlapReply *rs ) /* we need this to know if back-ldap returned any result */ lb.lb_lc = lc; + sc2.sc_next = sc->sc_next; sc2.sc_private = &lb; sc2.sc_response = ldap_chain_cb_response; op->o_callback = &sc2; @@ -947,6 +948,7 @@ ldap_chain_response( Operation *op, SlapReply *rs ) case LDAP_SUCCESS: case LDAP_REFERRAL: + sr_err = rs->sr_err; /* slapd-ldap sent response */ if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) { /* FIXME: should we send response? */ @@ -974,7 +976,7 @@ cannot_chain:; default: #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ if ( LDAP_CHAIN_RETURN_ERR( lc ) ) { - rs->sr_err = rc; + sr_err = rs->sr_err = rc; rs->sr_type = sr_type; } else { @@ -992,7 +994,8 @@ cannot_chain:; } if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) { - op->o_callback = NULL; + /* give the remaining callbacks a chance */ + op->o_callback = sc->sc_next; rc = rs->sr_err = slap_map_api2result( rs ); send_ldap_result( op, rs ); } diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 2987bf6d9a..1db63ea574 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -179,6 +179,8 @@ enum { CFG_LASTMOD, CFG_AZPOLICY, CFG_AZREGEXP, + CFG_AZDUC, + CFG_AZDUC_IGNORE, CFG_SASLSECP, CFG_SSTR_IF_MAX, CFG_SSTR_IF_MIN, @@ -549,6 +551,24 @@ static ConfigTable config_back_cf_table[] = { #endif "( OLcfgGlAt:89 NAME 'olcSaslAuxprops' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "sasl-auxprops-dontusecopy", NULL, 2, 0, 0, +#if defined(HAVE_CYRUS_SASL) && defined(SLAP_AUXPROP_DONTUSECOPY) + ARG_MAGIC|CFG_AZDUC, &config_generic, +#else + ARG_IGNORED, NULL, +#endif + "( OLcfgGlAt:91 NAME 'olcSaslAuxpropsDontUseCopy' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "sasl-auxprops-dontusecopy-ignore", "true|FALSE", 2, 0, 0, +#if defined(HAVE_CYRUS_SASL) && defined(SLAP_AUXPROP_DONTUSECOPY) + ARG_ON_OFF|CFG_AZDUC_IGNORE, &slap_dontUseCopy_ignore, +#else + ARG_IGNORED, NULL, +#endif + "( OLcfgGlAt:92 NAME 'olcSaslAuxpropsDontUseCopyIgnore' " + "EQUALITY booleanMatch " + "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "sasl-host", "host", 2, 2, 0, #ifdef HAVE_CYRUS_SASL ARG_STRING|ARG_UNIQUE, &sasl_host, @@ -792,7 +812,8 @@ static ConfigOCs cf_ocs[] = { "olcPluginLogFile $ olcReadOnly $ olcReferral $ " "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ " "olcRootDSE $ " - "olcSaslAuxprops $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ " + "olcSaslAuxprops $ olcSaslAuxpropsDontUseCopy $ olcSaslAuxpropsDontUseCopyIgnore $ " + "olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ " "olcSecurity $ olcServerID $ olcSizeLimit $ " "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ " "olcTCPBuffer $ " @@ -939,6 +960,47 @@ config_generic(ConfigArgs *c) { if ( !c->rvalue_vals ) rc = 1; break; #ifdef HAVE_CYRUS_SASL +#ifdef SLAP_AUXPROP_DONTUSECOPY + case CFG_AZDUC: { + static int duc_done = 0; + + /* take the opportunity to initialize with known values */ + if ( !duc_done ) { + struct berval duc[] = { BER_BVC("cmusaslsecretOTP"), BER_BVNULL }; + int i; + + for ( i = 0; !BER_BVISNULL( &duc[ i ] ); i++ ) { + const char *text = NULL; + AttributeDescription *ad = NULL; + + if ( slap_bv2ad( &duc[ i ], &ad, &text ) == LDAP_SUCCESS ) { + int gotit = 0; + if ( slap_dontUseCopy_propnames ) { + int j; + + for ( j = 0; !BER_BVISNULL( &slap_dontUseCopy_propnames[ j ] ); j++ ) { + if ( bvmatch( &slap_dontUseCopy_propnames[ j ], &ad->ad_cname ) ) { + gotit = 1; + } + } + } + + if ( !gotit ) { + value_add_one( &slap_dontUseCopy_propnames, &ad->ad_cname ); + } + } + } + + duc_done = 1; + } + + if ( slap_dontUseCopy_propnames != NULL ) { + ber_bvarray_dup_x( &c->rvalue_vals, slap_dontUseCopy_propnames, NULL ); + } else { + rc = 1; + } + } break; +#endif /* SLAP_AUXPROP_DONTUSECOPY */ case CFG_SASLSECP: { struct berval bv = BER_BVNULL; slap_sasl_secprops_unparse( &bv ); @@ -1221,6 +1283,35 @@ config_generic(ConfigArgs *c) { snprintf(c->log, sizeof( c->log ), "change requires slapd restart"); break; +#if defined(HAVE_CYRUS_SASL) && defined(SLAP_AUXPROP_DONTUSECOPY) + case CFG_AZDUC: + if ( c->valx < 0 ) { + if ( slap_dontUseCopy_propnames != NULL ) { + ber_bvarray_free( slap_dontUseCopy_propnames ); + slap_dontUseCopy_propnames = NULL; + } + + } else { + int i; + + if ( slap_dontUseCopy_propnames == NULL ) { + rc = 1; + break; + } + + for ( i = 0; !BER_BVISNULL( &slap_dontUseCopy_propnames[ i ] ) && i < c->valx; i++ ); + if ( i < c->valx ) { + rc = 1; + break; + } + ber_memfree( slap_dontUseCopy_propnames[ i ].bv_val ); + for ( ; !BER_BVISNULL( &slap_dontUseCopy_propnames[ i + 1 ] ); i++ ) { + slap_dontUseCopy_propnames[ i ] = slap_dontUseCopy_propnames[ i + 1 ]; + } + BER_BVZERO( &slap_dontUseCopy_propnames[ i ] ); + } + break; +#endif /* SLAP_AUXPROP_DONTUSECOPY */ case CFG_SALT: ch_free( passwd_salt ); passwd_salt = NULL; @@ -1556,6 +1647,47 @@ config_generic(ConfigArgs *c) { break; #ifdef HAVE_CYRUS_SASL +#ifdef SLAP_AUXPROP_DONTUSECOPY + case CFG_AZDUC: { + int arg, cnt; + + for ( arg = 1; arg < c->argc; arg++ ) { + int duplicate = 0, err; + AttributeDescription *ad = NULL; + const char *text = NULL; + + err = slap_str2ad( c->argv[ arg ], &ad, &text ); + if ( err != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s>: attr #%d (\"%s\") unknown (err=%d \"%s\"; ignored)", + c->argv[0], arg, c->argv[ arg ], err, text ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", + c->log, c->cr_msg, 0 ); + + } else { + if ( slap_dontUseCopy_propnames != NULL ) { + for ( cnt = 0; !BER_BVISNULL( &slap_dontUseCopy_propnames[ cnt ] ); cnt++ ) { + if ( bvmatch( &slap_dontUseCopy_propnames[ cnt ], &ad->ad_cname ) ) { + duplicate = 1; + break; + } + } + } + + if ( duplicate ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s>: attr #%d (\"%s\") already defined (ignored)", + c->argv[0], arg, ad->ad_cname.bv_val); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", + c->log, c->cr_msg, 0 ); + continue; + } + + value_add_one( &slap_dontUseCopy_propnames, &ad->ad_cname ); + } + } + + } break; +#endif /* SLAP_AUXPROP_DONTUSECOPY */ + case CFG_SASLSECP: { char *txt = slap_sasl_secprops( c->argv[1] ); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index fa225d9e7e..7fdf090fac 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -1965,6 +1965,10 @@ LDAP_SLAPD_V (struct berval) global_host_bv; LDAP_SLAPD_V (char *) global_realm; LDAP_SLAPD_V (char *) sasl_host; LDAP_SLAPD_V (char *) slap_sasl_auxprops; +#ifdef SLAP_AUXPROP_DONTUSECOPY +LDAP_SLAPD_V (int) slap_dontUseCopy_ignore; +LDAP_SLAPD_V (BerVarray) slap_dontUseCopy_propnames; +#endif /* SLAP_AUXPROP_DONTUSECOPY */ LDAP_SLAPD_V (char **) default_passwd_hash; LDAP_SLAPD_V (int) lber_debug; LDAP_SLAPD_V (int) ldap_syslog; diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c index fd25cf363f..ca6e7c9ce8 100644 --- a/servers/slapd/sasl.c +++ b/servers/slapd/sasl.c @@ -149,6 +149,11 @@ static const char *slap_propnames[] = { "*slapConn", "*slapAuthcDNlen", "*slapAuthcDN", "*slapAuthzDNlen", "*slapAuthzDN", NULL }; +#ifdef SLAP_AUXPROP_DONTUSECOPY +int slap_dontUseCopy_ignore; +BerVarray slap_dontUseCopy_propnames; +#endif /* SLAP_AUXPROP_DONTUSECOPY */ + static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL }; static struct berval generic_filterstr = BER_BVC("(objectclass=*)"); @@ -179,7 +184,10 @@ sasl_ap_lookup( Operation *op, SlapReply *rs ) int rc, i; lookup_info *sl = (lookup_info *)op->o_callback->sc_private; - if (rs->sr_type != REP_SEARCH) return 0; + /* return the actual error code, + * to allow caller to handle specific errors + */ + if (rs->sr_type != REP_SEARCH) return rs->sr_err; for( i = 0; sl->list[i].name; i++ ) { const char *name = sl->list[i].name; @@ -276,6 +284,10 @@ slap_auxprop_lookup( Connection *conn = NULL; lookup_info sl; int rc = LDAP_SUCCESS; +#ifdef SLAP_AUXPROP_DONTUSECOPY + int dontUseCopy = 0; + BackendDB *dontUseCopy_bd = NULL; +#endif /* SLAP_AUXPROP_DONTUSECOPY */ sl.list = sparams->utils->prop_get( sparams->propctx ); sl.sparams = sparams; @@ -312,6 +324,19 @@ slap_auxprop_lookup( break; } } +#ifdef SLAP_AUXPROP_DONTUSECOPY + if ( slap_dontUseCopy_propnames != NULL ) { + int j; + struct berval bv; + ber_str2bv( &sl.list[i].name[1], 0, 1, &bv ); + for ( j = 0; !BER_BVISNULL( &slap_dontUseCopy_propnames[ j ]); j++ ) { + if ( bvmatch( &bv, &slap_dontUseCopy_propnames[ j ] ) ) { + dontUseCopy = 1; + break; + } + } + } +#endif /* SLAP_AUXPROP_DONTUSECOPY */ } } @@ -386,8 +411,22 @@ slap_auxprop_lookup( } } +#ifdef SLAP_AUXPROP_DONTUSECOPY + if ( SLAP_SHADOW( op->o_bd ) && dontUseCopy ) { + dontUseCopy_bd = op->o_bd; + op->o_bd = frontendDB; + } + +retry_dontUseCopy:; +#endif /* SLAP_AUXPROP_DONTUSECOPY */ + if ( op->o_bd->be_search ) { SlapReply rs = {REP_RESULT}; +#ifdef SLAP_AUXPROP_DONTUSECOPY + LDAPControl **save_ctrls = NULL, c; + int save_dontUseCopy; +#endif /* SLAP_AUXPROP_DONTUSECOPY */ + op->o_hdr = conn->c_sasl_bindop->o_hdr; op->o_controls = opbuf.ob_controls; op->o_tag = LDAP_REQ_SEARCH; @@ -408,7 +447,49 @@ slap_auxprop_lookup( /* FIXME: we want all attributes, right? */ op->ors_attrs = NULL; +#ifdef SLAP_AUXPROP_DONTUSECOPY + if ( dontUseCopy ) { + save_dontUseCopy = op->o_dontUseCopy; + if ( !op->o_dontUseCopy ) { + int cnt = 0; + save_ctrls = op->o_ctrls; + if ( op->o_ctrls ) { + for ( ; op->o_ctrls[ cnt ]; cnt++ ) + ; + } + op->o_ctrls = op->o_tmpcalloc( sizeof(LDAPControl *), cnt + 2, op->o_tmpmemctx ); + if ( cnt ) { + for ( cnt = 0; save_ctrls[ cnt ]; cnt++ ) { + op->o_ctrls[ cnt ] = save_ctrls[ cnt ]; + } + } + c.ldctl_oid = LDAP_CONTROL_DONTUSECOPY; + c.ldctl_iscritical = 1; + BER_BVZERO( &c.ldctl_value ); + op->o_ctrls[ cnt ] = &c; + } + op->o_dontUseCopy = SLAP_CONTROL_CRITICAL; + } +#endif /* SLAP_AUXPROP_DONTUSECOPY */ + rc = op->o_bd->be_search( op, &rs ); + +#ifdef SLAP_AUXPROP_DONTUSECOPY + if ( dontUseCopy ) { + if ( save_ctrls != op->o_ctrls ) { + op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx ); + op->o_ctrls = save_ctrls; + op->o_dontUseCopy = save_dontUseCopy; + } + + if ( rs.sr_err == LDAP_UNAVAILABLE && slap_dontUseCopy_ignore ) + { + op->o_bd = dontUseCopy_bd; + dontUseCopy = 0; + goto retry_dontUseCopy; + } + } +#endif /* SLAP_AUXPROP_DONTUSECOPY */ } } } @@ -438,6 +519,10 @@ slap_auxprop_store( char textbuf[SLAP_TEXT_BUFLEN]; const char *text; size_t textlen = sizeof(textbuf); +#ifdef SLAP_AUXPROP_DONTUSECOPY + int dontUseCopy = 0; + BackendDB *dontUseCopy_bd = NULL; +#endif /* SLAP_AUXPROP_DONTUSECOPY */ /* just checking if we are enabled */ if (!prctx) return SASL_OK; @@ -462,6 +547,18 @@ slap_auxprop_store( if ( pr[i].values ) op.o_req_ndn.bv_val = (char *)pr[i].values[0]; } +#ifdef SLAP_AUXPROP_DONTUSECOPY + { + struct berval bv; + ber_str2bv( &pr[i].name[1], 0, 1, &bv ); + for ( j = 0; !BER_BVISNULL( &slap_dontUseCopy_propnames[ j ] ); j++ ) { + if ( bvmatch( &bv, &slap_dontUseCopy_propnames[ j ] ) ) { + dontUseCopy = 1; + break; + } + } + } +#endif /* SLAP_AUXPROP_DONTUSECOPY */ } } if (!conn || !op.o_req_ndn.bv_val) return SASL_BADPARAM; @@ -469,7 +566,15 @@ slap_auxprop_store( op.o_bd = select_backend( &op.o_req_ndn, 1 ); if ( !op.o_bd || !op.o_bd->be_modify ) return SASL_FAIL; - + +#ifdef SLAP_AUXPROP_DONTUSECOPY + if ( SLAP_SHADOW( op.o_bd ) && dontUseCopy ) { + dontUseCopy_bd = op.o_bd; + op.o_bd = frontendDB; + op.o_dontUseCopy = SLAP_CONTROL_CRITICAL; + } +#endif /* SLAP_AUXPROP_DONTUSECOPY */ + pr = sparams->utils->prop_get( prctx ); if (!pr) return SASL_BADPARAM; @@ -518,7 +623,20 @@ slap_auxprop_store( op.o_req_dn = op.o_req_ndn; op.orm_modlist = modlist; +retry_dontUseCopy:; rc = op.o_bd->be_modify( &op, &rs ); + +#ifdef SLAP_AUXPROP_DONTUSECOPY + if ( dontUseCopy && + rs.sr_err == LDAP_UNAVAILABLE && + slap_dontUseCopy_ignore ) + { + op.o_bd = dontUseCopy_bd; + op.o_dontUseCopy = SLAP_CONTROL_NONE; + dontUseCopy = 0; + goto retry_dontUseCopy; + } +#endif /* SLAP_AUXPROP_DONTUSECOPY */ } } slap_mods_free( modlist, 1 ); @@ -1188,6 +1306,13 @@ int slap_sasl_destroy( void ) { #ifdef HAVE_CYRUS_SASL sasl_done(); + +#ifdef SLAP_AUXPROP_DONTUSECOPY + if ( slap_dontUseCopy_propnames ) { + ber_bvarray_free( slap_dontUseCopy_propnames ); + slap_dontUseCopy_propnames = NULL; + } +#endif /* SLAP_AUXPROP_DONTUSECOPY */ #endif free( sasl_host ); sasl_host = NULL; diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 829b6973d1..2e7d0b28e4 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -65,6 +65,7 @@ LDAP_BEGIN_DECL #define SLAP_CONTROL_X_SESSION_TRACKING #define SLAP_CONTROL_X_WHATFAILED #define SLAP_CONFIG_DELETE +#define SLAP_AUXPROP_DONTUSECOPY #ifndef SLAP_SCHEMA_EXPOSE #define SLAP_SCHEMA_EXPOSE #endif -- 2.39.5