From 82fcd7941f5c54da2d994c8bd99dd8d86299a296 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 3 Sep 2008 15:30:17 +1000 Subject: [PATCH] Implement NETLOGON PAC verfication on the server-side This is implemented by means of a message to the KDC, to avoid having to link most of the KDC into netlogon. Andrew Bartlett --- source/auth/kerberos/kerberos_pac.c | 10 +- source/kdc/kdc.c | 112 +++++++++++++++++++ source/librpc/idl/irpc.idl | 17 +++ source/librpc/idl/krb5pac.idl | 2 +- source/rpc_server/netlogon/dcerpc_netlogon.c | 60 +++++----- source/samba4-skip | 1 - 6 files changed, 164 insertions(+), 38 deletions(-) diff --git a/source/auth/kerberos/kerberos_pac.c b/source/auth/kerberos/kerberos_pac.c index 9ebace32cb5b..2943e05b18e8 100644 --- a/source/auth/kerberos/kerberos_pac.c +++ b/source/auth/kerberos/kerberos_pac.c @@ -32,11 +32,11 @@ #include "auth/auth_sam_reply.h" #include "param/param.h" -static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, - DATA_BLOB pac_data, - struct PAC_SIGNATURE_DATA *sig, - krb5_context context, - const krb5_keyblock *keyblock) +krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, + DATA_BLOB pac_data, + struct PAC_SIGNATURE_DATA *sig, + krb5_context context, + const krb5_keyblock *keyblock) { krb5_error_code ret; krb5_crypto crypto; diff --git a/source/kdc/kdc.c b/source/kdc/kdc.c index dfd62c55a47d..5d7b48afe4be 100644 --- a/source/kdc/kdc.c +++ b/source/kdc/kdc.c @@ -33,9 +33,12 @@ #include "lib/messaging/irpc.h" #include "lib/stream/packet.h" #include "librpc/gen_ndr/samr.h" +#include "librpc/gen_ndr/ndr_irpc.h" +#include "librpc/gen_ndr/ndr_krb5pac.h" #include "lib/socket/netif.h" #include "param/param.h" #include "kdc/kdc.h" +#include "librpc/gen_ndr/ndr_misc.h" /* Disgusting hack to get a mem_ctx and lp_ctx into the hdb plugin, when @@ -555,6 +558,108 @@ static struct krb5plugin_windc_ftable windc_plugin_table = { }; +static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, + struct kdc_check_generic_kerberos *r) +{ + struct PAC_Validate pac_validate; + DATA_BLOB srv_sig; + struct PAC_SIGNATURE_DATA kdc_sig; + struct kdc_server *kdc = talloc_get_type(msg->private, 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); + + ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, + lp_iconv_convenience(kdc->task->lp_ctx), + &pac_validate, + (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return NT_STATUS_INVALID_PARAMETER; + } + +#if 0 + /* Windows does not check this */ + if (pac_validate.MessageType != 3) { + /* We don't implement any other message types - such as certificate validation - yet */ + return NT_STATUS_INVALID_PARAMETER; + } +#endif + if (pac_validate.ChecksumAndSignature.length != (pac_validate.ChecksumLength + pac_validate.SignatureLength) + || pac_validate.ChecksumAndSignature.length < pac_validate.ChecksumLength + || pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) { + return NT_STATUS_INVALID_PARAMETER; + } + + 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, + lp_realm(kdc->task->lp_ctx), + "krbtgt", lp_realm(kdc->task->lp_ctx), + NULL); + + if (ret != 0) { + return NT_STATUS_NO_MEMORY; + } + + ret = kdc->config->db[0]->hdb_fetch(kdc->smb_krb5_context->krb5_context, + kdc->config->db[0], + principal, + HDB_F_GET_KRBTGT | HDB_F_DECRYPT, + &ent); + + 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; + } + + 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); + + hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent); + krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal); + + if (ret != 0) { + return NT_STATUS_LOGON_FAILURE; + } + + return NT_STATUS_OK; +} + + + /* startup the kdc task */ @@ -656,6 +761,13 @@ static void kdc_task_init(struct task_server *task) return; } + status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, + kdc_check_generic_kerberos, kdc); + if (!NT_STATUS_IS_OK(status)) { + task_server_terminate(task, "nbtd failed to setup monitoring"); + return; + } + irpc_add_name(task->msg_ctx, "kdc_server"); } diff --git a/source/librpc/idl/irpc.idl b/source/librpc/idl/irpc.idl index 2c659aa78500..e3ea7e55e1a8 100644 --- a/source/librpc/idl/irpc.idl +++ b/source/librpc/idl/irpc.idl @@ -52,6 +52,9 @@ import "misc.idl", "security.idl", "nbt.idl"; [out,switch_is(level)] nbtd_info info ); + /* Send a GetDCName from the privilaged port (owned by nbtd), + * and await a reply */ + void nbtd_getdcname( [in] astring domainname, [in] astring ip_address, @@ -78,6 +81,20 @@ import "misc.idl", "security.idl", "nbt.idl"; [in] nbtd_proxy_wins_addr addrs[num_addrs] ); + /* + Generic Kerberos package call (on the NETLOGON pipe, as a SamLogon) + + The normal use for this call is to check the PAC signature in the KDC + + The KDC has the routines to check this, so it is easier to + proxy the request over by IRPC than set up the environment + */ + + void kdc_check_generic_kerberos( + [in] DATA_BLOB generic_request, + [out] DATA_BLOB generic_reply + ); + /****************************************************** management calls for the smb server ******************************************************/ diff --git a/source/librpc/idl/krb5pac.idl b/source/librpc/idl/krb5pac.idl index dcee280150db..bddba0416517 100644 --- a/source/librpc/idl/krb5pac.idl +++ b/source/librpc/idl/krb5pac.idl @@ -105,7 +105,7 @@ interface krb5pac typedef [public] struct { [value(NETLOGON_GENERIC_KRB5_PAC_VALIDATE)] uint32 MessageType; uint32 ChecksumLength; - uint32 SignatureType; + int32 SignatureType; uint32 SignatureLength; [flag(NDR_REMAINING)] DATA_BLOB ChecksumAndSignature; } PAC_Validate; diff --git a/source/rpc_server/netlogon/dcerpc_netlogon.c b/source/rpc_server/netlogon/dcerpc_netlogon.c index 5672d29cb285..36ac650b08a8 100644 --- a/source/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source/rpc_server/netlogon/dcerpc_netlogon.c @@ -34,6 +34,8 @@ #include "auth/gensec/schannel_state.h" #include "libcli/security/security.h" #include "param/param.h" +#include "lib/messaging/irpc.h" +#include "librpc/gen_ndr/ndr_irpc.h" struct server_pipe_state { struct netr_Credential client_challenge; @@ -496,41 +498,37 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal return NT_STATUS_INVALID_PARAMETER; } - if (strcmp(r->in.logon.generic->package_name.string, "Kerberos")) { - struct PAC_Validate pac_validate; - DATA_BLOB srv_sig; - struct PAC_SIGNATURE_DATA kdc_sig; - DATA_BLOB pac_validate_blob = data_blob_const(r->in.logon.generic->data, - r->in.logon.generic->length); - ndr_err = ndr_pull_struct_blob(&pac_validate_blob, mem_ctx, - lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), - &pac_validate, - (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return NT_STATUS_INVALID_PARAMETER; - } + if (strcmp(r->in.logon.generic->package_name.string, "Kerberos") == 0) { + NTSTATUS status; + struct server_id *kdc; + struct kdc_check_generic_kerberos check; + struct netr_GenericInfo2 *generic = talloc_zero(mem_ctx, struct netr_GenericInfo2); + NT_STATUS_HAVE_NO_MEMORY(generic); + r->out.authoritative = 1; + + /* TODO: Describe and deal with these flags */ + r->out.flags = 0; - if (pac_validate->MessageType != 3) { - /* We don't implement any other message types - such as certificate validation - yet */ - return NT_STATUS_INVALID_PARAMETER; + r->out.validation.generic = generic; + + kdc = irpc_servers_byname(dce_call->msg_ctx, mem_ctx, "kdc_server"); + if ((kdc == NULL) || (kdc[0].id == 0)) { + return NT_STATUS_NO_LOGON_SERVERS; } - if (pac_validate->ChecksumAndSignature.length != (pac_validate->ChecksumLength + pac_validate->SignatureLength) - || pac_validate->ChecksumAndSignature.length < pac_validate->ChecksumLength - || pac_validate->ChecksumAndSignature.length < pac_validate->SignatureLength ) { - return NT_STATUS_INVALID_PARAMETER; + check.in.generic_request = + data_blob_const(r->in.logon.generic->data, + r->in.logon.generic->length); + + status = irpc_call(dce_call->msg_ctx, kdc[0], + &ndr_table_irpc, NDR_KDC_CHECK_GENERIC_KERBEROS, + &check, mem_ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; } - - srv_sig = data_blob_const(pac_validate->ChecksumAndSignature.data, - pac_validate->ChecksumLength); - - kdc_sig.type = pac_validate->SignatureType; - kdc_sig.signature = data_blob_const(&pac_validate->ChecksumAndSignature.data[pac_validate->ChecksumLength], - pac_validate->SignatureLength); - check_pac_checksum(mem_ctx, srv_sig, &kdc_sig, - context, keyblock); - - + generic->length = check.out.generic_reply.length; + generic->data = check.out.generic_reply.data; + return NT_STATUS_OK; } /* Until we get an implemetnation of these other packages */ diff --git a/source/samba4-skip b/source/samba4-skip index 35b274f63f69..b1313adea0cf 100644 --- a/source/samba4-skip +++ b/source/samba4-skip @@ -41,7 +41,6 @@ ntvfs.cifs.raw.context ntvfs.cifs.raw.qfileinfo.ipc rpc.dssync rpc.samsync -rpc.pac # Not finished yet ldap.uptodatevector # Segfaults rpc.remact # Not provided by Samba 4 rpc.oxidresolve # Not provided by Samba 4 -- 2.34.1