Rob Shearman : rpcrt4: Fix RPCRT4_Receive to accept authentication verifier data on any packets, not just bind packets.

Alexandre Julliard julliard at wine.codeweavers.com
Fri Oct 27 05:49:21 CDT 2006


Module: wine
Branch: master
Commit: 28d3bd3e42fcd9388416efde0e9c5d2aa9b5886c
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=28d3bd3e42fcd9388416efde0e9c5d2aa9b5886c

Author: Rob Shearman <rob at codeweavers.com>
Date:   Thu Oct 26 23:15:00 2006 +0100

rpcrt4: Fix RPCRT4_Receive to accept authentication verifier data on any packets, not just bind packets.

---

 dlls/rpcrt4/rpc_defs.h    |    3 ++
 dlls/rpcrt4/rpc_message.c |   59 ++++++++++++++++++++++++++++++++++++++------
 2 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/dlls/rpcrt4/rpc_defs.h b/dlls/rpcrt4/rpc_defs.h
index 1bc8f5b..4ee840c 100644
--- a/dlls/rpcrt4/rpc_defs.h
+++ b/dlls/rpcrt4/rpc_defs.h
@@ -143,6 +143,9 @@ typedef struct
   unsigned long auth_context_id; /* unique value for the authenticated connection */
 } RpcAuthVerifier;
 
+#define RPC_AUTH_VERIFIER_LEN(common_hdr) \
+    ((common_hdr)->auth_len ? (common_hdr)->auth_len + sizeof(RpcAuthVerifier) : 0)
+
 #define RPC_VER_MAJOR             5
 #define RPC_VER_MINOR             0
 
diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c
index 0120bf6..f102cf6 100644
--- a/dlls/rpcrt4/rpc_message.c
+++ b/dlls/rpcrt4/rpc_message.c
@@ -475,7 +475,9 @@ RPC_STATUS RPCRT4_Receive(RpcConnection
   unsigned short first_flag;
   unsigned long data_length;
   unsigned long buffer_length;
+  unsigned long auth_length;
   unsigned char *buffer_ptr;
+  unsigned char *auth_data = NULL;
   RpcPktCommonHdr common_hdr;
 
   *Header = NULL;
@@ -525,7 +527,7 @@ RPC_STATUS RPCRT4_Receive(RpcConnection
     pMsg->BufferLength = (*Header)->request.alloc_hint;
     break;
   default:
-    pMsg->BufferLength = common_hdr.frag_len - hdr_length;
+    pMsg->BufferLength = common_hdr.frag_len - hdr_length - RPC_AUTH_VERIFIER_LEN(&common_hdr);
   }
 
   TRACE("buffer length = %u\n", pMsg->BufferLength);
@@ -534,11 +536,38 @@ RPC_STATUS RPCRT4_Receive(RpcConnection
   if (status != RPC_S_OK) goto fail;
 
   first_flag = RPC_FLG_FIRST;
+  auth_length = common_hdr.auth_len;
+  if (auth_length) {
+    auth_data = HeapAlloc(GetProcessHeap(), 0, RPC_AUTH_VERIFIER_LEN(&common_hdr));
+    if (!auth_data) {
+      status = RPC_S_PROTOCOL_ERROR;
+      goto fail;
+    }
+  }
   buffer_length = 0;
   buffer_ptr = pMsg->Buffer;
   while (buffer_length < pMsg->BufferLength)
   {
-    data_length = (*Header)->common.frag_len - hdr_length;
+    unsigned int header_auth_len = RPC_AUTH_VERIFIER_LEN(&(*Header)->common);
+
+    /* verify header fields */
+
+    if (((*Header)->common.frag_len < hdr_length) ||
+        ((*Header)->common.frag_len - hdr_length < header_auth_len)) {
+      WARN("frag_len %d too small for hdr_length %ld and auth_len %d\n",
+        common_hdr.frag_len, hdr_length, common_hdr.auth_len);
+      status = RPC_S_PROTOCOL_ERROR;
+      goto fail;
+    }
+
+    if ((*Header)->common.auth_len != auth_length) {
+      WARN("auth_len header field changed from %ld to %d\n",
+        auth_length, (*Header)->common.auth_len);
+      status = RPC_S_PROTOCOL_ERROR;
+      goto fail;
+    }
+
+    data_length = (*Header)->common.frag_len - hdr_length - header_auth_len;
     if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag ||
         data_length + buffer_length > pMsg->BufferLength) {
       TRACE("invalid packet flags or buffer length\n");
@@ -554,6 +583,21 @@ RPC_STATUS RPCRT4_Receive(RpcConnection
       goto fail;
     }
 
+    if (header_auth_len) {
+      /* FIXME: we should accumulate authentication data for the bind,
+       * bind_ack, alter_context and alter_context_response if necessary.
+       * however, the details of how this is done is very sketchy in the
+       * DCE/RPC spec. for all other packet types that have authentication
+       * verifier data then it is just duplicated in all the fragments */
+      dwRead = rpcrt4_conn_read(Connection, auth_data, header_auth_len);
+      if (dwRead != header_auth_len) {
+        WARN("bad authentication data length, %ld/%d\n", dwRead,
+          header_auth_len);
+        status = RPC_S_PROTOCOL_ERROR;
+        goto fail;
+      }
+    }
+
     /* when there is no more data left, it should be the last packet */
     if (buffer_length == pMsg->BufferLength &&
         ((*Header)->common.flags & RPC_FLG_LAST) == 0) {
@@ -580,13 +624,11 @@ RPC_STATUS RPCRT4_Receive(RpcConnection
   }
 
   /* respond to authorization request */
-  if (common_hdr.ptype == PKT_BIND_ACK && common_hdr.auth_len > 8)
+  if (common_hdr.ptype == PKT_BIND_ACK && auth_length > sizeof(RpcAuthVerifier))
   {
-    unsigned int offset;
-
-    offset = common_hdr.frag_len - hdr_length - common_hdr.auth_len;
-    status = RPCRT_AuthorizeConnection(Connection, (LPBYTE)pMsg->Buffer + offset,
-                                       common_hdr.auth_len);
+    status = RPCRT_AuthorizeConnection(Connection,
+                                       auth_data + sizeof(RpcAuthVerifier),
+                                       auth_length);
     if (status)
         goto fail;
   }
@@ -599,6 +641,7 @@ fail:
     RPCRT4_FreeHeader(*Header);
     *Header = NULL;
   }
+  HeapFree(GetProcessHeap(), 0, auth_data);
   return status;
 }
 




More information about the wine-cvs mailing list