ITS#7084 ACL of 'manage' gives pasword administrator access

Password administrators can bypass safeModify, password quality checks
and trigger reset if policy instructs the server to.
This commit is contained in:
Ondřej Kuzník 2020-06-03 13:40:03 +01:00 committed by Quanah Gibson-Mount
parent a030aacc39
commit 376d5d65cb
2 changed files with 41 additions and 11 deletions

View file

@ -31,6 +31,11 @@ identity; all the operations, when performed with any other identity,
may be subjected to constraints, like access control. This overlay
requires a rootdn to be configured on the database.
.P
During password update, an identity with
.B manage
access to the userPassword attribute is considered a password
administrator where relevant to the IETF Password Policy proposal.
.P
Note that the IETF Password Policy proposal for LDAP makes sense
when considering a single-valued password attribute, while
the userPassword attribute allows multiple values. This implementation

View file

@ -2031,7 +2031,7 @@ ppolicy_modify( Operation *op, SlapReply *rs )
LDAPPasswordPolicyError pErr = PP_noError;
LDAPControl *ctrl = NULL;
LDAPControl **oldctrls = NULL;
int is_pwdexop = 0;
int is_pwdexop = 0, is_pwdadmin = 0;
int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0,
got_del_success = 0;
int got_changed = 0, got_history = 0;
@ -2191,6 +2191,10 @@ ppolicy_modify( Operation *op, SlapReply *rs )
goto do_modify;
}
if ( access_allowed( op, e, pp.ad, NULL, ACL_MANAGE, NULL ) ) {
is_pwdadmin = 1;
}
for ( ml = op->orm_modlist,
pwmod = 0, mod_pw_only = 1,
deladd = 0, delmod = NULL,
@ -2327,7 +2331,7 @@ ppolicy_modify( Operation *op, SlapReply *rs )
for(p=tl; p; p=p->next, hsize++); /* count history size */
}
if (be_isroot( op )) goto do_modify;
if (is_pwdadmin) goto do_modify;
/* NOTE: according to draft-behera-ldap-password-policy
* pwdAllowUserChange == FALSE must only prevent pwd changes
@ -2575,15 +2579,36 @@ do_modify:
modtail = mods;
}
/* Delete the pwdReset attribute, since it's being reset */
if ((zapReset) && (attr_find(e->e_attrs, ad_pwdReset ))) {
mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
mods->sml_op = LDAP_MOD_DELETE;
mods->sml_desc = ad_pwdReset;
mods->sml_flags = SLAP_MOD_INTERNAL;
mods->sml_next = NULL;
modtail->sml_next = mods;
modtail = mods;
if ( zapReset ) {
/*
* ITS#7084 Is this a modification by the password
* administrator? Then force a reset if configured.
* Otherwise clear it.
*/
if ( pp.pwdMustChange && is_pwdadmin ) {
mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
mods->sml_op = LDAP_MOD_REPLACE;
mods->sml_desc = ad_pwdReset;
mods->sml_flags = SLAP_MOD_INTERNAL;
mods->sml_numvals = 1;
mods->sml_values = (BerVarray) ch_calloc( sizeof( struct berval ), 2 );
mods->sml_nvalues = (BerVarray) ch_calloc( sizeof( struct berval ), 2 );
ber_dupbv( &mods->sml_values[0], (struct berval *)&slap_true_bv );
ber_dupbv( &mods->sml_nvalues[0], (struct berval *)&slap_true_bv );
mods->sml_next = NULL;
modtail->sml_next = mods;
modtail = mods;
} else if ( attr_find( e->e_attrs, ad_pwdReset ) ) {
mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
mods->sml_op = LDAP_MOD_DELETE;
mods->sml_desc = ad_pwdReset;
mods->sml_flags = SLAP_MOD_INTERNAL;
mods->sml_next = NULL;
modtail->sml_next = mods;
modtail = mods;
}
}
/* TODO: do we remove pwdLastSuccess or set it to 'now'? */