summaryrefslogtreecommitdiff
path: root/source4/librpc
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2015-07-08 16:25:48 +0200
committerStefan Metzmacher <metze@samba.org>2016-04-12 19:25:28 +0200
commit335b3cee5c7789a68629948ba6f3096847550c58 (patch)
tree104918366c4629b556ca5d4933f2172e493a4d64 /source4/librpc
parent67f6fd305c88c288523ffa3b4550d6a2d02e5d9a (diff)
downloadsamba-335b3cee5c7789a68629948ba6f3096847550c58.tar.gz
CVE-2015-5370: s4:librpc/rpc: send a dcerpc_sec_verification_trailer if needed
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Günther Deschner <gd@samba.org>
Diffstat (limited to 'source4/librpc')
-rw-r--r--source4/librpc/rpc/dcerpc.c136
-rw-r--r--source4/librpc/rpc/dcerpc.h5
2 files changed, 141 insertions, 0 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 88a041c82d2..5900c063bba 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -65,6 +65,8 @@ struct rpc_request {
DATA_BLOB request_data;
bool ignore_timeout;
bool wait_for_sync;
+ bool verify_bitmask1;
+ bool verify_pcontext;
struct {
void (*callback)(struct rpc_request *);
@@ -1547,6 +1549,13 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
return;
}
+ if (req->verify_bitmask1) {
+ req->p->conn->security_state.verified_bitmask1 = true;
+ }
+ if (req->verify_pcontext) {
+ req->p->verified_pcontext = true;
+ }
+
if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
req->flags |= DCERPC_PULL_BIGENDIAN;
} else {
@@ -1571,6 +1580,8 @@ req_done:
}
}
+static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
+
/*
perform the send side of a async dcerpc request
*/
@@ -1581,6 +1592,7 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
DATA_BLOB *stub_data)
{
struct rpc_request *req;
+ NTSTATUS status;
req = talloc_zero(mem_ctx, struct rpc_request);
if (req == NULL) {
@@ -1603,6 +1615,12 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
req->request_data.length = stub_data->length;
req->request_data.data = stub_data->data;
+ status = dcerpc_request_prepare_vt(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(req);
+ return NULL;
+ }
+
DLIST_ADD_END(p->conn->request_queue, req);
talloc_set_destructor(req, dcerpc_req_dequeue);
@@ -1617,6 +1635,124 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
return req;
}
+static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
+{
+ struct dcecli_security *sec = &req->p->conn->security_state;
+ struct dcerpc_sec_verification_trailer *t;
+ struct dcerpc_sec_vt *c = NULL;
+ struct ndr_push *ndr = NULL;
+ enum ndr_err_code ndr_err;
+
+ if (sec->auth_info == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ if (sec->auth_info->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
+ return NT_STATUS_OK;
+ }
+
+ t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
+ if (t == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!sec->verified_bitmask1) {
+ t->commands = talloc_realloc(t, t->commands,
+ struct dcerpc_sec_vt,
+ t->count.count + 1);
+ if (t->commands == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ c = &t->commands[t->count.count++];
+ ZERO_STRUCTP(c);
+
+ c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
+ if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
+ c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
+ }
+ req->verify_bitmask1 = true;
+ }
+
+ if (!req->p->verified_pcontext) {
+ t->commands = talloc_realloc(t, t->commands,
+ struct dcerpc_sec_vt,
+ t->count.count + 1);
+ if (t->commands == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ c = &t->commands[t->count.count++];
+ ZERO_STRUCTP(c);
+
+ c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
+ c->u.pcontext.abstract_syntax = req->p->syntax;
+ c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
+
+ req->verify_pcontext = true;
+ }
+
+ if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
+ t->commands = talloc_realloc(t, t->commands,
+ struct dcerpc_sec_vt,
+ t->count.count + 1);
+ if (t->commands == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ c = &t->commands[t->count.count++];
+ ZERO_STRUCTP(c);
+
+ c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
+ c->u.header2.ptype = DCERPC_PKT_REQUEST;
+ if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
+ c->u.header2.drep[0] = 0;
+ } else {
+ c->u.header2.drep[0] = DCERPC_DREP_LE;
+ }
+ c->u.header2.drep[1] = 0;
+ c->u.header2.drep[2] = 0;
+ c->u.header2.drep[3] = 0;
+ c->u.header2.call_id = req->call_id;
+ c->u.header2.context_id = req->p->context_id;
+ c->u.header2.opnum = req->opnum;
+ }
+
+ if (t->count.count == 0) {
+ TALLOC_FREE(t);
+ return NT_STATUS_OK;
+ }
+
+ c = &t->commands[t->count.count - 1];
+ c->command |= DCERPC_SEC_VT_COMMAND_END;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
+ }
+
+ ndr = ndr_push_init_ctx(req);
+ if (ndr == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * for now we just copy and append
+ */
+
+ ndr_err = ndr_push_bytes(ndr, req->request_data.data,
+ req->request_data.length);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
+ NDR_SCALARS | NDR_BUFFERS,
+ t);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ req->request_data = ndr_push_blob(ndr);
+
+ return NT_STATUS_OK;
+}
+
/*
Send a request using the transport
*/
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index 6385dd06dce..707e4ccfd09 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -51,6 +51,9 @@ struct dcecli_security {
/* get the session key */
NTSTATUS (*session_key)(struct dcecli_connection *, DATA_BLOB *);
+
+ bool verified_bitmask1;
+
};
/*
@@ -126,6 +129,8 @@ struct dcerpc_pipe {
*/
bool inhibit_timeout_processing;
bool timed_out;
+
+ bool verified_pcontext;
};
/* default timeout for all rpc requests, in seconds */