summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/rpc_server/dcerpc_server.c121
-rw-r--r--source4/rpc_server/dcerpc_server.h17
-rw-r--r--source4/rpc_server/handles.c7
3 files changed, 111 insertions, 34 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 97ed0a0d53..a70c920f75 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -36,10 +36,70 @@
#include "libcli/security/security.h"
#include "param/param.h"
-#define SAMBA_ASSOC_GROUP 0x12345678
+/* this is only used when the client asks for an unknown interface */
+#define DUMMY_ASSOC_GROUP 0x0FFFFFFF
extern const struct dcesrv_interface dcesrv_mgmt_interface;
+
+/*
+ find an association group given a assoc_group_id
+ */
+static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
+ uint32_t id)
+{
+ void *id_ptr;
+
+ id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
+ if (id_ptr == NULL) {
+ return NULL;
+ }
+ return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
+}
+
+/*
+ take a reference to an existing association group
+ */
+static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
+ struct dcesrv_context *dce_ctx,
+ uint32_t id)
+{
+ struct dcesrv_assoc_group *assoc_group;
+
+ assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
+ if (assoc_group == NULL) {
+ DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
+ return NULL;
+ }
+ return talloc_reference(mem_ctx, assoc_group);
+}
+
+/*
+ allocate a new association group
+ */
+static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
+ struct dcesrv_context *dce_ctx)
+{
+ struct dcesrv_assoc_group *assoc_group;
+ int id;
+
+ assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
+ if (assoc_group == NULL) {
+ return NULL;
+ }
+
+ id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
+ if (id == -1) {
+ talloc_free(assoc_group);
+ DEBUG(0,(__location__ ": Out of association groups!\n"));
+ return NULL;
+ }
+
+ assoc_group->id = id;
+ return assoc_group;
+}
+
+
/*
see if two endpoints match
*/
@@ -510,18 +570,11 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
uint32_t extra_flags = 0;
/*
- * Association groups allow policy handles to be shared across
- * multiple client connections. We don't implement this yet.
- *
- * So we just allow 0 if the client wants to create a new
- * association group.
- *
- * And we allow the 0x12345678 value, we give away as
- * assoc_group_id back to the clients
+ if provided, check the assoc_group is valid
*/
if (call->pkt.u.bind.assoc_group_id != 0 &&
lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
- call->pkt.u.bind.assoc_group_id != SAMBA_ASSOC_GROUP) {
+ dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
return dcesrv_bind_nak(call, 0);
}
@@ -572,13 +625,18 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
context->conn = call->conn;
context->iface = iface;
context->context_id = context_id;
- /*
- * we need to send a non zero assoc_group_id here to make longhorn happy,
- * it also matches samba3
- */
- context->assoc_group_id = SAMBA_ASSOC_GROUP;
+ if (call->pkt.u.bind.assoc_group_id != 0) {
+ context->assoc_group = dcesrv_assoc_group_reference(context,
+ call->conn->dce_ctx,
+ call->pkt.u.bind.assoc_group_id);
+ } else {
+ context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
+ }
+ if (context->assoc_group == NULL) {
+ talloc_free(context);
+ return dcesrv_bind_nak(call, 0);
+ }
context->private_data = NULL;
- context->handles = NULL;
DLIST_ADD(call->conn->contexts, context);
call->context = context;
talloc_set_destructor(context, dcesrv_connection_context_destructor);
@@ -630,12 +688,9 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
metze
*/
if (call->context) {
- pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
+ pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
} else {
- /* we better pick something - this chosen so as to
- * send a non zero assoc_group_id (matching windows),
- * it also matches samba3 */
- pkt.u.bind_ack.assoc_group_id = SAMBA_ASSOC_GROUP;
+ pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
}
if (iface) {
@@ -748,9 +803,19 @@ static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_
context->conn = call->conn;
context->iface = iface;
context->context_id = context_id;
- context->assoc_group_id = SAMBA_ASSOC_GROUP;
+ if (call->pkt.u.alter.assoc_group_id != 0) {
+ context->assoc_group = dcesrv_assoc_group_reference(context,
+ call->conn->dce_ctx,
+ call->pkt.u.alter.assoc_group_id);
+ } else {
+ context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
+ }
+ if (context->assoc_group == NULL) {
+ talloc_free(context);
+ call->context = NULL;
+ return NT_STATUS_NO_MEMORY;
+ }
context->private_data = NULL;
- context->handles = NULL;
DLIST_ADD(call->conn->contexts, context);
call->context = context;
talloc_set_destructor(context, dcesrv_connection_context_destructor);
@@ -803,8 +868,10 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
if (result == 0 &&
call->pkt.u.alter.assoc_group_id != 0 &&
lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
- call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
- /* TODO: work out what to return here */
+ call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
+ DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
+ call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
+ /* TODO: can they ask for a new association group? */
result = DCERPC_BIND_PROVIDER_REJECT;
reason = DCERPC_BIND_REASON_ASYNTAX;
}
@@ -818,7 +885,7 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
pkt.u.alter_resp.max_xmit_frag = 0x2000;
pkt.u.alter_resp.max_recv_frag = 0x2000;
if (result == 0) {
- pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
+ pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
} else {
pkt.u.alter_resp.assoc_group_id = 0;
}
@@ -1205,6 +1272,8 @@ _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
dce_ctx->endpoint_list = NULL;
dce_ctx->lp_ctx = lp_ctx;
+ dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
for (i=0;endpoint_servers[i];i++) {
const struct dcesrv_endpoint_server *ep_server;
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 0c4d4d413d..a64b01fdc5 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -153,7 +153,7 @@ struct dcesrv_connection_context {
struct dcesrv_connection_context *next, *prev;
uint32_t context_id;
- uint32_t assoc_group_id;
+ struct dcesrv_assoc_group *assoc_group;
/* the connection this is on */
struct dcesrv_connection *conn;
@@ -163,10 +163,6 @@ struct dcesrv_connection_context {
/* private data for the interface implementation */
void *private_data;
-
- /* current rpc handles - this is really the wrong scope for
- them, but it will do for now */
- struct dcesrv_handle *handles;
};
@@ -252,6 +248,15 @@ struct dcesrv_endpoint_server {
};
+/* one association groups */
+struct dcesrv_assoc_group {
+ /* the wire id */
+ uint32_t id;
+
+ /* list of handles in this association group */
+ struct dcesrv_handle *handles;
+};
+
/* server-wide context information for the dcerpc server */
struct dcesrv_context {
/* the list of endpoints that have registered
@@ -272,6 +277,8 @@ struct dcesrv_context {
/* loadparm context to use for this connection */
struct loadparm_context *lp_ctx;
+
+ struct idr_context *assoc_groups_idr;
};
/* this structure is used by modules to determine the size of some critical types */
diff --git a/source4/rpc_server/handles.c b/source4/rpc_server/handles.c
index 284354feb4..74b0ddc82e 100644
--- a/source4/rpc_server/handles.c
+++ b/source4/rpc_server/handles.c
@@ -28,7 +28,7 @@
*/
static int dcesrv_handle_destructor(struct dcesrv_handle *h)
{
- DLIST_REMOVE(h->context->handles, h);
+ DLIST_REMOVE(h->context->assoc_group->handles, h);
return 0;
}
@@ -51,7 +51,7 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_connection_contex
h->wire_handle.handle_type = handle_type;
h->wire_handle.uuid = GUID_random();
- DLIST_ADD(context->handles, h);
+ DLIST_ADD(context->assoc_group->handles, h);
talloc_set_destructor(h, dcesrv_handle_destructor);
@@ -70,10 +70,11 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch(
struct dcesrv_handle *h;
if (policy_handle_empty(p)) {
+ /* TODO: we should probably return a NULL handle here */
return dcesrv_handle_new(context, handle_type);
}
- for (h=context->handles; h; h=h->next) {
+ for (h=context->assoc_group->handles; h; h=h->next) {
if (h->wire_handle.handle_type == p->handle_type &&
GUID_equal(&p->uuid, &h->wire_handle.uuid)) {
if (handle_type != DCESRV_HANDLE_ANY &&