More fixes for bug #7146 - Samba miss-parses authenticated RPC packets.
[ira/wip.git] / source3 / rpc_server / srv_pipe.c
index 576bd85745d7bb5da25a68e5a8e1c96327eaa76a..1c10525659386b9ee954d01d9d4cd1a0577e88aa 100644 (file)
  */
 
 #include "includes.h"
-#include "../libcli/auth/libcli_auth.h"
 #include "../librpc/gen_ndr/ndr_schannel.h"
 #include "../libcli/auth/schannel.h"
-#include "../libcli/auth/schannel_proto.h"
+#include "../libcli/auth/spnego.h"
+#include "ntlmssp.h"
 
 extern struct current_user current_user;
 
@@ -84,11 +84,11 @@ static bool create_next_pdu_ntlmssp(pipes_struct *p)
        memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
 
        /* Change the incoming request header to a response. */
-       p->hdr.pkt_type = RPC_RESPONSE;
+       p->hdr.pkt_type = DCERPC_PKT_RESPONSE;
 
        /* Set up rpc header flags. */
        if (p->out_data.data_sent_length == 0) {
-               p->hdr.flags = RPC_FLG_FIRST;
+               p->hdr.flags = DCERPC_PFC_FLAG_FIRST;
        } else {
                p->hdr.flags = 0;
        }
@@ -108,8 +108,15 @@ static bool create_next_pdu_ntlmssp(pipes_struct *p)
                return False;
        }
 
-       data_space_available = RPC_MAX_PDU_FRAG_LEN - RPC_HEADER_LEN
-               - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - NTLMSSP_SIG_SIZE;
+       if (data_len_left % SERVER_NDR_PADDING_SIZE) {
+               ss_padding_len = SERVER_NDR_PADDING_SIZE - (data_len_left % SERVER_NDR_PADDING_SIZE);
+               DEBUG(10,("create_next_pdu_ntlmssp: adding sign/seal padding of %u\n",
+                       ss_padding_len ));
+       }
+
+       data_space_available = RPC_MAX_PDU_FRAG_LEN - RPC_HEADER_LEN -
+               RPC_HDR_RESP_LEN - ss_padding_len - RPC_HDR_AUTH_LEN -
+               NTLMSSP_SIG_SIZE;
 
        /*
         * The amount we send is the minimum of the available
@@ -130,12 +137,7 @@ static bool create_next_pdu_ntlmssp(pipes_struct *p)
         */
 
        if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
-               p->hdr.flags |= RPC_FLG_LAST;
-               if (data_len_left % 8) {
-                       ss_padding_len = 8 - (data_len_left % 8);
-                       DEBUG(10,("create_next_pdu_ntlmssp: adding sign/seal padding of %u\n",
-                               ss_padding_len ));
-               }
+               p->hdr.flags |= DCERPC_PFC_FLAG_LAST;
        }
 
        /*
@@ -179,9 +181,9 @@ static bool create_next_pdu_ntlmssp(pipes_struct *p)
 
        /* Copy the sign/seal padding data. */
        if (ss_padding_len) {
-               char pad[8];
+               char pad[SERVER_NDR_PADDING_SIZE];
 
-               memset(pad, '\0', 8);
+               memset(pad, '\0', SERVER_NDR_PADDING_SIZE);
                if (!prs_copy_data_in(&p->out_data.frag, pad,
                                      ss_padding_len)) {
                        DEBUG(0,("create_next_pdu_ntlmssp: failed to add %u bytes of pad data.\n",
@@ -205,8 +207,9 @@ static bool create_next_pdu_ntlmssp(pipes_struct *p)
        }
 
        init_rpc_hdr_auth(&auth_info, auth_type, auth_level, ss_padding_len, 1 /* context id. */);
-       if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &p->out_data.frag,
-                               0)) {
+
+       if (!smb_io_rpc_hdr_auth("hdr_auth", &auth_info,
+                               &p->out_data.frag, 0)) {
                DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR_AUTH.\n"));
                prs_mem_free(&p->out_data.frag);
                return False;
@@ -302,11 +305,11 @@ static bool create_next_pdu_schannel(pipes_struct *p)
        memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
 
        /* Change the incoming request header to a response. */
-       p->hdr.pkt_type = RPC_RESPONSE;
+       p->hdr.pkt_type = DCERPC_PKT_RESPONSE;
 
        /* Set up rpc header flags. */
        if (p->out_data.data_sent_length == 0) {
-               p->hdr.flags = RPC_FLG_FIRST;
+               p->hdr.flags = DCERPC_PFC_FLAG_FIRST;
        } else {
                p->hdr.flags = 0;
        }
@@ -326,8 +329,14 @@ static bool create_next_pdu_schannel(pipes_struct *p)
                return False;
        }
 
+       if (data_len_left % SERVER_NDR_PADDING_SIZE) {
+               ss_padding_len = SERVER_NDR_PADDING_SIZE - (data_len_left % SERVER_NDR_PADDING_SIZE);
+               DEBUG(10,("create_next_pdu_schannel: adding sign/seal padding of %u\n",
+                       ss_padding_len ));
+       }
+
        data_space_available = RPC_MAX_PDU_FRAG_LEN - RPC_HEADER_LEN
-               - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN
+               - RPC_HDR_RESP_LEN - ss_padding_len - RPC_HDR_AUTH_LEN
                - RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN;
 
        /*
@@ -349,12 +358,7 @@ static bool create_next_pdu_schannel(pipes_struct *p)
         */
 
        if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
-               p->hdr.flags |= RPC_FLG_LAST;
-               if (data_len_left % 8) {
-                       ss_padding_len = 8 - (data_len_left % 8);
-                       DEBUG(10,("create_next_pdu_schannel: adding sign/seal padding of %u\n",
-                               ss_padding_len ));
-               }
+               p->hdr.flags |= DCERPC_PFC_FLAG_LAST;
        }
 
        p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + ss_padding_len +
@@ -395,8 +399,8 @@ static bool create_next_pdu_schannel(pipes_struct *p)
 
        /* Copy the sign/seal padding data. */
        if (ss_padding_len) {
-               char pad[8];
-               memset(pad, '\0', 8);
+               char pad[SERVER_NDR_PADDING_SIZE];
+               memset(pad, '\0', SERVER_NDR_PADDING_SIZE);
                if (!prs_copy_data_in(&p->out_data.frag, pad,
                                      ss_padding_len)) {
                        DEBUG(0,("create_next_pdu_schannel: failed to add %u bytes of pad data.\n", (unsigned int)ss_padding_len));
@@ -410,9 +414,8 @@ static bool create_next_pdu_schannel(pipes_struct *p)
                 * Schannel processing.
                 */
                RPC_HDR_AUTH auth_info;
-               struct NL_AUTH_SIGNATURE verf;
                DATA_BLOB blob;
-               enum ndr_err_code ndr_err;
+               uint8_t *data;
 
                /* Check it's the type of reply we were expecting to decode */
 
@@ -422,27 +425,31 @@ static bool create_next_pdu_schannel(pipes_struct *p)
                                        DCERPC_AUTH_LEVEL_PRIVACY : DCERPC_AUTH_LEVEL_INTEGRITY,
                                ss_padding_len, 1);
 
-               if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info,
+               if (!smb_io_rpc_hdr_auth("hdr_auth", &auth_info,
                                        &p->out_data.frag, 0)) {
                        DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR_AUTH.\n"));
                        prs_mem_free(&p->out_data.frag);
                        return False;
                }
 
+               data = (uint8_t *)prs_data_p(&p->out_data.frag) + data_pos;
+
                switch (p->auth.auth_level) {
                case DCERPC_AUTH_LEVEL_PRIVACY:
-                       status = schannel_seal_packet(p->auth.a_u.schannel_auth,
-                                                     talloc_tos(),
-                                                     (uint8_t *)prs_data_p(&p->out_data.frag) + data_pos,
-                                                     data_len + ss_padding_len,
-                                                     &blob);
+                       status = netsec_outgoing_packet(p->auth.a_u.schannel_auth,
+                                                       talloc_tos(),
+                                                       true,
+                                                       data,
+                                                       data_len + ss_padding_len,
+                                                       &blob);
                        break;
                case DCERPC_AUTH_LEVEL_INTEGRITY:
-                       status = schannel_sign_packet(p->auth.a_u.schannel_auth,
-                                                     talloc_tos(),
-                                                     (uint8_t *)prs_data_p(&p->out_data.frag) + data_pos,
-                                                     data_len + ss_padding_len,
-                                                     &blob);
+                       status = netsec_outgoing_packet(p->auth.a_u.schannel_auth,
+                                                       talloc_tos(),
+                                                       false,
+                                                       data,
+                                                       data_len + ss_padding_len,
+                                                       &blob);
                        break;
                default:
                        status = NT_STATUS_INTERNAL_ERROR;
@@ -458,18 +465,10 @@ static bool create_next_pdu_schannel(pipes_struct *p)
 
                /* Finally marshall the blob. */
 
-#if 0
-               ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), NULL, &verf,
-                                      (ndr_push_flags_fn_t)ndr_push_NL_AUTH_SIGNATURE);
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                       prs_mem_free(&p->out_data.frag);
-                       return false;
-               }
-
                if (DEBUGLEVEL >= 10) {
-                       NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &verf);
+                       dump_NL_AUTH_SIGNATURE(talloc_tos(), &blob);
                }
-#endif
+
                if (!prs_copy_data_in(&p->out_data.frag, (const char *)blob.data, blob.length)) {
                        prs_mem_free(&p->out_data.frag);
                        return false;
@@ -511,11 +510,11 @@ static bool create_next_pdu_noauth(pipes_struct *p)
        memset((char *)&hdr_resp, '\0', sizeof(hdr_resp));
 
        /* Change the incoming request header to a response. */
-       p->hdr.pkt_type = RPC_RESPONSE;
+       p->hdr.pkt_type = DCERPC_PKT_RESPONSE;
 
        /* Set up rpc header flags. */
        if (p->out_data.data_sent_length == 0) {
-               p->hdr.flags = RPC_FLG_FIRST;
+               p->hdr.flags = DCERPC_PFC_FLAG_FIRST;
        } else {
                p->hdr.flags = 0;
        }
@@ -557,7 +556,7 @@ static bool create_next_pdu_noauth(pipes_struct *p)
         */
 
        if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) {
-               p->hdr.flags |= RPC_FLG_LAST;
+               p->hdr.flags |= DCERPC_PFC_FLAG_LAST;
        }
 
        /*
@@ -651,7 +650,7 @@ static bool pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob)
        bool ret;
 
        DEBUG(5,("pipe_ntlmssp_verify_final: pipe %s checking user details\n",
-                get_pipe_name_from_iface(&p->syntax)));
+                get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
 
        ZERO_STRUCT(reply);
 
@@ -675,7 +674,8 @@ static bool pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob)
                if (!(a->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
                        DEBUG(0,("pipe_ntlmssp_verify_final: pipe %s : packet integrity requested "
                                "but client declined signing.\n",
-                               get_pipe_name_from_iface(&p->syntax)));
+                                get_pipe_name_from_syntax(talloc_tos(),
+                                                          &p->syntax)));
                        return False;
                }
        }
@@ -683,7 +683,8 @@ static bool pipe_ntlmssp_verify_final(pipes_struct *p, DATA_BLOB *p_resp_blob)
                if (!(a->ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
                        DEBUG(0,("pipe_ntlmssp_verify_final: pipe %s : packet privacy requested "
                                "but client declined sealing.\n",
-                               get_pipe_name_from_iface(&p->syntax)));
+                                get_pipe_name_from_syntax(talloc_tos(),
+                                                          &p->syntax)));
                        return False;
                }
        }
@@ -749,12 +750,13 @@ bool api_pipe_bind_auth3(pipes_struct *p, prs_struct *rpc_in_p)
        RPC_HDR_AUTH auth_info;
        uint32 pad = 0;
        DATA_BLOB blob;
+       uint32_t auth_len = p->hdr.auth_len;
 
        ZERO_STRUCT(blob);
 
        DEBUG(5,("api_pipe_bind_auth3: decode request. %d\n", __LINE__));
 
-       if (p->hdr.auth_len == 0) {
+       if (auth_len == 0) {
                DEBUG(0,("api_pipe_bind_auth3: No auth field sent !\n"));
                goto err;
        }
@@ -765,15 +767,45 @@ bool api_pipe_bind_auth3(pipes_struct *p, prs_struct *rpc_in_p)
                goto err;
        }
 
+       /* Ensure there's enough data for an authenticated request. */
+       if (RPC_HEADER_LEN + RPC_HDR_AUTH_LEN + auth_len >
+                               p->hdr.frag_len) {
+                       DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len "
+                               "%u is too large.\n",
+                        (unsigned int)auth_len ));
+               goto err;
+       }
+
        /*
         * Decode the authentication verifier response.
         */
 
-       if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
-               DEBUG(0,("api_pipe_bind_auth3: unmarshall of RPC_HDR_AUTH failed.\n"));
+       /* Pull the auth header and the following data into a blob. */
+       /* NB. The offset of the auth_header is relative to the *end*
+        * of the packet, not the start. Also, the length of the
+        * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN,
+        * as the RPC header isn't included in rpc_in_p. */
+       if(!prs_set_offset(rpc_in_p,
+                       p->hdr.frag_len - RPC_HEADER_LEN -
+                       RPC_HDR_AUTH_LEN - auth_len)) {
+               DEBUG(0,("api_pipe_bind_auth3: cannot move "
+                       "offset to %u.\n",
+                       (unsigned int)(p->hdr.frag_len -
+                               RPC_HDR_AUTH_LEN - auth_len) ));
                goto err;
        }
 
+       if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in_p, 0)) {
+               DEBUG(0,("api_pipe_bind_auth3: failed to "
+                       "unmarshall RPC_HDR_AUTH.\n"));
+               goto err;
+       }
+
+       /* We must NEVER look at auth_info->auth_pad_len here,
+        * as old Samba client code gets it wrong and sends it
+        * as zero. JRA.
+        */
+
        if (auth_info.auth_type != DCERPC_AUTH_TYPE_NTLMSSP) {
                DEBUG(0,("api_pipe_bind_auth3: incorrect auth type (%u).\n",
                        (unsigned int)auth_info.auth_type ));
@@ -836,7 +868,7 @@ static bool setup_bind_nak(pipes_struct *p)
         * Initialize a bind_nak header.
         */
 
-       init_rpc_hdr(&nak_hdr, RPC_BINDNACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+       init_rpc_hdr(&nak_hdr, DCERPC_PKT_BIND_NAK, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST,
                p->hdr.call_id, RPC_HEADER_LEN + sizeof(uint16), 0);
 
        /*
@@ -896,7 +928,7 @@ bool setup_fault_pdu(pipes_struct *p, NTSTATUS status)
         * Initialize a fault header.
         */
 
-       init_rpc_hdr(&fault_hdr, RPC_FAULT, RPC_FLG_FIRST | RPC_FLG_LAST | RPC_FLG_NOCALL,
+       init_rpc_hdr(&fault_hdr, DCERPC_PKT_FAULT, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
             p->hdr.call_id, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_FAULT_LEN, 0);
 
        /*
@@ -963,7 +995,7 @@ bool setup_cancel_ack_reply(pipes_struct *p, prs_struct *rpc_in_p)
         * Initialize a cancel_ack header.
         */
 
-       init_rpc_hdr(&ack_reply_hdr, RPC_CANCEL_ACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+       init_rpc_hdr(&ack_reply_hdr, DCERPC_PKT_CANCEL_ACK, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST,
                        p->hdr.call_id, RPC_HEADER_LEN, 0);
 
        /*
@@ -999,7 +1031,7 @@ static bool check_bind_req(struct pipes_struct *p,
        struct pipe_rpc_fns *context_fns;
 
        DEBUG(3,("check_bind_req for %s\n",
-                get_pipe_name_from_iface(&p->syntax)));
+                get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
 
        /* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */
 
@@ -1096,6 +1128,7 @@ bool is_known_pipename(const char *cli_filename, struct ndr_syntax_id *syntax)
 {
        const char *pipename = cli_filename;
        int i;
+       NTSTATUS status;
 
        if (strnequal(pipename, "\\PIPE\\", 6)) {
                pipename += 5;
@@ -1117,7 +1150,27 @@ bool is_known_pipename(const char *cli_filename, struct ndr_syntax_id *syntax)
                }
        }
 
-       DEBUG(10, ("is_known_pipename: %s unknown\n", cli_filename));
+       status = smb_probe_module("rpc", pipename);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("is_known_pipename: %s unknown\n", cli_filename));
+               return false;
+       }
+       DEBUG(10, ("is_known_pipename: %s loaded dynamically\n", pipename));
+
+       /*
+        * Scan the list again for the interface id
+        */
+
+       for (i=0; i<rpc_lookup_size; i++) {
+               if (strequal(pipename, rpc_lookup[i].pipe.clnt)) {
+                       *syntax = rpc_lookup[i].rpc_interface;
+                       return true;
+               }
+       }
+
+       DEBUG(10, ("is_known_pipename: pipe %s did not register itself!\n",
+                  pipename));
+
        return false;
 }
 
@@ -1136,6 +1189,7 @@ static bool pipe_spnego_auth_bind_kerberos(pipes_struct *p, prs_struct *rpc_in_p
 *******************************************************************/
 
 static bool pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_p,
+                                       uint32_t ss_padding_len,
                                        RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
 {
        DATA_BLOB blob;
@@ -1227,8 +1281,11 @@ static bool pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_
                                        OID_NTLMSSP);
        }
 
+       /* auth_pad_len will be handled by the caller */
+
        /* Copy the blob into the pout_auth parse struct */
-       init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SPNEGO, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+       init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SPNEGO,
+                       pauth_info->auth_level, ss_padding_len, 1);
        if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
                DEBUG(0,("pipe_spnego_auth_bind_negotiate: marshalling of RPC_HDR_AUTH failed.\n"));
                goto err;
@@ -1268,7 +1325,8 @@ static bool pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_
 *******************************************************************/
 
 static bool pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p,
-                                       RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
+                               uint32_t ss_padding_len,
+                               RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
 {
        RPC_HDR_AUTH auth_info;
        DATA_BLOB spnego_blob;
@@ -1325,8 +1383,11 @@ static bool pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p
        /* Generate the spnego "accept completed" blob - no incoming data. */
        response = spnego_gen_auth_response(&auth_reply, NT_STATUS_OK, OID_NTLMSSP);
 
+       /* FIXME - add auth_pad_len here ! */
+
        /* Copy the blob into the pout_auth parse struct */
-       init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SPNEGO, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+       init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SPNEGO,
+                       pauth_info->auth_level, ss_padding_len, 1);
        if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
                DEBUG(0,("pipe_spnego_auth_bind_continue: marshalling of RPC_HDR_AUTH failed.\n"));
                goto err;
@@ -1362,6 +1423,7 @@ static bool pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p
 *******************************************************************/
 
 static bool pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
+                                       uint32_t ss_padding_len,
                                        RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
 {
        RPC_HDR_AUTH auth_info;
@@ -1448,7 +1510,8 @@ static bool pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
                return false;
        }
 
-       init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SCHANNEL, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+       init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SCHANNEL,
+                       pauth_info->auth_level, ss_padding_len, 1);
        if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
                DEBUG(0,("pipe_schannel_auth_bind: marshalling of RPC_HDR_AUTH failed.\n"));
                return False;
@@ -1494,6 +1557,7 @@ static bool pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
 *******************************************************************/
 
 static bool pipe_ntlmssp_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
+                                       uint32_t ss_padding_len,
                                        RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth)
 {
        RPC_HDR_AUTH auth_info;
@@ -1537,7 +1601,8 @@ static bool pipe_ntlmssp_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
        data_blob_free(&blob);
 
        /* Copy the blob into the pout_auth parse struct */
-       init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_NTLMSSP, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
+       init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_NTLMSSP,
+                       pauth_info->auth_level, ss_padding_len, 1);
        if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
                DEBUG(0,("pipe_ntlmssp_auth_bind: marshalling of RPC_HDR_AUTH failed.\n"));
                goto err;
@@ -1557,7 +1622,7 @@ static bool pipe_ntlmssp_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
 
        DEBUG(10,("pipe_ntlmssp_auth_bind: NTLMSSP auth started\n"));
 
-       /* We can't set pipe_bound True yet - we need an RPC_AUTH3 response packet... */
+       /* We can't set pipe_bound True yet - we need an DCERPC_PKT_AUTH3 response packet... */
        return True;
 
   err:
@@ -1586,11 +1651,13 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
        int i = 0;
        int auth_len = 0;
        unsigned int auth_type = DCERPC_AUTH_TYPE_NONE;
+       uint32_t ss_padding_len = 0;
 
        /* No rebinds on a bound pipe - use alter context. */
        if (p->pipe_bound) {
                DEBUG(2,("api_pipe_bind_req: rejecting bind request on bound "
-                        "pipe %s.\n", get_pipe_name_from_iface(&p->syntax)));
+                        "pipe %s.\n",
+                        get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
                return setup_bind_nak(p);
        }
 
@@ -1655,12 +1722,15 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
                NTSTATUS status;
 
                status = smb_probe_module(
-                       "rpc", get_pipe_name_from_iface(
+                       "rpc", get_pipe_name_from_syntax(
+                               talloc_tos(),
                                &hdr_rb.rpc_context[0].abstract));
 
                if (NT_STATUS_IS_ERR(status)) {
                        DEBUG(3,("api_pipe_bind_req: Unknown pipe name %s in bind request.\n",
-                                get_pipe_name_from_iface(&hdr_rb.rpc_context[0].abstract)));
+                                get_pipe_name_from_syntax(
+                                       talloc_tos(),
+                                       &hdr_rb.rpc_context[0].abstract)));
                        prs_mem_free(&p->out_data.frag);
                        prs_mem_free(&out_hdr_ba);
                        prs_mem_free(&out_auth);
@@ -1670,7 +1740,8 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
 
                 for (i = 0; i < rpc_lookup_size; i++) {
                        if (strequal(rpc_lookup[i].pipe.clnt,
-                                   get_pipe_name_from_iface(&p->syntax))) {
+                                   get_pipe_name_from_syntax(talloc_tos(),
+                                                             &p->syntax))) {
                                DEBUG(3, ("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
                                          rpc_lookup[i].pipe.clnt, rpc_lookup[i].pipe.srv));
                                break;
@@ -1680,8 +1751,10 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
                if (i == rpc_lookup_size) {
                        DEBUG(0, ("module %s doesn't provide functions for "
                                  "pipe %s!\n",
-                                 get_pipe_name_from_iface(&p->syntax),
-                                 get_pipe_name_from_iface(&p->syntax)));
+                                 get_pipe_name_from_syntax(talloc_tos(),
+                                                           &p->syntax),
+                                 get_pipe_name_from_syntax(talloc_tos(),
+                                                           &p->syntax)));
                        goto err_exit;
                }
        }
@@ -1692,6 +1765,45 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
 
        DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__));
 
+       assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0;
+
+       /*
+        * Create the bind response struct.
+        */
+
+       /* If the requested abstract synt uuid doesn't match our client pipe,
+               reject the bind_ack & set the transfer interface synt to all 0's,
+               ver 0 (observed when NT5 attempts to bind to abstract interfaces
+               unknown to NT4)
+               Needed when adding entries to a DACL from NT5 - SK */
+
+       if(check_bind_req(p, &hdr_rb.rpc_context[0].abstract, &hdr_rb.rpc_context[0].transfer[0],
+                               hdr_rb.rpc_context[0].context_id )) {
+               init_rpc_hdr_ba(&hdr_ba,
+                       RPC_MAX_PDU_FRAG_LEN,
+                       RPC_MAX_PDU_FRAG_LEN,
+                       assoc_gid,
+                       ack_pipe_name,
+                       0x1, 0x0, 0x0,
+                       &hdr_rb.rpc_context[0].transfer[0]);
+       } else {
+               /* Rejection reason: abstract syntax not supported */
+               init_rpc_hdr_ba(&hdr_ba, RPC_MAX_PDU_FRAG_LEN,
+                                       RPC_MAX_PDU_FRAG_LEN, assoc_gid,
+                                       ack_pipe_name, 0x1, 0x2, 0x1,
+                                       &null_ndr_syntax_id);
+               p->pipe_bound = False;
+       }
+
+       /*
+        * and marshall it.
+        */
+
+       if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) {
+               DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n"));
+               goto err_exit;
+       }
+
        /*
         * Check if this is an authenticated bind request.
         */
@@ -1701,6 +1813,40 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
                 * Decode the authentication verifier.
                 */
 
+               /* Work out any padding needed before the auth footer. */
+               if ((RPC_HEADER_LEN + prs_offset(&out_hdr_ba)) % SERVER_NDR_PADDING_SIZE) {
+                       ss_padding_len = SERVER_NDR_PADDING_SIZE -
+                               ((RPC_HEADER_LEN + prs_offset(&out_hdr_ba)) % SERVER_NDR_PADDING_SIZE);
+                       DEBUG(10,("api_pipe_bind_req: auth pad_len = %u\n",
+                               (unsigned int)ss_padding_len ));
+               }
+
+               /* Quick length check. Won't catch a bad auth footer,
+                * prevents overrun. */
+
+               if (p->hdr.frag_len < RPC_HEADER_LEN + RPC_HDR_AUTH_LEN + p->hdr.auth_len) {
+                       DEBUG(0,("api_pipe_bind_req: auth_len (%u) "
+                               "too long for fragment %u.\n",
+                               (unsigned int)p->hdr.auth_len,
+                               (unsigned int)p->hdr.frag_len ));
+                       goto err_exit;
+               }
+
+               /* Pull the auth header and the following data into a blob. */
+               /* NB. The offset of the auth_header is relative to the *end*
+                * of the packet, not the start. Also, the length of the
+                * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN,
+                * as the RPC header isn't included in rpc_in_p. */
+               if(!prs_set_offset(rpc_in_p,
+                               p->hdr.frag_len - RPC_HEADER_LEN -
+                               RPC_HDR_AUTH_LEN - p->hdr.auth_len)) {
+                       DEBUG(0,("api_pipe_bind_req: cannot move "
+                               "offset to %u.\n",
+                               (unsigned int)(p->hdr.frag_len -
+                               RPC_HDR_AUTH_LEN - p->hdr.auth_len) ));
+                       goto err_exit;
+               }
+
                if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
                        DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n"));
                        goto err_exit;
@@ -1725,24 +1871,25 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
                ZERO_STRUCT(auth_info);
        }
 
-       assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0;
-
        switch(auth_type) {
                case DCERPC_AUTH_TYPE_NTLMSSP:
-                       if (!pipe_ntlmssp_auth_bind(p, rpc_in_p, &auth_info, &out_auth)) {
+                       if (!pipe_ntlmssp_auth_bind(p, rpc_in_p,
+                                       ss_padding_len, &auth_info, &out_auth)) {
                                goto err_exit;
                        }
                        assoc_gid = 0x7a77;
                        break;
 
                case DCERPC_AUTH_TYPE_SCHANNEL:
-                       if (!pipe_schannel_auth_bind(p, rpc_in_p, &auth_info, &out_auth)) {
+                       if (!pipe_schannel_auth_bind(p, rpc_in_p,
+                                       ss_padding_len, &auth_info, &out_auth)) {
                                goto err_exit;
                        }
                        break;
 
                case DCERPC_AUTH_TYPE_SPNEGO:
-                       if (!pipe_spnego_auth_bind_negotiate(p, rpc_in_p, &auth_info, &out_auth)) {
+                       if (!pipe_spnego_auth_bind_negotiate(p, rpc_in_p,
+                                       ss_padding_len, &auth_info, &out_auth)) {
                                goto err_exit;
                        }
                        break;
@@ -1756,50 +1903,13 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
                        p->pipe_bound = True;
                        /* The session key was initialized from the SMB
                         * session in make_internal_rpc_pipe_p */
+                       ss_padding_len = 0;
                        break;
 
                default:
                        DEBUG(0,("api_pipe_bind_req: unknown auth type %x requested.\n", auth_type ));
                        goto err_exit;
        }
-
-       /*
-        * Create the bind response struct.
-        */
-
-       /* If the requested abstract synt uuid doesn't match our client pipe,
-               reject the bind_ack & set the transfer interface synt to all 0's,
-               ver 0 (observed when NT5 attempts to bind to abstract interfaces
-               unknown to NT4)
-               Needed when adding entries to a DACL from NT5 - SK */
-
-       if(check_bind_req(p, &hdr_rb.rpc_context[0].abstract, &hdr_rb.rpc_context[0].transfer[0],
-                               hdr_rb.rpc_context[0].context_id )) {
-               init_rpc_hdr_ba(&hdr_ba,
-                       RPC_MAX_PDU_FRAG_LEN,
-                       RPC_MAX_PDU_FRAG_LEN,
-                       assoc_gid,
-                       ack_pipe_name,
-                       0x1, 0x0, 0x0,
-                       &hdr_rb.rpc_context[0].transfer[0]);
-       } else {
-               /* Rejection reason: abstract syntax not supported */
-               init_rpc_hdr_ba(&hdr_ba, RPC_MAX_PDU_FRAG_LEN,
-                                       RPC_MAX_PDU_FRAG_LEN, assoc_gid,
-                                       ack_pipe_name, 0x1, 0x2, 0x1,
-                                       &null_ndr_syntax_id);
-               p->pipe_bound = False;
-       }
-
-       /*
-        * and marshall it.
-        */
-
-       if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) {
-               DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n"));
-               goto err_exit;
-       }
-
        /*
         * Create the header, now we know the length.
         */
@@ -1808,9 +1918,10 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
                auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
        }
 
-       init_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+       init_rpc_hdr(&p->hdr, DCERPC_PKT_BIND_ACK, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST,
                        p->hdr.call_id,
-                       RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth),
+                       RPC_HEADER_LEN + prs_offset(&out_hdr_ba) +
+                               ss_padding_len + prs_offset(&out_auth),
                        auth_len);
 
        /*
@@ -1831,9 +1942,23 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
                goto err_exit;
        }
 
-       if (auth_len && !prs_append_prs_data( &p->out_data.frag, &out_auth)) {
-               DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n"));
-               goto err_exit;
+       if (auth_len) {
+               if (ss_padding_len) {
+                       char pad[SERVER_NDR_PADDING_SIZE];
+                       memset(pad, '\0', SERVER_NDR_PADDING_SIZE);
+                       if (!prs_copy_data_in(&p->out_data.frag, pad,
+                                       ss_padding_len)) {
+                               DEBUG(0,("api_pipe_bind_req: failed to add %u "
+                                       "bytes of pad data.\n",
+                                       (unsigned int)ss_padding_len));
+                               goto err_exit;
+                       }
+               }
+
+               if (!prs_append_prs_data( &p->out_data.frag, &out_auth)) {
+                       DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n"));
+                       goto err_exit;
+               }
        }
 
        /*
@@ -1871,6 +1996,7 @@ bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p)
        prs_struct out_hdr_ba;
        prs_struct out_auth;
        int auth_len = 0;
+       uint32_t ss_padding_len = 0;
 
        prs_init_empty(&p->out_data.frag, p->mem_ctx, MARSHALL);
 
@@ -1916,39 +2042,6 @@ bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p)
 
        DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__));
 
-       /*
-        * Check if this is an authenticated alter context request.
-        */
-
-       if (p->hdr.auth_len != 0) {
-               /* 
-                * Decode the authentication verifier.
-                */
-
-               if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
-                       DEBUG(0,("api_pipe_alter_context: unable to unmarshall RPC_HDR_AUTH struct.\n"));
-                       goto err_exit;
-               }
-
-               /*
-                * Currently only the SPNEGO auth type uses the alter ctx
-                * response in place of the NTLMSSP auth3 type.
-                */
-
-               if (auth_info.auth_type == DCERPC_AUTH_TYPE_SPNEGO) {
-                       /* We can only finish if the pipe is unbound. */
-                       if (!p->pipe_bound) {
-                               if (!pipe_spnego_auth_bind_continue(p, rpc_in_p, &auth_info, &out_auth)) {
-                                       goto err_exit;
-                               }
-                       } else {
-                               goto err_exit;
-                       }
-               }
-       } else {
-               ZERO_STRUCT(auth_info);
-       }
-
        assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0;
 
        /*
@@ -1988,6 +2081,74 @@ bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p)
                goto err_exit;
        }
 
+
+       /*
+        * Check if this is an authenticated alter context request.
+        */
+
+       if (p->hdr.auth_len != 0) {
+               /* 
+                * Decode the authentication verifier.
+                */
+
+               /* Work out any padding needed before the auth footer. */
+               if ((RPC_HEADER_LEN + prs_offset(&out_hdr_ba)) % SERVER_NDR_PADDING_SIZE) {
+                       ss_padding_len = SERVER_NDR_PADDING_SIZE -
+                               ((RPC_HEADER_LEN + prs_offset(&out_hdr_ba)) % SERVER_NDR_PADDING_SIZE);
+                       DEBUG(10,("api_pipe_alter_context: auth pad_len = %u\n",
+                               (unsigned int)ss_padding_len ));
+               }
+
+               /* Quick length check. Won't catch a bad auth footer,
+                * prevents overrun. */
+
+               if (p->hdr.frag_len < RPC_HEADER_LEN + RPC_HDR_AUTH_LEN + p->hdr.auth_len) {
+                       DEBUG(0,("api_pipe_alter_context: auth_len (%u) "
+                               "too long for fragment %u.\n",
+                               (unsigned int)p->hdr.auth_len,
+                               (unsigned int)p->hdr.frag_len ));
+                       goto err_exit;
+               }
+
+               /* Pull the auth header and the following data into a blob. */
+               /* NB. The offset of the auth_header is relative to the *end*
+                * of the packet, not the start. Also, the length of the
+                * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN,
+                * as the RPC header isn't included in rpc_in_p. */
+               if(!prs_set_offset(rpc_in_p,
+                               p->hdr.frag_len - RPC_HEADER_LEN -
+                               RPC_HDR_AUTH_LEN - p->hdr.auth_len)) {
+                       DEBUG(0,("api_alter_context: cannot move "
+                               "offset to %u.\n",
+                               (unsigned int)(p->hdr.frag_len -
+                               RPC_HDR_AUTH_LEN - p->hdr.auth_len) ));
+                       goto err_exit;
+               }
+
+               if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) {
+                       DEBUG(0,("api_pipe_alter_context: unable to unmarshall RPC_HDR_AUTH struct.\n"));
+                       goto err_exit;
+               }
+
+               /*
+                * Currently only the SPNEGO auth type uses the alter ctx
+                * response in place of the NTLMSSP auth3 type.
+                */
+
+               if (auth_info.auth_type == DCERPC_AUTH_TYPE_SPNEGO) {
+                       /* We can only finish if the pipe is unbound. */
+                       if (!p->pipe_bound) {
+                               if (!pipe_spnego_auth_bind_continue(p, rpc_in_p,
+                                               ss_padding_len, &auth_info, &out_auth)) {
+                                       goto err_exit;
+                               }
+                       } else {
+                               goto err_exit;
+                       }
+               }
+       } else {
+               ZERO_STRUCT(auth_info);
+       }
        /*
         * Create the header, now we know the length.
         */
@@ -1996,7 +2157,7 @@ bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p)
                auth_len = prs_offset(&out_auth) - RPC_HDR_AUTH_LEN;
        }
 
-       init_rpc_hdr(&p->hdr, RPC_ALTCONTRESP, RPC_FLG_FIRST | RPC_FLG_LAST,
+       init_rpc_hdr(&p->hdr, DCERPC_PKT_ALTER_RESP, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST,
                        p->hdr.call_id,
                        RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth),
                        auth_len);
@@ -2019,9 +2180,23 @@ bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p)
                goto err_exit;
        }
 
-       if (auth_len && !prs_append_prs_data(&p->out_data.frag, &out_auth)) {
-               DEBUG(0,("api_pipe_alter_context: append of auth info failed.\n"));
-               goto err_exit;
+       if (auth_len) {
+               if (ss_padding_len) {
+                       char pad[SERVER_NDR_PADDING_SIZE];
+                       memset(pad, '\0', SERVER_NDR_PADDING_SIZE);
+                       if (!prs_copy_data_in(&p->out_data.frag, pad,
+                                       ss_padding_len)) {
+                               DEBUG(0,("api_pipe_alter_context: failed to add %u "
+                                       "bytes of pad data.\n",
+                                       (unsigned int)ss_padding_len));
+                               goto err_exit;
+                       }
+               }
+
+               if (!prs_append_prs_data( &p->out_data.frag, &out_auth)) {
+                       DEBUG(0,("api_pipe_alter_context: append of auth info failed.\n"));
+                       goto err_exit;
+               }
        }
 
        /*
@@ -2073,8 +2248,8 @@ bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in,
        }
 
        /* Ensure there's enough data for an authenticated request. */
-       if ((auth_len > RPC_MAX_SIGN_SIZE) ||
-                       (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN + auth_len > p->hdr.frag_len)) {
+       if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN
+                       + auth_len > p->hdr.frag_len) {
                DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len %u is too large.\n",
                        (unsigned int)auth_len ));
                *pstatus = NT_STATUS_INVALID_PARAMETER;
@@ -2083,9 +2258,10 @@ bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in,
 
        /*
         * We need the full packet data + length (minus auth stuff) as well as the packet data + length
-        * after the RPC header. 
+        * after the RPC header.
         * We need to pass in the full packet (minus auth len) to the NTLMSSP sign and check seal
         * functions as NTLMv2 checks the rpc headers also.
+        * Both of these values include any auth_pad_len bytes.
         */
 
        data = (unsigned char *)(prs_data_p(rpc_in) + RPC_HDR_REQ_LEN);
@@ -2095,15 +2271,36 @@ bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in,
        full_packet_data_len = p->hdr.frag_len - auth_len;
 
        /* Pull the auth header and the following data into a blob. */
-       if(!prs_set_offset(rpc_in, RPC_HDR_REQ_LEN + data_len)) {
-               DEBUG(0,("api_pipe_ntlmssp_auth_process: cannot move offset to %u.\n",
-                       (unsigned int)RPC_HDR_REQ_LEN + (unsigned int)data_len ));
+       /* NB. The offset of the auth_header is relative to the *end*
+        * of the packet, not the start. Also, the length of the
+        * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN,
+        * as the RPC header isn't included in rpc_in_p. */
+       if(!prs_set_offset(rpc_in,
+                       p->hdr.frag_len - RPC_HEADER_LEN -
+                       RPC_HDR_AUTH_LEN - auth_len)) {
+               DEBUG(0,("api_pipe_ntlmssp_auth_process: cannot move "
+                       "offset to %u.\n",
+                       (unsigned int)(p->hdr.frag_len -
+                               RPC_HDR_AUTH_LEN - auth_len) ));
                *pstatus = NT_STATUS_INVALID_PARAMETER;
                return False;
        }
 
        if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) {
-               DEBUG(0,("api_pipe_ntlmssp_auth_process: failed to unmarshall RPC_HDR_AUTH.\n"));
+               DEBUG(0,("api_pipe_ntlmssp_auth_process: failed to "
+                       "unmarshall RPC_HDR_AUTH.\n"));
+               *pstatus = NT_STATUS_INVALID_PARAMETER;
+               return False;
+       }
+
+       /* Ensure auth_pad_len fits into the packet. */
+       if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + auth_info.auth_pad_len +
+                       RPC_HDR_AUTH_LEN + auth_len > p->hdr.frag_len) {
+               DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_info.auth_pad_len "
+                       "too large (%u), auth_len (%u), frag_len = (%u).\n",
+                       (unsigned int)auth_info.auth_pad_len,
+                       (unsigned int)auth_len,
+                       (unsigned int)p->hdr.frag_len ));
                *pstatus = NT_STATUS_INVALID_PARAMETER;
                return False;
        }
@@ -2170,10 +2367,9 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss
        uint32 auth_len;
        uint32 save_offset = prs_offset(rpc_in);
        RPC_HDR_AUTH auth_info;
-       struct NL_AUTH_SIGNATURE schannel_chk;
-       enum ndr_err_code ndr_err;
        DATA_BLOB blob;
        NTSTATUS status;
+       uint8_t *data;
 
        auth_len = p->hdr.auth_len;
 
@@ -2189,7 +2385,7 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss
        /*
         * The following is that length of the data we must verify or unseal.
         * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN
-        * preceeding the auth_data.
+        * preceeding the auth_data, but does include the auth_pad_len bytes.
         */
 
        if (p->hdr.frag_len < RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN + auth_len) {
@@ -2204,14 +2400,35 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss
 
        DEBUG(5,("data %d auth %d\n", data_len, auth_len));
 
-       if(!prs_set_offset(rpc_in, RPC_HDR_REQ_LEN + data_len)) {
-               DEBUG(0,("cannot move offset to %u.\n",
-                        (unsigned int)RPC_HDR_REQ_LEN + data_len ));
+       /* Pull the auth header and the following data into a blob. */
+       /* NB. The offset of the auth_header is relative to the *end*
+        * of the packet, not the start. Also, the length of the
+        * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN,
+        * as the RPC header isn't included in rpc_in_p. */
+       if(!prs_set_offset(rpc_in,
+                       p->hdr.frag_len - RPC_HEADER_LEN -
+                       RPC_HDR_AUTH_LEN - auth_len)) {
+               DEBUG(0,("api_pipe_schannel_process: cannot move "
+                       "offset to %u.\n",
+                       (unsigned int)(p->hdr.frag_len -
+                               RPC_HDR_AUTH_LEN - auth_len) ));
                return False;
        }
 
        if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) {
-               DEBUG(0,("failed to unmarshall RPC_HDR_AUTH.\n"));
+               DEBUG(0,("api_pipe_schannel_process: failed to "
+                       "unmarshall RPC_HDR_AUTH.\n"));
+               return False;
+       }
+
+       /* Ensure auth_pad_len fits into the packet. */
+       if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + auth_info.auth_pad_len +
+                       RPC_HDR_AUTH_LEN + auth_len > p->hdr.frag_len) {
+               DEBUG(0,("api_pipe_schannel_process: auth_info.auth_pad_len "
+                       "too large (%u), auth_len (%u), frag_len = (%u).\n",
+                       (unsigned int)auth_info.auth_pad_len,
+                       (unsigned int)auth_len,
+                       (unsigned int)p->hdr.frag_len ));
                return False;
        }
 
@@ -2223,32 +2440,28 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss
 
        blob = data_blob_const(prs_data_p(rpc_in) + prs_offset(rpc_in), auth_len);
 
-       ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &schannel_chk,
-                              (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_SIGNATURE);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               DEBUG(0,("failed to pull NL_AUTH_SIGNATURE\n"));
-               dump_data(2, blob.data, blob.length);
-               return false;
-       }
-
        if (DEBUGLEVEL >= 10) {
-               NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &schannel_chk);
+               dump_NL_AUTH_SIGNATURE(talloc_tos(), &blob);
        }
 
+       data = (uint8_t *)prs_data_p(rpc_in)+RPC_HDR_REQ_LEN;
+
        switch (auth_info.auth_level) {
        case DCERPC_AUTH_LEVEL_PRIVACY:
-               status = schannel_unseal_packet(p->auth.a_u.schannel_auth,
+               status = netsec_incoming_packet(p->auth.a_u.schannel_auth,
                                                talloc_tos(),
-                                               (uint8_t *)prs_data_p(rpc_in)+RPC_HDR_REQ_LEN,
+                                               true,
+                                               data,
                                                data_len,
                                                &blob);
                break;
        case DCERPC_AUTH_LEVEL_INTEGRITY:
-               status = schannel_check_packet(p->auth.a_u.schannel_auth,
-                                              talloc_tos(),
-                                              (uint8_t *)prs_data_p(rpc_in)+RPC_HDR_REQ_LEN,
-                                              data_len,
-                                              &blob);
+               status = netsec_incoming_packet(p->auth.a_u.schannel_auth,
+                                               talloc_tos(),
+                                               false,
+                                               data,
+                                               data_len,
+                                               &blob);
                break;
        default:
                status = NT_STATUS_INTERNAL_ERROR;
@@ -2344,7 +2557,7 @@ bool api_pipe_request(pipes_struct *p)
        }
 
        DEBUG(5, ("Requested \\PIPE\\%s\n",
-                 get_pipe_name_from_iface(&p->syntax)));
+                 get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
 
        /* get the set of RPC functions for this context */
 
@@ -2358,7 +2571,7 @@ bool api_pipe_request(pipes_struct *p)
        else {
                DEBUG(0,("api_pipe_request: No rpc function table associated with context [%d] on pipe [%s]\n",
                        p->hdr_req.context_id,
-                       get_pipe_name_from_iface(&p->syntax)));
+                        get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
        }
 
        if (changed_user) {
@@ -2380,12 +2593,13 @@ static bool api_rpcTNP(pipes_struct *p,
 
        /* interpret the command */
        DEBUG(4,("api_rpcTNP: %s op 0x%x - ",
-                get_pipe_name_from_iface(&p->syntax), p->hdr_req.opnum));
+                get_pipe_name_from_syntax(talloc_tos(), &p->syntax),
+                p->hdr_req.opnum));
 
        if (DEBUGLEVEL >= 50) {
                fstring name;
                slprintf(name, sizeof(name)-1, "in_%s",
-                        get_pipe_name_from_iface(&p->syntax));
+                        get_pipe_name_from_syntax(talloc_tos(), &p->syntax));
                prs_dump(name, p->hdr_req.opnum, &p->in_data.data);
        }
 
@@ -2414,7 +2628,7 @@ static bool api_rpcTNP(pipes_struct *p,
        /* do the actual command */
        if(!api_rpc_cmds[fn_num].fn(p)) {
                DEBUG(0,("api_rpcTNP: %s: %s failed.\n",
-                        get_pipe_name_from_iface(&p->syntax),
+                        get_pipe_name_from_syntax(talloc_tos(), &p->syntax),
                         api_rpc_cmds[fn_num].name));
                prs_mem_free(&p->out_data.rdata);
                return False;
@@ -2439,13 +2653,13 @@ static bool api_rpcTNP(pipes_struct *p,
        if (DEBUGLEVEL >= 50) {
                fstring name;
                slprintf(name, sizeof(name)-1, "out_%s",
-                        get_pipe_name_from_iface(&p->syntax));
+                        get_pipe_name_from_syntax(talloc_tos(), &p->syntax));
                prs_dump(name, p->hdr_req.opnum, &p->out_data.rdata);
        }
        prs_set_offset(&p->out_data.rdata, offset2);
 
        DEBUG(5,("api_rpcTNP: called %s successfully\n",
-                get_pipe_name_from_iface(&p->syntax)));
+                get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
 
        /* Check for buffer underflow in rpc parsing */