Blame SOURCES/0017-authtok-add-dedicated-type-for-2fa-with-single-strin.patch

841ac7
From fc57f57b805a5b91348a8355e74ceb4444881729 Mon Sep 17 00:00:00 2001
841ac7
From: Sumit Bose <sbose@redhat.com>
841ac7
Date: Wed, 27 Mar 2019 09:04:53 +0100
841ac7
Subject: [PATCH 17/21] authtok: add dedicated type for 2fa with single string
841ac7
841ac7
Currently the password type is used to send two-factor authentication
841ac7
credentials entered in a single string to the backend, This is
841ac7
unreliable and only works properly if password authentication is not
841ac7
available for the user as well.
841ac7
841ac7
To support 2FA credentials in a single string better a new authtok type
841ac7
is added.
841ac7
841ac7
Related to https://pagure.io/SSSD/sssd/issue/3264
841ac7
841ac7
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
841ac7
(cherry picked from commit ac4b33f765ac322949ac7c2f24985d3b9c178168)
841ac7
---
841ac7
 src/providers/krb5/krb5_auth.c          |  1 +
841ac7
 src/providers/krb5/krb5_child.c         | 13 +++++++
841ac7
 src/providers/krb5/krb5_child_handler.c |  4 +++
841ac7
 src/responder/pam/pamsrv_cmd.c          |  1 +
841ac7
 src/sss_client/sss_cli.h                |  3 ++
841ac7
 src/tests/cmocka/test_authtok.c         | 45 +++++++++++++++++++++++++
841ac7
 src/util/authtok.c                      | 42 +++++++++++++++++++++++
841ac7
 src/util/authtok.h                      | 35 +++++++++++++++++++
841ac7
 8 files changed, 144 insertions(+)
841ac7
841ac7
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
841ac7
index d40d2afed..9a9250434 100644
841ac7
--- a/src/providers/krb5/krb5_auth.c
841ac7
+++ b/src/providers/krb5/krb5_auth.c
841ac7
@@ -495,6 +495,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
841ac7
         case SSS_PAM_CHAUTHTOK:
841ac7
             if (authtok_type != SSS_AUTHTOK_TYPE_PASSWORD
841ac7
                     && authtok_type != SSS_AUTHTOK_TYPE_2FA
841ac7
+                    && authtok_type != SSS_AUTHTOK_TYPE_2FA_SINGLE
841ac7
                     && authtok_type != SSS_AUTHTOK_TYPE_SC_PIN
841ac7
                     && authtok_type != SSS_AUTHTOK_TYPE_SC_KEYPAD) {
841ac7
                 /* handle empty password gracefully */
841ac7
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
841ac7
index a578930a9..a86d9a7ae 100644
841ac7
--- a/src/providers/krb5/krb5_child.c
841ac7
+++ b/src/providers/krb5/krb5_child.c
841ac7
@@ -503,6 +503,15 @@ static krb5_error_code tokeninfo_matches(TALLOC_CTX *mem_ctx,
841ac7
             return ret;
841ac7
         }
841ac7
 
841ac7
+        return tokeninfo_matches_pwd(mem_ctx, ti, pwd, len, out_token, out_pin);
841ac7
+        break;
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
+        ret = sss_authtok_get_2fa_single(auth_tok, &pwd, &len;;
841ac7
+        if (ret != EOK) {
841ac7
+            DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_password failed.\n");
841ac7
+            return ret;
841ac7
+        }
841ac7
+
841ac7
         return tokeninfo_matches_pwd(mem_ctx, ti, pwd, len, out_token, out_pin);
841ac7
         break;
841ac7
     case SSS_AUTHTOK_TYPE_2FA:
841ac7
@@ -2091,6 +2100,7 @@ static errno_t tgt_req_child(struct krb5_req *kr)
841ac7
     /* No password is needed for pre-auth or if we have 2FA or SC */
841ac7
     if (kr->pd->cmd != SSS_PAM_PREAUTH
841ac7
             && sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_2FA
841ac7
+            && sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_2FA_SINGLE
841ac7
             && sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN
841ac7
             && sss_authtok_get_type(kr->pd->authtok)
841ac7
                                                 != SSS_AUTHTOK_TYPE_SC_KEYPAD) {
841ac7
@@ -2349,6 +2359,9 @@ static errno_t unpack_authtok(struct sss_auth_token *tok,
841ac7
     case SSS_AUTHTOK_TYPE_CCFILE:
841ac7
         ret = sss_authtok_set_ccfile(tok, (char *)(buf + *p), 0);
841ac7
         break;
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
+        ret = sss_authtok_set_2fa_single(tok, (char *)(buf + *p), 0);
841ac7
+        break;
841ac7
     case SSS_AUTHTOK_TYPE_2FA:
841ac7
     case SSS_AUTHTOK_TYPE_SC_PIN:
841ac7
     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
841ac7
diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c
841ac7
index 352ff980d..b7fb54499 100644
841ac7
--- a/src/providers/krb5/krb5_child_handler.c
841ac7
+++ b/src/providers/krb5/krb5_child_handler.c
841ac7
@@ -79,6 +79,10 @@ static errno_t pack_authtok(struct io_buffer *buf, size_t *rp,
841ac7
         ret = sss_authtok_get_ccfile(tok, &data, &len;;
841ac7
         auth_token_length = len + 1;
841ac7
         break;
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
+        ret = sss_authtok_get_2fa_single(tok, &data, &len;;
841ac7
+        auth_token_length = len + 1;
841ac7
+        break;
841ac7
     case SSS_AUTHTOK_TYPE_2FA:
841ac7
     case SSS_AUTHTOK_TYPE_SC_PIN:
841ac7
     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
841ac7
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
841ac7
index 94867a0fe..6f3a7e56b 100644
841ac7
--- a/src/responder/pam/pamsrv_cmd.c
841ac7
+++ b/src/responder/pam/pamsrv_cmd.c
841ac7
@@ -160,6 +160,7 @@ static int extract_authtok_v2(struct sss_auth_token *tok,
841ac7
         }
841ac7
         break;
841ac7
     case SSS_AUTHTOK_TYPE_2FA:
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
     case SSS_AUTHTOK_TYPE_SC_PIN:
841ac7
     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
841ac7
         ret = sss_authtok_set(tok, auth_token_type,
841ac7
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
841ac7
index 7e748c281..23ef21608 100644
841ac7
--- a/src/sss_client/sss_cli.h
841ac7
+++ b/src/sss_client/sss_cli.h
841ac7
@@ -340,6 +340,9 @@ enum sss_authtok_type {
841ac7
                                           * Smart Card authentication is used
841ac7
                                           * and that the PIN will be entered
841ac7
                                           * at the card reader. */
841ac7
+    SSS_AUTHTOK_TYPE_2FA_SINGLE = 0x0006, /**< Authentication token has two
841ac7
+                                           * factors in a single string, it may
841ac7
+                                           * or may no contain a trailing \\0 */
841ac7
 };
841ac7
 
841ac7
 /**
841ac7
diff --git a/src/tests/cmocka/test_authtok.c b/src/tests/cmocka/test_authtok.c
841ac7
index 9422f96bc..84e209783 100644
841ac7
--- a/src/tests/cmocka/test_authtok.c
841ac7
+++ b/src/tests/cmocka/test_authtok.c
841ac7
@@ -652,6 +652,49 @@ void test_sss_authtok_sc_pin(void **state)
841ac7
     assert_int_equal(ret, EFAULT);
841ac7
 }
841ac7
 
841ac7
+/* Test when type has value SSS_AUTHTOK_TYPE_2FA_SINGLE */
841ac7
+static void test_sss_authtok_2fa_single(void **state)
841ac7
+{
841ac7
+    size_t len;
841ac7
+    errno_t ret;
841ac7
+    char *data;
841ac7
+    size_t ret_len;
841ac7
+    const char *pwd;
841ac7
+    struct test_state *ts;
841ac7
+    enum sss_authtok_type type;
841ac7
+
841ac7
+    ts = talloc_get_type_abort(*state, struct test_state);
841ac7
+    data = talloc_strdup(ts, "1stfacto2ndfactor");
841ac7
+    assert_non_null(data);
841ac7
+
841ac7
+    len = strlen(data) + 1;
841ac7
+    type = SSS_AUTHTOK_TYPE_2FA_SINGLE;
841ac7
+    ret = sss_authtok_set(ts->authtoken, type, (const uint8_t *)data, len);
841ac7
+
841ac7
+    assert_int_equal(ret, EOK);
841ac7
+    assert_int_equal(type, sss_authtok_get_type(ts->authtoken));
841ac7
+    assert_int_equal(len, sss_authtok_get_size(ts->authtoken));
841ac7
+    assert_string_equal(data, sss_authtok_get_data(ts->authtoken));
841ac7
+
841ac7
+    ret = sss_authtok_get_2fa_single(ts->authtoken, &pwd, &ret_len);
841ac7
+
841ac7
+    assert_int_equal(ret, EOK);
841ac7
+    assert_string_equal(data, pwd);
841ac7
+    assert_int_equal(len - 1, ret_len);
841ac7
+
841ac7
+    ret = sss_authtok_set_2fa_single(ts->authtoken, data, len);
841ac7
+    assert_int_equal(ret, EOK);
841ac7
+
841ac7
+    ret = sss_authtok_get_2fa_single(ts->authtoken, &pwd, &ret_len);
841ac7
+    assert_int_equal(ret, EOK);
841ac7
+    assert_string_equal(data, pwd);
841ac7
+    assert_int_equal(len - 1, ret_len);
841ac7
+
841ac7
+    talloc_free(data);
841ac7
+    sss_authtok_set_empty(ts->authtoken);
841ac7
+}
841ac7
+
841ac7
+
841ac7
 int main(int argc, const char *argv[])
841ac7
 {
841ac7
     poptContext pc;
841ac7
@@ -687,6 +730,8 @@ int main(int argc, const char *argv[])
841ac7
                                         setup, teardown),
841ac7
         cmocka_unit_test_setup_teardown(test_sss_authtok_sc_blobs,
841ac7
                                         setup, teardown),
841ac7
+        cmocka_unit_test_setup_teardown(test_sss_authtok_2fa_single,
841ac7
+                                        setup, teardown),
841ac7
     };
841ac7
 
841ac7
     /* Set debug level to invalid value so we can decide if -d 0 was used. */
841ac7
diff --git a/src/util/authtok.c b/src/util/authtok.c
841ac7
index c2f78be32..0cac24598 100644
841ac7
--- a/src/util/authtok.c
841ac7
+++ b/src/util/authtok.c
841ac7
@@ -41,6 +41,7 @@ size_t sss_authtok_get_size(struct sss_auth_token *tok)
841ac7
     case SSS_AUTHTOK_TYPE_2FA:
841ac7
     case SSS_AUTHTOK_TYPE_SC_PIN:
841ac7
     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
         return tok->length;
841ac7
     case SSS_AUTHTOK_TYPE_EMPTY:
841ac7
         return 0;
841ac7
@@ -76,6 +77,7 @@ errno_t sss_authtok_get_password(struct sss_auth_token *tok,
841ac7
     case SSS_AUTHTOK_TYPE_2FA:
841ac7
     case SSS_AUTHTOK_TYPE_SC_PIN:
841ac7
     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
         return EACCES;
841ac7
     }
841ac7
 
841ac7
@@ -101,6 +103,33 @@ errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok,
841ac7
     case SSS_AUTHTOK_TYPE_2FA:
841ac7
     case SSS_AUTHTOK_TYPE_SC_PIN:
841ac7
     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
+        return EACCES;
841ac7
+    }
841ac7
+
841ac7
+    return EINVAL;
841ac7
+}
841ac7
+
841ac7
+errno_t sss_authtok_get_2fa_single(struct sss_auth_token *tok,
841ac7
+                                   const char **str, size_t *len)
841ac7
+{
841ac7
+    if (!tok) {
841ac7
+        return EINVAL;
841ac7
+    }
841ac7
+    switch (tok->type) {
841ac7
+    case SSS_AUTHTOK_TYPE_EMPTY:
841ac7
+        return ENOENT;
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
+        *str = (const char *)tok->data;
841ac7
+        if (len) {
841ac7
+            *len = tok->length - 1;
841ac7
+        }
841ac7
+        return EOK;
841ac7
+    case SSS_AUTHTOK_TYPE_PASSWORD:
841ac7
+    case SSS_AUTHTOK_TYPE_2FA:
841ac7
+    case SSS_AUTHTOK_TYPE_SC_PIN:
841ac7
+    case SSS_AUTHTOK_TYPE_SC_KEYPAD:
841ac7
+    case SSS_AUTHTOK_TYPE_CCFILE:
841ac7
         return EACCES;
841ac7
     }
841ac7
 
841ac7
@@ -151,6 +180,7 @@ void sss_authtok_set_empty(struct sss_auth_token *tok)
841ac7
     case SSS_AUTHTOK_TYPE_PASSWORD:
841ac7
     case SSS_AUTHTOK_TYPE_2FA:
841ac7
     case SSS_AUTHTOK_TYPE_SC_PIN:
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
         safezero(tok->data, tok->length);
841ac7
         break;
841ac7
     case SSS_AUTHTOK_TYPE_CCFILE:
841ac7
@@ -181,6 +211,15 @@ errno_t sss_authtok_set_ccfile(struct sss_auth_token *tok,
841ac7
                                   "ccfile", ccfile, len);
841ac7
 }
841ac7
 
841ac7
+errno_t sss_authtok_set_2fa_single(struct sss_auth_token *tok,
841ac7
+                                   const char *str, size_t len)
841ac7
+{
841ac7
+    sss_authtok_set_empty(tok);
841ac7
+
841ac7
+    return sss_authtok_set_string(tok, SSS_AUTHTOK_TYPE_2FA_SINGLE,
841ac7
+                                  "2fa_single", str, len);
841ac7
+}
841ac7
+
841ac7
 static errno_t sss_authtok_set_2fa_from_blob(struct sss_auth_token *tok,
841ac7
                                              const uint8_t *data, size_t len);
841ac7
 
841ac7
@@ -199,6 +238,8 @@ errno_t sss_authtok_set(struct sss_auth_token *tok,
841ac7
         return sss_authtok_set_sc_from_blob(tok, data, len);
841ac7
     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
841ac7
         return sss_authtok_set_sc_from_blob(tok, data, len);
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
+        return sss_authtok_set_2fa_single(tok, (const char *) data, len);
841ac7
     case SSS_AUTHTOK_TYPE_EMPTY:
841ac7
         sss_authtok_set_empty(tok);
841ac7
         return EOK;
841ac7
@@ -566,6 +607,7 @@ errno_t sss_authtok_get_sc_pin(struct sss_auth_token *tok, const char **_pin,
841ac7
     case SSS_AUTHTOK_TYPE_CCFILE:
841ac7
     case SSS_AUTHTOK_TYPE_2FA:
841ac7
     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
841ac7
+    case SSS_AUTHTOK_TYPE_2FA_SINGLE:
841ac7
         return EACCES;
841ac7
     }
841ac7
 
841ac7
diff --git a/src/util/authtok.h b/src/util/authtok.h
841ac7
index a55e89fd2..dae3ff6b1 100644
841ac7
--- a/src/util/authtok.h
841ac7
+++ b/src/util/authtok.h
841ac7
@@ -348,4 +348,39 @@ errno_t sss_authtok_get_sc(struct sss_auth_token *tok,
841ac7
                            const char **_token_name, size_t *_token_name_len,
841ac7
                            const char **_module_name, size_t *_module_name_len,
841ac7
                            const char **_key_id, size_t *_key_id_len);
841ac7
+
841ac7
+
841ac7
+/**
841ac7
+ * @brief Returns a const string if the auth token is of type
841ac7
+          SSS_AUTHTOK_TYPE_2FA_SINGLE, otherwise it returns an error
841ac7
+ *
841ac7
+ * @param tok    A pointer to an sss_auth_token
841ac7
+ * @param pwd    A pointer to a const char *, that will point to a null
841ac7
+ *               terminated string
841ac7
+ * @param len    The length of the credential string
841ac7
+ *
841ac7
+ * @return       EOK on success
841ac7
+ *               ENOENT if the token is empty
841ac7
+ *               EACCESS if the token is not a password token
841ac7
+ */
841ac7
+errno_t sss_authtok_get_2fa_single(struct sss_auth_token *tok,
841ac7
+                                   const char **str, size_t *len);
841ac7
+
841ac7
+/**
841ac7
+ * @brief Set a 2FA credentials in a single strings  into an auth token,
841ac7
+ *        replacing any previous data
841ac7
+ *
841ac7
+ * @param tok        A pointer to an sss_auth_token structure to change, also
841ac7
+ *                   used as a memory context to allocate the internal data.
841ac7
+ * @param password   A string where the two authentication factors are
841ac7
+ *                   concatenated together
841ac7
+ * @param len        The length of the string or, if 0 is passed,
841ac7
+ *                   then strlen(password) will be used internally.
841ac7
+ *
841ac7
+ * @return       EOK on success
841ac7
+ *               ENOMEM on error
841ac7
+ */
841ac7
+errno_t sss_authtok_set_2fa_single(struct sss_auth_token *tok,
841ac7
+                                   const char *str, size_t len);
841ac7
+
841ac7
 #endif /*  __AUTHTOK_H__ */
841ac7
-- 
841ac7
2.19.1
841ac7