mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
ipa-pwd-extop: don't check password policy for non-Kerberos account set by DM or a passsync manager
Password changes performed by cn=Directory Manager are excluded from password policy checks according to [1]. This is correctly handled by ipa-pwd-extop in case of a normal Kerberos principal in IPA. However, non-kerberos accounts were not excluded from the check. As result, password updates for PKI CA admin account in o=ipaca were failing if a password policy does not allow a password reuse. We are re-setting the password for PKI CA admin in ipa-replica-prepare in case the original directory manager's password was updated since creation of `cacert.p12`. Do password policy check for non-Kerberos accounts only if it was set by a regular user or admin. Changes performed by a cn=Directory Manager and passsync managers should be excluded from the policy check. Fixes: https://pagure.io/freeipa/issue/7181 Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com> [1] https://access.redhat.com/documentation/en-us/red_hat_directory_server/10/html/administration_guide/user_account_management-managing_the_password_policy Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Christian Heimes <cheimes@redhat.com>
This commit is contained in:
committed by
Christian Heimes
parent
527f30be76
commit
d9c41df6fd
@@ -422,6 +422,7 @@ done:
|
||||
|
||||
int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e,
|
||||
int *is_root, int *is_krb, int *is_smb, int *is_ipant,
|
||||
int *is_memberof,
|
||||
char *attr, int acc)
|
||||
{
|
||||
Slapi_Value *sval;
|
||||
@@ -440,6 +441,10 @@ int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e,
|
||||
}
|
||||
}
|
||||
|
||||
/* Default to not setting memberof flag: only set it for non-Kerberos principals
|
||||
* when they have krbPrincipalAux but no krbPrincipalName */
|
||||
*is_memberof = 0;
|
||||
|
||||
/* Check if this is a krbPrincial and therefore needs us to generate other
|
||||
* hashes */
|
||||
sval = slapi_value_new_string("krbPrincipalAux");
|
||||
@@ -450,6 +455,24 @@ int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e,
|
||||
*is_krb = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sval);
|
||||
slapi_value_free(&sval);
|
||||
|
||||
/* If entry has krbPrincipalAux object class but lacks krbPrincipalName and
|
||||
* memberOf attributes consider this not a Kerberos principal object. In
|
||||
* FreeIPA krbPrincipalAux allows to store krbPwdPolicyReference attribute
|
||||
* which is added by a CoS plugin configuration based on a memberOf
|
||||
* attribute value.
|
||||
* Note that slapi_entry_attr_find() returns 0 if attr exists, -1 for absence
|
||||
*/
|
||||
if (*is_krb) {
|
||||
Slapi_Attr *attr_prname = NULL;
|
||||
Slapi_Attr *attr_memberof = NULL;
|
||||
int has_prname = slapi_entry_attr_find(e, "krbPrincipalName", &attr_prname);
|
||||
int has_memberOf = slapi_entry_attr_find(e, "memberOf", &attr_memberof);
|
||||
if ((has_prname == -1) && (has_memberOf == 0)) {
|
||||
*is_memberof = 1;
|
||||
*is_krb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sval = slapi_value_new_string("sambaSamAccount");
|
||||
if (!sval) {
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
|
||||
@@ -222,7 +222,7 @@ static int ipapwd_chpwop(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
|
||||
Slapi_Value *objectclass=NULL;
|
||||
char *attrlist[] = {"*", "passwordHistory", NULL };
|
||||
struct ipapwd_data pwdata;
|
||||
int is_krb, is_smb, is_ipant;
|
||||
int is_krb, is_smb, is_ipant, is_memberof;
|
||||
char *principal = NULL;
|
||||
Slapi_PBlock *chpwop_pb = NULL;
|
||||
Slapi_DN *target_sdn = NULL;
|
||||
@@ -348,7 +348,7 @@ parse_req_done:
|
||||
/* Determine the target DN for this operation */
|
||||
slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn);
|
||||
if (target_sdn != NULL) {
|
||||
/* If there is a TARGET_DN we are consuming it */
|
||||
/* If there is a TARGET_SDN we are consuming it */
|
||||
slapi_pblock_set(pb, SLAPI_TARGET_SDN, NULL);
|
||||
target_dn = slapi_sdn_get_ndn(target_sdn);
|
||||
}
|
||||
@@ -485,6 +485,7 @@ parse_req_done:
|
||||
|
||||
rc = ipapwd_entry_checks(pb, targetEntry,
|
||||
&is_root, &is_krb, &is_smb, &is_ipant,
|
||||
&is_memberof,
|
||||
SLAPI_USERPWD_ATTR, SLAPI_ACL_WRITE);
|
||||
if (rc) {
|
||||
goto free_and_return;
|
||||
@@ -580,17 +581,22 @@ parse_req_done:
|
||||
/* check the policy */
|
||||
ret = ipapwd_CheckPolicy(&pwdata);
|
||||
if (ret) {
|
||||
errMesg = ipapwd_error2string(ret);
|
||||
if (ret == IPAPWD_POLICY_ERROR) {
|
||||
errMesg = "Internal error";
|
||||
rc = ret;
|
||||
} else {
|
||||
goto free_and_return;
|
||||
}
|
||||
/* ipapwd_CheckPolicy happily will try to apply a policy
|
||||
* even if it doesn't need to be applied for Directory Manager
|
||||
* or passsync managers, filter that error out */
|
||||
if (pwdata.changetype != IPA_CHANGETYPE_DSMGR) {
|
||||
errMesg = ipapwd_error2string(ret);
|
||||
ret = ipapwd_to_ldap_pwpolicy_error(ret);
|
||||
slapi_pwpolicy_make_response_control(pb, -1, -1, ret);
|
||||
rc = LDAP_CONSTRAINT_VIOLATION;
|
||||
}
|
||||
goto free_and_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we're ready to set the kerberos key material */
|
||||
ret = ipapwd_SetPassword(krbcfg, &pwdata, is_krb);
|
||||
|
||||
@@ -90,6 +90,7 @@ struct ipapwd_operation {
|
||||
struct ipapwd_data pwdata;
|
||||
int pwd_op;
|
||||
int is_krb;
|
||||
int is_memberof;
|
||||
int skip_keys;
|
||||
int skip_history;
|
||||
};
|
||||
@@ -113,6 +114,7 @@ struct ipapwd_krbcfg {
|
||||
|
||||
int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e,
|
||||
int *is_root, int *is_krb, int *is_smb, int *is_ipant,
|
||||
int *is_memberof,
|
||||
char *attr, int access);
|
||||
int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg,
|
||||
struct ipapwd_krbcfg **config, int check_flags);
|
||||
|
||||
@@ -80,6 +80,8 @@ struct ipapwd_op_ext {
|
||||
int object_type; /* handle to the extended object */
|
||||
int handle; /* extension handle */
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* pre/post operations to intercept writes to userPassword
|
||||
****************************************************************************/
|
||||
@@ -217,7 +219,7 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
|
||||
Slapi_DN *sdn = NULL;
|
||||
struct ipapwd_operation *pwdop = NULL;
|
||||
void *op;
|
||||
int is_repl_op, is_root, is_krb, is_smb, is_ipant;
|
||||
int is_repl_op, is_root, is_krb, is_smb, is_ipant, is_memberof;
|
||||
int ret;
|
||||
int rc = LDAP_SUCCESS;
|
||||
|
||||
@@ -312,6 +314,7 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
|
||||
|
||||
rc = ipapwd_entry_checks(pb, e,
|
||||
&is_root, &is_krb, &is_smb, &is_ipant,
|
||||
&is_memberof,
|
||||
NULL, SLAPI_ACL_ADD);
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
goto done;
|
||||
@@ -346,6 +349,7 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
|
||||
|
||||
pwdop->pwd_op = IPAPWD_OP_ADD;
|
||||
pwdop->pwdata.password = slapi_ch_strdup(userpw);
|
||||
pwdop->is_memberof = is_memberof;
|
||||
|
||||
if (is_root) {
|
||||
pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
|
||||
@@ -367,12 +371,15 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
|
||||
}
|
||||
}
|
||||
|
||||
pwdop->pwdata.dn = slapi_ch_strdup(dn);
|
||||
pwdop->pwdata.dn = slapi_ch_strdup(slapi_sdn_get_dn(sdn));
|
||||
pwdop->pwdata.timeNow = time(NULL);
|
||||
pwdop->pwdata.target = e;
|
||||
|
||||
ret = ipapwd_CheckPolicy(&pwdop->pwdata);
|
||||
if (ret) {
|
||||
/* For accounts created by cn=Directory Manager or a passsync
|
||||
* managers, ignore result of a policy check */
|
||||
if ((pwdop->pwdata.changetype != IPA_CHANGETYPE_DSMGR) &&
|
||||
(ret != 0) ) {
|
||||
errMesg = ipapwd_error2string(ret);
|
||||
rc = LDAP_CONSTRAINT_VIOLATION;
|
||||
goto done;
|
||||
@@ -474,7 +481,7 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
|
||||
struct slapi_entry *e = NULL;
|
||||
struct ipapwd_operation *pwdop = NULL;
|
||||
void *op;
|
||||
int is_repl_op, is_pwd_op, is_root, is_krb, is_smb, is_ipant;
|
||||
int is_repl_op, is_pwd_op, is_root, is_krb, is_smb, is_ipant, is_memberof;
|
||||
int has_krb_keys = 0;
|
||||
int has_history = 0;
|
||||
int gen_krb_keys = 0;
|
||||
@@ -607,6 +614,7 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
|
||||
|
||||
rc = ipapwd_entry_checks(pb, e,
|
||||
&is_root, &is_krb, &is_smb, &is_ipant,
|
||||
&is_memberof,
|
||||
is_pwd_op ? SLAPI_USERPWD_ATTR : "ipaNTHash",
|
||||
SLAPI_ACL_WRITE);
|
||||
if (rc) {
|
||||
@@ -809,6 +817,7 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
|
||||
}
|
||||
|
||||
pwdop->is_krb = is_krb;
|
||||
pwdop->is_memberof = is_memberof;
|
||||
pwdop->pwd_op = IPAPWD_OP_MOD;
|
||||
pwdop->pwdata.password = slapi_ch_strdup(unhashedpw);
|
||||
pwdop->pwdata.changetype = IPA_CHANGETYPE_NORMAL;
|
||||
@@ -853,11 +862,13 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
|
||||
pwdop->pwdata.target = e;
|
||||
|
||||
/* if krb keys are being set by an external agent we assume password
|
||||
* policies have been properly checked already, so we check them only
|
||||
* if no krb keys are available */
|
||||
* policies have been properly checked already. We check them only if no
|
||||
* krb keys are available and raise error if the change is not done by a
|
||||
* cn=Directory Manager or one of passsync managers */
|
||||
if (has_krb_keys == 0) {
|
||||
ret = ipapwd_CheckPolicy(&pwdop->pwdata);
|
||||
if (ret) {
|
||||
if ((pwdop->pwdata.changetype != IPA_CHANGETYPE_DSMGR) &&
|
||||
(ret != 0)) {
|
||||
errMesg = ipapwd_error2string(ret);
|
||||
rc = LDAP_CONSTRAINT_VIOLATION;
|
||||
goto done;
|
||||
@@ -1069,7 +1080,7 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb)
|
||||
if (IPAPWD_OP_NULL == pwdop->pwd_op)
|
||||
return 0;
|
||||
|
||||
if ( ! (pwdop->is_krb)) {
|
||||
if ( !pwdop->is_krb || pwdop->is_memberof) {
|
||||
LOG("Not a kerberos user, ignore krb attributes\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1428,6 +1439,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
ret = ipapwd_getEntry(sdn, &entry, (char **) attrs_list);
|
||||
if (ret) {
|
||||
LOG("failed to retrieve user entry: %s\n", dn);
|
||||
slapi_sdn_free(&sdn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1452,6 +1464,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
if (current_time > expire_time && expire_time > 0) {
|
||||
LOG_FATAL("kerberos principal in %s is expired\n", dn);
|
||||
slapi_entry_free(entry);
|
||||
slapi_sdn_free(&sdn);
|
||||
slapi_send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
|
||||
"Account (Kerberos principal) is expired",
|
||||
0, NULL);
|
||||
@@ -1474,6 +1487,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
ret = ipapwd_authenticate(dn, entry, credentials);
|
||||
if (ret) {
|
||||
slapi_entry_free(entry);
|
||||
slapi_sdn_free(&sdn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user