static NTSTATUS auth_anonymous_session_info(TALLOC_CTX *mem_ctx, struct auth_session_info_transport **session_info) { struct auth_session_info_transport *i; struct auth_serversupplied_info *s; struct auth_user_info_dc *u; union netr_Validation val; NTSTATUS status; i = talloc_zero(mem_ctx, struct auth_session_info_transport); if (i == NULL) { return NT_STATUS_NO_MEMORY; } status = make_server_info_guest(i, &s); if (!NT_STATUS_IS_OK(status)) { return status; } i->security_token = s->security_token; i->session_key = s->user_session_key; val.sam3 = s->info3; status = make_user_info_dc_netlogon_validation(mem_ctx, "", 3, &val, &u); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("conversion of info3 into user_info_dc failed!\n")); return status; } i->info = talloc_move(i, &u->info); talloc_free(u); *session_info = i; return NT_STATUS_OK; }
static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx_out, 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_user_info_dc *user_info_dc = NULL; struct auth_session_info *session_info = NULL; struct PAC_LOGON_INFO *logon_info; krb5_principal client_principal; char *principal_string; DATA_BLOB pac; krb5_data pac_data; krb5_error_code ret; TALLOC_CTX *mem_ctx = talloc_new(mem_ctx_out); if (!mem_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, mem_ctx))); talloc_free(mem_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, mem_ctx))); krb5_free_principal(context, client_principal); talloc_free(mem_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 && gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) { DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s \n", principal_string, smb_get_krb5_error_message(context, ret, mem_ctx))); free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return NT_STATUS_ACCESS_DENIED; } else 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, mem_ctx))); if (gensec_security->auth_context && !gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) { DEBUG(1, ("Unable to find PAC for %s, resorting to local user lookup: %s", principal_string, smb_get_krb5_error_message(context, ret, mem_ctx))); nt_status = gensec_security->auth_context->get_user_info_dc_principal(mem_ctx, gensec_security->auth_context, principal_string, NULL, &user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return nt_status; } } else { DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n", principal_string)); free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return NT_STATUS_ACCESS_DENIED; } } else { /* Found pac */ union netr_Validation validation; pac = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length); if (!pac.data) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return NT_STATUS_NO_MEMORY; } /* decode and verify the pac */ nt_status = kerberos_pac_logon_info(gensec_krb5_state, pac, gensec_krb5_state->smb_krb5_context->krb5_context, NULL, gensec_krb5_state->keyblock, client_principal, gensec_krb5_state->ticket->ticket.authtime, &logon_info); if (!NT_STATUS_IS_OK(nt_status)) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return nt_status; } validation.sam3 = &logon_info->info3; nt_status = make_user_info_dc_netlogon_validation(mem_ctx, NULL, 3, &validation, true, /* This user was authenticated */ &user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return nt_status; } } free(principal_string); krb5_free_principal(context, client_principal); /* references the user_info_dc into the session_info */ nt_status = gensec_generate_session_info(mem_ctx, gensec_security, user_info_dc, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_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(mem_ctx); return nt_status; } *_session_info = talloc_steal(mem_ctx_out, session_info); talloc_free(mem_ctx); 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_user_info_dc *user_info_dc; struct auth_user_info_dc *user_info_dc_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_user_info_dc(mem_ctx, lpcfg_netbios_name(tctx->lp_ctx), &user_info_dc); 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_user_info_dc"); } ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, user_info_dc->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, user_info_dc, 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, tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, &pac_data); 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_user_info_dc(mem_ctx, tmp_blob, smb_krb5_context->krb5_context, &user_info_dc_out, NULL, NULL); /* The user's SID is the first element in the list */ if (!dom_sid_equal(user_info_dc->sids, user_info_dc_out->sids)) { 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, user_info_dc->sids), dom_sid_string(mem_ctx, user_info_dc_out->sids))); } talloc_free(user_info_dc_out); /* Now check that we can read it back (yet again) */ nt_status = kerberos_pac_logon_info(mem_ctx, tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, &logon_info); 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_user_info_dc_netlogon_validation(mem_ctx, "", 3, &validation, true, /* This user was authenticated */ &user_info_dc_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(user_info_dc->sids, user_info_dc_out->sids)) { torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC Decode resulted in *different* domain SID: %s != %s", dom_sid_string(mem_ctx, user_info_dc->sids), dom_sid_string(mem_ctx, user_info_dc_out->sids))); } 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_user_info_dc *user_info_dc_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, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, &pac_data); 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_user_info_dc(mem_ctx, tmp_blob, smb_krb5_context->krb5_context, &user_info_dc_out, NULL, 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) 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"), user_info_dc_out->sids)) { 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, user_info_dc_out->sids))); } talloc_free(user_info_dc_out); /* Parse the PAC again, for the logon info this time (using Samba4's parsing) */ nt_status = kerberos_pac_logon_info(mem_ctx, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, &logon_info); 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_user_info_dc_netlogon_validation(mem_ctx, "", 3, &validation, true, /* This user was authenticated */ &user_info_dc_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"), user_info_dc_out->sids)) { 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, user_info_dc_out->sids))); } 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, 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, user_info_dc_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, &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, &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, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime + 1, &pac_data); 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, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, &pac_data); 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, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, &pac_data); 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; }