Blob Blame History Raw
From fc4862295d512e464feff60cbc5df8c50bf83644 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Thu, 27 Nov 2014 20:29:03 +0100
Subject: [PATCH 133/138] Skip CHAUTHTOK_PRELIM when using OTPs

https://fedorahosted.org/sssd/ticket/2484

When OTPs are used, we can only used each authtoken at most once. When
it comes to Kerberos password changes, this was only working previously
by accident, because the old authtoken was first used to verify the old
password is valid and not expired and then also to acquire a chpass
principal.

This patch looks at the user object in LDAP to check if the user has any
OTPs enabled. If he does, the CHAUTHTOK_PRELIM step is skipped
completely so that the OTP can be used to acquire the chpass ticket
later.

Reviewed-by: Sumit Bose <sbose@redhat.com>
---
 src/db/sysdb.h                 |  2 ++
 src/providers/ad/ad_opts.h     |  1 +
 src/providers/ipa/ipa_opts.h   |  1 +
 src/providers/krb5/krb5_auth.c | 38 +++++++++++++++++++++++++++++++++++---
 src/providers/ldap/ldap_opts.h |  3 +++
 src/providers/ldap/sdap.h      |  1 +
 6 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 5bd7f90acb685bbaff5c98f433c7dce8175c33ca..4fbbb16718a2fc3d444e4c6dba5fca4c1bb3096a 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -127,6 +127,8 @@
 
 #define SYSDB_SSH_PUBKEY "sshPublicKey"
 
+#define SYSDB_AUTH_TYPE "authType"
+
 #define SYSDB_SUBDOMAIN_REALM "realmName"
 #define SYSDB_SUBDOMAIN_FLAT "flatName"
 #define SYSDB_SUBDOMAIN_ID "domainID"
diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
index c3de3d94b1818665a86bba8a2432c699717b6a34..d9405e5020ca724a0f7caa752ac10fb07d8aa397 100644
--- a/src/providers/ad/ad_opts.h
+++ b/src/providers/ad/ad_opts.h
@@ -212,6 +212,7 @@ struct sdap_attr_map ad_2008r2_user_map[] = {
     { "ldap_user_nds_login_expiration_time", NULL, SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", NULL, SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
     { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL },
+    { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index f77ff1d05b9540155db44d04d4fb3aac9d7b5988..66af648583e552d7edd932f6bb5a2c3bef107e51 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -203,6 +203,7 @@ struct sdap_attr_map ipa_user_map[] = {
     { "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
     { "ldap_user_ssh_public_key", "ipaSshPubKey", SYSDB_SSH_PUBKEY, NULL },
+    { "ldap_user_auth_type", "ipaUserAuthType", SYSDB_AUTH_TYPE, NULL },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index e43b3652786678b79499e30ed546712ef080fe2c..25caf7b788a3f373f47e9d8aad38a2ea6fc12621 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -311,6 +311,25 @@ static void krb5_auth_store_creds(struct sss_domain_info *domain,
     }
 }
 
+static bool is_otp_enabled(struct ldb_message *user_msg)
+{
+    struct ldb_message_element *el;
+    size_t i;
+
+    el = ldb_msg_find_element(user_msg, SYSDB_AUTH_TYPE);
+    if (el == NULL) {
+        return false;
+    }
+
+    for (i = 0; i < el->num_values; i++) {
+        if (strcmp((const char * )el->values[i].data, "otp") == 0) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 /* krb5_auth request */
 
 struct krb5_auth_state {
@@ -344,8 +363,9 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
     const char *realm;
     struct tevent_req *req;
     struct tevent_req *subreq;
-    int authtok_type;
+    enum sss_authtok_type authtok_type;
     int ret;
+    bool otp;
 
     req = tevent_req_create(mem_ctx, &state, struct krb5_auth_state);
     if (req == NULL) {
@@ -441,7 +461,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    attrs = talloc_array(state, const char *, 7);
+    attrs = talloc_array(state, const char *, 8);
     if (attrs == NULL) {
         ret = ENOMEM;
         goto done;
@@ -453,7 +473,8 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
     attrs[3] = SYSDB_UIDNUM;
     attrs[4] = SYSDB_GIDNUM;
     attrs[5] = SYSDB_CANONICAL_UPN;
-    attrs[6] = NULL;
+    attrs[6] = SYSDB_AUTH_TYPE;
+    attrs[7] = NULL;
 
     ret = krb5_setup(state, pd, krb5_ctx, &state->kr);
     if (ret != EOK) {
@@ -547,6 +568,17 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
         break;
     }
 
+    otp = is_otp_enabled(res->msgs[0]);
+    if (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM && otp == true) {
+        /* To avoid consuming the OTP */
+        DEBUG(SSSDBG_TRACE_FUNC,
+              "Skipping password checks for OTP-enabled user\n");
+        state->pam_status = PAM_SUCCESS;
+        state->dp_err = DP_ERR_OK;
+        ret = EOK;
+        goto done;
+    }
+
     kr->srv = NULL;
     kr->kpasswd_srv = NULL;
 
diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
index f46381e9fac7b93730ce0767154989f2e3b7ebbf..7c9ed3e01f726f2ba6ecb2a7268867abd3baa37d 100644
--- a/src/providers/ldap/ldap_opts.h
+++ b/src/providers/ldap/ldap_opts.h
@@ -179,6 +179,7 @@ struct sdap_attr_map rfc2307_user_map[] = {
     { "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
     { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL },
+    { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
@@ -233,6 +234,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
     { "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
     { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL },
+    { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
@@ -287,6 +289,7 @@ struct sdap_attr_map gen_ad2008r2_user_map[] = {
     { "ldap_user_nds_login_expiration_time", NULL, SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", NULL, SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
     { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL },
+    { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index aa10623a58d7d667205b09e744dc2b924ca821ed..921051b41a911a2d1117672a8e9c2697b679f24e 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -280,6 +280,7 @@ enum sdap_user_attrs {
     SDAP_AT_NDS_LOGIN_EXPIRATION_TIME,
     SDAP_AT_NDS_LOGIN_ALLOWED_TIME_MAP,
     SDAP_AT_USER_SSH_PUBLIC_KEY,
+    SDAP_AT_USER_AUTH_TYPE,
 
     SDAP_OPTS_USER /* attrs counter */
 };
-- 
1.9.3