dcerpc_server.c

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

C
1,400
字号
		/* form the dcerpc response packet */		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_RESPONSE;		pkt.pfc_flags = 0;		if (stub.length == total_length) {			pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;		}		if (length == stub.length) {			pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;		}		pkt.u.response.alloc_hint = stub.length;		pkt.u.response.context_id = call->pkt.u.request.context_id;		pkt.u.response.cancel_count = 0;		pkt.u.response.stub_and_verifier.data = stub.data;		pkt.u.response.stub_and_verifier.length = length;		if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {			return dcesrv_fault(call, DCERPC_FAULT_OTHER);				}		dcerpc_set_frag_length(&rep->blob, rep->blob.length);		DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);				stub.data += length;		stub.length -= length;	} while (stub.length != 0);	/* move the call from the pending to the finished calls list */	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);	if (call->conn->call_list && call->conn->call_list->replies) {		if (call->conn->transport.report_output_data) {			call->conn->transport.report_output_data(call->conn);		}	}	return NT_STATUS_OK;}_PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx){	if (!conn->transport.get_my_addr) {		return NULL;	}	return conn->transport.get_my_addr(conn, mem_ctx);}_PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx){	if (!conn->transport.get_peer_addr) {		return NULL;	}	return conn->transport.get_peer_addr(conn, mem_ctx);}/*  work out if we have a full packet yet*/static bool dce_full_packet(const DATA_BLOB *data){	if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {		return false;	}	if (dcerpc_get_frag_length(data) > data->length) {		return false;	}	return true;}/*  we might have consumed only part of our input - advance past that part*/static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset){	DATA_BLOB blob;	if (dce_conn->partial_input.length == offset) {		data_blob_free(&dce_conn->partial_input);		return;	}	blob = dce_conn->partial_input;	dce_conn->partial_input = data_blob(blob.data + offset,					    blob.length - offset);	data_blob_free(&blob);}/*  remove the call from the right list when freed */static int dcesrv_call_dequeue(struct dcesrv_call_state *call){	dcesrv_call_set_list(call, DCESRV_LIST_NONE);	return 0;}/*  process some input to a dcerpc endpoint server.*/NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn){	struct ndr_pull *ndr;	enum ndr_err_code ndr_err;	NTSTATUS status;	struct dcesrv_call_state *call;	DATA_BLOB blob;	call = talloc_zero(dce_conn, struct dcesrv_call_state);	if (!call) {		talloc_free(dce_conn->partial_input.data);		return NT_STATUS_NO_MEMORY;	}	call->conn		= dce_conn;	call->event_ctx		= dce_conn->event_ctx;	call->msg_ctx		= dce_conn->msg_ctx;	call->state_flags	= call->conn->state_flags;	call->time		= timeval_current();	call->list              = DCESRV_LIST_NONE;	talloc_set_destructor(call, dcesrv_call_dequeue);	blob = dce_conn->partial_input;	blob.length = dcerpc_get_frag_length(&blob);	ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));	if (!ndr) {		talloc_free(dce_conn->partial_input.data);		talloc_free(call);		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, &call->pkt);	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {		talloc_free(dce_conn->partial_input.data);		talloc_free(call);		return ndr_map_error2ntstatus(ndr_err);	}	/* we have to check the signing here, before combining the	   pdus */	if (call->pkt.ptype == DCERPC_PKT_REQUEST &&	    !dcesrv_auth_request(call, &blob)) {		dce_partial_advance(dce_conn, blob.length);		return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);			}	dce_partial_advance(dce_conn, blob.length);	/* see if this is a continued packet */	if (call->pkt.ptype == DCERPC_PKT_REQUEST &&	    !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {		struct dcesrv_call_state *call2 = call;		uint32_t alloc_size;		/* we only allow fragmented requests, no other packet types */		if (call->pkt.ptype != DCERPC_PKT_REQUEST) {			return dcesrv_fault(call2, DCERPC_FAULT_OTHER);		}		/* this is a continuation of an existing call - find the call then		   tack it on the end */		call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);		if (!call) {			return dcesrv_fault(call2, DCERPC_FAULT_OTHER);		}		if (call->pkt.ptype != call2->pkt.ptype) {			/* trying to play silly buggers are we? */			return dcesrv_fault(call2, DCERPC_FAULT_OTHER);		}		alloc_size = call->pkt.u.request.stub_and_verifier.length +			call2->pkt.u.request.stub_and_verifier.length;		if (call->pkt.u.request.alloc_hint > alloc_size) {			alloc_size = call->pkt.u.request.alloc_hint;		}		call->pkt.u.request.stub_and_verifier.data = 			talloc_realloc(call, 				       call->pkt.u.request.stub_and_verifier.data, 				       uint8_t, alloc_size);		if (!call->pkt.u.request.stub_and_verifier.data) {			return dcesrv_fault(call2, DCERPC_FAULT_OTHER);		}		memcpy(call->pkt.u.request.stub_and_verifier.data +		       call->pkt.u.request.stub_and_verifier.length,		       call2->pkt.u.request.stub_and_verifier.data,		       call2->pkt.u.request.stub_and_verifier.length);		call->pkt.u.request.stub_and_verifier.length += 			call2->pkt.u.request.stub_and_verifier.length;		call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);		talloc_free(call2);	}	/* this may not be the last pdu in the chain - if its isn't then	   just put it on the incoming_fragmented_call_list and wait for the rest */	if (call->pkt.ptype == DCERPC_PKT_REQUEST &&	    !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {		dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);		return NT_STATUS_OK;	} 		/* This removes any fragments we may have had stashed away */	dcesrv_call_set_list(call, DCESRV_LIST_NONE);	switch (call->pkt.ptype) {	case DCERPC_PKT_BIND:		status = dcesrv_bind(call);		break;	case DCERPC_PKT_AUTH3:		status = dcesrv_auth3(call);		break;	case DCERPC_PKT_ALTER:		status = dcesrv_alter(call);		break;	case DCERPC_PKT_REQUEST:		status = dcesrv_request(call);		break;	default:		status = NT_STATUS_INVALID_PARAMETER;		break;	}	/* if we are going to be sending a reply then add	   it to the list of pending calls. We add it to the end to keep the call	   list in the order we will answer */	if (!NT_STATUS_IS_OK(status)) {		talloc_free(call);	}	return status;}/*  provide some input to a dcerpc endpoint server. This passes data  from a dcerpc client into the server*/_PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data){	NTSTATUS status;	dce_conn->partial_input.data = talloc_realloc(dce_conn,						      dce_conn->partial_input.data,						      uint8_t,						      dce_conn->partial_input.length + data->length);	if (!dce_conn->partial_input.data) {		return NT_STATUS_NO_MEMORY;	}	memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,	       data->data, data->length);	dce_conn->partial_input.length += data->length;	while (dce_full_packet(&dce_conn->partial_input)) {		status = dcesrv_input_process(dce_conn);		if (!NT_STATUS_IS_OK(status)) {			return status;		}	}	return NT_STATUS_OK;}/*  retrieve some output from a dcerpc server  The caller supplies a function that will be called to do the  actual output.   The first argument to write_fn() will be 'private', the second will  be a pointer to a buffer containing the data to be sent and the 3rd  will be a pointer to a size_t variable that will be set to the  number of bytes that are consumed from the output.  from the current fragment*/_PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 		       void *private_data,		       NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten)){	NTSTATUS status;	struct dcesrv_call_state *call;	struct data_blob_list_item *rep;	size_t nwritten;	call = dce_conn->call_list;	if (!call || !call->replies) {		if (dce_conn->pending_call_list) {			/* TODO: we need to say act async here			 *       as we know we have pending requests			 *	 which will be finished at a time			 */			return NT_STATUS_FOOBAR;		}		return NT_STATUS_FOOBAR;	}	rep = call->replies;	status = write_fn(private_data, &rep->blob, &nwritten);	NT_STATUS_IS_ERR_RETURN(status);	rep->blob.length -= nwritten;	rep->blob.data += nwritten;	if (rep->blob.length == 0) {		/* we're done with this section of the call */		DLIST_REMOVE(call->replies, rep);	}	if (call->replies == NULL) {		/* we're done with the whole call */		dcesrv_call_set_list(call, DCESRV_LIST_NONE);		talloc_free(call);	}	return status;}_PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 				      struct loadparm_context *lp_ctx,				      const char **endpoint_servers, struct dcesrv_context **_dce_ctx){	NTSTATUS status;	struct dcesrv_context *dce_ctx;	int i;	if (!endpoint_servers) {		DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));		return NT_STATUS_INTERNAL_ERROR;	}	dce_ctx = talloc(mem_ctx, struct dcesrv_context);	NT_STATUS_HAVE_NO_MEMORY(dce_ctx);	dce_ctx->endpoint_list	= NULL;	dce_ctx->lp_ctx = lp_ctx;	for (i=0;endpoint_servers[i];i++) {		const struct dcesrv_endpoint_server *ep_server;		ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);		if (!ep_server) {			DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));			return NT_STATUS_INTERNAL_ERROR;		}		status = ep_server->init_server(dce_ctx, ep_server);		if (!NT_STATUS_IS_OK(status)) {			DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],				nt_errstr(status)));			return status;		}	}	*_dce_ctx = dce_ctx;	return NT_STATUS_OK;}/* the list of currently registered DCERPC endpoint servers. */static struct ep_server {	struct dcesrv_endpoint_server *ep_server;} *ep_servers = NULL;static int num_ep_servers;/*  register a DCERPC endpoint server.   The 'name' can be later used by other backends to find the operations  structure for this backend.    The 'type' is used to specify whether this is for a disk, printer or IPC$ share*/_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server){	const struct dcesrv_endpoint_server *ep_server = _ep_server;		if (dcesrv_ep_server_byname(ep_server->name) != NULL) {		/* its already registered! */		DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 			 ep_server->name));		return NT_STATUS_OBJECT_NAME_COLLISION;	}	ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);	if (!ep_servers) {		smb_panic("out of memory in dcerpc_register");	}	ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));	ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);	num_ep_servers++;	DEBUG(3,("DCERPC endpoint server '%s' registered\n", 		 ep_server->name));	return NT_STATUS_OK;}/*  return the operations structure for a named backend of the specified type*/const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name){	int i;	for (i=0;i<num_ep_servers;i++) {		if (strcmp(ep_servers[i].ep_server->name, name) == 0) {			return ep_servers[i].ep_server;		}	}	return NULL;}/*  return the DCERPC module version, and the size of some critical types  This can be used by endpoint server modules to either detect compilation errors, or provide  multiple implementations for different smbd compilation options in one module*/const struct dcesrv_critical_sizes *dcerpc_module_version(void){	static const struct dcesrv_critical_sizes critical_sizes = {		DCERPC_MODULE_VERSION,		sizeof(struct dcesrv_context),		sizeof(struct dcesrv_endpoint),		sizeof(struct dcesrv_endpoint_server),		sizeof(struct dcesrv_interface),		sizeof(struct dcesrv_if_list),		sizeof(struct dcesrv_connection),		sizeof(struct dcesrv_call_state),		sizeof(struct dcesrv_auth),		sizeof(struct dcesrv_handle)	};	return &critical_sizes;}/*  initialise the dcerpc server context for ncacn_np based services*/_PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,					  struct dcesrv_context **_dce_ctx){	NTSTATUS status;	struct dcesrv_context *dce_ctx;	status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);	NT_STATUS_NOT_OK_RETURN(status);	*_dce_ctx = dce_ctx;	return NT_STATUS_OK;}

⌨️ 快捷键说明

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