diff options
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 71 | ||||
-rw-r--r-- | source4/rpc_server/dcesrv_auth.c | 15 |
2 files changed, 80 insertions, 6 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 808cad94d9..925004b191 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -599,6 +599,56 @@ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call) return NT_STATUS_OK; } + +/* + handle a bind request +*/ +static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32 context_id) +{ + uint32_t if_version, transfer_syntax_version; + const char *uuid, *transfer_syntax; + struct dcesrv_connection_context *context; + const struct dcesrv_interface *iface; + + if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version; + uuid = GUID_string(call, &call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid); + if (!uuid) { + return NT_STATUS_NO_MEMORY; + } + + transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version; + transfer_syntax = GUID_string(call, + &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid); + if (!transfer_syntax || + strcasecmp(NDR_GUID, transfer_syntax) != 0 || + NDR_GUID_VERSION != transfer_syntax_version) { + /* we only do NDR encoded dcerpc */ + return NT_STATUS_NO_MEMORY; + } + + iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version); + if (iface == NULL) { + DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version)); + return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED; + } + + /* add this context to the list of available context_ids */ + context = talloc(call->conn, struct dcesrv_connection_context); + if (context == NULL) { + return NT_STATUS_NO_MEMORY; + } + context->conn = call->conn; + context->iface = iface; + context->context_id = context_id; + context->private = NULL; + context->handles = NULL; + DLIST_ADD(call->conn->contexts, context); + call->context = context; + + return NT_STATUS_OK; +} + + /* handle a bind request */ @@ -608,14 +658,28 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call) struct dcesrv_call_reply *rep; NTSTATUS status; uint32_t result=0, reason=0; + uint32_t context_id; /* handle any authentication that is being requested */ if (!dcesrv_auth_alter(call)) { /* TODO: work out the right reject code */ - return dcesrv_bind_nak(call, 0); + result = DCERPC_BIND_PROVIDER_REJECT; + reason = DCERPC_BIND_REASON_ASYNTAX; + } + + context_id = call->pkt.u.alter.ctx_list[0].context_id; + + /* see if they are asking for a new interface */ + if (result == 0 && + dcesrv_find_context(call->conn, context_id) == NULL) { + status = dcesrv_alter_new_context(call, context_id); + if (!NT_STATUS_IS_OK(status)) { + result = DCERPC_BIND_PROVIDER_REJECT; + reason = DCERPC_BIND_REASON_ASYNTAX; + } } - /* setup a alter_ack */ + /* setup a alter_resp */ dcesrv_init_hdr(&pkt); pkt.auth_length = 0; pkt.call_id = call->pkt.call_id; @@ -623,7 +687,7 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call) pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; pkt.u.alter_resp.max_xmit_frag = 0x2000; pkt.u.alter_resp.max_recv_frag = 0x2000; - pkt.u.alter_resp.assoc_group_id = call->pkt.u.bind.assoc_group_id; + pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id; pkt.u.alter_resp.secondary_address = NULL; pkt.u.alter_resp.num_results = 1; pkt.u.alter_resp.ctx_list = talloc_p(call, struct dcerpc_ack_ctx); @@ -635,6 +699,7 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call) GUID_from_string(NDR_GUID, &pkt.u.alter_resp.ctx_list[0].syntax.uuid); pkt.u.alter_resp.ctx_list[0].syntax.if_version = NDR_GUID_VERSION; pkt.u.alter_resp.auth_info = data_blob(NULL, 0); + pkt.u.alter_resp.secondary_address = ""; if (!dcesrv_auth_alter_ack(call, &pkt)) { return dcesrv_bind_nak(call, 0); diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c index 71332b557d..91b579b9e4 100644 --- a/source4/rpc_server/dcesrv_auth.c +++ b/source4/rpc_server/dcesrv_auth.c @@ -204,9 +204,13 @@ BOOL dcesrv_auth_alter(struct dcesrv_call_state *call) struct dcesrv_connection *dce_conn = call->conn; NTSTATUS status; - /* We can't work without an existing gensec state, and an new blob to feed it */ - if (!dce_conn->auth_state.gensec_security || - pkt->u.alter.auth_info.length == 0) { + /* on a pure interface change there is no auth blob */ + if (pkt->u.alter.auth_info.length == 0) { + return True; + } + + /* We can't work without an existing gensec state */ + if (!dce_conn->auth_state.gensec_security) { return False; } @@ -235,6 +239,11 @@ BOOL dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct dcerpc_packet struct dcesrv_connection *dce_conn = call->conn; NTSTATUS status; + /* on a pure interface change there is no auth blob */ + if (pkt->u.alter.auth_info.length == 0) { + return True; + } + if (!call->conn->auth_state.gensec_security) { return False; } |