Imported Upstream version 4.0.5
This commit is contained in:
@@ -62,18 +62,19 @@
|
||||
|
||||
#include "ipapwd.h"
|
||||
#include "util.h"
|
||||
#include "otpctrl.h"
|
||||
#include "syncreq.h"
|
||||
#include "authcfg.h"
|
||||
|
||||
#define IPAPWD_OP_NULL 0
|
||||
#define IPAPWD_OP_ADD 1
|
||||
#define IPAPWD_OP_MOD 2
|
||||
|
||||
#define OTP_VALIDATE_STEPS 3
|
||||
|
||||
extern Slapi_PluginDesc ipapwd_plugin_desc;
|
||||
extern void *ipapwd_plugin_id;
|
||||
extern const char *ipa_realm_tree;
|
||||
|
||||
struct otp_config *otp_config = NULL;
|
||||
|
||||
/* structure with information for each extension */
|
||||
struct ipapwd_op_ext {
|
||||
char *object_name; /* name of the object extended */
|
||||
@@ -151,43 +152,6 @@ done:
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool has_krbprincipalkey(Slapi_Entry *entry) {
|
||||
int rc;
|
||||
krb5_key_data *keys = NULL;
|
||||
int num_keys = 0;
|
||||
int mkvno = 0;
|
||||
int hint;
|
||||
Slapi_Attr *attr;
|
||||
Slapi_Value *keys_value;
|
||||
const struct berval *bval;
|
||||
|
||||
|
||||
if (slapi_entry_attr_find(entry, "krbPrincipalKey", &attr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* It exists a krbPrincipalKey attribute checks it exists a valid value */
|
||||
for (hint = slapi_attr_first_value(attr, &keys_value);
|
||||
hint != -1; hint = slapi_attr_next_value(attr, hint, &keys_value)) {
|
||||
bval = slapi_value_get_berval(keys_value);
|
||||
if (NULL != bval && NULL != bval->bv_val) {
|
||||
rc = ber_decode_krb5_key_data(discard_const(bval),
|
||||
&mkvno, &num_keys, &keys);
|
||||
|
||||
if (rc || (num_keys <= 0)) {
|
||||
/* this one is not valid, ignore it */
|
||||
if (keys) ipa_krb5_free_key_data(keys, num_keys);
|
||||
} else {
|
||||
/* It exists at least this one that is valid, no need to continue */
|
||||
if (keys) ipa_krb5_free_key_data(keys, num_keys);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* PRE ADD Operation:
|
||||
* Gets the clean text password (fail the operation if the password came
|
||||
@@ -282,17 +246,6 @@ static int ipapwd_pre_add(Slapi_PBlock *pb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* With User Life Cycle, it could be a stage user that is activated.
|
||||
* The userPassword and krb keys were set while the user was a stage user.
|
||||
* Accept hashed userPassword and krb keys at the condition, it already contains
|
||||
* a valid krbPrincipalKey
|
||||
*/
|
||||
if (has_krbprincipalkey(e)) {
|
||||
slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
|
||||
LOG("User Life Cycle: %s is a activated stage user (with prehashed password and krb keys)\n", dn ? dn : "unknown");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG("pre-hashed passwords are not valid\n");
|
||||
errMesg = "pre-hashed passwords are not valid\n";
|
||||
goto done;
|
||||
@@ -683,8 +636,6 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
|
||||
is_smb = 0;
|
||||
is_ipant = 0;
|
||||
|
||||
/* After examining the output of covscan, we think that this
|
||||
* fallthrough is intentional.*/
|
||||
case LDAP_MOD_ADD:
|
||||
if (!lmod->mod_bvalues ||
|
||||
!lmod->mod_bvalues[0]) {
|
||||
@@ -1016,9 +967,23 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ipapwd_post_updatecfg(Slapi_PBlock *pb)
|
||||
static int ipapwd_post_authcfg(Slapi_PBlock *pb)
|
||||
{
|
||||
otp_config_update(otp_config, pb);
|
||||
Slapi_Entry *config_entry = NULL;
|
||||
Slapi_DN *sdn = NULL;
|
||||
int oprc = 0;
|
||||
|
||||
/* Just bail if the operation failed. */
|
||||
if (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 || oprc != 0)
|
||||
return 0;
|
||||
|
||||
if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn) != 0)
|
||||
return 0;
|
||||
|
||||
/* Ignore the error here (delete operations). */
|
||||
slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &config_entry);
|
||||
|
||||
authcfg_reload_global_config(sdn, config_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1028,6 +993,8 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb)
|
||||
struct ipapwd_operation *pwdop = NULL;
|
||||
Slapi_Mods *smods;
|
||||
Slapi_Value **pwvals;
|
||||
struct tm utctime;
|
||||
char timestr[GENERALIZED_TIME_LENGTH+1];
|
||||
int ret;
|
||||
char *errMsg = "Internal operations error\n";
|
||||
struct ipapwd_krbcfg *krbcfg = NULL;
|
||||
@@ -1036,7 +1003,8 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb)
|
||||
|
||||
LOG_TRACE("=>\n");
|
||||
|
||||
otp_config_update(otp_config, pb);
|
||||
/* Ignore error when parsing configuration. */
|
||||
ipapwd_post_authcfg(pb);
|
||||
|
||||
/* time to get the operation handler */
|
||||
ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op);
|
||||
@@ -1113,19 +1081,25 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb)
|
||||
(slapi_entry_attr_has_syntax_value(pwdop->pwdata.target,
|
||||
SLAPI_ATTR_OBJECTCLASS, ipahost)) == 0) {
|
||||
/* set Password Expiration date */
|
||||
ret = ipapwd_setdate(pwdop->pwdata.target, smods,
|
||||
"krbPasswordExpiration",
|
||||
pwdop->pwdata.expireTime,
|
||||
(pwdop->pwdata.expireTime == 0));
|
||||
if (ret != LDAP_SUCCESS)
|
||||
if (!gmtime_r(&(pwdop->pwdata.expireTime), &utctime)) {
|
||||
LOG_FATAL("failed to parse expiration date (buggy gmtime_r ?)\n");
|
||||
goto done;
|
||||
}
|
||||
strftime(timestr, GENERALIZED_TIME_LENGTH+1,
|
||||
"%Y%m%d%H%M%SZ", &utctime);
|
||||
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
|
||||
"krbPasswordExpiration", timestr);
|
||||
|
||||
/* change Last Password Change field with the current date */
|
||||
ret = ipapwd_setdate(pwdop->pwdata.target, smods,
|
||||
"krbLastPwdChange",
|
||||
pwdop->pwdata.timeNow, false);
|
||||
if (ret != LDAP_SUCCESS)
|
||||
if (!gmtime_r(&(pwdop->pwdata.timeNow), &utctime)) {
|
||||
LOG_FATAL("failed to parse current date (buggy gmtime_r ?)\n");
|
||||
slapi_value_free(&ipahost);
|
||||
goto done;
|
||||
}
|
||||
strftime(timestr, GENERALIZED_TIME_LENGTH+1,
|
||||
"%Y%m%d%H%M%SZ", &utctime);
|
||||
slapi_mods_add_string(smods, LDAP_MOD_REPLACE,
|
||||
"krbLastPwdChange", timestr);
|
||||
}
|
||||
slapi_value_free(&ipahost);
|
||||
}
|
||||
@@ -1153,8 +1127,8 @@ done:
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the bind functionality for OTP. The return value
|
||||
* indicates if the OTP portion of authentication was successful.
|
||||
* Authenticates creds against OTP tokens. Returns true when authentication
|
||||
* completed successfully against a token OR when a user has no active tokens.
|
||||
*
|
||||
* WARNING: This function DOES NOT authenticate the first factor. Only the OTP
|
||||
* code is validated! You still need to validate the first factor.
|
||||
@@ -1163,13 +1137,64 @@ done:
|
||||
* value at the end. This leaves only the password in creds for later
|
||||
* validation.
|
||||
*/
|
||||
static bool ipapwd_do_otp_auth(const char *dn, Slapi_Entry *bind_entry,
|
||||
struct berval *creds)
|
||||
{
|
||||
struct otptoken **tokens = NULL;
|
||||
bool success = false;
|
||||
|
||||
/* Find all of the user's active tokens. */
|
||||
tokens = otptoken_find(ipapwd_plugin_id, dn, NULL, true, NULL);
|
||||
if (tokens == NULL) {
|
||||
slapi_log_error(SLAPI_LOG_FATAL, IPAPWD_PLUGIN_NAME,
|
||||
"%s: can't find tokens for '%s'.\n", __func__, dn);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the user has no active tokens, succeed. */
|
||||
success = tokens[0] == NULL;
|
||||
|
||||
/* Loop through each token. */
|
||||
for (int i = 0; tokens[i] && !success; i++) {
|
||||
/* Attempt authentication. */
|
||||
success = otptoken_validate_berval(tokens[i], OTP_VALIDATE_STEPS,
|
||||
creds, true);
|
||||
|
||||
/* Truncate the password to remove the OTP code at the end. */
|
||||
if (success) {
|
||||
creds->bv_len -= otptoken_get_digits(tokens[i]);
|
||||
creds->bv_val[creds->bv_len] = '\0';
|
||||
}
|
||||
|
||||
slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME,
|
||||
"%s: token authentication %s "
|
||||
"(user: '%s', token: '%s\').\n", __func__,
|
||||
success ? "succeeded" : "failed", dn,
|
||||
slapi_sdn_get_ndn(otptoken_get_sdn(tokens[i])));
|
||||
}
|
||||
|
||||
otptoken_free_array(tokens);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the bind functionality for OTP. The return value
|
||||
* indicates if the OTP portion of authentication was successful.
|
||||
*
|
||||
* NOTE: This function may modify creds. See explanation in the comment for
|
||||
* ipapwd_do_otp_auth() above.
|
||||
*/
|
||||
static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
|
||||
struct berval *creds, bool otpreq)
|
||||
struct berval *creds)
|
||||
{
|
||||
uint32_t auth_types;
|
||||
|
||||
/* Get the configured authentication types. */
|
||||
auth_types = otp_config_auth_types(otp_config, entry);
|
||||
auth_types = authcfg_get_auth_types(entry);
|
||||
|
||||
/* If global disabled flag is set, just punt. */
|
||||
if (auth_types & AUTHCFG_AUTH_TYPE_DISABLED)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* IMPORTANT SECTION!
|
||||
@@ -1181,36 +1206,14 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
|
||||
* 2. If PWD is enabled or OTP succeeded, fall through to PWD validation.
|
||||
*/
|
||||
|
||||
if (auth_types & OTP_CONFIG_AUTH_TYPE_OTP) {
|
||||
struct otp_token **tokens = NULL;
|
||||
|
||||
if (auth_types & AUTHCFG_AUTH_TYPE_OTP) {
|
||||
LOG_PLUGIN_NAME(IPAPWD_PLUGIN_NAME,
|
||||
"Attempting OTP authentication for '%s'.\n", bind_dn);
|
||||
|
||||
/* Find all of the user's active tokens. */
|
||||
tokens = otp_token_find(otp_config, bind_dn, NULL, true, NULL);
|
||||
if (tokens == NULL) {
|
||||
slapi_log_error(SLAPI_LOG_FATAL, IPAPWD_PLUGIN_NAME,
|
||||
"%s: can't find tokens for '%s'.\n",
|
||||
__func__, bind_dn);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* With no tokens, succeed if tokens aren't required. */
|
||||
if (tokens[0] == NULL) {
|
||||
otp_token_free_array(tokens);
|
||||
return !otpreq;
|
||||
}
|
||||
|
||||
if (otp_token_validate_berval(tokens, creds, NULL)) {
|
||||
otp_token_free_array(tokens);
|
||||
if (ipapwd_do_otp_auth(bind_dn, entry, creds))
|
||||
return true;
|
||||
}
|
||||
|
||||
otp_token_free_array(tokens);
|
||||
}
|
||||
|
||||
return (auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD) && !otpreq;
|
||||
return auth_types & AUTHCFG_AUTH_TYPE_PASSWORD;
|
||||
}
|
||||
|
||||
static int ipapwd_authenticate(const char *dn, Slapi_Entry *entry,
|
||||
@@ -1378,8 +1381,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
static const char *attrs_list[] = {
|
||||
SLAPI_USERPWD_ATTR, "ipaUserAuthType", "krbprincipalkey", "uid",
|
||||
"krbprincipalname", "objectclass", "passwordexpirationtime",
|
||||
"passwordhistory", "krbprincipalexpiration", "krbcanonicalname",
|
||||
"krbPasswordExpiration", "krblastpwchange",
|
||||
"passwordhistory", "krbprincipalexpiration",
|
||||
NULL
|
||||
};
|
||||
struct berval *credentials = NULL;
|
||||
@@ -1387,7 +1389,6 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
char *dn = NULL;
|
||||
int method = 0;
|
||||
bool syncreq;
|
||||
bool otpreq;
|
||||
int ret = 0;
|
||||
time_t current_time;
|
||||
time_t expire_time;
|
||||
@@ -1444,9 +1445,8 @@ 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))
|
||||
syncreq = sync_request_present(pb);
|
||||
if (!syncreq && !ipapwd_pre_bind_otp(dn, entry, credentials))
|
||||
goto invalid_creds;
|
||||
|
||||
/* Ensure that there is a password. */
|
||||
@@ -1461,7 +1461,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
}
|
||||
|
||||
/* Attempt to handle a token synchronization request. */
|
||||
if (syncreq && !otpctrl_sync_handle(otp_config, pb, dn))
|
||||
if (syncreq && !sync_request_handle(ipapwd_get_plugin_id(), pb, dn))
|
||||
goto invalid_creds;
|
||||
|
||||
/* Attempt to write out kerberos keys for the user. */
|
||||
@@ -1483,7 +1483,6 @@ int ipapwd_pre_init(Slapi_PBlock *pb)
|
||||
int ret;
|
||||
|
||||
slapi_register_supported_control(OTP_SYNC_REQUEST_OID, SLAPI_OPERATION_BIND);
|
||||
slapi_register_supported_control(OTP_REQUIRED_OID, SLAPI_OPERATION_BIND);
|
||||
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
|
||||
@@ -1514,9 +1513,9 @@ int ipapwd_post_init(Slapi_PBlock *pb)
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, (void *)ipapwd_post_modadd);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_updatecfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_authcfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *)ipapwd_post_modadd);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_authcfg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1527,10 +1526,10 @@ int ipapwd_intpost_init(Slapi_PBlock *pb)
|
||||
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *)ipapwd_post_updatecfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *)ipapwd_post_updatecfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *)ipapwd_post_updatecfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *)ipapwd_post_authcfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *)ipapwd_post_authcfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *)ipapwd_post_authcfg);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *)ipapwd_post_authcfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user