Example #1
0
        /// <summary>
        /// Receive and reassemble PDU.
        /// </summary>
        /// <param name="timeout">timeout</param>
        /// <returns>PDU</returns>
        private RpcePdu ReceiveAndReassemblePdu(TimeSpan timeout)
        {
            RpcePdu   receivedPdu   = rpceClient.ExpectPdu(timeout);
            RpceCoPdu receivedCoPdu = receivedPdu as RpceCoPdu;

            if (receivedCoPdu == null)
            {
                return(receivedPdu);
            }

            List <RpceCoPdu> pduList = new List <RpceCoPdu>();

            pduList.Add(receivedCoPdu);

            while ((receivedCoPdu.pfc_flags & RpceCoPfcFlags.PFC_LAST_FRAG) == 0)
            {
                receivedPdu   = rpceClient.ExpectPdu(timeout);
                receivedCoPdu = receivedPdu as RpceCoPdu;
                if (receivedCoPdu == null)
                {
                    throw new InvalidOperationException("CL PDU received inside a connection.");
                }

                pduList.Add(receivedCoPdu);
            }

            return(RpceUtility.ReassemblePdu(rpceClient.Context, pduList.ToArray()));
        }
 /// <summary>
 /// Fragment and send PDU.
 /// </summary>
 /// <param name="sessionContext">Context of the RPCE session</param>
 /// <param name="pdu">PDU to Fragment and send.</param>
 private void FragmentAndSendPdu(
     RpceServerSessionContext sessionContext,
     RpceCoPdu pdu)
 {
     if (pdu.PTYPE == RpcePacketType.Bind ||
         pdu.PTYPE == RpcePacketType.BindAck ||
         pdu.PTYPE == RpcePacketType.AlterContext ||
         pdu.PTYPE == RpcePacketType.AlterContextResp ||
         pdu.PTYPE == RpcePacketType.Auth3)
     {
         pdu.InitializeAuthenticationToken();
         pdu.SetLength();
         foreach (RpceCoPdu fragPdu in RpceUtility.FragmentPdu(sessionContext, pdu))
         {
             rpceServer.SendPdu(sessionContext, fragPdu);
         }
     }
     else
     {
         foreach (RpceCoPdu fragPdu in RpceUtility.FragmentPdu(sessionContext, pdu))
         {
             fragPdu.InitializeAuthenticationToken();
             rpceServer.SendPdu(sessionContext, fragPdu);
         }
     }
 }
Example #3
0
        /// <summary>
        /// Decode CO PDU.
        /// </summary>
        /// <param name="context">The context that received data.</param>
        /// <param name="messageBytes">bytes received</param>
        /// <param name="consumedLength">num of bytes consumed in processing</param>
        /// <param name="expectedLength">num of bytes expected if the bytes is not enough</param>
        /// <returns>pdus</returns>
        internal static RpceCoPdu[] DecodeCoPdu(
            RpceContext context,
            byte[] messageBytes,
            out int consumedLength,
            out int expectedLength)
        {
            List <RpceCoPdu> pduList = new List <RpceCoPdu>();

            consumedLength = 0;
            expectedLength = 0;

            while (consumedLength < messageBytes.Length)
            {
                if ((messageBytes.Length - consumedLength) < RpceUtility.CO_PDU_HEADER_SIZE)
                {
                    expectedLength = RpceUtility.CO_PDU_HEADER_SIZE;
                    break;
                }

                //#4 byte is drep
                uint dataRepresentation = BitConverter.ToUInt32(
                    messageBytes,
                    consumedLength + RpceUtility.DREP_FIELD_OFFSET);
                //#8 byte is frag_length
                ushort fragmentLength = BitConverter.ToUInt16(
                    messageBytes,
                    consumedLength + RpceUtility.FRAG_LENGTH_FIELD_OFFSET);
                if ((dataRepresentation & 0x0000FFFFU) != NativeMethods.NDR_LOCAL_DATA_REPRESENTATION)
                {
                    fragmentLength = EndianUtility.ReverseByteOrder(fragmentLength);
                }

                if ((messageBytes.Length - consumedLength) < fragmentLength)
                {
                    expectedLength = fragmentLength;
                    break;
                }

                byte[] pduBytes = new byte[fragmentLength];
                Buffer.BlockCopy(messageBytes, consumedLength, pduBytes, 0, fragmentLength);

                RpceCoPdu pdu = RpceUtility.DecodeCoPdu(context, pduBytes);

                pduList.Add(pdu);
                consumedLength += fragmentLength;
            }

            return(pduList.ToArray());
        }
        /// <summary>
        /// Decode CO PDU.
        /// </summary>
        /// <param name="context">The context that received data.</param>
        /// <param name="messageBytes">bytes received</param>
        /// <param name="consumedLength">num of bytes consumed in processing</param>
        /// <param name="expectedLength">num of bytes expected if the bytes is not enough</param>
        /// <returns>pdus</returns>
        internal static RpceCoPdu[] DecodeCoPdu(
            RpceContext context,
            byte[] messageBytes,
            out int consumedLength,
            out int expectedLength)
        {
            List <RpceCoPdu> pduList = new List <RpceCoPdu>();

            consumedLength = 0;
            expectedLength = 0;

            while (consumedLength < messageBytes.Length)
            {
                if ((messageBytes.Length - consumedLength) < RpceUtility.CO_PDU_HEADER_SIZE)
                {
                    expectedLength = RpceUtility.CO_PDU_HEADER_SIZE;
                    break;
                }

                //#8 byte is frag_length
                ushort fragmentLength = BitConverter.ToUInt16(
                    messageBytes,
                    consumedLength + RpceUtility.FRAG_LENGTH_FIELD_OFFSET);
                if ((messageBytes.Length - consumedLength) < fragmentLength)
                {
                    expectedLength = fragmentLength;
                    break;
                }

                byte[] pduBytes = new byte[fragmentLength];
                Buffer.BlockCopy(messageBytes, consumedLength, pduBytes, 0, fragmentLength);

                RpceCoPdu pdu = RpceUtility.DecodeCoPdu(context, pduBytes);

                pduList.Add(pdu);
                consumedLength += fragmentLength;
            }

            return(pduList.ToArray());
        }
Example #5
0
        /// <summary>
        /// Fragment a PDU
        /// </summary>
        /// <param name="context">RpceContext to fragment PDU</param>
        /// <typeparam name="T">Type of PDU to fragment</typeparam>
        /// <param name="pdu">PDU to fragment</param>
        /// <param name="stubLength">length of data to be fragmented</param>
        /// <param name="extraLength">length of header and trailer</param>
        /// <returns>Fragmented PDUs</returns>
        private static T[] FragmentPdu <T>(
            RpceContext context,
            RpceCoPdu pdu,
            int stubLength,
            int extraLength) where T : RpceCoPdu
        {
            List <T> fragmentPduList = new List <T>();
            bool     isFirstFragment = true;

            while (stubLength > 0)
            {
                T fragmentPdu = (T)Activator.CreateInstance(typeof(T), context);
                fragmentPdu.rpc_vers       = pdu.rpc_vers;
                fragmentPdu.rpc_vers_minor = pdu.rpc_vers_minor;
                fragmentPdu.PTYPE          = pdu.PTYPE;
                fragmentPdu.pfc_flags      = pdu.pfc_flags
                                             & ~(RpceCoPfcFlags.PFC_FIRST_FRAG | RpceCoPfcFlags.PFC_LAST_FRAG);
                fragmentPdu.packed_drep = pdu.packed_drep;
                fragmentPdu.frag_length = (ushort)Math.Min(context.MaxTransmitFragmentSize, stubLength + extraLength);
                fragmentPdu.auth_length = pdu.auth_length;
                fragmentPdu.call_id     = pdu.call_id;

                if (isFirstFragment)
                {
                    fragmentPdu.pfc_flags |= RpceCoPfcFlags.PFC_FIRST_FRAG;
                    isFirstFragment        = false;
                }

                if (stubLength <= (context.MaxTransmitFragmentSize - extraLength))
                {
                    fragmentPdu.pfc_flags |= RpceCoPfcFlags.PFC_LAST_FRAG;
                }

                stubLength -= (context.MaxTransmitFragmentSize - extraLength);
                fragmentPduList.Add(fragmentPdu);
            }

            return(fragmentPduList.ToArray());
        }
        /// <summary>
        /// Receive and reassemble PDU.
        /// </summary>
        /// <param name="timeout">Timeout of receiving PDU</param>
        /// <param name="sessionContext">Context of the RPCE session</param>
        /// <returns>Received PDU</returns>
        private RpcePdu ReceiveAndReassemblePdu(
            TimeSpan timeout,
            ref RpceServerSessionContext sessionContext)
        {
            RpcePdu receivedPdu;
            bool    expectAny = sessionContext == null;

WaitForEvent:

            if (expectAny)
            {
                sessionContext = null;
            }
            EventType eventType = rpceServer.ExpectEvent(timeout, ref sessionContext, out receivedPdu);

            if (this.registeredInterfaceList.Count > 0)
            {
                // auto accept connect/bind/disconnect
                if (eventType == EventType.Connected)
                {
                    RpcIfMatchFunc matchFunc = delegate(RpcIf rpcIf)
                    {
                        for (int i = 0; i < this.registeredInterfaceList.Count; i++)
                        {
                            if (this.registeredInterfaceList[i].Equals(rpcIf))
                            {
                                return(true);
                            }
                        }
                        return(false);
                    };
                    InternalExpectBind(matchFunc, timeout, ref sessionContext);
                    goto WaitForEvent;
                }
                else if (eventType == EventType.Disconnected)
                {
                    goto WaitForEvent;
                }
                else
                {
                    // it is a PDU.
                }
            }
            else if (eventType != EventType.ReceivedPacket)
            {
                throw new InvalidOperationException(
                          string.Format("Unexpected event ({0}) received.", eventType));
            }


            RpceCoPdu receivedCoPdu = receivedPdu as RpceCoPdu;

            if (receivedCoPdu == null)
            {
                return(receivedPdu);
            }

            List <RpceCoPdu> pduList = new List <RpceCoPdu>();

            pduList.Add(receivedCoPdu);

            while ((receivedCoPdu.pfc_flags & RpceCoPfcFlags.PFC_LAST_FRAG) == 0)
            {
                receivedPdu = rpceServer.ExpectPdu(timeout, ref sessionContext);

                receivedCoPdu = receivedPdu as RpceCoPdu;
                if (receivedCoPdu == null)
                {
                    throw new InvalidOperationException("CL PDU received inside a connection.");
                }

                pduList.Add(receivedCoPdu);
            }

            return(RpceUtility.ReassemblePdu(sessionContext, pduList.ToArray()));
        }
Example #7
0
        /// <summary>
        /// update context on receiving PDU.
        /// </summary>
        /// <param name="pdu">PDU to receive.</param>
        /// <exception cref="ArgumentNullException">Thrown when pdu is null.</exception>
        internal void UpdateContextOnReceivingPdu(RpcePdu pdu)
        {
            RpceCoPdu coPdu = pdu as RpceCoPdu;

            if (coPdu == null)
            {
                return;
            }

            this.RpcVersionMajor = coPdu.rpc_vers;
            this.RpcVersionMinor = coPdu.rpc_vers_minor;
            if (coPdu.PTYPE == RpcePacketType.Bind ||
                coPdu.PTYPE == RpcePacketType.BindAck)
            {
                //TDI:
                //TD said PFC_SUPPORT_HEADER_SIGN is meanful in Bind and AltContext.
                //But when using Kerberos, AltContext doesn't have this flag,
                //if server or client read this flag according to AltContext, Sign/Encrypt will fail.
                this.SupportsHeaderSign
                    = (coPdu.pfc_flags & RpceCoPfcFlags.PFC_SUPPORT_HEADER_SIGN)
                      == RpceCoPfcFlags.PFC_SUPPORT_HEADER_SIGN;
                this.SupportsConcurrentMultiplexing
                    = (coPdu.pfc_flags & RpceCoPfcFlags.PFC_CONC_MPX)
                      == RpceCoPfcFlags.PFC_CONC_MPX;
            }

            this.PackedDataRepresentationFormat = coPdu.packed_drep.dataRepFormat;
            this.CurrentCallId = coPdu.call_id;
            if (coPdu.PTYPE != RpcePacketType.Response && coPdu.PTYPE != RpcePacketType.Auth3)
            {
                this.outstandingCalls.Add(coPdu.call_id);
            }

            switch (coPdu.PTYPE)
            {
            case RpcePacketType.Bind:
                RpceCoBindPdu bindPdu = coPdu as RpceCoBindPdu;
                if (bindPdu != null)
                {
                    UpdateContextOnReceivingBindPdu(bindPdu);
                }
                break;

            case RpcePacketType.Request:
                RpceCoRequestPdu requestPdu = coPdu as RpceCoRequestPdu;
                if (requestPdu != null)
                {
                    this.ContextIdentifier = requestPdu.p_cont_id;
                }
                break;

            case RpcePacketType.Response:
                RpceCoResponsePdu responsePdu = coPdu as RpceCoResponsePdu;
                if (responsePdu != null)
                {
                    this.ContextIdentifier = responsePdu.p_cont_id;
                }
                break;

            case RpcePacketType.Auth3:
            case RpcePacketType.AlterContext:
            case RpcePacketType.CoCancel:
            case RpcePacketType.Orphaned:
            default:
                //default situation should do nothing.
                //This is just update the context, if we cannot recognize the PDU, ignore it.
                break;
            }

            this.SecurityContextNeedContinueProcessing = coPdu.securityContextNeedContinueProcessing;
        }
Example #8
0
        /// <summary>
        /// update context on sending PDU.
        /// </summary>
        /// <param name="pdu">PDU to send.</param>
        internal void UpdateContextOnSendingPdu(RpcePdu pdu)
        {
            RpceCoPdu coPdu = pdu as RpceCoPdu;

            if (coPdu == null)
            {
                return;
            }

            this.RpcVersionMajor = coPdu.rpc_vers;
            this.RpcVersionMinor = coPdu.rpc_vers_minor;
            if (coPdu.PTYPE == RpcePacketType.Bind ||
                coPdu.PTYPE == RpcePacketType.BindAck ||
                coPdu.PTYPE == RpcePacketType.AlterContext ||
                coPdu.PTYPE == RpcePacketType.AlterContextResp)
            {
                this.SupportsHeaderSign
                    = (coPdu.pfc_flags & RpceCoPfcFlags.PFC_SUPPORT_HEADER_SIGN)
                      == RpceCoPfcFlags.PFC_SUPPORT_HEADER_SIGN;
            }

            this.SupportsConcurrentMultiplexing
                = (coPdu.pfc_flags & RpceCoPfcFlags.PFC_CONC_MPX)
                  == RpceCoPfcFlags.PFC_CONC_MPX;
            this.PackedDataRepresentationFormat = coPdu.packed_drep.dataRepFormat;

            if (coPdu.PTYPE != RpcePacketType.Request)
            {
                this.outstandingCalls.Remove(coPdu.call_id);
            }

            switch (coPdu.PTYPE)
            {
            case RpcePacketType.BindAck:
                RpceCoBindAckPdu bindAckPdu = coPdu as RpceCoBindAckPdu;
                if (bindAckPdu != null)
                {
                    UpdateContextOnSendingBindAckPdu(bindAckPdu);
                }
                break;

            case RpcePacketType.Request:
                RpceCoRequestPdu requestPdu = coPdu as RpceCoRequestPdu;
                if (requestPdu != null)
                {
                    this.ContextIdentifier = requestPdu.p_cont_id;
                }
                break;

            case RpcePacketType.Response:
                RpceCoResponsePdu responsePdu = coPdu as RpceCoResponsePdu;
                if (responsePdu != null)
                {
                    this.ContextIdentifier = responsePdu.p_cont_id;
                }
                break;

            case RpcePacketType.BindNak:
            case RpcePacketType.AlterContextResp:
            case RpcePacketType.Fault:
            case RpcePacketType.Shutdown:
            default:
                //default situation should do nothing.
                //This is just update the context, if we cannot recognize the PDU, ignore it.
                break;
            }
        }
Example #9
0
        /// <summary>
        /// Fragment a PDU into several PDUs by max_xmit_frag field.<para/>
        /// Only bind, bind_ack, alter_context, alter_context_response,
        /// request and response PDUs will be fragmented.<para/>
        /// Must call before sign/encrypt.
        /// </summary>
        /// <param name="context">RpceContext to fragment PDU</param>
        /// <param name="pdu">
        /// A PDU to be fragmented.
        /// Only bind, bind_ack, alter_context, alter_context_response,
        /// request and response PDUs will be fragmented.
        /// </param>
        /// <returns>Fragmented PDUs.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when pdu or context is null.
        /// </exception>
        /// <exception cref="NotSupportedException">Thrown when PDU PacketType isn't supported.</exception>
        public static RpceCoPdu[] FragmentPdu(RpceContext context, RpceCoPdu pdu)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (pdu == null)
            {
                throw new ArgumentNullException("pdu");
            }

            if (pdu.frag_length > context.MaxTransmitFragmentSize)
            {
                int    headerAndTrailerSize;
                byte[] stub;

                switch (pdu.PTYPE)
                {
                case RpcePacketType.Request:

                    //Get stub of request PDU
                    RpceCoRequestPdu requestPdu = pdu as RpceCoRequestPdu;

                    if (requestPdu == null)
                    {
                        throw new ArgumentException("The pdu is not a valid RpceCoRequestPdu.");
                    }

                    headerAndTrailerSize = requestPdu.GetSize();

                    if (requestPdu.auth_verifier != null)
                    {
                        //length of auth_verifier
                        headerAndTrailerSize += RpceUtility.AUTH_VERIFIER_SIZE;
                        headerAndTrailerSize += requestPdu.auth_verifier.Value.auth_value.Length;

                        //To keep stub always be padded to 16 bytes, and pdu doesnot exceed max transmit frag size.
                        int stubLength = context.MaxTransmitFragmentSize - headerAndTrailerSize;
                        headerAndTrailerSize +=
                            RpceUtility.Align(stubLength, RpceUtility.AUTH_PAD_LENGTH) - stubLength;

                        //The beginning of the verification_trailer header MUST be 4-byte aligned
                        //with respect to the beginning of the PDU.
                        headerAndTrailerSize = RpceUtility.Align(headerAndTrailerSize, RpceUtility.STUB_PAD_LENGTH);
                    }

                    stub = requestPdu.stub ?? new byte[0];

                    //Fragment
                    RpceCoRequestPdu[] requestFragmentPduList = FragmentPdu <RpceCoRequestPdu>(
                        context,
                        pdu,
                        stub.Length,
                        headerAndTrailerSize);

                    for (int i = 0; i < requestFragmentPduList.Length; i++)
                    {
                        //SHOULD set the alloc_hint field in every PDU to
                        //be the combined stub data length of all remaining fragment PDUs.
                        requestFragmentPduList[i].alloc_hint = (uint)stub.Length;
                        requestFragmentPduList[i].p_cont_id  = requestPdu.p_cont_id;
                        requestFragmentPduList[i].opnum      = requestPdu.opnum;
                        requestFragmentPduList[i].@object    = requestPdu.@object;
                        requestFragmentPduList[i].stub       = ArrayUtility.SubArray(
                            stub,
                            0,
                            Math.Min(stub.Length, context.MaxTransmitFragmentSize - headerAndTrailerSize));

                        //For request and response PDUs, where the request and response PDUs are
                        //part of a fragmented request or response and authentication is requested,
                        //the sec_trailer structure MUST be present in every fragment of the request
                        //or response.
                        requestFragmentPduList[i].AppendAuthenticationVerifier();
                        requestFragmentPduList[i].SetLength();
                        stub = ArrayUtility.SubArray(stub, requestFragmentPduList[i].stub.Length);
                    }

                    return(requestFragmentPduList);

                case RpcePacketType.Response:

                    //Get stub of response PDU
                    RpceCoResponsePdu responsePdu = pdu as RpceCoResponsePdu;

                    if (responsePdu == null)
                    {
                        throw new ArgumentException("The PDU is not a valid RpceCoResponsePdu");
                    }

                    headerAndTrailerSize = responsePdu.GetSize();

                    if (responsePdu.auth_verifier != null)
                    {
                        //length of auth_verifier
                        headerAndTrailerSize += RpceUtility.AUTH_VERIFIER_SIZE;
                        headerAndTrailerSize += responsePdu.auth_verifier.Value.auth_value.Length;

                        //To keep stub always be padded to 16 bytes, and pdu doesnot exceed max transmit frag size.
                        int stubLength = context.MaxTransmitFragmentSize - headerAndTrailerSize;
                        headerAndTrailerSize +=
                            RpceUtility.Align(stubLength, RpceUtility.AUTH_PAD_LENGTH) - stubLength;

                        //The beginning of the verification_trailer header MUST be 4-byte aligned
                        //with respect to the beginning of the PDU.
                        headerAndTrailerSize = RpceUtility.Align(headerAndTrailerSize, RpceUtility.STUB_PAD_LENGTH);
                    }

                    stub = responsePdu.stub ?? new byte[0];

                    //Fragment
                    RpceCoResponsePdu[] responseFragmentPduList = FragmentPdu <RpceCoResponsePdu>(
                        context,
                        pdu,
                        stub.Length,
                        headerAndTrailerSize);

                    for (int i = 0; i < responseFragmentPduList.Length; i++)
                    {
                        //SHOULD set the alloc_hint field in every PDU to
                        //be the combined stub data length of all remaining fragment PDUs.
                        responseFragmentPduList[i].alloc_hint   = (uint)stub.Length;
                        responseFragmentPduList[i].p_cont_id    = responsePdu.p_cont_id;
                        responseFragmentPduList[i].cancel_count = responsePdu.cancel_count;
                        responseFragmentPduList[i].reserved     = responsePdu.reserved;
                        responseFragmentPduList[i].stub         = ArrayUtility.SubArray(
                            stub,
                            0,
                            Math.Min(stub.Length, context.MaxTransmitFragmentSize - headerAndTrailerSize));

                        //For request and response PDUs, where the request and response PDUs are
                        //part of a fragmented request or response and authentication is requested,
                        //the sec_trailer structure MUST be present in every fragment of the request
                        //or response.
                        responseFragmentPduList[i].AppendAuthenticationVerifier();
                        responseFragmentPduList[i].SetLength();
                        stub = ArrayUtility.SubArray(stub, responseFragmentPduList[i].stub.Length);
                    }

                    return(responseFragmentPduList);

                case RpcePacketType.Bind:
                case RpcePacketType.BindAck:
                case RpcePacketType.AlterContext:
                case RpcePacketType.AlterContextResp:
                case RpcePacketType.Auth3:
                    //Windows RPC support version 5.0 only.
                    //Bind fragment requires RPC ver 5.1.
                    //We don't support it.
                    throw new NotSupportedException("bind/bind_ack/alt_context/alt_context_resp/auth3 PDU fragment are not supported.");

                default:
                    throw new InvalidOperationException("PDU PacketType isn't supported.");
                }
            }

            //If we cannot fragment the PDU
            return(new RpceCoPdu[] { pdu });
        }
 /// <summary>
 /// Fragment and send PDU.
 /// </summary>
 /// <param name="sessionContext">Context of the RPCE session</param>
 /// <param name="pdu">PDU to Fragment and send.</param>
 private void FragmentAndSendPdu(
     RpceServerSessionContext sessionContext,
     RpceCoPdu pdu)
 {
     if (pdu.PTYPE == RpcePacketType.Bind
         || pdu.PTYPE == RpcePacketType.BindAck
         || pdu.PTYPE == RpcePacketType.AlterContext
         || pdu.PTYPE == RpcePacketType.AlterContextResp
         || pdu.PTYPE == RpcePacketType.Auth3)
     {
         pdu.InitializeAuthenticationToken();
         pdu.SetLength();
         foreach (RpceCoPdu fragPdu in RpceUtility.FragmentPdu(sessionContext, pdu))
         {
             rpceServer.SendPdu(sessionContext, fragPdu);
         }
     }
     else
     {
         foreach (RpceCoPdu fragPdu in RpceUtility.FragmentPdu(sessionContext, pdu))
         {
             fragPdu.InitializeAuthenticationToken();
             rpceServer.SendPdu(sessionContext, fragPdu);
         }
     }
 }