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