Fix bug #7146 - Samba miss-parses authenticated RPC packets.
authorJeremy Allison <jra@samba.org>
Wed, 17 Feb 2010 23:27:59 +0000 (15:27 -0800)
committerJeremy Allison <jra@samba.org>
Wed, 17 Feb 2010 23:27:59 +0000 (15:27 -0800)
Parts of the Samba RPC client and server code misinterpret authenticated
packets.

DCE authenticated packets actually look like this :

+--------------------------+
|header                    |
| ... frag_len (packet len)|
| ... auth_len             |
+--------------------------+
|                          |
| Data payload             |
...                     ....
|                          |
+--------------------------+
|                          |
| auth_pad_len bytes       |
+--------------------------+
|                          |
| Auth footer              |
| auth_pad_len value       |
+--------------------------+
|                          |
| Auth payload             |
| (auth_len bytes long)    |
+--------------------------+

That's right. The pad bytes come *before* the footer specifying how many pad
bytes there are. In order to read this you must seek to the end of the packet
and subtract the auth_len (in the packet header) and the auth footer length (a
known value).

The client and server code gets this right (mostly) in 3.0.x -> 3.4.x so long
as the pad alignment is on an 8 byte boundary (there are some special cases in
the code for this).

Tridge discovered there are some (DRS replication) cases where on 64-bit
machines where the pad alignment is on a 16-byte boundary. This breaks the
existing S3 hand-optimized rpc code.

This patch removes all the special cases in client and server code, and allows
the pad alignment for generated packets to be specified by changing a constant
in include/local.h (this doesn't affect received packets, the new code always
handles them correctly whatever pad alignment is used).

This patch also works correctly with rpcclient using sign+seal from
the 3.4.x and 3.3.x builds (testing with 3.0.x and 3.2.x to follow)
so even as a server it should still work with older libsmbclient and
winbindd code.

Jeremy

source3/include/local.h
source3/rpc_client/cli_pipe.c
source3/rpc_parse/parse_rpc.c
source3/rpc_server/srv_pipe.c

index a88b17be137353194e64674829ee78194a5992f9..a3baf64f9aaa80b41077d82007d624885e978645 100644 (file)
 /* Maximum size of RPC data we will accept for one call. */
 #define MAX_RPC_DATA_SIZE (15*1024*1024)
 
+#define CLIENT_NDR_PADDING_SIZE 8
+#define SERVER_NDR_PADDING_SIZE 8
+
 #endif
index 48e2f9eb51e01c2c14249088b0371b0f5e1f7122..2f7db99f205deab49396b6351cd092a5b79afd22 100644 (file)
@@ -650,8 +650,9 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr
        }
 
        /* Ensure there's enough data for an authenticated response. */
-       if ((auth_len > RPC_MAX_SIGN_SIZE) ||
-                       (RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len)) {
+       if (auth_len > RPC_MAX_PDU_FRAG_LEN ||
+                       prhdr->frag_len < RPC_HEADER_LEN + RPC_HDR_RESP_LEN +
+                                       RPC_HDR_AUTH_LEN + auth_len) {
                DEBUG(0,("cli_pipe_verify_ntlmssp: auth_len %u is too large.\n",
                        (unsigned int)auth_len ));
                return NT_STATUS_BUFFER_TOO_SMALL;
@@ -671,17 +672,31 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr
        full_packet_data_len = prhdr->frag_len - auth_len;
 
        /* Pull the auth header and the following data into a blob. */
-       if(!prs_set_offset(current_pdu, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len)) {
+        /* NB. The offset of the auth_header is relative to the *end*
+        * of the packet, not the start. */
+       if(!prs_set_offset(current_pdu, prhdr->frag_len - RPC_HDR_AUTH_LEN - auth_len)) {
                DEBUG(0,("cli_pipe_verify_ntlmssp: cannot move offset to %u.\n",
                        (unsigned int)RPC_HEADER_LEN + (unsigned int)RPC_HDR_RESP_LEN + (unsigned int)data_len ));
                return NT_STATUS_BUFFER_TOO_SMALL;
-       }
+        }
 
        if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, current_pdu, 0)) {
                DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unmarshall RPC_HDR_AUTH.\n"));
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
+       /* 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 > prhdr->frag_len) {
+               DEBUG(0,("cli_pipe_verify_ntlmssp: 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)prhdr->frag_len ));
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+
        auth_blob.data = (unsigned char *)prs_data_p(current_pdu) + prs_offset(current_pdu);
        auth_blob.length = auth_len;
 
@@ -775,7 +790,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p
        }
 
        /* Ensure there's enough data for an authenticated response. */
-       if ((auth_len > RPC_MAX_SIGN_SIZE) ||
+       if ((auth_len > RPC_MAX_PDU_FRAG_LEN) ||
                        (RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len)) {
                DEBUG(0,("cli_pipe_verify_schannel: auth_len %u is too large.\n",
                        (unsigned int)auth_len ));
@@ -784,9 +799,15 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p
 
        data_len = prhdr->frag_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len;
 
-       if(!prs_set_offset(current_pdu, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len)) {
-               DEBUG(0,("cli_pipe_verify_schannel: cannot move offset to %u.\n",
-                       (unsigned int)RPC_HEADER_LEN + RPC_HDR_RESP_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. */
+       if(!prs_set_offset(current_pdu,
+                       prhdr->frag_len - RPC_HDR_AUTH_LEN - auth_len)) {
+               DEBUG(0,("cli_pipe_verify_schannel: cannot move "
+                       "offset to %u.\n",
+                       (unsigned int)(prhdr->frag_len -
+                               RPC_HDR_AUTH_LEN - auth_len) ));
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
@@ -795,6 +816,17 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
+       /* 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 > prhdr->frag_len) {
+               DEBUG(0,("cli_pipe_verify_schannel: 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)prhdr->frag_len ));
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
        if (auth_info.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
                DEBUG(0,("cli_pipe_verify_schannel: Invalid auth info %d on schannel\n",
                        auth_info.auth_type));
@@ -1790,8 +1822,8 @@ static NTSTATUS create_bind_or_alt_ctx_internal(enum dcerpc_pkt_type pkt_type,
        /* Do we need to pad ? */
        if (auth_len) {
                uint16 data_len = RPC_HEADER_LEN + RPC_HDR_RB_LEN(&hdr_rb);
-               if (data_len % 8) {
-                       ss_padding_len = 8 - (data_len % 8);
+               if (data_len % CLIENT_NDR_PADDING_SIZE) {
+                       ss_padding_len = CLIENT_NDR_PADDING_SIZE - (data_len % CLIENT_NDR_PADDING_SIZE);
                        phdr_auth->auth_pad_len = ss_padding_len;
                }
                frag_len += RPC_HDR_AUTH_LEN + auth_len + ss_padding_len;
@@ -1818,8 +1850,8 @@ static NTSTATUS create_bind_or_alt_ctx_internal(enum dcerpc_pkt_type pkt_type,
 
        if(auth_len != 0) {
                if (ss_padding_len) {
-                       char pad[8];
-                       memset(pad, '\0', 8);
+                       char pad[CLIENT_NDR_PADDING_SIZE];
+                       memset(pad, '\0', CLIENT_NDR_PADDING_SIZE);
                        if (!prs_copy_data_in(rpc_out, pad, ss_padding_len)) {
                                DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall padding.\n"));
                                return NT_STATUS_NO_MEMORY;
@@ -2120,8 +2152,8 @@ static uint32 calculate_data_len_tosend(struct rpc_pipe_client *cli,
 
                        data_len = MIN(data_space, data_left);
                        *p_ss_padding = 0;
-                       if (data_len % 8) {
-                               *p_ss_padding = 8 - (data_len % 8);
+                       if (data_len % CLIENT_NDR_PADDING_SIZE) {
+                               *p_ss_padding = CLIENT_NDR_PADDING_SIZE - (data_len % CLIENT_NDR_PADDING_SIZE);
                        }
                        *p_frag_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN +                /* Normal headers. */
                                        data_len + *p_ss_padding +              /* data plus padding. */
@@ -2517,7 +2549,7 @@ static NTSTATUS create_rpc_bind_auth3(struct rpc_pipe_client *cli,
 
        /*
                I'm puzzled about this - seems to violate the DCE RPC auth rules,
-               about padding - shouldn't this pad to length 8 ? JRA.
+               about padding - shouldn't this pad to length CLIENT_NDR_PADDING_SIZE ? JRA.
        */
 
        /* 4 bytes padding. */
index f720de35a10ca0a13ce18788ce8ed0aff5eb62bb..441a00b1ea9fa3e91b67280d71fec2e69386d896 100644 (file)
@@ -480,6 +480,8 @@ void init_rpc_hdr_auth(RPC_HDR_AUTH *rai,
 
 /*******************************************************************
  Reads or writes an RPC_HDR_AUTH structure.
+ NB This writes UNALIGNED. Ensure you're correctly aligned before
+ calling.
 ********************************************************************/
 
 bool smb_io_rpc_hdr_auth(const char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int depth)
@@ -490,9 +492,6 @@ bool smb_io_rpc_hdr_auth(const char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, in
        prs_debug(ps, depth, desc, "smb_io_rpc_hdr_auth");
        depth++;
 
-       if(!prs_align(ps))
-               return False;
-
        if(!prs_uint8 ("auth_type    ", ps, depth, &rai->auth_type))
                return False;
        if(!prs_uint8 ("auth_level   ", ps, depth, &rai->auth_level))
index f92a100d0a90c36e39f2bcbb197d7d503ce6cf55..6b08f1f9b377a91ca6ec3527292237300ac64ef8 100644 (file)
@@ -131,11 +131,12 @@ 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 |= DCERPC_PFC_FLAG_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 ));
-               }
+       }
+
+       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 ));
        }
 
        /*
@@ -179,9 +180,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 +206,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;
@@ -350,11 +352,11 @@ 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 |= DCERPC_PFC_FLAG_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 ));
-               }
+       }
+       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 ));
        }
 
        p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + ss_padding_len +
@@ -395,8 +397,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));
@@ -421,7 +423,7 @@ 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);
@@ -746,12 +748,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;
        }
@@ -762,15 +765,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 ));
@@ -1154,6 +1187,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;
@@ -1245,8 +1279,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;
@@ -1286,7 +1323,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;
@@ -1343,8 +1381,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;
@@ -1380,6 +1421,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;
@@ -1466,7 +1508,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;
@@ -1512,6 +1555,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;
@@ -1555,7 +1599,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;
@@ -1604,6 +1649,7 @@ 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) {
@@ -1717,6 +1763,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.
         */
@@ -1726,6 +1811,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;
@@ -1750,24 +1869,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;
@@ -1781,50 +1901,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.
         */
@@ -1835,7 +1918,8 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
 
        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);
 
        /*
@@ -1856,9 +1940,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;
+               }
        }
 
        /*
@@ -1896,6 +1994,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);
 
@@ -1941,39 +2040,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;
 
        /*
@@ -2013,6 +2079,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.
         */
@@ -2044,9 +2178,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;
+               }
        }
 
        /*
@@ -2098,8 +2246,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;
@@ -2108,9 +2256,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);
@@ -2120,15 +2269,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;
        }
@@ -2213,7 +2383,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) {
@@ -2228,14 +2398,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;
        }