added a basic dcerpc endpoint mapper to Samba4. Currently only
authorAndrew Tridgell <tridge@samba.org>
Sat, 13 Dec 2003 02:20:40 +0000 (02:20 +0000)
committerAndrew Tridgell <tridge@samba.org>
Sat, 13 Dec 2003 02:20:40 +0000 (02:20 +0000)
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)

14 files changed:
source4/Makefile.in
source4/include/talloc.h
source4/lib/data_blob.c
source4/lib/genparser.c
source4/lib/talloc.c
source4/lib/util.c
source4/librpc/idl/dcerpc.idl
source4/librpc/rpc/dcerpc_util.c
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h
source4/rpc_server/echo/rpc_echo.c
source4/rpc_server/epmapper/rpc_epmapper.c [new file with mode: 0644]
source4/rpc_server/handles.c [new file with mode: 0644]
source4/torture/rpc/epmapper.c

index ce0668b9f10b7d5bb4544f12a2e1b223fe9b0337..f675aa4b291f4502eaae631e66d46fd1c5370320 100644 (file)
@@ -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 \
index 4badddbb88047e4a14ce0577f9df1c45baabd005..60a2822f38e1da0e7d33a9b98b6dfb2c2ca4d3b0 100644 (file)
@@ -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_ */
index 457ad382a28aa196021005cb6835ba04e2e5b403..b5d1b4076e1e4cb1563e21e2f403b637dd460f6a 100644 (file)
@@ -87,6 +87,18 @@ DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length)
        return ret;
 }
 
+/*******************************************************************
+ 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
 *******************************************************************/
index 39c455def409444ded0755582876566e2ce3d6c6..0f5d26620b2a99beec7b5dd5e4d7440a54579ff4 100644 (file)
 
 #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)
 {
index 83a99d8071cd8d809cf0241f1b0dc7afde1cb4db..25871feac1c1abb0431f7545984b844e141d901b 100644 (file)
  **/
 
 /**
- * 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)
@@ -470,6 +477,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
@@ -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);
+}
 
 /** @} */
index 9b6cef8bfe2b7351b0571bc056dd5b6e7a687696..233609263d9c61db340b0b804f9603b953f7896e 100644 (file)
@@ -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;
+}
+
index e6b59c2e2dab9e139bb02f7b1d0a38a5a55117e6..afe4b3003f9b25c720968bca13f7f0acf0a7b410 100644 (file)
@@ -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 */
index ef4af9f661038f0787d446ae303a403063c385ac..de46f532c6fbfc9472f8200a389d78ef68d667bb 100644 (file)
@@ -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;
index 4711f4e6ff487a6274ca9e5a1542582cb7355f7c..e2a6ab0132eb289b1b18233053bb2c99da774d32 100644 (file)
@@ -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;
        }
@@ -175,6 +185,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
 */
@@ -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;
@@ -612,11 +638,33 @@ 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;
 }
index 165eddc5e64f3be58b9e76676c4de78d18a5369e..3f2f5d039f35631b9cfabf3d61d1dfc2ba4174e6 100644 (file)
@@ -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 **);
 };
 
 
index 42856737c4b074dff30f8646cd3097cfaa015ebd..f741e63d6294cbfa99b4984348688a0452b00707 100644 (file)
@@ -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 (file)
index 0000000..945823c
--- /dev/null
@@ -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 (file)
index 0000000..16e4175
--- /dev/null
@@ -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;
+}
index 65e431bdc2eff740cb886f7624422406490841ac..afc83a512da67109afb3634bcd64b84d6a126086 100644 (file)
@@ -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) {