]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#7084 ACL of 'manage' gives pasword administrator access
authorOndřej Kuzník <ondra@mistotebe.net>
Wed, 3 Jun 2020 12:40:03 +0000 (13:40 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Fri, 3 Jul 2020 20:42:14 +0000 (20:42 +0000)
Password administrators can bypass safeModify, password quality checks
and trigger reset if policy instructs the server to.

doc/man/man5/slapo-ppolicy.5
servers/slapd/overlays/ppolicy.c

index e7168d849de545bf28c26168e467640e8aeafc61..401b182749abcf67075456be9d31d3009f3ace17 100644 (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
index f3bed2dac57dbbc8e86ef07b5509261e439e8254..c9610de06ab0fc4aa69b56a1f6a74f2300e5fd2b 100644 (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'? */