mirror of
https://github.com/samba-team/samba.git
synced 2025-02-24 13:57:43 +03:00
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)
This commit is contained in:
parent
f7065cc0a5
commit
340d9b71f9
@ -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 \
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
*******************************************************************/
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 **);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
/*
|
||||
|
274
source4/rpc_server/epmapper/rpc_epmapper.c
Normal file
274
source4/rpc_server/epmapper/rpc_epmapper.c
Normal file
@ -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"));
|
||||
}
|
||||
}
|
92
source4/rpc_server/handles.c
Normal file
92
source4/rpc_server/handles.c
Normal file
@ -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;
|
||||
}
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user