From 11f795fcd7ec3ddaeb6e674818d415d14050d600 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Fri, 27 Mar 2015 15:20:13 +0100 Subject: [PATCH 12/14] 2FA offline auth --- src/db/sysdb_ops.c | 77 ++++++++++++++++++++++++++++++++++++++++-- src/responder/pam/pamsrv_cmd.c | 35 +++++++++++++++++-- 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index b4b2eb9fc2ba6055fcfc770601c04815464228cd..d98ef8ddac4ca6f10efba594254fc6faf437fc8e 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -3161,6 +3161,76 @@ done: return ret; } +static errno_t check_for_combined_2fa_password(struct sss_domain_info *domain, + struct ldb_message *ldb_msg, + const char *password, + const char *userhash) +{ + + unsigned int cached_authtok_type; + unsigned int cached_fa2_len; + char *short_pw; + char *comphash; + size_t pw_len; + TALLOC_CTX *tmp_ctx; + int ret; + + cached_authtok_type = ldb_msg_find_attr_as_uint(ldb_msg, + SYSDB_CACHEDPWD_TYPE, + SSS_AUTHTOK_TYPE_EMPTY); + if (cached_authtok_type != SSS_AUTHTOK_TYPE_2FA) { + DEBUG(SSSDBG_TRACE_LIBS, "Wrong authtok type.\n"); + return EINVAL; + } + + cached_fa2_len = ldb_msg_find_attr_as_uint(ldb_msg, SYSDB_CACHEDPWD_FA2_LEN, + 0); + if (cached_fa2_len == 0) { + DEBUG(SSSDBG_TRACE_LIBS, "Second factor size not available.\n"); + return EINVAL; + } + + pw_len = strlen(password); + if (pw_len < cached_fa2_len + domain->cache_credentials_min_ff_length) { + DEBUG(SSSDBG_TRACE_LIBS, "Password too short.\n"); + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + short_pw = talloc_strndup(tmp_ctx , password, (pw_len - cached_fa2_len)); + if (short_pw == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); + ret = ENOMEM; + goto done; + } + + ret = s3crypt_sha512(tmp_ctx, short_pw, userhash, &comphash); + if (ret != EOK) { + DEBUG(SSSDBG_CONF_SETTINGS, "Failed to create password hash.\n"); + ret = ERR_INTERNAL; + goto done; + } + + if (strcmp(userhash, comphash) != 0) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Hash of shorten password does not match.\n"); + ret = ERR_AUTH_FAILED; + goto done; + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + return ret; +} + int sysdb_cache_auth(struct sss_domain_info *domain, const char *name, const char *password, @@ -3174,7 +3244,8 @@ int sysdb_cache_auth(struct sss_domain_info *domain, SYSDB_LAST_LOGIN, SYSDB_LAST_ONLINE_AUTH, "lastCachedPasswordChange", "accountExpires", SYSDB_FAILED_LOGIN_ATTEMPTS, - SYSDB_LAST_FAILED_LOGIN, NULL }; + SYSDB_LAST_FAILED_LOGIN, SYSDB_CACHEDPWD_TYPE, + SYSDB_CACHEDPWD_FA2_LEN, NULL }; struct ldb_message *ldb_msg; const char *userhash; char *comphash; @@ -3285,7 +3356,9 @@ int sysdb_cache_auth(struct sss_domain_info *domain, goto done; } - if (strcmp(userhash, comphash) == 0) { + if (strcmp(userhash, comphash) == 0 + || check_for_combined_2fa_password(domain, ldb_msg, + password, userhash) == EOK ) { /* TODO: probable good point for audit logging */ DEBUG(SSSDBG_CONF_SETTINGS, "Hashes do match!\n"); authentication_successful = true; diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index f84349d1f60e4e7c858b9bc6303ade3a962172d1..20aeda41e143f10faa9319fea6b2a9ff9041ed55 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -528,6 +528,34 @@ static void pam_reply_delay(struct tevent_context *ev, struct tevent_timer *te, pam_reply(preq); } +static errno_t get_password_for_cache_auth(struct sss_auth_token *authtok, + const char **password) +{ + int ret; + size_t pw_len; + const char *fa2; + size_t fa2_len; + + switch (sss_authtok_get_type(authtok)) { + case SSS_AUTHTOK_TYPE_PASSWORD: + ret = sss_authtok_get_password(authtok, password, NULL); + break; + case SSS_AUTHTOK_TYPE_2FA: + ret = sss_authtok_get_2fa(authtok, password, &pw_len, &fa2, &fa2_len); + break; + default: + DEBUG(SSSDBG_FATAL_FAILURE, "Unsupported auth token type [%d].\n", + sss_authtok_get_type(authtok)); + ret = EINVAL; + } + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get password.\n"); + return ret; + } + + return EOK; +} + static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd); static void pam_handle_cached_login(struct pam_auth_req *preq, int ret, time_t expire_date, time_t delayed_until); @@ -587,9 +615,10 @@ static void pam_reply(struct pam_auth_req *preq) goto done; } - ret = sss_authtok_get_password(pd->authtok, &password, NULL); - if (ret) { - DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get password.\n"); + ret = get_password_for_cache_auth(pd->authtok, &password); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "get_password_and_type_for_cache_auth failed.\n"); goto done; } -- 2.1.0