From 340d9b71f9e75d634389104da5949ba59669ede2 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 13 Dec 2003 02:20:40 +0000 Subject: 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) --- source4/Makefile.in | 4 +- source4/include/talloc.h | 5 + source4/lib/data_blob.c | 12 ++ source4/lib/genparser.c | 11 -- source4/lib/talloc.c | 57 +++++- source4/lib/util.c | 14 ++ source4/librpc/idl/dcerpc.idl | 7 +- source4/librpc/rpc/dcerpc_util.c | 10 +- source4/rpc_server/dcerpc_server.c | 64 ++++++- source4/rpc_server/dcerpc_server.h | 31 +++- source4/rpc_server/echo/rpc_echo.c | 8 +- source4/rpc_server/epmapper/rpc_epmapper.c | 274 +++++++++++++++++++++++++++++ source4/rpc_server/handles.c | 92 ++++++++++ source4/torture/rpc/epmapper.c | 12 +- 14 files changed, 562 insertions(+), 39 deletions(-) create mode 100644 source4/rpc_server/epmapper/rpc_epmapper.c create mode 100644 source4/rpc_server/handles.c (limited to 'source4') 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 @@ -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 *******************************************************************/ 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;ilist) 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); +} /** @} */ 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;imem_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; } @@ -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; } 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;iout.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) { -- cgit