samlogon.c
来自「samba最新软件」· C语言 代码 · 共 1,856 行 · 第 1/4 页
C
1,856 行
/* Unix SMB/CIFS implementation. test suite for netlogon SamLogon operations Copyright (C) Andrew Tridgell 2003 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004 Copyright (C) Tim Potter 2003 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 "librpc/gen_ndr/ndr_netlogon.h"#include "librpc/gen_ndr/ndr_netlogon_c.h"#include "librpc/gen_ndr/ndr_samr_c.h"#include "auth/auth.h"#include "lib/crypto/crypto.h"#include "lib/cmdline/popt_common.h"#include "torture/rpc/rpc.h"#include "auth/gensec/schannel_proto.h"#include "auth/gensec/gensec.h"#include "libcli/auth/libcli_auth.h"#include "param/param.h"#define TEST_MACHINE_NAME "samlogontest"#define TEST_USER_NAME "samlogontestuser"#define TEST_USER_NAME_WRONG_WKS "samlogontest2"#define TEST_USER_NAME_WRONG_TIME "samlogontest3"enum ntlm_break { BREAK_BOTH, BREAK_NONE, BREAK_LM, BREAK_NT, NO_LM, NO_NT};struct samlogon_state { TALLOC_CTX *mem_ctx; const char *comment; const char *account_name; const char *account_domain; const char *password; struct dcerpc_pipe *p; int function_level; uint32_t parameter_control; struct netr_LogonSamLogon r; struct netr_LogonSamLogonEx r_ex; struct netr_LogonSamLogonWithFlags r_flags; struct netr_Authenticator auth, auth2; struct creds_CredentialState *creds; NTSTATUS expected_error; bool old_password; /* Allow an old password to be accepted or rejected without error, as well as session key bugs */ DATA_BLOB chall; struct smb_iconv_convenience *iconv_convenience;};/* Authenticate a user with a challenge/response, checking session key and valid authentication types*/static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state, enum ntlm_break break_which, uint32_t parameter_control, DATA_BLOB *chall, DATA_BLOB *lm_response, DATA_BLOB *nt_response, uint8_t lm_key[8], uint8_t user_session_key[16], char **error_string){ NTSTATUS status; struct netr_LogonSamLogon *r = &samlogon_state->r; struct netr_LogonSamLogonEx *r_ex = &samlogon_state->r_ex; struct netr_LogonSamLogonWithFlags *r_flags = &samlogon_state->r_flags; struct netr_NetworkInfo ninfo; struct netr_SamBaseInfo *base = NULL; uint16_t validation_level = 0; samlogon_state->r.in.logon.network = &ninfo; samlogon_state->r_ex.in.logon.network = &ninfo; samlogon_state->r_flags.in.logon.network = &ninfo; ninfo.identity_info.domain_name.string = samlogon_state->account_domain; ninfo.identity_info.parameter_control = parameter_control; ninfo.identity_info.logon_id_low = 0; ninfo.identity_info.logon_id_high = 0; ninfo.identity_info.account_name.string = samlogon_state->account_name; ninfo.identity_info.workstation.string = TEST_MACHINE_NAME; memcpy(ninfo.challenge, chall->data, 8); switch (break_which) { case BREAK_NONE: break; case BREAK_LM: if (lm_response && lm_response->data) { lm_response->data[0]++; } break; case BREAK_NT: if (nt_response && nt_response->data) { nt_response->data[0]++; } break; case BREAK_BOTH: if (lm_response && lm_response->data) { lm_response->data[0]++; } if (nt_response && nt_response->data) { nt_response->data[0]++; } break; case NO_LM: data_blob_free(lm_response); break; case NO_NT: data_blob_free(nt_response); break; } if (nt_response) { ninfo.nt.data = nt_response->data; ninfo.nt.length = nt_response->length; } else { ninfo.nt.data = NULL; ninfo.nt.length = 0; } if (lm_response) { ninfo.lm.data = lm_response->data; ninfo.lm.length = lm_response->length; } else { ninfo.lm.data = NULL; ninfo.lm.length = 0; } switch (samlogon_state->function_level) { case NDR_NETR_LOGONSAMLOGON: ZERO_STRUCT(samlogon_state->auth2); creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth); r->out.return_authenticator = NULL; status = dcerpc_netr_LogonSamLogon(samlogon_state->p, samlogon_state->mem_ctx, r); if (!r->out.return_authenticator || !creds_client_check(samlogon_state->creds, &r->out.return_authenticator->cred)) { d_printf("Credential chaining failed\n"); } if (!NT_STATUS_IS_OK(status)) { if (error_string) { *error_string = strdup(nt_errstr(status)); } return status; } validation_level = r->in.validation_level; creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r->out.validation); switch (validation_level) { case 2: base = &r->out.validation.sam2->base; break; case 3: base = &r->out.validation.sam3->base; break; case 6: base = &r->out.validation.sam6->base; break; } break; case NDR_NETR_LOGONSAMLOGONEX: status = dcerpc_netr_LogonSamLogonEx(samlogon_state->p, samlogon_state->mem_ctx, r_ex); if (!NT_STATUS_IS_OK(status)) { if (error_string) { *error_string = strdup(nt_errstr(status)); } return status; } validation_level = r_ex->in.validation_level; creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r_ex->out.validation); switch (validation_level) { case 2: base = &r_ex->out.validation.sam2->base; break; case 3: base = &r_ex->out.validation.sam3->base; break; case 6: base = &r_ex->out.validation.sam6->base; break; } break; case NDR_NETR_LOGONSAMLOGONWITHFLAGS: ZERO_STRUCT(samlogon_state->auth2); creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth); r_flags->out.return_authenticator = NULL; status = dcerpc_netr_LogonSamLogonWithFlags(samlogon_state->p, samlogon_state->mem_ctx, r_flags); if (!r_flags->out.return_authenticator || !creds_client_check(samlogon_state->creds, &r_flags->out.return_authenticator->cred)) { d_printf("Credential chaining failed\n"); } if (!NT_STATUS_IS_OK(status)) { if (error_string) { *error_string = strdup(nt_errstr(status)); } return status; } validation_level = r_flags->in.validation_level; creds_decrypt_samlogon(samlogon_state->creds, validation_level, &r_flags->out.validation); switch (validation_level) { case 2: base = &r_flags->out.validation.sam2->base; break; case 3: base = &r_flags->out.validation.sam3->base; break; case 6: base = &r_flags->out.validation.sam6->base; break; } break; default: /* can't happen */ return NT_STATUS_INVALID_PARAMETER; } if (!base) { d_printf("No user info returned from 'successful' SamLogon*() call!\n"); return NT_STATUS_INVALID_PARAMETER; } if (user_session_key) { memcpy(user_session_key, base->key.key, 16); } if (lm_key) { memcpy(lm_key, base->LMSessKey.key, 8); } return status;} /* * Test the normal 'LM and NTLM' combination */static bool test_lm_ntlm_broken(struct samlogon_state *samlogon_state, enum ntlm_break break_which, char **error_string) { bool pass = true; bool lm_good; NTSTATUS nt_status; DATA_BLOB lm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24); DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24); DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16); uint8_t lm_key[8]; uint8_t user_session_key[16]; uint8_t lm_hash[16]; uint8_t nt_hash[16]; ZERO_STRUCT(lm_key); ZERO_STRUCT(user_session_key); lm_good = SMBencrypt(samlogon_state->password, samlogon_state->chall.data, lm_response.data); if (!lm_good) { ZERO_STRUCT(lm_hash); } else { E_deshash(samlogon_state->password, lm_hash); } SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, nt_response.data); E_md4hash(samlogon_state->password, nt_hash); SMBsesskeygen_ntv1(nt_hash, session_key.data); nt_status = check_samlogon(samlogon_state, break_which, samlogon_state->parameter_control, &samlogon_state->chall, &lm_response, &nt_response, lm_key, user_session_key, error_string); data_blob_free(&lm_response); if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) { /* for 'long' passwords, the LM password is invalid */ if (break_which == NO_NT && !lm_good) { return true; } /* for 'old' passwords, we allow the server to be OK or wrong password */ if (samlogon_state->old_password) { return true; } return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH)); } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) { return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT)); } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) { SAFE_FREE(*error_string); asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status)); return false; } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) { return true; } else if (!NT_STATUS_IS_OK(nt_status)) { return false; } if (break_which == NO_NT && !lm_good) { *error_string = strdup("LM password is 'long' (> 14 chars and therefore invalid) but login did not fail!"); return false; } if (memcmp(lm_hash, lm_key, sizeof(lm_key)) != 0) { d_printf("LM Key does not match expectations!\n"); d_printf("lm_key:\n"); dump_data(1, lm_key, 8); d_printf("expected:\n"); dump_data(1, lm_hash, 8); pass = false; } switch (break_which) { case NO_NT: { uint8_t lm_key_expected[16]; memcpy(lm_key_expected, lm_hash, 8); memset(lm_key_expected+8, '\0', 8); if (memcmp(lm_key_expected, user_session_key, 16) != 0) { *error_string = strdup("NT Session Key does not match expectations (should be first-8 LM hash)!\n"); d_printf("user_session_key:\n"); dump_data(1, user_session_key, sizeof(user_session_key)); d_printf("expected:\n"); dump_data(1, lm_key_expected, sizeof(lm_key_expected)); pass = false; } break; } default: if (memcmp(session_key.data, user_session_key, sizeof(user_session_key)) != 0) { *error_string = strdup("NT Session Key does not match expectations!\n"); d_printf("user_session_key:\n"); dump_data(1, user_session_key, 16); d_printf("expected:\n"); dump_data(1, session_key.data, session_key.length); pass = false; } } return pass;}/* * Test LM authentication, no NT response supplied */static bool test_lm(struct samlogon_state *samlogon_state, char **error_string) { return test_lm_ntlm_broken(samlogon_state, NO_NT, error_string);}/* * Test the NTLM response only, no LM. */static bool test_ntlm(struct samlogon_state *samlogon_state, char **error_string) { return test_lm_ntlm_broken(samlogon_state, NO_LM, error_string);}/* * Test the NTLM response only, but in the LM field. */static bool test_ntlm_in_lm(struct samlogon_state *samlogon_state, char **error_string) { bool lm_good; bool pass = true; NTSTATUS nt_status; DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24); DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16); uint8_t lm_key[8]; uint8_t lm_hash[16]; uint8_t user_session_key[16]; uint8_t nt_hash[16]; ZERO_STRUCT(lm_key); ZERO_STRUCT(user_session_key); SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, nt_response.data); E_md4hash(samlogon_state->password, nt_hash); SMBsesskeygen_ntv1(nt_hash, session_key.data); lm_good = E_deshash(samlogon_state->password, lm_hash); if (!lm_good) { ZERO_STRUCT(lm_hash); } nt_status = check_samlogon(samlogon_state, BREAK_NONE, samlogon_state->parameter_control, &samlogon_state->chall, &nt_response, NULL, lm_key, user_session_key, error_string); if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) { /* for 'old' passwords, we allow the server to be OK or wrong password */ if (samlogon_state->old_password) { return true; } return false; } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) { SAFE_FREE(*error_string); asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status)); return false; } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) { return true; } else if (!NT_STATUS_IS_OK(nt_status)) { return false; } if (lm_good) { if (memcmp(lm_hash, lm_key, sizeof(lm_key)) != 0) { d_printf("LM Key does not match expectations!\n"); d_printf("lm_key:\n"); dump_data(1, lm_key, 8); d_printf("expected:\n"); dump_data(1, lm_hash, 8); pass = false; }#if 0 } else { if (memcmp(session_key.data, lm_key,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?