]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:kdc/hdb: Store and retrieve a FX-COOKIE value
authorAndrew Bartlett <abartlet@samba.org>
Thu, 20 Sep 2018 02:24:11 +0000 (19:24 -0700)
committerJoseph Sutton <jsutton@samba.org>
Wed, 19 Jan 2022 20:50:35 +0000 (20:50 +0000)
Note Windows uses the string "MICROSOFT" as cookie,
so it's wrong to have a per DC cookie, but we need to
adjust the Heimdal logic to support that.

NOTE: THIS COMMIT WON'T COMPILE/WORK ON ITS OWN!

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source4/kdc/db-glue.c
source4/kdc/db-glue.h
source4/kdc/hdb-samba4.c
source4/kdc/samba_kdc.h

index b059d8c7e61fb02c57fc461acafcc23109d0b90e..bef8bd4f4547aafcdcea56011b3f7399f294f261 100644 (file)
@@ -29,6 +29,7 @@
 #include "dsdb/common/util.h"
 #include "librpc/gen_ndr/ndr_drsblobs.h"
 #include "param/param.h"
+#include "param/secrets.h"
 #include "../lib/crypto/md4.h"
 #include "system/kerberos.h"
 #include "auth/kerberos/kerberos.h"
@@ -317,6 +318,104 @@ static int samba_kdc_sort_encryption_keys(struct sdb_entry_ex *entry_ex)
        return 0;
 }
 
+int samba_kdc_set_fixed_keys(krb5_context context,
+                            struct samba_kdc_db_context *kdc_db_ctx,
+                            const struct ldb_val *secretbuffer,
+                            struct sdb_entry_ex *entry_ex)
+{
+       const uint32_t supported_enctypes = ENC_ALL_TYPES;
+       uint16_t allocated_keys = 0;
+       int ret;
+
+       allocated_keys = 3;
+       entry_ex->entry.keys.len = 0;
+       entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(struct sdb_key));
+       if (entry_ex->entry.keys.val == NULL) {
+               memset(secretbuffer->data, 0, secretbuffer->length);
+               ret = ENOMEM;
+               goto out;
+       }
+
+       if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
+               struct sdb_key key = {};
+
+               ret = smb_krb5_keyblock_init_contents(context,
+                                                     ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+                                                     secretbuffer->data,
+                                                     MIN(secretbuffer->length, 32),
+                                                     &key.key);
+               if (ret) {
+                       memset(secretbuffer->data, 0, secretbuffer->length);
+                       goto out;
+               }
+
+               entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
+               entry_ex->entry.keys.len++;
+       }
+
+       if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
+               struct sdb_key key = {};
+
+               ret = smb_krb5_keyblock_init_contents(context,
+                                                     ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+                                                     secretbuffer->data,
+                                                     MIN(secretbuffer->length, 16),
+                                                     &key.key);
+               if (ret) {
+                       memset(secretbuffer->data, 0, secretbuffer->length);
+                       goto out;
+               }
+
+               entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
+               entry_ex->entry.keys.len++;
+       }
+
+       if (supported_enctypes & ENC_RC4_HMAC_MD5) {
+               struct sdb_key key = {};
+
+               ret = smb_krb5_keyblock_init_contents(context,
+                                                     ENCTYPE_ARCFOUR_HMAC,
+                                                     secretbuffer->data,
+                                                     MIN(secretbuffer->length, 16),
+                                                     &key.key);
+               if (ret) {
+                       memset(secretbuffer->data, 0, secretbuffer->length);
+                       goto out;
+               }
+
+               entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
+               entry_ex->entry.keys.len++;
+       }
+       ret = 0;
+out:
+       return ret;
+}
+
+
+static int samba_kdc_set_random_keys(krb5_context context,
+                                    struct samba_kdc_db_context *kdc_db_ctx,
+                                    struct sdb_entry_ex *entry_ex)
+{
+       struct ldb_val secret_val;
+       uint8_t secretbuffer[32];
+
+       /*
+        * Fake keys until we have a better way to reject
+        * non-pkinit requests.
+        *
+        * We just need to indicate which encryption types are
+        * supported.
+        */
+       generate_secret_buffer(secretbuffer, sizeof(secretbuffer));
+
+       secret_val = data_blob_const(secretbuffer,
+                                    sizeof(secretbuffer));
+       return samba_kdc_set_fixed_keys(context, kdc_db_ctx,
+                                       &secret_val,
+                                       entry_ex);
+}
+
+
 static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
                                                    struct samba_kdc_db_context *kdc_db_ctx,
                                                    TALLOC_CTX *mem_ctx,
@@ -386,75 +485,9 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
 
        if ((ent_type == SAMBA_KDC_ENT_TYPE_CLIENT)
            && (userAccountControl & UF_SMARTCARD_REQUIRED)) {
-               uint8_t secretbuffer[32];
-
-               /*
-                * Fake keys until we have a better way to reject
-                * non-pkinit requests.
-                *
-                * We just need to indicate which encryption types are
-                * supported.
-                */
-               generate_secret_buffer(secretbuffer, sizeof(secretbuffer));
-
-               allocated_keys = 3;
-               entry_ex->entry.keys.len = 0;
-               entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(struct sdb_key));
-               if (entry_ex->entry.keys.val == NULL) {
-                       ZERO_STRUCT(secretbuffer);
-                       ret = ENOMEM;
-                       goto out;
-               }
-
-               if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
-                       struct sdb_key key = {};
-
-                       ret = smb_krb5_keyblock_init_contents(context,
-                                                             ENCTYPE_AES256_CTS_HMAC_SHA1_96,
-                                                             secretbuffer, 32,
-                                                             &key.key);
-                       if (ret) {
-                               ZERO_STRUCT(secretbuffer);
-                               goto out;
-                       }
-
-                       entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
-                       entry_ex->entry.keys.len++;
-               }
-
-               if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
-                       struct sdb_key key = {};
-
-                       ret = smb_krb5_keyblock_init_contents(context,
-                                                             ENCTYPE_AES128_CTS_HMAC_SHA1_96,
-                                                             secretbuffer, 16,
-                                                             &key.key);
-                       if (ret) {
-                               ZERO_STRUCT(secretbuffer);
-                               goto out;
-                       }
-
-                       entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
-                       entry_ex->entry.keys.len++;
-               }
-
-               if (supported_enctypes & ENC_RC4_HMAC_MD5) {
-                       struct sdb_key key = {};
-
-                       ret = smb_krb5_keyblock_init_contents(context,
-                                                             ENCTYPE_ARCFOUR_HMAC,
-                                                             secretbuffer, 16,
-                                                             &key.key);
-                       if (ret) {
-                               ZERO_STRUCT(secretbuffer);
-                               goto out;
-                       }
-
-                       entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
-                       entry_ex->entry.keys.len++;
-               }
-
-               ret = 0;
+               ret = samba_kdc_set_random_keys(context,
+                                               kdc_db_ctx,
+                                               entry_ex);
                goto out;
        }
 
@@ -2788,6 +2821,21 @@ NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_conte
                return NT_STATUS_INTERNAL_ERROR;
        }
 
+       /* Setup the link to secrets.ldb */
+
+       kdc_db_ctx->secrets_db = secrets_db_connect(kdc_db_ctx,
+                                                   base_ctx->lp_ctx);
+       if (kdc_db_ctx->secrets_db == NULL) {
+               DEBUG(1, ("samba_kdc_setup_db_ctx: "
+                         "Cannot open secrets.ldb for KDC backend!"));
+               talloc_free(kdc_db_ctx);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       kdc_db_ctx->fx_cookie_dn = ldb_dn_new(kdc_db_ctx,
+                                             kdc_db_ctx->secrets_db,
+                                             "CN=FX Cookie");
+
        /* Setup the link to LDB */
        kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx,
                                          base_ctx->ev_ctx,
index 4defca2320ca1c21d5c654385fa7f83387fdfa6c..218bd3cfae2e27e1f9ed66d4e6d997a9514e2728 100644 (file)
 
 struct sdb_entry_ex;
 
+
+int samba_kdc_set_fixed_keys(krb5_context context,
+                            struct samba_kdc_db_context *kdc_db_ctx,
+                            const struct ldb_val *secretbuffer,
+                            struct sdb_entry_ex *entry_ex);
+
 krb5_error_code samba_kdc_fetch(krb5_context context,
                                struct samba_kdc_db_context *kdc_db_ctx,
                                krb5_const_principal principal,
index 9132bb46212d705a2f0a1403182f61e8dd1c776a..c0ec4bd3cd8449ea9c5b7029ab18f5a5259c1a86 100644 (file)
@@ -92,6 +92,128 @@ static krb5_error_code hdb_samba4_set_sync(krb5_context context, struct HDB *db,
        return 0;
 }
 
+static int hdb_samba4_fill_fast_cookie(krb5_context context,
+                                      struct samba_kdc_db_context *kdc_db_ctx)
+{
+       struct ldb_message *msg = ldb_msg_new(kdc_db_ctx);
+       int ldb_ret;
+
+       uint8_t secretbuffer[32];
+       struct ldb_val val = data_blob_const(secretbuffer,
+                                            sizeof(secretbuffer));
+
+       if (msg == NULL) {
+               DBG_ERR("Failed to allocate msg for new fast cookie\n");
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /* Fill in all the keys with the same secret */
+       generate_secret_buffer(secretbuffer,
+                              sizeof(secretbuffer));
+
+       msg->dn = kdc_db_ctx->fx_cookie_dn;
+
+       ldb_ret = ldb_msg_add_value(msg, "secret", &val, NULL);
+
+       if (ldb_ret != LDB_SUCCESS) {
+               return ldb_ret;
+       }
+
+       ldb_ret = ldb_add(kdc_db_ctx->secrets_db,
+                         msg);
+       if (ldb_ret != LDB_SUCCESS) {
+               DBG_ERR("Failed to add fast cookie to ldb: %s\n",
+                       ldb_errstring(kdc_db_ctx->secrets_db));
+       }
+       return ldb_ret;
+}
+
+static krb5_error_code hdb_samba4_fetch_fast_cookie(krb5_context context,
+                                                   struct samba_kdc_db_context *kdc_db_ctx,
+                                                   hdb_entry_ex *entry_ex)
+{
+       krb5_error_code ret = SDB_ERR_NOENTRY;
+       TALLOC_CTX *mem_ctx;
+       struct ldb_result *res;
+       int ldb_ret;
+       struct sdb_entry_ex sdb_entry_ex = {};
+       const char *attrs[] = {
+               "secret",
+               NULL
+       };
+       const struct ldb_val *val;
+
+       mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
+       if (!mem_ctx) {
+               ret = ENOMEM;
+               krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
+               return ret;
+       }
+
+       /* search for CN=FX-COOKIE */
+       ldb_ret = ldb_search(kdc_db_ctx->secrets_db,
+                            mem_ctx,
+                            &res,
+                            kdc_db_ctx->fx_cookie_dn,
+                            LDB_SCOPE_BASE,
+                            attrs, NULL);
+
+       if (ldb_ret == LDB_ERR_NO_SUCH_OBJECT || res->count == 0) {
+
+               ldb_ret = hdb_samba4_fill_fast_cookie(context,
+                                                     kdc_db_ctx);
+
+               if (ldb_ret != LDB_SUCCESS) {
+                       TALLOC_FREE(mem_ctx);
+                       return HDB_ERR_NO_WRITE_SUPPORT;
+               }
+
+               /* search for CN=FX-COOKIE */
+               ldb_ret = ldb_search(kdc_db_ctx->secrets_db,
+                                    mem_ctx,
+                                    &res,
+                                    kdc_db_ctx->fx_cookie_dn,
+                                    LDB_SCOPE_BASE,
+                                    attrs, NULL);
+
+               if (ldb_ret != LDB_SUCCESS || res->count != 1) {
+                       TALLOC_FREE(mem_ctx);
+                       return HDB_ERR_NOENTRY;
+               }
+       }
+
+       val = ldb_msg_find_ldb_val(res->msgs[0],
+                                  "secret");
+       if (val == NULL || val->length != 32) {
+               TALLOC_FREE(mem_ctx);
+               return HDB_ERR_NOENTRY;
+       }
+
+
+       ret = krb5_make_principal(context,
+                                 &sdb_entry_ex.entry.principal,
+                                 KRB5_WELLKNOWN_ORG_H5L_REALM,
+                                 KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie",
+                                 NULL);
+       if (ret) {
+               TALLOC_FREE(mem_ctx);
+               return ret;
+       }
+
+       ret = samba_kdc_set_fixed_keys(context, kdc_db_ctx,
+                                      val, &sdb_entry_ex);
+       if (ret != 0) {
+               return ret;
+       }
+
+       ret = sdb_entry_ex_to_hdb_entry_ex(context,
+                                          &sdb_entry_ex,
+                                          entry_ex);
+       TALLOC_FREE(mem_ctx);
+
+       return ret;
+}
+
 static krb5_error_code hdb_samba4_fetch_kvno(krb5_context context, HDB *db,
                                             krb5_const_principal principal,
                                             unsigned flags,
@@ -101,10 +223,15 @@ static krb5_error_code hdb_samba4_fetch_kvno(krb5_context context, HDB *db,
        struct samba_kdc_db_context *kdc_db_ctx;
        struct sdb_entry_ex sdb_entry_ex = {};
        krb5_error_code code, ret;
-
        kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
                                           struct samba_kdc_db_context);
 
+       if (flags & HDB_F_GET_FAST_COOKIE) {
+               return hdb_samba4_fetch_fast_cookie(context,
+                                                   kdc_db_ctx,
+                                                   entry_ex);
+       }
+
        ret = samba_kdc_fetch(context,
                              kdc_db_ctx,
                              principal,
index e228a82ce6ac323b605d9c590e8301900b34614d..150729a01f3fc4bde6befa5aeea682a87713dc6e 100644 (file)
@@ -48,6 +48,8 @@ struct samba_kdc_db_context {
        unsigned int my_krbtgt_number;
        struct ldb_dn *krbtgt_dn;
        struct samba_kdc_policy policy;
+       struct ldb_dn *fx_cookie_dn;
+       struct ldb_context *secrets_db;
 };
 
 struct samba_kdc_entry {