diff options
Diffstat (limited to 'daemons/ipa-slapi-plugins/ipa-pwd-extop/auth.c')
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-pwd-extop/auth.c | 398 |
1 files changed, 0 insertions, 398 deletions
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/auth.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/auth.c deleted file mode 100644 index cccddeb91..000000000 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/auth.c +++ /dev/null @@ -1,398 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * This Program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; version 3 of the License. - * - * This Program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place, Suite 330, Boston, MA 02111-1307 USA. - * - * In addition, as a special exception, Red Hat, Inc. gives You the additional - * right to link the code of this Program with code not covered under the GNU - * General Public License ("Non-GPL Code") and to distribute linked combinations - * including the two, subject to the limitations in this paragraph. Non-GPL Code - * permitted under this exception must only link to the code of this Program - * through those well defined interfaces identified in the file named EXCEPTION - * found in the source code files (the "Approved Interfaces"). The files of - * Non-GPL Code may instantiate templates or use macros or inline functions from - * the Approved Interfaces without causing the resulting work to be covered by - * the GNU General Public License. Only Red Hat, Inc. may make changes or - * additions to the list of Approved Interfaces. You must obey the GNU General - * Public License in all respects for all of the Program code and other code used - * in conjunction with the Program except the Non-GPL Code covered by this - * exception. If you modify this file, you may extend this exception to your - * version of the file, but you are not obligated to do so. If you do not wish to - * provide this exception without modification, you must delete this exception - * statement from your version and license this file solely under the GPL without - * exception. - * - * - * Copyright (C) 2013 Red Hat, Inc. - * All rights reserved. - * END COPYRIGHT BLOCK **/ - -#include "ipapwd.h" - -#define IPA_OTP_TOKEN_TOTP_OC "ipaTokenTOTP" -#define IPA_OTP_DEFAULT_TOKEN_ALGORITHM "sha1" -#define IPA_OTP_DEFAULT_TOKEN_OFFSET 0 -#define IPA_OTP_DEFAULT_TOKEN_STEP 30 - -/* - * From otp.c - */ -bool ipapwd_hotp(const uint8_t *key, size_t len, const char *algo, int digits, - uint64_t counter, uint32_t *out); - -bool ipapwd_totp(const uint8_t *key, size_t len, const char *algo, int digits, - time_t time, int offset, unsigned int step, uint32_t *out); - -/* From ipa_pwd_extop.c */ -extern void *ipapwd_plugin_id; - -/* Data types. */ -struct token { - struct { - uint8_t *data; - size_t len; - } key; - char *algo; - int len; - union { - struct { - uint64_t counter; - } hotp; - struct { - unsigned int step; - int offset; - } totp; - }; - bool (*auth)(const struct token *token, uint32_t otp); -}; - -struct credentials { - struct token token; - Slapi_Value *ltp; - uint32_t otp; -}; - -static const char *valid_algos[] = { "sha1", "sha256", "sha384", - "sha512", NULL }; - -static inline bool is_algo_valid(const char *algo) -{ - int i, ret; - - for (i = 0; valid_algos[i]; i++) { - ret = strcasecmp(algo, valid_algos[i]); - if (ret == 0) - return true; - } - - return false; -} - -static const struct berval *entry_attr_get_berval(const Slapi_Entry* e, - const char *type) -{ - Slapi_Attr* attr = NULL; - Slapi_Value *v; - int ret; - - ret = slapi_entry_attr_find(e, type, &attr); - if (ret != 0 || attr == NULL) - return NULL; - - ret = slapi_attr_first_value(attr, &v); - if (ret < 0) - return NULL; - - return slapi_value_get_berval(v); -} - -/* Authenticate a totp token. Return zero on success. */ -static bool auth_totp(const struct token *token, uint32_t otp) -{ - time_t times[5]; - uint32_t val; - int i; - - /* Get the token value for now and two steps in either direction. */ - times[0] = time(NULL); - times[1] = times[0] + token->totp.step * 1; - times[2] = times[0] - token->totp.step * 1; - times[3] = times[0] + token->totp.step * 2; - times[4] = times[0] - token->totp.step * 2; - if (times[0] == -1) - return false; - - /* Check all the times for a match. */ - for (i = 0; i < sizeof(times) / sizeof(times[0]); i++) { - if (!ipapwd_totp(token->key.data, token->key.len, token->algo, - token->len, times[i], token->totp.offset, - token->totp.step, &val)) { - return false; - } - - if (val == otp) { - return true; - } - } - - return false; -} - -static void token_free_contents(struct token *token) -{ - if (token == NULL) - return; - - slapi_ch_free_string(&token->algo); - slapi_ch_free((void **) &token->key.data); -} - -/* Decode an OTP token entry. Return zero on success. */ -static bool token_decode(Slapi_Entry *te, struct token *token) -{ - const struct berval *tmp; - - /* Get key. */ - tmp = entry_attr_get_berval(te, IPA_OTP_TOKEN_KEY_TYPE); - if (tmp == NULL) { - slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME, - "token_decode: key not set for token \"%s\".\n", - slapi_entry_get_ndn(te)); - return false; - } - token->key.len = tmp->bv_len; - token->key.data = (void *) slapi_ch_malloc(token->key.len); - memcpy(token->key.data, tmp->bv_val, token->key.len); - - /* Get length. */ - token->len = slapi_entry_attr_get_int(te, IPA_OTP_TOKEN_LENGTH_TYPE); - if (token->len < 6 || token->len > 10) { - slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME, - "token_decode: %s is not defined or invalid " - "for token \"%s\".\n", IPA_OTP_TOKEN_LENGTH_TYPE, - slapi_entry_get_ndn(te)); - token_free_contents(token); - return false; - } - - /* Get algorithm. */ - token->algo = slapi_entry_attr_get_charptr(te, - IPA_OTP_TOKEN_ALGORITHM_TYPE); - if (token->algo == NULL) - token->algo = slapi_ch_strdup(IPA_OTP_DEFAULT_TOKEN_ALGORITHM); - if (!is_algo_valid(token->algo)) { - slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME, - "token_decode: invalid token algorithm " - "specified for token \"%s\".\n", - slapi_entry_get_ndn(te)); - token_free_contents(token); - return false; - } - - /* Currently, we only support TOTP. */ - token->auth = auth_totp; - - /* Get offset. */ - token->totp.offset = slapi_entry_attr_get_int(te, - IPA_OTP_TOKEN_OFFSET_TYPE); - if (token->totp.offset == 0) - token->totp.offset = IPA_OTP_DEFAULT_TOKEN_OFFSET; - - /* Get step. */ - token->totp.step = slapi_entry_attr_get_uint(te, IPA_OTP_TOKEN_STEP_TYPE); - if (token->totp.step == 0) - token->totp.step = IPA_OTP_DEFAULT_TOKEN_STEP; - - return true; -} - -static void credentials_free_contents(struct credentials *credentials) -{ - if (!credentials) - return; - - token_free_contents(&credentials->token); - slapi_value_free(&credentials->ltp); -} - -/* Parse credentials and token entry. Return zero on success. */ -static bool credentials_parse(Slapi_Entry *te, struct berval *creds, - struct credentials *credentials) -{ - char *tmp; - int len; - - if (!token_decode(te, &credentials->token)) - return false; - - /* Is the credential too short? If so, error. */ - if (credentials->token.len >= creds->bv_len) { - slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME, - "credentials_parse: supplied credential is less " - "than or equal to %s for token \"%s\".\n", - IPA_OTP_TOKEN_LENGTH_TYPE, slapi_entry_get_ndn(te)); - token_free_contents(&credentials->token); - return false; - } - - /* Extract the password from the supplied credential. We hand the - * memory off to a Slapi_Value, so we don't want to directly free the - * string. */ - len = creds->bv_len - credentials->token.len; - tmp = slapi_ch_calloc(len + 1, sizeof(char)); - strncpy(tmp, creds->bv_val, len); - credentials->ltp = slapi_value_new_string_passin(tmp); - - /* Extract the token value as a (minimum) 32-bit unsigned integer. */ - tmp = slapi_ch_calloc(credentials->token.len + 1, sizeof(char)); - strncpy(tmp, creds->bv_val + len, credentials->token.len); - credentials->otp = strtoul(tmp, NULL, 10); - slapi_ch_free_string(&tmp); - - return true; -} - -/* - * Attempts to perform OTP authentication for the passed in bind entry using - * the passed in credentials. - */ -bool ipapwd_do_otp_auth(Slapi_Entry *bind_entry, struct berval *creds) -{ - Slapi_PBlock *search_pb = NULL; - Slapi_Value **pwd_vals = NULL; - Slapi_Attr *pwd_attr = NULL; - Slapi_Entry **tokens = NULL; - Slapi_DN *base_sdn = NULL; - Slapi_Backend *be = NULL; - char *user_dn = NULL; - char *filter = NULL; - int pwd_numvals = 0; - bool ret = false; - int result = 0; - int hint = 0; - int i = 0; - - search_pb = slapi_pblock_new(); - - /* Fetch the user DN. */ - user_dn = slapi_entry_get_ndn(bind_entry); - if (user_dn == NULL) { - slapi_log_error(SLAPI_LOG_FATAL, IPAPWD_PLUGIN_NAME, - "ipapwd_do_otp_auth: error retrieving bind DN.\n"); - goto done; - } - - /* Search for TOTP tokens associated with this user. We search for - * tokens who list this user as the owner in the same backend where - * the user entry is located. */ - filter = slapi_ch_smprintf("(&(%s=%s)(%s=%s))", SLAPI_ATTR_OBJECTCLASS, - IPA_OTP_TOKEN_TOTP_OC, IPA_OTP_TOKEN_OWNER_TYPE, - user_dn); - - be = slapi_be_select(slapi_entry_get_sdn(bind_entry)); - if (be != NULL) { - base_sdn = (Slapi_DN *) slapi_be_getsuffix(be, 0); - } - if (base_sdn == NULL) { - slapi_log_error(SLAPI_LOG_FATAL, IPAPWD_PLUGIN_NAME, - "ipapwd_do_otp_auth: error determining the search " - "base for user \"%s\".\n", - user_dn); - } - - slapi_search_internal_set_pb(search_pb, slapi_sdn_get_ndn(base_sdn), - LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, - NULL, ipapwd_plugin_id, 0); - - slapi_search_internal_pb(search_pb); - slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result); - - if (LDAP_SUCCESS != result) { - slapi_log_error(SLAPI_LOG_FATAL, IPAPWD_PLUGIN_NAME, - "ipapwd_do_otp_auth: error searching for tokens " - "associated with user \"%s\" (err=%d).\n", - user_dn, result); - goto done; - } - - slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &tokens); - - if (tokens == NULL) { - /* This user has no associated tokens, so just bail out. */ - goto done; - } - - /* Fetch the userPassword values so we can perform the password checks - * when processing tokens below. */ - if (slapi_entry_attr_find(bind_entry, SLAPI_USERPWD_ATTR, &pwd_attr) != 0 || - slapi_attr_get_numvalues(pwd_attr, &pwd_numvals) != 0) { - slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME, - "ipapwd_do_otp_auth: no passwords are set for user " - "\"%s\".\n", user_dn); - goto done; - } - - /* We need to create a Slapi_Value array of the present password values - * for the compare function. There's no nicer way of doing this. */ - pwd_vals = (Slapi_Value **) slapi_ch_calloc(pwd_numvals, - sizeof(Slapi_Value *)); - - for (hint = slapi_attr_first_value(pwd_attr, &pwd_vals[i]); hint != -1; - hint = slapi_attr_next_value(pwd_attr, hint, &pwd_vals[i])) { - ++i; - } - - /* Loop through each token and attempt to authenticate. */ - for (i = 0; tokens && tokens[i]; i++) { - struct credentials credentials = {}; - - /* Parse the token entry and the credentials. */ - if (!credentials_parse(tokens[i], creds, &credentials)) - continue; - - /* Check if the password portion of the credential is correct. */ - i = slapi_pw_find_sv(pwd_vals, credentials.ltp); - if (i != 0) { - slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME, - "ipapwd_do_otp_auth: password check failed when " - "processing token \"%s\" for user \"%s\".\n", - slapi_entry_get_ndn(tokens[i]), user_dn); - credentials_free_contents(&credentials); - continue; - } - - /* Attempt to perform OTP authentication for this token. */ - if (!credentials.token.auth(&credentials.token, credentials.otp)) { - slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME, - "ipapwd_do_otp_auth: OTP auth failed when " - "processing token \"%s\" for user \"%s\".\n", - slapi_entry_get_ndn(tokens[i]), user_dn); - credentials_free_contents(&credentials); - continue; - } - - /* Authentication successful! */ - credentials_free_contents(&credentials); - slapi_log_error(SLAPI_LOG_PLUGIN, IPAPWD_PLUGIN_NAME, - "ipapwd_do_otp_auth: successfully " - "authenticated user \"%s\" using token " - "\"%s\".\n", - user_dn, slapi_entry_get_ndn(tokens[i])); - ret = true; - break; - } - -done: - slapi_ch_free_string(&filter); - slapi_free_search_results_internal(search_pb); - slapi_pblock_destroy(search_pb); - return ret; -} |