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 + -
显示快捷键?