summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-12-13 02:20:40 +0000
committerAndrew Tridgell <tridge@samba.org>2003-12-13 02:20:40 +0000
commit340d9b71f9e75d634389104da5949ba59669ede2 (patch)
tree1bc2c22f57eade574841d8e4d9f3f5a5ff1c1022 /source4
parentf7065cc0a5555a32499908a499f926ede3f7d851 (diff)
downloadsamba-340d9b71f9e75d634389104da5949ba59669ede2.tar.gz
samba-340d9b71f9e75d634389104da5949ba59669ede2.tar.bz2
samba-340d9b71f9e75d634389104da5949ba59669ede2.zip
added a basic dcerpc endpoint mapper to Samba4. Currently only
implements the epm_Lookup() call, I'll add the other important calls soon. I was rather pleased to find that epm_Lookup() worked first time, which is particularly surprising given its complexity. This required quite a bit of new infrastructure: * a generic way of handling dcerpc policy handles in the rpc server * added type checked varients of talloc. These are much less error prone. I'd like to move to using these for nearly all uses of talloc. * added more dcerpc fault handling code, and translation from NTSTATUS to a dcerpc fault code * added data_blob_talloc_zero() for allocating an initially zero blob * added a endpoint enumeration hook in the dcerpc endpoint server operations (This used to be commit 3f85f9b782dc17417baf1ca557fcae22f5b6a83a)
Diffstat (limited to 'source4')
-rw-r--r--source4/Makefile.in4
-rw-r--r--source4/include/talloc.h5
-rw-r--r--source4/lib/data_blob.c12
-rw-r--r--source4/lib/genparser.c11
-rw-r--r--source4/lib/talloc.c57
-rw-r--r--source4/lib/util.c14
-rw-r--r--source4/librpc/idl/dcerpc.idl7
-rw-r--r--source4/librpc/rpc/dcerpc_util.c10
-rw-r--r--source4/rpc_server/dcerpc_server.c64
-rw-r--r--source4/rpc_server/dcerpc_server.h31
-rw-r--r--source4/rpc_server/echo/rpc_echo.c8
-rw-r--r--source4/rpc_server/epmapper/rpc_epmapper.c274
-rw-r--r--source4/rpc_server/handles.c92
-rw-r--r--source4/torture/rpc/epmapper.c12
14 files changed, 562 insertions, 39 deletions
diff --git a/source4/Makefile.in b/source4/Makefile.in
index ce0668b9f1..f675aa4b29 100644
--- a/source4/Makefile.in
+++ b/source4/Makefile.in
@@ -285,7 +285,9 @@ SMBD_NTVFS_OBJ = ntvfs/ntvfs_base.o ntvfs/ntvfs_util.o \
ntvfs/ntvfs_generic.o @NTVFS_STATIC@
SMBD_RPC_OBJ = rpc_server/dcerpc_server.o \
- rpc_server/echo/rpc_echo.o
+ rpc_server/handles.o \
+ rpc_server/echo/rpc_echo.o \
+ rpc_server/epmapper/rpc_epmapper.o
SMBD_OBJ_SRV = smbd/connection.o \
smbd/session.o \
diff --git a/source4/include/talloc.h b/source4/include/talloc.h
index 4badddbb88..60a2822f38 100644
--- a/source4/include/talloc.h
+++ b/source4/include/talloc.h
@@ -46,6 +46,11 @@ char *talloc_vasprintf_append(TALLOC_CTX *t, char *, const char *, va_list ap)
char *talloc_asprintf_append(TALLOC_CTX *t, char *, const char *, ...)
PRINTF_ATTRIBUTE(3, 4);
+/* useful macros for creating type checked pointers */
+#define talloc_p(ctx, type) (type *)talloc(ctx, sizeof(type));
+#define talloc_array_p(ctx, type, count) (type *)talloc_realloc_array(ctx, NULL, sizeof(type), count)
+#define talloc_realloc_p(ctx, p, type, count) (type *)talloc_realloc_array(ctx, p, sizeof(type), count)
+
/** @} */
#endif /* ndef _TALLOC_H_ */
diff --git a/source4/lib/data_blob.c b/source4/lib/data_blob.c
index 457ad382a2..b5d1b4076e 100644
--- a/source4/lib/data_blob.c
+++ b/source4/lib/data_blob.c
@@ -88,6 +88,18 @@ DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length)
}
/*******************************************************************
+ construct a zero data blob, using supplied TALLOC_CTX.
+ use this sparingly as it initialises data - better to initialise
+ yourself if you want specific data in the blob
+*******************************************************************/
+DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
+{
+ DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
+ data_blob_clear(&blob);
+ return blob;
+}
+
+/*******************************************************************
free a data blob
*******************************************************************/
void data_blob_free(DATA_BLOB *d)
diff --git a/source4/lib/genparser.c b/source4/lib/genparser.c
index 39c455def4..0f5d26620b 100644
--- a/source4/lib/genparser.c
+++ b/source4/lib/genparser.c
@@ -22,17 +22,6 @@
#include "includes.h"
-/* see if a range of memory is all zero. Used to prevent dumping of zero elements */
-static int all_zero(const char *ptr, unsigned size)
-{
- int i;
- if (!ptr) return 1;
- for (i=0;i<size;i++) {
- if (ptr[i]) return 0;
- }
- return 1;
-}
-
/* encode a buffer of bytes into a escaped string */
static char *encode_bytes(TALLOC_CTX *mem_ctx, const char *ptr, unsigned len)
{
diff --git a/source4/lib/talloc.c b/source4/lib/talloc.c
index 83a99d8071..25871feac1 100644
--- a/source4/lib/talloc.c
+++ b/source4/lib/talloc.c
@@ -48,12 +48,13 @@
**/
/**
- * If you want testing for memory corruption, link with dmalloc or use
- * Insure++. It doesn't seem useful to duplicate them here.
+ * If you want testing for memory corruption use valgrind
**/
#include "includes.h"
+#define MAX_TALLOC_SIZE 0x10000000
+
struct talloc_chunk {
struct talloc_chunk *next;
size_t size;
@@ -188,8 +189,14 @@ void *talloc_realloc(TALLOC_CTX *t, void *ptr, size_t size)
void *new_ptr;
/* size zero is equivalent to free() */
- if (!t || size == 0)
+ if (!t) {
return NULL;
+ }
+
+ if (size == 0) {
+ talloc_free(t, ptr);
+ return NULL;
+ }
/* realloc(NULL) is equavalent to malloc() */
if (ptr == NULL)
@@ -471,6 +478,39 @@ void talloc_get_allocation(TALLOC_CTX *t,
/*
+ free a lump from a pool. Use sparingly please.
+*/
+void talloc_free(TALLOC_CTX *ctx, void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (!ptr || !ctx->list) return;
+
+ /* as a special case, see if its the first element in the
+ list */
+ if (ctx->list->ptr == ptr) {
+ ctx->total_alloc_size -= ctx->list->size;
+ ctx->list = ctx->list->next;
+ free(ptr);
+ return;
+ }
+
+ /* find it in the context */
+ for (tc=ctx->list; tc->next; tc=tc->next) {
+ if (tc->next->ptr == ptr) break;
+ }
+
+ if (tc->next) {
+ ctx->total_alloc_size -= tc->next->size;
+ tc->next = tc->next->next;
+ } else {
+ DEBUG(0,("Attempt to free non-allocated chunk in context '%s'\n",
+ ctx->name));
+ }
+}
+
+
+/*
move a lump of memory from one talloc context to another
return the ptr on success, or NULL if it could not be found
in the old context or could not be transferred
@@ -511,5 +551,16 @@ const void *talloc_steal(TALLOC_CTX *old_ctx, TALLOC_CTX *new_ctx, const void *p
return ptr;
}
+/*
+ realloc an array, checking for integer overflow in the array size
+*/
+void *talloc_realloc_array(TALLOC_CTX *ctx, void *ptr, size_t el_size, unsigned count)
+{
+ if (count == 0 ||
+ count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return talloc_realloc(ctx, ptr, el_size * count);
+}
/** @} */
diff --git a/source4/lib/util.c b/source4/lib/util.c
index 9b6cef8bfe..233609263d 100644
--- a/source4/lib/util.c
+++ b/source4/lib/util.c
@@ -1009,3 +1009,17 @@ void dump_data_pw(const char *msg, const uchar * data, size_t len)
}
#endif
}
+
+
+/* see if a range of memory is all zero. A NULL pointer is considered
+ to be all zero */
+BOOL all_zero(const char *ptr, unsigned size)
+{
+ int i;
+ if (!ptr) return True;
+ for (i=0;i<size;i++) {
+ if (ptr[i]) return False;
+ }
+ return True;
+}
+
diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl
index e6b59c2e2d..afe4b3003f 100644
--- a/source4/librpc/idl/dcerpc.idl
+++ b/source4/librpc/idl/dcerpc.idl
@@ -82,9 +82,10 @@ interface dcerpc
} dcerpc_response;
- const int DCERPC_FAULT_OP_RNG_ERROR = 0x1c010002;
- const int DCERPC_FAULT_NDR = 0x000006f7;
- const int DCERPC_FAULT_OTHER = 0x00000001;
+ const int DCERPC_FAULT_OP_RNG_ERROR = 0x1c010002;
+ const int DCERPC_FAULT_NDR = 0x000006f7;
+ const int DCERPC_FAULT_CONTEXT_MISMATCH = 0x1c00001a;
+ const int DCERPC_FAULT_OTHER = 0x00000001;
/* we return this fault when we haven't yet run the test
to see what fault w2k3 returns in this case */
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index ef4af9f661..de46f532c6 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -96,28 +96,28 @@ NTSTATUS dcerpc_epm_map_tcp_port(const char *server,
twr.towers.floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
GUID_from_string(uuid, &twr.towers.floors[0].lhs.info.uuid.uuid);
twr.towers.floors[0].lhs.info.uuid.version = version;
- twr.towers.floors[0].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2);
+ twr.towers.floors[0].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 2);
/* encoded with NDR ... */
twr.towers.floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
GUID_from_string(NDR_GUID, &twr.towers.floors[1].lhs.info.uuid.uuid);
twr.towers.floors[1].lhs.info.uuid.version = NDR_GUID_VERSION;
- twr.towers.floors[1].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2);
+ twr.towers.floors[1].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 2);
/* on an RPC connection ... */
twr.towers.floors[2].lhs.protocol = EPM_PROTOCOL_RPC_C;
twr.towers.floors[2].lhs.info.lhs_data = data_blob(NULL, 0);
- twr.towers.floors[2].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2);
+ twr.towers.floors[2].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 2);
/* on a TCP port ... */
twr.towers.floors[3].lhs.protocol = EPM_PROTOCOL_TCP;
twr.towers.floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
- twr.towers.floors[3].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2);
+ twr.towers.floors[3].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 2);
/* on an IP link ... */
twr.towers.floors[4].lhs.protocol = EPM_PROTOCOL_IP;
twr.towers.floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
- twr.towers.floors[4].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 4);
+ twr.towers.floors[4].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 4);
/* with some nice pretty paper around it of course */
r.in.object = &guid;
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 4711f4e6ff..e2a6ab0132 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -89,12 +89,13 @@ NTSTATUS dcesrv_endpoint_connect(struct server_context *smb,
return NT_STATUS_NO_MEMORY;
}
- *p = talloc(mem_ctx, sizeof(struct dcesrv_state));
+ *p = talloc_p(mem_ctx, struct dcesrv_state);
if (! *p) {
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
+ (*p)->smb = smb;
(*p)->mem_ctx = mem_ctx;
(*p)->endpoint = *endpoint;
(*p)->ops = ops;
@@ -103,6 +104,7 @@ NTSTATUS dcesrv_endpoint_connect(struct server_context *smb,
(*p)->cli_max_recv_frag = 0;
(*p)->ndr = NULL;
(*p)->dispatch = NULL;
+ (*p)->handles = NULL;
/* make sure the endpoint server likes the connection */
status = ops->connect(*p);
@@ -121,6 +123,14 @@ NTSTATUS dcesrv_endpoint_connect(struct server_context *smb,
void dcesrv_endpoint_disconnect(struct dcesrv_state *p)
{
p->ops->disconnect(p);
+
+ /* destroy any handles */
+ while (p->handles) {
+ TALLOC_CTX *m = p->handles->mem_ctx;
+ DLIST_REMOVE(p->handles, p->handles);
+ talloc_destroy(m);
+ }
+
talloc_destroy(p->mem_ctx);
}
@@ -161,7 +171,7 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
return status;
}
- rep = talloc(call->mem_ctx, sizeof(*rep));
+ rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
@@ -176,6 +186,22 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
/*
+ return a dcerpc fault from a ntstatus code
+*/
+static NTSTATUS dcesrv_fault_nt(struct dcesrv_call_state *call, NTSTATUS status)
+{
+ uint32 fault_code = DCERPC_FAULT_OTHER;
+
+ /* TODO: we need to expand this table to include more mappings */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
+ fault_code = DCERPC_FAULT_CONTEXT_MISMATCH;
+ }
+
+ return dcesrv_fault(call, fault_code);
+}
+
+
+/*
return a dcerpc bind_nak
*/
static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason)
@@ -210,7 +236,7 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason)
return status;
}
- rep = talloc(call->mem_ctx, sizeof(*rep));
+ rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
@@ -290,7 +316,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
pkt.u.bind_ack.secondary_address = "";
}
pkt.u.bind_ack.num_results = 1;
- pkt.u.bind_ack.ctx_list = talloc(call->mem_ctx, sizeof(struct dcerpc_ack_ctx));
+ pkt.u.bind_ack.ctx_list = talloc_p(call->mem_ctx, struct dcerpc_ack_ctx);
if (!pkt.u.bind_ack.ctx_list) {
return NT_STATUS_NO_MEMORY;
}
@@ -312,7 +338,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
return status;
}
- rep = talloc(call->mem_ctx, sizeof(*rep));
+ rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
@@ -363,7 +389,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
/* call the dispatch function */
status = call->dce->dispatch[opnum](call->dce, call->mem_ctx, r);
if (!NT_STATUS_IS_OK(status)) {
- return dcesrv_fault(call, DCERPC_FAULT_NDR);
+ return dcesrv_fault_nt(call, status);
}
/* form the reply NDR */
@@ -384,7 +410,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
struct dcesrv_call_reply *rep;
struct dcerpc_packet pkt;
- rep = talloc(call->mem_ctx, sizeof(*rep));
+ rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
if (!rep) {
return NT_STATUS_NO_MEMORY;
}
@@ -455,7 +481,7 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
}
- call = talloc(mem_ctx, sizeof(*call));
+ call = talloc_p(mem_ctx, struct dcesrv_call_state);
if (!call) {
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
@@ -613,10 +639,32 @@ BOOL dcesrv_table_query(const struct dcerpc_interface_table *table,
/*
+ 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)
+{
+ *e = talloc_p(mem_ctx, struct dcesrv_ep_iface);
+ if (! *e) {
+ return -1;
+ }
+
+ (*e)->uuid = table->uuid;
+ (*e)->if_version = table->if_version;
+ (*e)->endpoint.type = ENDPOINT_SMB;
+ (*e)->endpoint.info.smb_pipe = table->endpoints->names[0];
+
+ return 1;
+}
+
+
+/*
initialise the dcerpc server subsystem
*/
BOOL dcesrv_init(struct server_context *smb)
{
rpc_echo_init(smb);
+ rpc_epmapper_init(smb);
return True;
}
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 165eddc5e6..3f2f5d039f 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -23,7 +23,8 @@
enum endpoint_type {ENDPOINT_SMB, ENDPOINT_TCP};
-/* a description of a single dcerpc endpoint */
+/* a description of a single dcerpc endpoint. Not as flexible as a full epm tower,
+ but much easier to work with */
struct dcesrv_endpoint {
enum endpoint_type type;
union {
@@ -32,6 +33,13 @@ struct dcesrv_endpoint {
} info;
};
+/* a endpoint combined with an interface description */
+struct dcesrv_ep_iface {
+ struct dcesrv_endpoint endpoint;
+ const char *uuid;
+ uint32 if_version;
+};
+
struct dcesrv_state;
/* the dispatch functions for an interface take this form */
@@ -50,8 +58,20 @@ struct dcesrv_call_state {
} *replies;
};
+
+/* a dcerpc handle in internal format */
+struct dcesrv_handle {
+ struct dcesrv_handle *next, *prev;
+ struct policy_handle wire_handle;
+ TALLOC_CTX *mem_ctx;
+ void *data;
+};
+
/* the state associated with a dcerpc server connection */
struct dcesrv_state {
+ /* the top level context for this server */
+ struct server_context *smb;
+
TALLOC_CTX *mem_ctx;
/* the endpoint that was opened */
@@ -75,6 +95,11 @@ struct dcesrv_state {
/* private data for the endpoint server */
void *private;
+
+ /* current rpc handles - this is really the wrong scope for
+ them, but it will do for now */
+ uint32 next_handle;
+ struct dcesrv_handle *handles;
};
@@ -92,6 +117,10 @@ struct dcesrv_endpoint_ops {
/* disconnect() is called when the endpoint is disconnected */
void (*disconnect)(struct dcesrv_state *);
+
+ /* this function is used to ask an endpoint server for a list
+ of endpoints it wants to handle */
+ int (*lookup_endpoints)(TALLOC_CTX *mem_ctx, struct dcesrv_ep_iface **);
};
diff --git a/source4/rpc_server/echo/rpc_echo.c b/source4/rpc_server/echo/rpc_echo.c
index 42856737c4..f741e63d62 100644
--- a/source4/rpc_server/echo/rpc_echo.c
+++ b/source4/rpc_server/echo/rpc_echo.c
@@ -163,11 +163,17 @@ static void op_disconnect(struct dcesrv_state *dce)
}
+static int op_lookup_endpoints(TALLOC_CTX *mem_ctx, struct dcesrv_ep_iface **e)
+{
+ return dcesrv_lookup_endpoints(&dcerpc_table_rpcecho, mem_ctx, e);
+}
+
static const struct dcesrv_endpoint_ops rpc_echo_ops = {
op_query_endpoint,
op_set_interface,
op_connect,
- op_disconnect
+ op_disconnect,
+ op_lookup_endpoints
};
/*
diff --git a/source4/rpc_server/epmapper/rpc_epmapper.c b/source4/rpc_server/epmapper/rpc_epmapper.c
new file mode 100644
index 0000000000..945823c013
--- /dev/null
+++ b/source4/rpc_server/epmapper/rpc_epmapper.c
@@ -0,0 +1,274 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ endpoint server for the epmapper pipe
+
+ Copyright (C) Andrew Tridgell 2003
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/* handle types for this module */
+enum handle_types {HTYPE_LOOKUP};
+
+static NTSTATUS epm_Insert(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
+ struct epm_Lookup *r)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS epm_Delete(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
+ struct epm_Lookup *r)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/*
+ implement epm_Lookup. This call is used to enumerate the interfaces
+ available on a rpc server
+*/
+static NTSTATUS epm_Lookup(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
+ struct epm_Lookup *r)
+{
+ struct dcesrv_handle *h;
+ struct rpc_eps {
+ uint32 count;
+ struct dcesrv_ep_iface *e;
+ } *eps;
+ uint32 num_ents;
+ int i;
+
+ h = dcesrv_handle_fetch(dce, r->in.entry_handle, HTYPE_LOOKUP);
+ if (!h) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ eps = h->data;
+
+ if (!eps) {
+ /* this is the first call - fill the list. Subsequent calls
+ will feed from this list, stored in the handle */
+ struct dce_endpoint *d;
+ struct dcesrv_ep_iface *e;
+
+ eps = talloc_p(h->mem_ctx, struct rpc_eps);
+ if (!eps) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ eps->count = 0;
+ eps->e = NULL;
+ h->data = eps;
+
+ for (d=dce->smb->dcesrv.endpoint_list; d; d=d->next) {
+ int count = d->endpoint_ops->lookup_endpoints(h->mem_ctx, &e);
+ if (count > 0) {
+ eps->e = talloc_realloc_p(h->mem_ctx,
+ eps->e,
+ struct dcesrv_ep_iface,
+ eps->count + count);
+ if (!eps->e) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ memcpy(eps->e + eps->count, e, sizeof(*e) * count);
+ eps->count += count;
+ }
+ }
+ }
+
+ /* return the next N elements */
+ num_ents = r->in.max_ents;
+ if (num_ents > eps->count) {
+ num_ents = eps->count;
+ }
+
+ *r->out.entry_handle = h->wire_handle;
+ r->out.num_ents = num_ents;
+ r->out.status = 0;
+
+ if (num_ents == 0) {
+ r->out.entries = NULL;
+ return NT_STATUS_OK;
+ }
+
+ r->out.entries = talloc_array_p(mem_ctx, struct epm_entry_t, num_ents);
+ if (!r->out.entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<num_ents;i++) {
+ struct epm_twr_t *t;
+ struct epm_towers *twr;
+
+ ZERO_STRUCT(r->out.entries[i].object);
+ r->out.entries[i].annotation = "";
+ t = talloc_p(mem_ctx, struct epm_twr_t);
+ if (!twr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ r->out.entries[i].tower = t;
+ twr = &t->towers;
+ twr->num_floors = 5;
+ twr->floors = talloc_array_p(mem_ctx, struct epm_floor, 5);
+ if (!twr->floors) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ twr->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
+ GUID_from_string(eps->e[i].uuid, &twr->floors[0].lhs.info.uuid.uuid);
+ twr->floors[0].lhs.info.uuid.version = eps->e[i].if_version;
+ twr->floors[0].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 2);
+
+ /* encoded with NDR ... */
+ twr->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
+ GUID_from_string(NDR_GUID, &twr->floors[1].lhs.info.uuid.uuid);
+ twr->floors[1].lhs.info.uuid.version = NDR_GUID_VERSION;
+ twr->floors[1].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 2);
+
+ /* on an RPC connection ... */
+ twr->floors[2].lhs.protocol = EPM_PROTOCOL_RPC_C;
+ twr->floors[2].lhs.info.lhs_data = data_blob(NULL, 0);
+ twr->floors[2].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 2);
+
+ /* on a SMB pipe ... */
+ twr->floors[3].lhs.protocol = EPM_PROTOCOL_SMB;
+ twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
+ twr->floors[3].rhs.rhs_data.data = talloc_asprintf(mem_ctx, "\\PIPE\\%s",
+ eps->e[i].endpoint.info.smb_pipe);
+ twr->floors[3].rhs.rhs_data.length = strlen(twr->floors[3].rhs.rhs_data.data);
+
+ /* on an NetBIOS link ... */
+ twr->floors[4].lhs.protocol = EPM_PROTOCOL_NETBIOS;
+ twr->floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
+ twr->floors[4].rhs.rhs_data.data = talloc_asprintf(mem_ctx, "\\\\%s",
+ lp_netbios_name());
+ twr->floors[4].rhs.rhs_data.length = strlen(twr->floors[4].rhs.rhs_data.data);
+ }
+
+ eps->count -= num_ents;
+ eps->e += num_ents;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ implement epm_Map. This is used to find the specific endpoint to talk to given
+ a generic protocol tower
+*/
+static NTSTATUS epm_Map(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
+ struct epm_Lookup *r)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS epm_LookupHandleFree(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
+ struct epm_Lookup *r)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS epm_InqObject(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
+ struct epm_Lookup *r)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS epm_MgmtDelete(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx,
+ struct epm_Lookup *r)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/**************************************************************************
+ all the code below this point is boilerplate that will be auto-generated
+***************************************************************************/
+
+static const dcesrv_dispatch_fn_t dispatch_table[] = {
+ (dcesrv_dispatch_fn_t)epm_Insert,
+ (dcesrv_dispatch_fn_t)epm_Delete,
+ (dcesrv_dispatch_fn_t)epm_Lookup,
+ (dcesrv_dispatch_fn_t)epm_Map,
+ (dcesrv_dispatch_fn_t)epm_LookupHandleFree,
+ (dcesrv_dispatch_fn_t)epm_InqObject,
+ (dcesrv_dispatch_fn_t)epm_MgmtDelete
+};
+
+
+/*
+ return True if we want to handle the given endpoint
+*/
+static BOOL op_query_endpoint(const struct dcesrv_endpoint *ep)
+{
+ return dcesrv_table_query(&dcerpc_table_epmapper, ep);
+}
+
+/*
+ setup for a particular rpc interface
+*/
+static BOOL op_set_interface(struct dcesrv_state *dce, const char *uuid, uint32 if_version)
+{
+ if (strcasecmp(uuid, dcerpc_table_epmapper.uuid) != 0 ||
+ if_version != dcerpc_table_epmapper.if_version) {
+ DEBUG(2,("Attempt to use unknown interface %s/%d\n", uuid, if_version));
+ return False;
+ }
+
+ dce->ndr = &dcerpc_table_epmapper;
+ dce->dispatch = dispatch_table;
+
+ return True;
+}
+
+
+/* op_connect is called when a connection is made to an endpoint */
+static NTSTATUS op_connect(struct dcesrv_state *dce)
+{
+ return NT_STATUS_OK;
+}
+
+static void op_disconnect(struct dcesrv_state *dce)
+{
+ /* nothing to do */
+}
+
+
+static int op_lookup_endpoints(TALLOC_CTX *mem_ctx, struct dcesrv_ep_iface **e)
+{
+ return dcesrv_lookup_endpoints(&dcerpc_table_epmapper, mem_ctx, e);
+}
+
+
+static const struct dcesrv_endpoint_ops rpc_epmapper_ops = {
+ op_query_endpoint,
+ op_set_interface,
+ op_connect,
+ op_disconnect,
+ op_lookup_endpoints
+};
+
+/*
+ register with the dcerpc server
+*/
+void rpc_epmapper_init(struct server_context *smb)
+{
+ if (!dcesrv_endpoint_register(smb, &rpc_epmapper_ops)) {
+ DEBUG(1,("Failed to register epmapper endpoint\n"));
+ }
+}
diff --git a/source4/rpc_server/handles.c b/source4/rpc_server/handles.c
new file mode 100644
index 0000000000..16e4175184
--- /dev/null
+++ b/source4/rpc_server/handles.c
@@ -0,0 +1,92 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ server side dcerpc handle code
+
+ Copyright (C) Andrew Tridgell 2003
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ allocate a new rpc handle
+*/
+struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_state *dce,
+ uint8 handle_type)
+{
+ TALLOC_CTX *mem_ctx;
+ struct dcesrv_handle *h;
+
+ mem_ctx = talloc_init("rpc handle type %d\n", handle_type);
+ if (!mem_ctx) {
+ return NULL;
+ }
+ h = talloc(mem_ctx, sizeof(*h));
+ if (!h) {
+ talloc_destroy(mem_ctx);
+ return NULL;
+ }
+ h->mem_ctx = mem_ctx;
+ h->data = NULL;
+
+ memset(h->wire_handle.data, 'H', sizeof(h->wire_handle.data));
+ strncpy(h->wire_handle.data, dce->ndr->name, 11);
+ h->wire_handle.data[11] = handle_type;
+
+ /* TODO: check for wraparound here */
+ SIVAL(&h->wire_handle.data, 12, random());
+ SIVAL(&h->wire_handle.data, 16, dce->next_handle);
+ dce->next_handle++;
+
+ DLIST_ADD(dce->handles, h);
+
+ return h;
+}
+
+/*
+ destroy a rpc handle
+*/
+void dcesrv_handle_destroy(struct dcesrv_state *dce,
+ struct dcesrv_handle *h)
+{
+ DLIST_REMOVE(dce->handles, h);
+ talloc_destroy(h->mem_ctx);
+}
+
+
+/*
+ find an internal handle given a wire handle. If the wire handle is NULL then
+ allocate a new handle
+*/
+struct dcesrv_handle *dcesrv_handle_fetch(struct dcesrv_state *dce,
+ struct policy_handle *p,
+ uint8 handle_type)
+{
+ struct dcesrv_handle *h;
+
+ if (all_zero(p->data, sizeof(p->data))) {
+ return dcesrv_handle_new(dce, handle_type);
+ }
+
+ for (h=dce->handles; h; h=h->next) {
+ if (memcmp(h->wire_handle.data, p->data, sizeof(p->data)) == 0) {
+ return h;
+ }
+ }
+
+ return NULL;
+}
diff --git a/source4/torture/rpc/epmapper.c b/source4/torture/rpc/epmapper.c
index 65e431bdc2..afc83a512d 100644
--- a/source4/torture/rpc/epmapper.c
+++ b/source4/torture/rpc/epmapper.c
@@ -130,15 +130,15 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
twr->towers.floors[2].lhs.protocol = EPM_PROTOCOL_RPC_C;
twr->towers.floors[2].lhs.info.lhs_data = data_blob(NULL, 0);
- twr->towers.floors[2].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2);
+ twr->towers.floors[2].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 2);
twr->towers.floors[3].lhs.protocol = EPM_PROTOCOL_TCP;
twr->towers.floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
- twr->towers.floors[3].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2);
+ twr->towers.floors[3].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 2);
twr->towers.floors[4].lhs.protocol = EPM_PROTOCOL_IP;
twr->towers.floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
- twr->towers.floors[4].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 4);
+ twr->towers.floors[4].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 4);
status = dcerpc_epm_Map(p, mem_ctx, &r);
if (NT_STATUS_IS_OK(status) && r.out.status == 0) {
@@ -151,7 +151,7 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
twr->towers.floors[3].lhs.protocol = EPM_PROTOCOL_HTTP;
twr->towers.floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
- twr->towers.floors[3].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2);
+ twr->towers.floors[3].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 2);
status = dcerpc_epm_Map(p, mem_ctx, &r);
if (NT_STATUS_IS_OK(status) && r.out.status == 0) {
@@ -164,11 +164,11 @@ static BOOL test_Map(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
twr->towers.floors[3].lhs.protocol = EPM_PROTOCOL_SMB;
twr->towers.floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
- twr->towers.floors[3].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2);
+ twr->towers.floors[3].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 2);
twr->towers.floors[4].lhs.protocol = EPM_PROTOCOL_NETBIOS;
twr->towers.floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
- twr->towers.floors[4].rhs.rhs_data = data_blob_talloc(p->mem_ctx, NULL, 2);
+ twr->towers.floors[4].rhs.rhs_data = data_blob_talloc_zero(p->mem_ctx, 2);
status = dcerpc_epm_Map(p, mem_ctx, &r);
if (NT_STATUS_IS_OK(status) && r.out.status == 0) {