s4-kdc Handle the case where we may be given a ticket from an RODC in db layer
authorAndrew Bartlett <abartlet@samba.org>
Tue, 28 Sep 2010 03:13:28 +0000 (13:13 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 28 Sep 2010 18:23:07 +0000 (04:23 +1000)
This includes rewriting the PAC if the original krbtgt isn't to be
trusted, and reading different entries from the DB for the krbtgt
depending on the krbtgt number.

Andrew Bartlett

source4/kdc/db-glue.c
source4/kdc/db-glue.h
source4/kdc/hdb-samba4.c
source4/kdc/kdc.c
source4/kdc/mit_samba.c
source4/kdc/wdc-samba4.c

index 2cda04bca8fcc143f57ca48d44a53a92a4616b3b..ecb160caf36b8c8346f8ae14152273f2a3828533 100644 (file)
@@ -1049,10 +1049,11 @@ static krb5_error_code samba_kdc_fetch_client(krb5_context context,
 }
 
 static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
-                                       struct samba_kdc_db_context *kdc_db_ctx,
-                                       TALLOC_CTX *mem_ctx,
-                                       krb5_const_principal principal,
-                                       hdb_entry_ex *entry_ex)
+                                             struct samba_kdc_db_context *kdc_db_ctx,
+                                             TALLOC_CTX *mem_ctx,
+                                             krb5_const_principal principal,
+                                             uint32_t krbtgt_number,
+                                             hdb_entry_ex *entry_ex)
 {
        struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
        krb5_error_code ret;
@@ -1070,7 +1071,7 @@ static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
 
        if (lpcfg_is_my_domain_or_realm(lp_ctx, principal->realm)
            && lpcfg_is_my_domain_or_realm(lp_ctx, principal->name.name_string.val[1])) {
-               /* us */
+               /* us, or someone quite like us */
                /* Cludge, cludge cludge.  If the realm part of krbtgt/realm,
                 * is in our db, then direct the caller at our primary
                 * krbtgt */
@@ -1078,18 +1079,35 @@ static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
                int lret;
                char *realm_fixed;
 
-               lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx,
-                                      &msg, realm_dn, LDB_SCOPE_SUBTREE,
-                                      krbtgt_attrs,
-                                      DSDB_SEARCH_SHOW_EXTENDED_DN,
-                                      "(&(objectClass=user)(samAccountName=krbtgt))");
+               if (krbtgt_number == kdc_db_ctx->my_krbtgt_number) {
+                       lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx,
+                                              &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
+                                              krbtgt_attrs, 0,
+                                              "(objectClass=user)");
+               } else {
+                       /* We need to look up an RODC krbtgt (perhaps
+                        * ours, if we are an RODC, perhaps another
+                        * RODC if we are a read-write DC */
+                       lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx,
+                                              &msg, realm_dn, LDB_SCOPE_SUBTREE,
+                                              krbtgt_attrs,
+                                              DSDB_SEARCH_SHOW_EXTENDED_DN,
+                                              "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=%u))", (unsigned)(krbtgt_number));
+               }
+
                if (lret == LDB_ERR_NO_SUCH_OBJECT) {
-                       krb5_warnx(context, "samba_kdc_fetch: could not find own KRBTGT in DB!");
-                       krb5_set_error_message(context, HDB_ERR_NOENTRY, "samba_kdc_fetch: could not find own KRBTGT in DB!");
+                       krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
+                                  (unsigned)(krbtgt_number));
+                       krb5_set_error_message(context, HDB_ERR_NOENTRY,
+                                              "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
+                                              (unsigned)(krbtgt_number));
                        return HDB_ERR_NOENTRY;
                } else if (lret != LDB_SUCCESS) {
-                       krb5_warnx(context, "samba_kdc_fetch: could not find own KRBTGT in DB: %s", ldb_errstring(kdc_db_ctx->samdb));
-                       krb5_set_error_message(context, HDB_ERR_NOENTRY, "samba_kdc_fetch: could not find own KRBTGT in DB: %s", ldb_errstring(kdc_db_ctx->samdb));
+                       krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
+                                  (unsigned)(krbtgt_number));
+                       krb5_set_error_message(context, HDB_ERR_NOENTRY,
+                                              "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
+                                              (unsigned)(krbtgt_number));
                        return HDB_ERR_NOENTRY;
                }
 
@@ -1281,11 +1299,24 @@ krb5_error_code samba_kdc_fetch(krb5_context context,
                                struct samba_kdc_db_context *kdc_db_ctx,
                                krb5_const_principal principal,
                                unsigned flags,
+                               unsigned kvno,
                                hdb_entry_ex *entry_ex)
 {
        krb5_error_code ret = HDB_ERR_NOENTRY;
-       TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
+       TALLOC_CTX *mem_ctx;
+       unsigned int krbtgt_number;
+       if (flags & HDB_F_KVNO_SPECIFIED) {
+               krbtgt_number = kvno >> 16;
+               if (kdc_db_ctx->rodc) {
+                       if (krbtgt_number != kdc_db_ctx->my_krbtgt_number) {
+                               return HDB_ERR_NOT_FOUND_HERE;
+                       }
+               }
+       } else {
+               krbtgt_number = kdc_db_ctx->my_krbtgt_number;
+       }
 
+       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!");
@@ -1298,7 +1329,7 @@ krb5_error_code samba_kdc_fetch(krb5_context context,
        }
        if (flags & HDB_F_GET_SERVER) {
                /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
-               ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, entry_ex);
+               ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, krbtgt_number, entry_ex);
                if (ret != HDB_ERR_NOENTRY) goto done;
 
                /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
@@ -1306,7 +1337,7 @@ krb5_error_code samba_kdc_fetch(krb5_context context,
                if (ret != HDB_ERR_NOENTRY) goto done;
        }
        if (flags & HDB_F_GET_KRBTGT) {
-               ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, entry_ex);
+               ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, krbtgt_number, entry_ex);
                if (ret != HDB_ERR_NOENTRY) goto done;
        }
 
index 5f9c39dfb686038e9e6e57d39fe81cf20814eb9c..9738fbc76949be24ad883c8bd1289488a173cb9c 100644 (file)
@@ -25,6 +25,7 @@ krb5_error_code samba_kdc_fetch(krb5_context context,
                                struct samba_kdc_db_context *kdc_db_ctx,
                                krb5_const_principal principal,
                                unsigned flags,
+                               unsigned kvno,
                                hdb_entry_ex *entry_ex);
 
 krb5_error_code samba_kdc_firstkey(krb5_context context,
index cbc00df0aef6ceba55da0a26d08b9ea15c40fc9c..53b1abee94e81a7fbae4ac0364bce9e7f97d0781 100644 (file)
@@ -83,16 +83,17 @@ static krb5_error_code hdb_samba4_remove(krb5_context context, HDB *db, krb5_con
 }
 
 static krb5_error_code hdb_samba4_fetch(krb5_context context, HDB *db,
-                                krb5_const_principal principal,
-                                unsigned flags,
-                                hdb_entry_ex *entry_ex)
+                                       krb5_const_principal principal,
+                                       unsigned flags,
+                                       unsigned kvno,
+                                       hdb_entry_ex *entry_ex)
 {
        struct samba_kdc_db_context *kdc_db_ctx;
 
        kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
                                           struct samba_kdc_db_context);
 
-       return samba_kdc_fetch(context, kdc_db_ctx, principal, flags, entry_ex);
+       return samba_kdc_fetch(context, kdc_db_ctx, principal, flags, kvno, entry_ex);
 }
 
 static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsigned flags,
index 5adb0709cfb7f636b98d7cf1d3b2bb85e4968736..4dd2113dff0f5addcb3d7ff09238cd201c04afd5 100644 (file)
@@ -632,6 +632,7 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
                                            kdc->config->db[0],
                                            principal,
                                            HDB_F_GET_KRBTGT | HDB_F_DECRYPT,
+                                           0,
                                            &ent);
 
        if (ret != 0) {
index 217f0983ae413a2701f9e59a240152dc09b2e624..14ad7be414d173fe008290deb9dbf2af47733c4f 100644 (file)
@@ -130,7 +130,7 @@ static int mit_samba_get_principal(struct mit_samba_context *ctx,
        }
 
        ret = samba_kdc_fetch(ctx->context, ctx->db_ctx,
-                             principal, flags, hentry);
+                             principal, flags, 0, hentry);
 
        krb5_free_principal(ctx->context, principal);
 
index 0ebc4e7c2b41a1320dad7d7a908c2c1fe4fd4952..89265946988365bcb4e3272c08552fcba7450df6 100644 (file)
@@ -60,7 +60,9 @@ static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
 static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
                                           const krb5_principal client_principal,
                                           struct hdb_entry_ex *client,
-                                          struct hdb_entry_ex *server, krb5_pac *pac)
+                                          struct hdb_entry_ex *server,
+                                          struct hdb_entry_ex *krbtgt,
+                                          krb5_pac *pac)
 {
        struct samba_kdc_entry *p = talloc_get_type(server->ctx, struct samba_kdc_entry);
        TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac context");
@@ -72,27 +74,37 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
                return ENOMEM;
        }
 
-       pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
-       if (!pac_blob) {
-               talloc_free(mem_ctx);
-               return ENOMEM;
-       }
-
        /* The user account may be set not to want the PAC */
        if (!samba_princ_needs_pac(server)) {
                talloc_free(mem_ctx);
                return EINVAL;
        }
 
-       nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
-                                             pac, pac_blob);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(0, ("Building PAC failed: %s\n",
-                         nt_errstr(nt_status)));
-               talloc_free(mem_ctx);
-               return EINVAL;
-       }
+       /* If the krbtgt was generated by an RODC, and we are not that
+        * RODC, then we need to regenerate the PAC - we can't trust
+        * it */
+       if (samba_krbtgt_was_untrusted_rodc(krbtgt)) {
+               nt_status = samba_kdc_get_pac_blob(mem_ctx, client, &pac_blob);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       talloc_free(mem_ctx);
+                       return EINVAL;
+               }
+       } else {
+               pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
+               if (!pac_blob) {
+                       talloc_free(mem_ctx);
+                       return ENOMEM;
+               }
 
+               nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
+                                                     pac, pac_blob);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       DEBUG(0, ("Building PAC failed: %s\n",
+                                 nt_errstr(nt_status)));
+                       talloc_free(mem_ctx);
+                       return EINVAL;
+               }
+       }
        /* We now completely regenerate this pac */
        krb5_pac_free(context, *pac);