diff options
author | Nathaniel McCallum <npmccallum@redhat.com> | 2014-11-11 14:41:42 -0500 |
---|---|---|
committer | Petr Vobornik <pvoborni@redhat.com> | 2014-12-05 13:42:19 +0100 |
commit | 9baa93da1cbf56c2a6f7e82e099bc3ff3f19e2e4 (patch) | |
tree | 84108cff4ba380a6842ef3fe3f189b5c3f963135 /daemons/ipa-slapi-plugins/libotp | |
parent | bea417828d61777015785c716c4225bb48dcf037 (diff) | |
download | freeipa-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/libotp')
-rw-r--r-- | daemons/ipa-slapi-plugins/libotp/otp_config.c | 89 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/libotp/otp_config.h | 17 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/libotp/otp_token.c | 137 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/libotp/otp_token.h | 26 |
4 files changed, 173 insertions, 96 deletions
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); |