summaryrefslogtreecommitdiff
path: root/source4/kdc
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2012-01-11 18:06:55 +1100
committerAndrew Bartlett <abartlet@samba.org>2012-01-12 18:02:54 +1100
commit49f8113fabd2603b45439404c91d350b4d6eaeac (patch)
treeace3a19fcb94bb5ab6396f1be30fb2af7bec8817 /source4/kdc
parentd0bb8b8a15c76c739062e7a78c013b54729dc5ab (diff)
downloadsamba-49f8113fabd2603b45439404c91d350b4d6eaeac.tar.gz
samba-49f8113fabd2603b45439404c91d350b4d6eaeac.tar.bz2
samba-49f8113fabd2603b45439404c91d350b4d6eaeac.zip
s4-kdc Do the KDC PAC checksum validation in the Samba plugin
Here we can fetch the right key, and check if the PAC is likely to be signed by a key that we know. We cannot check the KDC signature on incoming trusts. Andrew Bartlett
Diffstat (limited to 'source4/kdc')
-rw-r--r--source4/kdc/kdc.c29
-rw-r--r--source4/kdc/mit_samba.c5
-rw-r--r--source4/kdc/pac-glue.c114
-rw-r--r--source4/kdc/pac-glue.h10
-rw-r--r--source4/kdc/wdc-samba4.c36
-rw-r--r--source4/kdc/wscript_build2
6 files changed, 152 insertions, 44 deletions
diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c
index e91b8a9b9f..d1ce527b24 100644
--- a/source4/kdc/kdc.c
+++ b/source4/kdc/kdc.c
@@ -32,6 +32,7 @@
#include "lib/socket/netif.h"
#include "param/param.h"
#include "kdc/kdc-glue.h"
+#include "kdc/pac-glue.h"
#include "dsdb/samdb/samdb.h"
#include "auth/session.h"
@@ -777,7 +778,6 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_c
return NT_STATUS_OK;
}
-
static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
struct kdc_check_generic_kerberos *r)
{
@@ -786,12 +786,9 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
struct PAC_SIGNATURE_DATA kdc_sig;
struct kdc_server *kdc = talloc_get_type(msg->private_data, struct kdc_server);
enum ndr_err_code ndr_err;
- krb5_enctype etype;
int ret;
hdb_entry_ex ent;
krb5_principal principal;
- krb5_keyblock keyblock;
- Key *key;
/* There is no reply to this request */
r->out.generic_reply = data_blob(NULL, 0);
@@ -816,16 +813,6 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data,
pac_validate.ChecksumLength);
- if (pac_validate.SignatureType == CKSUMTYPE_HMAC_MD5) {
- etype = ETYPE_ARCFOUR_HMAC_MD5;
- } else {
- ret = krb5_cksumtype_to_enctype(kdc->smb_krb5_context->krb5_context, pac_validate.SignatureType,
- &etype);
- if (ret != 0) {
- return NT_STATUS_LOGON_FAILURE;
- }
- }
-
ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal,
lpcfg_realm(kdc->task->lp_ctx),
"krbtgt", lpcfg_realm(kdc->task->lp_ctx),
@@ -849,21 +836,11 @@ static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
return NT_STATUS_LOGON_FAILURE;
}
- ret = hdb_enctype2key(kdc->smb_krb5_context->krb5_context, &ent.entry, etype, &key);
-
- if (ret != 0) {
- hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
- krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
- return NT_STATUS_LOGON_FAILURE;
- }
-
- keyblock = key->key;
-
kdc_sig.type = pac_validate.SignatureType;
kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
pac_validate.SignatureLength);
- ret = check_pac_checksum(msg, srv_sig, &kdc_sig,
- kdc->smb_krb5_context->krb5_context, &keyblock);
+
+ ret = kdc_check_pac(kdc->smb_krb5_context->krb5_context, srv_sig, &kdc_sig, &ent);
hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c
index 06ee46eac0..f56e6796d0 100644
--- a/source4/kdc/mit_samba.c
+++ b/source4/kdc/mit_samba.c
@@ -254,8 +254,11 @@ static int mit_samba_update_pac_data(struct mit_samba_context *ctx,
goto done;
}
+ /* TODO: An implementation-specific decision will need to be
+ * made as to when to check the KDC pac signature, and how to
+ * untrust untrusted RODCs */
nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context,
- pac, logon_blob);
+ pac, logon_blob, NULL, NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("Building PAC failed: %s\n",
nt_errstr(nt_status)));
diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c
index 5718452cc0..3983d7b201 100644
--- a/source4/kdc/pac-glue.c
+++ b/source4/kdc/pac-glue.c
@@ -30,6 +30,8 @@
#include "kdc/pac-glue.h"
#include "param/param.h"
#include "librpc/gen_ndr/ndr_krb5pac.h"
+#include "libcli/security/security.h"
+#include "dsdb/samdb/samdb.h"
static
NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
@@ -143,22 +145,74 @@ bool samba_princ_needs_pac(struct hdb_entry_ex *princ)
return true;
}
-/* Was the krbtgt an RODC (and we are not) */
-bool samba_krbtgt_was_untrusted_rodc(struct hdb_entry_ex *princ)
+/* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
+int samba_krbtgt_is_in_db(struct hdb_entry_ex *princ, bool *is_in_db, bool *is_untrusted)
{
-
+ NTSTATUS status;
struct samba_kdc_entry *p = talloc_get_type(princ->ctx, struct samba_kdc_entry);
- int rodc_krbtgt_number;
+ int rodc_krbtgt_number, trust_direction;
+ uint32_t rid;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ if (!mem_ctx) {
+ return ENOMEM;
+ }
+
+ trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
+
+ if (trust_direction != 0) {
+ /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
+
+ This is exactly where we should flag for SID
+ validation when we do inter-foreest trusts
+ */
+ talloc_free(mem_ctx);
+ *is_untrusted = false;
+ *is_in_db = false;
+ return 0;
+ }
+
+ /* The lack of password controls etc applies to krbtgt by
+ * virtue of being that particular RID */
+ status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, p->msg, "objectSid"), NULL, &rid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return EINVAL;
+ }
- /* Determine if this was printed by an RODC */
rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1);
- if (rodc_krbtgt_number == -1) {
- return false;
- } else if (rodc_krbtgt_number != p->kdc_db_ctx->my_krbtgt_number) {
- return true;
+
+ if (p->kdc_db_ctx->my_krbtgt_number == 0) {
+ if (rid == DOMAIN_RID_KRBTGT) {
+ *is_untrusted = false;
+ *is_in_db = true;
+ talloc_free(mem_ctx);
+ return 0;
+ } else if (rodc_krbtgt_number != -1) {
+ *is_in_db = true;
+ *is_untrusted = true;
+ talloc_free(mem_ctx);
+ return 0;
+ }
+ } else if ((rid != DOMAIN_RID_KRBTGT) && (rodc_krbtgt_number == p->kdc_db_ctx->my_krbtgt_number)) {
+ talloc_free(mem_ctx);
+ *is_untrusted = false;
+ *is_in_db = true;
+ return 0;
+ } else if (rid == DOMAIN_RID_KRBTGT) {
+ /* krbtgt viewed from an RODC */
+ talloc_free(mem_ctx);
+ *is_untrusted = false;
+ *is_in_db = false;
+ return 0;
}
- return false;
+ /* Another RODC */
+ talloc_free(mem_ctx);
+ *is_untrusted = true;
+ *is_in_db = false;
+ return 0;
}
NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
@@ -208,14 +262,16 @@ NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
krb5_context context,
- const krb5_pac pac, DATA_BLOB *pac_blob)
+ const krb5_pac pac, DATA_BLOB *pac_blob,
+ struct PAC_SIGNATURE_DATA *pac_srv_sig,
+ struct PAC_SIGNATURE_DATA *pac_kdc_sig)
{
struct auth_user_info_dc *user_info_dc;
krb5_error_code ret;
NTSTATUS nt_status;
ret = kerberos_pac_to_user_info_dc(mem_ctx, pac,
- context, &user_info_dc, NULL, NULL);
+ context, &user_info_dc, pac_srv_sig, pac_kdc_sig);
if (ret) {
return NT_STATUS_UNSUCCESSFUL;
}
@@ -405,3 +461,37 @@ NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
return nt_status;
}
+int kdc_check_pac(krb5_context context,
+ DATA_BLOB srv_sig,
+ struct PAC_SIGNATURE_DATA *kdc_sig,
+ hdb_entry_ex *ent)
+{
+ krb5_enctype etype;
+ int ret;
+ krb5_keyblock keyblock;
+ Key *key;
+ if (kdc_sig->type == CKSUMTYPE_HMAC_MD5) {
+ etype = ETYPE_ARCFOUR_HMAC_MD5;
+ } else {
+ ret = krb5_cksumtype_to_enctype(context,
+ kdc_sig->type,
+ &etype);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = hdb_enctype2key(context, &ent->entry, etype, &key);
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ keyblock = key->key;
+
+ return check_pac_checksum(NULL, srv_sig, kdc_sig,
+ context, &keyblock);
+}
+
+
+
diff --git a/source4/kdc/pac-glue.h b/source4/kdc/pac-glue.h
index 66c20cdc1e..0e1cdcd2f2 100644
--- a/source4/kdc/pac-glue.h
+++ b/source4/kdc/pac-glue.h
@@ -28,7 +28,7 @@ krb5_error_code samba_make_krb5_pac(krb5_context context,
bool samba_princ_needs_pac(struct hdb_entry_ex *princ);
-bool samba_krbtgt_was_untrusted_rodc(struct hdb_entry_ex *princ);
+int samba_krbtgt_is_in_db(struct hdb_entry_ex *princ, bool *is_in_db, bool *is_untrusted);
NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
struct hdb_entry_ex *client,
@@ -36,7 +36,9 @@ NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
krb5_context context,
- const krb5_pac pac, DATA_BLOB *pac_blob);
+ const krb5_pac pac, DATA_BLOB *pac_blob,
+ struct PAC_SIGNATURE_DATA *pac_srv_sig,
+ struct PAC_SIGNATURE_DATA *pac_kdc_sig);
NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx,
krb5_context context,
@@ -53,3 +55,7 @@ NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
const char *client_name,
const char *workstation,
bool password_change);
+int kdc_check_pac(krb5_context krb5_context,
+ DATA_BLOB server_sig,
+ struct PAC_SIGNATURE_DATA *kdc_sig,
+ hdb_entry_ex *ent);
diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c
index 99ad96a6b5..70e849ccb7 100644
--- a/source4/kdc/wdc-samba4.c
+++ b/source4/kdc/wdc-samba4.c
@@ -68,6 +68,9 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
DATA_BLOB *deleg_blob = NULL;
krb5_error_code ret;
NTSTATUS nt_status;
+ struct PAC_SIGNATURE_DATA *pac_srv_sig;
+ struct PAC_SIGNATURE_DATA *pac_kdc_sig;
+ bool is_in_db, is_untrusted;
if (!mem_ctx) {
return ENOMEM;
@@ -82,7 +85,13 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
/* 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)) {
+ ret = samba_krbtgt_is_in_db(krbtgt, &is_in_db, &is_untrusted);
+ if (ret != 0) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ if (is_untrusted) {
if (client == NULL) {
return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
}
@@ -98,14 +107,37 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
return ENOMEM;
}
+ pac_srv_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA);
+ if (!pac_srv_sig) {
+ talloc_free(mem_ctx);
+ return ENOMEM;
+ }
+
+ pac_kdc_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA);
+ if (!pac_kdc_sig) {
+ talloc_free(mem_ctx);
+ return ENOMEM;
+ }
+
nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
- *pac, pac_blob);
+ *pac, pac_blob,
+ pac_srv_sig, pac_kdc_sig);
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 (is_in_db) {
+ /* Now check the KDC signature, fetching the correct key based on the enc type */
+ ret = kdc_check_pac(context, pac_srv_sig->signature, pac_kdc_sig, krbtgt);
+ if (ret != 0) {
+ DEBUG(1, ("PAC KDC signature failed to verify\n"));
+ talloc_free(mem_ctx);
+ return ret;
+ }
+ }
}
if (delegated_proxy_principal) {
diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build
index 5b2ba28793..22eee12c8b 100644
--- a/source4/kdc/wscript_build
+++ b/source4/kdc/wscript_build
@@ -4,7 +4,7 @@ bld.SAMBA_MODULE('service_kdc',
source='kdc.c kpasswdd.c proxy.c',
subsystem='service',
init_function='server_service_kdc_init',
- deps='kdc HDB_SAMBA4 WDC_SAMBA4 samba-hostconfig LIBTSOCKET LIBSAMBA_TSOCKET com_err samba_server_gensec',
+ deps='kdc HDB_SAMBA4 WDC_SAMBA4 samba-hostconfig LIBTSOCKET LIBSAMBA_TSOCKET com_err samba_server_gensec PAC_GLUE',
internal_module=False,
)