Merge branch 'master' of ssh://git.samba.org/data/git/samba
[kai/samba.git] / source4 / librpc / rpc / dcerpc.c
index 70c60b100a4a40d53b2f36cd4f2bd7fe8297da5f..4e07cc7b57c89e4233da1df00f7fdca70131de8e 100644 (file)
@@ -8,7 +8,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
 #include "lib/events/events.h"
 #include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_proto.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/gen_ndr/ndr_dcerpc.h"
 #include "libcli/composite/composite.h"
 #include "auth/gensec/gensec.h"
+#include "param/param.h"
 
-NTSTATUS dcerpc_init(void)
+_PUBLIC_ NTSTATUS dcerpc_init(void)
 {
-       gensec_init();
-
-       return NT_STATUS_OK;
+       return gensec_init(global_loadparm);
 }
 
+static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
 
 /* destroy a dcerpc connection */
-static int dcerpc_connection_destructor(struct dcerpc_connection *c)
+static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
 {
-       if (c->transport.shutdown_pipe) {
-               c->transport.shutdown_pipe(c);
+       if (conn->dead) {
+               conn->free_skipped = true;
+               return -1;
        }
+       dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
        return 0;
 }
 
@@ -52,8 +54,9 @@ static int dcerpc_connection_destructor(struct dcerpc_connection *c)
 /* initialise a dcerpc connection. 
    the event context is optional
 */
-struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
-                                                struct event_context *ev)
+static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
+                                                struct event_context *ev,
+                                                struct smb_iconv_convenience *ic)
 {
        struct dcerpc_connection *c;
 
@@ -62,20 +65,15 @@ struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       if (ev == NULL) {
-               ev = event_context_init(c);
-               if (ev == NULL) {
-                       talloc_free(c);
-                       return NULL;
-               }
-       }
+       c->iconv_convenience = talloc_reference(c, ic);
 
-       c->event_ctx = ev;
-       
-       if (!talloc_reference(c, ev)) {
+       c->event_ctx = talloc_reference(c, ev);
+
+       if (c->event_ctx == NULL) {
                talloc_free(c);
                return NULL;
        }
+
        c->call_id = 1;
        c->security_state.auth_info = NULL;
        c->security_state.session_key = dcerpc_generic_session_key;
@@ -92,7 +90,8 @@ struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
 }
 
 /* initialise a dcerpc pipe. */
-struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
+_PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev,
+                                    struct smb_iconv_convenience *ic)
 {
        struct dcerpc_pipe *p;
 
@@ -101,7 +100,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *
                return NULL;
        }
 
-       p->conn = dcerpc_connection_init(p, ev);
+       p->conn = dcerpc_connection_init(p, ev, ic);
        if (p->conn == NULL) {
                talloc_free(p);
                return NULL;
@@ -110,6 +109,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *
        p->last_fault_code = 0;
        p->context_id = 0;
        p->request_timeout = DCERPC_REQUEST_TIMEOUT;
+       p->binding = NULL;
 
        ZERO_STRUCT(p->syntax);
        ZERO_STRUCT(p->transfer_syntax);
@@ -160,13 +160,13 @@ void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
 }
 
 
-/*
+/**
   setup for a ndr pull, also setting up any flags from the binding string
 */
 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);
+       struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
 
        if (ndr == NULL) return ndr;
 
@@ -189,6 +189,7 @@ static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_
                            struct ncacn_packet *pkt)
 {
        struct ndr_pull *ndr;
+       enum ndr_err_code ndr_err;
 
        ndr = ndr_pull_init_flags(c, blob, mem_ctx);
        if (!ndr) {
@@ -199,32 +200,11 @@ static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_
                ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
        }
 
-       return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
-}
-
-/*
-  generate a CONNECT level verifier
-*/
-static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
-{
-       *blob = data_blob_talloc(mem_ctx, NULL, 16);
-       if (blob->data == NULL) {
-               return NT_STATUS_NO_MEMORY;
+       ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return ndr_map_error2ntstatus(ndr_err);
        }
-       SIVAL(blob->data, 0, 1);
-       memset(blob->data+4, 0, 12);
-       return NT_STATUS_OK;
-}
 
-/*
-  check a CONNECT level verifier
-*/
-static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
-{
-       if (blob->length != 16 ||
-           IVAL(blob->data, 0) != 1) {
-               return NT_STATUS_ACCESS_DENIED;
-       }
        return NT_STATUS_OK;
 }
 
@@ -239,12 +219,33 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX
        NTSTATUS status;
        struct dcerpc_auth auth;
        DATA_BLOB auth_blob;
+       enum ndr_err_code ndr_err;
 
-       if (pkt->auth_length == 0 &&
-           c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
+       if (!c->security_state.auth_info ||
+           !c->security_state.generic_state) {
                return NT_STATUS_OK;
        }
 
+       switch (c->security_state.auth_info->auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+               break;
+
+       case DCERPC_AUTH_LEVEL_CONNECT:
+               if (pkt->auth_length != 0) {
+                       break;
+               }
+               return NT_STATUS_OK;
+       case DCERPC_AUTH_LEVEL_NONE:
+               if (pkt->auth_length != 0) {
+                       return NT_STATUS_INVALID_NETWORK_RESPONSE;
+               }
+               return NT_STATUS_OK;
+
+       default:
+               return NT_STATUS_INVALID_LEVEL;
+       }
+
        auth_blob.length = 8 + pkt->auth_length;
 
        /* check for a valid length */
@@ -267,12 +268,12 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX
                ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
        }
 
-       status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
-       if (!NT_STATUS_IS_OK(status)) {
-               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;
+
        /* check signature or unseal the packet */
        switch (c->security_state.auth_info->auth_level) {
        case DCERPC_AUTH_LEVEL_PRIVACY:
@@ -299,10 +300,8 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX
                break;
 
        case DCERPC_AUTH_LEVEL_CONNECT:
-               status = dcerpc_check_connect_verifier(&auth.credentials);
-               break;
-
-       case DCERPC_AUTH_LEVEL_NONE:
+               /* for now we ignore possible signatures here */
+               status = NT_STATUS_OK;
                break;
 
        default:
@@ -325,20 +324,38 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX
 */
 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, 
                                         DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
+                                        size_t sig_size,
                                         struct ncacn_packet *pkt)
 {
        NTSTATUS status;
        struct ndr_push *ndr;
        DATA_BLOB creds2;
        size_t payload_length;
+       enum ndr_err_code ndr_err;
+       size_t hdr_size = DCERPC_REQUEST_LENGTH;
 
        /* non-signed packets are simpler */
-       if (!c->security_state.auth_info || 
-           !c->security_state.generic_state) {
-               return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
+       if (sig_size == 0) {
+               return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
        }
 
-       ndr = ndr_push_init_ctx(mem_ctx);
+       switch (c->security_state.auth_info->auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+               break;
+
+       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);
+
+       case DCERPC_AUTH_LEVEL_NONE:
+               return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
+
+       default:
+               return NT_STATUS_INVALID_LEVEL;
+       }
+
+       ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
        if (!ndr) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -347,103 +364,78 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
                ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
        }
 
-       if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
+       if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
                ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
+               hdr_size += 16;
        }
 
-       status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+       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 = 
                (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
-       ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
+       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;
 
-       /* sign or seal the packet */
-       switch (c->security_state.auth_info->auth_level) {
-       case DCERPC_AUTH_LEVEL_PRIVACY:
-       case DCERPC_AUTH_LEVEL_INTEGRITY:
-               c->security_state.auth_info->credentials
-                       = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state, 
-                                                                         payload_length));
-               data_blob_clear(&c->security_state.auth_info->credentials);
-               break;
-
-       case DCERPC_AUTH_LEVEL_CONNECT:
-               status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
-               break;
-               
-       case DCERPC_AUTH_LEVEL_NONE:
-               c->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;
-       }       
+       /* we start without signature, it will appended later */
+       c->security_state.auth_info->credentials = data_blob(NULL,0);
 
        /* add the auth verifier */
-       status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
+       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);
 
-       /* fill in the fragment length and auth_length, we can't fill
-          in these earlier as we don't know the signature length (it
-          could be variable length) */
-       dcerpc_set_frag_length(blob, blob->length);
-       dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
+       /*
+        * Setup the frag and auth length in the packet buffer.
+        * This is needed if the GENSEC mech does AEAD signing
+        * of the packet headers. The signature itself will be
+        * appended later.
+        */
+       dcerpc_set_frag_length(blob, blob->length + sig_size);
+       dcerpc_set_auth_length(blob, sig_size);
 
        /* sign or seal the packet */
        switch (c->security_state.auth_info->auth_level) {
        case DCERPC_AUTH_LEVEL_PRIVACY:
                status = gensec_seal_packet(c->security_state.generic_state, 
                                            mem_ctx, 
-                                           blob->data + DCERPC_REQUEST_LENGTH, 
+                                           blob->data + hdr_size,
                                            payload_length,
                                            blob->data,
-                                           blob->length - 
-                                           c->security_state.auth_info->credentials.length,
+                                           blob->length,
                                            &creds2);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
-               memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
                break;
 
        case DCERPC_AUTH_LEVEL_INTEGRITY:
                status = gensec_sign_packet(c->security_state.generic_state, 
                                            mem_ctx, 
-                                           blob->data + DCERPC_REQUEST_LENGTH, 
+                                           blob->data + hdr_size,
                                            payload_length, 
                                            blob->data,
-                                           blob->length - 
-                                           c->security_state.auth_info->credentials.length,
+                                           blob->length,
                                            &creds2);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
-               memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
-               break;
-
-       case DCERPC_AUTH_LEVEL_CONNECT:
-               break;
-
-       case DCERPC_AUTH_LEVEL_NONE:
-               c->security_state.auth_info->credentials = data_blob(NULL, 0);
                break;
 
        default:
@@ -451,7 +443,17 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
                break;
        }
 
-       data_blob_free(&c->security_state.auth_info->credentials);
+       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;
+       }
+
+       if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        return NT_STATUS_OK;
 }
@@ -493,26 +495,58 @@ static NTSTATUS dcerpc_map_reason(uint16_t reason)
 */
 static void dcerpc_composite_fail(struct rpc_request *req)
 {
-       struct composite_context *c = talloc_get_type(req->async.private, 
+       struct composite_context *c = talloc_get_type(req->async.private_data
                                                      struct composite_context);
        composite_error(c, req->status);
 }
 
+/*
+  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;
+       }
+       return 0;
+}
+
+
 /*
   mark the dcerpc connection dead. All outstanding requests get an error
 */
 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
 {
+       if (conn->dead) return;
+
+       conn->dead = true;
+
+       if (conn->transport.shutdown_pipe) {
+               conn->transport.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;
-               DLIST_REMOVE(conn->pending, req);
                if (req->async.callback) {
                        req->async.callback(req);
                }
        }       
+
+       talloc_set_destructor(conn, NULL);
+       if (conn->free_skipped) {
+               talloc_free(conn);
+       }
 }
 
 /*
@@ -563,7 +597,7 @@ static void dcerpc_bind_recv_handler(struct rpc_request *req,
        struct composite_context *c;
        struct dcerpc_connection *conn;
 
-       c = talloc_get_type(req->async.private, struct composite_context);
+       c = talloc_get_type(req->async.private_data, struct composite_context);
 
        if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
                DEBUG(2,("dcerpc: bind_nak reason %d\n",
@@ -576,7 +610,7 @@ static void dcerpc_bind_recv_handler(struct rpc_request *req,
        if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
            (pkt->u.bind_ack.num_results == 0) ||
            (pkt->u.bind_ack.ctx_list[0].result != 0)) {
-               composite_error(c, NT_STATUS_UNSUCCESSFUL);
+               composite_error(c, NT_STATUS_NET_WRITE_FAULT);
                return;
        }
 
@@ -585,16 +619,33 @@ static void dcerpc_bind_recv_handler(struct rpc_request *req,
        conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
        conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
 
+       if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
+           (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
+               conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
+       }
+
+       if ((req->p->binding->flags & DCERPC_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 (conn->security_state.auth_info &&
            pkt->u.bind_ack.auth_info.length) {
-               c->status = ndr_pull_struct_blob(
+               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 (!composite_is_ok(c)) return;
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
        }
 
+       req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
+
        composite_done(c);
 }
 
@@ -606,44 +657,36 @@ static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event
 {
        struct rpc_request *req = talloc_get_type(private, struct rpc_request);
 
-       if (req->state != RPC_REQUEST_PENDING) {
+       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;
        }
 
-       req->status = NT_STATUS_IO_TIMEOUT;
-       req->state = RPC_REQUEST_DONE;
-       DLIST_REMOVE(req->p->conn->pending, req);
-       if (req->async.callback) {
-               req->async.callback(req);
-       }
+       dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
 }
 
-
 /*
   send a async dcerpc bind request
 */
 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
                                           TALLOC_CTX *mem_ctx,
-                                          const struct dcerpc_syntax_id *syntax,
-                                          const struct dcerpc_syntax_id *transfer_syntax)
+                                          const struct ndr_syntax_id *syntax,
+                                          const struct ndr_syntax_id *transfer_syntax)
 {
        struct composite_context *c;
        struct ncacn_packet pkt;
        DATA_BLOB blob;
        struct rpc_request *req;
 
-       /* we allocate a dcerpc_request so we can be in the same
-          request queue as normal requests, but most of the request
-          fields are not used as there is no call id */
-       req = talloc_zero(mem_ctx, struct rpc_request);
-       if (req == NULL) return NULL;
-
-       c = talloc_zero(mem_ctx, struct composite_context);
+       c = composite_create(mem_ctx,p->conn->event_ctx);
        if (c == NULL) return NULL;
 
-       c->state = COMPOSITE_STATE_IN_PROGRESS;
        c->private_data = p;
-       c->event_ctx = p->conn->event_ctx;
 
        p->syntax = *syntax;
        p->transfer_syntax = *transfer_syntax;
@@ -655,16 +698,20 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
        pkt.call_id = p->conn->call_id;
        pkt.auth_length = 0;
 
+       if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
+               pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
+       }
+
+       if (p->binding->flags & DCERPC_HEADER_SIGNING) {
+               pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+       }
+
        pkt.u.bind.max_xmit_frag = 5840;
        pkt.u.bind.max_recv_frag = 5840;
-       pkt.u.bind.assoc_group_id = 0;
+       pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
        pkt.u.bind.num_contexts = 1;
-       pkt.u.bind.ctx_list =
-               talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
-       if (pkt.u.bind.ctx_list == NULL) {
-               c->status = NT_STATUS_NO_MEMORY;
-               goto failed;
-       }
+       pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
+       if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
        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;
@@ -672,38 +719,37 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
        pkt.u.bind.auth_info = data_blob(NULL, 0);
 
        /* construct the NDR form of the packet */
-       c->status = ncacn_push_auth(&blob, c, &pkt,
+       c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
                                    p->conn->security_state.auth_info);
-       if (!NT_STATUS_IS_OK(c->status)) {
-               goto failed;
-       }
+       if (!composite_is_ok(c)) return c;
 
        p->conn->transport.recv_data = dcerpc_recv_data;
 
+       /*
+        * we allocate a dcerpc_request so we can be in the same
+        * request queue as normal requests
+        */
+       req = talloc_zero(c, struct rpc_request);
+       if (composite_nomem(req, c)) return c;
+
        req->state = RPC_REQUEST_PENDING;
        req->call_id = pkt.call_id;
-       req->async.private = c;
+       req->async.private_data = c;
        req->async.callback = dcerpc_composite_fail;
        req->p = p;
        req->recv_handler = dcerpc_bind_recv_handler;
-
        DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
+       talloc_set_destructor(req, dcerpc_req_dequeue);
 
        c->status = p->conn->transport.send_request(p->conn, &blob,
-                                                   True);
-       if (!NT_STATUS_IS_OK(c->status)) {
-               goto failed;
-       }
+                                                   true);
+       if (!composite_is_ok(c)) return c;
 
        event_add_timed(c->event_ctx, req,
                        timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
                        dcerpc_timeout_handler, req);
 
        return c;
-
- failed:
-       composite_error(c, c->status);
-       return c;
 }
 
 /*
@@ -716,89 +762,49 @@ NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
        return result;
 }
 
-/* 
-   perform a bind using the given syntax 
-
-   the auth_info structure is updated with the reply authentication info
-   on success
-*/
-NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
-                    TALLOC_CTX *mem_ctx,
-                    const struct dcerpc_syntax_id *syntax,
-                    const struct dcerpc_syntax_id *transfer_syntax)
-{
-       struct composite_context *creq;
-       creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
-       return dcerpc_bind_recv(creq);
-}
-
 /* 
    perform a continued bind (and auth3)
 */
-NTSTATUS dcerpc_auth3(struct dcerpc_connection *c, 
+NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
                      TALLOC_CTX *mem_ctx)
 {
        struct ncacn_packet pkt;
        NTSTATUS status;
        DATA_BLOB blob;
 
-       init_ncacn_hdr(c, &pkt);
+       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(c);
+       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);
 
-       /* construct the NDR form of the packet */
-       status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
+               pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
        }
 
-       /* send it on its way */
-       status = c->transport.send_request(c, &blob, False);
+       if (p->binding->flags & DCERPC_HEADER_SIGNING) {
+               pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+       }
+
+       /* 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)) {
                return status;
        }
 
-       return status;  
-}
-
-
-/*
-  return the rpc syntax and transfer syntax given the pipe uuid and version
-*/
-NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
-                             struct dcerpc_syntax_id *syntax,
-                             struct dcerpc_syntax_id *transfer_syntax)
-{
-       syntax->uuid = table->syntax_id.uuid;
-       syntax->if_version = table->syntax_id.if_version;
-
-       *transfer_syntax = ndr_transfer_syntax;
-
-       return NT_STATUS_OK;
-}
-
-/* perform a dcerpc bind, using the uuid as the key */
-NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
-                           TALLOC_CTX *mem_ctx,
-                           const struct dcerpc_interface_table *table)
-{
-       struct dcerpc_syntax_id syntax;
-       struct dcerpc_syntax_id transfer_syntax;
-       NTSTATUS status;
-
-       status = dcerpc_init_syntaxes(table,
-                                     &syntax, &transfer_syntax);
+       /* send it on its way */
+       status = p->conn->transport.send_request(p->conn, &blob, false);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
                return status;
        }
 
-       return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
+       return NT_STATUS_OK;    
 }
 
 
@@ -833,6 +839,14 @@ static void dcerpc_request_recv_data(struct dcerpc_connection *c,
                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);
@@ -842,8 +856,8 @@ static void dcerpc_request_recv_data(struct dcerpc_connection *c,
        talloc_steal(req, raw_packet->data);
 
        if (req->recv_handler != NULL) {
+               dcerpc_req_dequeue(req);
                req->state = RPC_REQUEST_DONE;
-               DLIST_REMOVE(c->pending, req);
                req->recv_handler(req, raw_packet, pkt);
                return;
        }
@@ -914,22 +928,13 @@ req_done:
        }
 }
 
-/*
-  make sure requests are cleaned up 
- */
-static int dcerpc_req_destructor(struct rpc_request *req)
-{
-       DLIST_REMOVE(req->p->conn->pending, req);
-       return 0;
-}
-
 /*
   perform the send side of a async dcerpc request
 */
 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
                                               const struct GUID *object,
                                               uint16_t opnum,
-                                              BOOL async,
+                                              bool async,
                                               DATA_BLOB *stub_data)
 {
        struct rpc_request *req;
@@ -944,17 +949,18 @@ static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
        req->p = p;
        req->call_id = next_call_id(p->conn);
        req->status = NT_STATUS_OK;
-       req->state = RPC_REQUEST_PENDING;
+       req->state = RPC_REQUEST_QUEUED;
        req->payload = data_blob(NULL, 0);
        req->flags = 0;
        req->fault_code = 0;
        req->async_call = async;
+       req->ignore_timeout = false;
        req->async.callback = NULL;
-       req->async.private = NULL;
+       req->async.private_data = NULL;
        req->recv_handler = NULL;
 
        if (object != NULL) {
-               req->object = talloc_memdup(req, object, sizeof(*object));
+               req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
                if (req->object == NULL) {
                        talloc_free(req);
                        return NULL;
@@ -966,11 +972,12 @@ static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
        req->opnum = opnum;
        req->request_data.length = stub_data->length;
        req->request_data.data = talloc_reference(req, stub_data->data);
-       if (req->request_data.data == NULL) {
+       if (req->request_data.length && req->request_data.data == NULL) {
                return NULL;
        }
 
        DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
+       talloc_set_destructor(req, dcerpc_req_dequeue);
 
        dcerpc_ship_next_request(p->conn);
 
@@ -980,7 +987,6 @@ static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
                                dcerpc_timeout_handler, req);
        }
 
-       talloc_set_destructor(req, dcerpc_req_destructor);
        return req;
 }
 
@@ -996,7 +1002,8 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
        struct ncacn_packet pkt;
        DATA_BLOB blob;
        uint32_t remaining, chunk_size;
-       BOOL first_packet = True;
+       bool first_packet = true;
+       size_t sig_size = 0;
 
        req = c->request_queue;
        if (req == NULL) {
@@ -1012,6 +1019,7 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
 
        DLIST_REMOVE(c->request_queue, req);
        DLIST_ADD(c->pending, req);
+       req->state = RPC_REQUEST_PENDING;
 
        init_ncacn_hdr(p->conn, &pkt);
 
@@ -1019,7 +1027,18 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
 
        /* we can write a full max_recv_frag size, minus the dcerpc
           request header size */
-       chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
+       chunk_size = p->conn->srv_max_recv_frag;
+       chunk_size -= DCERPC_REQUEST_LENGTH;
+       if (c->security_state.auth_info &&
+           c->security_state.generic_state) {
+               sig_size = gensec_sig_size(c->security_state.generic_state,
+                                          p->conn->srv_max_recv_frag);
+               if (sig_size) {
+                       chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
+                       chunk_size -= sig_size;
+               }
+       }
+       chunk_size -= (chunk_size % 16);
 
        pkt.ptype = DCERPC_PKT_REQUEST;
        pkt.call_id = req->call_id;
@@ -1031,16 +1050,16 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
 
        if (req->object) {
                pkt.u.request.object.object = *req->object;
-               pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
+               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 last_frag = false;
 
-               first_packet = False;
+               first_packet = false;
                pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
 
                if (remaining == stub_data->length) {
@@ -1048,14 +1067,14 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
                }
                if (chunk == remaining) {
                        pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
-                       last_frag = True;
+                       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;
 
-               req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
+               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);
@@ -1077,7 +1096,7 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
   return the event context for a dcerpc pipe
   used by callers who wish to operate asynchronously
 */
-struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
+_PUBLIC_ struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
 {
        return p->conn->event_ctx;
 }
@@ -1093,7 +1112,7 @@ NTSTATUS dcerpc_request_recv(struct rpc_request *req,
 {
        NTSTATUS status;
 
-       while (req->state == RPC_REQUEST_PENDING) {
+       while (req->state != RPC_REQUEST_DONE) {
                struct event_context *ctx = dcerpc_event_context(req->p);
                if (event_loop_once(ctx) != 0) {
                        return NT_STATUS_CONNECTION_DISCONNECTED;
@@ -1117,7 +1136,7 @@ NTSTATUS dcerpc_request_recv(struct rpc_request *req,
 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
                        struct GUID *object,
                        uint16_t opnum,
-                       BOOL async,
+                       bool async,
                        TALLOC_CTX *mem_ctx,
                        DATA_BLOB *stub_data_in,
                        DATA_BLOB *stub_data_out)
@@ -1149,8 +1168,8 @@ static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
        void *st;
        struct ndr_pull *pull;
        struct ndr_push *push;
-       NTSTATUS status;
        DATA_BLOB blob2;
+       enum ndr_err_code ndr_err;
 
        st = talloc_size(mem_ctx, struct_size);
        if (!st) {
@@ -1163,35 +1182,39 @@ static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
        }
        pull->flags |= LIBNDR_FLAG_REF_ALLOC;
 
-       status = ndr_pull(pull, NDR_IN, st);
-       if (!NT_STATUS_IS_OK(status)) {
-               return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
-                                     "failed input validation pull - %s",
-                                     nt_errstr(status));
+       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);
+       push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
        if (!push) {
                return NT_STATUS_NO_MEMORY;
        }       
 
-       status = ndr_push(push, NDR_IN, st);
-       if (!NT_STATUS_IS_OK(status)) {
-               return ndr_push_error(push, NDR_ERR_VALIDATE, 
-                                     "failed input validation push - %s",
-                                     nt_errstr(status));
+       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_equal(&blob, &blob2)) {
+       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);
-               return ndr_push_error(push, NDR_ERR_VALIDATE, 
-                                     "failed input validation data - %s",
-                                     nt_errstr(status));
+               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;
@@ -1215,10 +1238,10 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
        void *st;
        struct ndr_pull *pull;
        struct ndr_push *push;
-       NTSTATUS status;
        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) {
@@ -1226,16 +1249,18 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
        }
        memcpy(st, struct_ptr, struct_size);
 
-       push = ndr_push_init_ctx(mem_ctx);
+       push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
        if (!push) {
                return NT_STATUS_NO_MEMORY;
        }       
 
-       status = ndr_push(push, NDR_OUT, struct_ptr);
-       if (!NT_STATUS_IS_OK(status)) {
-               return ndr_push_error(push, NDR_ERR_VALIDATE, 
-                                     "failed output validation push - %s",
-                                     nt_errstr(status));
+       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);
@@ -1246,35 +1271,39 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
        }
 
        pull->flags |= LIBNDR_FLAG_REF_ALLOC;
-       status = ndr_pull(pull, NDR_OUT, st);
-       if (!NT_STATUS_IS_OK(status)) {
-               return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
-                                     "failed output validation pull - %s",
-                                     nt_errstr(status));
+       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);
+       push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
        if (!push) {
                return NT_STATUS_NO_MEMORY;
        }       
 
-       status = ndr_push(push, NDR_OUT, st);
-       if (!NT_STATUS_IS_OK(status)) {
-               return ndr_push_error(push, NDR_ERR_VALIDATE, 
-                                     "failed output validation push2 - %s",
-                                     nt_errstr(status));
+       ndr_err = ndr_push(push, NDR_OUT, st);
+       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 push2 - %s",
+                                        nt_errstr(status));
+               return ndr_map_error2ntstatus(ndr_err);
        }
 
        blob2 = ndr_push_blob(push);
 
-       if (!data_blob_equal(&blob, &blob2)) {
+       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);
-               return ndr_push_error(push, NDR_ERR_VALIDATE, 
-                                     "failed output validation data - %s",
-                                     nt_errstr(status));
+               ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
+                                        "failed output validation blobs doesn't match");
+               return ndr_map_error2ntstatus(ndr_err);
        }
 
        /* this checks the printed forms of the two structures, which effectively
@@ -1285,7 +1314,7 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
                                       NDR_OUT, st);
        if (strcmp(s1, s2) != 0) {
 #if 1
-               printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
+               DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
 #else
                /* this is sometimes useful */
                printf("VALIDATE ERROR\n");
@@ -1293,32 +1322,36 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
                file_save("gen.dat", s2, strlen(s2));
                system("diff -u wire.dat gen.dat");
 #endif
+               ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
+                                        "failed output validation strings doesn't match");
+               return ndr_map_error2ntstatus(ndr_err);
        }
 
        return NT_STATUS_OK;
 }
 
 
-/*
+/**
  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 dcerpc_interface_table *table,
+                                               const struct ndr_interface_table *table,
                                                uint32_t opnum, 
                                                TALLOC_CTX *mem_ctx, 
                                                void *r)
 {
-       const struct dcerpc_interface_call *call;
+       const struct ndr_interface_call *call;
        struct ndr_push *push;
        NTSTATUS status;
        DATA_BLOB request;
        struct rpc_request *req;
+       enum ndr_err_code ndr_err;
 
        call = &table->calls[opnum];
 
        /* setup for a ndr_push_* call */
-       push = ndr_push_init_ctx(mem_ctx);
+       push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
        if (!push) {
                return NULL;
        }
@@ -1328,8 +1361,9 @@ struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
        }
 
        /* push the structure into a blob */
-       status = call->ndr_push(push, NDR_IN, r);
-       if (!NT_STATUS_IS_OK(status)) {
+       ndr_err = call->ndr_push(push, NDR_IN, r);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               status = ndr_map_error2ntstatus(ndr_err);
                DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
                         nt_errstr(status)));
                talloc_free(push);
@@ -1372,7 +1406,7 @@ struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
 /*
   receive the answer from a dcerpc_ndr_request_send()
 */
-NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
+_PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
 {
        struct dcerpc_pipe *p = req->p;
        NTSTATUS status;
@@ -1382,15 +1416,19 @@ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
        TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
        void *r = req->ndr.struct_ptr;
        uint32_t opnum = req->ndr.opnum;
-       const struct dcerpc_interface_table *table = req->ndr.table;
-       const struct dcerpc_interface_call *call = &table->calls[opnum];
+       const struct ndr_interface_table *table = req->ndr.table;
+       const struct ndr_interface_call *call = &table->calls[opnum];
+       enum ndr_err_code ndr_err;
 
        /* make sure the recv code doesn't free the request, as we
           need to grab the flags element before it is freed */
-       talloc_increase_ref_count(req);
+       if (talloc_reference(p, req) == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        status = dcerpc_request_recv(req, mem_ctx, &response);
        if (!NT_STATUS_IS_OK(status)) {
+               talloc_unlink(p, req);
                return status;
        }
 
@@ -1399,14 +1437,14 @@ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
        /* prepare for ndr_pull_* */
        pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
        if (!pull) {
-               talloc_free(req);
+               talloc_unlink(p, req);
                return NT_STATUS_NO_MEMORY;
        }
 
        if (pull->data) {
                pull->data = talloc_steal(pull, pull->data);
        }
-       talloc_free(req);
+       talloc_unlink(p, req);
 
        if (flags & DCERPC_PULL_BIGENDIAN) {
                pull->flags |= LIBNDR_FLAG_BIGENDIAN;
@@ -1416,8 +1454,9 @@ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
        dump_data(10, pull->data, pull->data_size);
 
        /* pull the structure from the blob */
-       status = call->ndr_pull(pull, NDR_OUT, r);
-       if (!NT_STATUS_IS_OK(status)) {
+       ndr_err = call->ndr_pull(pull, NDR_OUT, r);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               status = ndr_map_error2ntstatus(ndr_err);
                dcerpc_log_packet(table, opnum, NDR_OUT, 
                                  &response);
                return status;
@@ -1456,9 +1495,9 @@ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
   this can be used when you have ndr push/pull functions in the
   standard format
 */
-NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
+_PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
                            const struct GUID *object,
-                           const struct dcerpc_interface_table *table,
+                           const struct ndr_interface_table *table,
                            uint32_t opnum, 
                            TALLOC_CTX *mem_ctx, 
                            void *r)
@@ -1477,12 +1516,15 @@ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
 /*
   a useful function for retrieving the server name we connected to
 */
-const char *dcerpc_server_name(struct dcerpc_pipe *p)
+_PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
 {
-       if (!p->conn->transport.peer_name) {
-               return "";
+       if (!p->conn->transport.target_hostname) {
+               if (!p->conn->transport.peer_name) {
+                       return "";
+               }
+               return p->conn->transport.peer_name(p->conn);
        }
-       return p->conn->transport.peer_name(p->conn);
+       return p->conn->transport.target_hostname(p->conn);
 }
 
 
@@ -1514,7 +1556,7 @@ static void dcerpc_alter_recv_handler(struct rpc_request *req,
        struct composite_context *c;
        struct dcerpc_pipe *recv_pipe;
 
-       c = talloc_get_type(req->async.private, struct composite_context);
+       c = talloc_get_type(req->async.private_data, struct composite_context);
        recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
 
        if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
@@ -1529,18 +1571,23 @@ static void dcerpc_alter_recv_handler(struct rpc_request *req,
        if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
            pkt->u.alter_resp.num_results == 0 ||
            pkt->u.alter_resp.ctx_list[0].result != 0) {
-               composite_error(c, NT_STATUS_UNSUCCESSFUL);
+               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) {
-               c->status = ndr_pull_struct_blob(
+               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 (!composite_is_ok(c)) return;
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
        }
 
        composite_done(c);
@@ -1551,26 +1598,18 @@ static void dcerpc_alter_recv_handler(struct rpc_request *req,
 */
 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
                                                    TALLOC_CTX *mem_ctx,
-                                                   const struct dcerpc_syntax_id *syntax,
-                                                   const struct dcerpc_syntax_id *transfer_syntax)
+                                                   const struct ndr_syntax_id *syntax,
+                                                   const struct ndr_syntax_id *transfer_syntax)
 {
        struct composite_context *c;
        struct ncacn_packet pkt;
        DATA_BLOB blob;
        struct rpc_request *req;
 
-       /* we allocate a dcerpc_request so we can be in the same
-          request queue as normal requests, but most of the request
-          fields are not used as there is no call id */
-       req = talloc_zero(mem_ctx, struct rpc_request);
-       if (req == NULL) return NULL;
-
-       c = talloc_zero(req, struct composite_context);
+       c = composite_create(mem_ctx, p->conn->event_ctx);
        if (c == NULL) return NULL;
 
-       c->state = COMPOSITE_STATE_IN_PROGRESS;
        c->private_data = p;
-       c->event_ctx = p->conn->event_ctx;
 
        p->syntax = *syntax;
        p->transfer_syntax = *transfer_syntax;
@@ -1582,16 +1621,20 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
        pkt.call_id = p->conn->call_id;
        pkt.auth_length = 0;
 
+       if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
+               pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
+       }
+
+       if (p->binding->flags & DCERPC_HEADER_SIGNING) {
+               pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+       }
+
        pkt.u.alter.max_xmit_frag = 5840;
        pkt.u.alter.max_recv_frag = 5840;
-       pkt.u.alter.assoc_group_id = 0;
+       pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
        pkt.u.alter.num_contexts = 1;
-       pkt.u.alter.ctx_list = talloc_array(mem_ctx,
-                                                  struct dcerpc_ctx_list, 1);
-       if (pkt.u.alter.ctx_list == NULL) {
-               c->status = NT_STATUS_NO_MEMORY;
-               goto failed;
-       }
+       pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
+       if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
        pkt.u.alter.ctx_list[0].context_id = p->context_id;
        pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
        pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
@@ -1599,37 +1642,36 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
        pkt.u.alter.auth_info = data_blob(NULL, 0);
 
        /* construct the NDR form of the packet */
-       c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
+       c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
                                    p->conn->security_state.auth_info);
-       if (!NT_STATUS_IS_OK(c->status)) {
-               goto failed;
-       }
+       if (!composite_is_ok(c)) return c;
 
        p->conn->transport.recv_data = dcerpc_recv_data;
 
+       /*
+        * we allocate a dcerpc_request so we can be in the same
+        * request queue as normal requests
+        */
+       req = talloc_zero(c, struct rpc_request);
+       if (composite_nomem(req, c)) return c;
+
        req->state = RPC_REQUEST_PENDING;
        req->call_id = pkt.call_id;
-       req->async.private = c;
+       req->async.private_data = c;
        req->async.callback = dcerpc_composite_fail;
        req->p = p;
        req->recv_handler = dcerpc_alter_recv_handler;
-
        DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
+       talloc_set_destructor(req, dcerpc_req_dequeue);
 
-       c->status = p->conn->transport.send_request(p->conn, &blob, True);
-       if (!NT_STATUS_IS_OK(c->status)) {
-               goto failed;
-       }
+       c->status = p->conn->transport.send_request(p->conn, &blob, true);
+       if (!composite_is_ok(c)) return c;
 
        event_add_timed(c->event_ctx, req,
                        timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
                        dcerpc_timeout_handler, req);
 
        return c;
-
- failed:
-       composite_error(c, c->status);
-       return c;
 }
 
 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
@@ -1642,10 +1684,10 @@ NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
 /* 
    send a dcerpc alter_context request
 */
-NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
+_PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
                              TALLOC_CTX *mem_ctx,
-                             const struct dcerpc_syntax_id *syntax,
-                             const struct dcerpc_syntax_id *transfer_syntax)
+                             const struct ndr_syntax_id *syntax,
+                             const struct ndr_syntax_id *transfer_syntax)
 {
        struct composite_context *creq;
        creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);