/**************************************************************** Callback to get the PAC_LOGON_INFO from the blob ****************************************************************/ static NTSTATUS kerberos_fetch_pac(struct auth4_context *auth_ctx, TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, DATA_BLOB *pac_blob, const char *princ_name, const struct tsocket_address *remote_address, uint32_t session_info_flags, struct auth_session_info **session_info) { TALLOC_CTX *tmp_ctx; struct PAC_DATA *pac_data = NULL; struct PAC_DATA_CTR *pac_data_ctr = NULL; NTSTATUS status = NT_STATUS_INTERNAL_ERROR; tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } if (pac_blob) { status = kerberos_decode_pac(tmp_ctx, *pac_blob, NULL, NULL, NULL, NULL, 0, &pac_data); if (!NT_STATUS_IS_OK(status)) { goto done; } } pac_data_ctr = talloc(mem_ctx, struct PAC_DATA_CTR); if (pac_data_ctr == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } talloc_set_name_const(pac_data_ctr, "struct PAC_DATA_CTR"); pac_data_ctr->pac_data = talloc_steal(pac_data_ctr, pac_data); pac_data_ctr->pac_blob = data_blob_talloc(pac_data_ctr, pac_blob->data, pac_blob->length); auth_ctx->private_data = talloc_steal(auth_ctx, pac_data_ctr); *session_info = talloc_zero(mem_ctx, struct auth_session_info); if (!*session_info) { status = NT_STATUS_NO_MEMORY; goto done; } status = NT_STATUS_OK; done: TALLOC_FREE(tmp_ctx); return status; }
_PUBLIC_ NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, struct PAC_LOGON_INFO **logon_info, DATA_BLOB blob, krb5_context context, const krb5_keyblock *krbtgt_keyblock, const krb5_keyblock *service_keyblock, krb5_const_principal client_principal, time_t tgs_authtime, krb5_error_code *k5ret) { NTSTATUS nt_status; struct PAC_DATA *pac_data; int i; nt_status = kerberos_decode_pac(mem_ctx, iconv_convenience, &pac_data, blob, context, krbtgt_keyblock, service_keyblock, client_principal, tgs_authtime, k5ret); 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 bool torture_pac_self_check(struct torture_context *tctx) { NTSTATUS nt_status; DATA_BLOB tmp_blob; struct PAC_DATA *pac_data; struct PAC_LOGON_INFO *logon_info; union netr_Validation validation; /* Generate a nice, arbitary keyblock */ uint8_t server_bytes[16]; uint8_t krbtgt_bytes[16]; krb5_keyblock server_keyblock; krb5_keyblock krbtgt_keyblock; krb5_error_code ret; struct smb_krb5_context *smb_krb5_context; struct auth_serversupplied_info *server_info; struct auth_serversupplied_info *server_info_out; krb5_principal client_principal; time_t logon_time = time(NULL); TALLOC_CTX *mem_ctx = tctx; torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, NULL, tctx->lp_ctx, &smb_krb5_context), "smb_krb5_init_context"); generate_random_buffer(server_bytes, 16); generate_random_buffer(krbtgt_bytes, 16); ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, server_bytes, sizeof(server_bytes), &server_keyblock); torture_assert(tctx, !ret, talloc_asprintf(tctx, "(self test) Server Keyblock encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, krbtgt_bytes, sizeof(krbtgt_bytes), &krbtgt_keyblock); if (ret) { char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(self test) KRBTGT Keyblock encoding failed: %s", err)); } /* We need an input, and this one requires no underlying database */ nt_status = auth_anonymous_server_info(mem_ctx, lp_netbios_name(tctx->lp_ctx), &server_info); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); torture_fail(tctx, "auth_anonymous_server_info"); } ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, server_info->account_name, KRB5_PRINCIPAL_PARSE_NO_REALM, &client_principal); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); torture_fail(tctx, "krb5_parse_name_flags(norealm)"); } /* OK, go ahead and make a PAC */ ret = kerberos_create_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), server_info, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, &tmp_blob); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } dump_data(10,tmp_blob.data,tmp_blob.length); /* Now check that we can read it back (using full decode and validate) */ nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC decoding failed: %s", nt_errstr(nt_status))); } /* Now check we can read it back (using Heimdal's pac parsing) */ nt_status = kerberos_pac_blob_to_server_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), tmp_blob, smb_krb5_context->krb5_context, &server_info_out); if (!dom_sid_equal(server_info->account_sid, server_info_out->account_sid)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC Decode resulted in *different* domain SID: %s != %s", dom_sid_string(mem_ctx, server_info->account_sid), dom_sid_string(mem_ctx, server_info_out->account_sid))); } talloc_free(server_info_out); /* Now check that we can read it back (yet again) */ nt_status = kerberos_pac_logon_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &logon_info, tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC decoding (for logon info) failed: %s", 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); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); /* And make a server info from the samba-parsed PAC */ validation.sam3 = &logon_info->info3; nt_status = make_server_info_netlogon_validation(mem_ctx, "", 3, &validation, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC decoding (make server info) failed: %s", nt_errstr(nt_status))); } if (!dom_sid_equal(server_info->account_sid, server_info_out->account_sid)) { torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC Decode resulted in *different* domain SID: %s != %s", dom_sid_string(mem_ctx, server_info->account_sid), dom_sid_string(mem_ctx, server_info_out->account_sid))); } return true; }
/* Check with a known 'well formed' PAC, from my test server */ static bool torture_pac_saved_check(struct torture_context *tctx) { NTSTATUS nt_status; enum ndr_err_code ndr_err; DATA_BLOB tmp_blob, validate_blob; struct PAC_DATA *pac_data, pac_data2; struct PAC_LOGON_INFO *logon_info; union netr_Validation validation; const char *pac_file, *pac_kdc_key, *pac_member_key; struct auth_serversupplied_info *server_info_out; krb5_keyblock server_keyblock; krb5_keyblock krbtgt_keyblock, *krbtgt_keyblock_p; struct samr_Password *krbtgt_bytes, *krbsrv_bytes; krb5_error_code ret; struct smb_krb5_context *smb_krb5_context; const char *principal_string; char *broken_principal_string; krb5_principal client_principal; const char *authtime_string; time_t authtime; TALLOC_CTX *mem_ctx = tctx; torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, NULL, tctx->lp_ctx, &smb_krb5_context), "smb_krb5_init_context"); pac_kdc_key = torture_setting_string(tctx, "pac_kdc_key", "B286757148AF7FD252C53603A150B7E7"); pac_member_key = torture_setting_string(tctx, "pac_member_key", "D217FAEAE5E6B5F95CCC94077AB8A5FC"); torture_comment(tctx, "Using pac_kdc_key '%s'\n", pac_kdc_key); torture_comment(tctx, "Using pac_member_key '%s'\n", pac_member_key); /* The krbtgt key in use when the above PAC was generated. * This is an arcfour-hmac-md5 key, extracted with our 'net * samdump' tool. */ if (*pac_kdc_key == 0) { krbtgt_bytes = NULL; } else { krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key); if (!krbtgt_bytes) { torture_fail(tctx, "(saved test) Could not interpret krbtgt key"); } } krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key); if (!krbsrv_bytes) { torture_fail(tctx, "(saved test) Could not interpret krbsrv key"); } ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash), &server_keyblock); torture_assert(tctx, !ret, talloc_asprintf(tctx, "(saved test) Server Keyblock encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); if (krbtgt_bytes) { ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash), &krbtgt_keyblock); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) Server Keyblock encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } krbtgt_keyblock_p = &krbtgt_keyblock; } else { krbtgt_keyblock_p = NULL; } pac_file = torture_setting_string(tctx, "pac_file", NULL); if (pac_file) { tmp_blob.data = (uint8_t *)file_load(pac_file, &tmp_blob.length, 0, mem_ctx); torture_comment(tctx, "(saved test) Loaded pac of size %ld from %s\n", (long)tmp_blob.length, pac_file); } else { tmp_blob = data_blob_talloc(mem_ctx, saved_pac, sizeof(saved_pac)); } dump_data(10,tmp_blob.data,tmp_blob.length); principal_string = torture_setting_string(tctx, "pac_client_principal", "[email protected]"); authtime_string = torture_setting_string(tctx, "pac_authtime", "1120440609"); authtime = strtoull(authtime_string, NULL, 0); ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string, &client_principal); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) parsing of client principal [%s] failed: %s", principal_string, smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } /* Decode and verify the signaure on the PAC */ nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC decoding failed: %s", nt_errstr(nt_status))); } /* Now check we can read it back (using Heimdal's pac parsing) */ nt_status = kerberos_pac_blob_to_server_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), tmp_blob, smb_krb5_context->krb5_context, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) Heimdal PAC decoding failed: %s", nt_errstr(nt_status))); } if (!pac_file && !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, "S-1-5-21-3048156945-3961193616-3706469200-1005"), server_info_out->account_sid)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) Heimdal PAC Decode resulted in *different* domain SID: %s != %s", "S-1-5-21-3048156945-3961193616-3706469200-1005", dom_sid_string(mem_ctx, server_info_out->account_sid))); } talloc_free(server_info_out); /* Parse the PAC again, for the logon info this time (using Samba4's parsing) */ nt_status = kerberos_pac_logon_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &logon_info, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC decoding (for logon info) failed: %s", nt_errstr(nt_status))); } validation.sam3 = &logon_info->info3; nt_status = make_server_info_netlogon_validation(mem_ctx, "", 3, &validation, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC decoding (make server info) failed: %s", nt_errstr(nt_status))); } if (!pac_file && !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, "S-1-5-21-3048156945-3961193616-3706469200-1005"), server_info_out->account_sid)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC Decode resulted in *different* domain SID: %s != %s", "S-1-5-21-3048156945-3961193616-3706469200-1005", dom_sid_string(mem_ctx, server_info_out->account_sid))); } if (krbtgt_bytes == NULL) { torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n"); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); return true; } ret = kerberos_encode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), pac_data, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, &validate_blob); if (ret != 0) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, "(saved test) PAC push failed"); } dump_data(10, validate_blob.data, validate_blob.length); /* compare both the length and the data bytes after a * pull/push cycle. This ensures we use the exact same * pointer, padding etc algorithms as win2k3. */ if (tmp_blob.length != validate_blob.length) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: original buffer length[%u] != created buffer length[%u]", (unsigned)tmp_blob.length, (unsigned)validate_blob.length)); } if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); DEBUG(0, ("tmp_data:\n")); dump_data(0, tmp_blob.data, tmp_blob.length); DEBUG(0, ("validate_blob:\n")); dump_data(0, validate_blob.data, validate_blob.length); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length)); } ret = kerberos_create_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), server_info_out, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, &validate_blob); if (ret != 0) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, "(saved test) regnerated PAC create failed"); } dump_data(10,validate_blob.data,validate_blob.length); /* compare both the length and the data bytes after a * pull/push cycle. This ensures we use the exact same * pointer, padding etc algorithms as win2k3. */ if (tmp_blob.length != validate_blob.length) { ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data2, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); nt_status = ndr_map_error2ntstatus(ndr_err); torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC"); NDR_PRINT_DEBUG(PAC_DATA, pac_data); NDR_PRINT_DEBUG(PAC_DATA, &pac_data2); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC regenerate failed: original buffer length[%u] != created buffer length[%u]", (unsigned)tmp_blob.length, (unsigned)validate_blob.length)); } if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) { ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data2, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); nt_status = ndr_map_error2ntstatus(ndr_err); torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC"); NDR_PRINT_DEBUG(PAC_DATA, pac_data); NDR_PRINT_DEBUG(PAC_DATA, &pac_data2); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); DEBUG(0, ("tmp_data:\n")); dump_data(0, tmp_blob.data, tmp_blob.length); DEBUG(0, ("validate_blob:\n")); dump_data(0, validate_blob.data, validate_blob.length); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC regenerate failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length)); } /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */ nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime + 1, NULL); if (NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)"); } /* Break the client principal */ krb5_free_principal(smb_krb5_context->krb5_context, client_principal); broken_principal_string = talloc_strdup(mem_ctx, principal_string); broken_principal_string[0]++; ret = krb5_parse_name(smb_krb5_context->krb5_context, broken_principal_string, &client_principal); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) parsing of broken client principal failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal"); } /* Finally... Bugger up the signature, and check we fail the checksum */ tmp_blob.data[tmp_blob.length - 2]++; nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum"); } krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); return true; }
static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, struct auth_session_info **_session_info) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data; krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context; struct auth_session_info *session_info = NULL; krb5_principal client_principal; char *principal_string; DATA_BLOB pac_blob, *pac_blob_ptr = NULL; krb5_data pac_data; krb5_error_code ret; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal); if (ret) { DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n", smb_get_krb5_error_message(context, ret, tmp_ctx))); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } ret = krb5_unparse_name(gensec_krb5_state->smb_krb5_context->krb5_context, client_principal, &principal_string); if (ret) { DEBUG(1, ("Unable to parse client principal: %s\n", smb_get_krb5_error_message(context, ret, tmp_ctx))); krb5_free_principal(context, client_principal); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } ret = krb5_ticket_get_authorization_data_type(context, gensec_krb5_state->ticket, KRB5_AUTHDATA_WIN2K_PAC, &pac_data); if (ret) { /* NO pac */ DEBUG(5, ("krb5_ticket_get_authorization_data_type failed to find PAC: %s\n", smb_get_krb5_error_message(context, ret, tmp_ctx))); } else { /* Found pac */ pac_blob = data_blob_talloc(tmp_ctx, pac_data.data, pac_data.length); if (!pac_blob.data) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* decode and verify the pac */ nt_status = kerberos_decode_pac(gensec_krb5_state, pac_blob, gensec_krb5_state->smb_krb5_context->krb5_context, NULL, gensec_krb5_state->keyblock, client_principal, gensec_krb5_state->ticket->ticket.authtime, NULL); if (!NT_STATUS_IS_OK(nt_status)) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(tmp_ctx); return nt_status; } pac_blob_ptr = &pac_blob; } nt_status = gensec_generate_session_info_pac(tmp_ctx, gensec_security, gensec_krb5_state->smb_krb5_context, pac_blob_ptr, principal_string, gensec_get_remote_address(gensec_security), &session_info); free(principal_string); krb5_free_principal(context, client_principal); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } nt_status = gensec_krb5_session_key(gensec_security, session_info, &session_info->session_key); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } *_session_info = talloc_steal(mem_ctx, session_info); talloc_free(tmp_ctx); return NT_STATUS_OK; }
/**************************************************************** Callback to get the PAC_LOGON_INFO from the blob ****************************************************************/ static NTSTATUS kerberos_fetch_pac(struct auth4_context *auth_ctx, TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, DATA_BLOB *pac_blob, const char *princ_name, const struct tsocket_address *remote_address, uint32_t session_info_flags, struct auth_session_info **session_info) { TALLOC_CTX *tmp_ctx; struct PAC_DATA *pac_data = NULL; struct PAC_LOGON_INFO *logon_info = NULL; unsigned int i; NTSTATUS status = NT_STATUS_INTERNAL_ERROR; tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } if (pac_blob) { status = kerberos_decode_pac(tmp_ctx, *pac_blob, NULL, NULL, NULL, NULL, 0, &pac_data); if (!NT_STATUS_IS_OK(status)) { goto done; } /* get logon name and logon info */ for (i = 0; i < pac_data->num_buffers; i++) { struct PAC_BUFFER *data_buf = &pac_data->buffers[i]; switch (data_buf->type) { case PAC_TYPE_LOGON_INFO: if (!data_buf->info) { break; } logon_info = data_buf->info->logon_info.info; break; default: break; } } if (!logon_info) { DEBUG(1, ("Invalid PAC data, missing logon info!\n")); status = NT_STATUS_NOT_FOUND; goto done; } } talloc_set_name_const(logon_info, "struct PAC_LOGON_INFO"); auth_ctx->private_data = talloc_steal(auth_ctx, logon_info); *session_info = talloc_zero(mem_ctx, struct auth_session_info); if (!*session_info) { status = NT_STATUS_NO_MEMORY; goto done; } status = NT_STATUS_OK; done: TALLOC_FREE(tmp_ctx); return status; }