diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c index dd4276009..60dfe1b16 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c @@ -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; @@ -655,7 +678,7 @@ int ipapwd_getEntry(Slapi_DN *sdn, Slapi_Entry **e2, char **attrlist) if (sdn == NULL) { LOG_TRACE("No entry to fetch!\n"); - return LDAP_PARAM_ERROR; + return LDAP_PARAM_ERROR; } local_sdn = slapi_sdn_dup(sdn); diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c index ad1d7e960..bae8e7400 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c @@ -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); } @@ -372,11 +372,11 @@ parse_req_done: } slapi_sdn_free(&target_sdn); - if (slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, dn )) { - LOG_FATAL("slapi_pblock_set failed!\n"); - rc = LDAP_OPERATIONS_ERROR; - goto free_and_return; - } + if (slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, dn )) { + LOG_FATAL("slapi_pblock_set failed!\n"); + rc = LDAP_OPERATIONS_ERROR; + goto free_and_return; + } if (usetxn) { Slapi_DN *sdn = slapi_sdn_new_dn_byref(dn); @@ -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,16 +581,21 @@ 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; } - goto free_and_return; } /* Now we're ready to set the kerberos key material */ diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h index d21d74ec1..31c76b3f1 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h @@ -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); diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c index 6781b8f47..8590ac98e 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c @@ -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; @@ -242,8 +244,8 @@ static int ipapwd_pre_add(Slapi_PBlock *pb) /* check this is something interesting for us first */ userpw = slapi_entry_attr_get_charptr(e, SLAPI_USERPWD_ATTR); if (!userpw) { - /* nothing interesting here */ - return 0; + /* nothing interesting here */ + return 0; } /* Ok this is interesting, @@ -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; }