STEP04c: HACK s4 client remove unused
authorStefan Metzmacher <metze@samba.org>
Wed, 22 Jan 2014 11:57:53 +0000 (12:57 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 10:45:39 +0000 (12:45 +0200)
source4/librpc/rpc/dcerpc.c
source4/librpc/rpc/dcerpc.h
source4/librpc/rpc/dcerpc_connect.c
source4/librpc/rpc/dcerpc_util.c

index 6b6dc028cd323296b2bd50b84a8d65095bf6568a..b618b0ecd4363cc6991b43d0f891d3a99192a209 100644 (file)
 #include "libcli/smb/tstream_smbXcli_np.h"
 #include "librpc/rpc/dcerpc_connection.h"
 
-
-enum rpc_request_state {
-       RPC_REQUEST_QUEUED,
-       RPC_REQUEST_PENDING,
-       RPC_REQUEST_DONE
-};
-
-/*
-  handle for an async dcerpc request
-*/
-struct rpc_request {
-       struct rpc_request *next, *prev;
-       struct dcerpc_pipe *p;
-       NTSTATUS status;
-       uint32_t call_id;
-       enum rpc_request_state state;
-       DATA_BLOB payload;
-       uint32_t flags;
-       uint32_t fault_code;
-
-       /* this is used to distinguish bind and alter_context requests
-          from normal requests */
-       void (*recv_handler)(struct rpc_request *conn, 
-                            DATA_BLOB *blob, struct ncacn_packet *pkt);
-
-       const struct GUID *object;
-       uint16_t opnum;
-       DATA_BLOB request_data;
-       bool ignore_timeout;
-       bool wait_for_sync;
-       bool verify_bitmask1;
-       bool verify_pcontext;
-
-       struct {
-               void (*callback)(struct rpc_request *);
-               void *private_data;
-       } async;
-};
-
 _PUBLIC_ NTSTATUS dcerpc_init(void)
 {
        return gensec_init();
 }
 
-static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
-static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
-
-static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
-                                              struct dcerpc_pipe *p,
-                                              const struct GUID *object,
-                                              uint16_t opnum,
-                                              DATA_BLOB *stub_data);
-static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
-                                   TALLOC_CTX *mem_ctx,
-                                   DATA_BLOB *stub_data);
 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
                                       TALLOC_CTX *mem_ctx,
                                       DATA_BLOB blob,
@@ -104,21 +54,6 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
                                        ndr_push_flags_fn_t ndr_push,
                                        ndr_pull_flags_fn_t ndr_pull,
                                        ndr_print_function_t ndr_print);
-static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
-static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
-                            bool trigger_read);
-static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
-
-/* destroy a dcerpc connection */
-static int dcerpc_connection_destructor(struct dcecli_connection *conn)
-{
-       if (conn->dead) {
-               conn->free_skipped = true;
-               return -1;
-       }
-       dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
-       return 0;
-}
 
 
 /* initialise a dcerpc connection. 
@@ -141,31 +76,8 @@ static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       c->call_id = 1;
-       c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
-       c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
-       c->security_state.auth_context_id = 0;
        c->security_state.session_key = dcerpc_generic_session_key;
-       c->security_state.generic_state = NULL;
        c->flags = 0;
-       /*
-        * Windows uses 5840 for ncacn_ip_tcp,
-        * so we also use it (for every transport)
-        * by default. But we give the transport
-        * the chance to overwrite it.
-        */
-       c->srv_max_xmit_frag = 5840;
-       c->srv_max_recv_frag = 5840;
-       c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
-       c->pending = NULL;
-
-       c->io_trigger = tevent_create_immediate(c);
-       if (c->io_trigger == NULL) {
-               talloc_free(c);
-               return NULL;
-       }
-
-       talloc_set_destructor(c, dcerpc_connection_destructor);
 
        return c;
 }
@@ -187,10 +99,6 @@ static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
                return false;
        }
 
-       if (hs->p->conn->dead) {
-               return false;
-       }
-
        return dcerpc_connection_is_connected(hs->p->conn->conn);
 }
 
@@ -663,19 +571,6 @@ _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent
        return p;
 }
 
-
-/* 
-   choose the next call id to use
-*/
-static uint32_t next_call_id(struct dcecli_connection *c)
-{
-       c->call_id++;
-       if (c->call_id == 0) {
-               c->call_id++;
-       }
-       return c->call_id;
-}
-
 /**
   setup for a ndr pull, also setting up any flags from the binding string
 */
@@ -701,1290 +596,155 @@ static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
        return ndr;
 }
 
-/* 
-   parse the authentication information on a dcerpc response packet
-*/
-static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
-                                   TALLOC_CTX *mem_ctx,
-                                   enum dcerpc_pkt_type ptype,
-                                   uint8_t required_flags,
-                                   uint8_t optional_flags,
-                                   uint8_t payload_offset,
-                                   DATA_BLOB *payload_and_verifier,
-                                   DATA_BLOB *raw_packet,
-                                   const struct ncacn_packet *pkt)
-{
-       const struct dcerpc_auth tmp_auth = {
-               .auth_type = c->security_state.auth_type,
-               .auth_level = c->security_state.auth_level,
-               .auth_context_id = c->security_state.auth_context_id,
-       };
-       NTSTATUS status;
-
-       status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
-                                           c->security_state.generic_state,
-                                           mem_ctx,
-                                           ptype,
-                                           required_flags,
-                                           optional_flags,
-                                           payload_offset,
-                                           payload_and_verifier,
-                                           raw_packet,
-                                           pkt);
-       if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
-               return NT_STATUS_INVALID_NETWORK_RESPONSE;
-       }
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       return NT_STATUS_OK;
-}
-
-
-/* 
-   push a dcerpc request packet into a blob, possibly signing it.
+/*
+  this is a paranoid NDR validator. For every packet we push onto the wire
+  we pull it back again, then push it again. Then we compare the raw NDR data
+  for that to the NDR we initially generated. If they don't match then we know
+  we must have a bug in either the pull or push side of our code
 */
-static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c, 
-                                        DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
-                                        size_t sig_size,
-                                        struct ncacn_packet *pkt)
+static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
+                                      TALLOC_CTX *mem_ctx,
+                                      DATA_BLOB blob,
+                                      size_t struct_size,
+                                      ndr_push_flags_fn_t ndr_push,
+                                      ndr_pull_flags_fn_t ndr_pull)
 {
-       const struct dcerpc_auth tmp_auth = {
-               .auth_type = c->security_state.auth_type,
-               .auth_level = c->security_state.auth_level,
-               .auth_context_id = c->security_state.auth_context_id,
-       };
-       NTSTATUS status;
-       uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
+       void *st;
+       struct ndr_pull *pull;
+       struct ndr_push *push;
+       DATA_BLOB blob2;
+       enum ndr_err_code ndr_err;
 
-       if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
-               payload_offset += 16;
+       st = talloc_size(mem_ctx, struct_size);
+       if (!st) {
+               return NT_STATUS_NO_MEMORY;
        }
 
-       status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
-                                           c->security_state.generic_state,
-                                           mem_ctx, blob,
-                                           sig_size,
-                                           payload_offset,
-                                           &pkt->u.request.stub_and_verifier,
-                                           pkt);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       pull = ndr_pull_init_flags(c, &blob, mem_ctx);
+       if (!pull) {
+               return NT_STATUS_NO_MEMORY;
        }
+       pull->flags |= LIBNDR_FLAG_REF_ALLOC;
 
-       return NT_STATUS_OK;
-}
-
-
-/* 
-   fill in the fixed values in a dcerpc header 
-*/
-static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
-{
-       pkt->rpc_vers = 5;
-       pkt->rpc_vers_minor = 0;
        if (c->flags & DCERPC_PUSH_BIGENDIAN) {
-               pkt->drep[0] = 0;
-       } else {
-               pkt->drep[0] = DCERPC_DREP_LE;
-       }
-       pkt->drep[1] = 0;
-       pkt->drep[2] = 0;
-       pkt->drep[3] = 0;
-}
-
-/*
-  map a bind nak reason to a NTSTATUS
-*/
-static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
-{
-       switch (reason) {
-       case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
-               return NT_STATUS_REVISION_MISMATCH;
-       case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
-               return NT_STATUS_INVALID_PARAMETER;
-       default:
-               break;
-       }
-       return NT_STATUS_UNSUCCESSFUL;
-}
-
-static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
-{
-       if (ack == NULL) {
-               return NT_STATUS_RPC_PROTOCOL_ERROR;
-       }
-
-       switch (ack->result) {
-       case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
-               /*
-                * We have not asked for this...
-                */
-               return NT_STATUS_RPC_PROTOCOL_ERROR;
-       default:
-               break;
+               pull->flags |= LIBNDR_FLAG_BIGENDIAN;
        }
 
-       switch (ack->reason.value) {
-       case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
-               return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
-       case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
-               return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
-       default:
-               break;
+       if (c->flags & DCERPC_NDR64) {
+               pull->flags |= LIBNDR_FLAG_NDR64;
        }
-       return NT_STATUS_UNSUCCESSFUL;
-}
 
-/*
-  remove requests from the pending or queued queues
- */
-static int dcerpc_req_dequeue(struct rpc_request *req)
-{
-       switch (req->state) {
-       case RPC_REQUEST_QUEUED:
-               DLIST_REMOVE(req->p->conn->request_queue, req);
-               break;
-       case RPC_REQUEST_PENDING:
-               DLIST_REMOVE(req->p->conn->pending, req);
-               break;
-       case RPC_REQUEST_DONE:
-               break;
+       ndr_err = ndr_pull(pull, NDR_IN, st);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+               ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
+                                        "failed input validation pull - %s",
+                                        nt_errstr(status));
+               return ndr_map_error2ntstatus(ndr_err);
        }
-       return 0;
-}
-
-
-/*
-  mark the dcerpc connection dead. All outstanding requests get an error
-*/
-static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
-{
-       if (conn->dead) return;
-
-       conn->dead = true;
 
-       TALLOC_FREE(conn->io_trigger);
-       conn->io_trigger_pending = false;
-
-       dcerpc_shutdown_pipe(conn, status);
-
-       /* all pending requests get the error */
-       while (conn->pending) {
-               struct rpc_request *req = conn->pending;
-               dcerpc_req_dequeue(req);
-               req->state = RPC_REQUEST_DONE;
-               req->status = status;
-               if (req->async.callback) {
-                       req->async.callback(req);
-               }
-       }       
-
-       /* all requests, which are not shipped */
-       while (conn->request_queue) {
-               struct rpc_request *req = conn->request_queue;
-               dcerpc_req_dequeue(req);
-               req->state = RPC_REQUEST_DONE;
-               req->status = status;
-               if (req->async.callback) {
-                       req->async.callback(req);
-               }
+       push = ndr_push_init_ctx(mem_ctx);
+       if (!push) {
+               return NT_STATUS_NO_MEMORY;
        }
 
-       talloc_set_destructor(conn, NULL);
-       if (conn->free_skipped) {
-               talloc_free(conn);
+       if (c->flags & DCERPC_PUSH_BIGENDIAN) {
+               push->flags |= LIBNDR_FLAG_BIGENDIAN;
        }
-}
-
-/*
-  forward declarations of the recv_data handlers for the types of
-  packets we need to handle
-*/
-static void dcerpc_request_recv_data(struct dcecli_connection *c, 
-                                    DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
-
-/*
-  receive a dcerpc reply from the transport. Here we work out what
-  type of reply it is (normal request, bind or alter context) and
-  dispatch to the appropriate handler
-*/
-static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
-{
-       struct ncacn_packet pkt;
 
-       if (conn->dead) {
-               return;
+       if (c->flags & DCERPC_NDR64) {
+               push->flags |= LIBNDR_FLAG_NDR64;
        }
 
-       if (NT_STATUS_IS_OK(status) && blob->length == 0) {
-               status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+       ndr_err = ndr_push(push, NDR_IN, st);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+               ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
+                                        "failed input validation push - %s",
+                                        nt_errstr(status));
+               return ndr_map_error2ntstatus(ndr_err);
        }
 
-       /* the transport may be telling us of a severe error, such as
-          a dropped socket */
-       if (!NT_STATUS_IS_OK(status)) {
-               data_blob_free(blob);
-               dcerpc_connection_dead(conn, status);
-               return;
-       }
+       blob2 = ndr_push_blob(push);
 
-       /* parse the basic packet to work out what type of response this is */
-       status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
-       if (!NT_STATUS_IS_OK(status)) {
-               data_blob_free(blob);
-               dcerpc_connection_dead(conn, status);
-               return;
+       if (data_blob_cmp(&blob, &blob2) != 0) {
+               DEBUG(3,("original:\n"));
+               dump_data(3, blob.data, blob.length);
+               DEBUG(3,("secondary:\n"));
+               dump_data(3, blob2.data, blob2.length);
+               ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
+                                        "failed input validation blobs doesn't match");
+               return ndr_map_error2ntstatus(ndr_err);
        }
 
-       dcerpc_request_recv_data(conn, blob, &pkt);
+       return NT_STATUS_OK;
 }
 
 /*
-  handle timeouts of individual dcerpc requests
+  this is a paranoid NDR input validator. For every packet we pull
+  from the wire we push it back again then pull and push it
+  again. Then we compare the raw NDR data for that to the NDR we
+  initially generated. If they don't match then we know we must have a
+  bug in either the pull or push side of our code
 */
-static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
-                                  struct timeval t, void *private_data)
-{
-       struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
-
-       if (req->ignore_timeout) {
-               dcerpc_req_dequeue(req);
-               req->state = RPC_REQUEST_DONE;
-               req->status = NT_STATUS_IO_TIMEOUT;
-               if (req->async.callback) {
-                       req->async.callback(req);
-               }
-               return;
-       }
-
-       dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
-}
-
-struct dcerpc_bind_state {
-       struct tevent_context *ev;
-       struct dcerpc_pipe *p;
-};
-
-static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
-static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
-                                    DATA_BLOB *raw_packet,
-                                    struct ncacn_packet *pkt);
-
-struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
-                                   struct tevent_context *ev,
-                                   struct dcerpc_pipe *p,
-                                   const struct ndr_syntax_id *syntax,
-                                   const struct ndr_syntax_id *transfer_syntax)
+static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
+                                       struct ndr_pull *pull_in,
+                                       void *struct_ptr,
+                                       size_t struct_size,
+                                       ndr_push_flags_fn_t ndr_push,
+                                       ndr_pull_flags_fn_t ndr_pull,
+                                       ndr_print_function_t ndr_print)
 {
-       struct tevent_req *req;
-       struct dcerpc_bind_state *state;
-       struct ncacn_packet pkt;
-       DATA_BLOB blob;
-       NTSTATUS status;
-       struct rpc_request *subreq;
-       uint32_t flags;
-       struct ndr_syntax_id bind_time_features;
-
-       bind_time_features = dcerpc_construct_bind_time_features(
-                       DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
-                       DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
+       void *st;
+       struct ndr_pull *pull;
+       struct ndr_push *push;
+       DATA_BLOB blob, blob2;
+       TALLOC_CTX *mem_ctx = pull_in;
+       char *s1, *s2;
+       enum ndr_err_code ndr_err;
 
-       req = tevent_req_create(mem_ctx, &state,
-                               struct dcerpc_bind_state);
-       if (req == NULL) {
-               return NULL;
+       st = talloc_size(mem_ctx, struct_size);
+       if (!st) {
+               return NT_STATUS_NO_MEMORY;
        }
+       memcpy(st, struct_ptr, struct_size);
 
-       state->ev = ev;
-       state->p = p;
-
-       p->syntax = *syntax;
-       p->transfer_syntax = *transfer_syntax;
-
-       flags = dcerpc_binding_get_flags(p->binding);
-
-       init_ncacn_hdr(p->conn, &pkt);
-
-       pkt.ptype = DCERPC_PKT_BIND;
-       pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
-       pkt.call_id = p->conn->call_id;
-       pkt.auth_length = 0;
-
-       if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
-               pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
+       push = ndr_push_init_ctx(mem_ctx);
+       if (!push) {
+               return NT_STATUS_NO_MEMORY;
        }
 
-       if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
-               pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+       ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+               ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
+                                        "failed output validation push - %s",
+                                        nt_errstr(status));
+               return ndr_map_error2ntstatus(ndr_err);
        }
 
-       pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
-       pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
-       pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
-       pkt.u.bind.num_contexts = 2;
-       pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
-                                               pkt.u.bind.num_contexts);
-       if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
-               return tevent_req_post(req, ev);
+       blob = ndr_push_blob(push);
+
+       pull = ndr_pull_init_flags(c, &blob, mem_ctx);
+       if (!pull) {
+               return NT_STATUS_NO_MEMORY;
        }
-       pkt.u.bind.ctx_list[0].context_id = p->context_id;
-       pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
-       pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
-       pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
-       pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
-       pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
-       pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
-       pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
-       pkt.u.bind.auth_info = data_blob(NULL, 0);
 
-       /* construct the NDR form of the packet */
-       status = ncacn_push_auth(&blob, state, &pkt,
-                                p->conn->security_state.tmp_auth_info.out);
-       if (tevent_req_nterror(req, status)) {
-               return tevent_req_post(req, ev);
+       pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+       ndr_err = ndr_pull(pull, NDR_OUT, st);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+               ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
+                                        "failed output validation pull - %s",
+                                        nt_errstr(status));
+               return ndr_map_error2ntstatus(ndr_err);
        }
 
-       /*
-        * we allocate a dcerpc_request so we can be in the same
-        * request queue as normal requests
-        */
-       subreq = talloc_zero(state, struct rpc_request);
-       if (tevent_req_nomem(subreq, req)) {
-               return tevent_req_post(req, ev);
-       }
-
-       subreq->state = RPC_REQUEST_PENDING;
-       subreq->call_id = pkt.call_id;
-       subreq->async.private_data = req;
-       subreq->async.callback = dcerpc_bind_fail_handler;
-       subreq->p = p;
-       subreq->recv_handler = dcerpc_bind_recv_handler;
-       DLIST_ADD_END(p->conn->pending, subreq);
-       talloc_set_destructor(subreq, dcerpc_req_dequeue);
-
-       status = dcerpc_send_request(p->conn, &blob, true);
-       if (tevent_req_nterror(req, status)) {
-               return tevent_req_post(req, ev);
-       }
-
-       tevent_add_timer(ev, subreq,
-                        timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
-                        dcerpc_timeout_handler, subreq);
-
-       return req;
-}
-
-static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
-{
-       struct tevent_req *req =
-               talloc_get_type_abort(subreq->async.private_data,
-               struct tevent_req);
-       struct dcerpc_bind_state *state =
-               tevent_req_data(req,
-               struct dcerpc_bind_state);
-       NTSTATUS status = subreq->status;
-
-       TALLOC_FREE(subreq);
-
-       /*
-        * We trigger the callback in the next event run
-        * because the code in this file might trigger
-        * multiple request callbacks from within a single
-        * while loop.
-        *
-        * In order to avoid segfaults from within
-        * dcerpc_connection_dead() we call
-        * tevent_req_defer_callback().
-        */
-       tevent_req_defer_callback(req, state->ev);
-
-       tevent_req_nterror(req, status);
-}
-
-static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
-                                    DATA_BLOB *raw_packet,
-                                    struct ncacn_packet *pkt)
-{
-       struct tevent_req *req =
-               talloc_get_type_abort(subreq->async.private_data,
-               struct tevent_req);
-       struct dcerpc_bind_state *state =
-               tevent_req_data(req,
-               struct dcerpc_bind_state);
-       struct dcecli_connection *conn = state->p->conn;
-       struct dcecli_security *sec = &conn->security_state;
-       struct dcerpc_binding *b = NULL;
-       NTSTATUS status;
-       uint32_t flags;
-
-       /*
-        * Note that pkt is allocated under raw_packet->data,
-        * while raw_packet->data is a child of subreq.
-        */
-       talloc_steal(state, raw_packet->data);
-       TALLOC_FREE(subreq);
-
-       /*
-        * We trigger the callback in the next event run
-        * because the code in this file might trigger
-        * multiple request callbacks from within a single
-        * while loop.
-        *
-        * In order to avoid segfaults from within
-        * dcerpc_connection_dead() we call
-        * tevent_req_defer_callback().
-        */
-       tevent_req_defer_callback(req, state->ev);
-
-       if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
-               status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
-
-               DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
-                        pkt->u.bind_nak.reject_reason, nt_errstr(status)));
-
-               tevent_req_nterror(req, status);
-               return;
-       }
-
-       status = dcerpc_verify_ncacn_packet_header(pkt,
-                                       DCERPC_PKT_BIND_ACK,
-                                       pkt->u.bind_ack.auth_info.length,
-                                       DCERPC_PFC_FLAG_FIRST |
-                                       DCERPC_PFC_FLAG_LAST,
-                                       DCERPC_PFC_FLAG_CONC_MPX |
-                                       DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
-       if (!NT_STATUS_IS_OK(status)) {
-               state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
-               tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
-               return;
-       }
-
-       if (pkt->u.bind_ack.num_results < 1) {
-               state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
-               tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
-               return;
-       }
-
-       if (pkt->u.bind_ack.ctx_list[0].result != 0) {
-               status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
-               DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
-                        pkt->u.bind_ack.ctx_list[0].reason.value,
-                        nt_errstr(status)));
-               tevent_req_nterror(req, status);
-               return;
-       }
-
-       if (pkt->u.bind_ack.num_results >= 2) {
-               if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
-                       conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
-               } else {
-                       status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
-                       DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
-                                pkt->u.bind_ack.ctx_list[1].reason.value,
-                                nt_errstr(status)));
-                       status = NT_STATUS_OK;
-               }
-       }
-
-       /*
-        * DCE-RPC 1.1 (c706) specifies
-        * CONST_MUST_RCV_FRAG_SIZE as 1432
-        */
-       if (pkt->u.bind_ack.max_xmit_frag < 1432) {
-               state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
-               tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
-               return;
-       }
-       if (pkt->u.bind_ack.max_recv_frag < 1432) {
-               state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
-               tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
-               return;
-       }
-       conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
-                                     pkt->u.bind_ack.max_xmit_frag);
-       conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
-                                     pkt->u.bind_ack.max_recv_frag);
-
-       flags = dcerpc_binding_get_flags(state->p->binding);
-
-       if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
-               if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
-                       conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
-               } else {
-                       conn->flags &= ~DCERPC_CONCURRENT_MULTIPLEX;
-               }
-       }
-
-       if (!(conn->flags & DCERPC_CONCURRENT_MULTIPLEX)) {
-               struct dcerpc_binding *pb =
-                       discard_const_p(struct dcerpc_binding, state->p->binding);
-               /*
-                * clear DCERPC_CONCURRENT_MULTIPLEX
-                */
-               status = dcerpc_binding_set_flags(pb, 0,
-                                                 DCERPC_CONCURRENT_MULTIPLEX);
-               if (tevent_req_nterror(req, status)) {
-                       return;
-               }
-       }
-       if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
-           (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
-               conn->flags |= DCERPC_HEADER_SIGNING;
-       }
-
-       /* the bind_ack might contain a reply set of credentials */
-       if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
-               status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
-                                                 &pkt->u.bind_ack.auth_info,
-                                                 sec->tmp_auth_info.in,
-                                                 NULL, true);
-               if (tevent_req_nterror(req, status)) {
-                       return;
-               }
-       }
-
-       /*
-        * We're the owner of the binding, so we're allowed to modify it.
-        */
-       b = discard_const_p(struct dcerpc_binding, state->p->binding);
-       status = dcerpc_binding_set_assoc_group_id(b,
-                                                  pkt->u.bind_ack.assoc_group_id);
-       if (tevent_req_nterror(req, status)) {
-               return;
-       }
-
-       tevent_req_done(req);
-}
-
-NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
-{
-       return tevent_req_simple_recv_ntstatus(req);
-}
-
-/* 
-   perform a continued bind (and auth3)
-*/
-NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
-                     TALLOC_CTX *mem_ctx)
-{
-       struct ncacn_packet pkt;
-       NTSTATUS status;
-       DATA_BLOB blob;
-       uint32_t flags;
-
-       flags = dcerpc_binding_get_flags(p->binding);
-
-       init_ncacn_hdr(p->conn, &pkt);
-
-       pkt.ptype = DCERPC_PKT_AUTH3;
-       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.auth_info = data_blob(NULL, 0);
-
-       if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
-               pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
-       }
-
-       /* construct the NDR form of the packet */
-       status = ncacn_push_auth(&blob, mem_ctx, &pkt,
-                                p->conn->security_state.tmp_auth_info.out);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       /* send it on its way */
-       status = dcerpc_send_request(p->conn, &blob, false);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       return NT_STATUS_OK;    
-}
-
-
-/*
-  process a fragment received from the transport layer during a
-  request
-
-  This function frees the data 
-*/
-static void dcerpc_request_recv_data(struct dcecli_connection *c, 
-                                    DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
-{
-       struct rpc_request *req;
-       unsigned int length;
-       NTSTATUS status = NT_STATUS_OK;
-
-       /*
-         if this is an authenticated connection then parse and check
-         the auth info. We have to do this before finding the
-         matching packet, as the request structure might have been
-         removed due to a timeout, but if it has been we still need
-         to run the auth routines so that we don't get the sign/seal
-         info out of step with the server
-       */
-       switch (pkt->ptype) {
-       case DCERPC_PKT_RESPONSE:
-               status = ncacn_pull_pkt_auth(c, raw_packet->data,
-                                  DCERPC_PKT_RESPONSE,
-                                  0, /* required_flags */
-                                  DCERPC_PFC_FLAG_FIRST |
-                                  DCERPC_PFC_FLAG_LAST,
-                                  DCERPC_REQUEST_LENGTH,
-                                  &pkt->u.response.stub_and_verifier,
-                                  raw_packet, pkt);
-               break;
-       default:
-               break;
-       }
-
-       /* find the matching request */
-       for (req=c->pending;req;req=req->next) {
-               if (pkt->call_id == req->call_id) break;
-       }
-
-#if 0
-       /* useful for testing certain vendors RPC servers */
-       if (req == NULL && c->pending && pkt->call_id == 0) {
-               DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
-               req = c->pending;
-       }
-#endif
-
-       if (req == NULL) {
-               DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
-               data_blob_free(raw_packet);
-               return;
-       }
-
-       talloc_steal(req, raw_packet->data);
-
-       if (req->recv_handler != NULL) {
-               dcerpc_req_dequeue(req);
-               req->state = RPC_REQUEST_DONE;
-
-               /*
-                * We have to look at shipping further requests before calling
-                * the async function, that one might close the pipe
-                */
-               dcerpc_schedule_io_trigger(c);
-
-               req->recv_handler(req, raw_packet, pkt);
-               return;
-       }
-
-       if (pkt->ptype == DCERPC_PKT_FAULT) {
-               status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
-               DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
-               if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
-                       dcerpc_connection_dead(c, status);
-                       return;
-               }
-               if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
-                       dcerpc_connection_dead(c, status);
-                       return;
-               }
-               req->fault_code = pkt->u.fault.status;
-               req->status = NT_STATUS_NET_WRITE_FAULT;
-               goto req_done;
-       }
-
-       if (pkt->ptype != DCERPC_PKT_RESPONSE) {
-               DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
-                        (int)pkt->ptype)); 
-               dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
-               return;
-       }
-
-       /* now check the status from the auth routines, and if it failed then fail
-          this request accordingly */
-       if (!NT_STATUS_IS_OK(status)) {
-               dcerpc_connection_dead(c, status);
-               return;
-       }
-
-       length = pkt->u.response.stub_and_verifier.length;
-
-       if (req->payload.length + length > c->max_total_response_size) {
-               DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
-                        (unsigned)req->payload.length + length,
-                        (unsigned)c->max_total_response_size));
-               dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
-               return;
-       }
-
-       if (length > 0) {
-               req->payload.data = talloc_realloc(req, 
-                                                  req->payload.data, 
-                                                  uint8_t,
-                                                  req->payload.length + length);
-               if (!req->payload.data) {
-                       req->status = NT_STATUS_NO_MEMORY;
-                       goto req_done;
-               }
-               memcpy(req->payload.data+req->payload.length, 
-                      pkt->u.response.stub_and_verifier.data, length);
-               req->payload.length += length;
-       }
-
-       if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
-               data_blob_free(raw_packet);
-               dcerpc_send_read(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 {
-               req->flags &= ~DCERPC_PULL_BIGENDIAN;
-       }
-
-req_done:
-       data_blob_free(raw_packet);
-
-       /* we've got the full payload */
-       dcerpc_req_dequeue(req);
-       req->state = RPC_REQUEST_DONE;
-
-       /*
-        * We have to look at shipping further requests before calling
-        * the async function, that one might close the pipe
-        */
-       dcerpc_schedule_io_trigger(c);
-
-       if (req->async.callback) {
-               req->async.callback(req);
-       }
-}
-
-static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
-
-/*
-  perform the send side of a async dcerpc request
-*/
-static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
-                                              struct dcerpc_pipe *p,
-                                              const struct GUID *object,
-                                              uint16_t opnum,
-                                              DATA_BLOB *stub_data)
-{
-       struct rpc_request *req;
-       NTSTATUS status;
-
-       req = talloc_zero(mem_ctx, struct rpc_request);
-       if (req == NULL) {
-               return NULL;
-       }
-
-       req->p = p;
-       req->call_id = next_call_id(p->conn);
-       req->state = RPC_REQUEST_QUEUED;
-
-       if (object != NULL) {
-               req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
-               if (req->object == NULL) {
-                       talloc_free(req);
-                       return NULL;
-               }
-       }
-
-       req->opnum = opnum;
-       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);
-
-       dcerpc_schedule_io_trigger(p->conn);
-
-       if (p->request_timeout) {
-               tevent_add_timer(p->conn->event_ctx, req,
-                               timeval_current_ofs(p->request_timeout, 0), 
-                               dcerpc_timeout_handler, req);
-       }
-
-       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_level < DCERPC_AUTH_LEVEL_PACKET) {
-               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
-*/
-
-static void dcerpc_ship_next_request(struct dcecli_connection *c)
-{
-       struct rpc_request *req;
-       struct dcerpc_pipe *p;
-       DATA_BLOB *stub_data;
-       struct ncacn_packet pkt;
-       DATA_BLOB blob;
-       uint32_t remaining, chunk_size;
-       bool first_packet = true;
-       size_t sig_size = 0;
-       bool need_async = false;
-       bool can_async = true;
-
-       req = c->request_queue;
-       if (req == NULL) {
-               return;
-       }
-
-       p = req->p;
-       stub_data = &req->request_data;
-
-       if (c->pending) {
-               need_async = true;
-       }
-
-       if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
-               can_async = gensec_have_feature(c->security_state.generic_state,
-                                               GENSEC_FEATURE_ASYNC_REPLIES);
-       }
-
-       if (need_async && !can_async) {
-               req->wait_for_sync = true;
-               return;
-       }
-
-       DLIST_REMOVE(c->request_queue, req);
-       DLIST_ADD(c->pending, req);
-       req->state = RPC_REQUEST_PENDING;
-
-       init_ncacn_hdr(p->conn, &pkt);
-
-       remaining = stub_data->length;
-
-       /* we can write a full max_recv_frag size, minus the dcerpc
-          request header size */
-       chunk_size = p->conn->srv_max_recv_frag;
-       chunk_size -= DCERPC_REQUEST_LENGTH;
-       if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
-               size_t max_payload = chunk_size;
-
-               max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
-               max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
-
-               sig_size = gensec_sig_size(c->security_state.generic_state,
-                                          max_payload);
-               if (sig_size) {
-                       chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
-                       chunk_size -= sig_size;
-               }
-       }
-       chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
-
-       pkt.ptype = DCERPC_PKT_REQUEST;
-       pkt.call_id = req->call_id;
-       pkt.auth_length = 0;
-       pkt.pfc_flags = 0;
-       pkt.u.request.context_id = p->context_id;
-       pkt.u.request.opnum = req->opnum;
-
-       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,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);
-
-               if (remaining == stub_data->length) {
-                       pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
-               }
-               if (chunk == remaining) {
-                       pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
-                       last_frag = true;
-               }
-
-               pkt.u.request.alloc_hint = remaining;
-               pkt.u.request.stub_and_verifier.data = stub_data->data + 
-                       (stub_data->length - remaining);
-               pkt.u.request.stub_and_verifier.length = chunk;
-
-               req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
-               if (!NT_STATUS_IS_OK(req->status)) {
-                       req->state = RPC_REQUEST_DONE;
-                       DLIST_REMOVE(p->conn->pending, req);
-                       return;
-               }
-
-               if (last_frag && !need_async) {
-                       do_trans = true;
-               }
-
-               req->status = dcerpc_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 = dcerpc_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;
-       }
-}
-
-static void dcerpc_io_trigger(struct tevent_context *ctx,
-                             struct tevent_immediate *im,
-                             void *private_data)
-{
-       struct dcecli_connection *c =
-               talloc_get_type_abort(private_data,
-               struct dcecli_connection);
-
-       c->io_trigger_pending = false;
-
-       dcerpc_schedule_io_trigger(c);
-
-       dcerpc_ship_next_request(c);
-}
-
-static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
-{
-       if (c->dead) {
-               return;
-       }
-
-       if (c->request_queue == NULL) {
-               return;
-       }
-
-       if (c->request_queue->wait_for_sync && c->pending) {
-               return;
-       }
-
-       if (c->io_trigger_pending) {
-               return;
-       }
-
-       c->io_trigger_pending = true;
-
-       tevent_schedule_immediate(c->io_trigger,
-                                 c->event_ctx,
-                                 dcerpc_io_trigger,
-                                 c);
-}
-
-/*
-  perform the receive side of a async dcerpc request
-*/
-static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
-                                   TALLOC_CTX *mem_ctx,
-                                   DATA_BLOB *stub_data)
-{
-       NTSTATUS status;
-
-       while (req->state != RPC_REQUEST_DONE) {
-               struct tevent_context *ctx = req->p->conn->event_ctx;
-               if (tevent_loop_once(ctx) != 0) {
-                       return NT_STATUS_CONNECTION_DISCONNECTED;
-               }
-       }
-       *stub_data = req->payload;
-       status = req->status;
-       if (stub_data->data) {
-               stub_data->data = talloc_steal(mem_ctx, stub_data->data);
-       }
-       if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
-               req->p->last_fault_code = req->fault_code;
-       }
-       talloc_unlink(talloc_parent(req), req);
-       return status;
-}
-
-/*
-  this is a paranoid NDR validator. For every packet we push onto the wire
-  we pull it back again, then push it again. Then we compare the raw NDR data
-  for that to the NDR we initially generated. If they don't match then we know
-  we must have a bug in either the pull or push side of our code
-*/
-static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c, 
-                                      TALLOC_CTX *mem_ctx,
-                                      DATA_BLOB blob,
-                                      size_t struct_size,
-                                      ndr_push_flags_fn_t ndr_push,
-                                      ndr_pull_flags_fn_t ndr_pull)
-{
-       void *st;
-       struct ndr_pull *pull;
-       struct ndr_push *push;
-       DATA_BLOB blob2;
-       enum ndr_err_code ndr_err;
-
-       st = talloc_size(mem_ctx, struct_size);
-       if (!st) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       pull = ndr_pull_init_flags(c, &blob, mem_ctx);
-       if (!pull) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       pull->flags |= LIBNDR_FLAG_REF_ALLOC;
-
-       if (c->flags & DCERPC_PUSH_BIGENDIAN) {
-               pull->flags |= LIBNDR_FLAG_BIGENDIAN;
-       }
-
-       if (c->flags & DCERPC_NDR64) {
-               pull->flags |= LIBNDR_FLAG_NDR64;
-       }
-
-       ndr_err = ndr_pull(pull, NDR_IN, st);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
-               ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
-                                        "failed input validation pull - %s",
-                                        nt_errstr(status));
-               return ndr_map_error2ntstatus(ndr_err);
-       }
-
-       push = ndr_push_init_ctx(mem_ctx);
-       if (!push) {
-               return NT_STATUS_NO_MEMORY;
-       }       
-
-       if (c->flags & DCERPC_PUSH_BIGENDIAN) {
-               push->flags |= LIBNDR_FLAG_BIGENDIAN;
-       }
-
-       if (c->flags & DCERPC_NDR64) {
-               push->flags |= LIBNDR_FLAG_NDR64;
-       }
-
-       ndr_err = ndr_push(push, NDR_IN, st);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
-               ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
-                                        "failed input validation push - %s",
-                                        nt_errstr(status));
-               return ndr_map_error2ntstatus(ndr_err);
-       }
-
-       blob2 = ndr_push_blob(push);
-
-       if (data_blob_cmp(&blob, &blob2) != 0) {
-               DEBUG(3,("original:\n"));
-               dump_data(3, blob.data, blob.length);
-               DEBUG(3,("secondary:\n"));
-               dump_data(3, blob2.data, blob2.length);
-               ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
-                                        "failed input validation blobs doesn't match");
-               return ndr_map_error2ntstatus(ndr_err);
-       }
-
-       return NT_STATUS_OK;
-}
-
-/*
-  this is a paranoid NDR input validator. For every packet we pull
-  from the wire we push it back again then pull and push it
-  again. Then we compare the raw NDR data for that to the NDR we
-  initially generated. If they don't match then we know we must have a
-  bug in either the pull or push side of our code
-*/
-static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
-                                       struct ndr_pull *pull_in,
-                                       void *struct_ptr,
-                                       size_t struct_size,
-                                       ndr_push_flags_fn_t ndr_push,
-                                       ndr_pull_flags_fn_t ndr_pull,
-                                       ndr_print_function_t ndr_print)
-{
-       void *st;
-       struct ndr_pull *pull;
-       struct ndr_push *push;
-       DATA_BLOB blob, blob2;
-       TALLOC_CTX *mem_ctx = pull_in;
-       char *s1, *s2;
-       enum ndr_err_code ndr_err;
-
-       st = talloc_size(mem_ctx, struct_size);
-       if (!st) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       memcpy(st, struct_ptr, struct_size);
-
        push = ndr_push_init_ctx(mem_ctx);
        if (!push) {
                return NT_STATUS_NO_MEMORY;
-       }       
-
-       ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
-               ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
-                                        "failed output validation push - %s",
-                                        nt_errstr(status));
-               return ndr_map_error2ntstatus(ndr_err);
-       }
-
-       blob = ndr_push_blob(push);
-
-       pull = ndr_pull_init_flags(c, &blob, mem_ctx);
-       if (!pull) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       pull->flags |= LIBNDR_FLAG_REF_ALLOC;
-       ndr_err = ndr_pull(pull, NDR_OUT, st);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
-               ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
-                                        "failed output validation pull - %s",
-                                        nt_errstr(status));
-               return ndr_map_error2ntstatus(ndr_err);
        }
 
-       push = ndr_push_init_ctx(mem_ctx);
-       if (!push) {
-               return NT_STATUS_NO_MEMORY;
-       }       
-
        ndr_err = ndr_push(push, NDR_OUT, st);
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
@@ -2008,9 +768,9 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
 
        /* this checks the printed forms of the two structures, which effectively
           tests all of the value() attributes */
-       s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
+       s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
                                       NDR_OUT, struct_ptr);
-       s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
+       s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
                                       NDR_OUT, st);
        if (strcmp(s1, s2) != 0) {
 #if 1
index 09ae9d1d646ba91bfd1834a7c7e54d064e4e57cb..3bd918e8dbcf8fca50643fc4dff10690a0f6f4db 100644 (file)
@@ -47,75 +47,31 @@ struct gensec_settings;
 struct cli_credentials;
 struct dcecli_security {
        struct dcerpc_security *sec;
-       enum dcerpc_AuthType auth_type;
-       enum dcerpc_AuthLevel auth_level;
-       uint32_t auth_context_id;
-       struct {
-               struct dcerpc_auth *out;
-               struct dcerpc_auth *in;
-               TALLOC_CTX *mem;
-       } tmp_auth_info;
        struct gensec_security *generic_state;
 
        /* get the session key */
        NTSTATUS (*session_key)(struct dcecli_connection *, DATA_BLOB *);
-
-       bool verified_bitmask1;
-
 };
 
 /*
   this holds the information that is not specific to a particular rpc context_id
 */
-struct rpc_request;
 struct dcecli_connection {
        struct dcerpc_association *assoc;
        struct dcerpc_connection *conn;
-       uint32_t call_id;
-       uint32_t srv_max_xmit_frag;
-       uint32_t srv_max_recv_frag;
        uint32_t flags;
        struct dcecli_security security_state;
        struct tevent_context *event_ctx;
 
-       struct tevent_immediate *io_trigger;
-       bool io_trigger_pending;
-
        /** Directory in which to save ndrdump-parseable files */
        const char *packet_log_dir;
 
-       bool dead;
-       bool free_skipped;
-
        struct dcerpc_transport {
                enum dcerpc_transport_t transport;
                void *private_data;
-
-               struct tstream_context *stream;
-               /** to serialize write events */
-               struct tevent_queue *write_queue;
-               /** the current active read request if any */
-               struct tevent_req *read_subreq;
-               /** number of read requests other than the current active */
-               uint32_t pending_reads;
        } transport;
 
        const char *server_name;
-
-       /* Requests that have been sent, waiting for a reply */
-       struct rpc_request *pending;
-
-       /* Sync requests waiting to be shipped */
-       struct rpc_request *request_queue;
-
-       /* the next context_id to be assigned */
-       uint32_t next_context_id;
-
-       /* The maximum total payload of reassembled response pdus */
-       size_t max_total_response_size;
-
-       /* the negotiated bind time features */
-       uint16_t bind_time_features;
 };
 
 /*
@@ -126,8 +82,6 @@ struct dcerpc_pipe {
 
        struct dcerpc_presentation *pres;
 
-       uint32_t context_id;
-
        struct GUID object;
        struct ndr_syntax_id syntax;
        struct ndr_syntax_id transfer_syntax;
@@ -135,21 +89,8 @@ struct dcerpc_pipe {
        struct dcecli_connection *conn;
        const struct dcerpc_binding *binding;
 
-       /** the last fault code from a DCERPC fault */
-       uint32_t last_fault_code;
-
        /** timeout for individual rpc requests, in seconds */
        uint32_t request_timeout;
-
-       /*
-        * Set for the timeout in dcerpc_pipe_connect_b_send(), to
-        * allow the timeout not to destory the stack during a nested
-        * event loop caused by gensec_update()
-        */
-       bool inhibit_timeout_processing;
-       bool timed_out;
-
-       bool verified_pcontext;
 };
 
 /* default timeout for all rpc requests, in seconds */
index cff29bc06b2a9b70db446af3b3a8f823f153fd55..7fe57cd921ba11a37b9930d91e9de9443d2bcf13 100644 (file)
@@ -1203,12 +1203,12 @@ static void dcerpc_connect_timeout_handler(struct tevent_context *ev, struct tev
 {
        struct composite_context *c = talloc_get_type_abort(private_data,
                                                      struct composite_context);
-       struct pipe_connect_state *s = talloc_get_type_abort(c->private_data, struct pipe_connect_state);
-       if (!s->pipe->inhibit_timeout_processing) {
+       //struct pipe_connect_state *s = talloc_get_type_abort(c->private_data, struct pipe_connect_state);
+       //if (!s->pipe->inhibit_timeout_processing) {
                composite_error(c, NT_STATUS_IO_TIMEOUT);
-       } else {
-               s->pipe->timed_out = true;
-       }
+       //} else {
+       //      s->pipe->timed_out = true;
+       //}
 }
 
 /*
@@ -1252,9 +1252,6 @@ _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent
        s->credentials  = credentials;
        s->lp_ctx       = lp_ctx;
 
-       s->pipe->timed_out = false;
-       s->pipe->inhibit_timeout_processing = false;
-
        tevent_add_timer(c->event_ctx, c,
                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
                         dcerpc_connect_timeout_handler, c);
index 39f7d87fc8340a590273057750359cc240c3f981..b47dc7f258725476d1afc354aed3185ef3c81ceb 100644 (file)
 #include "auth/gensec/gensec.h"
 #include "param/param.h"
 #include "librpc/rpc/rpc_common.h"
+#include "librpc/rpc/dcerpc_connection.h"
 
-/*
-  find a dcerpc call on an interface by name
-*/
-const struct ndr_interface_call *dcerpc_iface_find_call(const struct ndr_interface_table *iface,
-                                                       const char *name)
+static uint32_t dcerpc_auth_level(struct dcecli_connection *c)
 {
-       int i;
-       for (i=0;i<iface->num_calls;i++) {
-               if (strcmp(iface->calls[i].name, name) == 0) {
-                       return &iface->calls[i];
-               }
+       uint8_t auth_level;
+
+       if (c->flags & DCERPC_SEAL) {
+               auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+       } else if (c->flags & DCERPC_SIGN) {
+               auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+       } else if (c->flags & DCERPC_CONNECT) {
+               auth_level = DCERPC_AUTH_LEVEL_CONNECT;
+       } else {
+               auth_level = DCERPC_AUTH_LEVEL_NONE;
        }
-       return NULL;
+       return auth_level;
 }
 
 /* 
@@ -845,7 +847,6 @@ _PUBLIC_ void dcerpc_log_packet(const char *lockdir,
 /*
   create a secondary context from a primary connection
 
-  this uses dcerpc_alter_context() to create a new dcerpc context_id
 */
 _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p, 
                                  struct dcerpc_pipe **pp2,
@@ -854,7 +855,8 @@ _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p,
        NTSTATUS status;
        struct dcerpc_pipe *p2;
        struct GUID *object = NULL;
-       
+       struct composite_context *subreq;
+
        p2 = talloc_zero(p, struct dcerpc_pipe);
        if (p2 == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -862,30 +864,18 @@ _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p,
        p2->conn = talloc_reference(p2, p->conn);
        p2->request_timeout = p->request_timeout;
 
-       p2->context_id = ++p->conn->next_context_id;
-
-       p2->syntax = table->syntax_id;
-
-       p2->transfer_syntax = p->transfer_syntax;
-
        p2->binding = dcerpc_binding_dup(p2, p->binding);
        if (p2->binding == NULL) {
                talloc_free(p2);
                return NT_STATUS_NO_MEMORY;
        }
 
-       p2->object = dcerpc_binding_get_object(p2->binding);
-       if (!GUID_all_zero(&p2->object)) {
-               object = &p2->object;
-       }
-
-       p2->binding_handle = dcerpc_pipe_binding_handle(p2, object, table);
-       if (p2->binding_handle == NULL) {
+       subreq = dcerpc_bind_auth_none_send(p2, p2, table);
+       if (subreq == NULL) {
                talloc_free(p2);
                return NT_STATUS_NO_MEMORY;
        }
-
-       status = dcerpc_alter_context(p2, p2, &p2->syntax, &p2->transfer_syntax);
+       status = dcerpc_bind_auth_none_recv(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(p2);
                return status;
@@ -895,3 +885,41 @@ _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p,
 
        return NT_STATUS_OK;
 }
+
+/*
+ * this is just for testing! use dcerpc_secondary_context() otherwise!
+ */
+NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+                             const struct ndr_syntax_id *abstract,
+                             const struct ndr_syntax_id *transfer)
+{
+       struct composite_context *subreq;
+       NTSTATUS status;
+       struct dcerpc_presentation *saved_pres = p->pres;
+       struct ndr_interface_table table = {
+               .syntax_id = *abstract,
+       };
+
+       p->pres = dcerpc_presentation_test_copy(mem_ctx,
+                                               saved_pres,
+                                               NULL, /* context_id */
+                                               &table,
+                                               transfer);
+       if (p->pres == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       subreq = dcerpc_bind_auth_none_send(mem_ctx, p, NULL);
+       if (subreq == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       status = dcerpc_bind_auth_none_recv(subreq);
+
+done:
+       TALLOC_FREE(p->pres);
+       p->pres = saved_pres;
+       return status;
+}