dcerpc_server.c

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

C
1,400
字号
	}	status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);	if (!NT_STATUS_IS_OK(status)) {		return status;	}	dcerpc_set_frag_length(&rep->blob, rep->blob.length);	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);	return NT_STATUS_OK;	}/*  return a dcerpc bind_nak*/static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason){	struct ncacn_packet pkt;	struct data_blob_list_item *rep;	NTSTATUS status;	/* setup a bind_nak */	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_BIND_NAK;	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;	pkt.u.bind_nak.reject_reason = reason;	if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {		pkt.u.bind_nak.versions.v.num_versions = 0;	}	rep = talloc(call, struct data_blob_list_item);	if (!rep) {		return NT_STATUS_NO_MEMORY;	}	status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);	if (!NT_STATUS_IS_OK(status)) {		return status;	}	dcerpc_set_frag_length(&rep->blob, rep->blob.length);	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);	return NT_STATUS_OK;	}/*  handle a bind request*/static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call){	uint32_t if_version, transfer_syntax_version;	struct GUID uuid, *transfer_syntax_uuid;	struct ncacn_packet pkt;	struct data_blob_list_item *rep;	NTSTATUS status;	uint32_t result=0, reason=0;	uint32_t context_id;	const struct dcesrv_interface *iface;	if (call->pkt.u.bind.assoc_group_id != 0) {		return dcesrv_bind_nak(call, 0);		}	if (call->pkt.u.bind.num_contexts < 1 ||	    call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {		return dcesrv_bind_nak(call, 0);	}	context_id = call->pkt.u.bind.ctx_list[0].context_id;	/* you can't bind twice on one context */	if (dcesrv_find_context(call->conn, context_id) != NULL) {		return dcesrv_bind_nak(call, 0);	}	if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;	uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;	transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;	transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;	if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||	    ndr_transfer_syntax.if_version != transfer_syntax_version) {		char *uuid_str = GUID_string(call, transfer_syntax_uuid);		/* we only do NDR encoded dcerpc */		DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));		talloc_free(uuid_str);		return dcesrv_bind_nak(call, 0);	}	iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);	if (iface == NULL) {		char *uuid_str = GUID_string(call, &uuid);		DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));		talloc_free(uuid_str);		/* we don't know about that interface */		result = DCERPC_BIND_PROVIDER_REJECT;		reason = DCERPC_BIND_REASON_ASYNTAX;			}	if (iface) {		/* add this context to the list of available context_ids */		struct dcesrv_connection_context *context = talloc(call->conn, 								   struct dcesrv_connection_context);		if (context == NULL) {			return dcesrv_bind_nak(call, 0);		}		context->conn = call->conn;		context->iface = iface;		context->context_id = context_id;		context->private = NULL;		context->handles = NULL;		DLIST_ADD(call->conn->contexts, context);		call->context = context;	}	if (call->conn->cli_max_recv_frag == 0) {		call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;	}	/* handle any authentication that is being requested */	if (!dcesrv_auth_bind(call)) {		return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);	}	/* 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_BIND_ACK;	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;	pkt.u.bind_ack.max_xmit_frag = 0x2000;	pkt.u.bind_ack.max_recv_frag = 0x2000;	/* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */	pkt.u.bind_ack.assoc_group_id = 0x12345678;	if (iface) {		/* FIXME: Use pipe name as specified by endpoint instead of interface name */		pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);	} else {		pkt.u.bind_ack.secondary_address = "";	}	pkt.u.bind_ack.num_results = 1;	pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);	if (!pkt.u.bind_ack.ctx_list) {		return NT_STATUS_NO_MEMORY;	}	pkt.u.bind_ack.ctx_list[0].result = result;	pkt.u.bind_ack.ctx_list[0].reason = reason;	pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;	pkt.u.bind_ack.auth_info = data_blob(NULL, 0);	status = dcesrv_auth_bind_ack(call, &pkt);	if (!NT_STATUS_IS_OK(status)) {		return dcesrv_bind_nak(call, 0);	}	if (iface) {		status = iface->bind(call, iface);		if (!NT_STATUS_IS_OK(status)) {			char *uuid_str = GUID_string(call, &uuid);			DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", 				 uuid_str, if_version, nt_errstr(status)));			talloc_free(uuid_str);			return dcesrv_bind_nak(call, 0);		}	}	rep = talloc(call, struct data_blob_list_item);	if (!rep) {		return NT_STATUS_NO_MEMORY;	}	status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);	if (!NT_STATUS_IS_OK(status)) {		return status;	}	dcerpc_set_frag_length(&rep->blob, rep->blob.length);	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);	return NT_STATUS_OK;}/*  handle a auth3 request*/static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call){	/* handle the auth3 in the auth code */	if (!dcesrv_auth_auth3(call)) {		return dcesrv_fault(call, DCERPC_FAULT_OTHER);	}	talloc_free(call);	/* we don't send a reply to a auth3 request, except by a	   fault */	return NT_STATUS_OK;}/*  handle a bind request*/static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id){	uint32_t if_version, transfer_syntax_version;	struct dcesrv_connection_context *context;	const struct dcesrv_interface *iface;	struct GUID uuid, *transfer_syntax_uuid;	NTSTATUS status;	if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;	uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;	transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;	transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;	if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||	    ndr_transfer_syntax.if_version != transfer_syntax_version) {		/* we only do NDR encoded dcerpc */		return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;	}	iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);	if (iface == NULL) {		char *uuid_str = GUID_string(call, &uuid);		DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));		talloc_free(uuid_str);		return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;	}	/* add this context to the list of available context_ids */	context = talloc(call->conn, struct dcesrv_connection_context);	if (context == NULL) {		return NT_STATUS_NO_MEMORY;	}	context->conn = call->conn;	context->iface = iface;	context->context_id = context_id;	context->private = NULL;	context->handles = NULL;	DLIST_ADD(call->conn->contexts, context);	call->context = context;	if (iface) {		status = iface->bind(call, iface);		if (!NT_STATUS_IS_OK(status)) {			return status;		}	}	return NT_STATUS_OK;}/*  handle a alter context request*/static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call){	struct ncacn_packet pkt;	struct data_blob_list_item *rep;	NTSTATUS status;	uint32_t result=0, reason=0;	uint32_t context_id;	/* handle any authentication that is being requested */	if (!dcesrv_auth_alter(call)) {		/* TODO: work out the right reject code */		result = DCERPC_BIND_PROVIDER_REJECT;		reason = DCERPC_BIND_REASON_ASYNTAX;			}	context_id = call->pkt.u.alter.ctx_list[0].context_id;	/* see if they are asking for a new interface */	if (result == 0 &&	    dcesrv_find_context(call->conn, context_id) == NULL) {		status = dcesrv_alter_new_context(call, context_id);		if (!NT_STATUS_IS_OK(status)) {			result = DCERPC_BIND_PROVIDER_REJECT;			reason = DCERPC_BIND_REASON_ASYNTAX;				}	}	/* setup a alter_resp */	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_ALTER_RESP;	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;	pkt.u.alter_resp.max_xmit_frag = 0x2000;	pkt.u.alter_resp.max_recv_frag = 0x2000;	pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;	pkt.u.alter_resp.num_results = 1;	pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);	if (!pkt.u.alter_resp.ctx_list) {		return NT_STATUS_NO_MEMORY;	}	pkt.u.alter_resp.ctx_list[0].result = result;	pkt.u.alter_resp.ctx_list[0].reason = reason;	pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;	pkt.u.alter_resp.auth_info = data_blob(NULL, 0);	pkt.u.alter_resp.secondary_address = "";	status = dcesrv_auth_alter_ack(call, &pkt);	if (!NT_STATUS_IS_OK(status)) {		if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)		    || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)		    || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)		    || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {			return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);		}		return dcesrv_fault(call, 0);	}	rep = talloc(call, struct data_blob_list_item);	if (!rep) {		return NT_STATUS_NO_MEMORY;	}	status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);	if (!NT_STATUS_IS_OK(status)) {		return status;	}	dcerpc_set_frag_length(&rep->blob, rep->blob.length);	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);	return NT_STATUS_OK;}/*  handle a dcerpc request packet*/static NTSTATUS dcesrv_request(struct dcesrv_call_state *call){	struct ndr_pull *pull;	NTSTATUS status;	struct dcesrv_connection_context *context;	/* if authenticated, and the mech we use can't do async replies, don't use them... */	if (call->conn->auth_state.gensec_security && 	    !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {		call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;	}	context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);	if (context == NULL) {		return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);	}	pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,				  lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));	NT_STATUS_HAVE_NO_MEMORY(pull);	pull->flags |= LIBNDR_FLAG_REF_ALLOC;	call->context	= context;	call->ndr_pull	= pull;	if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {		pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;	}	if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {		pull->flags |= LIBNDR_FLAG_BIGENDIAN;	}	/* unravel the NDR for the packet */	status = context->iface->ndr_pull(call, call, pull, &call->r);	if (!NT_STATUS_IS_OK(status)) {		return dcesrv_fault(call, call->fault_code);	}	if (pull->offset != pull->data_size) {		DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 			 pull->data_size - pull->offset));		dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);	}	/* call the dispatch function */	status = context->iface->dispatch(call, call, call->r);	if (!NT_STATUS_IS_OK(status)) {		DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",			 context->iface->name, 			 call->pkt.u.request.opnum,			 dcerpc_errstr(pull, call->fault_code)));		return dcesrv_fault(call, call->fault_code);	}	/* add the call to the pending list */	dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);	if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {		return NT_STATUS_OK;	}	return dcesrv_reply(call);}_PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call){	struct ndr_push *push;	NTSTATUS status;	DATA_BLOB stub;	uint32_t total_length;	struct dcesrv_connection_context *context = call->context;	/* call the reply function */	status = context->iface->reply(call, call, call->r);	if (!NT_STATUS_IS_OK(status)) {		return dcesrv_fault(call, call->fault_code);	}	/* form the reply NDR */	push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));	NT_STATUS_HAVE_NO_MEMORY(push);	/* carry over the pointer count to the reply in case we are	   using full pointer. See NDR specification for full	   pointers */	push->ptr_count = call->ndr_pull->ptr_count;	if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {		push->flags |= LIBNDR_FLAG_BIGENDIAN;	}	status = context->iface->ndr_push(call, call, push, call->r);	if (!NT_STATUS_IS_OK(status)) {		return dcesrv_fault(call, call->fault_code);	}	stub = ndr_push_blob(push);	total_length = stub.length;	do {		uint32_t length;		struct data_blob_list_item *rep;		struct ncacn_packet pkt;		rep = talloc(call, struct data_blob_list_item);		NT_STATUS_HAVE_NO_MEMORY(rep);		length = stub.length;		if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {			/* the 32 is to cope with signing data */			length = call->conn->cli_max_recv_frag - 				(DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);		}

⌨️ 快捷键说明

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