On (02/03/16 10:02), Simo Sorce wrote:
>On Wed, 2016-03-02 at 15:34 +0100, Lukas Slebodnik wrote:
>> On (01/03/16 18:28), Simo Sorce wrote:
>> >On Tue, 2016-03-01 at 18:22 -0500, Simo Sorce wrote:
>> >> On Tue, 2016-03-01 at 22:34 +0100, Lukas Slebodnik wrote:
>> >> > On (01/03/16 12:05), Simo Sorce wrote:
>> >> > >On Tue, 2016-03-01 at 17:51 +0100, Lukas Slebodnik wrote:
>> >> > >> On (01/03/16 17:45), Lukas Slebodnik wrote:
>> >> > >> >On (31/01/16 11:53), Simo Sorce wrote:
>> >> > >> >>Expired != Disabled
>> >> > >> >>this change is intentional.
>> >> > >> >>
>> >> > >> >Yes, but explain it to Active directory :-)
>> >> > >> >
>> >> > >> >Attached is patch with workaround/hack
>> >> > >> >regression with expired AD users.
>> >> > >> >
>> >> > >> ENOPATCH
>> >> > >> 
>> >> > >> LS
>> >> > >
>> >> > >I think a better approach is to return the KRBKDC error from the child
>> >> > >without mapping (or with an intermediate mapping) and have the IPA and
>> >> > >AD providers map it on their own.
>> >> > >
>> >> > It's not related to mapping KRBKDC error codes to internal error code.
>> >> > The main problem is that AD return the same error code for expired
>> >> > and disabled user. And ad provider used generic krb5 functions.
>> >> > 
>> >> > BTW the same issue would be with id_provider ldap +
>> >> > auth_provider = krb5 with AD :-(
>> >> > I'm not sure how your proposal would help.
>> >> 
>> >> I think AD returns additional information in edata, maybe we can use
>> >> that to do the proper mapping in the generic krb5 code.
>> >> 
>> >> Absence of AD specific edata would indicate MIT mapping, presence would
>> >> allow us to use that additional data to figure out the correct mapping.
>> >> 
>> >> Simo.
>> >> 
>> >
>> >See MS-KILE[1] 2.2.1, I bet the two conditions returns two different
>> >windows Style errors in etext (not edata, sorry).
>> >
>> >[1] https://msdn.microsoft.com/en-us/library/cc233855.aspx
>> >
>> Interesting idea and it seems to work.
>> The main difference was in time and last octet string.
>> * response for expired user [2]
>>    the last octet string in ASN:
>>       930100C00000000001000000
>
>This is error C0000193 aka NT_STATUS_ACCOUNT_EXPIRED NT_STATUS
>https://git.samba.org/?p=samba.git;a=blob;f=libcli/util/ntstatus.h;h=572093b431d80c9e12461255d01063412bbfa5b5;hb=HEAD#l494
>
>> * response for disabled user [3]
>>    the last octet string in ASN:
>>       720000C00000000001000000T
>
>This is error C0000072, aka NT_STATUS_ACCOUNT_DISABLED NT_STATUS
>https://git.samba.org/?p=samba.git;a=blob;f=libcli/util/ntstatus.h;h=572093b431d80c9e12461255d01063412bbfa5b5;hb=HEAD#l211
>> 
>> The only question is how to get etext from krb5 response.
>> I do not want to implement ASN.1 parser.
>
>We use asn1c in FreeIPA if we need to generate a parser, but I do not
>think we need to get that far.
>The main issue is whether the krb5 fucntions let us get access to the
>etext data at all, it seem buried pretty low in the internal of krb5.
>
It took me a while to find out why my patch broke password change
then I realized I have unused argument in_tkt_service
in my version of krb5_get_init_creds_password.
We might enable gcc warning Wunused-argument :-)

Please review attached patch.

LS
>From 8108259744e944b3521e8cf98105d791db82c402 Mon Sep 17 00:00:00 2001
From: root <r...@host1.kautest.com>
Date: Wed, 2 Mar 2016 11:21:44 -0500
Subject: [PATCH] KRB5_CHILD: Discern between expired & disabled AD user

Active directory return krb5 error code KRB5KDC_ERR_CLIENT_REVOKED
"-1765328366/Clients credentials have been revoked" for expired and
disabled user. This is difference between AD and IPA
https://fedorahosted.org/sssd/ticket/2924.

Therefore we need to distinguish between these two states.
AD provides krb5 error data together with krb5 error code.
They contains KERB-EXT-ERROR which is documeted in
"[MS-KILE]: Kerberos Protocol Extensions"[1] and contains
NTSTATUS in KERB-EXT-ERROR

[1] https://msdn.microsoft.com/en-us/library/cc233855.aspx

Related to:
https://fedorahosted.org/sssd/ticket/2924
---
 src/providers/krb5/krb5_child.c | 168 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 153 insertions(+), 15 deletions(-)

diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index 
fff6a0a0cb186ef72350b5906b85455db561e4b8..06e3fa5e7d8c10b62e26c18a36c3d69877f54fb0
 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -1191,6 +1191,144 @@ done:
 
 }
 
+/* [MS-KILE]: Kerberos Protocol Extensions
+ * https://msdn.microsoft.com/en-us/library/cc233855.aspx
+ * 
http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-KILE%5D.pdf
+ * 2.2.1 KERB-EXT-ERROR
+ */
+bool have_ms_kile_ext_error(unsigned char *data, unsigned int length,
+                            uint32_t *_ntstatus)
+{
+    /* [MS-KILE] 2.2.2 KERB-ERROR-DATA
+     * Kerberos V5 messages are defined using Abstract Syntax Notation One
+     * (ASN.1)
+     * KERB-ERROR-DATA ::= SEQUENCE {
+     *      data-type              [1] INTEGER,
+     *      data-value             [2] OCTET STRING OPTIONAL
+     * }
+     * We are interested in data-type 3 KERB_ERR_TYPE_EXTENDED
+     */
+    uint8_t kile_asn1_begining[] = {
+        0x30, 0x15, /* 0x30 is SEQUENCE, 0x15 length */
+        0xA1, 0x03, /* 0xA1 is 1st element of sequence, 0x03 length */
+        0x02, 0x01, 0x03, /* 0x02 is INTEGER, 0x01 length, 0x03 value */
+        0xA2, 0x0E, /* 0xA2 is 2nd element of sequence, 0x0E length */
+        0x04, 0x0C, /* 0x04 is OCTET STRING, 0x0C length (12 bytes) */
+    };
+    const size_t offset = sizeof(kile_asn1_begining);
+    uint32_t value;
+
+    if (length != 23 || data == NULL) {
+        return false;
+    }
+
+    if (memcmp(data, kile_asn1_begining, offset) != 0) {
+        return false;
+    }
+
+    /* [MS-KILE] 2.2.1 KERB-EXT-ERROR
+     * typedef struct KERB_EXT_ERROR {
+     *     unsigned long status;
+     *     unsigned long reserved;
+     *     unsigned long flags;
+     * } KERB_EXT_ERROR;
+     * Status: An NTSTATUS value. See [MS-ERREF] section 2.3.
+     */
+    value = data[offset + 3] << 24
+            | data[offset + 2] << 16
+            | data[offset + 1] << 8
+            | data[offset + 0];
+
+    *_ntstatus = value;
+    return true;
+}
+
+/* Following NTSTATUS values are from:
+ * [MS-ERREF]: Windows Error Codes -> Section 2.3.1
+ * https://msdn.microsoft.com/en-us/library/cc231196.aspx
+ * 
http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-ERREF%5D.pdf
+ */
+#define NT_STATUS_ACCOUNT_EXPIRED 0xC0000193
+#define NT_STATUS_ACCOUNT_DISABLED 0xC0000072
+
+void check_ms_kile_ext_krb5err(krb5_context context,
+                               krb5_init_creds_context init_cred_ctx,
+                               krb5_error_code *_kerr)
+{
+    krb5_error_code err;
+    krb5_error *error = NULL;
+    uint32_t ntstatus;
+
+    err = krb5_init_creds_get_error(context, init_cred_ctx, &error);
+    if (err != 0 || error == NULL) {
+        KRB5_CHILD_DEBUG(SSSDBG_TRACE_FUNC, err);
+        return;
+    }
+
+    if (have_ms_kile_ext_error((unsigned char *)error->e_data.data, 
error->e_data.length,
+                               &ntstatus)) {
+        switch (ntstatus) {
+        case NT_STATUS_ACCOUNT_EXPIRED:
+            *_kerr = KRB5KDC_ERR_NAME_EXP;
+            break;
+        case NT_STATUS_ACCOUNT_DISABLED:
+            *_kerr = KRB5KDC_ERR_CLIENT_REVOKED;
+            break;
+        }
+    }
+}
+
+krb5_error_code
+sss_krb5_get_init_creds_password(krb5_context context, krb5_creds *creds,
+                                 krb5_principal client, const char *password,
+                                 krb5_prompter_fct prompter, void *data,
+                                 krb5_deltat start_time,
+                                 const char *in_tkt_service,
+                                 krb5_get_init_creds_opt *k5_gic_options)
+{
+    krb5_error_code kerr;
+    krb5_init_creds_context init_cred_ctx = NULL;
+
+    kerr = krb5_init_creds_init(context, client, prompter, data,
+                                start_time, k5_gic_options,
+                                &init_cred_ctx);
+    if (kerr != 0) {
+        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+        goto done;
+    }
+
+    kerr = krb5_init_creds_set_password(context, init_cred_ctx, password);
+    if (kerr != 0) {
+        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+        goto done;
+    }
+
+    if (in_tkt_service != NULL) {
+        kerr = krb5_init_creds_set_service(context, init_cred_ctx,
+                                           in_tkt_service);
+        if (kerr != 0) {
+            KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+            goto done;
+        }
+    }
+
+    kerr = krb5_init_creds_get(context, init_cred_ctx);
+    if (kerr == KRB5KDC_ERR_CLIENT_REVOKED) {
+        check_ms_kile_ext_krb5err(context, init_cred_ctx, &kerr);
+    }
+
+    if (kerr != 0) {
+        KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+        goto done;
+    }
+
+    kerr = krb5_init_creds_get_creds(context, init_cred_ctx, creds);
+
+done:
+    krb5_init_creds_free(context, init_cred_ctx);
+    return kerr;
+}
+
 static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
                                         const char *password)
 {
@@ -1216,15 +1354,15 @@ static krb5_error_code get_and_save_tgt(struct krb5_req 
*kr,
 
     DEBUG(SSSDBG_TRACE_FUNC,
           "Attempting kinit for realm [%s]\n",realm_name);
-    kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
-                                        discard_const(password),
-                                        sss_krb5_prompter, kr, 0,
-                                        NULL, kr->options);
+    kerr = sss_krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
+                                            discard_const(password),
+                                            sss_krb5_prompter, kr, 0, NULL,
+                                            kr->options);
     if (kr->pd->cmd == SSS_PAM_PREAUTH) {
         /* Any errors are ignored during pre-auth, only data is collected to
          * be send back to the client.*/
         DEBUG(SSSDBG_TRACE_FUNC,
-              "krb5_get_init_creds_password returned [%d} during pre-auth.\n",
+              "sss_krb5_get_init_creds_password returned [%d} during 
pre-auth.\n",
               kerr);
         return 0;
     } else {
@@ -1395,11 +1533,11 @@ static errno_t changepw_child(struct krb5_req *kr, bool 
prelim)
 
     DEBUG(SSSDBG_TRACE_FUNC,
           "Attempting kinit for realm [%s]\n",realm_name);
-    kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
-                                        discard_const(password),
-                                        prompter, kr, 0,
-                                        SSSD_KRB5_CHANGEPW_PRINCIPAL,
-                                        kr->options);
+    kerr = sss_krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
+                                            discard_const(password),
+                                            prompter, kr, 0,
+                                            SSSD_KRB5_CHANGEPW_PRINCIPAL,
+                                            kr->options);
     DEBUG(SSSDBG_TRACE_INTERNAL,
           "chpass is%s using OTP\n", kr->otp ? "" : " not");
     if (kerr != 0) {
@@ -1588,11 +1726,11 @@ static errno_t tgt_req_child(struct krb5_req *kr)
     }
 
     set_changepw_options(kr->options);
-    kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
-                                        discard_const(password),
-                                        sss_krb5_prompter, kr, 0,
-                                        SSSD_KRB5_CHANGEPW_PRINCIPAL,
-                                        kr->options);
+    kerr = sss_krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,
+                                            discard_const(password),
+                                            sss_krb5_prompter, kr, 0,
+                                            SSSD_KRB5_CHANGEPW_PRINCIPAL,
+                                            kr->options);
 
     krb5_free_cred_contents(kr->ctx, kr->creds);
     if (kerr == 0) {
-- 
2.7.2

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/admin/lists/sssd-devel@lists.fedorahosted.org

Reply via email to