summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/librpc/idl/dcerpc.idl7
-rw-r--r--source4/rpc_server/dcerpc_server.c89
2 files changed, 79 insertions, 17 deletions
diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl
index 7646f7d223..e6b59c2e2d 100644
--- a/source4/librpc/idl/dcerpc.idl
+++ b/source4/librpc/idl/dcerpc.idl
@@ -45,6 +45,9 @@ interface dcerpc
[flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier;
} dcerpc_request;
+ const int DCERPC_BIND_PROVIDER_REJECT = 2;
+ const int DCERPC_BIND_REASON_ASYNTAX = 1;
+
typedef struct {
uint16 result;
uint16 reason;
@@ -80,6 +83,8 @@ interface dcerpc
const int DCERPC_FAULT_OP_RNG_ERROR = 0x1c010002;
+ const int DCERPC_FAULT_NDR = 0x000006f7;
+ 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 */
@@ -150,7 +155,7 @@ interface dcerpc
[case(DCERPC_PKT_ALTER_ACK)] dcerpc_bind_ack alter_ack;
[case(DCERPC_PKT_FAULT)] dcerpc_fault fault;
[case(DCERPC_PKT_AUTH3)] dcerpc_auth3 auth;
- [case(DCERPC_PKT_BIND_NAK)] dcerpc_bind_nak nak;
+ [case(DCERPC_PKT_BIND_NAK)] dcerpc_bind_nak bind_nak;
} dcerpc_payload;
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 45e720b8c1..4711f4e6ff 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -101,6 +101,8 @@ NTSTATUS dcesrv_endpoint_connect(struct server_context *smb,
(*p)->private = NULL;
(*p)->call_list = NULL;
(*p)->cli_max_recv_frag = 0;
+ (*p)->ndr = NULL;
+ (*p)->dispatch = NULL;
/* make sure the endpoint server likes the connection */
status = ops->connect(*p);
@@ -148,7 +150,56 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
pkt.u.fault.cancel_count = 0;
pkt.u.fault.status = fault_code;
- /* now form the NDR for the bind_ack */
+ /* now form the NDR for the fault */
+ push = ndr_push_init_ctx(call->mem_ctx);
+ if (!push) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ rep = talloc(call->mem_ctx, sizeof(*rep));
+ if (!rep) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rep->data = ndr_push_blob(push);
+ SSVAL(rep->data.data, DCERPC_FRAG_LEN_OFFSET, rep->data.length);
+
+ DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ return a dcerpc bind_nak
+*/
+static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason)
+{
+ struct ndr_push *push;
+ struct dcerpc_packet pkt;
+ struct dcesrv_call_reply *rep;
+ NTSTATUS status;
+
+ /* setup a bind_ack */
+ pkt.rpc_vers = 5;
+ pkt.rpc_vers_minor = 0;
+ pkt.drep[0] = 0x10; /* Little endian */
+ pkt.drep[1] = 0;
+ pkt.drep[2] = 0;
+ pkt.drep[3] = 0;
+ pkt.auth_length = 0;
+ pkt.call_id = call->pkt.call_id;
+ pkt.ptype = DCERPC_PKT_BIND_NAK;
+ pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ pkt.u.bind_nak.reject_reason = reason;
+ pkt.u.bind_nak.num_versions = 0;
+
+ /* now form the NDR for the bind_nak */
push = ndr_push_init_ctx(call->mem_ctx);
if (!push) {
return NT_STATUS_NO_MEMORY;
@@ -184,16 +235,17 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
struct ndr_push *push;
struct dcesrv_call_reply *rep;
NTSTATUS status;
+ uint32 result=0, reason=0;
if (call->pkt.u.bind.num_contexts != 1 ||
call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
- return dcesrv_fault(call, DCERPC_FAULT_TODO);
+ return dcesrv_bind_nak(call, 0);
}
if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.major_version;
uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
if (!uuid) {
- return dcesrv_fault(call, DCERPC_FAULT_TODO);
+ return dcesrv_bind_nak(call, 0);
}
transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].major_version;
@@ -203,13 +255,14 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
NDR_GUID_VERSION != transfer_syntax_version) {
/* we only do NDR encoded dcerpc */
- return dcesrv_fault(call, DCERPC_FAULT_TODO);
+ return dcesrv_bind_nak(call, 0);
}
if (!call->dce->ops->set_interface(call->dce, uuid, if_version)) {
DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
/* we don't know about that interface */
- return dcesrv_fault(call, DCERPC_FAULT_TODO);
+ result = DCERPC_BIND_PROVIDER_REJECT;
+ reason = DCERPC_BIND_REASON_ASYNTAX;
}
if (call->dce->cli_max_recv_frag == 0) {
@@ -230,15 +283,19 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
pkt.u.bind_ack.max_xmit_frag = 0x2000;
pkt.u.bind_ack.max_recv_frag = 0x2000;
pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
- pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s",
- call->dce->ndr->name);
+ if (call->dce->ndr) {
+ pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s",
+ call->dce->ndr->name);
+ } else {
+ 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));
if (!pkt.u.bind_ack.ctx_list) {
return NT_STATUS_NO_MEMORY;
}
- pkt.u.bind_ack.ctx_list[0].result = 0;
- pkt.u.bind_ack.ctx_list[0].reason = 0;
+ pkt.u.bind_ack.ctx_list[0].result = result;
+ pkt.u.bind_ack.ctx_list[0].reason = reason;
GUID_from_string(uuid, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
pkt.u.bind_ack.ctx_list[0].syntax.major_version = if_version;
pkt.u.bind_ack.ctx_list[0].syntax.minor_version = 0;
@@ -300,13 +357,13 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
/* unravel the NDR for the packet */
status = call->dce->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
if (!NT_STATUS_IS_OK(status)) {
- return dcesrv_fault(call, DCERPC_FAULT_TODO);
+ return dcesrv_fault(call, DCERPC_FAULT_NDR);
}
/* 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_TODO);
+ return dcesrv_fault(call, DCERPC_FAULT_NDR);
}
/* form the reply NDR */
@@ -317,7 +374,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
status = call->dce->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
if (!NT_STATUS_IS_OK(status)) {
- return dcesrv_fault(call, DCERPC_FAULT_TODO);
+ return dcesrv_fault(call, DCERPC_FAULT_NDR);
}
stub = ndr_push_blob(push);
@@ -426,19 +483,19 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
/* we only allow fragmented requests, no other packet types */
if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
- return dcesrv_fault(call2, DCERPC_FAULT_TODO);
+ return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
}
/* this is a continuation of an existing call - find the call then
tack it on the end */
call = dcesrv_find_call(dce, call2->pkt.call_id);
if (!call) {
- return dcesrv_fault(call2, DCERPC_FAULT_TODO);
+ return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
}
if (call->pkt.ptype != call2->pkt.ptype) {
/* trying to play silly buggers are we? */
- return dcesrv_fault(call2, DCERPC_FAULT_TODO);
+ return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
}
alloc_size = call->pkt.u.request.stub_and_verifier.length +
@@ -451,7 +508,7 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
talloc_realloc(call->mem_ctx,
call->pkt.u.request.stub_and_verifier.data, alloc_size);
if (!call->pkt.u.request.stub_and_verifier.data) {
- return dcesrv_fault(call2, DCERPC_FAULT_TODO);
+ return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
}
memcpy(call->pkt.u.request.stub_and_verifier.data +
call->pkt.u.request.stub_and_verifier.length,