diff options
Diffstat (limited to 'source4/librpc/rpc/dcerpc.c')
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 126 |
1 files changed, 71 insertions, 55 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 0595d5eade..c2f691aa09 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -36,6 +36,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(void) p->reference_count = 0; p->call_id = 1; p->security_state.auth_info = NULL; + p->security_state.session_key = dcerpc_generic_session_key; p->security_state.generic_state = NULL; p->binding_string = NULL; p->flags = 0; @@ -206,8 +207,8 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, if (!NT_STATUS_IS_OK(status)) { return status; } - - + + /* check signature or unseal the packet */ switch (p->security_state.auth_info->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: @@ -215,6 +216,8 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, mem_ctx, pkt->u.response.stub_and_verifier.data, pkt->u.response.stub_and_verifier.length, + blob->data, + blob->length - auth.credentials.length, &auth.credentials); break; @@ -223,9 +226,11 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, mem_ctx, pkt->u.response.stub_and_verifier.data, pkt->u.response.stub_and_verifier.length, + blob->data, + blob->length - auth.credentials.length, &auth.credentials); break; - + case DCERPC_AUTH_LEVEL_NONE: break; @@ -233,7 +238,7 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, status = NT_STATUS_INVALID_LEVEL; break; } - + /* remove the indicated amount of paddiing */ if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) { return NT_STATUS_INFO_LENGTH_MISMATCH; @@ -253,6 +258,7 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, { NTSTATUS status; struct ndr_push *ndr; + DATA_BLOB creds2; /* non-signed packets are simpler */ if (!p->security_state.auth_info || !p->security_state.generic_state) { @@ -282,30 +288,21 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, /* sign or seal the packet */ switch (p->security_state.auth_info->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: - status = gensec_seal_packet(p->security_state.generic_state, - mem_ctx, - ndr->data + DCERPC_REQUEST_LENGTH, - ndr->offset - DCERPC_REQUEST_LENGTH, - &p->security_state.auth_info->credentials); - break; - case DCERPC_AUTH_LEVEL_INTEGRITY: - status = gensec_sign_packet(p->security_state.generic_state, - mem_ctx, - ndr->data + DCERPC_REQUEST_LENGTH, - ndr->offset - DCERPC_REQUEST_LENGTH, - &p->security_state.auth_info->credentials); + p->security_state.auth_info->credentials + = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state)); + data_blob_clear(&p->security_state.auth_info->credentials); break; case DCERPC_AUTH_LEVEL_NONE: p->security_state.auth_info->credentials = data_blob(NULL, 0); break; - + default: status = NT_STATUS_INVALID_LEVEL; break; } - + if (!NT_STATUS_IS_OK(status)) { return status; } @@ -325,6 +322,41 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, dcerpc_set_frag_length(blob, blob->length); dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length); + /* sign or seal the packet */ + switch (p->security_state.auth_info->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + status = gensec_seal_packet(p->security_state.generic_state, + mem_ctx, + ndr->data + DCERPC_REQUEST_LENGTH, + ndr->offset - DCERPC_REQUEST_LENGTH, + blob->data, + blob->length - + p->security_state.auth_info->credentials.length, + &creds2); + memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length); + break; + + case DCERPC_AUTH_LEVEL_INTEGRITY: + status = gensec_sign_packet(p->security_state.generic_state, + mem_ctx, + ndr->data + DCERPC_REQUEST_LENGTH, + ndr->offset - DCERPC_REQUEST_LENGTH, + blob->data, + blob->length - + p->security_state.auth_info->credentials.length, + &creds2); + memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length); + break; + + case DCERPC_AUTH_LEVEL_NONE: + p->security_state.auth_info->credentials = data_blob(NULL, 0); + break; + + default: + status = NT_STATUS_INVALID_LEVEL; + break; + } + data_blob_free(&p->security_state.auth_info->credentials); return NT_STATUS_OK; @@ -433,8 +465,8 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, pkt.call_id = p->call_id; pkt.auth_length = 0; - pkt.u.bind.max_xmit_frag = 0x2000; - pkt.u.bind.max_recv_frag = 0x2000; + pkt.u.bind.max_xmit_frag = 5840; + pkt.u.bind.max_recv_frag = 5840; pkt.u.bind.assoc_group_id = 0; pkt.u.bind.num_contexts = 1; pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0])); @@ -782,60 +814,44 @@ struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, pkt.u.request.context_id = 0; pkt.u.request.opnum = opnum; - /* we send a series of pdus without waiting for a reply until - the last pdu */ - while (remaining > chunk_size) { + DLIST_ADD(p->pending, req); + + /* we send a series of pdus without waiting for a reply */ + while (remaining > 0) { + uint32_t chunk = MIN(chunk_size, remaining); + BOOL last_frag = False; + + pkt.pfc_flags = 0; + if (remaining == stub_data->length) { - pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST; - } else { - pkt.pfc_flags = 0; + pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST; + } + if (chunk == remaining) { + pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST; + last_frag = True; } pkt.u.request.stub_and_verifier.data = stub_data->data + (stub_data->length - remaining); - pkt.u.request.stub_and_verifier.length = chunk_size; + pkt.u.request.stub_and_verifier.length = chunk; req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt); if (!NT_STATUS_IS_OK(req->status)) { req->state = RPC_REQUEST_DONE; + DLIST_REMOVE(p->pending, req); return req; } - req->status = p->transport.send_request(p, &blob, False); + req->status = p->transport.send_request(p, &blob, last_frag); if (!NT_STATUS_IS_OK(req->status)) { req->state = RPC_REQUEST_DONE; + DLIST_REMOVE(p->pending, req); return req; } - remaining -= chunk_size; - } - - /* now we send a pdu with LAST_FRAG sent and get the first - part of the reply */ - if (remaining == stub_data->length) { - pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; - } else { - pkt.pfc_flags = DCERPC_PFC_FLAG_LAST; - } - pkt.u.request.stub_and_verifier.data = stub_data->data + - (stub_data->length - remaining); - pkt.u.request.stub_and_verifier.length = remaining; - - req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt); - if (!NT_STATUS_IS_OK(req->status)) { - req->state = RPC_REQUEST_DONE; - return req; - } - - /* send the final pdu */ - req->status = p->transport.send_request(p, &blob, True); - - if (!NT_STATUS_IS_OK(req->status)) { - req->state = RPC_REQUEST_DONE; + remaining -= chunk; } - DLIST_ADD(p->pending, req); - return req; } |