summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2014-01-05 08:12:45 +0100
committerStefan Metzmacher <metze@samba.org>2014-01-07 02:24:41 +0100
commit6ab9164c74e0ad57bdde8abb568953026b644e27 (patch)
treedfccd6f83a2feece64b948ee8e89479bdbb227a0
parentf0532fe0cd69aeb161088ca990d376f119102e61 (diff)
downloadsamba-6ab9164c74e0ad57bdde8abb568953026b644e27.tar.gz
samba-6ab9164c74e0ad57bdde8abb568953026b644e27.tar.xz
samba-6ab9164c74e0ad57bdde8abb568953026b644e27.zip
s3:rpc_client: send a dcerpc_sec_verification_trailer if needed
Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Autobuild-User(master): Stefan Metzmacher <metze@samba.org> Autobuild-Date(master): Tue Jan 7 02:24:42 CET 2014 on sn-devel-104
-rw-r--r--source3/librpc/rpc/dcerpc.h1
-rw-r--r--source3/rpc_client/cli_pipe.c202
-rw-r--r--source3/rpc_client/rpc_client.h1
3 files changed, 194 insertions, 10 deletions
diff --git a/source3/librpc/rpc/dcerpc.h b/source3/librpc/rpc/dcerpc.h
index aaf8d685783..9d0f86156e7 100644
--- a/source3/librpc/rpc/dcerpc.h
+++ b/source3/librpc/rpc/dcerpc.h
@@ -41,6 +41,7 @@ struct pipe_auth_data {
enum dcerpc_AuthLevel auth_level;
bool client_hdr_signing;
bool hdr_signing;
+ bool verified_bitmask1;
void *auth_ctx;
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index a8f3dc1a3d9..b6908be7e28 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -1163,12 +1163,17 @@ struct rpc_api_pipe_req_state {
uint32_t call_id;
const DATA_BLOB *req_data;
uint32_t req_data_sent;
+ DATA_BLOB req_trailer;
+ uint32_t req_trailer_sent;
+ bool verify_bitmask1;
+ bool verify_pcontext;
DATA_BLOB rpc_out;
DATA_BLOB reply_pdu;
};
static void rpc_api_pipe_req_write_done(struct tevent_req *subreq);
static void rpc_api_pipe_req_done(struct tevent_req *subreq);
+static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state);
static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
bool *is_last_frag);
@@ -1204,6 +1209,11 @@ static struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
goto post_status;
}
+ status = prepare_verification_trailer(state);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto post_status;
+ }
+
status = prepare_next_frag(state, &is_last_frag);
if (!NT_STATUS_IS_OK(status)) {
goto post_status;
@@ -1238,25 +1248,164 @@ static struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
return NULL;
}
+static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state)
+{
+ struct pipe_auth_data *a = state->cli->auth;
+ struct dcerpc_sec_verification_trailer *t;
+ struct dcerpc_sec_vt *c = NULL;
+ struct ndr_push *ndr = NULL;
+ enum ndr_err_code ndr_err;
+ size_t align = 0;
+ size_t pad = 0;
+
+ if (a == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ if (a->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
+ return NT_STATUS_OK;
+ }
+
+ t = talloc_zero(state, struct dcerpc_sec_verification_trailer);
+ if (t == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!a->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 (a->client_hdr_signing) {
+ c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
+ }
+ state->verify_bitmask1 = true;
+ }
+
+ if (!state->cli->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 = state->cli->abstract_syntax;
+ c->u.pcontext.transfer_syntax = state->cli->transfer_syntax;
+
+ state->verify_pcontext = true;
+ }
+
+ if (!a->hdr_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;
+ 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 = state->call_id;
+ c->u.header2.context_id = 0;
+ c->u.header2.opnum = state->op_num;
+ }
+
+ 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(state);
+ if (ndr == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ 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);
+ }
+ state->req_trailer = ndr_push_blob(ndr);
+
+ align = state->req_data->length & 0x3;
+ if (align > 0) {
+ pad = 4 - align;
+ }
+ if (pad > 0) {
+ bool ok;
+ uint8_t *p;
+ const uint8_t zeros[4] = { 0, };
+
+ ok = data_blob_append(ndr, &state->req_trailer, zeros, pad);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* move the padding to the start */
+ p = state->req_trailer.data;
+ memmove(p + pad, p, state->req_trailer.length - pad);
+ memset(p, 0, pad);
+ }
+
+ return NT_STATUS_OK;
+}
+
static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
bool *is_last_frag)
{
- size_t data_sent_thistime;
size_t auth_len;
size_t frag_len;
uint8_t flags = 0;
size_t pad_len;
size_t data_left;
+ size_t data_thistime;
+ size_t trailer_left;
+ size_t trailer_thistime = 0;
+ size_t total_left;
+ size_t total_thistime;
NTSTATUS status;
+ bool ok;
union dcerpc_payload u;
data_left = state->req_data->length - state->req_data_sent;
+ trailer_left = state->req_trailer.length - state->req_trailer_sent;
+ total_left = data_left + trailer_left;
+ if ((total_left < data_left) || (total_left < trailer_left)) {
+ /*
+ * overflow
+ */
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
status = dcerpc_guess_sizes(state->cli->auth,
- DCERPC_REQUEST_LENGTH, data_left,
+ DCERPC_REQUEST_LENGTH, total_left,
state->cli->max_xmit_frag,
CLIENT_NDR_PADDING_SIZE,
- &data_sent_thistime,
+ &total_thistime,
&frag_len, &auth_len, &pad_len);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -1266,15 +1415,20 @@ static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
flags = DCERPC_PFC_FLAG_FIRST;
}
- if (data_sent_thistime == data_left) {
+ if (total_thistime == total_left) {
flags |= DCERPC_PFC_FLAG_LAST;
}
+ data_thistime = MIN(total_thistime, data_left);
+ if (data_thistime < total_thistime) {
+ trailer_thistime = total_thistime - data_thistime;
+ }
+
data_blob_free(&state->rpc_out);
ZERO_STRUCT(u.request);
- u.request.alloc_hint = data_left;
+ u.request.alloc_hint = total_left;
u.request.context_id = 0;
u.request.opnum = state->op_num;
@@ -1294,11 +1448,26 @@ static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
* at this stage */
dcerpc_set_frag_length(&state->rpc_out, frag_len);
- /* Copy in the data. */
- if (!data_blob_append(NULL, &state->rpc_out,
+ if (data_thistime > 0) {
+ /* Copy in the data. */
+ ok = data_blob_append(NULL, &state->rpc_out,
state->req_data->data + state->req_data_sent,
- data_sent_thistime)) {
- return NT_STATUS_NO_MEMORY;
+ data_thistime);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state->req_data_sent += data_thistime;
+ }
+
+ if (trailer_thistime > 0) {
+ /* Copy in the verification trailer. */
+ ok = data_blob_append(NULL, &state->rpc_out,
+ state->req_trailer.data + state->req_trailer_sent,
+ trailer_thistime);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state->req_trailer_sent += trailer_thistime;
}
switch (state->cli->auth->auth_level) {
@@ -1318,7 +1487,6 @@ static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
return NT_STATUS_INVALID_PARAMETER;
}
- state->req_data_sent += data_sent_thistime;
*is_last_frag = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
return status;
@@ -1382,6 +1550,20 @@ static void rpc_api_pipe_req_done(struct tevent_req *subreq)
tevent_req_nterror(req, status);
return;
}
+
+ if (state->cli->auth == NULL) {
+ tevent_req_done(req);
+ return;
+ }
+
+ if (state->verify_bitmask1) {
+ state->cli->auth->verified_bitmask1 = true;
+ }
+
+ if (state->verify_pcontext) {
+ state->cli->verified_pcontext = true;
+ }
+
tevent_req_done(req);
}
diff --git a/source3/rpc_client/rpc_client.h b/source3/rpc_client/rpc_client.h
index 6561b28b7c1..8024f018215 100644
--- a/source3/rpc_client/rpc_client.h
+++ b/source3/rpc_client/rpc_client.h
@@ -39,6 +39,7 @@ struct rpc_pipe_client {
struct ndr_syntax_id abstract_syntax;
struct ndr_syntax_id transfer_syntax;
+ bool verified_pcontext;
char *desthost;
char *srv_name_slash;