X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Foverlays%2Fppolicy.c;h=b6a833c02bbca690ab0de9bc922cdc0daf37ac56;hb=34f4c2cb97dd6c7851e30298c7e014e170f54665;hp=3403e8084743331a9df6019c64150b5b8a5f39ca;hpb=e2ed30f7826e63c107b183e3206b6a8c88bea41c;p=openldap diff --git a/servers/slapd/overlays/ppolicy.c b/servers/slapd/overlays/ppolicy.c index 3403e80847..b6a833c02b 100644 --- a/servers/slapd/overlays/ppolicy.c +++ b/servers/slapd/overlays/ppolicy.c @@ -55,7 +55,7 @@ typedef struct pp_info { * used by all instances */ typedef struct pw_conn { - int restricted; /* TRUE if connection is restricted */ + struct berval dn; /* DN of restricted user */ } pw_conn; static pw_conn *pwcons; @@ -259,11 +259,12 @@ account_locked( Operation *op, Entry *e, return 0; } -#define PPOLICY_WARNING 0xa0L -#define PPOLICY_ERROR 0xa1L +/* IMPLICIT TAGS, all context-specific */ +#define PPOLICY_WARNING 0xa0L /* constructed + 0 */ +#define PPOLICY_ERROR 0x81L /* primitive + 1 */ -#define PPOLICY_EXPIRE 0xa0L -#define PPOLICY_GRACE 0xa1L +#define PPOLICY_EXPIRE 0x80L /* primitive + 0 */ +#define PPOLICY_GRACE 0x81L /* primitive + 1 */ static LDAPControl * create_passcontrol( int exptime, int grace, LDAPPasswordPolicyError err ) @@ -325,6 +326,8 @@ ppolicy_get( Operation *op, Entry *e, PassPolicy *pp ) memset( pp, 0, sizeof(PassPolicy) ); + pp->ad = slap_schema.si_ad_userPassword; + /* Users can change their own password by default */ pp->pwdAllowUserChange = 1; @@ -353,8 +356,6 @@ ppolicy_get( Operation *op, Entry *e, PassPolicy *pp ) #if 0 /* Only worry about userPassword for now */ if ((a = attr_find( pe->e_attrs, ad_pwdAttribute ))) slap_bv2ad( &a->a_vals[0], &pp->ad, &text ); -#else - pp->ad = slap_schema.si_ad_userPassword; #endif if ( ( a = attr_find( pe->e_attrs, ad_pwdMinAge ) ) @@ -410,7 +411,7 @@ ppolicy_get( Operation *op, Entry *e, PassPolicy *pp ) return; defaultpol: - Debug( LDAP_DEBUG_ANY, + Debug( LDAP_DEBUG_TRACE, "ppolicy_get: using default policy\n", 0, 0, 0 ); return; } @@ -434,9 +435,11 @@ password_scheme( struct berval *cred, struct berval *sch ) if (cred->bv_val[e]) { int rc; rc = lutil_passwd_scheme( cred->bv_val ); - if (rc && sch) { - sch->bv_val = cred->bv_val; - sch->bv_len = e; + if (rc) { + if (sch) { + sch->bv_val = cred->bv_val; + sch->bv_len = e; + } return LDAP_SUCCESS; } } @@ -731,8 +734,10 @@ ppolicy_bind_resp( Operation *op, SlapReply *rs ) m->sml_type = ad_pwdFailureTime->ad_cname; m->sml_desc = ad_pwdFailureTime; m->sml_values = ch_calloc( sizeof(struct berval), 2 ); + m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); ber_dupbv( &m->sml_values[0], ×tamp ); + ber_dupbv( &m->sml_nvalues[0], ×tamp ); m->sml_next = mod; mod = m; @@ -778,7 +783,9 @@ ppolicy_bind_resp( Operation *op, SlapReply *rs ) m->sml_type = ad_pwdAccountLockedTime->ad_cname; m->sml_desc = ad_pwdAccountLockedTime; m->sml_values = ch_calloc( sizeof(struct berval), 2 ); + m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); ber_dupbv( &m->sml_values[0], ×tamp ); + ber_dupbv( &m->sml_nvalues[0], ×tamp ); m->sml_next = mod; mod = m; } @@ -809,7 +816,8 @@ ppolicy_bind_resp( Operation *op, SlapReply *rs ) * that we are disallowed from doing anything * other than change password. */ - pwcons[op->o_conn->c_conn_idx].restricted = 1; + ber_dupbv( &pwcons[op->o_conn->c_conn_idx].dn, + &op->o_conn->c_ndn ); ppb->pErr = PP_changeAfterReset; @@ -880,7 +888,9 @@ grace: m->sml_type = ad_pwdGraceUseTime->ad_cname; m->sml_desc = ad_pwdGraceUseTime; m->sml_values = ch_calloc( sizeof(struct berval), 2 ); + m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); ber_dupbv( &m->sml_values[0], ×tamp ); + ber_dupbv( &m->sml_nvalues[0], ×tamp ); m->sml_next = mod; mod = m; @@ -965,7 +975,10 @@ ppolicy_bind( Operation *op, SlapReply *rs ) slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; /* Reset lockout status on all Bind requests */ - pwcons[op->o_conn->c_conn_idx].restricted = 0; + if ( !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { + ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); + BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); + } /* Root bypasses policy */ if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn )) { @@ -1019,11 +1032,14 @@ ppolicy_bind( Operation *op, SlapReply *rs ) return SLAP_CB_CONTINUE; } -/* Reset the restricted flag for the next session on this connection */ +/* Reset the restricted info for the next session on this connection */ static int ppolicy_connection_destroy( BackendDB *bd, Connection *conn ) { - pwcons[conn->c_conn_idx].restricted = 0; + if ( !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) { + ch_free( pwcons[conn->c_conn_idx].dn.bv_val ); + BER_BVZERO( &pwcons[conn->c_conn_idx].dn ); + } return SLAP_CB_CONTINUE; } @@ -1041,7 +1057,18 @@ ppolicy_restrict( send_ctrl = 1; } - if ( op->o_conn && pwcons[op->o_conn->c_conn_idx].restricted ) { + if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { + /* if the current authcDN doesn't match the one we recorded, + * then an intervening Bind has succeeded and the restriction + * no longer applies. (ITS#4516) + */ + if ( !dn_match( &op->o_conn->c_ndn, + &pwcons[op->o_conn->c_conn_idx].dn )) { + ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); + BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); + return SLAP_CB_CONTINUE; + } + Debug( LDAP_DEBUG_TRACE, "connection restricted to password changing only\n", 0, 0, 0); if ( send_ctrl ) { @@ -1155,12 +1182,25 @@ ppolicy_add( timestamp.bv_len = sizeof(timebuf); slap_timestamp( &now, ×tamp ); - attr_merge_one( op->ora_e, ad_pwdChangedTime, ×tamp, NULL ); + attr_merge_one( op->ora_e, ad_pwdChangedTime, ×tamp, ×tamp ); } } return SLAP_CB_CONTINUE; } +static int +ppolicy_mod_cb( Operation *op, SlapReply *rs ) +{ + slap_callback *sc = op->o_callback; + op->o_callback = sc->sc_next; + if ( rs->sr_err == LDAP_SUCCESS ) { + ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); + BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); + } + op->o_tmpfree( sc, op->o_tmpmemctx ); + return SLAP_CB_CONTINUE; +} + static int ppolicy_modify( Operation *op, SlapReply *rs ) { @@ -1347,13 +1387,19 @@ ppolicy_modify( Operation *op, SlapReply *rs ) } } - if (pwcons[op->o_conn->c_conn_idx].restricted && !mod_pw_only) { - Debug( LDAP_DEBUG_TRACE, - "connection restricted to password changing only\n", 0, 0, 0 ); - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password"; - pErr = PP_changeAfterReset; - goto return_results; + if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) { + if ( dn_match( &op->o_conn->c_ndn, + &pwcons[op->o_conn->c_conn_idx].dn )) { + Debug( LDAP_DEBUG_TRACE, + "connection restricted to password changing only\n", 0, 0, 0 ); + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password"; + pErr = PP_changeAfterReset; + goto return_results; + } else { + ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); + BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); + } } /* @@ -1552,7 +1598,23 @@ do_modify: struct berval timestamp; char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; time_t now = slap_get_time(); - + + /* If the conn is restricted, set a callback to clear it + * if the pwmod succeeds + */ + if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { + slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ), + op->o_tmpmemctx ); + sc->sc_next = op->o_callback; + /* Must use sc_response to insure we reset on success, before + * the client sees the response. Must use sc_cleanup to insure + * that it gets cleaned up if sc_response is not called. + */ + sc->sc_response = ppolicy_mod_cb; + sc->sc_cleanup = ppolicy_mod_cb; + op->o_callback = sc; + } + /* * keep the necessary pwd.. operational attributes * up to date. @@ -1568,7 +1630,9 @@ do_modify: if (pwmop != LDAP_MOD_DELETE) { mods->sml_op = LDAP_MOD_REPLACE; mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); + mods->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mods->sml_values[0], ×tamp ); + ber_dupbv( &mods->sml_nvalues[0], ×tamp ); mods->sml_values[1].bv_len = 0; mods->sml_values[1].bv_val = NULL; assert( mods->sml_values[0].bv_val != NULL ); @@ -1774,11 +1838,9 @@ ppolicy_parseCtrl( rs->sr_text = "passwordPolicyRequest control value not empty"; return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_iscritical ) { - rs->sr_text = "passwordPolicyRequest control invalid criticality"; - return LDAP_PROTOCOL_ERROR; - } - op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL; + op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; return LDAP_SUCCESS; }