libfreerdp-core: started validating RTS RPC PDUs
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Fri, 16 Nov 2012 18:31:16 +0000 (13:31 -0500)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Fri, 16 Nov 2012 18:31:16 +0000 (13:31 -0500)
libfreerdp/core/rpc.h
libfreerdp/core/rts.c
libfreerdp/core/rts.h

index 11f62c2..43112f3 100644 (file)
@@ -34,7 +34,17 @@ typedef struct rdp_rpc rdpRpc;
        UINT16 auth_length; \
        UINT32 call_id
 
-#define RPC_COMMON_FIELDS_LENGTH    20
+#define RPC_COMMON_FIELDS_LENGTH       16
+
+typedef struct
+{
+       DEFINE_RPC_COMMON_FIELDS();
+
+       UINT16 Flags;
+       UINT16 NumberOfCommands;
+} rpcconn_rts_hdr_t;
+
+#define RTS_PDU_HEADER_LENGTH          20
 
 #include "tcp.h"
 #include "rts.h"
@@ -498,14 +508,6 @@ typedef struct
        DEFINE_RPC_COMMON_FIELDS();
 } rpcconn_shutdown_hdr_t;
 
-typedef struct
-{
-       DEFINE_RPC_COMMON_FIELDS();
-
-       UINT16 Flags;
-       UINT16 NumberOfCommands;
-} rpcconn_rts_hdr_t;
-
 typedef union
 {
        rpcconn_common_hdr_t common;
index b8d52df..30cedd5 100644 (file)
  * http://msdn.microsoft.com/en-us/library/cc243950/
  */
 
+static RtsPduSignature RTS_PDU_CONN_A1_SIGNATURE;
+static RtsPduSignature RTS_PDU_CONN_A2_SIGNATURE;
+static RtsPduSignature RTS_PDU_CONN_A3_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_CONN_B1_SIGNATURE;
+static RtsPduSignature RTS_PDU_CONN_B2_SIGNATURE;
+static RtsPduSignature RTS_PDU_CONN_B3_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_CONN_C1_SIGNATURE;
+static RtsPduSignature RTS_PDU_CONN_C2_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_IN_R1_A1_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R1_A2_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R1_A3_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R1_A4_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R1_A5_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R1_A6_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_IN_R1_B1_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R1_B2_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_IN_R2_A1_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R2_A2_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R2_A3_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R2_A4_SIGNATURE;
+static RtsPduSignature RTS_PDU_IN_R2_A5_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_OUT_R1_A1_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A2_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A3_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A4_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A5_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A6_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A7_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A8_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A9_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A10_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R1_A11_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_OUT_R2_A1_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R2_A2_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R2_A3_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R2_A4_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R2_A5_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R2_A6_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R2_A7_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R2_A8_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_OUT_R2_B1_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R2_B2_SIGNATURE;
+static RtsPduSignature RTS_PDU_OUT_R2_B3_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_OUT_R2_C1_SIGNATURE;
+
+static RtsPduSignature RTS_PDU_KEEP_ALIVE_SIGNATURE;
+static RtsPduSignature RTS_PDU_PING_TRAFFIC_SENT_NOTIFY_SIGNATURE;
+static RtsPduSignature RTS_PDU_ECHO_SIGNATURE;
+static RtsPduSignature RTS_PDU_PING_SIGNATURE;
+static RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE;
+static RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE;
+
 /**
  *                                      Connection Establishment\n
  *
 BOOL rts_connect(rdpRpc* rpc)
 {
        int status;
+       rpcconn_rts_hdr_t* rts;
        HttpResponse* http_response;
 
        /**
@@ -169,11 +231,22 @@ BOOL rts_connect(rdpRpc* rpc)
         * machine to Wait_C2 state and wait for network events.
         *
         */
+
        status = rts_recv_pdu(rpc);
 
        if (status < 1)
                return FALSE;
 
+       rts = (rpcconn_rts_hdr_t*) rpc->buffer;
+
+       if (!rts_match_pdu_signature(rpc, &RTS_PDU_CONN_A3_SIGNATURE, rts))
+       {
+               printf("Unexpected RTS PDU: Expected CONN/A3\n");
+               return FALSE;
+       }
+
+       rts_recv_pdu_commands(rpc, rts);
+
        rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_WAIT_C2;
        DEBUG_RTS("VIRTUAL_CONNECTION_STATE_WAIT_C2");
 
@@ -203,6 +276,16 @@ BOOL rts_connect(rdpRpc* rpc)
        if (status < 1)
                return FALSE;
 
+       rts = (rpcconn_rts_hdr_t*) rpc->buffer;
+
+       if (!rts_match_pdu_signature(rpc, &RTS_PDU_CONN_C2_SIGNATURE, rts))
+       {
+               printf("Unexpected RTS PDU: Expected CONN/C2\n");
+               return FALSE;
+       }
+
+       rts_recv_pdu_commands(rpc, rts);
+
        rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_OPENED;
        DEBUG_RTS("VIRTUAL_CONNECTION_STATE_OPENED");
 
@@ -941,6 +1024,123 @@ RTS_PDU_SIGNATURE_ENTRY RTS_PDU_SIGNATURE_TABLE[] =
        { 0, NULL }
 };
 
+int rts_command_length(rdpRpc* rpc, UINT32 CommandType, BYTE* buffer, UINT32 length)
+{
+       int CommandLength = 0;
+
+       switch (CommandType)
+       {
+               case RTS_CMD_RECEIVE_WINDOW_SIZE:
+                       CommandLength = RTS_CMD_RECEIVE_WINDOW_SIZE_LENGTH;
+                       break;
+
+               case RTS_CMD_FLOW_CONTROL_ACK:
+                       CommandLength = RTS_CMD_FLOW_CONTROL_ACK_LENGTH;
+                       break;
+
+               case RTS_CMD_CONNECTION_TIMEOUT:
+                       CommandLength = RTS_CMD_CONNECTION_TIMEOUT_LENGTH;
+                       break;
+
+               case RTS_CMD_COOKIE:
+                       CommandLength = RTS_CMD_COOKIE_LENGTH;
+                       break;
+
+               case RTS_CMD_CHANNEL_LIFETIME:
+                       CommandLength = RTS_CMD_CHANNEL_LIFETIME_LENGTH;
+                       break;
+
+               case RTS_CMD_CLIENT_KEEPALIVE:
+                       CommandLength =  RTS_CMD_CLIENT_KEEPALIVE_LENGTH;
+                       break;
+
+               case RTS_CMD_VERSION:
+                       CommandLength = RTS_CMD_VERSION_LENGTH;
+                       break;
+
+               case RTS_CMD_EMPTY:
+                       CommandLength = RTS_CMD_EMPTY_LENGTH;
+                       break;
+
+               case RTS_CMD_PADDING: /* variable-size */
+                       CommandLength = rts_padding_command_read(rpc, buffer, length);
+                       break;
+
+               case RTS_CMD_NEGATIVE_ANCE:
+                       CommandLength = RTS_CMD_NEGATIVE_ANCE_LENGTH;
+                       break;
+
+               case RTS_CMD_ANCE:
+                       CommandLength = RTS_CMD_ANCE_LENGTH;
+                       break;
+
+               case RTS_CMD_CLIENT_ADDRESS: /* variable-size */
+                       CommandLength = rts_client_address_command_read(rpc, buffer, length);
+                       break;
+
+               case RTS_CMD_ASSOCIATION_GROUP_ID:
+                       CommandLength = RTS_CMD_ASSOCIATION_GROUP_ID_LENGTH;
+                       break;
+
+               case RTS_CMD_DESTINATION:
+                       CommandLength = RTS_CMD_DESTINATION_LENGTH;
+                       break;
+
+               case RTS_CMD_PING_TRAFFIC_SENT_NOTIFY:
+                       CommandLength = RTS_CMD_PING_TRAFFIC_SENT_NOTIFY_LENGTH;
+                       break;
+
+               default:
+                       printf("Error: Unknown RTS Command Type: 0x%x\n", CommandType);
+                       return -1;
+                       break;
+       }
+
+       return CommandLength;
+}
+
+BOOL rts_match_pdu_signature(rdpRpc* rpc, RtsPduSignature* signature, rpcconn_rts_hdr_t* rts)
+{
+       int i;
+       int status;
+       BYTE* buffer;
+       UINT32 length;
+       UINT32 offset;
+       UINT32 CommandType;
+       UINT32 CommandLength;
+
+       if (rts->Flags != signature->Flags)
+               return FALSE;
+
+       if (rts->NumberOfCommands != signature->NumberOfCommands)
+               return FALSE;
+
+       buffer = (BYTE*) rts;
+       offset = RTS_PDU_HEADER_LENGTH;
+       length = rts->frag_length - offset;
+
+       for (i = 0; i < rts->NumberOfCommands; i++)
+       {
+               CommandType = *((UINT32*) &buffer[offset]); /* CommandType (4 bytes) */
+               offset += 4;
+
+               if (CommandType != signature->CommandTypes[i])
+                       return FALSE;
+
+               status = rts_command_length(rpc, CommandType, &buffer[offset], length);
+
+               if (status < 0)
+                       return FALSE;
+
+               CommandLength = (UINT32) status;
+               offset += CommandLength;
+
+               length = rts->frag_length - offset;
+       }
+
+       return TRUE;
+}
+
 int rts_recv_pdu_commands(rdpRpc* rpc, rpcconn_rts_hdr_t* rts)
 {
        int i;
@@ -957,77 +1157,80 @@ int rts_recv_pdu_commands(rdpRpc* rpc, rpcconn_rts_hdr_t* rts)
                return 0;
        }
 
-       offset = 24;
-       buffer = &((BYTE*) rts)[offset];
+       buffer = (BYTE*) rts;
+       offset = RTS_PDU_HEADER_LENGTH;
        length = rts->frag_length - offset;
 
+       freerdp_hexdump(buffer, rts->frag_length);
+
        for (i = 0; i < rts->NumberOfCommands; i++)
        {
                CommandType = *((UINT32*) &buffer[offset]); /* CommandType (4 bytes) */
                offset += 4;
 
-               DEBUG_RTS("CommandType: %s (0x%08X)", RTS_CMD_STRINGS[CommandType % 14], CommandType);
+               DEBUG_RTS("CommandType: %s (0x%08X)",
+                               (CommandType >= RTS_CMD_LAST_ID) ? "UNKNOWN" : RTS_CMD_STRINGS[CommandType], CommandType);
 
                switch (CommandType)
                {
                        case RTS_CMD_RECEIVE_WINDOW_SIZE:
-                               offset += rts_receive_window_size_command_read(rpc, buffer, length);
+                               offset += rts_receive_window_size_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_FLOW_CONTROL_ACK:
-                               offset += rts_flow_control_ack_command_read(rpc, buffer, length);
+                               offset += rts_flow_control_ack_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_CONNECTION_TIMEOUT:
-                               offset += rts_connection_timeout_command_read(rpc, buffer, length);
+                               offset += rts_connection_timeout_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_COOKIE:
-                               offset += rts_cookie_command_read(rpc, buffer, length);
+                               offset += rts_cookie_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_CHANNEL_LIFETIME:
-                               offset += rts_channel_lifetime_command_read(rpc, buffer, length);
+                               offset += rts_channel_lifetime_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_CLIENT_KEEPALIVE:
-                               offset += rts_client_keepalive_command_read(rpc, buffer, length);
+                               offset += rts_client_keepalive_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_VERSION:
-                               offset += rts_version_command_read(rpc, buffer, length);
+                               offset += rts_version_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_EMPTY:
-                               offset += rts_empty_command_read(rpc, buffer, length);
+                               offset += rts_empty_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_PADDING:
-                               offset += rts_padding_command_read(rpc, buffer, length);
+                               offset += rts_padding_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_NEGATIVE_ANCE:
-                               offset += rts_negative_ance_command_read(rpc, buffer, length);
+                               offset += rts_negative_ance_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_ANCE:
-                               offset += rts_ance_command_read(rpc, buffer, length);
+                               offset += rts_ance_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_CLIENT_ADDRESS:
-                               offset += rts_client_address_command_read(rpc, buffer, length);
+                               offset += rts_client_address_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_ASSOCIATION_GROUP_ID:
-                               offset += rts_association_group_id_command_read(rpc, buffer, length);
+                               offset += rts_association_group_id_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_DESTINATION:
-                               offset += rts_destination_command_read(rpc, buffer, length);
+                               offset += rts_destination_command_read(rpc, &buffer[offset], length);
                                break;
 
                        case RTS_CMD_PING_TRAFFIC_SENT_NOTIFY:
-                               offset += rts_ping_traffic_sent_notify_command_read(rpc, buffer, length);
+                               offset += rts_ping_traffic_sent_notify_command_read(rpc, &buffer[offset], length);
                                break;
 
                        default:
@@ -1036,7 +1239,6 @@ int rts_recv_pdu_commands(rdpRpc* rpc, rpcconn_rts_hdr_t* rts)
                                break;
                }
 
-               buffer = &((BYTE*) rts)[offset];
                length = rts->frag_length - offset;
        }
 
@@ -1062,7 +1264,5 @@ int rts_recv_pdu(rdpRpc* rpc)
                }
        }
 
-       rts_recv_pdu_commands(rpc, rts);
-
        return status;
 }
index 99b1aa8..616b930 100644 (file)
 #include <freerdp/types.h>
 #include <freerdp/utils/debug.h>
 
-#define RTS_FLAG_NONE                          0x0000
-#define RTS_FLAG_PING                          0x0001
-#define RTS_FLAG_OTHER_CMD                     0x0002
-#define RTS_FLAG_RECYCLE_CHANNEL               0x0004
-#define RTS_FLAG_IN_CHANNEL                    0x0008
-#define RTS_FLAG_OUT_CHANNEL                   0x0010
-#define RTS_FLAG_EOF                           0x0020
-#define RTS_FLAG_ECHO                          0x0040
-
-#define RTS_CMD_RECEIVE_WINDOW_SIZE            0x00000000
-#define RTS_CMD_FLOW_CONTROL_ACK               0x00000001
-#define RTS_CMD_CONNECTION_TIMEOUT             0x00000002
-#define RTS_CMD_COOKIE                         0x00000003
-#define RTS_CMD_CHANNEL_LIFETIME               0x00000004
-#define RTS_CMD_CLIENT_KEEPALIVE               0x00000005
-#define RTS_CMD_VERSION                                0x00000006
-#define RTS_CMD_EMPTY                          0x00000007
-#define RTS_CMD_PADDING                                0x00000008
-#define RTS_CMD_NEGATIVE_ANCE                  0x00000009
-#define RTS_CMD_ANCE                           0x0000000A
-#define RTS_CMD_CLIENT_ADDRESS                 0x0000000B
-#define RTS_CMD_ASSOCIATION_GROUP_ID           0x0000000C
-#define RTS_CMD_DESTINATION                    0x0000000D
-#define RTS_CMD_PING_TRAFFIC_SENT_NOTIFY       0x0000000E
-
-#define FDClient                               0x00000000
-#define FDInProxy                              0x00000001
-#define FDServer                               0x00000002
-#define FDOutProxy                             0x00000003
+#define RTS_FLAG_NONE                                  0x0000
+#define RTS_FLAG_PING                                  0x0001
+#define RTS_FLAG_OTHER_CMD                             0x0002
+#define RTS_FLAG_RECYCLE_CHANNEL                       0x0004
+#define RTS_FLAG_IN_CHANNEL                            0x0008
+#define RTS_FLAG_OUT_CHANNEL                           0x0010
+#define RTS_FLAG_EOF                                   0x0020
+#define RTS_FLAG_ECHO                                  0x0040
+
+#define RTS_CMD_RECEIVE_WINDOW_SIZE                    0x00000000
+#define RTS_CMD_FLOW_CONTROL_ACK                       0x00000001
+#define RTS_CMD_CONNECTION_TIMEOUT                     0x00000002
+#define RTS_CMD_COOKIE                                 0x00000003
+#define RTS_CMD_CHANNEL_LIFETIME                       0x00000004
+#define RTS_CMD_CLIENT_KEEPALIVE                       0x00000005
+#define RTS_CMD_VERSION                                        0x00000006
+#define RTS_CMD_EMPTY                                  0x00000007
+#define RTS_CMD_PADDING                                        0x00000008
+#define RTS_CMD_NEGATIVE_ANCE                          0x00000009
+#define RTS_CMD_ANCE                                   0x0000000A
+#define RTS_CMD_CLIENT_ADDRESS                         0x0000000B
+#define RTS_CMD_ASSOCIATION_GROUP_ID                   0x0000000C
+#define RTS_CMD_DESTINATION                            0x0000000D
+#define RTS_CMD_PING_TRAFFIC_SENT_NOTIFY               0x0000000E
+#define RTS_CMD_LAST_ID                                        0x0000000F
+
+#define RTS_CMD_RECEIVE_WINDOW_SIZE_LENGTH             0x00000004
+#define RTS_CMD_FLOW_CONTROL_ACK_LENGTH                        0x00000018
+#define RTS_CMD_CONNECTION_TIMEOUT_LENGTH              0x00000004
+#define RTS_CMD_COOKIE_LENGTH                          0x00000010
+#define RTS_CMD_CHANNEL_LIFETIME_LENGTH                        0x00000004
+#define RTS_CMD_CLIENT_KEEPALIVE_LENGTH                        0x00000004
+#define RTS_CMD_VERSION_LENGTH                                 0x00000004
+#define RTS_CMD_EMPTY_LENGTH                           0x00000000
+#define RTS_CMD_PADDING_LENGTH                         0x00000000 /* variable-size */
+#define RTS_CMD_NEGATIVE_ANCE_LENGTH                   0x00000000
+#define RTS_CMD_ANCE_LENGTH                            0x00000000
+#define RTS_CMD_CLIENT_ADDRESS_LENGTH                  0x00000000 /* variable-size */
+#define RTS_CMD_ASSOCIATION_GROUP_ID_LENGTH            0x00000010
+#define RTS_CMD_DESTINATION_LENGTH                     0x00000004
+#define RTS_CMD_PING_TRAFFIC_SENT_NOTIFY_LENGTH                0x00000004
+
+#define FDClient                                       0x00000000
+#define FDInProxy                                      0x00000001
+#define FDServer                                       0x00000002
+#define FDOutProxy                                     0x00000003
 
 struct rts_pdu_signature
 {
@@ -142,6 +159,10 @@ typedef struct rts_pdu_signature RtsPduSignature;
 #define RTS_PDU_FLOW_CONTROL_ACK                       (RTS_PDU_OUT_OF_SEQUENCE | 0x00000005)
 #define RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION      (RTS_PDU_OUT_OF_SEQUENCE | 0x00000006)
 
+int rts_command_length(rdpRpc* rpc, UINT32 CommandType, BYTE* buffer, UINT32 length);
+BOOL rts_match_pdu_signature(rdpRpc* rpc, RtsPduSignature* signature, rpcconn_rts_hdr_t* rts);
+int rts_recv_pdu_commands(rdpRpc* rpc, rpcconn_rts_hdr_t* rts);
+
 BOOL rts_connect(rdpRpc* rpc);
 
 int rts_receive_window_size_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length);