librpc/rpc: correct the chunk_size depending on the signature size
[tprouty/samba.git] / source4 / librpc / rpc / dcerpc.c
index 160b9772f48abc6a9fb3081c8030681da29d479a..28b5cd65a9143a3f398bfc2146103a7739973308 100644 (file)
 #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();
+       gensec_init(global_loadparm);
 
        return NT_STATUS_OK;
 }
@@ -43,7 +45,7 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c);
 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
 {
        if (conn->dead) {
-               conn->free_skipped = True;
+               conn->free_skipped = true;
                return -1;
        }
        dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
@@ -55,7 +57,8 @@ static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
    the event context is optional
 */
 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
-                                                struct event_context *ev)
+                                                struct event_context *ev,
+                                                struct smb_iconv_convenience *ic)
 {
        struct dcerpc_connection *c;
 
@@ -64,20 +67,15 @@ static 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;
@@ -94,7 +92,8 @@ static 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;
 
@@ -103,7 +102,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;
@@ -163,13 +162,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;
 
@@ -192,6 +191,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) {
@@ -202,7 +202,12 @@ 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);
+       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);
+       }
+
+       return NT_STATUS_OK;
 }
 
 /*
@@ -242,6 +247,7 @@ 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) {
@@ -270,11 +276,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:
@@ -327,20 +334,22 @@ 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;
 
        /* 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);
+               return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, c->security_state.auth_info);
        }
 
-       ndr = ndr_push_init_ctx(mem_ctx);
+       ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
        if (!ndr) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -353,10 +362,11 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
                ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
        }
 
-       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 */
@@ -375,8 +385,7 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
                 * GENSEC mech does AEAD signing of the packet
                 * headers */
                c->security_state.auth_info->credentials
-                       = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state, 
-                                                                         payload_length));
+                       = data_blob_talloc(mem_ctx, NULL, sig_size);
                data_blob_clear(&c->security_state.auth_info->credentials);
                break;
 
@@ -398,10 +407,11 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
        }       
 
        /* 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);
@@ -648,14 +658,29 @@ 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;
@@ -716,6 +741,10 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
                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 = p->binding->assoc_group_id;
@@ -729,7 +758,7 @@ 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 (!composite_is_ok(c)) return c;
 
@@ -752,7 +781,7 @@ struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
        talloc_set_destructor(req, dcerpc_req_dequeue);
 
        c->status = p->conn->transport.send_request(p->conn, &blob,
-                                                   True);
+                                                   true);
        if (!composite_is_ok(c)) return c;
 
        event_add_timed(c->event_ctx, req,
@@ -775,35 +804,46 @@ NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
 /* 
    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);
 
+       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;
+       }
+
        /* construct the NDR form of the packet */
-       status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
+       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;
        }
 
        /* send it on its way */
-       status = c->transport.send_request(c, &blob, False);
+       status = p->conn->transport.send_request(p->conn, &blob, false);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       return status;  
+       return NT_STATUS_OK;    
 }
 
 
@@ -933,7 +973,7 @@ req_done:
 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;
@@ -953,13 +993,13 @@ static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
        req->flags = 0;
        req->fault_code = 0;
        req->async_call = async;
-       req->ignore_timeout = False;
+       req->ignore_timeout = false;
        req->async.callback = NULL;
        req->async.private_data = NULL;
        req->recv_handler = NULL;
 
        if (object != NULL) {
-               req->object = talloc_memdup(req, (void *)object, sizeof(*object));
+               req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
                if (req->object == NULL) {
                        talloc_free(req);
                        return NULL;
@@ -1001,7 +1041,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) {
@@ -1025,7 +1066,15 @@ 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.generic_state) {
+               chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
+               sig_size = gensec_sig_size(c->security_state.generic_state,
+                                          p->conn->srv_max_recv_frag);
+               chunk_size -= sig_size;
+               chunk_size -= (chunk_size % 16);
+       }
 
        pkt.ptype = DCERPC_PKT_REQUEST;
        pkt.call_id = req->call_id;
@@ -1044,9 +1093,9 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c)
        /* 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) {
@@ -1054,14 +1103,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);
@@ -1083,7 +1132,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;
 }
@@ -1123,7 +1172,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)
@@ -1155,8 +1204,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) {
@@ -1169,23 +1218,27 @@ 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);
@@ -1195,9 +1248,9 @@ static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
                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;
@@ -1221,10 +1274,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) {
@@ -1232,16 +1285,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);
@@ -1252,23 +1307,27 @@ 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);
@@ -1278,9 +1337,9 @@ static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
                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
@@ -1291,7 +1350,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");
@@ -1299,13 +1358,16 @@ 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,
@@ -1320,11 +1382,12 @@ struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
        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;
        }
@@ -1334,8 +1397,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);
@@ -1390,6 +1454,7 @@ _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
        uint32_t opnum = req->ndr.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 */
@@ -1425,8 +1490,9 @@ _PUBLIC_ 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;
@@ -1465,7 +1531,7 @@ _PUBLIC_ 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 ndr_interface_table *table,
                            uint32_t opnum, 
@@ -1486,12 +1552,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);
 }
 
 
@@ -1545,11 +1614,16 @@ static void dcerpc_alter_recv_handler(struct rpc_request *req,
        /* 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);
@@ -1587,6 +1661,10 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
                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 = p->binding->assoc_group_id;
@@ -1600,7 +1678,7 @@ 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 (!composite_is_ok(c)) return c;
 
@@ -1622,7 +1700,7 @@ struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
        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);
+       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,
@@ -1642,7 +1720,7 @@ 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 ndr_syntax_id *syntax,
                              const struct ndr_syntax_id *transfer_syntax)