Import Upstream version 4.12.4

This commit is contained in:
geos_one
2025-08-12 22:28:56 +02:00
parent 03a8170b15
commit 9181ee2487
1629 changed files with 874094 additions and 554378 deletions

View File

@@ -33,7 +33,7 @@
* Authors:
* Simo Sorce <ssorce@redhat.com>
*
* Copyright (C) 2007-2010 Red Hat, Inc.
* Copyright (C) 2007-2023 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
@@ -248,6 +248,13 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
return 0;
}
/* Get target DN */
ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
if (ret) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
/* Ok this is interesting,
* Check this is a clear text password, or refuse operation */
if ('{' == userpw[0]) {
@@ -280,6 +287,8 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
} else {
rc = ipapwd_check_max_pwd_len(strlen(userpw_clear), &errMesg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
goto done;
}
userpw = slapi_ch_strdup(userpw_clear);
@@ -329,13 +338,6 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
goto done;
}
/* Get target DN */
ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
if (ret) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
/* time to get the operation handler */
ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op);
if (ret != 0) {
@@ -359,7 +361,6 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
} else {
char *binddn;
int i;
pwdop->pwdata.changetype = IPA_CHANGETYPE_ADMIN;
@@ -367,7 +368,7 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
slapi_pblock_get(pb, SLAPI_CONN_DN, &binddn);
/* if it is a passsync manager we also need to skip resets */
for (i = 0; i < krbcfg->num_passsync_mgrs; i++) {
for (size_t i = 0; i < krbcfg->num_passsync_mgrs; i++) {
if (strcasecmp(krbcfg->passsync_mgrs[i], binddn) == 0) {
pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
break;
@@ -385,6 +386,8 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
if ((pwdop->pwdata.changetype != IPA_CHANGETYPE_DSMGR) &&
(ret != 0) ) {
errMesg = ipapwd_error2string(ret);
LOG_PWDPOLICY("Failed to add password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
rc = LDAP_CONSTRAINT_VIOLATION;
goto done;
}
@@ -507,6 +510,13 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
goto done;
}
/* Get target DN */
ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
if (ret) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
/* grab the mods - we'll put them back later with
* our modifications appended
*/
@@ -568,6 +578,8 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
rc = ipapwd_check_max_pwd_len(bv->bv_len, &errMesg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
goto done;
}
slapi_ch_free_string(&unhashedpw);
@@ -591,14 +603,6 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
/* OK we have something interesting here, start checking for
* pre-requisites */
/* Get target DN */
ret = slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
if (ret) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
tmp_sdn = slapi_sdn_dup(sdn);
if (tmp_sdn) {
/* xxxPAR: Ideally SLAPI_MODIFY_EXISTING_ENTRY should be
@@ -795,6 +799,8 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
const char *userpw_clear = &userpw[strlen("{CLEAR}")];
rc = ipapwd_check_max_pwd_len(strlen(userpw_clear), &errMesg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
goto done;
}
unhashedpw = slapi_ch_strdup(userpw_clear);
@@ -806,9 +812,8 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
slapi_ch_free_string(&userpw);
} else if (slapi_is_encoded(userpw)) {
LOG("Pre-Encoded passwords are not valid\n");
errMesg = "Pre-Encoded passwords are not valid\n";
errMesg = "Pre-Encoded passwords are not valid";
LOG("%s (%s)\n", errMesg, slapi_sdn_get_dn(sdn));
rc = LDAP_CONSTRAINT_VIOLATION;
goto done;
}
@@ -843,7 +848,6 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
} else {
char *binddn;
Slapi_DN *bdn, *tdn;
int i;
/* Check Bind DN */
slapi_pblock_get(pb, SLAPI_CONN_DN, &binddn);
@@ -857,18 +861,16 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
pwdop->pwdata.changetype = IPA_CHANGETYPE_ADMIN;
/* if it is a passsync manager we also need to skip resets */
for (i = 0; i < krbcfg->num_passsync_mgrs; i++) {
for (size_t i = 0; i < krbcfg->num_passsync_mgrs; i++) {
if (strcasecmp(krbcfg->passsync_mgrs[i], binddn) == 0) {
pwdop->pwdata.changetype = IPA_CHANGETYPE_DSMGR;
break;
}
}
}
slapi_sdn_free(&bdn);
slapi_sdn_free(&tdn);
}
pwdop->pwdata.dn = slapi_ch_strdup(slapi_sdn_get_dn(sdn));
@@ -884,6 +886,8 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
if ((pwdop->pwdata.changetype != IPA_CHANGETYPE_DSMGR) &&
(ret != 0)) {
errMesg = ipapwd_error2string(ret);
LOG_PWDPOLICY("Check Password Policy failed for (%s) - %s/n",
pwdop->pwdata.dn, errMesg);
rc = LDAP_CONSTRAINT_VIOLATION;
goto done;
}
@@ -976,7 +980,6 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
int num_keys;
int mkvno;
int ret;
int i;
ret = slapi_entry_attr_find(entry, "ipaNTHash", &attr);
if (ret == 0) {
@@ -1008,7 +1011,7 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
ret = LDAP_UNWILLING_TO_PERFORM;
for (i = 0; i < num_keys; i++) {
for (size_t i = 0; i < num_keys; i++) {
char nthash[16];
krb5_enc_data cipher;
krb5_data plain;
@@ -1071,6 +1074,7 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb)
struct ipapwd_krbcfg *krbcfg = NULL;
char *principal = NULL;
Slapi_Value *ipahost;
Slapi_Value *zero;
LOG_TRACE("=>\n");
@@ -1167,6 +1171,13 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb)
}
slapi_value_free(&ipahost);
}
zero = slapi_value_new_string("0");
if (!slapi_entry_attr_has_syntax_value(pwdop->pwdata.target,
"passwordgraceusertime", zero)) {
/* Clear the passwordgraceusertime from the user entry */
slapi_mods_add_string(smods, LDAP_MOD_REPLACE, "passwordgraceusertime", "0");
}
slapi_value_free(&zero);
ret = ipapwd_apply_mods(pwdop->pwdata.dn, smods);
if (ret)
@@ -1201,13 +1212,20 @@ done:
* value at the end. This leaves only the password in creds for later
* validation.
*/
typedef enum {
OTP_IS_NOT_REQUIRED = 0,
OTP_IS_REQUIRED_EXPLICITLY,
OTP_IS_REQUIRED_IMPLICITLY
} otp_req_enum;
static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
struct berval *creds, bool otpreq)
struct berval *creds, otp_req_enum otpreq,
bool *notokens)
{
uint32_t auth_types;
/* Get the configured authentication types. */
auth_types = otp_config_auth_types(otp_config, entry);
*notokens = false;
/*
* IMPORTANT SECTION!
@@ -1237,7 +1255,11 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
/* With no tokens, succeed if tokens aren't required. */
if (tokens[0] == NULL) {
otp_token_free_array(tokens);
return !otpreq;
*notokens = true;
if (otpreq != OTP_IS_NOT_REQUIRED)
/* DENY: OTP is required, either explicitly or implicitly */
return false;
return true;
}
if (otp_token_validate_berval(tokens, creds, NULL)) {
@@ -1248,7 +1270,8 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
otp_token_free_array(tokens);
}
return (auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD) && !otpreq;
return (auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD) &&
(otpreq == OTP_IS_NOT_REQUIRED);
}
static int ipapwd_authenticate(const char *dn, Slapi_Entry *entry,
@@ -1403,6 +1426,11 @@ done:
}
#ifdef USE_OP_NOTE_MFA_AUTH
/* defined in ldap/servers/slapd/pblock.c in 389-ds but not exposed via slapi-plugin.h */
extern void slapi_pblock_set_flag_operation_notes(Slapi_PBlock *pb, uint32_t opflag);
#endif
/* PRE BIND Operation
*
* Used for:
@@ -1420,12 +1448,13 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
"krbPasswordExpiration", "krblastpwchange",
NULL
};
struct ipapwd_krbcfg *krbcfg = NULL;
struct berval *credentials = NULL;
Slapi_Entry *entry = NULL;
Slapi_DN *target_sdn = NULL;
Slapi_DN *sdn = NULL;
const char *dn = NULL;
int method = 0;
ber_tag_t method = 0;
bool syncreq;
bool otpreq;
int ret = 0;
@@ -1435,6 +1464,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
struct tm expire_tm;
int rc = LDAP_INVALID_CREDENTIALS;
char *errMesg = NULL;
bool notokens = false;
/* get BIND parameters */
ret |= slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &target_sdn);
@@ -1446,8 +1476,10 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
}
/* We're only interested in simple authentication. */
if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0)
if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0) {
LOG("Not handled (not simple bind or NULL dn/credentials)\n");
return 0;
}
/* Retrieve the user's entry. */
sdn = slapi_sdn_dup(target_sdn);
@@ -1491,9 +1523,28 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
/* Try to do OTP first. */
syncreq = otpctrl_present(pb, OTP_SYNC_REQUEST_OID);
otpreq = otpctrl_present(pb, OTP_REQUIRED_OID);
if (!syncreq && !ipapwd_pre_bind_otp(dn, entry, credentials, otpreq))
goto invalid_creds;
otpreq = otpctrl_present(pb, OTP_REQUIRED_OID) ?
OTP_IS_REQUIRED_EXPLICITLY : OTP_IS_NOT_REQUIRED;
if (!syncreq && (otpreq == OTP_IS_NOT_REQUIRED)) {
ret = ipapwd_gen_checks(pb, &errMesg, &krbcfg, IPAPWD_CHECK_ONLY_CONFIG);
if (ret != 0) {
LOG_FATAL("ipapwd_gen_checks failed!?\n");
slapi_entry_free(entry);
slapi_sdn_free(&sdn);
return 0;
}
if (krbcfg->enforce_ldap_otp) {
otpreq = OTP_IS_REQUIRED_IMPLICITLY;
}
}
if (!syncreq && !ipapwd_pre_bind_otp(dn, entry,
credentials, otpreq, &notokens)) {
/* We got here because ipapwd_pre_bind_otp() returned false,
* it means that either token verification failed or
* a rule for empty tokens failed current policy. */
if (!(notokens || (otpreq == OTP_IS_NOT_REQUIRED)))
goto invalid_creds;
}
/* Ensure that there is a password. */
if (credentials->bv_len == 0) {
@@ -1501,10 +1552,15 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
} else {
rc = ipapwd_check_max_pwd_len(credentials->bv_len, &errMesg);
if (rc) {
LOG_PWDPOLICY("Failed to set password credentials for '%s': %s\n",
slapi_sdn_get_dn(sdn), errMesg);
goto invalid_creds;
}
}
/* Reset rc to make sure errors are reported*/
rc = LDAP_INVALID_CREDENTIALS;
/* Authenticate the user. */
ret = ipapwd_authenticate(dn, entry, credentials);
if (ret) {
@@ -1520,11 +1576,23 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
/* Attempt to write out kerberos keys for the user. */
ipapwd_write_krb_keys(pb, discard_const(dn), entry, credentials);
#ifdef USE_OP_NOTE_MFA_AUTH
/* If it was a successful authentication with OTP required, mark it
* for access log to notice multi-factor authentication has happened
* https://www.port389.org/docs/389ds/design/mfa-operation-note-design.html
*/
if (!syncreq &&
((otpreq != OTP_IS_NOT_REQUIRED) && !notokens)) {
slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_MFA_AUTH);
}
#endif
slapi_entry_free(entry);
slapi_sdn_free(&sdn);
return 0;
invalid_creds:
free_ipapwd_krbcfg(&krbcfg);
slapi_entry_free(entry);
slapi_sdn_free(&sdn);
slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL);