summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-slapi-plugins
diff options
context:
space:
mode:
authorNathaniel McCallum <npmccallum@redhat.com>2014-11-11 14:41:42 -0500
committerPetr Vobornik <pvoborni@redhat.com>2014-12-05 13:42:19 +0100
commit9baa93da1cbf56c2a6f7e82e099bc3ff3f19e2e4 (patch)
tree84108cff4ba380a6842ef3fe3f189b5c3f963135 /daemons/ipa-slapi-plugins
parentbea417828d61777015785c716c4225bb48dcf037 (diff)
downloadfreeipa-9baa93da1cbf56c2a6f7e82e099bc3ff3f19e2e4.tar.gz
freeipa-9baa93da1cbf56c2a6f7e82e099bc3ff3f19e2e4.tar.xz
freeipa-9baa93da1cbf56c2a6f7e82e099bc3ff3f19e2e4.zip
Make token auth and sync windows configurable
This introduces two new CLI commands: * otpconfig-show * otpconfig-mod https://fedorahosted.org/freeipa/ticket/4511 Reviewed-By: Thierry Bordaz <tbordaz@redhat.com> Reviewed-By: Petr Vobornik <pvoborni@redhat.com>
Diffstat (limited to 'daemons/ipa-slapi-plugins')
-rw-r--r--daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c77
-rw-r--r--daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c4
-rw-r--r--daemons/ipa-slapi-plugins/libotp/otp_config.c89
-rw-r--r--daemons/ipa-slapi-plugins/libotp/otp_config.h17
-rw-r--r--daemons/ipa-slapi-plugins/libotp/otp_token.c137
-rw-r--r--daemons/ipa-slapi-plugins/libotp/otp_token.h26
6 files changed, 199 insertions, 151 deletions
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
index 96c55f39b..84eff1701 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
@@ -68,8 +68,6 @@
#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;
@@ -1113,8 +1111,8 @@ done:
}
/*
- * Authenticates creds against OTP tokens. Returns true when authentication
- * completed successfully against a token OR when a user has no active tokens.
+ * This function handles the bind functionality for OTP. The return value
+ * indicates if the OTP portion of authentication was successful.
*
* WARNING: This function DOES NOT authenticate the first factor. Only the OTP
* code is validated! You still need to validate the first factor.
@@ -1123,53 +1121,6 @@ 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 otp_token **tokens = NULL;
- bool success = false;
-
- /* Find all of the user's active tokens. */
- tokens = otp_token_find(otp_config, 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 = otp_token_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 -= otp_token_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(otp_token_get_sdn(tokens[i])));
- }
-
- otp_token_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)
{
@@ -1189,10 +1140,32 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
*/
if (auth_types & OTP_CONFIG_AUTH_TYPE_OTP) {
+ struct otp_token **tokens = NULL;
+
LOG_PLUGIN_NAME(IPAPWD_PLUGIN_NAME,
"Attempting OTP authentication for '%s'.\n", bind_dn);
- if (ipapwd_do_otp_auth(bind_dn, entry, creds))
+
+ /* 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;
+ }
+
+ /* If the user has no active tokens, succeed. */
+ if (tokens[0] == NULL) {
+ otp_token_free_array(tokens);
+ return true;
+ }
+
+ if (otp_token_validate_berval(tokens, creds, NULL)) {
+ otp_token_free_array(tokens);
return true;
+ }
+
+ otp_token_free_array(tokens);
}
return auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD;
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c
index 0aef43802..3a31529f7 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c
@@ -40,8 +40,6 @@
#include "../libotp/otp_token.h"
#include "syncreq.h"
-#define OTP_SYNC_MAX_STEPS 25
-
bool sync_request_present(Slapi_PBlock *pb)
{
LDAPControl **controls = NULL;
@@ -92,7 +90,7 @@ bool sync_request_handle(const struct otp_config *cfg, Slapi_PBlock *pb,
if (ber_scanf(ber, "}") != LBER_ERROR) {
tokens = otp_token_find(cfg, user_dn, token_dn, true, NULL);
if (tokens != NULL) {
- success = otp_token_sync_berval(tokens, OTP_SYNC_MAX_STEPS, first, second);
+ success = otp_token_validate_berval(tokens, first, second);
otp_token_free_array(tokens);
}
}
diff --git a/daemons/ipa-slapi-plugins/libotp/otp_config.c b/daemons/ipa-slapi-plugins/libotp/otp_config.c
index 1b7c1e658..ac2cfc72a 100644
--- a/daemons/ipa-slapi-plugins/libotp/otp_config.c
+++ b/daemons/ipa-slapi-plugins/libotp/otp_config.c
@@ -105,6 +105,17 @@ static uint32_t entry_to_authtypes(Slapi_Entry *e, const char *attr)
return types;
}
+static uint32_t entry_to_window(Slapi_Entry *e, const char *attr)
+{
+ long long val;
+
+ if (e == NULL)
+ return 0;
+
+ val = slapi_entry_attr_get_longlong(e, attr);
+ return val > 0 ? val : 0;
+}
+
static const struct spec authtypes = {
entry_to_authtypes,
"cn=ipaConfig,cn=etc,%s",
@@ -112,6 +123,34 @@ static const struct spec authtypes = {
OTP_CONFIG_AUTH_TYPE_PASSWORD
};
+static const struct spec totp_auth_window = {
+ entry_to_window,
+ "cn=otp,cn=etc,%s",
+ "ipatokenTOTPauthWindow",
+ 300
+};
+
+static const struct spec totp_sync_window = {
+ entry_to_window,
+ "cn=otp,cn=etc,%s",
+ "ipatokenTOTPsyncWindow",
+ 86400
+};
+
+static const struct spec hotp_auth_window = {
+ entry_to_window,
+ "cn=otp,cn=etc,%s",
+ "ipatokenHOTPauthWindow",
+ 10
+};
+
+static const struct spec hotp_sync_window = {
+ entry_to_window,
+ "cn=otp,cn=etc,%s",
+ "ipatokenHOTPsyncWindow",
+ 100
+};
+
static Slapi_DN *make_sdn(const char *prefix, const Slapi_DN *suffix)
{
char *dn = slapi_ch_smprintf(prefix, slapi_sdn_get_dn(suffix));
@@ -126,10 +165,14 @@ static uint32_t find_value(const struct otp_config *cfg,
sdn = make_sdn(spec->prefix, suffix);
for (struct record *rec = cfg->records; rec != NULL; rec = rec->next) {
- if (rec->spec == spec) {
- value = PR_ATOMIC_ADD(&rec->value, 0);
- break;
- }
+ if (rec->spec != spec)
+ continue;
+
+ if (slapi_sdn_compare(sdn, rec->sdn) != 0)
+ continue;
+
+ value = PR_ATOMIC_ADD(&rec->value, 0);
+ break;
}
slapi_sdn_free(&sdn);
@@ -162,6 +205,10 @@ struct otp_config *otp_config_init(Slapi_ComponentId *plugin_id)
{
static const struct spec *specs[] = {
&authtypes,
+ &totp_auth_window,
+ &totp_sync_window,
+ &hotp_auth_window,
+ &hotp_sync_window,
NULL
};
@@ -272,3 +319,37 @@ uint32_t otp_config_auth_types(const struct otp_config *cfg,
return OTP_CONFIG_AUTH_TYPE_PASSWORD;
}
+
+struct otp_config_window
+otp_config_window(const struct otp_config *cfg, Slapi_Entry *token_entry)
+{
+ const struct spec *auth = NULL, *sync = NULL;
+ struct otp_config_window wndw = { 0, 0 };
+ const Slapi_DN *sfx;
+ char **clses;
+
+ sfx = slapi_get_suffix_by_dn(slapi_entry_get_sdn_const(token_entry));
+
+ clses = slapi_entry_attr_get_charray(token_entry, SLAPI_ATTR_OBJECTCLASS);
+ for (size_t i = 0; clses != NULL && clses[i] != NULL; i++) {
+ if (strcasecmp(clses[i], "ipatokenTOTP") == 0) {
+ auth = &totp_auth_window;
+ sync = &totp_sync_window;
+ break;
+ }
+
+ if (strcasecmp(clses[i], "ipatokenHOTP") == 0) {
+ auth = &hotp_auth_window;
+ sync = &hotp_sync_window;
+ break;
+ }
+ }
+ slapi_ch_array_free(clses);
+
+ if (auth == NULL || sync == NULL)
+ return wndw;
+
+ wndw.auth = find_value(cfg, sfx, auth);
+ wndw.sync = find_value(cfg, sfx, sync);
+ return wndw;
+}
diff --git a/daemons/ipa-slapi-plugins/libotp/otp_config.h b/daemons/ipa-slapi-plugins/libotp/otp_config.h
index bfd514bd5..b7f14fafa 100644
--- a/daemons/ipa-slapi-plugins/libotp/otp_config.h
+++ b/daemons/ipa-slapi-plugins/libotp/otp_config.h
@@ -49,6 +49,11 @@
struct otp_config;
+struct otp_config_window {
+ uint32_t auth;
+ uint32_t sync;
+};
+
struct otp_config *otp_config_init(Slapi_ComponentId *plugin_id);
void otp_config_fini(struct otp_config **cfg);
@@ -63,3 +68,15 @@ Slapi_ComponentId *otp_config_plugin_id(const struct otp_config *cfg);
*/
uint32_t otp_config_auth_types(const struct otp_config *cfg,
Slapi_Entry *user_entry);
+
+/* Gets the window sizes for a token.
+ *
+ * The entry should be queried for the following attributes:
+ * objectClass
+ * ipatokenTOTPauthWindow
+ * ipatokenTOTPsyncWindow
+ * ipatokenHOTPauthWindow
+ * ipatokenHOTPsyncWindow
+ */
+struct otp_config_window otp_config_window(const struct otp_config *cfg,
+ Slapi_Entry *token_entry);
diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.c b/daemons/ipa-slapi-plugins/libotp/otp_token.c
index eef072685..bc6acc42c 100644
--- a/daemons/ipa-slapi-plugins/libotp/otp_token.c
+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.c
@@ -38,6 +38,7 @@
* END COPYRIGHT BLOCK **/
#include "otp_token.h"
+#include "otp_config.h"
#include "hotp.h"
#include <time.h>
@@ -63,10 +64,11 @@ struct otp_token {
Slapi_DN *sdn;
struct hotp_token token;
enum type type;
+ struct otp_config_window window;
union {
struct {
uint64_t watermark;
- unsigned int step;
+ int step; /* Seconds. */
int offset;
} totp;
struct {
@@ -247,6 +249,7 @@ static struct otp_token *otp_token_new(const struct otp_config *cfg,
if (token == NULL)
return NULL;
token->cfg = cfg;
+ token->window = otp_config_window(cfg, entry);
/* Get the token type. */
vals = slapi_entry_attr_get_charray(entry, "objectClass");
@@ -300,7 +303,7 @@ static struct otp_token *otp_token_new(const struct otp_config *cfg,
/* Get step. */
token->totp.step = slapi_entry_attr_get_uint(entry, T("timeStep"));
- if (token->totp.step == 0)
+ if (token->totp.step < 5)
token->totp.step = IPA_OTP_DEFAULT_TOKEN_STEP;
break;
case TYPE_HOTP:
@@ -431,42 +434,11 @@ struct otp_token **otp_token_find(const struct otp_config *cfg,
return find(cfg, user_dn, token_dn, actfilt, filter);
}
-int otp_token_get_digits(struct otp_token *token)
-{
- return token == NULL ? 0 : token->token.digits;
-}
-
const Slapi_DN *otp_token_get_sdn(struct otp_token *token)
{
return token->sdn;
}
-static bool otp_token_validate(struct otp_token *token, size_t steps,
- uint32_t code)
-{
- time_t now = 0;
-
- if (token == NULL)
- return false;
-
- /* We only need the local time for time-based tokens. */
- if (token->type == TYPE_TOTP && time(&now) == (time_t) -1)
- return false;
-
- for (int i = 0; i <= steps; i++) {
- /* Validate the positive step. */
- if (validate(token, now, i, code, NULL))
- return true;
-
- /* Validate the negative step. */
- if (validate(token, now, 0 - i, code, NULL))
- return true;
- }
-
- return false;
-}
-
-
/*
* Convert code berval to decimal.
*
@@ -474,45 +446,40 @@ static bool otp_token_validate(struct otp_token *token, size_t steps,
* 1. If we have leading zeros, atol() fails.
* 2. Neither support limiting conversion by length.
*/
-static bool bvtod(const struct berval *code, uint32_t *out)
+static bool bvtod(const struct berval *code, int digits, uint32_t *out)
{
*out = 0;
- for (ber_len_t i = 0; i < code->bv_len; i++) {
+ if (code == NULL || digits <= 0 || code->bv_len < digits)
+ return false;
+
+ for (ber_len_t i = code->bv_len - digits; i < code->bv_len; i++) {
if (code->bv_val[i] < '0' || code->bv_val[i] > '9')
return false;
*out *= 10;
*out += code->bv_val[i] - '0';
}
- return code->bv_len != 0;
+ return true;
}
-bool otp_token_validate_berval(struct otp_token *token, size_t steps,
- const struct berval *code, bool tail)
+static bool step_is_valid(struct otp_token *token, bool sync, uint32_t i)
{
- struct berval tmp;
- uint32_t otp;
-
- if (token == NULL || code == NULL)
- return false;
- tmp = *code;
-
- if (tmp.bv_len < token->token.digits)
- return false;
-
- if (tail)
- tmp.bv_val = &tmp.bv_val[tmp.bv_len - token->token.digits];
- tmp.bv_len = token->token.digits;
+ uint32_t window = sync ? token->window.sync : token->window.auth;
- if (!bvtod(&tmp, &otp))
+ switch (token->type) {
+ case TYPE_TOTP:
+ return i * token->totp.step < window;
+ case TYPE_HOTP:
+ return i < window;
+ default:
return false;
-
- return otp_token_validate(token, steps, otp);
+ }
}
-static bool otp_token_sync(struct otp_token * const *tokens, size_t steps,
- uint32_t first_code, uint32_t second_code)
+bool otp_token_validate_berval(struct otp_token * const *tokens,
+ struct berval *first_code,
+ struct berval *second_code)
{
time_t now = 0;
@@ -522,33 +489,45 @@ static bool otp_token_sync(struct otp_token * const *tokens, size_t steps,
if (time(&now) == (time_t) -1)
return false;
- for (int i = 0; i <= steps; i++) {
+ for (uint32_t i = 0, cnt = 1; cnt != 0; i++) {
+ cnt = 0;
for (int j = 0; tokens[j] != NULL; j++) {
- /* Validate the positive step. */
- if (validate(tokens[j], now, i, first_code, &second_code))
- return true;
+ uint32_t *secondp = NULL;
+ uint32_t second;
+ uint32_t first;
+
+ /* Don't validate beyond the specified window. */
+ if (!step_is_valid(tokens[j], second_code != NULL, i))
+ continue;
+ cnt++;
+
+ /* Parse the first code. */
+ if (!bvtod(first_code, tokens[j]->token.digits, &first))
+ continue;
+
+ /* Parse the second code. */
+ if (second_code != NULL) {
+ secondp = &second;
+ if (!bvtod(second_code, tokens[j]->token.digits, secondp))
+ continue;
+ }
+
+ /* Validate the positive/negative steps. */
+ if (!validate(tokens[j], now, i, first, secondp) &&
+ !validate(tokens[j], now, 0 - i, first, secondp))
+ continue;
+
+ /* Codes validated; strip. */
+ first_code->bv_len -= tokens[j]->token.digits;
+ first_code->bv_val[first_code->bv_len] = '\0';
+ if (second_code != NULL) {
+ second_code->bv_len -= tokens[j]->token.digits;
+ second_code->bv_val[second_code->bv_len] = '\0';
+ }
- /* Validate the negative step. */
- if (validate(tokens[j], now, 0 - i, first_code, &second_code))
- return true;
+ return true;
}
}
return false;
}
-
-bool otp_token_sync_berval(struct otp_token * const *tokens, size_t steps,
- const struct berval *first_code,
- const struct berval *second_code)
-{
- uint32_t second = 0;
- uint32_t first = 0;
-
- if (!bvtod(first_code, &first))
- return false;
-
- if (!bvtod(second_code, &second))
- return false;
-
- return otp_token_sync(tokens, steps, first, second);
-}
diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.h b/daemons/ipa-slapi-plugins/libotp/otp_token.h
index 4b159077d..4cef9a63b 100644
--- a/daemons/ipa-slapi-plugins/libotp/otp_token.h
+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.h
@@ -70,19 +70,19 @@ struct otp_token **otp_token_find(const struct otp_config *cfg,
const char *user_dn, const char *token_dn,
bool active, const char *filter);
-/* Get the length of the token code. */
-int otp_token_get_digits(struct otp_token *token);
-
/* Get the SDN of the token. */
const Slapi_DN *otp_token_get_sdn(struct otp_token *token);
-/* Validate the token code within a range of steps. If tail is true,
- * it will be assumed that the token is specified at the end of the string. */
-bool otp_token_validate_berval(struct otp_token *token, size_t steps,
- const struct berval *code, bool tail);
-
-/* Synchronize the token within a range of steps. */
-bool otp_token_sync_berval(struct otp_token * const *tokens, size_t steps,
- const struct berval *first_code,
- const struct berval *second_code);
-
+/* Perform OTP authentication.
+ *
+ * If only the first code is specified, validation will be performed and the
+ * validated token will be stripped.
+ *
+ * If both codes are specified, synchronization will be performed and the
+ * validated tokens will be stripped.
+ *
+ * Returns true if and only if all specified tokens were validated.
+ */
+bool otp_token_validate_berval(struct otp_token * const *tokens,
+ struct berval *first_code,
+ struct berval *second_code);