From 60936dd2c4e82550e31e5f1b6d476d8b10bde687 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 29 Aug 2008 18:05:06 +1000 Subject: Start implementing the server-sde NETLOGON PAC verification. (This used to be commit 8741e8fee619cccd84f2f10e00426df1d4f34074) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 47 ++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 763e6a327e..5672d29cb2 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -488,7 +488,52 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal case NetlogonGenericInformation: { - /* Until we get enough information for an implemetnation */ + if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { + creds_arcfour_crypt(creds, + r->in.logon.generic->data, r->in.logon.generic->length); + } else { + /* Using DES to verify kerberos tickets makes no sense */ + 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 (pac_validate->MessageType != 3) { + /* We don't implement any other message types - such as certificate validation - yet */ + return NT_STATUS_INVALID_PARAMETER; + } + + 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); + + 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); + + + } + + /* Until we get an implemetnation of these other packages */ return NT_STATUS_INVALID_PARAMETER; } default: -- cgit From ef57d9587bdd9cf094fb832bb9a96f6cd906835c Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 3 Sep 2008 14:19:16 +1000 Subject: Test a few more error cases in RPC-PAC (This used to be commit 50502b3b8faf89cf5ad396102f4fe80eaa213908) --- source4/torture/rpc/remote_pac.c | 181 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/torture/rpc/remote_pac.c b/source4/torture/rpc/remote_pac.c index 58c8ba0ee0..6419e40014 100644 --- a/source4/torture/rpc/remote_pac.c +++ b/source4/torture/rpc/remote_pac.c @@ -68,6 +68,8 @@ static bool test_PACVerify(struct torture_context *tctx, TALLOC_CTX *tmp_ctx = talloc_new(tctx); + int i; + torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed"); if (!test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, @@ -157,6 +159,9 @@ static bool test_PACVerify(struct torture_context *tctx, torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption"); creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length); + generic.length = pac_wrapped.length; + generic.data = pac_wrapped.data; + /* Validate it over the netlogon pipe */ generic.identity_info.parameter_control = 0; @@ -167,8 +172,6 @@ static bool test_PACVerify(struct torture_context *tctx, generic.identity_info.workstation.string = TEST_MACHINE_NAME; generic.package_name.string = "Kerberos"; - generic.length = pac_wrapped.length; - generic.data = pac_wrapped.data; ZERO_STRUCT(auth2); creds_client_authenticator(creds, &auth); @@ -184,9 +187,183 @@ static bool test_PACVerify(struct torture_context *tctx, torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed"); + /* This will break the signature nicely (even in the crypto wrapping), check we get a logon failure */ + generic.data[generic.length-1]++; + + ZERO_STRUCT(auth2); + creds_client_authenticator(creds, &auth); + r.in.credential = &auth; + r.in.return_authenticator = &auth2; + r.in.logon_level = NetlogonGenericInformation; + r.in.logon.generic = &generic; + r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.validation_level = NetlogonValidationGenericInfo2; + + status = dcerpc_netr_LogonSamLogon(p, tctx, &r); + + torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed"); + + torture_assert(tctx, creds_client_check(creds, &r.out.return_authenticator->cred), + "Credential chaining failed"); + + /* This will break message type, check that however we still get NT_STATUS_OK */ + for (i=0; i < 256; i++) { + pac_wrapped_struct.MessageType = i; + pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length; + pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type; + pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length; + pac_wrapped_struct.ChecksumAndSignature = payload + = data_blob_talloc(tmp_ctx, NULL, + pac_wrapped_struct.ChecksumLength + + pac_wrapped_struct.SignatureLength); + memcpy(&payload.data[0], + session_info->server_info->pac_srv_sig.signature.data, + pac_wrapped_struct.ChecksumLength); + memcpy(&payload.data[pac_wrapped_struct.ChecksumLength], + session_info->server_info->pac_kdc_sig.signature.data, + pac_wrapped_struct.SignatureLength); + + ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct, + (ndr_push_flags_fn_t)ndr_push_PAC_Validate); + torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed"); + + torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption"); + creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length); + + generic.length = pac_wrapped.length; + generic.data = pac_wrapped.data; + + ZERO_STRUCT(auth2); + creds_client_authenticator(creds, &auth); + r.in.credential = &auth; + r.in.return_authenticator = &auth2; + r.in.logon_level = NetlogonGenericInformation; + r.in.logon.generic = &generic; + r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.validation_level = NetlogonValidationGenericInfo2; + + status = dcerpc_netr_LogonSamLogon(p, tctx, &r); + + torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed"); + + torture_assert(tctx, creds_client_check(creds, &r.out.return_authenticator->cred), + "Credential chaining failed"); + } + + /* This will break the parsing nicely (even in the crypto wrapping), check we get INVALID_PARAMETER */ + generic.length--; + + ZERO_STRUCT(auth2); + creds_client_authenticator(creds, &auth); + r.in.credential = &auth; + r.in.return_authenticator = &auth2; + r.in.logon_level = NetlogonGenericInformation; + r.in.logon.generic = &generic; + r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.validation_level = NetlogonValidationGenericInfo2; + + status = dcerpc_netr_LogonSamLogon(p, tctx, &r); + + torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed"); + + torture_assert(tctx, creds_client_check(creds, &r.out.return_authenticator->cred), + "Credential chaining failed"); + + pac_wrapped_struct.MessageType = 0x3; + pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length; + pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type; + + /* Break the SignatureType */ + pac_wrapped_struct.SignatureType++; + + pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length; + pac_wrapped_struct.ChecksumAndSignature = payload + = data_blob_talloc(tmp_ctx, NULL, + pac_wrapped_struct.ChecksumLength + + pac_wrapped_struct.SignatureLength); + memcpy(&payload.data[0], + session_info->server_info->pac_srv_sig.signature.data, + pac_wrapped_struct.ChecksumLength); + memcpy(&payload.data[pac_wrapped_struct.ChecksumLength], + session_info->server_info->pac_kdc_sig.signature.data, + pac_wrapped_struct.SignatureLength); + + ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct, + (ndr_push_flags_fn_t)ndr_push_PAC_Validate); + torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed"); + + torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption"); + creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length); + + generic.length = pac_wrapped.length; + generic.data = pac_wrapped.data; + + ZERO_STRUCT(auth2); + creds_client_authenticator(creds, &auth); + r.in.credential = &auth; + r.in.return_authenticator = &auth2; + r.in.logon_level = NetlogonGenericInformation; + r.in.logon.generic = &generic; + r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.validation_level = NetlogonValidationGenericInfo2; + + status = dcerpc_netr_LogonSamLogon(p, tctx, &r); + + torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed"); + torture_assert(tctx, creds_client_check(creds, &r.out.return_authenticator->cred), "Credential chaining failed"); + + pac_wrapped_struct.MessageType = 0x3; + pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length; + pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type; + pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length; + + pac_wrapped_struct.ChecksumAndSignature = payload + = data_blob_talloc(tmp_ctx, NULL, + pac_wrapped_struct.ChecksumLength + + pac_wrapped_struct.SignatureLength); + memcpy(&payload.data[0], + session_info->server_info->pac_srv_sig.signature.data, + pac_wrapped_struct.ChecksumLength); + memcpy(&payload.data[pac_wrapped_struct.ChecksumLength], + session_info->server_info->pac_kdc_sig.signature.data, + pac_wrapped_struct.SignatureLength); + + /* Break the signature length */ + pac_wrapped_struct.SignatureLength++; + + ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct, + (ndr_push_flags_fn_t)ndr_push_PAC_Validate); + torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed"); + + torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption"); + creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length); + + generic.length = pac_wrapped.length; + generic.data = pac_wrapped.data; + + ZERO_STRUCT(auth2); + creds_client_authenticator(creds, &auth); + r.in.credential = &auth; + r.in.return_authenticator = &auth2; + r.in.logon_level = NetlogonGenericInformation; + r.in.logon.generic = &generic; + r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + r.in.computer_name = cli_credentials_get_workstation(credentials); + r.in.validation_level = NetlogonValidationGenericInfo2; + + status = dcerpc_netr_LogonSamLogon(p, tctx, &r); + + torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed"); + + torture_assert(tctx, creds_client_check(creds, &r.out.return_authenticator->cred), + "Credential chaining failed"); return true; } -- cgit From baf0b360812dc8532f9420e224bf3ee3a51fb04a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 3 Sep 2008 14:20:30 +1000 Subject: Merge krb5_cksumtype_to_enctype from Heimdal svn -r 23719 (This used to be commit cc1df3c002e6af25add3c8ae20e7efc2ab6f2fa8) --- source4/heimdal/lib/krb5/crypto.c | 102 ++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 32 deletions(-) (limited to 'source4') diff --git a/source4/heimdal/lib/krb5/crypto.c b/source4/heimdal/lib/krb5/crypto.c index 6675647736..9379c6fdf1 100644 --- a/source4/heimdal/lib/krb5/crypto.c +++ b/source4/heimdal/lib/krb5/crypto.c @@ -2677,37 +2677,6 @@ krb5_enctype_to_keytype(krb5_context context, return 0; } -krb5_error_code KRB5_LIB_FUNCTION -krb5_keytype_to_enctypes (krb5_context context, - krb5_keytype keytype, - unsigned *len, - krb5_enctype **val) -{ - int i; - unsigned n = 0; - krb5_enctype *ret; - - for (i = num_etypes - 1; i >= 0; --i) { - if (etypes[i]->keytype->type == keytype - && !(etypes[i]->flags & F_PSEUDO)) - ++n; - } - ret = malloc(n * sizeof(*ret)); - if (ret == NULL && n != 0) { - krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); - return ENOMEM; - } - n = 0; - for (i = num_etypes - 1; i >= 0; --i) { - if (etypes[i]->keytype->type == keytype - && !(etypes[i]->flags & F_PSEUDO)) - ret[n++] = etypes[i]->type; - } - *len = n; - *val = ret; - return 0; -} - krb5_error_code KRB5_LIB_FUNCTION krb5_enctype_valid(krb5_context context, krb5_enctype etype) @@ -2728,6 +2697,44 @@ krb5_enctype_valid(krb5_context context, return 0; } +/** + * Return the coresponding encryption type for a checksum type. + * + * @param context Kerberos context + * @param ctype The checksum type to get the result enctype for + * @param etype The returned encryption, when the matching etype is + * not found, etype is set to ETYPE_NULL. + * + * @return Return an error code for an failure or 0 on success. + * @ingroup krb5_crypto + */ + + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cksumtype_to_enctype(krb5_context context, + krb5_cksumtype ctype, + krb5_enctype *etype) +{ + int i; + + *etype = ETYPE_NULL; + + for(i = 0; i < num_etypes; i++) { + if(etypes[i]->keyed_checksum && + etypes[i]->keyed_checksum->type == ctype) + { + *etype = etypes[i]->type; + return 0; + } + } + + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + "ckecksum type %d not supported", + (int)ctype); + return KRB5_PROG_SUMTYPE_NOSUPP; +} + + krb5_error_code KRB5_LIB_FUNCTION krb5_cksumtype_valid(krb5_context context, krb5_cksumtype ctype) @@ -3491,7 +3498,6 @@ krb5_decrypt_iov_ivec(krb5_context context, return 0; } - size_t KRB5_LIB_FUNCTION krb5_crypto_length(krb5_context context, krb5_crypto crypto, @@ -4562,4 +4568,36 @@ krb5_string_to_keytype(krb5_context context, "key type %s not supported", string); return KRB5_PROG_KEYTYPE_NOSUPP; } + +krb5_error_code KRB5_LIB_FUNCTION +krb5_keytype_to_enctypes (krb5_context context, + krb5_keytype keytype, + unsigned *len, + krb5_enctype **val) +{ + int i; + unsigned n = 0; + krb5_enctype *ret; + + for (i = num_etypes - 1; i >= 0; --i) { + if (etypes[i]->keytype->type == keytype + && !(etypes[i]->flags & F_PSEUDO)) + ++n; + } + ret = malloc(n * sizeof(*ret)); + if (ret == NULL && n != 0) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + n = 0; + for (i = num_etypes - 1; i >= 0; --i) { + if (etypes[i]->keytype->type == keytype + && !(etypes[i]->flags & F_PSEUDO)) + ret[n++] = etypes[i]->type; + } + *len = n; + *val = ret; + return 0; +} + #endif -- cgit From a35263e1ab81cac7855158012157769e3e9000f7 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 3 Sep 2008 15:30:17 +1000 Subject: 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 (This used to be commit 82fcd7941f5c54da2d994c8bd99dd8d86299a296) --- source4/auth/kerberos/kerberos_pac.c | 10 +-- source4/kdc/kdc.c | 112 ++++++++++++++++++++++++++ source4/librpc/idl/irpc.idl | 17 ++++ source4/librpc/idl/krb5pac.idl | 2 +- source4/rpc_server/netlogon/dcerpc_netlogon.c | 60 +++++++------- source4/samba4-skip | 1 - 6 files changed, 164 insertions(+), 38 deletions(-) (limited to 'source4') diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c index 9ebace32cb..2943e05b18 100644 --- a/source4/auth/kerberos/kerberos_pac.c +++ b/source4/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/source4/kdc/kdc.c b/source4/kdc/kdc.c index dfd62c55a4..5d7b48afe4 100644 --- a/source4/kdc/kdc.c +++ b/source4/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/source4/librpc/idl/irpc.idl b/source4/librpc/idl/irpc.idl index 2c659aa785..e3ea7e55e1 100644 --- a/source4/librpc/idl/irpc.idl +++ b/source4/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/source4/librpc/idl/krb5pac.idl b/source4/librpc/idl/krb5pac.idl index dcee280150..bddba04165 100644 --- a/source4/librpc/idl/krb5pac.idl +++ b/source4/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/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 5672d29cb2..36ac650b08 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/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/source4/samba4-skip b/source4/samba4-skip index 35b274f63f..b1313adea0 100644 --- a/source4/samba4-skip +++ b/source4/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 -- cgit