dcerpc_server.c

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

C
1,400
字号
/*    Unix SMB/CIFS implementation.   server side dcerpc core code   Copyright (C) Andrew Tridgell 2003-2005   Copyright (C) Stefan (metze) Metzmacher 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 "librpc/gen_ndr/ndr_dcerpc.h"#include "auth/auth.h"#include "auth/gensec/gensec.h"#include "lib/util/dlinklist.h"#include "rpc_server/dcerpc_server.h"#include "rpc_server/dcerpc_server_proto.h"#include "librpc/rpc/dcerpc_proto.h"#include "lib/events/events.h"#include "smbd/service_task.h"#include "smbd/service_stream.h"#include "smbd/service.h"#include "system/filesys.h"#include "libcli/security/security.h"#include "param/param.h"extern const struct dcesrv_interface dcesrv_mgmt_interface;/*  see if two endpoints match*/static bool endpoints_match(const struct dcerpc_binding *ep1,			    const struct dcerpc_binding *ep2){	if (ep1->transport != ep2->transport) {		return false;	}	if (!ep1->endpoint || !ep2->endpoint) {		return ep1->endpoint == ep2->endpoint;	}	if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) 		return false;	return true;}/*  find an endpoint in the dcesrv_context*/static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,					     const struct dcerpc_binding *ep_description){	struct dcesrv_endpoint *ep;	for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {		if (endpoints_match(ep->ep_description, ep_description)) {			return ep;		}	}	return NULL;}/*  find a registered context_id from a bind or alter_context*/static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn, 								   uint32_t context_id){	struct dcesrv_connection_context *c;	for (c=conn->contexts;c;c=c->next) {		if (c->context_id == context_id) return c;	}	return NULL;}/*  see if a uuid and if_version match to an interface*/static bool interface_match(const struct dcesrv_interface *if1,							const struct dcesrv_interface *if2){	return (if1->syntax_id.if_version == if2->syntax_id.if_version && 			GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));}/*  find the interface operations on an endpoint*/static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,						     const struct dcesrv_interface *iface){	struct dcesrv_if_list *ifl;	for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {		if (interface_match(&(ifl->iface), iface)) {			return &(ifl->iface);		}	}	return NULL;}/*  see if a uuid and if_version match to an interface*/static bool interface_match_by_uuid(const struct dcesrv_interface *iface,				    const struct GUID *uuid, uint32_t if_version){	return (iface->syntax_id.if_version == if_version && 			GUID_equal(&iface->syntax_id.uuid, uuid));}/*  find the interface operations on an endpoint by uuid*/static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,							     const struct GUID *uuid, uint32_t if_version){	struct dcesrv_if_list *ifl;	for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {		if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {			return &(ifl->iface);		}	}	return NULL;}/*  find the earlier parts of a fragmented call awaiting reassembily*/static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id){	struct dcesrv_call_state *c;	for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {		if (c->pkt.call_id == call_id) {			return c;		}	}	return NULL;}/*  register an interface on an endpoint*/_PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,				   const char *ep_name,				   const struct dcesrv_interface *iface,				   const struct security_descriptor *sd){	struct dcesrv_endpoint *ep;	struct dcesrv_if_list *ifl;	struct dcerpc_binding *binding;	bool add_ep = false;	NTSTATUS status;		status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);	if (NT_STATUS_IS_ERR(status)) {		DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));		return status;	}	/* check if this endpoint exists	 */	if ((ep=find_endpoint(dce_ctx, binding))==NULL) {		ep = talloc(dce_ctx, struct dcesrv_endpoint);		if (!ep) {			return NT_STATUS_NO_MEMORY;		}		ZERO_STRUCTP(ep);		ep->ep_description = talloc_reference(ep, binding);		add_ep = true;		/* add mgmt interface */		ifl = talloc(dce_ctx, struct dcesrv_if_list);		if (!ifl) {			return NT_STATUS_NO_MEMORY;		}		memcpy(&(ifl->iface), &dcesrv_mgmt_interface, 			   sizeof(struct dcesrv_interface));		DLIST_ADD(ep->interface_list, ifl);	}	/* see if the interface is already registered on te endpoint */	if (find_interface(ep, iface)!=NULL) {		DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",			iface->name, ep_name));		return NT_STATUS_OBJECT_NAME_COLLISION;	}	/* talloc a new interface list element */	ifl = talloc(dce_ctx, struct dcesrv_if_list);	if (!ifl) {		return NT_STATUS_NO_MEMORY;	}	/* copy the given interface struct to the one on the endpoints interface list */	memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));	/* if we have a security descriptor given,	 * we should see if we can set it up on the endpoint	 */	if (sd != NULL) {		/* if there's currently no security descriptor given on the endpoint		 * we try to set it		 */		if (ep->sd == NULL) {			ep->sd = security_descriptor_copy(dce_ctx, sd);		}		/* if now there's no security descriptor given on the endpoint		 * something goes wrong, either we failed to copy the security descriptor		 * or there was already one on the endpoint		 */		if (ep->sd != NULL) {			DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"			         "                           on endpoint '%s'\n",				iface->name, ep_name));			if (add_ep) free(ep);			free(ifl);			return NT_STATUS_OBJECT_NAME_COLLISION;		}	}	/* finally add the interface on the endpoint */	DLIST_ADD(ep->interface_list, ifl);	/* if it's a new endpoint add it to the dcesrv_context */	if (add_ep) {		DLIST_ADD(dce_ctx->endpoint_list, ep);	}	DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",		iface->name, ep_name));	return NT_STATUS_OK;}static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,					      DATA_BLOB *session_key){	if (p->auth_state.session_info->session_key.length) {		*session_key = p->auth_state.session_info->session_key;		return NT_STATUS_OK;	}	return NT_STATUS_NO_USER_SESSION_KEY;}NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,				    DATA_BLOB *session_key){	/* this took quite a few CPU cycles to find ... */	session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");	session_key->length = 16;	return NT_STATUS_OK;}/*  fetch the user session key - may be default (above) or the SMB session key*/_PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,				  DATA_BLOB *session_key){	return p->auth_state.session_key(p, session_key);}/*  destroy a link to an endpoint*/static int dcesrv_endpoint_destructor(struct dcesrv_connection *p){	while (p->contexts) {		struct dcesrv_connection_context *c = p->contexts;		DLIST_REMOVE(p->contexts, c);		if (c->iface) {			c->iface->unbind(c, c->iface);		}	}	return 0;}/*  connect to a dcerpc endpoint*/_PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,				 TALLOC_CTX *mem_ctx,				 const struct dcesrv_endpoint *ep,				 struct auth_session_info *session_info,				 struct event_context *event_ctx,				 struct messaging_context *msg_ctx,				 struct server_id server_id,				 uint32_t state_flags,				 struct dcesrv_connection **_p){	struct dcesrv_connection *p;	if (!session_info) {		return NT_STATUS_ACCESS_DENIED;	}	p = talloc(mem_ctx, struct dcesrv_connection);	NT_STATUS_HAVE_NO_MEMORY(p);	if (!talloc_reference(p, session_info)) {		talloc_free(p);		return NT_STATUS_NO_MEMORY;	}	p->dce_ctx = dce_ctx;	p->endpoint = ep;	p->contexts = NULL;	p->call_list = NULL;	p->incoming_fragmented_call_list = NULL;	p->pending_call_list = NULL;	p->cli_max_recv_frag = 0;	p->partial_input = data_blob(NULL, 0);	p->auth_state.auth_info = NULL;	p->auth_state.gensec_security = NULL;	p->auth_state.session_info = session_info;	p->auth_state.session_key = dcesrv_generic_session_key;	p->event_ctx = event_ctx;	p->msg_ctx = msg_ctx;	p->server_id = server_id;	p->processing = false;	p->state_flags = state_flags;	ZERO_STRUCT(p->transport);	talloc_set_destructor(p, dcesrv_endpoint_destructor);	*_p = p;	return NT_STATUS_OK;}/*  search and connect to a dcerpc endpoint*/_PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,					TALLOC_CTX *mem_ctx,					const struct dcerpc_binding *ep_description,					struct auth_session_info *session_info,					struct event_context *event_ctx,					struct messaging_context *msg_ctx,					struct server_id server_id,					uint32_t state_flags,					struct dcesrv_connection **dce_conn_p){	NTSTATUS status;	const struct dcesrv_endpoint *ep;	/* make sure this endpoint exists */	ep = find_endpoint(dce_ctx, ep_description);	if (!ep) {		return NT_STATUS_OBJECT_NAME_NOT_FOUND;	}	status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,					 event_ctx, msg_ctx, server_id,					 state_flags, dce_conn_p);	NT_STATUS_NOT_OK_RETURN(status);	(*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;	/* TODO: check security descriptor of the endpoint here 	 *       if it's a smb named pipe	 *	 if it's failed free dce_conn_p	 */	return NT_STATUS_OK;}static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian){	pkt->rpc_vers = 5;	pkt->rpc_vers_minor = 0;	if (bigendian) {		pkt->drep[0] = 0;	} else {		pkt->drep[0] = DCERPC_DREP_LE;	}	pkt->drep[1] = 0;	pkt->drep[2] = 0;	pkt->drep[3] = 0;}/*  move a call from an existing linked list to the specified list. This  prevents bugs where we forget to remove the call from a previous  list when moving it. */static void dcesrv_call_set_list(struct dcesrv_call_state *call, 				 enum dcesrv_call_list list){	switch (call->list) {	case DCESRV_LIST_NONE:		break;	case DCESRV_LIST_CALL_LIST:		DLIST_REMOVE(call->conn->call_list, call);		break;	case DCESRV_LIST_FRAGMENTED_CALL_LIST:		DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);		break;	case DCESRV_LIST_PENDING_CALL_LIST:		DLIST_REMOVE(call->conn->pending_call_list, call);		break;	}	call->list = list;	switch (list) {	case DCESRV_LIST_NONE:		break;	case DCESRV_LIST_CALL_LIST:		DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);		break;	case DCESRV_LIST_FRAGMENTED_CALL_LIST:		DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);		break;	case DCESRV_LIST_PENDING_CALL_LIST:		DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);		break;	}}/*  return a dcerpc fault*/static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code){	struct ncacn_packet pkt;	struct data_blob_list_item *rep;	uint8_t zeros[4];	NTSTATUS status;	/* setup a bind_ack */	dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));	pkt.auth_length = 0;	pkt.call_id = call->pkt.call_id;	pkt.ptype = DCERPC_PKT_FAULT;	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;	pkt.u.fault.alloc_hint = 0;	pkt.u.fault.context_id = 0;	pkt.u.fault.cancel_count = 0;	pkt.u.fault.status = fault_code;	ZERO_STRUCT(zeros);	pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));	rep = talloc(call, struct data_blob_list_item);	if (!rep) {		return NT_STATUS_NO_MEMORY;

⌨️ 快捷键说明

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