summaryrefslogtreecommitdiff
path: root/source4/rpc_server/dcerpc_server.c
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2004-01-08 22:55:27 +0000
committerStefan Metzmacher <metze@samba.org>2004-01-08 22:55:27 +0000
commit7e6cf43756b7643e2f0ee7ada5076f36f3a24bb7 (patch)
treead6aebaaf7e3da39992548925135537d66ffabaa /source4/rpc_server/dcerpc_server.c
parent8364fd2853ff4bb608157656878e05ca7984a2b9 (diff)
downloadsamba-7e6cf43756b7643e2f0ee7ada5076f36f3a24bb7.tar.gz
samba-7e6cf43756b7643e2f0ee7ada5076f36f3a24bb7.tar.bz2
samba-7e6cf43756b7643e2f0ee7ada5076f36f3a24bb7.zip
This patch adds a better dcerpc server infastructure.
1.) We now register endpoint servers add startup via register_backend() and later use the smb.conf 'dcerpc endpoint servers' parameter to setup the dcesrv_context 2.) each endpoint server can register at context creation time as much interfaces as it wants (multiple interfaces on one endpoint are supported!) (NOTE: there's a difference between 'endpoint server' and 'endpoint'! for details look at rpc_server/dcesrv_server.h) 3.) one endpoint can have a security descriptor registered to it self this will be checked in the future when a client wants to connect to an smb pipe endpoint. 4.) we now have a 'remote' endpoint server, which works like the ntvfs_cifs module it takes this options in the [globals] section: dcerpc remote:interfaces = srvsvc, winreg, w32time, epmapper dcerpc remote:binding = ... dcerpc remote:user = ... dcerpc remote:password = ... 5.) we currently have tree endpoint servers: epmapper, rpcecho and remote the default for the 'dcerpc endpiont servers = epmapper, rpcecho' for testing you can also do dcerpc endpoint servers = rpcecho, remote, epmapper dcerpc remote:interfaces = srvsvc, samr, netlogon 6,) please notice the the epmapper now only returns NO_ENTRIES (but I think we'll find a solution for this too:-) 7.) also there're some other stuff left, but step by step :-) This patch also includes updates for the register_subsystem() , ntvfs_init(), and some other funtions to check for duplicate subsystem registration metze (hmmm, my first large commit...I hope it works as supposed :-) (This used to be commit 917e45dafd5be4c2cd90ff425b8d6f8403122349)
Diffstat (limited to 'source4/rpc_server/dcerpc_server.c')
-rw-r--r--source4/rpc_server/dcerpc_server.c529
1 files changed, 373 insertions, 156 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index d3e2f1917f..46341e6db1 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -4,6 +4,7 @@
server side dcerpc core code
Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan (metze) Metzmacher 2004
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
@@ -23,15 +24,105 @@
#include "includes.h"
/*
- find the set of endpoint operations for an endpoint server
+ see if two endpoints match
*/
-static const struct dcesrv_endpoint_ops *find_endpoint(struct dcesrv_context *dce,
- const struct dcesrv_endpoint *endpoint)
+static BOOL endpoints_match(const struct dcesrv_ep_description *ep1,
+ const struct dcesrv_ep_description *ep2)
{
- struct dce_endpoint *ep;
- for (ep=dce->endpoint_list; ep; ep=ep->next) {
- if (ep->endpoint_ops->query_endpoint(endpoint)) {
- return ep->endpoint_ops;
+ if (ep1->type != ep2->type) {
+ return False;
+ }
+
+ switch (ep1->type) {
+ case ENDPOINT_SMB:
+ if (strcmp(ep1->info.smb_pipe,ep2->info.smb_pipe)==0) {
+ return True;
+ }
+ break;
+ case ENDPOINT_TCP:
+ if (ep1->info.tcp_port == ep2->info.tcp_port) {
+ return True;
+ }
+ break;
+ }
+
+ return False;
+}
+
+/*
+ find an endpoint in the dcesrv_context
+*/
+static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
+ const struct dcesrv_ep_description *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;
+}
+
+/*
+ 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)
+{
+ if (if1->ndr->if_version != if2->ndr->if_version) {
+ return False;
+ }
+
+ if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
+ return True;
+ }
+
+ return False;
+}
+
+/*
+ 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 char *uuid, uint32 if_version)
+{
+ if (iface->ndr->if_version != if_version) {
+ return False;
+ }
+
+ if (strcmp(iface->ndr->uuid, uuid)==0) {
+ return True;
+ }
+
+ return False;
+}
+
+/*
+ find the interface operations on an endpoint by uuid
+*/
+static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
+ const char *uuid, uint32 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;
@@ -40,10 +131,10 @@ static const struct dcesrv_endpoint_ops *find_endpoint(struct dcesrv_context *dc
/*
find a call that is pending in our call list
*/
-static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_state *dce, uint16 call_id)
+static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16 call_id)
{
struct dcesrv_call_state *c;
- for (c=dce->call_list;c;c=c->next) {
+ for (c=dce_conn->call_list;c;c=c->next) {
if (c->pkt.call_id == call_id) {
return c;
}
@@ -52,121 +143,175 @@ static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_state *dce, uint
}
/*
- register an endpoint server
+ register an interface on an endpoint
*/
-BOOL dcesrv_endpoint_register(struct dcesrv_context *dce,
- const struct dcesrv_endpoint_ops *ops,
- const struct dcerpc_interface_table *table)
+NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
+ const char *ep_name,
+ const struct dcesrv_interface *iface,
+ const struct security_descriptor *sd)
{
- BOOL done_smb=False;
- BOOL done_tcp=False;
- int i;
+ struct dcesrv_ep_description ep_description;
+ struct dcesrv_endpoint *ep;
+ struct dcesrv_if_list *ifl;
+ BOOL tcp;
+ BOOL add_ep = False;
- for (i=0;i<table->endpoints->count;i++) {
- struct dce_endpoint *ep;
- BOOL tcp;
+ tcp = (strncasecmp(ep_name, "TCP-", 4) == 0);
- tcp = (strncasecmp(table->endpoints->names[i], "TCP-", 4) == 0);
+ if (tcp) {
+ ep_description.type = ENDPOINT_TCP;
+ ep_description.info.tcp_port = atoi(ep_name+4);
+ } else {
+ ep_description.type = ENDPOINT_SMB;
+ ep_description.info.smb_pipe = ep_name;
+ }
+ /* check if this endpoint exists
+ */
+ if ((ep=find_endpoint(dce_ctx, &ep_description))==NULL) {
+ ep = talloc(dce_ctx->mem_ctx, sizeof(*ep));
+ if (!ep) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCTP(ep);
if (tcp) {
- if (done_tcp) continue;
- done_tcp = True;
+ ep->ep_description.type = ENDPOINT_TCP;
+ ep->ep_description.info.tcp_port = atoi(ep_name+4);
} else {
- if (done_smb) continue;
- done_smb = True;
+ ep->ep_description.type = ENDPOINT_SMB;
+ ep->ep_description.info.smb_pipe = smb_xstrdup(ep_name);
}
+ add_ep = True;
+ }
- ep = malloc(sizeof(*ep));
- if (!ep) {
- return False;
+ /* 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->ndr->name, ep_name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ /* talloc a new interface list element */
+ ifl = talloc(dce_ctx->mem_ctx, sizeof(*ifl));
+ 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 = copy_security_descriptor(dce_ctx->mem_ctx, sd);
}
- if (tcp) {
- ep->endpoint.type = ENDPOINT_TCP;
- ep->endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
- } else {
- ep->endpoint.type = ENDPOINT_SMB;
- ep->endpoint.info.smb_pipe = table->endpoints->names[i];
+ /* 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->ndr->name, ep_name));
+ if (add_ep) free(ep);
+ free(ifl);
+ return NT_STATUS_OBJECT_NAME_COLLISION;
}
+ }
- ep->endpoint_ops = ops;
- DLIST_ADD(dce->endpoint_list, ep);
+ /* 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);
}
- return True;
+ DEBUG(3,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
+ iface->ndr->name, ep_name));
+
+ return NT_STATUS_OK;
}
/*
connect to a dcerpc endpoint
*/
-NTSTATUS dcesrv_endpoint_connect_ops(struct dcesrv_context *dce,
- const struct dcesrv_endpoint *endpoint,
- const struct dcesrv_endpoint_ops *ops,
- struct dcesrv_state **p)
+NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
+ const struct dcesrv_endpoint *ep,
+ struct dcesrv_connection **p)
{
TALLOC_CTX *mem_ctx;
- NTSTATUS status;
mem_ctx = talloc_init("dcesrv_endpoint_connect");
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
}
- *p = talloc_p(mem_ctx, struct dcesrv_state);
+ *p = talloc_p(mem_ctx, struct dcesrv_connection);
if (! *p) {
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
- (*p)->dce = dce;
+ (*p)->dce_ctx = dce_ctx;
(*p)->mem_ctx = mem_ctx;
- (*p)->endpoint = *endpoint;
- (*p)->ops = ops;
+ (*p)->endpoint = ep;
+ (*p)->iface = NULL;
(*p)->private = NULL;
(*p)->call_list = NULL;
(*p)->cli_max_recv_frag = 0;
- (*p)->ndr = NULL;
- (*p)->dispatch = NULL;
(*p)->handles = NULL;
(*p)->partial_input = data_blob(NULL, 0);
(*p)->auth_state.ntlmssp_state = NULL;
(*p)->auth_state.auth_info = NULL;
- /* make sure the endpoint server likes the connection */
- status = ops->connect(*p);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_destroy(mem_ctx);
- return status;
- }
-
return NT_STATUS_OK;
}
/*
- connect to a dcerpc endpoint
+ search and connect to a dcerpc endpoint
*/
-NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce,
- const struct dcesrv_endpoint *endpoint,
- struct dcesrv_state **p)
+NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
+ const struct dcesrv_ep_description *ep_description,
+ struct dcesrv_connection **dce_conn_p)
{
- const struct dcesrv_endpoint_ops *ops;
+ NTSTATUS status;
+ const struct dcesrv_endpoint *ep;
/* make sure this endpoint exists */
- ops = find_endpoint(dce, endpoint);
- if (!ops) {
+ ep = find_endpoint(dce_ctx, ep_description);
+ if (!ep) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
- return dcesrv_endpoint_connect_ops(dce, endpoint, ops, p);
+ status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* 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;
}
/*
disconnect a link to an endpoint
*/
-void dcesrv_endpoint_disconnect(struct dcesrv_state *p)
+void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
{
- p->ops->disconnect(p);
+ if (p->iface) {
+ p->iface->unbind(p, p->iface);
+ }
/* destroy any handles */
while (p->handles) {
@@ -315,15 +460,16 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
return dcesrv_bind_nak(call, 0);
}
- if (!call->dce->ops->set_interface(call->dce, uuid, if_version)) {
+ call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
+ if (!call->conn->iface) {
DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
/* we don't know about that interface */
result = DCERPC_BIND_PROVIDER_REJECT;
- reason = DCERPC_BIND_REASON_ASYNTAX;
+ reason = DCERPC_BIND_REASON_ASYNTAX;
}
- if (call->dce->cli_max_recv_frag == 0) {
- call->dce->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
+ 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 */
@@ -340,9 +486,9 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
pkt.u.bind_ack.max_xmit_frag = 0x2000;
pkt.u.bind_ack.max_recv_frag = 0x2000;
pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
- if (call->dce->ndr) {
+ if (call->conn->iface && call->conn->iface->ndr) {
pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s",
- call->dce->ndr->name);
+ call->conn->iface->ndr->name);
} else {
pkt.u.bind_ack.secondary_address = "";
}
@@ -361,13 +507,21 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
return dcesrv_bind_nak(call, 0);
}
+ if (call->conn->iface) {
+ status = call->conn->iface->bind(call, call->conn->iface);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2,("Request for dcerpc interface %s/%d rejected\n", uuid, if_version));
+ return status;
+ }
+ }
+
rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt,
- call->dce->auth_state.auth_info);
+ call->conn->auth_state.auth_info);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -375,7 +529,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
dcerpc_set_frag_length(&rep->data, rep->data.length);
DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
- DLIST_ADD_END(call->dce->call_list, call, struct dcesrv_call_state *);
+ DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
return NT_STATUS_OK;
}
@@ -413,7 +567,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
opnum = call->pkt.u.request.opnum;
- if (opnum >= call->dce->ndr->num_calls) {
+ if (opnum >= call->conn->iface->ndr->num_calls) {
return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
}
@@ -422,7 +576,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
return NT_STATUS_NO_MEMORY;
}
- r = talloc(call->mem_ctx, call->dce->ndr->calls[opnum].struct_size);
+ r = talloc(call->mem_ctx, call->conn->iface->ndr->calls[opnum].struct_size);
if (!r) {
return NT_STATUS_NO_MEMORY;
}
@@ -432,13 +586,13 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
}
/* unravel the NDR for the packet */
- status = call->dce->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
+ status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_fault(call, DCERPC_FAULT_NDR);
}
/* call the dispatch function */
- status = call->dce->dispatch[opnum](call->dce, call->mem_ctx, r);
+ status = call->conn->iface->dispatch(call, call->mem_ctx, r);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_fault_nt(call, status);
}
@@ -453,7 +607,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
push->flags |= LIBNDR_FLAG_BIGENDIAN;
}
- status = call->dce->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
+ status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_fault(call, DCERPC_FAULT_NDR);
}
@@ -471,9 +625,9 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
}
length = stub.length;
- if (length + DCERPC_RESPONSE_LENGTH > call->dce->cli_max_recv_frag) {
+ if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
/* the 32 is to cope with signing data */
- length = call->dce->cli_max_recv_frag -
+ length = call->conn->cli_max_recv_frag -
(DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
}
@@ -507,7 +661,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
stub.length -= length;
} while (stub.length != 0);
- DLIST_ADD_END(call->dce->call_list, call, struct dcesrv_call_state *);
+ DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
return NT_STATUS_OK;
}
@@ -530,18 +684,18 @@ static BOOL dce_full_packet(const DATA_BLOB *data)
/*
we might have consumed only part of our input - advance past that part
*/
-static void dce_partial_advance(struct dcesrv_state *dce, uint32 offset)
+static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32 offset)
{
DATA_BLOB blob;
- if (dce->partial_input.length == offset) {
- free(dce->partial_input.data);
- dce->partial_input = data_blob(NULL, 0);
+ if (dce_conn->partial_input.length == offset) {
+ free(dce_conn->partial_input.data);
+ dce_conn->partial_input = data_blob(NULL, 0);
return;
}
- blob = dce->partial_input;
- dce->partial_input = data_blob(blob.data + offset,
+ blob = dce_conn->partial_input;
+ dce_conn->partial_input = data_blob(blob.data + offset,
blob.length - offset);
free(blob.data);
}
@@ -549,7 +703,7 @@ static void dce_partial_advance(struct dcesrv_state *dce, uint32 offset)
/*
process some input to a dcerpc endpoint server.
*/
-NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
+NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
{
struct ndr_pull *ndr;
TALLOC_CTX *mem_ctx;
@@ -563,20 +717,20 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
}
call = talloc_p(mem_ctx, struct dcesrv_call_state);
if (!call) {
- talloc_free(dce->mem_ctx, dce->partial_input.data);
+ talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
call->mem_ctx = mem_ctx;
- call->dce = dce;
+ call->conn = dce_conn;
call->replies = NULL;
- blob = dce->partial_input;
+ blob = dce_conn->partial_input;
blob.length = dcerpc_get_frag_length(&blob);
ndr = ndr_pull_init_blob(&blob, mem_ctx);
if (!ndr) {
- talloc_free(dce->mem_ctx, dce->partial_input.data);
+ talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
@@ -587,12 +741,12 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
if (!NT_STATUS_IS_OK(status)) {
- talloc_free(dce->mem_ctx, dce->partial_input.data);
+ talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
talloc_destroy(mem_ctx);
return status;
}
- dce_partial_advance(dce, blob.length);
+ dce_partial_advance(dce_conn, blob.length);
/* we have to check the signing here, before combining the
pdus */
@@ -613,7 +767,7 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
/* this is a continuation of an existing call - find the call then
tack it on the end */
- call = dcesrv_find_call(dce, call2->pkt.call_id);
+ call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
if (!call) {
return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
}
@@ -648,7 +802,7 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
/* this may not be the last pdu in the chain - if its isn't then
just put it on the call_list and wait for the rest */
if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
- DLIST_ADD_END(dce->call_list, call, struct dcesrv_call_state *);
+ DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
return NT_STATUS_OK;
}
@@ -682,21 +836,21 @@ NTSTATUS dcesrv_input_process(struct dcesrv_state *dce)
provide some input to a dcerpc endpoint server. This passes data
from a dcerpc client into the server
*/
-NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
+NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
{
NTSTATUS status;
- dce->partial_input.data = Realloc(dce->partial_input.data,
- dce->partial_input.length + data->length);
- if (!dce->partial_input.data) {
+ dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data,
+ dce_conn->partial_input.length + data->length);
+ if (!dce_conn->partial_input.data) {
return NT_STATUS_NO_MEMORY;
}
- memcpy(dce->partial_input.data + dce->partial_input.length,
+ memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
data->data, data->length);
- dce->partial_input.length += data->length;
+ dce_conn->partial_input.length += data->length;
- while (dce_full_packet(&dce->partial_input)) {
- status = dcesrv_input_process(dce);
+ while (dce_full_packet(&dce_conn->partial_input)) {
+ status = dcesrv_input_process(dce_conn);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -710,12 +864,12 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
is wanted is in data->length and data->data is already allocated
to hold that much data.
*/
-NTSTATUS dcesrv_output(struct dcesrv_state *dce, DATA_BLOB *data)
+NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, DATA_BLOB *data)
{
struct dcesrv_call_state *call;
struct dcesrv_call_reply *rep;
- call = dce->call_list;
+ call = dce_conn->call_list;
if (!call || !call->replies) {
return NT_STATUS_FOOBAR;
}
@@ -736,88 +890,151 @@ NTSTATUS dcesrv_output(struct dcesrv_state *dce, DATA_BLOB *data)
if (call->replies == NULL) {
/* we're done with the whole call */
- DLIST_REMOVE(dce->call_list, call);
+ DLIST_REMOVE(dce_conn->call_list, call);
talloc_destroy(call->mem_ctx);
}
return NT_STATUS_OK;
}
-
/*
- a useful function for implementing the query endpoint op
- */
-BOOL dcesrv_table_query(const struct dcerpc_interface_table *table,
- const struct dcesrv_endpoint *ep)
+ initialise the dcerpc server context
+*/
+NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
{
int i;
- const struct dcerpc_endpoint_list *endpoints = table->endpoints;
+ const char **endpoint_servers = lp_dcerpc_endpoint_servers();
- if (ep->type != ENDPOINT_SMB) {
- return False;
+ dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
+ if (!dce_ctx->mem_ctx) {
+ DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
+ return NT_STATUS_NO_MEMORY;
}
- for (i=0;i<endpoints->count;i++) {
- if (strcasecmp(ep->info.smb_pipe, endpoints->names[i]) == 0) {
- return True;
+ dce_ctx->endpoint_list = NULL;
+
+ if (!endpoint_servers) {
+ DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
+ return NT_STATUS_OK;
+ }
+
+ for (i=0;endpoint_servers[i];i++) {
+ NTSTATUS ret;
+ 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_UNSUCCESSFUL;
+ }
+
+ ret = ep_server->init_server(dce_ctx, ep_server);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
+ return ret;
}
}
- return False;
+
+ return NT_STATUS_OK;
}
+/* the list of currently registered DCERPC endpoint servers.
+ */
+static struct {
+ struct dcesrv_endpoint_server *ep_server;
+} *ep_servers = NULL;
+static int num_ep_servers;
/*
- a useful function for implementing the lookup_endpoints op
- */
-int dcesrv_lookup_endpoints(const struct dcerpc_interface_table *table,
- TALLOC_CTX *mem_ctx,
- struct dcesrv_ep_iface **e)
+ 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
+*/
+static NTSTATUS decrpc_register_ep_server(void *_ep_server)
{
- int i;
- *e = talloc_array_p(mem_ctx, struct dcesrv_ep_iface, table->endpoints->count);
- if (! *e) {
- return -1;
- }
-
- for (i=0;i<table->endpoints->count;i++) {
- (*e)[i].name = table->name;
- (*e)[i].uuid = table->uuid;
- (*e)[i].if_version = table->if_version;
- if (strncmp(table->endpoints->names[i], "TCP-", 4) == 0) {
- (*e)[i].endpoint.type = ENDPOINT_TCP;
- (*e)[i].endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
- } else {
- (*e)[i].endpoint.type = ENDPOINT_SMB;
- (*e)[i].endpoint.info.smb_pipe = table->endpoints->names[i];
- }
+ const struct dcesrv_endpoint_server *ep_server = _ep_server;
+
+ if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
+ /* its already registered! */
+ DEBUG(1,("DCERPC endpoint server '%s' already registered\n",
+ ep_server->name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
}
- return i;
-}
+ ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
+ if (!ep_servers) {
+ smb_panic("out of memory in decrpc_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(1,("DCERPC module '%s' registered\n",
+ ep_server->name));
+ return NT_STATUS_OK;
+}
-BOOL dcesrv_set_interface(struct dcesrv_state *dce,
- const char *uuid, uint32 if_version,
- const struct dcerpc_interface_table *table,
- const dcesrv_dispatch_fn_t *dispatch_table)
+/*
+ return the operations structure for a named backend of the specified type
+*/
+const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
{
- if (strcasecmp(table->uuid, uuid) != 0 || if_version != table->if_version) {
- DEBUG(2,("Attempt to use unknown interface %s/%d\n", uuid, if_version));
- return False;
+ 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;
+ }
}
- dce->ndr = table;
- dce->dispatch = dispatch_table;
- return True;
+ 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_ep_description),
+ 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 subsystem
+ initialise the DCERPC subsystem
*/
-BOOL dcesrv_init(struct dcesrv_context *dce)
+BOOL dcesrv_init(void)
{
- rpc_rpcecho_init(dce);
- rpc_epmapper_init(dce);
+ NTSTATUS status;
+
+ status = register_subsystem("dcerpc", decrpc_register_ep_server);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
+ static_init_dcerpc;
+
+ DEBUG(1,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
return True;
}