diff options
-rw-r--r-- | source4/auth/gensec/gensec_gssapi.c | 6 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_krb5.c | 6 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos.h | 22 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_pac.c | 259 | ||||
-rw-r--r-- | source4/kdc/pac-glue.c | 2 | ||||
-rw-r--r-- | source4/torture/auth/pac.c | 56 |
6 files changed, 219 insertions, 132 deletions
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 0a98b69f82..b6fda0402f 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -795,9 +795,9 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi gss_release_buffer(&min_stat, &pac); /* decode and verify the pac */ - nt_status = kerberos_decode_pac(mem_ctx, &logon_info, pac_blob, - gensec_gssapi_state->smb_krb5_context, - NULL, keyblock); + nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob, + gensec_gssapi_state->smb_krb5_context, + NULL, keyblock); if (NT_STATUS_IS_OK(nt_status)) { union netr_Validation validation; diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index 76f9171713..2568f11006 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -449,9 +449,9 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security account_name = principal; /* decode and verify the pac */ - nt_status = kerberos_decode_pac(gensec_krb5_state, &logon_info, gensec_krb5_state->pac, - gensec_krb5_state->smb_krb5_context, - NULL, gensec_krb5_state->keyblock); + nt_status = kerberos_pac_logon_info(gensec_krb5_state, &logon_info, gensec_krb5_state->pac, + gensec_krb5_state->smb_krb5_context, + NULL, gensec_krb5_state->keyblock); /* IF we have the PAC - otherwise we need to get this * data from elsewere - local ldb, or (TODO) lookup of some diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h index dcafea3c0c..0f1b0779b2 100644 --- a/source4/auth/kerberos/kerberos.h +++ b/source4/auth/kerberos/kerberos.h @@ -127,17 +127,29 @@ NTSTATUS create_memory_keytab(TALLOC_CTX *parent_ctx, struct smb_krb5_context *smb_krb5_context, krb5_keytab *keytab); NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, - struct PAC_LOGON_INFO **logon_info_out, + struct PAC_DATA **pac_data_out, DATA_BLOB blob, struct smb_krb5_context *smb_krb5_context, - krb5_keyblock *service_keyblock, - krb5_keyblock *krbtgt_keyblock); - -krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock); +NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx, + struct PAC_LOGON_INFO **logon_info, + DATA_BLOB blob, + struct smb_krb5_context *smb_krb5_context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock); +krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx, struct auth_serversupplied_info *server_info, krb5_context context, krb5_keyblock *krbtgt_keyblock, krb5_keyblock *server_keyblock, DATA_BLOB *pac); + +krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + struct PAC_DATA *pac_data, + krb5_context context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock, + DATA_BLOB *pac); #endif /* HAVE_KRB5 */ diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c index f561bdfe76..83679972d9 100644 --- a/source4/auth/kerberos/kerberos_pac.c +++ b/source4/auth/kerberos/kerberos_pac.c @@ -78,7 +78,7 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, } NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, - struct PAC_LOGON_INFO **logon_info_out, + struct PAC_DATA **pac_data_out, DATA_BLOB blob, struct smb_krb5_context *smb_krb5_context, krb5_keyblock *krbtgt_keyblock, @@ -90,46 +90,50 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, struct PAC_SIGNATURE_DATA kdc_sig; struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL; struct PAC_LOGON_INFO *logon_info = NULL; - struct PAC_DATA pac_data; + struct PAC_DATA *pac_data; + DATA_BLOB modified_pac_blob = data_blob_talloc(mem_ctx, blob.data, blob.length); int i; - /* file_save("tmp_pac_data.dat",blob.data,blob.length); */ + pac_data = talloc(mem_ctx, struct PAC_DATA); + if (!pac_data) { + return NT_STATUS_NO_MEMORY; + } - status = ndr_pull_struct_blob(&blob, mem_ctx, &pac_data, - (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); + status = ndr_pull_struct_blob(&blob, mem_ctx, pac_data, + (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("can't parse the PAC\n")); return status; } - if (pac_data.num_buffers < 3) { + if (pac_data->num_buffers < 3) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0,("less than 3 PAC buffers\n")); return NT_STATUS_FOOBAR; } - for (i=0; i < pac_data.num_buffers; i++) { - switch (pac_data.buffers[i].type) { + for (i=0; i < pac_data->num_buffers; i++) { + switch (pac_data->buffers[i].type) { case PAC_TYPE_LOGON_INFO: - if (!pac_data.buffers[i].info) { + if (!pac_data->buffers[i].info) { break; } - logon_info = pac_data.buffers[i].info->logon_info.info; + logon_info = pac_data->buffers[i].info->logon_info.info; break; case PAC_TYPE_SRV_CHECKSUM: - if (!pac_data.buffers[i].info) { + if (!pac_data->buffers[i].info) { break; } - srv_sig_ptr = &pac_data.buffers[i].info->srv_cksum; - srv_sig = pac_data.buffers[i].info->srv_cksum; + srv_sig_ptr = &pac_data->buffers[i].info->srv_cksum; + srv_sig = pac_data->buffers[i].info->srv_cksum; break; case PAC_TYPE_KDC_CHECKSUM: - if (!pac_data.buffers[i].info) { + if (!pac_data->buffers[i].info) { break; } - kdc_sig_ptr = &pac_data.buffers[i].info->kdc_cksum; - kdc_sig = pac_data.buffers[i].info->kdc_cksum; + kdc_sig_ptr = &pac_data->buffers[i].info->kdc_cksum; + kdc_sig = pac_data->buffers[i].info->kdc_cksum; break; case PAC_TYPE_LOGON_NAME: break; @@ -181,16 +185,56 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, } } +#if 0 + if (strcasecmp(logon_info->info3.base.account_name.string, + "Administrator")== 0) { + file_save("tmp_pac_data-admin.dat",blob.data,blob.length); + } +#endif + DEBUG(0,("account_name: %s [%s]\n", logon_info->info3.base.account_name.string, logon_info->info3.base.full_name.string)); - *logon_info_out = logon_info; + *pac_data_out = pac_data; return status; } + NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx, + struct PAC_LOGON_INFO **logon_info, + DATA_BLOB blob, + struct smb_krb5_context *smb_krb5_context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock) +{ + NTSTATUS nt_status; + struct PAC_DATA *pac_data; + int i; + + nt_status = kerberos_decode_pac(mem_ctx, &pac_data, + blob, + smb_krb5_context, + krbtgt_keyblock, + service_keyblock); + if (NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + *logon_info = NULL; + for (i=0; i < pac_data->num_buffers; i++) { + if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) { + continue; + } + *logon_info = pac_data->buffers[i].info->logon_info.info; + } + if (!*logon_info) { + return NT_STATUS_INVALID_PARAMETER; + } + return NT_STATUS_OK; +} + static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, - DATA_BLOB pac_data, + DATA_BLOB *pac_data, struct PAC_SIGNATURE_DATA *sig, krb5_context context, krb5_keyblock *keyblock) @@ -205,15 +249,16 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, 0, &crypto); if (ret) { - DEBUG(0,("krb5_crypto_init() failed\n")); + DEBUG(0,("krb5_crypto_init() failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); return ret; } ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0, - pac_data.data, - pac_data.length, + pac_data->data, + pac_data->length, &cksum); if (ret) { DEBUG(2, ("PAC Verification failed: %s\n", @@ -235,6 +280,107 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, } krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + struct PAC_DATA *pac_data, + krb5_context context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock, + DATA_BLOB *pac) +{ + NTSTATUS nt_status; + krb5_error_code ret; + DATA_BLOB zero_blob = data_blob(NULL, 0); + DATA_BLOB tmp_blob = data_blob(NULL, 0); + DATA_BLOB service_checksum_blob; + struct PAC_SIGNATURE_DATA *kdc_checksum = NULL; + struct PAC_SIGNATURE_DATA *srv_checksum = NULL; + int i; + + /* First, just get the keytypes filled in (and lengths right, eventually) */ + for (i=0; i < pac_data->num_buffers; i++) { + if (pac_data->buffers[i].type != PAC_TYPE_KDC_CHECKSUM) { + continue; + } + kdc_checksum = &pac_data->buffers[i].info->kdc_cksum, + ret = make_pac_checksum(mem_ctx, &zero_blob, + kdc_checksum, + context, krbtgt_keyblock); + if (ret) { + DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + talloc_free(pac_data); + return ret; + } + } + + for (i=0; i < pac_data->num_buffers; i++) { + if (pac_data->buffers[i].type != PAC_TYPE_SRV_CHECKSUM) { + continue; + } + srv_checksum = &pac_data->buffers[i].info->srv_cksum; + ret = make_pac_checksum(mem_ctx, &zero_blob, + srv_checksum, + context, service_keyblock); + if (ret) { + DEBUG(2, ("making service PAC checksum failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + talloc_free(pac_data); + return ret; + } + } + + if (!kdc_checksum) { + DEBUG(2, ("Invalid PAC constructed for signing, no KDC checksum present!")); + return EINVAL; + } + if (!srv_checksum) { + DEBUG(2, ("Invalid PAC constructed for signing, no SRV checksum present!")); + return EINVAL; + } + + /* But wipe out the actual signatures */ + ZERO_STRUCT(kdc_checksum->signature); + ZERO_STRUCT(srv_checksum->signature); + + nt_status = ndr_push_struct_blob(&tmp_blob, mem_ctx, pac_data, + (ndr_push_flags_fn_t)ndr_push_PAC_DATA); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("PAC (presig) push failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + /* Then sign the result of the previous push, where the sig was zero'ed out */ + ret = make_pac_checksum(mem_ctx, &tmp_blob, srv_checksum, + context, service_keyblock); + + service_checksum_blob + = data_blob_const(srv_checksum->signature, sizeof(srv_checksum->signature)); + + /* Then sign Server checksum */ + ret = make_pac_checksum(mem_ctx, &service_checksum_blob, kdc_checksum, context, krbtgt_keyblock); + if (ret) { + DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + talloc_free(pac_data); + return ret; + } + + /* And push it out again, this time to the world. This relies on determanistic pointer values */ + nt_status = ndr_push_struct_blob(&tmp_blob, mem_ctx, pac_data, + (ndr_push_flags_fn_t)ndr_push_PAC_DATA); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("PAC (final) push failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + *pac = tmp_blob; + + return ret; +} + + + krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx, struct auth_serversupplied_info *server_info, krb5_context context, krb5_keyblock *krbtgt_keyblock, @@ -242,9 +388,6 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, DATA_BLOB *pac) { NTSTATUS nt_status; - DATA_BLOB zero_blob = data_blob(NULL, 0); - DATA_BLOB tmp_blob = data_blob(NULL, 0); - DATA_BLOB service_checksum_blob; krb5_error_code ret; struct PAC_DATA *pac_data = talloc(mem_ctx, struct PAC_DATA); struct netr_SamInfo3 *sam3; @@ -254,9 +397,7 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, union PAC_INFO *u_LOGON_NAME; struct PAC_LOGON_NAME *LOGON_NAME; union PAC_INFO *u_KDC_CHECKSUM; - struct PAC_SIGNATURE_DATA *KDC_CHECKSUM; union PAC_INFO *u_SRV_CHECKSUM; - struct PAC_SIGNATURE_DATA *SRV_CHECKSUM; enum { PAC_BUF_LOGON_INFO = 0, @@ -308,7 +449,6 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, } pac_data->buffers[PAC_BUF_SRV_CHECKSUM].type = PAC_TYPE_SRV_CHECKSUM; pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info = u_SRV_CHECKSUM; - SRV_CHECKSUM = &u_SRV_CHECKSUM->srv_cksum; /* KDC_CHECKSUM */ u_KDC_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO); @@ -318,7 +458,6 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, } pac_data->buffers[PAC_BUF_KDC_CHECKSUM].type = PAC_TYPE_KDC_CHECKSUM; pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info = u_KDC_CHECKSUM; - KDC_CHECKSUM = &u_KDC_CHECKSUM->kdc_cksum; /* now the real work begins... */ @@ -341,64 +480,12 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, LOGON_NAME->account_name = server_info->account_name; LOGON_NAME->logon_time = timeval_to_nttime(&tv); - - - /* First, just get the keytypes filled in (and lengths right, eventually) */ - ret = make_pac_checksum(mem_ctx, zero_blob, KDC_CHECKSUM, context, krbtgt_keyblock); - if (ret) { - DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - talloc_free(pac_data); - return ret; - } - - ret = make_pac_checksum(mem_ctx, zero_blob, SRV_CHECKSUM, context, service_keyblock); - if (ret) { - DEBUG(2, ("making service PAC checksum failed: %s\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - talloc_free(pac_data); - return ret; - } - - /* But wipe out the actual signatures */ - ZERO_STRUCT(KDC_CHECKSUM->signature); - ZERO_STRUCT(SRV_CHECKSUM->signature); - - nt_status = ndr_push_struct_blob(&tmp_blob, mem_ctx, pac_data, - (ndr_push_flags_fn_t)ndr_push_PAC_DATA); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("PAC (presig) push failed: %s\n", nt_errstr(nt_status))); - talloc_free(pac_data); - return EINVAL; - } - - /* Then sign the result of the previous push, where the sig was zero'ed out */ - ret = make_pac_checksum(mem_ctx, tmp_blob, SRV_CHECKSUM, - context, service_keyblock); - - service_checksum_blob - = data_blob_const(SRV_CHECKSUM->signature, sizeof(SRV_CHECKSUM->signature)); - - /* Then sign Server checksum */ - ret = make_pac_checksum(mem_ctx, service_checksum_blob, KDC_CHECKSUM, context, krbtgt_keyblock); - if (ret) { - DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - talloc_free(pac_data); - return ret; - } - - /* And push it out again, this time to the world. This relies on determanistic pointer values */ - nt_status = ndr_push_struct_blob(&tmp_blob, mem_ctx, pac_data, - (ndr_push_flags_fn_t)ndr_push_PAC_DATA); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("PAC (final) push failed: %s\n", nt_errstr(nt_status))); - talloc_free(pac_data); - return EINVAL; - } - - *pac = tmp_blob; - + ret = kerberos_encode_pac(mem_ctx, + pac_data, + context, + krbtgt_keyblock, + service_keyblock, + pac); talloc_free(pac_data); return ret; } diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index c986d60fdf..44326cabef 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -70,7 +70,7 @@ return EINVAL; } - ret = kerberos_encode_pac(mem_ctx, server_info, + ret = kerberos_create_pac(mem_ctx, server_info, context, krbtgt_keyblock, server_keyblock, diff --git a/source4/torture/auth/pac.c b/source4/torture/auth/pac.c index 59bf008970..74a31af890 100644 --- a/source4/torture/auth/pac.c +++ b/source4/torture/auth/pac.c @@ -28,14 +28,12 @@ #include "librpc/gen_ndr/ndr_krb5pac.h" #include "librpc/gen_ndr/ndr_samr.h" -#ifdef HAVE_KRB5 - static BOOL torture_pac_self_check(void) { NTSTATUS nt_status; TALLOC_CTX *mem_ctx = talloc_named(NULL, 0, "PAC self check"); DATA_BLOB tmp_blob; - struct PAC_LOGON_INFO *pac_info; + struct PAC_DATA *pac_data; /* Generate a nice, arbitary keyblock */ uint8_t server_bytes[16]; @@ -100,7 +98,7 @@ static BOOL torture_pac_self_check(void) } /* OK, go ahead and make a PAC */ - ret = kerberos_encode_pac(mem_ctx, server_info, + ret = kerberos_create_pac(mem_ctx, server_info, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, @@ -122,7 +120,7 @@ static BOOL torture_pac_self_check(void) dump_data(10,tmp_blob.data,tmp_blob.length); /* Now check that we can read it back */ - nt_status = kerberos_decode_pac(mem_ctx, &pac_info, + nt_status = kerberos_decode_pac(mem_ctx, &pac_data, tmp_blob, smb_krb5_context, &krbtgt_keyblock, @@ -197,8 +195,7 @@ static BOOL torture_pac_saved_check(void) NTSTATUS nt_status; TALLOC_CTX *mem_ctx = talloc_named(NULL, 0, "PAC saved check"); DATA_BLOB tmp_blob, validate_blob; - struct PAC_LOGON_INFO *pac_info; - struct PAC_DATA pac_data; + struct PAC_DATA *pac_data; krb5_keyblock server_keyblock; krb5_keyblock krbtgt_keyblock; uint8_t server_bytes[16]; @@ -264,35 +261,37 @@ static BOOL torture_pac_saved_check(void) dump_data(10,tmp_blob.data,tmp_blob.length); /* Decode and verify the signaure on the PAC */ - nt_status = kerberos_decode_pac(mem_ctx, &pac_info, + nt_status = kerberos_decode_pac(mem_ctx, &pac_data, tmp_blob, smb_krb5_context, &krbtgt_keyblock, &server_keyblock); - krb5_free_keyblock_contents(smb_krb5_context->krb5_context, - &krbtgt_keyblock); - krb5_free_keyblock_contents(smb_krb5_context->krb5_context, - &server_keyblock); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("PAC decoding failed: %s\n", nt_errstr(nt_status))); + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &krbtgt_keyblock); + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &server_keyblock); talloc_free(mem_ctx); return False; } - nt_status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data, - (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0,("can't parse the PAC\n")); - talloc_free(mem_ctx); - return False; - } + ret = kerberos_encode_pac(mem_ctx, + pac_data, + smb_krb5_context->krb5_context, + &krbtgt_keyblock, + &server_keyblock, + &validate_blob); - nt_status = ndr_push_struct_blob(&validate_blob, mem_ctx, &pac_data, - (ndr_push_flags_fn_t)ndr_push_PAC_DATA); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("PAC push failed: %s\n", nt_errstr(nt_status))); + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &krbtgt_keyblock); + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &server_keyblock); + + if (ret != 0) { + DEBUG(0, ("PAC push failed\n")); talloc_free(mem_ctx); return False; } @@ -328,14 +327,3 @@ BOOL torture_pac(void) ret &= torture_pac_saved_check(); return ret; } - -#else - -BOOL torture_pac(void) -{ - printf("Cannot do PAC test without Krb5\n"); - return False; -} - -#endif - |