diff --git a/CHANGES b/CHANGES index 1d92d67e42864e21a2786dba1db0f85f860831be..09152a5253d3ccbc5b8ddeeb285208a6a85c6e7b 100644 --- a/CHANGES +++ b/CHANGES @@ -37,6 +37,7 @@ OpenLDAP 2.4.12 Engineering Fixed slapo-memberof internal operations DN (ITS#5622) Fixed slapo-pcache attrset crash (ITS#5665) Fixed slapo-pcache caching with invalid schema (ITS#5680) + Fixed slapo-ppolicy control return on password modify exop (ITS#5711) Fixed slapo-rwm callback cleanup (ITS#5601,ITS#5687) Fixed slapo-rwm attr mapping and merging (ITS#5624) Fixed slapo-rwm objectClass filtering (ITS#5647) diff --git a/servers/slapd/overlays/ppolicy.c b/servers/slapd/overlays/ppolicy.c index 160358a9646aadcab27b864f6059c584e38ef088..99db2bd5b1326afb26c370541ed08ead84d5c286 100644 --- a/servers/slapd/overlays/ppolicy.c +++ b/servers/slapd/overlays/ppolicy.c @@ -362,20 +362,14 @@ account_locked( Operation *op, Entry *e, static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE; static LDAPControl * -create_passcontrol( int exptime, int grace, LDAPPasswordPolicyError err ) +create_passcontrol( Operation *op, int exptime, int grace, LDAPPasswordPolicyError err ) { char berbuf[LBER_ELEMENT_SIZEOF], bb2[LBER_ELEMENT_SIZEOF]; BerElement *ber = (BerElement *)berbuf, *b2 = (BerElement *)bb2; - LDAPControl *c; + LDAPControl c = { 0 }, *cp; struct berval bv; - c = ch_calloc( sizeof( LDAPControl ), 1 ); - if ( c == NULL ) { - return NULL; - } - c->ldctl_oid = (char *)ppolicy_ctrl_oid; - c->ldctl_iscritical = 0; - BER_BVZERO( &c->ldctl_value ); + BER_BVZERO( &c.ldctl_value ); ber_init2( ber, NULL, LBER_USE_DER ); ber_printf( ber, "{" /*}*/ ); @@ -401,12 +395,19 @@ create_passcontrol( int exptime, int grace, LDAPPasswordPolicyError err ) } ber_printf( ber, /*{*/ "N}" ); - if (ber_flatten2( ber, &(c->ldctl_value), 1 ) == LBER_DEFAULT) { - ch_free(c); - c = NULL; + if (ber_flatten2( ber, &(c.ldctl_value), 1 ) == LBER_DEFAULT) { + return NULL; } (void)ber_free_buf(ber); - return c; + cp = op->o_tmpalloc( sizeof( LDAPControl ) + c.ldctl_value.bv_len, op->o_tmpmemctx ); + cp->ldctl_oid = (char *)ppolicy_ctrl_oid; + cp->ldctl_iscritical = 0; + cp->ldctl_value.bv_val = (char *)&cp[1]; + cp->ldctl_value.bv_len = c.ldctl_value.bv_len; + AC_MEMCPY( cp->ldctl_value.bv_val, c.ldctl_value.bv_val, c.ldctl_value.bv_len ); + ber_memfree( c.ldctl_value.bv_val ); + + return cp; } static LDAPControl ** @@ -854,8 +855,7 @@ ctrls_cleanup( Operation *op, SlapReply *rs, LDAPControl **oldctrls ) for ( n = 0; rs->sr_ctrls[n]; n++ ) { if ( rs->sr_ctrls[n]->ldctl_oid == ppolicy_ctrl_oid ) { - ch_free( rs->sr_ctrls[n]->ldctl_value.bv_val ); - ch_free( rs->sr_ctrls[n] ); + op->o_tmpfree( rs->sr_ctrls[n], op->o_tmpmemctx ); rs->sr_ctrls[n] = (LDAPControl *)(-1); break; } @@ -1138,7 +1138,7 @@ locked: if ( ppb->pErr == PP_accountLocked && !pi->use_lockout ) { ppb->pErr = PP_noError; } - ctrl = create_passcontrol( warn, ngut, ppb->pErr ); + ctrl = create_passcontrol( op, warn, ngut, ppb->pErr ); ppb->oldctrls = add_passcontrol( op, rs, ctrl ); op->o_callback->sc_cleanup = ppolicy_ctrls_cleanup; } @@ -1251,7 +1251,7 @@ ppolicy_restrict( "connection restricted to password changing only\n", 0, 0, 0); if ( send_ctrl ) { LDAPControl *ctrl = NULL; - ctrl = create_passcontrol( -1, -1, PP_changeAfterReset ); + ctrl = create_passcontrol( op, -1, -1, PP_changeAfterReset ); oldctrls = add_passcontrol( op, rs, ctrl ); } op->o_bd->bd_info = (BackendInfo *)on->on_info; @@ -1317,7 +1317,7 @@ ppolicy_add( op->o_bd->bd_info = (BackendInfo *)on->on_info; if ( send_ctrl ) { LDAPControl *ctrl = NULL; - ctrl = create_passcontrol( -1, -1, pErr ); + ctrl = create_passcontrol( op, -1, -1, pErr ); oldctrls = add_passcontrol( op, rs, ctrl ); } send_ldap_error( op, rs, rc, "Password fails quality checking policy" ); @@ -1406,7 +1406,9 @@ ppolicy_modify( Operation *op, SlapReply *rs ) struct berval newpw = BER_BVNULL, oldpw = BER_BVNULL, *bv, cr[2]; LDAPPasswordPolicyError pErr = PP_noError; + LDAPControl *ctrl = NULL; LDAPControl **oldctrls = NULL; + int is_pwdexop = 0; op->o_bd->bd_info = (BackendInfo *)on->on_info; rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); @@ -1526,6 +1528,7 @@ ppolicy_modify( Operation *op, SlapReply *rs ) req_pwdexop_s *qpw = sc->sc_private; newpw = qpw->rs_new; oldpw = qpw->rs_old; + is_pwdexop = 1; break; } } @@ -2010,14 +2013,21 @@ return_results: op->o_bd->bd_info = (BackendInfo *)on->on_info; be_entry_release_r( op, e ); if ( send_ctrl ) { - LDAPControl *ctrl = NULL; - - ctrl = create_passcontrol( -1, -1, pErr ); + ctrl = create_passcontrol( op, -1, -1, pErr ); oldctrls = add_passcontrol( op, rs, ctrl ); } send_ldap_result( op, rs ); if ( send_ctrl ) { - ctrls_cleanup( op, rs, oldctrls ); + if ( is_pwdexop ) { + if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) { + op->o_tmpfree( oldctrls, op->o_tmpmemctx ); + } + oldctrls = NULL; + rs->sr_flags |= REP_CTRLS_MUSTBEFREED; + + } else { + ctrls_cleanup( op, rs, oldctrls ); + } } return rs->sr_err; } diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 8b623bbaba50a320a7bf80568f09f42b98c03218..f89b87304c5e8acabcf07077b72ec189b91e81a6 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -538,6 +538,14 @@ clean2:; } } + if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) { + rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */ + if ( rs->sr_ctrls ) { + slap_free_ctrls( op, rs->sr_ctrls ); + rs->sr_ctrls = NULL; + } + } + return rc; } diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 95c4e898ac109f7a92885d54341f2b928e95c37f..deba5720e9eaaac451ef8cc35df218950bb2cf44 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -2057,6 +2057,9 @@ struct SlapReply { #define REP_REF_MUSTBEFREED 0x0020U #define REP_REF_MASK (REP_REF_MUSTBEFREED) +#define REP_CTRLS_MUSTBEFREED 0x0040U +#define REP_CTRLS_MASK (REP_CTRLS_MUSTBEFREED) + #define REP_NO_ENTRYDN 0x1000U #define REP_NO_SUBSCHEMA 0x2000U #define REP_NO_OPERATIONALS (REP_NO_ENTRYDN|REP_NO_SUBSCHEMA) diff --git a/tests/scripts/test022-ppolicy b/tests/scripts/test022-ppolicy index 3a8d9d09e09f1b49302f52209c6b23fbd95e0c83..51f5f48f2cb1bd8e186d1f9e8f0ecc6e9b066406 100755 --- a/tests/scripts/test022-ppolicy +++ b/tests/scripts/test022-ppolicy @@ -142,7 +142,7 @@ $LDAPMODIFY -v -D "$USER" -h $LOCALHOST -p $PORT1 -w $PASS >> \ dn: uid=nd, ou=People, dc=example, dc=com changetype: modify delete: userpassword -userpassword: testpassword +userpassword: $PASS - replace: userpassword userpassword: 20urgle12-1 @@ -220,7 +220,7 @@ $LDAPMODIFY -v -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD >> \ dn: uid=nd, ou=People, dc=example, dc=com changetype: modify replace: userPassword -userPassword: testpassword +userPassword: $PASS - replace: pwdReset pwdReset: TRUE @@ -288,8 +288,11 @@ fi sleep 2 +OLDPASS=$PASS +PASS=successexpect + $LDAPPASSWD -h $LOCALHOST -p $PORT1 \ - -w $PASS -s failexpect -a $PASS \ + -w $OLDPASS -s $PASS -a $OLDPASS \ -D "$USER" >> $TESTOUT 2>&1 RC=$? if test $RC != 0 ; then @@ -299,10 +302,10 @@ if test $RC != 0 ; then fi echo "Testing length requirement..." - +# check control in response (ITS#5711) $LDAPPASSWD -h $LOCALHOST -p $PORT1 \ - -w failexpect -a failexpect -s spw \ - -D "$USER" > ${TESTOUT}.2 2>&1 + -w $PASS -a $PASS -s 2shr \ + -D "$USER" -e ppolicy > ${TESTOUT}.2 2>&1 RC=$? cat ${TESTOUT}.2 >> $TESTOUT if test $RC = 0 ; then @@ -316,15 +319,21 @@ if test $COUNT != 1 ; then test $KILLSERVERS != no && kill -HUP $KILLPIDS exit 1 fi +COUNT=`grep "Password is too short for policy" ${TESTOUT}.2 | wc -l` +if test $COUNT != 1 ; then + echo "Control not returned in response" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi echo "Testing hashed length requirement..." -$LDAPMODIFY -h $LOCALHOST -p $PORT1 -D "$USER" -w failexpect > \ +$LDAPMODIFY -h $LOCALHOST -p $PORT1 -D "$USER" -w $PASS > \ ${TESTOUT}.2 2>&1 << EOMODS dn: $USER changetype: modify delete: userPassword -userPassword: failexpect +userPassword: $PASS - add: userPassword userPassword: {MD5}xxxxxx