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

📄 dcerpc.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    Unix SMB/CIFS implementation.   raw dcerpc operations   Copyright (C) Tim Potter 2003   Copyright (C) Andrew Tridgell 2003-2005   Copyright (C) Jelmer Vernooij 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 "lib/util/dlinklist.h"#include "lib/events/events.h"#include "librpc/rpc/dcerpc.h"#include "librpc/rpc/dcerpc_proto.h"#include "librpc/gen_ndr/ndr_misc.h"#include "librpc/gen_ndr/ndr_dcerpc.h"#include "libcli/composite/composite.h"#include "auth/gensec/gensec.h"#include "param/param.h"_PUBLIC_ NTSTATUS dcerpc_init(void){	gensec_init(global_loadparm);	return NT_STATUS_OK;}static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);static void dcerpc_ship_next_request(struct dcerpc_connection *c);/* destroy a dcerpc connection */static int dcerpc_connection_destructor(struct dcerpc_connection *conn){	if (conn->dead) {		conn->free_skipped = true;		return -1;	}	dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);	return 0;}/* initialise a dcerpc connection.    the event context is optional*/static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 						 struct event_context *ev,						 struct smb_iconv_convenience *ic){	struct dcerpc_connection *c;	c = talloc_zero(mem_ctx, struct dcerpc_connection);	if (!c) {		return NULL;	}	c->iconv_convenience = talloc_reference(c, ic);	c->event_ctx = talloc_reference(c, ev);	if (c->event_ctx == NULL) {		talloc_free(c);		return NULL;	}	c->call_id = 1;	c->security_state.auth_info = NULL;	c->security_state.session_key = dcerpc_generic_session_key;	c->security_state.generic_state = NULL;	c->binding_string = NULL;	c->flags = 0;	c->srv_max_xmit_frag = 0;	c->srv_max_recv_frag = 0;	c->pending = NULL;	talloc_set_destructor(c, dcerpc_connection_destructor);	return c;}/* initialise a dcerpc pipe. */_PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev,				     struct smb_iconv_convenience *ic){	struct dcerpc_pipe *p;	p = talloc(mem_ctx, struct dcerpc_pipe);	if (!p) {		return NULL;	}	p->conn = dcerpc_connection_init(p, ev, ic);	if (p->conn == NULL) {		talloc_free(p);		return NULL;	}	p->last_fault_code = 0;	p->context_id = 0;	p->request_timeout = DCERPC_REQUEST_TIMEOUT;	p->binding = NULL;	ZERO_STRUCT(p->syntax);	ZERO_STRUCT(p->transfer_syntax);	return p;}/*    choose the next call id to use*/static uint32_t next_call_id(struct dcerpc_connection *c){	c->call_id++;	if (c->call_id == 0) {		c->call_id++;	}	return c->call_id;}/* we need to be able to get/set the fragment length without doing a full   decode */void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v){	if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {		SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);	} else {		RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);	}}uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob){	if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {		return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);	} else {		return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);	}}void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v){	if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {		SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);	} else {		RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);	}}/**  setup for a ndr pull, also setting up any flags from the binding string*/static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c, 					    DATA_BLOB *blob, TALLOC_CTX *mem_ctx){	struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);	if (ndr == NULL) return ndr;	if (c->flags & DCERPC_DEBUG_PAD_CHECK) {		ndr->flags |= LIBNDR_FLAG_PAD_CHECK;	}	if (c->flags & DCERPC_NDR_REF_ALLOC) {		ndr->flags |= LIBNDR_FLAG_REF_ALLOC;	}	return ndr;}/*    parse a data blob into a ncacn_packet structure. This handles both   input and output packets*/static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 			    struct ncacn_packet *pkt){	struct ndr_pull *ndr;	enum ndr_err_code ndr_err;	ndr = ndr_pull_init_flags(c, blob, mem_ctx);	if (!ndr) {		return NT_STATUS_NO_MEMORY;	}	if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;	}	ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {		return ndr_map_error2ntstatus(ndr_err);	}	return NT_STATUS_OK;}/*  generate a CONNECT level verifier*/static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob){	*blob = data_blob_talloc(mem_ctx, NULL, 16);	if (blob->data == NULL) {		return NT_STATUS_NO_MEMORY;	}	SIVAL(blob->data, 0, 1);	memset(blob->data+4, 0, 12);	return NT_STATUS_OK;}/*  check a CONNECT level verifier*/static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob){	if (blob->length != 16 ||	    IVAL(blob->data, 0) != 1) {		return NT_STATUS_ACCESS_DENIED;	}	return NT_STATUS_OK;}/*    parse the authentication information on a dcerpc response packet*/static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx, 					DATA_BLOB *raw_packet,					struct ncacn_packet *pkt){	struct ndr_pull *ndr;	NTSTATUS status;	struct dcerpc_auth auth;	DATA_BLOB auth_blob;	enum ndr_err_code ndr_err;	if (pkt->auth_length == 0 &&	    c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {		return NT_STATUS_OK;	}	auth_blob.length = 8 + pkt->auth_length;	/* check for a valid length */	if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {		return NT_STATUS_INFO_LENGTH_MISMATCH;	}	auth_blob.data = 		pkt->u.response.stub_and_verifier.data + 		pkt->u.response.stub_and_verifier.length - auth_blob.length;	pkt->u.response.stub_and_verifier.length -= auth_blob.length;	/* pull the auth structure */	ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);	if (!ndr) {		return NT_STATUS_NO_MEMORY;	}	if (!(pkt->drep[0] & DCERPC_DREP_LE)) {		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;	}	ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {		return ndr_map_error2ntstatus(ndr_err);	}	status = NT_STATUS_OK;	/* check signature or unseal the packet */	switch (c->security_state.auth_info->auth_level) {	case DCERPC_AUTH_LEVEL_PRIVACY:		status = gensec_unseal_packet(c->security_state.generic_state, 					      mem_ctx, 					      raw_packet->data + DCERPC_REQUEST_LENGTH,					      pkt->u.response.stub_and_verifier.length, 					      raw_packet->data,					      raw_packet->length - auth.credentials.length,					      &auth.credentials);		memcpy(pkt->u.response.stub_and_verifier.data,		       raw_packet->data + DCERPC_REQUEST_LENGTH,		       pkt->u.response.stub_and_verifier.length);		break;			case DCERPC_AUTH_LEVEL_INTEGRITY:		status = gensec_check_packet(c->security_state.generic_state, 					     mem_ctx, 					     pkt->u.response.stub_and_verifier.data, 					     pkt->u.response.stub_and_verifier.length, 					     raw_packet->data,					     raw_packet->length - auth.credentials.length,					     &auth.credentials);		break;	case DCERPC_AUTH_LEVEL_CONNECT:		status = dcerpc_check_connect_verifier(&auth.credentials);		break;	case DCERPC_AUTH_LEVEL_NONE:		break;	default:		status = NT_STATUS_INVALID_LEVEL;		break;	}		/* remove the indicated amount of paddiing */	if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {		return NT_STATUS_INFO_LENGTH_MISMATCH;	}	pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;	return status;}/*    push a dcerpc request packet into a blob, possibly signing it.*/static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, 					 DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 					 struct ncacn_packet *pkt){	NTSTATUS status;	struct ndr_push *ndr;	DATA_BLOB creds2;	size_t payload_length;	enum ndr_err_code ndr_err;	/* non-signed packets are simpler */	if (!c->security_state.auth_info || 	    !c->security_state.generic_state) {		return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, c->security_state.auth_info);	}	ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);	if (!ndr) {		return NT_STATUS_NO_MEMORY;	}	if (c->flags & DCERPC_PUSH_BIGENDIAN) {		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;	}	if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {		ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;	}	ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {		return ndr_map_error2ntstatus(ndr_err);	}	status = NT_STATUS_OK;	/* pad to 16 byte multiple in the payload portion of the	   packet. This matches what w2k3 does */	c->security_state.auth_info->auth_pad_length = 		(16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;	ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);	payload_length = pkt->u.request.stub_and_verifier.length + 		c->security_state.auth_info->auth_pad_length;	/* sign or seal the packet */	switch (c->security_state.auth_info->auth_level) {	case DCERPC_AUTH_LEVEL_PRIVACY:	case DCERPC_AUTH_LEVEL_INTEGRITY:		/* We hope this length is accruate.  If must be if the		 * GENSEC mech does AEAD signing of the packet		 * headers */		c->security_state.auth_info->credentials			= data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state, 									  payload_length));		data_blob_clear(&c->security_state.auth_info->credentials);		break;	case DCERPC_AUTH_LEVEL_CONNECT:		status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);		break;			case DCERPC_AUTH_LEVEL_NONE:		c->security_state.auth_info->credentials = data_blob(NULL, 0);		break;			default:		status = NT_STATUS_INVALID_LEVEL;		break;	}		if (!NT_STATUS_IS_OK(status)) {		return status;	}		/* add the auth verifier */	ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {		return ndr_map_error2ntstatus(ndr_err);	}	status = NT_STATUS_OK;	/* extract the whole packet as a blob */	*blob = ndr_push_blob(ndr);	/* fill in the fragment length and auth_length, we can't fill	   in these earlier as we don't know the signature length (it	   could be variable length) */	dcerpc_set_frag_length(blob, blob->length);	/* We hope this value is accruate.  If must be if the GENSEC	 * mech does AEAD signing of the packet headers */	dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);	/* sign or seal the packet */	switch (c->security_state.auth_info->auth_level) {	case DCERPC_AUTH_LEVEL_PRIVACY:		status = gensec_seal_packet(c->security_state.generic_state, 					    mem_ctx, 					    blob->data + DCERPC_REQUEST_LENGTH, 					    payload_length,					    blob->data,					    blob->length - 					    c->security_state.auth_info->credentials.length,					    &creds2);		if (!NT_STATUS_IS_OK(status)) {			return status;		}		blob->length -= c->security_state.auth_info->credentials.length;		if (!data_blob_append(mem_ctx, blob,					  creds2.data, creds2.length)) {			return NT_STATUS_NO_MEMORY;		}		dcerpc_set_auth_length(blob, creds2.length);		if (c->security_state.auth_info->credentials.length == 0) {			/* this is needed for krb5 only, to correct the total packet			   length */			dcerpc_set_frag_length(blob, 					       dcerpc_get_frag_length(blob)					       +creds2.length);		}		break;	case DCERPC_AUTH_LEVEL_INTEGRITY:		status = gensec_sign_packet(c->security_state.generic_state, 					    mem_ctx, 					    blob->data + DCERPC_REQUEST_LENGTH, 					    payload_length, 					    blob->data,					    blob->length - 					    c->security_state.auth_info->credentials.length,					    &creds2);		if (!NT_STATUS_IS_OK(status)) {			return status;		}		blob->length -= c->security_state.auth_info->credentials.length;		if (!data_blob_append(mem_ctx, blob,					  creds2.data, creds2.length)) {			return NT_STATUS_NO_MEMORY;		}		dcerpc_set_auth_length(blob, creds2.length);		if (c->security_state.auth_info->credentials.length == 0) {			/* this is needed for krb5 only, to correct the total packet			   length */			dcerpc_set_frag_length(blob, 					       dcerpc_get_frag_length(blob)					       +creds2.length);		}		break;	case DCERPC_AUTH_LEVEL_CONNECT:		break;	case DCERPC_AUTH_LEVEL_NONE:		c->security_state.auth_info->credentials = data_blob(NULL, 0);		break;	default:		status = NT_STATUS_INVALID_LEVEL;		break;	}	data_blob_free(&c->security_state.auth_info->credentials);	return NT_STATUS_OK;}/*    fill in the fixed values in a dcerpc header */static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt){	pkt->rpc_vers = 5;	pkt->rpc_vers_minor = 0;	if (c->flags & DCERPC_PUSH_BIGENDIAN) {		pkt->drep[0] = 0;	} else {		pkt->drep[0] = DCERPC_DREP_LE;	}	pkt->drep[1] = 0;	pkt->drep[2] = 0;	pkt->drep[3] = 0;}/*  map a bind nak reason to a NTSTATUS*/static NTSTATUS dcerpc_map_reason(uint16_t reason){	switch (reason) {	case DCERPC_BIND_REASON_ASYNTAX:		return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;	case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:		return NT_STATUS_INVALID_PARAMETER;	}	return NT_STATUS_UNSUCCESSFUL;}/*  a bind or alter context has failed*/static void dcerpc_composite_fail(struct rpc_request *req){	struct composite_context *c = talloc_get_type(req->async.private_data, 						      struct composite_context);	composite_error(c, req->status);}/*  remove requests from the pending or queued queues */static int dcerpc_req_dequeue(struct rpc_request *req){	switch (req->state) {	case RPC_REQUEST_QUEUED:		DLIST_REMOVE(req->p->conn->request_queue, req);		break;	case RPC_REQUEST_PENDING:		DLIST_REMOVE(req->p->conn->pending, req);		break;	case RPC_REQUEST_DONE:		break;	}	return 0;}/*  mark the dcerpc connection dead. All outstanding requests get an error*/static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status){

⌨️ 快捷键说明

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