diff options
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 121 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_server.h | 17 | ||||
-rw-r--r-- | source4/rpc_server/handles.c | 7 |
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 && |