diff options
author | Andrew Tridgell <tridge@samba.org> | 2009-09-21 21:36:54 -0700 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2009-09-22 17:10:05 -0700 |
commit | 69cb91a2eb2c3853663a61c2ed8f38e8fdde0964 (patch) | |
tree | 8a2bbcce7e837c5c3e2dda558dabed4306f6b236 /source4 | |
parent | a30d6130869239a6d6160c50908092e1d1424af5 (diff) | |
download | samba-69cb91a2eb2c3853663a61c2ed8f38e8fdde0964.tar.gz samba-69cb91a2eb2c3853663a61c2ed8f38e8fdde0964.tar.bz2 samba-69cb91a2eb2c3853663a61c2ed8f38e8fdde0964.zip |
s4-rpcserver: added shared association groups
This patch allows us to share association groups and their rpc handles
between connections. This is needed for some DRSUAPI behaviour when
recent windows clients connect.
Diffstat (limited to 'source4')
-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 && |