⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ntlmssp_server.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Unix SMB/Netbios implementation.   Version 3.0   handle NLTMSSP, client server side parsing   Copyright (C) Andrew Tridgell      2001   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005   Copyright (C) Stefan Metzmacher 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 "auth/ntlmssp/ntlmssp.h"#include "auth/ntlmssp/msrpc_parse.h"#include "lib/crypto/crypto.h"#include "system/filesys.h"#include "libcli/auth/libcli_auth.h"#include "auth/credentials/credentials.h"#include "auth/gensec/gensec.h"#include "auth/auth.h"#include "auth/ntlm/auth_proto.h"#include "param/param.h"#include "auth/session_proto.h"/**  * Set a username on an NTLMSSP context - ensures it is talloc()ed  * */static NTSTATUS ntlmssp_set_username(struct gensec_ntlmssp_state *gensec_ntlmssp_state, const char *user) {	if (!user) {		/* it should be at least "" */		DEBUG(1, ("NTLMSSP failed to set username - cannot accept NULL username\n"));		return NT_STATUS_INVALID_PARAMETER;	}	gensec_ntlmssp_state->user = talloc_strdup(gensec_ntlmssp_state, user);	if (!gensec_ntlmssp_state->user) {		return NT_STATUS_NO_MEMORY;	}	return NT_STATUS_OK;}/**  * Set a domain on an NTLMSSP context - ensures it is talloc()ed  * */static NTSTATUS ntlmssp_set_domain(struct gensec_ntlmssp_state *gensec_ntlmssp_state, const char *domain) {	gensec_ntlmssp_state->domain = talloc_strdup(gensec_ntlmssp_state, domain);	if (!gensec_ntlmssp_state->domain) {		return NT_STATUS_NO_MEMORY;	}	return NT_STATUS_OK;}/**  * Set a workstation on an NTLMSSP context - ensures it is talloc()ed  * */static NTSTATUS ntlmssp_set_workstation(struct gensec_ntlmssp_state *gensec_ntlmssp_state, const char *workstation) {	gensec_ntlmssp_state->workstation = talloc_strdup(gensec_ntlmssp_state, workstation);	if (!gensec_ntlmssp_state->workstation) {		return NT_STATUS_NO_MEMORY;	}	return NT_STATUS_OK;}/** * Determine correct target name flags for reply, given server role  * and negotiated flags *  * @param gensec_ntlmssp_state NTLMSSP State * @param neg_flags The flags from the packet * @param chal_flags The flags to be set in the reply packet * @return The 'target name' string. */static const char *ntlmssp_target_name(struct gensec_ntlmssp_state *gensec_ntlmssp_state,				       uint32_t neg_flags, uint32_t *chal_flags) {	if (neg_flags & NTLMSSP_REQUEST_TARGET) {		*chal_flags |= NTLMSSP_CHAL_TARGET_INFO;		*chal_flags |= NTLMSSP_REQUEST_TARGET;		if (gensec_ntlmssp_state->server_role == ROLE_STANDALONE) {			*chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;			return gensec_ntlmssp_state->server_name;		} else {			*chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;			return gensec_ntlmssp_state->domain;		};	} else {		return "";	}}/** * Next state function for the Negotiate packet *  * @param gensec_security GENSEC state * @param out_mem_ctx Memory context for *out * @param in The request, as a DATA_BLOB.  reply.data must be NULL * @param out The reply, as an allocated DATA_BLOB, caller to free. * @return Errors or MORE_PROCESSING_REQUIRED if (normal) a reply is required.  */NTSTATUS ntlmssp_server_negotiate(struct gensec_security *gensec_security, 				  TALLOC_CTX *out_mem_ctx, 				  const DATA_BLOB in, DATA_BLOB *out) {	struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data;	DATA_BLOB struct_blob;	char dnsname[MAXHOSTNAMELEN], dnsdomname[MAXHOSTNAMELEN];	const char *p;	uint32_t neg_flags = 0;	uint32_t ntlmssp_command, chal_flags;	const uint8_t *cryptkey;	const char *target_name;	/* parse the NTLMSSP packet */#if 0	file_save("ntlmssp_negotiate.dat", request.data, request.length);#endif	if (in.length) {		if ((in.length < 16) || !msrpc_parse(out_mem_ctx, 				 lp_iconv_convenience(gensec_security->lp_ctx),				 			 &in, "Cdd",							 "NTLMSSP",							 &ntlmssp_command,							 &neg_flags)) {			DEBUG(1, ("ntlmssp_server_negotiate: failed to parse "				"NTLMSSP Negotiate of length %u:\n",				(unsigned int)in.length ));			dump_data(2, in.data, in.length);			return NT_STATUS_INVALID_PARAMETER;		}		debug_ntlmssp_flags(neg_flags);	}		ntlmssp_handle_neg_flags(gensec_ntlmssp_state, neg_flags, gensec_ntlmssp_state->allow_lm_key);	/* Ask our caller what challenge they would like in the packet */	cryptkey = gensec_ntlmssp_state->get_challenge(gensec_ntlmssp_state);	/* Check if we may set the challenge */	if (!gensec_ntlmssp_state->may_set_challenge(gensec_ntlmssp_state)) {		gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;	}	/* The flags we send back are not just the negotiated flags,	 * they are also 'what is in this packet'.  Therfore, we	 * operate on 'chal_flags' from here on 	 */	chal_flags = gensec_ntlmssp_state->neg_flags;	/* get the right name to fill in as 'target' */	target_name = ntlmssp_target_name(gensec_ntlmssp_state, 					  neg_flags, &chal_flags); 	if (target_name == NULL) 		return NT_STATUS_INVALID_PARAMETER;	gensec_ntlmssp_state->chal = data_blob_talloc(gensec_ntlmssp_state, cryptkey, 8);	gensec_ntlmssp_state->internal_chal = data_blob_talloc(gensec_ntlmssp_state, cryptkey, 8);	dnsname[0] = '\0';	if (gethostname(dnsname, sizeof(dnsname)) == -1) {		DEBUG(0,("gethostname failed\n"));		return NT_STATUS_UNSUCCESSFUL;	}	/* This should be a 'netbios domain -> DNS domain' mapping */	p = strchr(dnsname, '.');	if (p != NULL) {		safe_strcpy(dnsdomname, p+1, sizeof(dnsdomname));		strlower_m(dnsdomname);	} else {		dnsdomname[0] = '\0';	}		/* This creates the 'blob' of names that appears at the end of the packet */	if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) 	{		const char *target_name_dns = "";		if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) {			target_name_dns = dnsdomname;		} else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) {			target_name_dns = dnsname;		}		msrpc_gen(out_mem_ctx, 		          lp_iconv_convenience(gensec_security->lp_ctx),			  &struct_blob, "aaaaa",			  NTLMSSP_NAME_TYPE_DOMAIN, target_name,			  NTLMSSP_NAME_TYPE_SERVER, gensec_ntlmssp_state->server_name,			  NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsdomname,			  NTLMSSP_NAME_TYPE_SERVER_DNS, dnsname,			  0, "");	} else {		struct_blob = data_blob(NULL, 0);	}	{		/* Marshel the packet in the right format, be it unicode or ASCII */		const char *gen_string;		if (gensec_ntlmssp_state->unicode) {			gen_string = "CdUdbddB";		} else {			gen_string = "CdAdbddB";		}				msrpc_gen(out_mem_ctx, 		          lp_iconv_convenience(gensec_security->lp_ctx),			  out, gen_string,			  "NTLMSSP", 			  NTLMSSP_CHALLENGE,			  target_name,			  chal_flags,			  cryptkey, 8,			  0, 0,			  struct_blob.data, struct_blob.length);	}			gensec_ntlmssp_state->expected_state = NTLMSSP_AUTH;	return NT_STATUS_MORE_PROCESSING_REQUIRED;}/** * Next state function for the Authenticate packet *  * @param gensec_ntlmssp_state NTLMSSP State * @param request The request, as a DATA_BLOB * @return Errors or NT_STATUS_OK.  */static NTSTATUS ntlmssp_server_preauth(struct gensec_ntlmssp_state *gensec_ntlmssp_state,				       const DATA_BLOB request) {	uint32_t ntlmssp_command, auth_flags;	NTSTATUS nt_status;	uint8_t session_nonce_hash[16];	const char *parse_string;	char *domain = NULL;	char *user = NULL;	char *workstation = NULL;#if 0	file_save("ntlmssp_auth.dat", request.data, request.length);#endif	if (gensec_ntlmssp_state->unicode) {		parse_string = "CdBBUUUBd";	} else {		parse_string = "CdBBAAABd";	}	/* zero these out */	data_blob_free(&gensec_ntlmssp_state->lm_resp);	data_blob_free(&gensec_ntlmssp_state->nt_resp);	data_blob_free(&gensec_ntlmssp_state->encrypted_session_key);	gensec_ntlmssp_state->user = NULL;	gensec_ntlmssp_state->domain = NULL;	gensec_ntlmssp_state->workstation = NULL;	/* now the NTLMSSP encoded auth hashes */	if (!msrpc_parse(gensec_ntlmssp_state, 			 lp_iconv_convenience(gensec_ntlmssp_state->gensec_security->lp_ctx),			 &request, parse_string,			 "NTLMSSP", 			 &ntlmssp_command, 			 &gensec_ntlmssp_state->lm_resp,			 &gensec_ntlmssp_state->nt_resp,			 &domain, 			 &user, 			 &workstation,			 &gensec_ntlmssp_state->encrypted_session_key,			 &auth_flags)) {		DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n"));		dump_data(10, request.data, request.length);		/* zero this out */		data_blob_free(&gensec_ntlmssp_state->encrypted_session_key);		auth_flags = 0;				/* Try again with a shorter string (Win9X truncates this packet) */		if (gensec_ntlmssp_state->unicode) {			parse_string = "CdBBUUU";		} else {			parse_string = "CdBBAAA";		}		/* now the NTLMSSP encoded auth hashes */		if (!msrpc_parse(gensec_ntlmssp_state, 			 	 lp_iconv_convenience(gensec_ntlmssp_state->gensec_security->lp_ctx),				 &request, parse_string,				 "NTLMSSP", 				 &ntlmssp_command, 				 &gensec_ntlmssp_state->lm_resp,				 &gensec_ntlmssp_state->nt_resp,				 &domain, 				 &user, 				 &workstation)) {			DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n"));			dump_data(2, request.data, request.length);			return NT_STATUS_INVALID_PARAMETER;		}	}	if (auth_flags)		ntlmssp_handle_neg_flags(gensec_ntlmssp_state, auth_flags, gensec_ntlmssp_state->allow_lm_key);	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(gensec_ntlmssp_state, domain))) {		/* zero this out */		data_blob_free(&gensec_ntlmssp_state->encrypted_session_key);		return nt_status;	}	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(gensec_ntlmssp_state, user))) {		/* zero this out */		data_blob_free(&gensec_ntlmssp_state->encrypted_session_key);		return nt_status;	}	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_workstation(gensec_ntlmssp_state, workstation))) {		/* zero this out */		data_blob_free(&gensec_ntlmssp_state->encrypted_session_key);		return nt_status;	}	DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%lu len2=%lu\n",		 gensec_ntlmssp_state->user, gensec_ntlmssp_state->domain, gensec_ntlmssp_state->workstation, (unsigned long)gensec_ntlmssp_state->lm_resp.length, (unsigned long)gensec_ntlmssp_state->nt_resp.length));#if 0	file_save("nthash1.dat",  &gensec_ntlmssp_state->nt_resp.data,  &gensec_ntlmssp_state->nt_resp.length);	file_save("lmhash1.dat",  &gensec_ntlmssp_state->lm_resp.data,  &gensec_ntlmssp_state->lm_resp.length);#endif	/* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a 	   client challenge 		   However, the NTLM2 flag may still be set for the real NTLMv2 logins, be careful.	*/	if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {		if (gensec_ntlmssp_state->nt_resp.length == 24 && gensec_ntlmssp_state->lm_resp.length == 24) {			struct MD5Context md5_session_nonce_ctx;			SMB_ASSERT(gensec_ntlmssp_state->internal_chal.data 				   && gensec_ntlmssp_state->internal_chal.length == 8);						gensec_ntlmssp_state->doing_ntlm2 = true;			memcpy(gensec_ntlmssp_state->crypt.ntlm2.session_nonce, gensec_ntlmssp_state->internal_chal.data, 8);			memcpy(&gensec_ntlmssp_state->crypt.ntlm2.session_nonce[8], gensec_ntlmssp_state->lm_resp.data, 8);						MD5Init(&md5_session_nonce_ctx);			MD5Update(&md5_session_nonce_ctx, gensec_ntlmssp_state->crypt.ntlm2.session_nonce, 16);			MD5Final(session_nonce_hash, &md5_session_nonce_ctx);						gensec_ntlmssp_state->chal = data_blob_talloc(gensec_ntlmssp_state, 							       session_nonce_hash, 8);			/* LM response is no longer useful, zero it out */			data_blob_free(&gensec_ntlmssp_state->lm_resp);			/* We changed the effective challenge - set it */			if (!NT_STATUS_IS_OK(nt_status = 					     gensec_ntlmssp_state->set_challenge(gensec_ntlmssp_state, 										 &gensec_ntlmssp_state->chal))) {				/* zero this out */				data_blob_free(&gensec_ntlmssp_state->encrypted_session_key);				return nt_status;			}			/* LM Key is incompatible... */			gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;		}	}	return NT_STATUS_OK;}/** * Next state function for the Authenticate packet  * (after authentication - figures out the session keys etc) *  * @param gensec_ntlmssp_state NTLMSSP State * @return Errors or NT_STATUS_OK.  */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -