📄 kerberos_pac.c
字号:
/* Unix SMB/CIFS implementation. Create and parse the krb5 PAC Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 Copyright (C) Andrew Tridgell 2001 Copyright (C) Luke Howard 2002-2003 Copyright (C) Stefan Metzmacher 2004-2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "system/kerberos.h"#include "auth/kerberos/kerberos.h"#include "librpc/gen_ndr/ndr_krb5pac.h"#include "lib/ldb/include/ldb.h"#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 ret; krb5_crypto crypto; Checksum cksum; cksum.cksumtype = (CKSUMTYPE)sig->type; cksum.checksum.length = sig->signature.length; cksum.checksum.data = sig->signature.data; ret = krb5_crypto_init(context, keyblock, 0, &crypto); if (ret) { DEBUG(0,("krb5_crypto_init() failed: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); return ret; } ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, pac_data.data, pac_data.length, &cksum); krb5_crypto_destroy(context, crypto); return ret;} NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, struct PAC_DATA **pac_data_out, 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){ krb5_error_code ret; NTSTATUS status; enum ndr_err_code ndr_err; struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL; struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL; struct PAC_SIGNATURE_DATA *srv_sig_wipe = NULL; struct PAC_SIGNATURE_DATA *kdc_sig_wipe = NULL; struct PAC_LOGON_INFO *logon_info = NULL; struct PAC_LOGON_NAME *logon_name = NULL; struct PAC_DATA *pac_data; struct PAC_DATA_RAW *pac_data_raw; DATA_BLOB *srv_sig_blob = NULL; DATA_BLOB *kdc_sig_blob = NULL; DATA_BLOB modified_pac_blob; NTTIME tgs_authtime_nttime; krb5_principal client_principal_pac; int i; krb5_clear_error_string(context); if (k5ret) { *k5ret = KRB5_PARSE_MALFORMED; } pac_data = talloc(mem_ctx, struct PAC_DATA); pac_data_raw = talloc(mem_ctx, struct PAC_DATA_RAW); kdc_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA); srv_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA); if (!pac_data_raw || !pac_data || !kdc_sig_wipe || !srv_sig_wipe) { if (k5ret) { *k5ret = ENOMEM; } return NT_STATUS_NO_MEMORY; } ndr_err = ndr_pull_struct_blob(&blob, pac_data, iconv_convenience, pac_data, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the PAC: %s\n", nt_errstr(status))); return status; } if (pac_data->num_buffers < 4) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0,("less than 4 PAC buffers\n")); return NT_STATUS_INVALID_PARAMETER; } ndr_err = ndr_pull_struct_blob(&blob, pac_data_raw, iconv_convenience, pac_data_raw, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA_RAW); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the PAC: %s\n", nt_errstr(status))); return status; } if (pac_data_raw->num_buffers < 4) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0,("less than 4 PAC buffers\n")); return NT_STATUS_INVALID_PARAMETER; } if (pac_data->num_buffers != pac_data_raw->num_buffers) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0,("misparse! PAC_DATA has %d buffers while PAC_DATA_RAW has %d\n", pac_data->num_buffers, pac_data_raw->num_buffers)); return NT_STATUS_INVALID_PARAMETER; } for (i=0; i < pac_data->num_buffers; i++) { if (pac_data->buffers[i].type != pac_data_raw->buffers[i].type) { DEBUG(0,("misparse! PAC_DATA buffer %d has type %d while PAC_DATA_RAW has %d\n", i, pac_data->buffers[i].type, pac_data->buffers[i].type)); return NT_STATUS_INVALID_PARAMETER; } switch (pac_data->buffers[i].type) { case PAC_TYPE_LOGON_INFO: if (!pac_data->buffers[i].info) { break; } logon_info = pac_data->buffers[i].info->logon_info.info; break; case PAC_TYPE_SRV_CHECKSUM: if (!pac_data->buffers[i].info) { break; } srv_sig_ptr = &pac_data->buffers[i].info->srv_cksum; srv_sig_blob = &pac_data_raw->buffers[i].info->remaining; break; case PAC_TYPE_KDC_CHECKSUM: if (!pac_data->buffers[i].info) { break; } kdc_sig_ptr = &pac_data->buffers[i].info->kdc_cksum; kdc_sig_blob = &pac_data_raw->buffers[i].info->remaining; break; case PAC_TYPE_LOGON_NAME: logon_name = &pac_data->buffers[i].info->logon_name; break; default: break; } } if (!logon_info) { DEBUG(0,("PAC no logon_info\n")); return NT_STATUS_INVALID_PARAMETER; } if (!logon_name) { DEBUG(0,("PAC no logon_name\n")); return NT_STATUS_INVALID_PARAMETER; } if (!srv_sig_ptr || !srv_sig_blob) { DEBUG(0,("PAC no srv_key\n")); return NT_STATUS_INVALID_PARAMETER; } if (!kdc_sig_ptr || !kdc_sig_blob) { DEBUG(0,("PAC no kdc_key\n")); return NT_STATUS_INVALID_PARAMETER; } /* Find and zero out the signatures, as required by the signing algorithm */ /* We find the data blobs above, now we parse them to get at the exact portion we should zero */ ndr_err = ndr_pull_struct_blob(kdc_sig_blob, kdc_sig_wipe, iconv_convenience, kdc_sig_wipe, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the KDC signature: %s\n", nt_errstr(status))); return status; } ndr_err = ndr_pull_struct_blob(srv_sig_blob, srv_sig_wipe, iconv_convenience, srv_sig_wipe, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the SRV signature: %s\n", nt_errstr(status))); return status; } /* Now zero the decoded structure */ memset(kdc_sig_wipe->signature.data, '\0', kdc_sig_wipe->signature.length); memset(srv_sig_wipe->signature.data, '\0', srv_sig_wipe->signature.length); /* and reencode, back into the same place it came from */ ndr_err = ndr_push_struct_blob(kdc_sig_blob, pac_data_raw, iconv_convenience, kdc_sig_wipe, (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't repack the KDC signature: %s\n", nt_errstr(status))); return status; } ndr_err = ndr_push_struct_blob(srv_sig_blob, pac_data_raw, iconv_convenience, srv_sig_wipe, (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't repack the SRV signature: %s\n", nt_errstr(status))); return status; } /* push out the whole structure, but now with zero'ed signatures */ ndr_err = ndr_push_struct_blob(&modified_pac_blob, pac_data_raw, iconv_convenience, pac_data_raw, (ndr_push_flags_fn_t)ndr_push_PAC_DATA_RAW); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't repack the RAW PAC: %s\n", nt_errstr(status))); return status; } /* verify by service_key */ ret = check_pac_checksum(mem_ctx, modified_pac_blob, srv_sig_ptr, context, service_keyblock); if (ret) { DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); if (k5ret) { *k5ret = ret; } return NT_STATUS_ACCESS_DENIED; } if (krbtgt_keyblock) { ret = check_pac_checksum(mem_ctx, srv_sig_ptr->signature, kdc_sig_ptr, context, krbtgt_keyblock); if (ret) { DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); if (k5ret) { *k5ret = ret; } return NT_STATUS_ACCESS_DENIED; } } /* Convert to NT time, so as not to loose accuracy in comparison */ unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime); if (tgs_authtime_nttime != logon_name->logon_time) { DEBUG(2, ("PAC Decode: Logon time mismatch between ticket and PAC!\n")); DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time))); DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime))); return NT_STATUS_ACCESS_DENIED; } ret = krb5_parse_name_flags(context, logon_name->account_name, KRB5_PRINCIPAL_PARSE_NO_REALM, &client_principal_pac); if (ret) { DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n", logon_name->account_name, smb_get_krb5_error_message(context, ret, mem_ctx))); if (k5ret) { *k5ret = ret; } return NT_STATUS_INVALID_PARAMETER; } if (!krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) { DEBUG(2, ("Name in PAC [%s] does not match principal name in ticket\n", logon_name->account_name)); return NT_STATUS_ACCESS_DENIED; } #if 0 if (strcasecmp(logon_info->info3.base.account_name.string, "Administrator")== 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -