the event context is optional
*/
static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct smb_iconv_convenience *ic)
+ struct tevent_context *ev)
{
struct dcerpc_connection *c;
return NULL;
}
- c->iconv_convenience = talloc_reference(c, ic);
-
- c->event_ctx = talloc_reference(c, ev);
+ c->event_ctx = ev;
if (c->event_ctx == NULL) {
talloc_free(c);
}
/* initialise a dcerpc pipe. */
-_PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct smb_iconv_convenience *ic)
+_PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
{
struct dcerpc_pipe *p;
return NULL;
}
- p->conn = dcerpc_connection_init(p, ev, ic);
+ p->conn = dcerpc_connection_init(p, ev);
if (p->conn == NULL) {
talloc_free(p);
return NULL;
ZERO_STRUCT(p->syntax);
ZERO_STRUCT(p->transfer_syntax);
+ if (DEBUGLVL(100)) {
+ p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
+ }
+
+ p->binding_handle = talloc(p, struct dcerpc_binding_handle);
+ if (p->binding_handle == NULL) {
+ talloc_free(p);
+ return NULL;
+ }
+ p->binding_handle->private_data = p;
+
return p;
}
static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
{
- struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
+ struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
if (ndr == NULL) return ndr;
ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
}
+ if (c->flags & DCERPC_NDR64) {
+ ndr->flags |= LIBNDR_FLAG_NDR64;
+ }
+
return ndr;
}
DATA_BLOB *raw_packet,
struct ncacn_packet *pkt)
{
- struct ndr_pull *ndr;
NTSTATUS status;
struct dcerpc_auth auth;
- DATA_BLOB auth_blob;
- enum ndr_err_code ndr_err;
+ uint32_t auth_length;
if (!c->security_state.auth_info ||
!c->security_state.generic_state) {
return NT_STATUS_INVALID_LEVEL;
}
- auth_blob.length = 8 + pkt->auth_length;
-
- /* check for a valid length */
- if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
- return NT_STATUS_INFO_LENGTH_MISMATCH;
- }
-
- auth_blob.data =
- pkt->u.response.stub_and_verifier.data +
- pkt->u.response.stub_and_verifier.length - auth_blob.length;
- pkt->u.response.stub_and_verifier.length -= auth_blob.length;
-
- /* pull the auth structure */
- ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
- if (!ndr) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
- ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
- }
+ status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
+ &pkt->u.response.stub_and_verifier,
+ &auth, &auth_length, false);
+ NT_STATUS_NOT_OK_RETURN(status);
- ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- return ndr_map_error2ntstatus(ndr_err);
- }
- status = NT_STATUS_OK;
+ pkt->u.response.stub_and_verifier.length -= auth_length;
/* check signature or unseal the packet */
switch (c->security_state.auth_info->auth_level) {
break;
}
- /* remove the indicated amount of paddiing */
+ /* remove the indicated amount of padding */
if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
return NT_STATUS_INFO_LENGTH_MISMATCH;
}
/* non-signed packets are simpler */
if (sig_size == 0) {
- return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
+ return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
}
switch (c->security_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_CONNECT:
/* TODO: let the gensec mech decide if it wants to generate a signature */
- return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
+ return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
case DCERPC_AUTH_LEVEL_NONE:
- return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
+ return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
default:
return NT_STATUS_INVALID_LEVEL;
}
- ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
+ ndr = ndr_push_init_ctx(mem_ctx);
if (!ndr) {
return NT_STATUS_NO_MEMORY;
}
ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
}
+ if (c->flags & DCERPC_NDR64) {
+ ndr->flags |= LIBNDR_FLAG_NDR64;
+ }
+
if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
hdr_size += 16;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
}
- status = NT_STATUS_OK;
/* pad to 16 byte multiple in the payload portion of the
- packet. This matches what w2k3 does */
- c->security_state.auth_info->auth_pad_length =
+ packet. This matches what w2k3 does. Note that we can't use
+ ndr_push_align() as that is relative to the start of the
+ whole packet, whereas w2k8 wants it relative to the start
+ of the stub */
+ c->security_state.auth_info->auth_pad_length =
(16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
}
- status = NT_STATUS_OK;
payload_length = pkt->u.request.stub_and_verifier.length +
c->security_state.auth_info->auth_pad_length;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return ndr_map_error2ntstatus(ndr_err);
}
- status = NT_STATUS_OK;
/* extract the whole packet as a blob */
*blob = ndr_push_blob(ndr);
}
if (creds2.length != sig_size) {
- DEBUG(0,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
- creds2.length, (uint32_t)sig_size,
- c->security_state.auth_info->auth_pad_length,
- pkt->u.request.stub_and_verifier.length));
- return NT_STATUS_INTERNAL_ERROR;
+ /* this means the sig_size estimate for the signature
+ was incorrect. We have to correct the packet
+ sizes. That means we could go over the max fragment
+ length */
+ DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
+ (unsigned) creds2.length,
+ (unsigned) sig_size,
+ (unsigned) c->security_state.auth_info->auth_pad_length,
+ (unsigned) pkt->u.request.stub_and_verifier.length));
+ dcerpc_set_frag_length(blob, blob->length + creds2.length);
+ dcerpc_set_auth_length(blob, creds2.length);
}
if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
dcerpc_request_recv_data(conn, blob, &pkt);
}
-
/*
Receive a bind reply from the transport
*/
if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
(pkt->u.bind_ack.num_results == 0) ||
(pkt->u.bind_ack.ctx_list[0].result != 0)) {
+ req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
composite_error(c, NT_STATUS_NET_WRITE_FAULT);
return;
}
}
/* the bind_ack might contain a reply set of credentials */
- if (conn->security_state.auth_info &&
- pkt->u.bind_ack.auth_info.length) {
- enum ndr_err_code ndr_err;
- ndr_err = ndr_pull_struct_blob(
- &pkt->u.bind_ack.auth_info, conn,
- NULL,
- conn->security_state.auth_info,
- (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- c->status = ndr_map_error2ntstatus(ndr_err);
- if (!composite_is_ok(c)) return;
+ if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
+ NTSTATUS status;
+ uint32_t auth_length;
+ status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
+ conn->security_state.auth_info, &auth_length, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(c, status);
+ return;
}
}
handle timeouts of individual dcerpc requests
*/
static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
- struct timeval t, void *private)
+ struct timeval t, void *private_data)
{
- struct rpc_request *req = talloc_get_type(private, struct rpc_request);
+ struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
if (req->ignore_timeout) {
dcerpc_req_dequeue(req);
pkt.u.bind.auth_info = data_blob(NULL, 0);
/* construct the NDR form of the packet */
- c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
+ c->status = ncacn_push_auth(&blob, c, &pkt,
p->conn->security_state.auth_info);
if (!composite_is_ok(c)) return c;
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
pkt.call_id = next_call_id(p->conn);
pkt.auth_length = 0;
- pkt.u.auth3._pad = 0;
pkt.u.auth3.auth_info = data_blob(NULL, 0);
if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
/* construct the NDR form of the packet */
status = ncacn_push_auth(&blob, mem_ctx,
- p->conn->iconv_convenience,
&pkt,
p->conn->security_state.auth_info);
if (!NT_STATUS_IS_OK(status)) {
DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
{
struct rpc_request *req;
- uint_t length;
+ unsigned int length;
NTSTATUS status = NT_STATUS_OK;
/*
if (req->object) {
pkt.u.request.object.object = *req->object;
pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
- chunk_size -= ndr_size_GUID(req->object,NULL,0);
+ chunk_size -= ndr_size_GUID(req->object,0);
}
/* we send a series of pdus without waiting for a reply */
while (remaining > 0 || first_packet) {
uint32_t chunk = MIN(chunk_size, remaining);
bool last_frag = false;
+ bool do_trans = false;
first_packet = false;
pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
DLIST_REMOVE(p->conn->pending, req);
return;
}
-
- req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
+
+ if (last_frag && !req->async_call) {
+ do_trans = true;
+ }
+
+ req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
if (!NT_STATUS_IS_OK(req->status)) {
req->state = RPC_REQUEST_DONE;
DLIST_REMOVE(p->conn->pending, req);
return;
}
+ if (last_frag && !do_trans) {
+ req->status = p->conn->transport.send_read(p->conn);
+ if (!NT_STATUS_IS_OK(req->status)) {
+ req->state = RPC_REQUEST_DONE;
+ DLIST_REMOVE(p->conn->pending, req);
+ return;
+ }
+ }
+
remaining -= chunk;
}
}
if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
req->p->last_fault_code = req->fault_code;
}
- talloc_free(req);
+ talloc_unlink(talloc_parent(req), req);
return status;
}
NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
struct GUID *object,
uint16_t opnum,
- bool async,
TALLOC_CTX *mem_ctx,
DATA_BLOB *stub_data_in,
DATA_BLOB *stub_data_out)
{
struct rpc_request *req;
- req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
+ req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
if (req == NULL) {
return NT_STATUS_NO_MEMORY;
}
return ndr_map_error2ntstatus(ndr_err);
}
- push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
+ push = ndr_push_init_ctx(mem_ctx);
if (!push) {
return NT_STATUS_NO_MEMORY;
}
}
memcpy(st, struct_ptr, struct_size);
- push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
+ push = ndr_push_init_ctx(mem_ctx);
if (!push) {
return NT_STATUS_NO_MEMORY;
}
return ndr_map_error2ntstatus(ndr_err);
}
- push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
+ push = ndr_push_init_ctx(mem_ctx);
if (!push) {
return NT_STATUS_NO_MEMORY;
}
send a rpc request given a dcerpc_call structure
*/
struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
- const struct GUID *object,
- const struct ndr_interface_table *table,
- uint32_t opnum,
- TALLOC_CTX *mem_ctx,
- void *r)
+ const struct GUID *object,
+ const struct ndr_interface_table *table,
+ uint32_t opnum,
+ bool async,
+ TALLOC_CTX *mem_ctx,
+ void *r)
{
const struct ndr_interface_call *call;
struct ndr_push *push;
call = &table->calls[opnum];
/* setup for a ndr_push_* call */
- push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
+ push = ndr_push_init_ctx(mem_ctx);
if (!push) {
return NULL;
}
push->flags |= LIBNDR_FLAG_BIGENDIAN;
}
+ if (p->conn->flags & DCERPC_NDR64) {
+ push->flags |= LIBNDR_FLAG_NDR64;
+ }
+
/* push the structure into a blob */
ndr_err = call->ndr_push(push, NDR_IN, r);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
dump_data(10, request.data, request.length);
/* make the actual dcerpc request */
- req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
- &request);
+ req = dcerpc_request_send(p, object, opnum, async, &request);
if (req != NULL) {
req->ndr.table = table;
NTSTATUS status;
DATA_BLOB response;
struct ndr_pull *pull;
- uint_t flags;
+ unsigned int flags;
TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
void *r = req->ndr.struct_ptr;
uint32_t opnum = req->ndr.opnum;
{
struct rpc_request *req;
- req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
+ req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
if (req == NULL) {
return NT_STATUS_NO_MEMORY;
}
return;
}
+ if (pkt->ptype == DCERPC_PKT_FAULT) {
+ DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
+ recv_pipe->last_fault_code = pkt->u.fault.status;
+ composite_error(c, NT_STATUS_NET_WRITE_FAULT);
+ return;
+ }
+
if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
pkt->u.alter_resp.num_results == 0 ||
pkt->u.alter_resp.ctx_list[0].result != 0) {
+ recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
composite_error(c, NT_STATUS_NET_WRITE_FAULT);
return;
}
/* the alter_resp might contain a reply set of credentials */
if (recv_pipe->conn->security_state.auth_info &&
pkt->u.alter_resp.auth_info.length) {
- enum ndr_err_code ndr_err;
- ndr_err = ndr_pull_struct_blob(
- &pkt->u.alter_resp.auth_info, recv_pipe,
- NULL,
- recv_pipe->conn->security_state.auth_info,
- (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- c->status = ndr_map_error2ntstatus(ndr_err);
- if (!composite_is_ok(c)) return;
+ struct dcerpc_connection *conn = recv_pipe->conn;
+ NTSTATUS status;
+ uint32_t auth_length;
+ status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
+ conn->security_state.auth_info, &auth_length, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ composite_error(c, status);
+ return;
}
}
pkt.u.alter.auth_info = data_blob(NULL, 0);
/* construct the NDR form of the packet */
- c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
+ c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
p->conn->security_state.auth_info);
if (!composite_is_ok(c)) return c;
creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
return dcerpc_alter_context_recv(creq);
}
+