dcerpc_netlogon.c

来自「samba最新软件」· C语言 代码 · 共 1,270 行 · 第 1/3 页

C
1,270
字号
/*    Unix SMB/CIFS implementation.   endpoint server for the netlogon pipe   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004   Copyright (C) Stefan Metzmacher <metze@samba.org>  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 "rpc_server/dcerpc_server.h"#include "rpc_server/common/common.h"#include "lib/ldb/include/ldb.h"#include "auth/auth.h"#include "auth/auth_sam_reply.h"#include "dsdb/samdb/samdb.h"#include "dsdb/common/flags.h"#include "rpc_server/samr/proto.h"#include "util/util_ldb.h"#include "libcli/auth/libcli_auth.h"#include "auth/gensec/schannel_state.h"#include "libcli/security/security.h"#include "param/param.h"struct server_pipe_state {	struct netr_Credential client_challenge;	struct netr_Credential server_challenge;};static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,					struct netr_ServerReqChallenge *r){	struct server_pipe_state *pipe_state = dce_call->context->private;	ZERO_STRUCTP(r->out.credentials);	/* destroyed on pipe shutdown */	if (pipe_state) {		talloc_free(pipe_state);		dce_call->context->private = NULL;	}		pipe_state = talloc(dce_call->context, struct server_pipe_state);	NT_STATUS_HAVE_NO_MEMORY(pipe_state);	pipe_state->client_challenge = *r->in.credentials;	generate_random_buffer(pipe_state->server_challenge.data, 			       sizeof(pipe_state->server_challenge.data));	*r->out.credentials = pipe_state->server_challenge;	dce_call->context->private = pipe_state;	return NT_STATUS_OK;}static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,					 struct netr_ServerAuthenticate3 *r){	struct server_pipe_state *pipe_state = dce_call->context->private;	struct creds_CredentialState *creds;	void *sam_ctx;	struct samr_Password *mach_pwd;	uint32_t user_account_control;	int num_records;	struct ldb_message **msgs;	NTSTATUS nt_status;	const char *attrs[] = {"unicodePwd", "userAccountControl", 			       "objectSid", NULL};	ZERO_STRUCTP(r->out.credentials);	*r->out.rid = 0;	*r->out.negotiate_flags = *r->in.negotiate_flags;	if (!pipe_state) {		DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));		return NT_STATUS_ACCESS_DENIED;	}	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, 				system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));	if (sam_ctx == NULL) {		return NT_STATUS_INVALID_SYSTEM_SERVICE;	}	/* pull the user attributes */	num_records = gendb_search(sam_ctx, mem_ctx, NULL, &msgs, attrs,				   "(&(sAMAccountName=%s)(objectclass=user))", 				   r->in.account_name);	if (num_records == 0) {		DEBUG(3,("Couldn't find user [%s] in samdb.\n", 			 r->in.account_name));		return NT_STATUS_ACCESS_DENIED;	}	if (num_records > 1) {		DEBUG(0,("Found %d records matching user [%s]\n", num_records, r->in.account_name));		return NT_STATUS_INTERNAL_DB_CORRUPTION;	}		user_account_control = ldb_msg_find_attr_as_uint(msgs[0], "userAccountControl", 0);	if (user_account_control & UF_ACCOUNTDISABLE) {		DEBUG(1, ("Account [%s] is disabled\n", r->in.account_name));		return NT_STATUS_ACCESS_DENIED;	}	if (r->in.secure_channel_type == SEC_CHAN_WKSTA) {		if (!(user_account_control & UF_WORKSTATION_TRUST_ACCOUNT)) {			DEBUG(1, ("Client asked for a workstation secure channel, but is not a workstation (member server) acb flags: 0x%x\n", user_account_control));			return NT_STATUS_ACCESS_DENIED;		}	} else if (r->in.secure_channel_type == SEC_CHAN_DOMAIN) {		if (!(user_account_control & UF_INTERDOMAIN_TRUST_ACCOUNT)) {			DEBUG(1, ("Client asked for a trusted domain secure channel, but is not a trusted domain: acb flags: 0x%x\n", user_account_control));						return NT_STATUS_ACCESS_DENIED;		}	} else if (r->in.secure_channel_type == SEC_CHAN_BDC) {		if (!(user_account_control & UF_SERVER_TRUST_ACCOUNT)) {			DEBUG(1, ("Client asked for a server secure channel, but is not a server (domain controller): acb flags: 0x%x\n", user_account_control));			return NT_STATUS_ACCESS_DENIED;		}	} else {		DEBUG(1, ("Client asked for an invalid secure channel type: %d\n", 			  r->in.secure_channel_type));		return NT_STATUS_ACCESS_DENIED;	}	*r->out.rid = samdb_result_rid_from_sid(mem_ctx, msgs[0], 						"objectSid", 0);	mach_pwd = samdb_result_hash(mem_ctx, msgs[0], "unicodePwd");	if (mach_pwd == NULL) {		return NT_STATUS_ACCESS_DENIED;	}	creds = talloc(mem_ctx, struct creds_CredentialState);	NT_STATUS_HAVE_NO_MEMORY(creds);	creds_server_init(creds, &pipe_state->client_challenge, 			  &pipe_state->server_challenge, mach_pwd,			  r->out.credentials,			  *r->in.negotiate_flags);		if (!creds_server_check(creds, r->in.credentials)) {		talloc_free(creds);		return NT_STATUS_ACCESS_DENIED;	}	creds->account_name = talloc_steal(creds, r->in.account_name);		creds->computer_name = talloc_steal(creds, r->in.computer_name);	creds->domain = talloc_strdup(creds, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx));	creds->secure_channel_type = r->in.secure_channel_type;	creds->sid = samdb_result_dom_sid(creds, msgs[0], "objectSid");	/* remember this session key state */	nt_status = schannel_store_session_key(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, creds);	return nt_status;}						 static NTSTATUS dcesrv_netr_ServerAuthenticate(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,					struct netr_ServerAuthenticate *r){	struct netr_ServerAuthenticate3 r3;	uint32_t rid = 0;	/* TODO: 	 * negotiate_flags is used as an [in] parameter	 * so it need to be initialised.	 *	 * (I think ... = 0; seems wrong here --metze)	 */	uint32_t negotiate_flags = 0;  	r3.in.server_name = r->in.server_name;	r3.in.account_name = r->in.account_name;	r3.in.secure_channel_type = r->in.secure_channel_type;	r3.in.computer_name = r->in.computer_name;	r3.in.credentials = r->in.credentials;	r3.out.credentials = r->out.credentials;	r3.in.negotiate_flags = &negotiate_flags;	r3.out.negotiate_flags = &negotiate_flags;	r3.out.rid = &rid;		return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3);}static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,					 struct netr_ServerAuthenticate2 *r){	struct netr_ServerAuthenticate3 r3;	uint32_t rid = 0;	r3.in.server_name = r->in.server_name;	r3.in.account_name = r->in.account_name;	r3.in.secure_channel_type = r->in.secure_channel_type;	r3.in.computer_name = r->in.computer_name;	r3.in.credentials = r->in.credentials;	r3.out.credentials = r->out.credentials;	r3.in.negotiate_flags = r->in.negotiate_flags;	r3.out.negotiate_flags = r->out.negotiate_flags;	r3.out.rid = &rid;		return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3);}/*  Validate an incoming authenticator against the credentials for the remote machine.  The credentials are (re)read and from the schannel database, and  written back after the caclulations are performed.  The creds_out parameter (if not NULL) returns the credentials, if  the caller needs some of that information.*/static NTSTATUS dcesrv_netr_creds_server_step_check(struct event_context *event_ctx, 						    struct loadparm_context *lp_ctx,						    const char *computer_name,					     TALLOC_CTX *mem_ctx, 					     struct netr_Authenticator *received_authenticator,					     struct netr_Authenticator *return_authenticator,					     struct creds_CredentialState **creds_out) {	struct creds_CredentialState *creds;	NTSTATUS nt_status;	struct ldb_context *ldb;	int ret;	ldb = schannel_db_connect(mem_ctx, event_ctx, lp_ctx);	if (!ldb) {		return NT_STATUS_ACCESS_DENIED;	}	ret = ldb_transaction_start(ldb);	if (ret != 0) {		talloc_free(ldb);		return NT_STATUS_INTERNAL_DB_CORRUPTION;	}	/* Because this is a shared structure (even across	 * disconnects) we must update the database every time we	 * update the structure */ 		nt_status = schannel_fetch_session_key_ldb(ldb, ldb, computer_name, 						   lp_workgroup(lp_ctx),						   &creds);	if (NT_STATUS_IS_OK(nt_status)) {		nt_status = creds_server_step_check(creds, 						    received_authenticator, 						    return_authenticator);	}	if (NT_STATUS_IS_OK(nt_status)) {		nt_status = schannel_store_session_key_ldb(ldb, ldb, creds);	}	if (NT_STATUS_IS_OK(nt_status)) {		ldb_transaction_commit(ldb);		if (creds_out) {			*creds_out = creds;			talloc_steal(mem_ctx, creds);		}	} else {		ldb_transaction_cancel(ldb);	}	talloc_free(ldb);	return nt_status;}/*   Change the machine account password for the currently connected  client.  Supplies only the NT#.*/static NTSTATUS dcesrv_netr_ServerPasswordSet(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,				       struct netr_ServerPasswordSet *r){	struct creds_CredentialState *creds;	struct ldb_context *sam_ctx;	NTSTATUS nt_status;	nt_status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,							r->in.computer_name, mem_ctx, 						 &r->in.credential, &r->out.return_authenticator,						 &creds);	NT_STATUS_NOT_OK_RETURN(nt_status);	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));	if (sam_ctx == NULL) {		return NT_STATUS_INVALID_SYSTEM_SERVICE;	}	creds_des_decrypt(creds, &r->in.new_password);	/* Using the sid for the account as the key, set the password */	nt_status = samdb_set_password_sid(sam_ctx, mem_ctx, 					   creds->sid,					   NULL, /* Don't have plaintext */					   NULL, &r->in.new_password,					   false, /* This is not considered a password change */					   NULL, NULL);	return nt_status;}/*   Change the machine account password for the currently connected  client.  Supplies new plaintext.*/static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,				       struct netr_ServerPasswordSet2 *r){	struct creds_CredentialState *creds;	struct ldb_context *sam_ctx;	NTSTATUS nt_status;	char new_pass[512];	uint32_t new_pass_len;	bool ret;	struct samr_CryptPassword password_buf;	nt_status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,							r->in.computer_name, mem_ctx, 						 &r->in.credential, &r->out.return_authenticator,						 &creds);	NT_STATUS_NOT_OK_RETURN(nt_status);	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));	if (sam_ctx == NULL) {		return NT_STATUS_INVALID_SYSTEM_SERVICE;	}	memcpy(password_buf.data, r->in.new_password.data, 512);	SIVAL(password_buf.data,512,r->in.new_password.length);	creds_arcfour_crypt(creds, password_buf.data, 516);	ret = decode_pw_buffer(password_buf.data, new_pass, sizeof(new_pass),			       &new_pass_len, STR_UNICODE);	if (!ret) {		DEBUG(3,("netr_ServerPasswordSet2: failed to decode password buffer\n"));		return NT_STATUS_ACCESS_DENIED;	}	/* Using the sid for the account as the key, set the password */	nt_status = samdb_set_password_sid(sam_ctx, mem_ctx,					   creds->sid,					   new_pass, /* we have plaintext */					   NULL, NULL,					   false, /* This is not considered a password change */					   NULL, NULL);	return nt_status;}/*   netr_LogonUasLogon */static WERROR dcesrv_netr_LogonUasLogon(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,				 struct netr_LogonUasLogon *r){	DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);}/*   netr_LogonUasLogoff */static WERROR dcesrv_netr_LogonUasLogoff(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,		       struct netr_LogonUasLogoff *r){	DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);}/*   netr_LogonSamLogon_base  This version of the function allows other wrappers to say 'do not check the credentials'  We can't do the traditional 'wrapping' format completly, as this function must only run under schannel*/static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,					struct netr_LogonSamLogonEx *r, struct creds_CredentialState *creds){	struct auth_context *auth_context;	struct auth_usersupplied_info *user_info;	struct auth_serversupplied_info *server_info;	NTSTATUS nt_status;	static const char zeros[16];	struct netr_SamBaseInfo *sam;	struct netr_SamInfo2 *sam2;	struct netr_SamInfo3 *sam3;	struct netr_SamInfo6 *sam6;		user_info = talloc(mem_ctx, struct auth_usersupplied_info);	NT_STATUS_HAVE_NO_MEMORY(user_info);	user_info->flags = 0;	user_info->mapped_state = false;	user_info->remote_host = NULL;	switch (r->in.logon_level) {	case 1:

⌨️ 快捷键说明

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