Exemplo n.º 1
0
        /// <summary>
        /// update the context of smb server
        /// </summary>
        /// <param name="connection">the connection of the client</param>
        /// <param name="packet">the packet to update the context</param>
        internal void UpdateRoleContext(SmbServerConnection connection, SmbPacket packet)
        {
            if (connection == null)
            {
                return;
            }

            // packet status
            SmbStatus packetStatus = (SmbStatus)packet.SmbHeader.Status;

            // filter error packet
            if (packetStatus != SmbStatus.STATUS_SUCCESS &&
                packetStatus != SmbStatus.STATUS_MORE_PROCESSING_REQUIRED &&
                packetStatus != SmbStatus.STATUS_BUFFER_OVERFLOW)
            {
                return;
            }

            // process the response packet.
            if (packet.PacketType == SmbPacketType.BatchedResponse ||
                packet.PacketType == SmbPacketType.SingleResponse)
            {
                ResponsePacketUpdateRoleContext(connection, packet);
                return;
            }

            // process the request packet.
            if (packet.PacketType == SmbPacketType.BatchedRequest ||
                packet.PacketType == SmbPacketType.SingleRequest)
            {
                RequestPacketUpdateRoleContext(connection, packet);
                return;
            }
        }
Exemplo n.º 2
0
 /// <summary>
 /// Remove connection from the context. if connection does not exists, do nothing.
 /// </summary>
 /// <param name="connection">the connection to remove</param>
 internal void RemoveConnection(SmbServerConnection connection)
 {
     lock (this.connectionList)
     {
         if (this.connectionList.Contains(connection))
         {
             this.connectionList.Remove(connection);
         }
     }
 }
Exemplo n.º 3
0
        /// <summary>
        /// to decode stack packet from the received message bytes.
        /// the message bytes contains data without transport information
        /// </summary>
        /// <param name = "connection">the connection from which the message bytes are received. </param>
        /// <param name = "packetBytesWithoutTransport">the received message bytes to be decoded. </param>
        /// <param name = "consumedLength">the length of message bytes consumed by decoder. </param>
        /// <param name = "expectedLength">the length of message bytes the decoder expects to receive. </param>
        /// <returns>the stack packets decoded from the received message bytes. </returns>
        /// <exception cref="InvalidOperationException">
        /// thrown when packet security signature is invalid.
        /// </exception>
        private SmbPacket[] DecodePacketFromBytesWithoutTransport(
            SmbServerConnection connection, byte[] packetBytesWithoutTransport,
            out int consumedLength, out int expectedLength)
        {
            expectedLength = 0;
            consumedLength = 0;
            SmbPacket[] packets = new SmbPacket[0];

            int packetConsumedLength = 0;
            int packetExpectedLength = 0;

            // decode packets using cifs decorder.
            SmbPacket request = this.DecodeSmbRequestFromBytes(
                packetBytesWithoutTransport, out packetConsumedLength);

            // valid the signature
            if (request != null && request.SmbHeader.SecurityFeatures != 0 &&
                connection.GssApi != null && connection.GssApi.SessionKey != null)
            {
                byte[] bytesToValid = ArrayUtility.SubArray(packetBytesWithoutTransport, 0);

                // the signature offset is 14.
                byte[] zeroSignature = new byte[sizeof(ulong)];
                Array.Copy(zeroSignature, 0, bytesToValid, 14, zeroSignature.Length);

                // the signature offset is 14.
                zeroSignature = BitConverter.GetBytes((ulong)connection.ServerNextReceiveSequenceNumber);
                Array.Copy(zeroSignature, 0, bytesToValid, 14, zeroSignature.Length);

                byte[] signature = CifsMessageUtils.CreateSignature(bytesToValid, connection.GssApi.SessionKey);
                if (request.SmbHeader.SecurityFeatures != BitConverter.ToUInt64(signature, 0))
                {
                    throw new InvalidOperationException("packet security signature is invalid");
                }
            }

            // Use the decoded packet to UpdateRoleContext if it is not null and ContextUpdate is enabled:
            if (request != null)
            {
                if (this.context.IsUpdateContext)
                {
                    this.context.UpdateRoleContext(connection, request);
                }
                packets = new SmbPacket[] { request };
            }

            // update the length after decode packet.
            consumedLength += packetConsumedLength;
            expectedLength += packetExpectedLength;

            return(packets);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Add Connection to context
        /// </summary>
        /// <param name="connection">the connection</param>
        /// <exception cref="InvalidOperationException">
        /// the connection already exists in the connection list, can not add duplicate connection
        /// </exception>
        internal void AddConnection(SmbServerConnection connection)
        {
            lock (this.connectionList)
            {
                if (this.connectionList.Contains(connection))
                {
                    throw new InvalidOperationException(
                              "the connection already exists in the connection list, can not add duplicate connection");
                }

                this.connectionList.Add(connection);
            }
        }
        /// <summary>
        /// Create SMB_COM_OPEN_ANDX Server Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "fileId">
        /// This field MUST be the SMB file identifier returned by the SMB server for the file or device that was 
        /// opened or created 
        /// </param>
        /// <param name="fileType">the type of file to open</param>
        /// <param name="byteCount">
        /// This value should be set to zero.Windows-based servers may return a response where the ByteCount field is 
        /// not initialized to 0.
        /// </param>
        /// <returns>The SmbOpenAndXResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbOpenAndxResponsePacket CreateSmbComOpenResponse(
            SmbServerConnection connection,
            ushort fileId,
            ResourceTypeValue fileType,
            ushort byteCount)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbOpenAndxResponsePacket packet = new SmbOpenAndxResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_OPEN_ANDX,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_OPEN_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND;
            smbParameters.FID = fileId;
            smbParameters.FileAttrs = (SmbFileAttributes)0x00;
            smbParameters.LastWriteTime.Time = (uint)DateTime.Now.ToFileTime();
            smbParameters.DataSize = 0x0;
            smbParameters.GrantedAccess = (AccessRightsValue)0x00;
            smbParameters.FileType = fileType;
            smbParameters.DeviceState = SMB_NMPIPE_STATUS.None;
            smbParameters.Action = OpenResultsValues.OpenResult3;
            smbParameters.ServerFid = 0x00;
            smbParameters.MaximalAccessRights = connection.MaximalShareAccessRights;
            smbParameters.GuestMaximalAccessRights = connection.GuestMaximalShareAccessRights;

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_OPEN_ANDX_Response_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_OPEN_ANDX_Response_SMB_Data smbData = packet.SmbData;

            // update smbData.ByteCount
            smbData.ByteCount = byteCount;

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            return packet;
        }
        /// <summary>
        /// Create SMB_COM_NEGOTIATE response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "securityMode">
        /// An 8-bit field, indicating the security modes supported or REQUIRED by the server 
        /// </param>
        /// <param name = "maxBufferSize">
        /// The maximum size, in bytes, of the largest SMB message the server can receive. This is the size of the  
        /// SMB message that the client MAY send to the server. SMB message size includes the size of the  SMB  
        /// parameter, and data blocks. This size does not include any  transport-layer framing or other  data. The 
        /// server MUST provide a MaxBufferSize of 1024 bytes (1Kbyte) or larger. If CAP_RAW_MODE is  then the 
        /// SMB_COM_WRITE_RAW command can bypass the MaxBufferSize limit. Otherwise, SMB messages sent to  server  
        /// MUST have a total size less than or equal to the MaxBufferSize value. This includes AndX chained 
        /// </param>
        /// <param name="maxMpxCount">
        /// The maximum number of outstanding SMB operations the server supports. This value includes existing 
        /// OpLocks, the NT_TRANSACT_NOTIFY_CHANGE subcommand, and any other command that are pending on the server. 
        /// If the negotiated MaxMpxCount is one, then OpLock support MUST be disabled for this session. The 
        /// MaxMpxCount MUST be greater than zero. This parameter has no specific relationship to the 
        /// SMB_COM_READ_MPX and SMB_COM_WRITE_MPX commands. 
        /// </param>
        /// <returns>a smb negotiate response packet </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        /// <exception cref="NotImplementedException">the security package is invalid</exception>
        public virtual SmbNegotiateResponsePacket CreateSmbComNegotiateResponse(
            SmbServerConnection connection,
            SecurityModes securityMode,
            uint maxBufferSize,
            ushort maxMpxCount)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbNegotiateResponsePacket packet = new SmbNegotiateResponsePacket();

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_NEGOTIATE, connection.ProcessId, connection.MessageId, 0, 0,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_NEGOTIATE_NtLanManagerResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            ushort dialectIndex = 0x00;
            byte wordCount = 0x00;
            connection.GetPreferedDialectIndex(out dialectIndex, out wordCount);

            smbParameters.WordCount = wordCount;
            smbParameters.DialectIndex = dialectIndex;
            smbParameters.SecurityMode = securityMode;
            smbParameters.MaxBufferSize = maxBufferSize;
            smbParameters.MaxMpxCount = maxMpxCount;
            smbParameters.Capabilities = connection.ServerCapabilities;
            smbParameters.SystemTime.Time = (ulong)DateTime.Now.ToFileTime();

            // update smb data
            SMB_COM_NEGOTIATE_NtLanManagerResponse_SMB_Data smbData = packet.SmbData;

            if (connection.GssApi == null)
            {
                connection.GssApi = new SspiServerSecurityContext(
                    SecurityPackageType.Negotiate,
                    this.credential,
                    "cifs/" + Environment.MachineName,
                    ServerSecurityContextAttribute.Connection,
                    SecurityTargetDataRepresentation.SecurityNetworkDrep);
            }

            // to generate the token.
            connection.GssApi.Accept(null);

            smbData.SecurityBlob = connection.GssApi.Token;

            // update smbData.ByteCount
            smbData.ByteCount = 0;
            smbData.ByteCount += (ushort)CifsMessageUtils.GetSize<Guid>(smbData.ServerGuid);
            if (smbData.SecurityBlob != null)
            {
                smbData.ByteCount += (ushort)smbData.SecurityBlob.Length;
            }

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            return packet;
        }
        /// <summary>
        /// Create SMB_COM_LOGOFF_ANDX packet 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <returns>a SMB_COM_LOGOFF_ANDX packet </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbLogoffAndxResponsePacket CreateSmbComLogoffResponse(SmbServerConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbLogoffAndxResponsePacket packet = new SmbLogoffAndxResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_LOGOFF_ANDX,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_LOGOFF_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND;

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_LOGOFF_ANDX_Response_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_LOGOFF_ANDX_Response_SMB_Data smbData = packet.SmbData;

            // update smbData.ByteCount
            smbData.ByteCount = 0;

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            return packet;
        }
        /// <summary>
        /// Create NT_TRANSACT_SET_QUOTA Server Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <returns>The SmbNtTransSetQuotaResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbNtTransSetQuotaResponsePacket CreateNtTransSetQuotaResponse(SmbServerConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbNtTransSetQuotaResponsePacket packet = new SmbNtTransSetQuotaResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_NT_TRANSACT,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            // reserved 3 bytes.
            smbParameters.Reserved1 = new byte[3];
            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Data smbData = packet.SmbData;

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// Create NT_TRANSACT_CREATE Server Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "fileId">
        /// The SMB file identifier returned by the SMB server for the file or device that was opened or created 
        /// </param>
        /// <param name = "createAction">The action taken. This field MUST be interpreted as follows </param>
        /// <param name = "extFileAttributes">Extended attributes and flags for this file or directory </param>
        /// <param name = "fileType">The file type </param>
        /// <param name = "isDirectory">
        /// A value that indicates whether this is a directory. MUST be nonzero when this is a directory 
        /// </param>
        /// <returns>The SmbNtTransactCreateResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbNtTransactCreateResponsePacket CreateNtTransCreateResponse(
            SmbServerConnection connection,
            ushort fileId,
            uint createAction,
            uint extFileAttributes,
            FileTypeValue fileType,
            bool isDirectory)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbNtTransactCreateResponsePacket packet = new SmbNtTransactCreateResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_NT_TRANSACT,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            // reserved 3 bytes.
            smbParameters.Reserved1 = new byte[3];
            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Data smbData = packet.SmbData;

            // update smbData.ByteCount
            smbData.ByteCount = 0;

            // update nt transaction parameters
            NT_TRANSACT_CREATE_Response_NT_Trans_Parameters ntTransPamameters = packet.NtTransParameters;
            ntTransPamameters.FID = fileId;
            ntTransPamameters.CreateAction = (NtTransactCreateActionValues)createAction;
            ntTransPamameters.ExtFileAttributes = (SMB_EXT_FILE_ATTR)extFileAttributes;
            ntTransPamameters.ResourceType = fileType;
            ntTransPamameters.Directory = (byte)(isDirectory ? 1 : 0);

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;
            packet.NtTransParameters = ntTransPamameters;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        ///  Send bytes to specific connected client.
        /// </summary>
        /// <param name="bytes">the bytes to send to client</param>
        /// <param name="connection">the connection identified client</param>
        /// <exception cref="ArgumentNullException">the connection is null</exception>
        public virtual void SendBytes(byte[] bytes, SmbServerConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            this.transport.SendBytes(connection.Identity, bytes);
        }
        /// <summary>
        /// Create  SMB_COM_TREE_CONNECT_ANDX Server Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "treeId">
        /// This field identifies the subdirectory (or tree) (also referred to as a share in this document) on the 
        /// server that the client is accessing 
        /// </param>
        /// <param name = "service">The Service field indicates the type of resource the client is accessing </param>
        /// <param name = "nativeFileSystem">
        /// The name of the file system on the local resource that is being connected to 
        /// </param>
        /// <returns>The SmbTreeConnectAndXResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbTreeConnectAndxResponsePacket CreateSmbComTreeConnectResponse(
            SmbServerConnection connection,
            ushort treeId,
            string service,
            string nativeFileSystem)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbTreeConnectAndxResponsePacket packet = new SmbTreeConnectAndxResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_TREE_CONNECT_ANDX,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, treeId,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_TREE_CONNECT_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND;
            smbParameters.OptionalSupport = connection.OptionalSupport;
            smbParameters.MaximalShareAccessRights = connection.MaximalShareAccessRights;
            smbParameters.GuestMaximalShareAccessRights = connection.GuestMaximalShareAccessRights;

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TREE_CONNECT_ANDX_Response_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_TREE_CONNECT_ANDX_Response_SMB_Data smbData = packet.SmbData;

            smbData.Service = CifsMessageUtils.ToSmbStringBytes(service, false);
            smbData.NativeFileSystem = CifsMessageUtils.ToSmbStringBytes(nativeFileSystem, connection.Capability.IsUnicode);

            // update smbData.ByteCount
            smbData.ByteCount = 0;
            if (smbData.Service != null)
            {
                smbData.ByteCount += (ushort)smbData.Service.Length;
            }
            if (smbData.NativeFileSystem != null)
            {
                smbData.ByteCount += (ushort)smbData.NativeFileSystem.Length;
            }

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            return packet;
        }
        /// <summary>
        /// Create  SMB_COM_SESSION_SETUP_ANDX Server response packet 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "uid">
        /// the valid session id, must be response by server of the session setup request. 
        /// </param>
        /// <param name = "action">A 16-bit field. The two lowest order bits have been defined </param>
        /// <returns>The SmbSessionSetupAndXResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbSessionSetupAndxResponsePacket CreateSmbComSessionSetupResponse(
            SmbServerConnection connection,
            ushort uid,
            ActionValues action
            )
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbSessionSetupAndxResponsePacket packet = new SmbSessionSetupAndxResponsePacket();

            // create smb packet header
            SmbHeader smbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_SESSION_SETUP_ANDX, connection.ProcessId, connection.MessageId, uid, 0,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND;
            smbParameters.Action = action;

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            #region Generate security blob according to client request.

            byte[] securityBlob = null;

            SmbSessionSetupAndxRequestPacket request =
                connection.GetRequestPacket(connection.MessageId) as SmbSessionSetupAndxRequestPacket;

            if (request != null)
            {
                connection.GssApi.Accept(request.SmbData.SecurityBlob);

                securityBlob = connection.GssApi.Token;

                if (connection.GssApi.NeedContinueProcessing)
                {
                    unchecked
                    {
                        smbHeader.Status = (uint)SmbStatus.STATUS_MORE_PROCESSING_REQUIRED;
                    }
                }
            }

            #endregion

            smbParameters.SecurityBlobLength = (ushort)securityBlob.Length;

            // update smb data
            SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Data smbData = packet.SmbData;

            smbData.SecurityBlob = securityBlob;
            if (connection.Capability.IsUnicode
                && (smbParameters.SecurityBlobLength % SmbCapability.TWO_BYTES_ALIGN) == 0)
            {
                smbData.Pad = new byte[1];
            }
            else
            {
                smbData.Pad = new byte[0];
            }
            smbData.NativeOS = CifsMessageUtils.ToSmbStringBytes(
                Environment.OSVersion.VersionString, connection.Capability.IsUnicode);
            smbData.NativeLanMan = CifsMessageUtils.ToSmbStringBytes(
                Environment.OSVersion.VersionString, connection.Capability.IsUnicode);
            smbData.PrimaryDomain = CifsMessageUtils.ToSmbStringBytes(
                Environment.UserDomainName, connection.Capability.IsUnicode);

            // update smbData.ByteCount
            smbData.ByteCount = 0;
            smbData.ByteCount += (ushort)smbData.SecurityBlob.Length;
            smbData.ByteCount += (ushort)smbData.Pad.Length;
            smbData.ByteCount += (ushort)smbData.NativeOS.Length;
            smbData.ByteCount += (ushort)smbData.NativeLanMan.Length;
            smbData.ByteCount += (ushort)smbData.PrimaryDomain.Length;

            // store the parameters and data to packet.
            packet.SmbHeader = smbHeader;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            return packet;
        }
        /// <summary>
        /// Create  SMB_COM_SESSION_SETUP_ANDX Server response packet 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "uid">
        /// the valid session id, must be response by server of the session setup request. 
        /// </param>
        /// <param name = "action">A 16-bit field. The two lowest order bits have been defined </param>
        /// <returns>The SmbSessionSetupAndXResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbSessionSetupImplicitNtlmAndxResponsePacket CreateSmbComSessionSetupImplicitNtlmResponse(
            SmbServerConnection connection,
            ushort uid,
            ActionValues action
            )
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            Cifs.SmbSessionSetupAndxResponsePacket packet = new Cifs.SmbSessionSetupAndxResponsePacket();

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_SESSION_SETUP_ANDX, connection.ProcessId, connection.MessageId, uid, 0,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            Cifs.SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND;
            smbParameters.Action = action;

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<Cifs.SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            Cifs.SMB_COM_SESSION_SETUP_ANDX_Response_SMB_Data smbData = packet.SmbData;

            if (connection.Capability.IsUnicode)
            {
                smbData.Pad = new byte[1];
            }
            else
            {
                smbData.Pad = new byte[0];
            }
            smbData.NativeOS = CifsMessageUtils.ToSmbStringBytes(
                Environment.OSVersion.VersionString, connection.Capability.IsUnicode);
            smbData.NativeLanMan = CifsMessageUtils.ToSmbStringBytes(
                Environment.OSVersion.VersionString, connection.Capability.IsUnicode);
            smbData.PrimaryDomain = CifsMessageUtils.ToSmbStringBytes(
                Environment.UserDomainName, connection.Capability.IsUnicode);

            // update smbData.ByteCount
            smbData.ByteCount = 0;
            smbData.ByteCount += (ushort)smbData.Pad.Length;
            smbData.ByteCount += (ushort)smbData.NativeOS.Length;
            smbData.ByteCount += (ushort)smbData.NativeLanMan.Length;
            smbData.ByteCount += (ushort)smbData.PrimaryDomain.Length;

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            return new SmbSessionSetupImplicitNtlmAndxResponsePacket(packet);
        }
Exemplo n.º 14
0
        /// <summary>
        /// update the context with request packet
        /// </summary>
        /// <param name="connection">the connection of endpoint</param>
        /// <param name="packet">the packet to update the context</param>
        private void RequestPacketUpdateRoleContext(SmbServerConnection connection, SmbPacket packet)
        {
            connection.AddRequestPacket(packet);

            // update the message id
            connection.MessageId = packet.SmbHeader.Mid;

            // update the process id
            connection.ProcessId  = (uint)(packet.SmbHeader.PidHigh << 16);
            connection.ProcessId += packet.SmbHeader.PidLow;

            // update the message sign sequence number
            if (packet.SmbHeader.SecurityFeatures != 0 &&
                connection.GssApi != null && connection.GssApi.SessionKey != null)
            {
                if (packet.SmbHeader.Command == SmbCommand.SMB_COM_NT_CANCEL)
                {
                    connection.ServerNextReceiveSequenceNumber++;
                }
                else
                {
                    ServerSendSequenceNumberKey key = new ServerSendSequenceNumberKey();

                    key.PidHigh = packet.SmbHeader.PidHigh;
                    key.PidLow  = packet.SmbHeader.PidLow;
                    key.Mid     = packet.SmbHeader.Mid;

                    connection.ServerSendSequenceNumber[key]    = connection.ServerNextReceiveSequenceNumber + 1;
                    connection.ServerNextReceiveSequenceNumber += 2;
                }
            }

            // process each special command
            switch (packet.SmbHeader.Command)
            {
            case SmbCommand.SMB_COM_NEGOTIATE:
                SmbNegotiateRequestPacket request = packet as SmbNegotiateRequestPacket;
                byte[] dialects = request.SmbData.Dialects;

                List <string> negotiateDialects = new List <string>();

                for (int i = 0; i < dialects.Length; i++)
                {
                    if (dialects[i] == 0x02)
                    {
                        continue;
                    }

                    string dialect = "";

                    for (; i < dialects.Length && dialects[i] != 0x00; i++)
                    {
                        dialect += (char)dialects[i];
                    }

                    negotiateDialects.Add(dialect);
                }

                connection.NegotiatedDialects = negotiateDialects.ToArray();

                break;

            case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:

                // down-case the packet
                Cifs.SmbTreeConnectAndxRequestPacket treeconnect = packet as Cifs.SmbTreeConnectAndxRequestPacket;

                // get the specified session.
                SmbServerSession treeconnectSession = connection.GetSession((ushort)treeconnect.SmbHeader.Uid);
                if (treeconnectSession == null)
                {
                    return;
                }

                // Calculate the one-way hash
                byte[] sessionKey = FileServiceUtils.ProtectSessionKey(treeconnectSession.SessionKey);

                // update the session key state.
                treeconnectSession.SessionKeyState = SessionKeyStateValue.Available;

                // if server does not support SMB_EXTENDED_SIGNATURES, return.
                if (SmbClientTreeConnect.TreeConnectAndxExtendedSignatures !=
                    (treeconnect.SmbParameters.Flags & SmbClientTreeConnect.TreeConnectAndxExtendedSignatures))
                {
                    return;
                }

                treeconnectSession.SessionKey = sessionKey;

                break;

            default:
                return;
            }

            return;
        }
Exemplo n.º 15
0
        /// <summary>
        /// update the context with response packet
        /// </summary>
        /// <param name="connection">the connection of endpoint</param>
        /// <param name="packet">the packet to update the context</param>
        private void ResponsePacketUpdateRoleContext(SmbServerConnection connection, SmbPacket packet)
        {
            SmbHeader smbHeader = packet.SmbHeader;

            SmbPacket requestPacket = connection.GetRequestPacket(smbHeader.Mid);

            if (requestPacket == null)
            {
                return;
            }

            switch (smbHeader.Command)
            {
            case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:
                if (smbHeader.Uid == 0)
                {
                    break;
                }
                else
                {
                    SmbServerSession session = new SmbServerSession();
                    session.Uid = smbHeader.Uid;
                    session.AuthenticationState = SessionState.Complete;
                    session.Connection          = connection;
                    session.SessionKey          = connection.GssApi.SessionKey;

                    connection.AddSession(session);
                }

                break;

            case SmbCommand.SMB_COM_LOGOFF_ANDX:
                if (requestPacket.SmbHeader.Uid == 0)
                {
                    break;
                }
                else
                {
                    connection.RemoveSession(connection.GetSession(requestPacket.SmbHeader.Uid));
                }

                break;

            case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:
            {
                SmbTreeConnectAndxRequestPacket request = requestPacket as SmbTreeConnectAndxRequestPacket;

                SmbServerTreeConnect treeconnect = new SmbServerTreeConnect();
                treeconnect.TreeId  = smbHeader.Tid;
                treeconnect.Session = connection.GetSession(smbHeader.Uid);
                if (treeconnect.Session == null)
                {
                    break;
                }
                if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) != 0)
                {
                    treeconnect.Path = Encoding.Unicode.GetString(request.SmbData.Path);
                }
                else
                {
                    treeconnect.Path = Encoding.ASCII.GetString(request.SmbData.Path);
                }
                treeconnect.Path = treeconnect.Path.TrimEnd('\0');
                treeconnect.Session.AddTreeConnect(treeconnect);
            }

            break;

            case SmbCommand.SMB_COM_TREE_DISCONNECT:
                if (requestPacket.SmbHeader.Uid != 0)
                {
                    SmbServerSession session = connection.GetSession(requestPacket.SmbHeader.Uid);
                    if (session == null)
                    {
                        break;
                    }
                    session.RemoveTreeConnect(session.GetTreeConnect(requestPacket.SmbHeader.Tid));
                }

                break;

            case SmbCommand.SMB_COM_NT_CREATE_ANDX:
            {
                SmbNtCreateAndxResponsePacket response = packet as SmbNtCreateAndxResponsePacket;
                SmbNtCreateAndxRequestPacket  request  = requestPacket as SmbNtCreateAndxRequestPacket;

                SmbServerOpen open = new SmbServerOpen();
                open.SmbFid   = response.SmbParameters.FID;
                open.PathName = SmbMessageUtils.GetString(request.SmbData.FileName,
                                                          SmbFlags2.SMB_FLAGS2_UNICODE == (request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE));
                open.PathName    = open.PathName.TrimEnd('\0');
                open.Session     = connection.GetSession(smbHeader.Uid);
                open.TreeConnect = connection.GetTreeConnect(smbHeader.Tid);
                if (open.TreeConnect == null)
                {
                    break;
                }
                open.TreeConnect.AddOpen(open);
            }

            break;

            case SmbCommand.SMB_COM_OPEN_ANDX:
            {
                SmbOpenAndxResponsePacket response = packet as SmbOpenAndxResponsePacket;
                SmbOpenAndxRequestPacket  request  = requestPacket as SmbOpenAndxRequestPacket;

                SmbServerOpen open = new SmbServerOpen();
                open.SmbFid   = response.SmbParameters.FID;
                open.PathName = SmbMessageUtils.GetString(request.SmbData.FileName,
                                                          SmbFlags2.SMB_FLAGS2_UNICODE == (request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE));
                open.Session     = connection.GetSession(smbHeader.Uid);
                open.TreeConnect = connection.GetTreeConnect(smbHeader.Tid);
                if (open.TreeConnect == null)
                {
                    break;
                }
                open.TreeConnect.AddOpen(open);
            }

            break;

            case SmbCommand.SMB_COM_CLOSE:
            {
                SmbCloseRequestPacket closeRequest = requestPacket as SmbCloseRequestPacket;

                SmbServerTreeConnect treeconnect = connection.GetTreeConnect(requestPacket.SmbHeader.Tid);
                if (treeconnect == null)
                {
                    break;
                }

                treeconnect.RemoveOpen(treeconnect.GetOpen(closeRequest.SmbParameters.FID));
            }

            break;

            default:
                break;
            }

            connection.RemoveRequestPacket(packet);
        }
 /// <summary>
 /// Remove connection from the context. if connection does not exists, do nothing.
 /// </summary>
 /// <param name="connection">the connection to remove</param>
 internal void RemoveConnection(SmbServerConnection connection)
 {
     lock (this.connectionList)
     {
         if (this.connectionList.Contains(connection))
         {
             this.connectionList.Remove(connection);
         }
     }
 }
        /// <summary>
        /// update the context with request packet
        /// </summary>
        /// <param name="connection">the connection of endpoint</param>
        /// <param name="packet">the packet to update the context</param>
        private void RequestPacketUpdateRoleContext(SmbServerConnection connection, SmbPacket packet)
        {
            connection.AddRequestPacket(packet);

            // update the message id
            connection.MessageId = packet.SmbHeader.Mid;

            // update the process id
            connection.ProcessId = (uint)(packet.SmbHeader.PidHigh << 16);
            connection.ProcessId += packet.SmbHeader.PidLow;

            // update the message sign sequence number
            if (packet.SmbHeader.SecurityFeatures != 0
                && connection.GssApi != null && connection.GssApi.SessionKey != null)
            {
                if (packet.SmbHeader.Command == SmbCommand.SMB_COM_NT_CANCEL)
                {
                    connection.ServerNextReceiveSequenceNumber++;
                }
                else
                {
                    ServerSendSequenceNumberKey key = new ServerSendSequenceNumberKey();

                    key.PidHigh = packet.SmbHeader.PidHigh;
                    key.PidLow = packet.SmbHeader.PidLow;
                    key.Mid = packet.SmbHeader.Mid;

                    connection.ServerSendSequenceNumber[key] = connection.ServerNextReceiveSequenceNumber + 1;
                    connection.ServerNextReceiveSequenceNumber += 2;
                }
            }

            // process each special command
            switch (packet.SmbHeader.Command)
            {
                case SmbCommand.SMB_COM_NEGOTIATE:
                    SmbNegotiateRequestPacket request = packet as SmbNegotiateRequestPacket;
                    byte[] dialects = request.SmbData.Dialects;

                    List<string> negotiateDialects = new List<string>();

                    for (int i = 0; i < dialects.Length; i++)
                    {
                        if (dialects[i] == 0x02)
                        {
                            continue;
                        }

                        string dialect = "";

                        for (; i < dialects.Length && dialects[i] != 0x00; i++)
                        {
                            dialect += (char)dialects[i];
                        }

                        negotiateDialects.Add(dialect);
                    }

                    connection.NegotiatedDialects = negotiateDialects.ToArray();

                    break;

                case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:

                    // down-case the packet
                    Cifs.SmbTreeConnectAndxRequestPacket treeconnect = packet as Cifs.SmbTreeConnectAndxRequestPacket;

                    // get the specified session.
                    SmbServerSession treeconnectSession = connection.GetSession((ushort)treeconnect.SmbHeader.Uid);
                    if (treeconnectSession == null)
                    {
                        return;
                    }

                    // Calculate the one-way hash
                    byte[] sessionKey = FileServiceUtils.ProtectSessionKey(treeconnectSession.SessionKey);

                    // update the session key state.
                    treeconnectSession.SessionKeyState = SessionKeyStateValue.Available;

                    // if server does not support SMB_EXTENDED_SIGNATURES, return.
                    if (SmbClientTreeConnect.TreeConnectAndxExtendedSignatures !=
                        (treeconnect.SmbParameters.Flags & SmbClientTreeConnect.TreeConnectAndxExtendedSignatures))
                    {
                        return;
                    }

                    treeconnectSession.SessionKey = sessionKey;

                    break;

                default:
                    return;
            }

            return;
        }
        /// <summary>
        /// Create SMB_ERROR response, including only header portion 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "status">Status of the packet </param>
        /// <param name = "command">The operation code that this SMB is requesting or responding to </param>
        /// <returns>The CreateSmbErrorResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbErrorResponsePacket CreateSmbErrorResponse(
            SmbServerConnection connection,
            uint status,
            SmbCommand command)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbErrorResponsePacket packet = new SmbErrorResponsePacket();

            // create smb packet header
            SmbHeader smbHeader = CifsMessageUtils.CreateSmbHeader(
                command, connection.ProcessId, connection.MessageId, 0x00, 0x00,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);
            smbHeader.Status = status;

            packet.SmbHeader = smbHeader;

            return packet;
        }
        /// <summary>
        /// Expect a packet from a connected client
        /// </summary>
        /// <param name="timeout">waiting time</param>
        /// <param name="connection">the remote client who sent this packet</param>
        /// <returns>received smb the packet</returns>
        /// <exception cref="InvalidOperationException">
        /// The transport is null for not started. Please invoke Start() first
        /// </exception>
        /// <exception cref="InvalidOperationException">Unknown object received from transport.</exception>
        public virtual SmbPacket ExpectPacket(TimeSpan timeout, out SmbServerConnection connection)
        {
            if (this.transport == null)
            {
                throw new InvalidOperationException(
                    "The transport is null for not started. Please invoke Start() first.");
            }

            TransportEvent transportEvent = this.transport.ExpectTransportEvent(timeout);

            if (transportEvent.EventType == EventType.Connected)
            {
                connection = new SmbServerConnection();
                connection.Identity = transportEvent.EndPoint;
                this.context.AddConnection(connection);
                return null;
            }
            else if (transportEvent.EventType == EventType.ReceivedPacket)
            {
                connection = this.context.GetConnection(transportEvent.EndPoint);

                return transportEvent.EventObject as SmbPacket;
            }
            else if (transportEvent.EventType == EventType.Disconnected)
            {
                connection = this.context.GetConnection(transportEvent.EndPoint);
                this.context.RemoveConnection(connection);
                return null;
            }
            else if (transportEvent.EventType == EventType.Exception)
            {
                throw transportEvent.EventObject as Exception;
            }
            else
            {
                throw new InvalidOperationException("Unknown object received from transport.");
            }
        }
        /// <summary>
        /// Create  TRANS2_FIND_NEXT2 Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "searchCount">search count </param>
        /// <param name = "isEndOfSearch">whether end of search </param>
        /// <param name = "eaErrorOffset">eaError Offset </param>
        /// <param name = "lastNameOffset">last name offset </param>
        /// <param name = "data">data specified by [CIFS] </param>
        /// <returns>The SmbTrans2FindNext2ResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbTrans2FindNext2ResponsePacket CreateTrans2FindNext2Response(
            SmbServerConnection connection,
            ushort searchCount,
            bool isEndOfSearch,
            ushort eaErrorOffset,
            ushort lastNameOffset,
            object data)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbTrans2FindNext2ResponsePacket packet = new SmbTrans2FindNext2ResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_TRANSACTION2,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_TRANSACTION2_FinalResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION2_FinalResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_TRANSACTION2_FinalResponse_SMB_Data smbData = packet.SmbData;

            // update trans2 param
            TRANS2_FIND_NEXT2_Response_Trans2_Parameters trans2Parameters = packet.Trans2Parameters;

            trans2Parameters.SearchCount = searchCount;
            trans2Parameters.EndOfSearch = (ushort)(isEndOfSearch ? 1 : 0);
            trans2Parameters.EaErrorOffset = eaErrorOffset;
            trans2Parameters.LastNameOffset = lastNameOffset;

            // update trans2 data
            TRANS2_FIND_NEXT2_Response_Trans2_Data trans2Data = packet.Trans2Data;

            trans2Data.Data = data;

            // store the parameters and data to packet.
            packet.Trans2Parameters = trans2Parameters;
            packet.Trans2Data = trans2Data;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// Send packet to a specific connected client
        /// </summary>
        /// <param name="connection">connection to remote client</param>
        /// <param name="packet">the smb packet</param>
        /// <exception cref="ArgumentNullException">smbPacket</exception>
        /// <exception cref="ArgumentNullException">endpoint</exception>
        /// <exception cref="InvalidOperationException">
        /// The transport is null for not started. Please invoke Start() first
        /// </exception>
        public virtual void SendPacket(SmbPacket packet, SmbServerConnection connection)
        {
            if (packet == null)
            {
                throw new ArgumentNullException("packet");
            }

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

            if (this.transport == null)
            {
                throw new InvalidOperationException(
                    "The transport is null for not started. Please invoke Start() first.");
            }

            SmbPacket smbPacket = packet as SmbPacket;
            if (smbPacket != null && this.context.IsUpdateContext)
            {
                this.context.UpdateRoleContext(connection, smbPacket);
            }

            switch(this.transportType)
            {
                case TransportType.TCP:
                    // send packet through the direct tcp
                    this.transport.SendPacket(connection.Identity, new SmbDirectTcpPacket(packet));

                    break;

                case TransportType.NetBIOS:
                    // send packet through netbios over Tcp
                    this.transport.SendPacket(connection.Identity, smbPacket);

                    break;

                default:
                    break;
            }
        }
        /// <summary>
        /// Create FSCTL_SRV_ENUMERATE_SNAPSHOTS Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name="numberOfSnapShots">This value MUST be the number of snapshots for the volume. </param>
        /// <param name = "snapShotData">
        /// A concatenated set of snapshot names. Each snapshot name MUST be formatted as a null-terminated array of 
        /// 16-bit Unicode characters. The concatenated list MUST be terminated by two 16-bit Unicode NULL characters 
        /// </param>
        /// <returns>The SmbNtTransFsctlSrvEnumerateSnapshotsResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbNtTransFsctlSrvEnumerateSnapshotsResponsePacket CreateFsctlSrvEnumerateSnapshotsResponse(
            SmbServerConnection connection,
            uint numberOfSnapShots,
            params string[] snapShotData)
        {
            if (snapShotData == null)
            {
                snapShotData = new string[0];
            }

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

            SmbNtTransFsctlSrvEnumerateSnapshotsResponsePacket packet = new SmbNtTransFsctlSrvEnumerateSnapshotsResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_NT_TRANSACT,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            // reserved 3 bytes.
            smbParameters.Reserved1 = new byte[3];
            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Data smbData = packet.SmbData;

            // update trans2 data
            NT_TRANSACT_ENUMERATE_SNAPSHOTS_Response_NT_Trans_Data ntTransData = packet.NtTransData;
            ntTransData.NumberOfSnapShots = numberOfSnapShots;
            ntTransData.NumberOfSnapShotsReturned = (uint)snapShotData.Length;
            // initiallize to zero
            ntTransData.SnapShotArraySize = 0x00;
            ntTransData.snapShotMultiSZ = new byte[ntTransData.SnapShotArraySize];

            // update snapshots
            packet.SnapShots = new Collection<string>(snapShotData);

            // store the parameters and data to packet.
            packet.NtTransData = ntTransData;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// Create NT_TRANSACT_QUERY_QUOTA Server Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "quotaInfo">quota information </param>
        /// <returns>The SmbNtTransQueryQuotaResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbNtTransQueryQuotaResponsePacket CreateNtTransQueryQuotaResponse(
            SmbServerConnection connection,
            params NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data[] quotaInfo)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbNtTransQueryQuotaResponsePacket packet = new SmbNtTransQueryQuotaResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_NT_TRANSACT,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            // reserved 3 bytes.
            smbParameters.Reserved1 = new byte[3];
            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_NT_TRANSACT_SuccessResponse_SMB_Data smbData = packet.SmbData;

            // update query quota data
            Collection<NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data> ntTransDataList =
                new Collection<NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data>();
            if (quotaInfo != null)
            {
                ntTransDataList = new Collection<NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data>(quotaInfo);
            }

            // update trans2 param
            NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Parameters ntTransParameters = packet.NtTransParameters;

            foreach (NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data data in ntTransDataList)
            {
                ntTransParameters.QuotaDataSize += (uint)
                    CifsMessageUtils.GetSize<NT_TRANSACT_QUERY_QUOTA_Response_NT_Trans_Data>(data);
            }

            // store the parameters and data to packet.
            packet.NtTransParameters = ntTransParameters;
            packet.NtTransDataList = ntTransDataList;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// Create TRANS2_SET_PATH_INFORMATION Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <returns>The SmbTrans2SetPathInformationResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbTrans2SetPathInformationResponsePacket CreateTrans2SetPathInformationResponse(SmbServerConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbTrans2SetPathInformationResponsePacket packet = new SmbTrans2SetPathInformationResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_TRANSACTION2,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_TRANSACTION2_FinalResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION2_FinalResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_TRANSACTION2_FinalResponse_SMB_Data smbData = packet.SmbData;

            // update trans2 param
            TRANS2_SET_PATH_INFORMATION_Response_Trans2_Parameters trans2Parameters = packet.Trans2Parameters;

            // store the parameters and data to packet.
            packet.Trans2Parameters = trans2Parameters;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// Create SMB_COM_CLOSE packet 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <returns>a SMB_COM_CLOSE packet </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbCloseResponsePacket CreateSmbComCloseResponse(SmbServerConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbCloseResponsePacket packet = new SmbCloseResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_CLOSE,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_CLOSE_Response_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.WordCount = 0;

            // update smb data
            SMB_COM_CLOSE_Response_SMB_Data smbData = packet.SmbData;

            // update smbData.ByteCount
            smbData.ByteCount = 0;

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            return packet;
        }
        /// <summary>
        /// Create Named Rap Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name="win32ErrorCode">
        /// This MUST be a 16-bit unsigned integer. It contains a Win32 error code representing the result of the
        /// Remote Administration Protocol command. The following table lists error codes that have particular meaning
        /// to the Remote Administration Protocol, as indicated in this specification.
        /// </param>
        /// <param name="converter">
        /// This field MUST contain a 16-bit signed integer, which a client MUST subtract from the string offset
        /// contained in the low 16 bits of a variable-length field in the Remote Administration Protocol response
        /// buffer. This is to derive the actual byte offset from the start of the response buffer for that field.
        /// </param>
        /// <param name="rapOutParams">
        /// If present, this structure MUST contain the response information for the Remote Administration Protocol
        /// command in the corresponding Remote Administration Protocol request message. Certain RAPOpcodes require
        /// a RAPOutParams structure; for Remote Administration Protocol commands that require a RAPOutParams
        /// structure, see sections 2.5.5, 2.5.6, 2.5.7, 2.5.8, and 2.5.9.
        /// </param>
        /// <param name="rapOutData">
        /// This is the response data for the Remote Administration Protocol operation. The content of the RAPOutData
        /// structure varies according to the Remote Administration Protocol command and the parameters of each Remote
        /// Administration Protocol command. See Remote Administration Protocol responses for each Remote
        /// Administration Protocol command in sections 2.5.5, 2.5.6, 2.5.7, 2.5.8, and 2.5.9.
        /// </param>
        /// <returns>a Named Rap write response </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbTransRapResponsePacket CreateTransNamedRapResponse(
            SmbServerConnection connection,
            ushort win32ErrorCode,
            ushort converter,
            byte[] rapOutParams,
            byte[] rapOutData)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbTransRapResponsePacket packet = new SmbTransRapResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_TRANSACTION,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData;

            // update trans parameters
            TRANSACTION_Rap_Response_Trans_Parameters transParameters = packet.TransParameters;
            transParameters.Win32ErrorCode = win32ErrorCode;
            transParameters.Converter = converter;
            transParameters.RAPOutParams = rapOutParams;

            // update trans data
            TRANSACTION_Rap_Response_Trans_Data transData = packet.TransData;
            transData.RAPOutData = rapOutData;

            // store the parameters and data to packet.
            packet.TransParameters = transParameters;
            packet.TransData = transData;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// Create SMB_COM_NEGOTIATE response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "securityMode">
        /// An 8-bit field, indicating the security modes supported or REQUIRED by the server 
        /// </param>
        /// <param name = "maxBufferSize">
        /// The maximum size, in bytes, of the largest SMB message the servercan receive. This is the size of the  SMB 
        /// message that the clientMAY send to the server. SMB message size includes the size of the SMB header,  and 
        /// data blocks. This size does not include any transport-layer framing or other transport-layer data.  server 
        /// MUSTprovide a MaxBufferSize of 1024 bytes (1Kbyte) or larger.If CAP_RAW_MODE is negotiated, then  
        /// SMB_COM_WRITE_RAW commandcan bypass the MaxBufferSize limit. Otherwise, SMB messages sent to the server  
        /// have a total size less than or equal to the MaxBufferSize value.This includes AndX chained  default 
        /// MaxBufferSize on Windows NT server is 4356 bytes(4KB + 260Bytes) if the server has 512MB of  or less. If 
        /// the server has more than 512MB of memory, then the default MaxBufferSize is 16644 bytes (16KB  260Bytes). 
        /// Windows NT servers always use a MaxBufferSize value that is a multiple of four (4). The  can be configured 
        /// through the following registry setting: 
        /// </param>
        /// <param name="maxMpxCount">
        /// The maximum number of outstanding SMB operations the server
        /// supports. This value includes existing OpLocks, 
        /// the NT_TRANSACT_NOTIFY_CHANGE subcommand, and any other command 
        /// that are pending on the server. If the negotiated MaxMpxCount is one, 
        /// then OpLock support MUST be disabled for this session. The MaxMpxCount
        /// MUST be greater than zero. This parameter has no specific 
        /// relationship to the SMB_COM_READ_MPX and SMB_COM_WRITE_MPX commands. 
        /// </param>
        /// <returns>a smb implicit ntlm negotiate response packet </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbNegotiateImplicitNtlmResponsePacket CreateSmbComNegotiateImplicitNtlmResponse(
            SmbServerConnection connection,
            SecurityModes securityMode,
            uint maxBufferSize,
            ushort maxMpxCount)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            Cifs.SmbNegotiateResponsePacket packet = new Cifs.SmbNegotiateResponsePacket();

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_NEGOTIATE, connection.ProcessId, connection.MessageId, 0, 0,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            Cifs.SMB_COM_NEGOTIATE_NtLanManagerResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            ushort dialectIndex = 0x00;
            byte wordCount = 0x00;
            connection.GetPreferedDialectIndex(out dialectIndex, out wordCount);

            smbParameters.WordCount = wordCount;
            smbParameters.DialectIndex = dialectIndex;
            smbParameters.SecurityMode = securityMode;
            smbParameters.MaxBufferSize = maxBufferSize;
            smbParameters.MaxMpxCount = maxMpxCount;
            smbParameters.Capabilities = (Cifs.Capabilities)connection.ServerCapabilities;
            smbParameters.SystemTime.Time = (ulong)connection.SystemTime;
            smbParameters.ChallengeLength = (byte)connection.NtlmEncryptionKey.Length;

            // update smb data
            Cifs.SMB_COM_NEGOTIATE_NtLanManagerResponse_SMB_Data smbData = packet.SmbData;

            smbData.Challenge = connection.NtlmEncryptionKey;

            // update smbData.ByteCount
            smbData.ByteCount = 0;
            if (smbData.Challenge != null)
            {
                smbData.ByteCount += (ushort)smbData.Challenge.Length;
            }
            if (smbData.DomainName != null)
            {
                smbData.ByteCount += (ushort)smbData.DomainName.Length;
            }

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            return new SmbNegotiateImplicitNtlmResponsePacket(packet);
        }
        /// <summary>
        /// Create TRANS_PEEK_NMPIPE Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "readDataAvailable">
        /// The first USHORT value (as specified in [MS-DTYP] section 2.2.57) in the Parameter buffer contains the 
        /// total number of bytes available to be read from the pipe 
        /// </param>
        /// <param name = "messageByteLength">
        /// If the named pipe is a message mode pipe, this MUST be set to the number of bytes remaining in the message 
        /// that was peeked (the number of bytes in the message minus the number of bytes read). If the entire message 
        /// was read, this value is 0. If the named pipe is a byte mode pipe, this value MUST be set to 0 
        /// </param>
        /// <param name = "namedPipeState">The status of the named pipe </param>
        /// <param name = "peekedData">The data buffer contains the data read from the named pipe </param>
        /// <returns>The SmbTransPeekNmpipeResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbTransPeekNmpipeResponsePacket CreateTransPeekNmpipeResponse(
            SmbServerConnection connection,
            ushort readDataAvailable,
            ushort messageByteLength,
            NamedPipePeekState namedPipeState,
            byte[] peekedData)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbTransPeekNmpipeResponsePacket packet = new SmbTransPeekNmpipeResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_TRANSACTION,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData;

            // update trans param
            TRANS_PEEK_NMPIPE_Response_Trans_Parameters transParameters = packet.TransParameters;

            transParameters.ReadDataAvailable = readDataAvailable;
            transParameters.MessageBytesLength = messageByteLength;
            transParameters.NamedPipeState = (ushort)namedPipeState;

            // update trans data
            TRANS_PEEK_NMPIPE_Response_Trans_Data transData = packet.TransData;

            transData.ReadData = peekedData;

            // store the parameters and data to packet.
            packet.TransParameters = transParameters;
            packet.TransData = transData;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// Create SMB_COM_NT_CREATE_ANDX Server Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "fileId">
        /// The SMB file identifier returned by the SMB server for the file or device that was opened or created 
        /// </param>
        /// <param name = "createAction">The action taken. This field MUST be interpreted as follows </param>
        /// <param name = "extFileAttributes">Extended attributes and flags for this file or directory </param>
        /// <param name = "fileType">The file type </param>
        /// <param name = "isDirectory">
        /// A value that indicates whether this is a directory. MUST be nonzero when this is a directory 
        /// </param>
        /// <returns>The SmbNtCreateAndXResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbNtCreateAndxResponsePacket CreateSmbComNtCreateResponse(
            SmbServerConnection connection,
            ushort fileId,
            uint createAction,
            uint extFileAttributes,
            FileTypeValue fileType,
            bool isDirectory)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbNtCreateAndxResponsePacket packet = new SmbNtCreateAndxResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_NT_CREATE_ANDX,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_NT_CREATE_ANDX_Response_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND;
            smbParameters.OplockLevel = OplockLevelValue.None;
            smbParameters.FID = fileId;
            smbParameters.CreationAction = createAction;
            smbParameters.CreateTime.Time = (ulong)DateTime.Now.ToFileTime();
            smbParameters.LastAccessTime.Time = (ulong)DateTime.Now.ToFileTime();
            smbParameters.LastWriteTime.Time = (ulong)DateTime.Now.ToFileTime();
            smbParameters.LastChangeTime.Time = (ulong)DateTime.Now.ToFileTime();
            smbParameters.ExtFileAttributes = extFileAttributes;
            smbParameters.AllocationSize = 0x00;
            smbParameters.EndOfFile = 0x00;
            smbParameters.ResourceType = fileType;
            smbParameters.NMPipeStatus_or_FileStatusFlags = SMB_NMPIPE_STATUS.None;
            smbParameters.Directory = (byte)(isDirectory == true ? 1 : 0);
            smbParameters.VolumeGUID = Guid.Empty.ToByteArray();
            smbParameters.FileId = new byte[sizeof(long)];
            smbParameters.MaximalAccessRights = new byte[sizeof(int)];
            smbParameters.GuestMaximalAccessRights = new byte[sizeof(int)];

            int size = CifsMessageUtils.GetSize<Cifs.SMB_COM_NT_CREATE_ANDX_Response_SMB_Parameters>(
                new Cifs.SMB_COM_NT_CREATE_ANDX_Response_SMB_Parameters());
            size += smbParameters.VolumeGUID.Length;
            size += smbParameters.FileId.Length;
            size += smbParameters.MaximalAccessRights.Length;
            size += smbParameters.GuestMaximalAccessRights.Length;

            smbParameters.WordCount = (byte)(size / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_NT_CREATE_ANDX_Response_SMB_Data smbData = packet.SmbData;

            // update smbData.ByteCount
            smbData.ByteCount = 0;

            // store the parameters and data to packet.
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            return packet;
        }
        /// <summary>
        /// Create TRANS_QUERY_NMPIPE_INFO Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "outputBufferSize">
        /// The first word of the data buffer that MUST contain the actual size of the buffer for outgoing (server) 
        /// I/O 
        /// </param>
        /// <param name = "inputBufferSize">
        /// This value MUST be the actual size of the buffer for incoming (client) I/O 
        /// </param>
        /// <param name = "maximumInstances">
        /// This value MUST be the maximum allowed number of named pipe instances. 
        /// </param>
        /// <param name = "currectInstances">This value MUST be the current number of named pipe instances </param>
        /// <param name = "pipeName">
        /// This value MUST be a null-terminated string containing the name of the named pipe 
        /// </param>
        /// <returns>The SmbTransQueryNmpipeInfoResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbTransQueryNmpipeInfoResponsePacket CreateTransQueryNmpipeInfoResponse(
            SmbServerConnection connection,
            ushort outputBufferSize,
            ushort inputBufferSize,
            byte maximumInstances,
            byte currectInstances,
            string pipeName)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbTransQueryNmpipeInfoResponsePacket packet = new SmbTransQueryNmpipeInfoResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_TRANSACTION,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData;

            // update trans data
            TRANS_QUERY_NMPIPE_INFO_Response_Trans_Data transData = packet.TransData;

            transData.OutputBufferSize = outputBufferSize;
            transData.InputBufferSize = inputBufferSize;
            transData.MaximumInstances = maximumInstances;
            transData.CurrentInstances = currectInstances;
            transData.PipeName = CifsMessageUtils.ToSmbStringBytes(pipeName, connection.Capability.IsUnicode);
            transData.PipeNameLength = (byte)transData.PipeName.Length;

            // store the parameters and data to packet.
            packet.TransData = transData;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// Add Connection to context
        /// </summary>
        /// <param name="connection">the connection</param>
        /// <exception cref="InvalidOperationException">
        /// the connection already exists in the connection list, can not add duplicate connection
        /// </exception>
        internal void AddConnection(SmbServerConnection connection)
        {
            lock (this.connectionList)
            {
                if(this.connectionList.Contains(connection))
                {
                    throw new InvalidOperationException(
                        "the connection already exists in the connection list, can not add duplicate connection");
                }

                this.connectionList.Add(connection);
            }
        }
        /// <summary>
        /// Create TRANS_RAW_READ_NMPIPE Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name = "dataBuffer">
        /// The Data buffer that MUST contain the bytes read from the named pipe in raw mode 
        /// </param>
        /// <returns>The SmbTransRawReadNmpipeResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbTransRawReadNmpipeResponsePacket CreateTransRawReadNmpipeResponse(
            SmbServerConnection connection,
            byte[] dataBuffer)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbTransRawReadNmpipeResponsePacket packet = new SmbTransRawReadNmpipeResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_TRANSACTION,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.SetupCount = 0;
            smbParameters.Setup = new ushort[0];
            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData;

            int alignBytesCount =
                (SmbCapability.NUM_BYTES_OF_BYTE // WordCount
                + smbParameters.WordCount * SmbCapability.NUM_BYTES_OF_WORD // Words
                + SmbCapability.NUM_BYTES_OF_WORD) // ByteCount
                % SmbCapability.FOUR_BYTES_ALIGN;

            if (alignBytesCount != 0)
            {
                smbData.Pad2 = new byte[SmbCapability.FOUR_BYTES_ALIGN - alignBytesCount];
            }

            // update trans data
            TRANS_RAW_READ_NMPIPE_Response_Trans_Data transData = packet.TransData;
            transData.BytesRead = dataBuffer;

            // store the parameters and data to packet.
            packet.TransData = transData;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// update the context of smb server
        /// </summary>
        /// <param name="connection">the connection of the client</param>
        /// <param name="packet">the packet to update the context</param>
        internal void UpdateRoleContext(SmbServerConnection connection, SmbPacket packet)
        {
            if (connection == null)
            {
                return;
            }

            // packet status
            SmbStatus packetStatus = (SmbStatus)packet.SmbHeader.Status;

            // filter error packet
            if (packetStatus != SmbStatus.STATUS_SUCCESS &&
                    packetStatus != SmbStatus.STATUS_MORE_PROCESSING_REQUIRED &&
                    packetStatus != SmbStatus.STATUS_BUFFER_OVERFLOW)
            {
                return;
            }

            // process the response packet.
            if (packet.PacketType == SmbPacketType.BatchedResponse
                || packet.PacketType == SmbPacketType.SingleResponse)
            {
                ResponsePacketUpdateRoleContext(connection, packet);
                return;
            }

            // process the request packet.
            if (packet.PacketType == SmbPacketType.BatchedRequest
                || packet.PacketType == SmbPacketType.SingleRequest)
            {
                RequestPacketUpdateRoleContext(connection, packet);
                return;
            }
        }
        /// <summary>
        /// Create TRANS_WRITE_NMPIPE Response 
        /// </summary>
        /// <param name="connection">the connection identified the client</param>
        /// <param name="bytesWritten">This value MUST be set to the number of bytes written to the pipe.</param>
        /// <returns>The SmbTransWriteNmpipeResponsePacket </returns>
        /// <exception cref="ArgumentNullException">connection must not be null</exception>
        public virtual SmbTransWriteNmpipeResponsePacket CreateTransWriteNmpipeResponse(
            SmbServerConnection connection,
            ushort bytesWritten)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            SmbTransWriteNmpipeResponsePacket packet = new SmbTransWriteNmpipeResponsePacket();

            // get the request packet
            SmbPacket request = connection.GetRequestPacket(connection.MessageId);

            // create smb packet header
            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(
                SmbCommand.SMB_COM_TRANSACTION,
                connection.ProcessId, connection.MessageId, request.SmbHeader.Uid, request.SmbHeader.Tid,
                (SmbFlags)connection.Capability.Flag, (SmbFlags2)connection.Capability.Flags2);

            // update smb parameters
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters smbParameters = packet.SmbParameters;

            smbParameters.Setup = new ushort[0];

            smbParameters.WordCount = (byte)(CifsMessageUtils.GetSize<SMB_COM_TRANSACTION_SuccessResponse_SMB_Parameters>(
                smbParameters) / SmbCapability.NUM_BYTES_OF_WORD);

            // update smb data
            SMB_COM_TRANSACTION_SuccessResponse_SMB_Data smbData = packet.SmbData;

            // update trans param
            TRANS_WRITE_NMPIPE_Response_Trans_Parameters transParameters = packet.TransParameters;

            transParameters.BytesWritten = bytesWritten;

            // store the parameters and data to packet.
            packet.TransParameters = transParameters;
            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;

            packet.UpdateCountAndOffset();

            return packet;
        }
        /// <summary>
        /// update the context with response packet
        /// </summary>
        /// <param name="connection">the connection of endpoint</param>
        /// <param name="packet">the packet to update the context</param>
        private void ResponsePacketUpdateRoleContext(SmbServerConnection connection, SmbPacket packet)
        {
            SmbHeader smbHeader = packet.SmbHeader;

            SmbPacket requestPacket = connection.GetRequestPacket(smbHeader.Mid);
            if (requestPacket == null)
            {
                return;
            }

            switch (smbHeader.Command)
            {
                case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:
                    if (smbHeader.Uid == 0)
                    {
                        break;
                    }
                    else
                    {
                        SmbServerSession session = new SmbServerSession();
                        session.Uid = smbHeader.Uid;
                        session.AuthenticationState = SessionState.Complete;
                        session.Connection = connection;
                        session.SessionKey = connection.GssApi.SessionKey;

                        connection.AddSession(session);
                    }

                    break;

                case SmbCommand.SMB_COM_LOGOFF_ANDX:
                    if (requestPacket.SmbHeader.Uid == 0)
                    {
                        break;
                    }
                    else
                    {
                        connection.RemoveSession(connection.GetSession(requestPacket.SmbHeader.Uid));
                    }

                    break;

                case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:
                    {
                        SmbTreeConnectAndxRequestPacket request = requestPacket as SmbTreeConnectAndxRequestPacket;

                        SmbServerTreeConnect treeconnect = new SmbServerTreeConnect();
                        treeconnect.TreeId = smbHeader.Tid;
                        treeconnect.Session = connection.GetSession(smbHeader.Uid);
                        if (treeconnect.Session == null)
                        {
                            break;
                        }
                        if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) != 0)
                        {
                            treeconnect.Path = Encoding.Unicode.GetString(request.SmbData.Path);
                        }
                        else
                        {
                            treeconnect.Path = Encoding.ASCII.GetString(request.SmbData.Path);
                        }
                        treeconnect.Path = treeconnect.Path.TrimEnd('\0');
                        treeconnect.Session.AddTreeConnect(treeconnect);
                    }

                    break;

                case SmbCommand.SMB_COM_TREE_DISCONNECT:
                    if (requestPacket.SmbHeader.Uid != 0)
                    {
                        SmbServerSession session = connection.GetSession(requestPacket.SmbHeader.Uid);
                        if (session == null)
                        {
                            break;
                        }
                        session.RemoveTreeConnect(session.GetTreeConnect(requestPacket.SmbHeader.Tid));
                    }

                    break;

                case SmbCommand.SMB_COM_NT_CREATE_ANDX:
                    {
                        SmbNtCreateAndxResponsePacket response = packet as SmbNtCreateAndxResponsePacket;
                        SmbNtCreateAndxRequestPacket request = requestPacket as SmbNtCreateAndxRequestPacket;

                        SmbServerOpen open = new SmbServerOpen();
                        open.SmbFid = response.SmbParameters.FID;
                        open.PathName = SmbMessageUtils.GetString(request.SmbData.FileName,
                            SmbFlags2.SMB_FLAGS2_UNICODE == (request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE));
                        open.PathName = open.PathName.TrimEnd('\0');
                        open.Session = connection.GetSession(smbHeader.Uid);
                        open.TreeConnect = connection.GetTreeConnect(smbHeader.Tid);
                        if (open.TreeConnect == null)
                        {
                            break;
                        }
                        open.TreeConnect.AddOpen(open);
                    }

                    break;

                case SmbCommand.SMB_COM_OPEN_ANDX:
                    {
                        SmbOpenAndxResponsePacket response = packet as SmbOpenAndxResponsePacket;
                        SmbOpenAndxRequestPacket request = requestPacket as SmbOpenAndxRequestPacket;

                        SmbServerOpen open = new SmbServerOpen();
                        open.SmbFid = response.SmbParameters.FID;
                        open.PathName = SmbMessageUtils.GetString(request.SmbData.FileName,
                            SmbFlags2.SMB_FLAGS2_UNICODE == (request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE));
                        open.Session = connection.GetSession(smbHeader.Uid);
                        open.TreeConnect = connection.GetTreeConnect(smbHeader.Tid);
                        if (open.TreeConnect == null)
                        {
                            break;
                        }
                        open.TreeConnect.AddOpen(open);
                    }

                    break;

                case SmbCommand.SMB_COM_CLOSE:
                    {
                        SmbCloseRequestPacket closeRequest = requestPacket as SmbCloseRequestPacket;

                        SmbServerTreeConnect treeconnect = connection.GetTreeConnect(requestPacket.SmbHeader.Tid);
                        if (treeconnect == null)
                        {
                            break;
                        }

                        treeconnect.RemoveOpen(treeconnect.GetOpen(closeRequest.SmbParameters.FID));
                    }

                    break;

                default:
                    break;
            }

            connection.RemoveRequestPacket(packet);
        }
        /// <summary>
        /// disconnect the connection
        /// </summary>
        /// <param name="connection">the connection to disconnect</param>
        /// <exception cref="ArgumentNullException">the connection is null</exception>
        /// <exception cref="NotImplementedException">dis connect the connection have not been implemented</exception>
        public virtual void Disconnect(SmbServerConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            this.transport.Disconnect(connection.Identity);

            this.context.RemoveConnection(connection);

            // dispose gss api
            connection.DisposeGssApi();
        }