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 + -
显示快捷键?