/// <summary>
        /// Disconnect the connection specified by endpoint
        /// </summary>
        /// <param name="endpoint">The endpoint</param>
        public override void Disconnect(FsEndpoint endpoint)
        {
            CifsServerPerConnection connection = this.cifsServer.Context.ConnectionTable[endpoint.NetBiosEndpoint];

            this.cifsServer.Disconnect(connection);
            this.fsEndpoints.Remove(endpoint.NetBiosEndpoint);
        }
        /// <summary>
        /// Expect tcp or netbios connection
        /// </summary>
        /// <param name="timeout">Timeout</param>
        /// <returns>The endpoint of client</returns>
        public override FsEndpoint ExpectConnect(TimeSpan timeout)
        {
            CifsServerPerConnection connection = this.cifsServer.ExpectConnect(timeout);
            FsEndpoint fsEndpoint = new FsEndpoint((int)connection.Identity);

            this.fsEndpoints.Add(fsEndpoint.NetBiosEndpoint, fsEndpoint);
            return(fsEndpoint);
        }
        /// <summary>
        /// server response the negotiate request from client.
        /// </summary>
        /// <param name="connection">the connection between server and client</param>
        /// <param name="requestPacket">the request</param>
        public override void SendNegotiateResponse(
            IFileServiceServerConnection connection,
            SmbFamilyPacket requestPacket)
        {
            CifsServerPerConnection cifsConnection = connection as CifsServerPerConnection;
            SmbPacket response = this.cifsServer.CreateDefaultResponse(cifsConnection,
                                                                       requestPacket as SmbNegotiateRequestPacket);

            this.cifsServer.SendPacket(response, cifsConnection);
        }
        /// <summary>
        /// server response the session request from client.
        /// </summary>
        /// <param name="connection">the connection between server and client</param>
        /// <param name="requestPacket">the request</param>
        /// <returns>The session object.</returns>
        public override IFileServiceServerSession SendSessionSetupResponse(
            IFileServiceServerConnection connection,
            SmbFamilyPacket requestPacket)
        {
            CifsServerPerConnection cifsConnection = connection as CifsServerPerConnection;
            SmbPacket response = this.cifsServer.CreateDefaultResponse(cifsConnection,
                                                                       requestPacket as SmbPacket);

            this.cifsServer.SendPacket(response, cifsConnection);
            return(cifsConnection.GetSession(response.SmbHeader.Uid));
        }
        /// <summary>
        /// Automatically response latest request.
        /// </summary>
        /// <param name="connection">the connection between server and client</param>
        /// <param name="session">the session between server and client</param>
        /// <param name="treeConnect">the tree connect between server and client</param>
        /// <param name="open">the file open between server and client</param>
        /// <param name="requestPacket">the request</param>
        public override void DefaultSendResponse(
            IFileServiceServerConnection connection,
            IFileServiceServerSession session,
            IFileServiceServerTreeConnect treeConnect,
            IFileServiceServerOpen open,
            SmbFamilyPacket requestPacket)
        {
            CifsServerPerConnection cifsConnection = connection as CifsServerPerConnection;
            SmbPacket response = this.cifsServer.CreateDefaultResponse(cifsConnection,
                                                                       requestPacket as SmbPacket);

            this.cifsServer.SendPacket(response, cifsConnection);
        }
        /// <summary>
        /// server response an error packet
        /// </summary>
        /// <param name="connection">the connection between server and client</param>
        /// <param name="status">error code</param>
        /// <param name="requestPacket">the request packet to send the error response</param>
        public override void SendErrorResponse(
            IFileServiceServerConnection connection,
            uint status,
            SmbFamilyPacket requestPacket)
        {
            CifsServerPerConnection cifsConnection = connection as CifsServerPerConnection;
            SmbPacket response = this.cifsServer.CreateDefaultResponse(cifsConnection,
                                                                       requestPacket as SmbPacket);

            SmbHeader smbHeader = response.SmbHeader;

            smbHeader.Status   = status;
            response.SmbHeader = smbHeader;
            this.cifsServer.SendPacket(response, cifsConnection);
        }
        /// <summary>
        /// server response the create request from client.
        /// </summary>
        /// <param name="treeConnect">the tree connect between server and client</param>
        /// <param name="requestPacket">the request</param>
        /// <returns>The file open object</returns>
        public override IFileServiceServerOpen SendCreateResponse(
            IFileServiceServerTreeConnect treeConnect,
            SmbFamilyPacket requestPacket)
        {
            CifsServerPerConnection cifsConnection = treeConnect.Session.Connection as CifsServerPerConnection;
            IFileServiceServerOpen  open           = null;
            SmbCreateResponsePacket response       = this.cifsServer.CreateDefaultResponse(cifsConnection, requestPacket
                                                                                           as SmbPacket) as SmbCreateResponsePacket;

            if (response != null)
            {
                this.cifsServer.SendPacket(response, cifsConnection);
                open = (treeConnect as CifsServerPerTreeConnect).GetOpen(response.SmbParameters.FID);
            }
            return(open);
        }
        /// <summary>
        /// server response the logoff request from client.
        /// </summary>
        /// <param name="session">the session between server and client</param>
        public override void SendLogoffResponse(IFileServiceServerSession session)
        {
            CifsServerPerConnection connection = session.Connection as CifsServerPerConnection;

            foreach (SmbLogoffAndxRequestPacket request in connection.PendingRequestTable)
            {
                if (request != null &&
                    request.SmbHeader.Uid == session.SessionId)
                {
                    SmbPacket response = this.cifsServer.CreateDefaultResponse(connection, request);

                    this.cifsServer.SendPacket(response, connection);
                    return;
                }
            }
        }
        /// <summary>
        /// server response TransSetNmpipeState request from client.
        /// </summary>
        /// <param name="treeConnect">the tree connect between server and client</param>
        public override void SendTransSetNmpipeStateResponse(IFileServiceServerTreeConnect treeConnect)
        {
            CifsServerPerConnection connection = treeConnect.Session.Connection as CifsServerPerConnection;

            foreach (SmbTransSetNmpipeStateRequestPacket request in connection.PendingRequestTable)
            {
                if (request != null &&
                    request.SmbHeader.Uid == treeConnect.Session.SessionId &&
                    request.SmbHeader.Tid == treeConnect.TreeConnectId)
                {
                    SmbPacket response = this.cifsServer.CreateTransSetNmpipeStateSuccessResponse(
                        connection, request);
                    this.cifsServer.SendPacket(response, connection);
                    return;
                }
            }
        }
        /// <summary>
        /// server response the close request from client.
        /// </summary>
        /// <param name="open">the file open between server and client</param>
        public override void SendCloseResponse(IFileServiceServerOpen open)
        {
            CifsServerPerConnection connection = open.TreeConnect.Session.Connection as CifsServerPerConnection;

            foreach (SmbCloseRequestPacket request in connection.PendingRequestTable)
            {
                if (request != null &&
                    request.SmbHeader.Uid == open.TreeConnect.Session.SessionId &&
                    request.SmbHeader.Tid == open.TreeConnect.TreeConnectId &&
                    request.SmbParameters.FID == open.FileId)
                {
                    SmbCloseResponsePacket response = this.cifsServer.CreateCloseResponse(connection, request);

                    this.cifsServer.SendPacket(response, connection);
                    return;
                }
            }
        }
        /// <summary>
        /// server response the IO control request from client.
        /// </summary>
        /// <param name="open">the file open between server and client</param>
        /// <param name="controlCode">The file system control code</param>
        /// <param name="data">The information about this IO control</param>
        public override void SendIoControlResponse(IFileServiceServerOpen open, FsCtlCode controlCode, byte[] data)
        {
            CifsServerPerConnection connection = open.TreeConnect.Session.Connection as CifsServerPerConnection;

            foreach (SmbIoctlRequestPacket request in connection.PendingRequestTable)
            {
                if (request != null &&
                    request.SmbHeader.Uid == open.TreeConnect.Session.SessionId &&
                    request.SmbHeader.Tid == open.TreeConnect.TreeConnectId &&
                    request.SmbParameters.FID == open.FileId)
                {
                    SmbIoctlResponsePacket response = this.cifsServer.CreateIoctlResponse(connection,
                                                                                          request, null, data);
                    this.cifsServer.SendPacket(response, connection);
                    return;
                }
            }
        }
        /// <summary>
        /// server response Trans2QueryFileInformation request from client.
        /// </summary>
        /// <param name="open">the file open between server and client</param>
        /// <param name="data">The transaction2 data to send</param>
        public override void SendTrans2QueryFileInformationResponse(IFileServiceServerOpen open, object data)
        {
            CifsServerPerConnection connection = open.TreeConnect.Session.Connection as CifsServerPerConnection;

            foreach (SmbTrans2QueryFileInformationRequestPacket request in connection.PendingRequestTable)
            {
                if (request != null &&
                    request.SmbHeader.Uid == open.TreeConnect.Session.SessionId &&
                    request.SmbHeader.Tid == open.TreeConnect.TreeConnectId &&
                    request.Trans2Parameters.FID == open.FileId)
                {
                    SmbPacket response = this.cifsServer.CreateTrans2QueryFileInformationFinalResponse(
                        connection, request, data);
                    this.cifsServer.SendPacket(response, connection);
                    return;
                }
            }
        }
        /// <summary>
        /// server response the read request from client.
        /// The method will automatically reply multiple READ response if data is too large.
        /// </summary>
        /// <param name="open">the file open between server and client</param>
        /// <param name="data">The actual bytes</param>
        /// <param name = "available">
        /// This field is valid when reading from named pipes or I/O devices. This field indicates the number of bytes
        /// remaining to be read after the requested read was completed.
        /// </param>
        public override void SendReadResponse(IFileServiceServerOpen open, byte[] data, int available)
        {
            CifsServerPerConnection connection = open.TreeConnect.Session.Connection as CifsServerPerConnection;

            foreach (SmbReadAndxRequestPacket request in connection.PendingRequestTable)
            {
                if (request != null &&
                    request.SmbHeader.Uid == open.TreeConnect.Session.SessionId &&
                    request.SmbHeader.Tid == open.TreeConnect.TreeConnectId &&
                    request.SmbParameters.FID == open.FileId)
                {
                    SmbPacket response = this.cifsServer.CreateReadAndxResponse(connection, request, (ushort)available,
                                                                                data, null);
                    this.cifsServer.SendPacket(response, connection);
                    return;
                }
            }
        }
        /// <summary>
        /// server response the write request from client.
        /// </summary>
        /// <param name="open">the file open between server and client</param>
        /// <param name="writtenCount">number of bytes in Write request</param>
        public override void SendWriteResponse(IFileServiceServerOpen open, int writtenCount)
        {
            CifsServerPerConnection connection = open.TreeConnect.Session.Connection as CifsServerPerConnection;

            foreach (SmbWriteAndxRequestPacket request in connection.PendingRequestTable)
            {
                if (request != null &&
                    request.SmbHeader.Uid == open.TreeConnect.Session.SessionId &&
                    request.SmbHeader.Tid == open.TreeConnect.TreeConnectId &&
                    request.SmbParameters.FID == open.FileId)
                {
                    SmbWriteAndxResponsePacket response = this.cifsServer.CreateWriteAndxResponse(
                        connection, request, 0, null);
                    SMB_COM_WRITE_ANDX_Response_SMB_Parameters smbParameters = response.SmbParameters;
                    smbParameters.Count    = (ushort)writtenCount;
                    response.SmbParameters = smbParameters;
                    this.cifsServer.SendPacket(response, connection);
                    return;
                }
            }
        }
        /// <summary>
        /// server response the trans transact nmpipe request from client.
        /// </summary>
        /// <param name="open">the file open between server and client</param>
        /// <param name="data">The actual bytes</param>
        /// <param name = "available">indicates the number of bytes remaining to be read</param>
        public override void SendTransTransactNmpipeResponse(IFileServiceServerOpen open, byte[] data, int available)
        {
            CifsServerPerConnection connection = open.TreeConnect.Session.Connection as CifsServerPerConnection;

            foreach (SmbTransTransactNmpipeRequestPacket request in connection.PendingRequestTable)
            {
                if (request != null &&
                    request.SmbHeader.Uid == open.TreeConnect.Session.SessionId &&
                    request.SmbHeader.Tid == open.TreeConnect.TreeConnectId)
                {
                    SmbTransTransactNmpipeSuccessResponsePacket response =
                        this.cifsServer.CreateTransTransactNmpipeSuccessResponse(
                            connection, request, data);
                    if (available > 0)
                    {
                        Cifs.SmbHeader header = response.SmbHeader;
                        header.Status      = (uint)NtStatus.STATUS_BUFFER_OVERFLOW;
                        response.SmbHeader = header;
                    }
                    this.cifsServer.SendPacket(response, connection);
                    return;
                }
            }
        }
        public SmbWritePrintFileResponsePacket CreateWritePrintFileResponse(
            CifsServerPerConnection connection,
            SmbWritePrintFileRequestPacket request)
        {
            SmbWritePrintFileResponsePacket response = new SmbWritePrintFileResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            return response;
        }
        /// <summary>
        /// Update the context when received request.
        /// </summary>
        /// <param name="connection">The connection between client and server.</param>
        /// <param name="requestPacket">The received packet in stack transport.</param>
        protected virtual void UpdateRequestRoleConext(
            CifsServerPerConnection connection,
            SmbPacket requestPacket)
        {
            if (requestPacket == null)
            {
                return;
            }

            bool isAndxPacket = requestPacket.SmbHeader.Protocol == CifsMessageUtils.SMB_PROTOCOL_ANDXPACKET;

            if (!isAndxPacket)
            {
                connection.MultiplexId = requestPacket.SmbHeader.Mid;
            }

            /*If the UID is valid, the server MUST enumerate all connections in the Server.ConnectionTable and MUST
             *look up Session in the Server.Connection.SessionTable where UID is equal to Server.Session.UID.
             *If a session is found, Server.Session.IdleTime MUST be set to the current time. If no session is found,
             *no action regarding idle time is taken.*/
            if (requestPacket.SmbHeader.Uid != 0)
            {
                foreach (CifsServerPerSession session in connection.SessionTable)
                {
                    if (session.SessionId == requestPacket.SmbHeader.Uid)
                    {
                        session.IdleTime = DateTime.Now;
                        break;
                    }
                }
            }

            switch (requestPacket.SmbHeader.Command)
            {
                case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:
                    {
                        SmbSessionSetupAndxRequestPacket request = requestPacket as SmbSessionSetupAndxRequestPacket;
                        connection.SessionSetupReceived = true;
                        connection.ClientCapabilites = request.SmbParameters.Capabilities;
                        connection.ClientMaxBufferSize = request.SmbParameters.MaxBufferSize;
                        connection.ClientMaxMpxCount = request.SmbParameters.MaxMpxCount;
                        connection.IsSigningActive = false;
                        connection.NativeLanMan = CifsMessageUtils.ToSmbString(request.SmbData.NativeLanMan, 0, false);
                        connection.NativeOS = CifsMessageUtils.ToSmbString(request.SmbData.NativeOS, 0, false);
                    }
                    break;
                default:
                    break;
            }

            if (!isAndxPacket
                && requestPacket.SmbHeader.Command != SmbCommand.SMB_COM_TRANSACTION_SECONDARY
                && requestPacket.SmbHeader.Command != SmbCommand.SMB_COM_TRANSACTION2_SECONDARY
                && requestPacket.SmbHeader.Command != SmbCommand.SMB_COM_NT_TRANSACT_SECONDARY
                && requestPacket.SmbHeader.Command != SmbCommand.SMB_COM_NT_CANCEL)
            {
                connection.AddPendingRequest(requestPacket);
            }

            if (!isAndxPacket)
            {
                connection.UpdateSequenceNumber(requestPacket);
            }

            SmbBatchedRequestPacket batchedRequest = requestPacket as SmbBatchedRequestPacket;
            if (batchedRequest != null)
            {
                SmbPacket andxPacket = batchedRequest.AndxPacket;
                this.UpdateRequestRoleConext(connection, andxPacket);
            }
        }
        protected virtual void UpdateResponseRoleContext(
            CifsServerPerConnection connection,
            SmbPacket requestPacket,
            SmbPacket responsePacket)
        {
            if (requestPacket == null || responsePacket == null || responsePacket.SmbHeader.Status != 0)
            {
                return;
            }

            SmbHeader smbHeader = responsePacket.SmbHeader;

            switch (responsePacket.SmbHeader.Command)
            {
                #region Negotiate
                case SmbCommand.SMB_COM_NEGOTIATE:
                    {
                        SmbNegotiateRequestPacket request = requestPacket as SmbNegotiateRequestPacket;
                        SmbNegotiateResponsePacket response = responsePacket as SmbNegotiateResponsePacket;
                        if (request != null && response != null && request.SmbData.Dialects != null)
                        {
                            int dialectIndex = (int)(response.SmbParameters.DialectIndex);
                            byte[] dialectBytes = request.SmbData.Dialects;
                            int startIndex = 0;
                            for (int i = 0; i < dialectIndex; i++)
                            {
                                startIndex = Array.IndexOf<byte>(dialectBytes, 0, startIndex,
                                    dialectBytes.Length - startIndex) + 1;
                            }
                            connection.SelectedDialect = CifsMessageUtils.ToSmbString(dialectBytes, startIndex, true);
                            connection.NTLMChallenge = response.SmbData.Challenge;
                            connection.OpLockSupport = this.opLockSupport;
                            connection.NegotiateTime = response.SmbParameters.SystemTime;

                            if (this.ntlmAuthenticationPolicy != NTLMAuthenticationPolicyValues.Disabled)
                            {
                                //Prepare security context for the coming ntlm authentication.
                                foreach (AccountCredential accountCredential in this.accountCredentials)
                                {
                                    NlmpServerSecurityContext serverSecurityContext = new NlmpServerSecurityContext(
                                        NegotiateTypes.NTLM_NEGOTIATE_OEM | NegotiateTypes.NTLMSSP_NEGOTIATE_NTLM,
                                        new NlmpClientCredential(string.Empty, accountCredential.DomainName,
                                            accountCredential.AccountName, accountCredential.Password),
                                        !string.IsNullOrEmpty(this.domainName),
                                        this.domainName,
                                        this.serverName);
                                    serverSecurityContext.UpdateServerChallenge(
                                        BitConverter.ToUInt64(response.SmbData.Challenge, 0));
                                    this.nlmpServerSecurityContexts.Add(serverSecurityContext);
                                }
                            }

                            if ((response.SmbParameters.SecurityMode & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
                                == SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
                            {
                                connection.IsSigningActive = true;
                            }
                        }
                    }
                    break;
                #endregion

                #region Session

                case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:
                    #region SMB_COM_SESSION_SETUP_ANDX
                    {
                        SmbSessionSetupAndxRequestPacket request = requestPacket as SmbSessionSetupAndxRequestPacket;
                        SmbSessionSetupAndxResponsePacket response = responsePacket as SmbSessionSetupAndxResponsePacket;

                        if (request != null && response != null)
                        {
                            NlmpServerSecurityContext securityContext = null;
                            if (response.SmbParameters.Action != ActionValues.GuestAccess)
                            {
                                this.ActiveAccount = CifsMessageUtils.PlainTextAuthenticate(request, this.accountCredentials);

                                if (string.IsNullOrEmpty(this.ActiveAccount))
                                {
                                    securityContext = CifsMessageUtils.NTLMAuthenticate(request,
                                        this.nlmpServerSecurityContexts, connection.NegotiateTime.Time);

                                    if (securityContext != null)
                                    {
                                        connection.IsSigningActive = true;
                                        connection.SigningChallengeResponse = request.SmbData.UnicodePassword;
                                        this.ActiveAccount = securityContext.Context.ClientCredential.AccountName;
                                        connection.SigningSessionKey = NlmpUtility.GetResponseKeyNt(
                                            NlmpVersion.v1,
                                            securityContext.Context.ClientCredential.DomainName,
                                            securityContext.Context.ClientCredential.AccountName,
                                            securityContext.Context.ClientCredential.Password);
                                    }
                                }
                            }

                            CifsServerPerSession session = new CifsServerPerSession(
                                connection,
                                smbHeader.Uid,
                                securityContext,
                                DateTime.Now,
                                DateTime.Now,
                                CifsMessageUtils.ToSmbString(request.SmbData.AccountName, 0, false),
                                GenerateSessionGlobalId());
                            this.AddSession(session);
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_LOGOFF_ANDX:
                    #region SMB_COM_LOGOFF_ANDX
                    {
                        SmbLogoffAndxRequestPacket request = requestPacket as SmbLogoffAndxRequestPacket;
                        SmbLogoffAndxResponsePacket response = responsePacket as SmbLogoffAndxResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            this.RemoveSession(session.SessionGlobalId);
                        }
                    }
                    #endregion
                    break;

                #endregion

                #region Tree Connect

                case SmbCommand.SMB_COM_TREE_CONNECT:
                    #region SMB_COM_TREE_CONNECT
                    {
                        SmbTreeConnectRequestPacket request = requestPacket as SmbTreeConnectRequestPacket;
                        SmbTreeConnectResponsePacket response = responsePacket as SmbTreeConnectResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        //If Core Protocol, No sessions setup, make a default session
                        if (session == null
                            && (connection.SelectedDialect == CifsMessageUtils.DIALECT_PCNETWORK_PROGRAM
                                || connection.SelectedDialect == CifsMessageUtils.DIALECT_NTLANMAN))
                        {
                            session = new CifsServerPerSession(
                                    connection,
                                    smbHeader.Uid, //should be unique, windows always be zero
                                    null,
                                    DateTime.Now,
                                    DateTime.Now,
                                    string.Empty,
                                    GenerateSessionGlobalId());
                            this.AddSession(session);
                        }

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = new CifsServerPerTreeConnect(
                                session,
                                CifsMessageUtils.ToSmbString(request.SmbData.Path, 0, false),
                                response.SmbParameters.TID,
                                this.GenerateTreeGlobalId(),
                                DateTime.Now);
                            this.AddTreeConnect(treeConnect);
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:
                    #region SMB_COM_TREE_CONNECT_ANDX
                    {
                        SmbTreeConnectAndxRequestPacket request = requestPacket as SmbTreeConnectAndxRequestPacket;

                        SmbTreeConnectAndxResponsePacket response = responsePacket as SmbTreeConnectAndxResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = new CifsServerPerTreeConnect(
                                session,
                                CifsMessageUtils.ToString(request.SmbData.Path, request.SmbHeader.Flags2),
                                smbHeader.Tid,
                                this.GenerateTreeGlobalId(),
                                DateTime.Now);
                            this.AddTreeConnect(treeConnect);
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_TREE_DISCONNECT:
                    #region SMB_COM_TREE_DISCONNECT
                    {
                        SmbTreeDisconnectRequestPacket request = requestPacket as SmbTreeDisconnectRequestPacket;
                        SmbTreeDisconnectResponsePacket response = responsePacket as SmbTreeDisconnectResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            //If core protocol, no logoff any more, we have to remove the session if there is
                            // no treeconnects in it except this.
                            if (session.TreeConnectTable.Count == 1
                                && (connection.SelectedDialect == CifsMessageUtils.DIALECT_PCNETWORK_PROGRAM
                                    || connection.SelectedDialect == CifsMessageUtils.DIALECT_NTLANMAN))
                            {
                                this.RemoveSession(session.SessionGlobalId);
                            }
                            else
                            {
                                CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                                if (treeConnect != null)
                                {
                                    this.RemoveTreeConnect(treeConnect.TreeGlobalId);
                                }
                            }
                        }
                    }
                    #endregion
                    break;

                #endregion

                #region Open File/Search

                case SmbCommand.SMB_COM_OPEN:
                    #region SMB_COM_OPEN
                    {
                        SmbOpenRequestPacket request = requestPacket as SmbOpenRequestPacket;
                        SmbOpenResponsePacket response = responsePacket as SmbOpenResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                OplockLevelValue opLock = OplockLevelValue.None;
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
                                {
                                    opLock = OplockLevelValue.Exclusive;
                                }
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
                                {
                                    opLock = OplockLevelValue.Batch;
                                }
                                CifsServerPerOpenFile open = new CifsServerPerOpenFile(
                                    treeConnect,
                                    CifsMessageUtils.ToSmbString(request.SmbData.FileName, 0, false),
                                    response.SmbParameters.FID,
                                    response.SmbParameters.AccessMode,
                                    opLock,
                                    this.GenerateFileGlobalId(),
                                    request.SmbHeader.Pid);
                                this.AddOpenFile(open);
                            }
                        }
                    }
                    #endregion
                    break;

                case SmbCommand.SMB_COM_CREATE:
                    #region SMB_COM_CREATE
                    {
                        SmbCreateRequestPacket request = requestPacket as SmbCreateRequestPacket;
                        SmbCreateResponsePacket response = responsePacket as SmbCreateResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                OplockLevelValue opLock = OplockLevelValue.None;
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
                                {
                                    opLock = OplockLevelValue.Exclusive;
                                }
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
                                {
                                    opLock = OplockLevelValue.Batch;
                                }
                                CifsServerPerOpenFile open = new CifsServerPerOpenFile(
                                    treeConnect,
                                    CifsMessageUtils.ToSmbString(request.SmbData.FileName, 0, false),
                                    response.SmbParameters.FID,
                                    (ushort)request.SmbParameters.FileAttributes,
                                    opLock,
                                    this.GenerateFileGlobalId(),
                                    request.SmbHeader.Pid);
                                this.AddOpenFile(open);
                            }
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_CREATE_TEMPORARY:
                    #region SMB_COM_CREATE_TEMPORARY
                    {
                        SmbCreateTemporaryRequestPacket request = requestPacket as SmbCreateTemporaryRequestPacket;
                        SmbCreateTemporaryResponsePacket response = responsePacket as SmbCreateTemporaryResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                OplockLevelValue opLock = OplockLevelValue.None;
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
                                {
                                    opLock = OplockLevelValue.Exclusive;
                                }
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
                                {
                                    opLock = OplockLevelValue.Batch;
                                }
                                CifsServerPerOpenFile open = new CifsServerPerOpenFile(
                                    treeConnect,
                                    CifsMessageUtils.ToSmbString(response.SmbData.TemporaryFileName, 0, false),
                                    response.SmbParameters.FID,
                                    (uint)request.SmbParameters.FileAttributes,
                                    opLock,
                                    this.GenerateFileGlobalId(),
                                    request.SmbHeader.Pid);
                                this.AddOpenFile(open);
                            }
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_CREATE_NEW:
                    #region SMB_COM_CREATE_NEW
                    {
                        SmbCreateNewRequestPacket request = requestPacket as SmbCreateNewRequestPacket;
                        SmbCreateNewResponsePacket response = responsePacket as SmbCreateNewResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                OplockLevelValue opLock = OplockLevelValue.None;
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
                                {
                                    opLock = OplockLevelValue.Exclusive;
                                }
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
                                {
                                    opLock |= OplockLevelValue.Batch;
                                }
                                CifsServerPerOpenFile open = new CifsServerPerOpenFile(
                                    treeConnect,
                                    CifsMessageUtils.ToSmbString(request.SmbData.FileName, 0, false),
                                    response.SmbParameters.FID,
                                    (uint)request.SmbParameters.FileAttributes,
                                    opLock,
                                    this.GenerateFileGlobalId(),
                                    request.SmbHeader.Pid);
                                this.AddOpenFile(open);
                            }
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_OPEN_ANDX:
                    #region SMB_COM_OPEN_ANDX
                    {
                        SmbOpenAndxRequestPacket request = requestPacket as SmbOpenAndxRequestPacket;
                        SmbOpenAndxResponsePacket response = responsePacket as SmbOpenAndxResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                OplockLevelValue opLock = OplockLevelValue.None;
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
                                {
                                    opLock = OplockLevelValue.Exclusive;
                                }
                                if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
                                {
                                    opLock |= OplockLevelValue.Batch;
                                }
                                string fileName;
                                if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE)
                                {
                                    fileName = Encoding.Unicode.GetString(request.SmbData.FileName);
                                }
                                else
                                {
                                    fileName = Encoding.ASCII.GetString(request.SmbData.FileName);
                                }
                                CifsServerPerOpenFile open = new CifsServerPerOpenFile(
                                    treeConnect,
                                    fileName,
                                    response.SmbParameters.FID,
                                    (uint)response.SmbParameters.FileAttrs,
                                    opLock,
                                    this.GenerateFileGlobalId(),
                                    request.SmbHeader.Pid);
                                this.AddOpenFile(open);

                                //save FID for chained response like:
                                //treeConnect->openAndx->readAndx->close
                                //when "close", FID is need to close the open opened in openAndx.
                                if (response.AndxPacket != null)
                                {
                                    //borrow smbHeader.Protocol to save FID for later process.
                                    //smbHeader.Protocol also use a flag to differentiate a single packet from a
                                    //batched andx packet.
                                    //FID is ushort, impossible to impact smbHeader.Protocol's usage as
                                    //a real packet header 0x424D53FF(0xFF, 'S', 'M', 'B')
                                    SmbHeader andxHeader = response.AndxPacket.SmbHeader;
                                    andxHeader.Protocol = response.SmbParameters.FID;
                                    response.AndxPacket.SmbHeader = andxHeader;
                                }
                            }
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_NT_CREATE_ANDX:
                    #region SMB_COM_NT_CREATE_ANDX
                    {
                        SmbNtCreateAndxRequestPacket request = requestPacket as SmbNtCreateAndxRequestPacket;
                        SmbNtCreateAndxResponsePacket response = responsePacket as SmbNtCreateAndxResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                string fileName;
                                if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE)
                                {
                                    fileName = Encoding.Unicode.GetString(request.SmbData.FileName);
                                }
                                else
                                {
                                    fileName = Encoding.ASCII.GetString(request.SmbData.FileName);
                                }
                                CifsServerPerOpenFile open = new CifsServerPerOpenFile(
                                    treeConnect,
                                    fileName,
                                    response.SmbParameters.FID,
                                    (uint)response.SmbParameters.ExtFileAttributes,
                                    response.SmbParameters.OplockLevel,
                                    this.GenerateFileGlobalId(),
                                    request.SmbHeader.Pid);
                                this.AddOpenFile(open);
                            }
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_OPEN_PRINT_FILE:
                    #region SMB_COM_OPEN_PRINT_FILE
                    {
                        SmbOpenPrintFileRequestPacket request = requestPacket as SmbOpenPrintFileRequestPacket;
                        SmbOpenPrintFileResponsePacket response = responsePacket as SmbOpenPrintFileResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                CifsServerPerOpenFile open = new CifsServerPerOpenFile(
                                    treeConnect,
                                    CifsMessageUtils.ToSmbString(request.SmbData.Identifier, 0, false),
                                    response.SmbParameters.FID,
                                    request.SmbParameters.Mode,
                                    OplockLevelValue.None,
                                    this.GenerateFileGlobalId(),
                                    request.SmbHeader.Pid);
                                this.AddOpenFile(open);
                            }
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_TRANSACTION2:
                    #region Trans2Open2
                    {
                        SmbTrans2Open2RequestPacket request = requestPacket as SmbTrans2Open2RequestPacket;
                        SmbTrans2Open2FinalResponsePacket response = responsePacket as SmbTrans2Open2FinalResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                string fileName;
                                if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
                                    SmbFlags2.SMB_FLAGS2_UNICODE)
                                {
                                    fileName = Encoding.Unicode.GetString(request.Trans2Parameters.FileName);
                                }
                                else
                                {
                                    fileName = Encoding.ASCII.GetString(request.Trans2Parameters.FileName);
                                }
                                CifsServerPerOpenFile open = new CifsServerPerOpenFile(
                                    treeConnect,
                                    fileName,
                                    response.Trans2Parameters.Fid,
                                    (uint)response.Trans2Parameters.FileAttributes,
                                    OplockLevelValue.None,
                                    this.GenerateFileGlobalId(),
                                    request.SmbHeader.Pid);
                                this.AddOpenFile(open);
                            }
                        }
                    }
                    #endregion

                    #region Trans2FindFirst2
                    {
                        SmbTrans2FindFirst2RequestPacket request = requestPacket as SmbTrans2FindFirst2RequestPacket;
                        SmbTrans2FindFirst2FinalResponsePacket response = responsePacket as SmbTrans2FindFirst2FinalResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                string fileName;
                                if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
                                    SmbFlags2.SMB_FLAGS2_UNICODE)
                                {
                                    fileName = Encoding.Unicode.GetString(request.Trans2Parameters.FileName);
                                }
                                else
                                {
                                    fileName = Encoding.ASCII.GetString(request.Trans2Parameters.FileName);
                                }
                                CifsServerPerOpenSearch openSearch = new CifsServerPerOpenSearch(
                                    treeConnect,
                                    response.Trans2Parameters.SID,
                                    smbHeader.Mid,
                                    smbHeader.Pid,
                                    this.GenerateSearchGlobalId());
                                this.AddOpenSearch(openSearch);
                            }
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_WRITE_AND_CLOSE:
                    #region SMB_COM_WRITE_AND_CLOSE
                    {
                        SmbWriteAndCloseRequestPacket request = requestPacket as SmbWriteAndCloseRequestPacket;
                        SmbWriteAndCloseResponsePacket response = responsePacket as SmbWriteAndCloseResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                CifsServerPerOpenFile open = treeConnect.GetOpen(request.SmbParameters.FID);
                                if (open != null)
                                {
                                    this.RemoveOpenFile(open.FileGlobalId);
                                }
                            }
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_CLOSE:
                    #region SMB_COM_CLOSE
                    {
                        SmbCloseRequestPacket request = requestPacket as SmbCloseRequestPacket;
                        SmbCloseResponsePacket response = responsePacket as SmbCloseResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                CifsServerPerOpenFile open = treeConnect.GetOpen(request.SmbParameters.FID);
                                if (open == null)
                                {
                                    open = treeConnect.GetOpen((ushort)smbHeader.Protocol);
                                }
                                if (open != null)
                                {
                                    this.RemoveOpenFile(open.FileGlobalId);
                                }
                            }
                        }
                    }
                    #endregion
                    break;
                case SmbCommand.SMB_COM_FIND_CLOSE2:
                    #region SMB_COM_FIND_CLOSE2
                    {
                        SmbFindClose2RequestPacket request = requestPacket as SmbFindClose2RequestPacket;
                        SmbFindClose2ResponsePacket response = responsePacket as SmbFindClose2ResponsePacket;
                        CifsServerPerSession session = connection.GetSession(smbHeader.Uid);

                        if (request != null && response != null && session != null)
                        {
                            CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
                            if (treeConnect != null)
                            {
                                CifsServerPerOpenSearch openSearch = treeConnect.GetOpenSearch(
                                    request.SmbParameters.SearchHandle); ;
                                if (openSearch != null)
                                {
                                    this.RemoveOpenSearch(openSearch.SearchGlobalId);
                                }
                            }
                        }
                    }
                    #endregion
                    break;

                #endregion

                default:
                    // No Connection/Session/Tree/Open will be updated if other types of response.
                    break;
            }

            SmbBatchedRequestPacket batchedRequest = requestPacket as SmbBatchedRequestPacket;
            SmbBatchedResponsePacket batchedResponse = responsePacket as SmbBatchedResponsePacket;

            if (batchedRequest != null && batchedResponse != null)
            {

                //pass the FID stored in the andxHeader.Protocol into response.AndxPacket
                if (batchedRequest.AndxPacket != null && batchedResponse.AndxPacket != null
                    && batchedResponse.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_ANDXPACKET
                    && batchedResponse.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_IDENTIFIER)
                {
                    SmbHeader andxHeader = batchedResponse.AndxPacket.SmbHeader;
                    andxHeader.Protocol = smbHeader.Protocol;
                    batchedResponse.AndxPacket.SmbHeader = andxHeader;
                }
                this.UpdateResponseRoleContext(connection, batchedRequest.AndxPacket, batchedResponse.AndxPacket);
            }
        }
        public SmbTreeConnectAndxResponsePacket CreateTreeConnectAndxResponse(
            CifsServerPerConnection connection,
            SmbTreeConnectAndxRequestPacket request,
            OptionalSupport optionalSupport,
            string service,
            SmbPacket andxPacket)
        {
            SmbTreeConnectAndxResponsePacket response = new SmbTreeConnectAndxResponsePacket();
            SmbHeader smbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);
            smbHeader.Tid = connection.GenerateTID();
            response.SmbHeader = smbHeader;

            bool isUnicode = (response.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE;
            byte[] serviceBytes = CifsMessageUtils.ToSmbStringBytes(service, false);
            byte[] fileSystem = CifsMessageUtils.ToSmbStringBytes(CifsMessageUtils.NATIVE_FS, isUnicode);
            int padOffset = Marshal.SizeOf(response.SmbParameters) + sizeof(ushort);
            SMB_COM_TREE_CONNECT_ANDX_Response_SMB_Data smbData = response.SmbData;
            smbData.Pad = new byte[((padOffset + 3) & ~3) - padOffset];
            smbData.Service = serviceBytes;
            smbData.NativeFileSystem = fileSystem;
            smbData.ByteCount = (ushort)(smbData.Pad.Length + smbData.Service.Length
                + smbData.NativeFileSystem.Length);
            response.SmbData = smbData;

            SMB_COM_TREE_CONNECT_ANDX_Response_SMB_Parameters smbParameters = response.SmbParameters;
            smbParameters.AndXCommand =
                andxPacket != null ? andxPacket.SmbHeader.Command : SmbCommand.SMB_COM_NO_ANDX_COMMAND;
            smbParameters.AndXReserved = 0x00;
            smbParameters.AndXOffset = (ushort)(padOffset + response.SmbData.ByteCount);
            smbParameters.OptionalSupport = (ushort)optionalSupport;
            smbParameters.WordCount = (byte)(TypeMarshal.GetBlockMemorySize(smbParameters) / 2);
            response.SmbParameters = smbParameters;

            response.AndxPacket = andxPacket;
            response.UpdateHeader();

            return response;
        }
        /// <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 not started. Please invoke Start() first
        /// </exception>
        public virtual void SendPacket(SmbPacket packet, CifsServerPerConnection connection)
        {
            if (packet == null)
            {
                throw new ArgumentNullException("packet");
            }

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

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

            if (connection.IsSigningActive
                && (packet as SmbLockingAndxRequestPacket == null)
                && (packet as SmbReadRawResponsePacket == null))
            {
                packet.Sign(connection.ServerSendSequenceNumbers[packet.SmbHeader.Mid], connection.SigningSessionKey,
                    connection.SigningChallengeResponse);
            }

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

            // send packet through netbios over Tcp
            this.transport.SendPacket(connection.Identity, smbPacket);
        }
        public SmbUnlockByteRangeResponsePacket CreateUnlockByteRangeResponse(
            CifsServerPerConnection connection,
            SmbUnlockByteRangeRequestPacket request)
        {
            SmbUnlockByteRangeResponsePacket response = new SmbUnlockByteRangeResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            return response;
        }
 /// <summary>
 /// <para>Create default response based on the request.</para>
 /// If the request is a chained andx packet, the corresponding response is also chained.
 /// </summary>
 /// <param name="connection">the connection on which the response will be sent.</param>
 /// <param name="request">the corresponding request</param>
 /// <returns>the default response to the request.</returns>
 public SmbPacket CreateDefaultResponse(CifsServerPerConnection connection, SmbPacket request)
 {
     return this.CreateDefaultResponseWithCallBack(connection, request, null);
 }
        public SmbTransWriteNmpipeSuccessResponsePacket CreateTransWriteNmpipeSuccessResponse(
            CifsServerPerConnection connection,
            SmbTransWriteNmpipeRequestPacket request)
        {
            SmbTransWriteNmpipeSuccessResponsePacket response = new SmbTransWriteNmpipeSuccessResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            TRANS_WRITE_NMPIPE_Response_Trans_Parameters transParameters = response.TransParameters;
            transParameters.BytesWritten = (ushort)request.TransData.WriteData.Length;
            response.TransParameters = transParameters;

            response.UpdateCountAndOffset();

            return response;
        }
        public SmbFindNotifyCloseResponsePacket CreateFindNotifyCloseResponse(
            CifsServerPerConnection connection,
            SmbFindNotifyCloseRequestPacket request)
        {
            SmbFindNotifyCloseResponsePacket response = new SmbFindNotifyCloseResponsePacket();
            SmbHeader smbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            if ((smbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_NT_STATUS) == SmbFlags2.SMB_FLAGS2_NT_STATUS)
            {
                smbHeader.Status = (uint)NtStatus.STATUS_NOT_IMPLEMENTED;
            }
            else
            {
                SmbStatus smbStatus = new SmbStatus();
                smbStatus.ErrorClass = SmbErrorClass.ERRDOS;
                smbStatus.Reserved = 0;
                smbStatus.ErrorCode = (ushort)SmbErrorCodeOfERRDOS.ERRbadfunc;
                smbHeader.Status = smbStatus;
            }
            response.SmbHeader = smbHeader;

            return response;
        }
        public SmbEchoResponsePacket CreateEchoResponse(
            CifsServerPerConnection connection,
            SmbEchoRequestPacket request)
        {
            SmbEchoResponsePacket response = new SmbEchoResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            SMB_COM_ECHO_Response_SMB_Parameters smbParameters = response.SmbParameters;
            smbParameters.WordCount = 0x01;
            //The SMB_Parameters.Words.SequenceNumber field MUST be set to 1.(3.3.5.32)
            smbParameters.SequenceNumber = 0x01;
            response.SmbParameters = smbParameters;

            SMB_COM_ECHO_Response_SMB_Data smbData = response.SmbData;
            smbData.ByteCount = request.SmbData.ByteCount;
            smbData.Data = request.SmbData.Data;
            response.SmbData = smbData;

            return response;
        }
        public SmbWriteRawFinalResponsePacket CreateWriteRawFinalResponse(
            CifsServerPerConnection connection,
            SmbWriteRawRequestPacket request,
            ushort count)
        {
            SmbWriteRawFinalResponsePacket response = new SmbWriteRawFinalResponsePacket();
            SmbHeader smbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);
            smbHeader.Command = SmbCommand.SMB_COM_WRITE_COMPLETE;
            response.SmbHeader = smbHeader;

            SMB_COM_WRITE_RAW_FinalResponse_SMB_Parameters smbParameters = response.SmbParameters;
            smbParameters.Count = count;
            smbParameters.WordCount = (byte)(TypeMarshal.GetBlockMemorySize(smbParameters) / 2);
            response.SmbParameters = smbParameters;

            return response;
        }
        /// <summary>
        /// Create Trans response
        /// </summary>
        /// <param name="connection">the connection on which the response will be sent.</param>
        /// <param name="request">the corresponding request</param>
        /// <returns>the default response to the request.</returns>
        private SmbPacket CreateDefaultTransResponse(
            CifsServerPerConnection connection,
            SmbTransactionRequestPacket request)
        {
            SmbTransSetNmpipeStateRequestPacket setStateRequest = request as SmbTransSetNmpipeStateRequestPacket;
            SmbTransRawReadNmpipeRequestPacket rewReadRequest = request as SmbTransRawReadNmpipeRequestPacket;
            SmbTransQueryNmpipeStateRequestPacket queryStateRequest = request as SmbTransQueryNmpipeStateRequestPacket;
            SmbTransQueryNmpipeInfoRequestPacket queryInfoRequest = request as SmbTransQueryNmpipeInfoRequestPacket;
            SmbTransPeekNmpipeRequestPacket peekStateRequest = request as SmbTransPeekNmpipeRequestPacket;
            SmbTransTransactNmpipeRequestPacket transactRequest = request as SmbTransTransactNmpipeRequestPacket;
            SmbTransRawWriteNmpipeRequestPacket rawWriteRequest = request as SmbTransRawWriteNmpipeRequestPacket;
            SmbTransReadNmpipeRequestPacket readRequest = request as SmbTransReadNmpipeRequestPacket;
            SmbTransWriteNmpipeRequestPacket writeRequest = request as SmbTransWriteNmpipeRequestPacket;
            SmbTransCallNmpipeRequestPacket callRequest = request as SmbTransCallNmpipeRequestPacket;
            SmbTransRapRequestPacket rapRequest = request as SmbTransRapRequestPacket;
            SmbPacket response = null;
            if (setStateRequest != null)
            {
                response = this.CreateTransSetNmpipeStateSuccessResponse(connection, setStateRequest);
            }
            else if (rewReadRequest != null)
            {
                response = this.CreateTransRawReadNmpipeSuccessResponse(connection, rewReadRequest, new byte[0]);
            }
            else if (queryStateRequest != null)
            {
                response = this.CreateTransQueryNmpipeStateSuccessResponse(connection, queryStateRequest,
                    SMB_NMPIPE_STATUS.Endpoint);
            }
            else if (queryInfoRequest != null)
            {
                response = this.CreateTransQueryNmpipeInfoSuccessResponse(connection, queryInfoRequest, 0x0, 0x0, 0x0,
                    0x0, @"\\Cifs\share");
            }
            else if (peekStateRequest != null)
            {
                response = this.CreateTransPeekNmpipeSuccessResponse(connection, peekStateRequest, 0x0, 0x0,
                    SMB_NMPIPE_STATUS.Endpoint, new byte[0]);
            }
            else if (transactRequest != null)
            {
                response = this.CreateTransTransactNmpipeSuccessResponse(connection, transactRequest, new byte[0]);
            }
            else if (rawWriteRequest != null)
            {
                response = this.CreateTransRawWriteNmpipeSuccessResponse(connection, rawWriteRequest);
            }
            else if (readRequest != null)
            {
                response = this.CreateTransReadNmpipeSuccessResponse(connection, readRequest, new byte[0]);
            }
            else if (writeRequest != null)
            {
                response = this.CreateTransWriteNmpipeSuccessResponse(connection, writeRequest);
            }
            else if (callRequest != null)
            {
                response = this.CreateTransCallNmpipeSuccessResponse(connection, callRequest, new byte[0]);
            }
            else if (rapRequest != null)
            {
                response = new SmbTransRapResponsePacket();
                response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);
            }

            return response;
        }
 /// <summary>
 /// Create default Trans2 response
 /// </summary>
 /// <param name="connection">the connection on which the response will be sent.</param>
 /// <param name="request">the corresponding request</param>
 /// <returns>the default response to the request.</returns>
 private SmbPacket CreateDefaultTrans2Response(
     CifsServerPerConnection connection,
     SmbTransaction2RequestPacket request)
 {
     SmbTrans2Open2RequestPacket open2Request = request as SmbTrans2Open2RequestPacket;
     SmbTrans2FindFirst2RequestPacket findFirst2Request = request as SmbTrans2FindFirst2RequestPacket;
     SmbTrans2FindNext2RequestPacket findNext2Request = request as SmbTrans2FindNext2RequestPacket;
     SmbTrans2QueryFsInformationRequestPacket queryFsRequest = request as SmbTrans2QueryFsInformationRequestPacket;
     SmbTrans2SetFsInformationRequestPacket setFsInfoRequest = request as SmbTrans2SetFsInformationRequestPacket;
     SmbTrans2QueryPathInformationRequestPacket queryPathRequest = request as SmbTrans2QueryPathInformationRequestPacket;
     SmbTrans2SetPathInformationRequestPacket setPathRequest = request as SmbTrans2SetPathInformationRequestPacket;
     SmbTrans2QueryFileInformationRequestPacket queryFileRequest = request as SmbTrans2QueryFileInformationRequestPacket;
     SmbTrans2SetFileInformationRequestPacket setFileRequest = request as SmbTrans2SetFileInformationRequestPacket;
     SmbTrans2FsctlRequestPacket fsctlRequest = request as SmbTrans2FsctlRequestPacket;
     SmbTrans2Ioctl2RequestPacket ioctl2Request = request as SmbTrans2Ioctl2RequestPacket;
     SmbTrans2FindNotifyFirstRequestPacket findNotifyFirstRequest = request as SmbTrans2FindNotifyFirstRequestPacket;
     SmbTrans2FindNotifyNextRequestPacket findNotifyNextRequest = request as SmbTrans2FindNotifyNextRequestPacket;
     SmbTrans2CreateDirectoryRequestPacket createDirRequest = request as SmbTrans2CreateDirectoryRequestPacket;
     SmbTrans2SessionSetupRequestPacket sessionSetupRequest = request as SmbTrans2SessionSetupRequestPacket;
     SmbTrans2GetDfsReferalRequestPacket getDfsReferalRequest = request as SmbTrans2GetDfsReferalRequestPacket;
     SmbTrans2ReportDfsInconsistencyRequestPacket reportDfsRequest = request as SmbTrans2ReportDfsInconsistencyRequestPacket;
     SmbPacket response = null;
     if (open2Request != null)
     {
         response = this.CreateTrans2Open2FinalResponse(connection, open2Request, 0x0, FileTypeValue.FileTypeDisk,
             SMB_NMPIPE_STATUS.Endpoint, OpenResultsValues.LockStatus);
     }
     if (findFirst2Request != null)
     {
         response = this.CreateTrans2FindFirst2FinalResponse(connection, findFirst2Request, 0x0, null);
     }
     if (findNext2Request != null)
     {
         response = this.CreateTrans2FindNext2FinalResponse(connection, findNext2Request, 0x0, null);
     }
     if (queryFsRequest != null)
     {
         response = this.CreateTrans2QueryFsInformationFinalResponse(connection, queryFsRequest, null);
     }
     if (setFsInfoRequest != null)
     {
         response = this.CreateTrans2SetFsInformationFinalResponse(connection, setFsInfoRequest);
     }
     if (queryPathRequest != null)
     {
         response = this.CreateTrans2QueryPathInformationFinalResponse(connection, queryPathRequest, null);
     }
     if (setPathRequest != null)
     {
         response = this.CreateTrans2SetPathInformationFinalResponse(connection, setPathRequest);
     }
     if (queryFileRequest != null)
     {
         response = this.CreateTrans2QueryFileInformationFinalResponse(connection, queryFileRequest, null);
     }
     if (setFileRequest != null)
     {
         response = this.CreateTrans2SetFileInformationFinalResponse(connection, setFileRequest);
     }
     if (fsctlRequest != null)
     {
         response = this.CreateTrans2FsctlFinalResponse(connection, fsctlRequest);
     }
     if (ioctl2Request != null)
     {
         response = this.CreateTrans2Ioctl2FinalResponse(connection, ioctl2Request);
     }
     if (findNotifyFirstRequest != null)
     {
         response = this.CreateTrans2FindNotifyFirstFinalResponse(connection, findNotifyFirstRequest);
     }
     if (findNotifyNextRequest != null)
     {
         response = this.CreateTrans2FindNotifyNextFinalResponse(connection, findNotifyNextRequest);
     }
     if (createDirRequest != null)
     {
         response = this.CreateTrans2CreateDirectoryFinalResponse(connection, createDirRequest);
     }
     if (sessionSetupRequest != null)
     {
         response = this.CreateTrans2SessionSetupFinalResponse(connection, sessionSetupRequest);
     }
     if (getDfsReferalRequest != null)
     {
         response = this.CreateTrans2GetDfsReferalFinalResponse(connection, getDfsReferalRequest,
             new RESP_GET_DFS_REFERRAL());
     }
     if (reportDfsRequest != null)
     {
         response = this.CreateTrans2ReportDfsInconsistencyFinalResponse(connection, reportDfsRequest);
     }
     return response;
 }
        /// <summary>
        /// Create default NtTrans response
        /// </summary>
        /// <param name="connection">the connection on which the response will be sent.</param>
        /// <param name="request">the corresponding request</param>
        /// <returns>the default response to the request.</returns>
        private SmbPacket CreateDefaultNtTransResponse(
            CifsServerPerConnection connection,
            SmbNtTransactRequestPacket request)
        {
            SmbNtTransactCreateRequestPacket ntCreateRequest = request as SmbNtTransactCreateRequestPacket;
            SmbNtTransactIoctlRequestPacket ioctlRequest = request as SmbNtTransactIoctlRequestPacket;
            SmbNtTransactSetSecurityDescRequestPacket setSecurityDescRequest =
                request as SmbNtTransactSetSecurityDescRequestPacket;
            SmbNtTransactNotifyChangeRequestPacket notifyChangeRequest =
                request as SmbNtTransactNotifyChangeRequestPacket;
            SmbNtTransactRenameRequestPacket renameRequest = request as SmbNtTransactRenameRequestPacket;
            SmbNtTransactQuerySecurityDescRequestPacket querySecurityDesc =
                request as SmbNtTransactQuerySecurityDescRequestPacket;

            SmbPacket response = null;
            if (ntCreateRequest != null)
            {
                response = this.CreateNtTransactCreateResponse(
                    connection,
                    ntCreateRequest,
                    0x0,
                    0x0,
                    FileTypeValue.FileTypeDisk,
                    SMB_NMPIPE_STATUS.Endpoint, 0x0);
            }
            if (ioctlRequest != null)
            {
                response = this.CreateNtTransactIoctlResponse(connection, ioctlRequest, new byte[0]);
            }

            if (setSecurityDescRequest != null)
            {
                response = this.CreateNtTransactSetSecurityDescResponse(connection, setSecurityDescRequest);
            }

            if (notifyChangeRequest != null)
            {
                response = this.CreateNtTransactNotifyChangeResponse(connection, notifyChangeRequest, null);
            }

            if (renameRequest != null)
            {
                response = this.CreateNtTransactRenameResponse(connection, renameRequest);
            }

            if (querySecurityDesc != null)
            {
                response = this.CreateNtTransactQuerySecurityDescResponse(connection, querySecurityDesc, null);
            }
            return response;
        }
        public SmbPacket CreateDefaultResponseWithCallBack(
            CifsServerPerConnection connection,
            SmbPacket request,
            CreateDefaultResponseCallBack callBack)
        {
            if (connection == null || request == null)
            {
                return null;
            }

            SmbPacket response = null;
            if (callBack != null)
            {
                response = callBack(connection, request);
            }
            if (response != null)
            {
                return response;
            }

            switch(request.SmbHeader.Command)
            {
                case SmbCommand.SMB_COM_CREATE_DIRECTORY:
                    response = this.CreateCreateDirectoryResponse(
                        connection,
                        request as SmbCreateDirectoryRequestPacket);
                    break;
                case SmbCommand.SMB_COM_DELETE_DIRECTORY:
                    response = this.CreateDeleteDirectoryResponse(
                        connection,
                        request as SmbDeleteDirectoryRequestPacket);
                    break;
                case SmbCommand.SMB_COM_OPEN:
                    response = this.CreateOpenResponse(
                        connection,
                        request as SmbOpenRequestPacket,
                        0x0,
                        0x0);
                    break;
                case SmbCommand.SMB_COM_CREATE:
                    response = this.CreateCreateResponse(
                        connection,
                        request as SmbCreateRequestPacket);
                    break;
                case SmbCommand.SMB_COM_CLOSE:
                    response = this.CreateCloseResponse(
                        connection,
                        request as SmbCloseRequestPacket);
                    break;
                case SmbCommand.SMB_COM_FLUSH:
                    response = this.CreateFlushResponse(
                        connection,
                        request as SmbFlushRequestPacket);
                    break;
                case SmbCommand.SMB_COM_DELETE:
                    response = this.CreateDeleteResponse(
                        connection,
                        request as SmbDeleteRequestPacket);
                    break;
                case SmbCommand.SMB_COM_RENAME:
                    response = this.CreateRenameResponse(
                        connection, request as SmbRenameRequestPacket);
                    break;
                case SmbCommand.SMB_COM_QUERY_INFORMATION:
                    response = this.CreateQueryInformationResponse(
                        connection,
                        request as SmbQueryInformationRequestPacket,
                        SmbFileAttributes.SMB_FILE_ATTRIBUTE_NORMAL,
                        0x0, 0x0);
                    break;
                case SmbCommand.SMB_COM_SET_INFORMATION:
                    response = this.CreateSetInformationResponse(
                        connection, request as SmbSetInformationRequestPacket);
                    break;
                case SmbCommand.SMB_COM_READ:
                    response = this.CreateReadResponse(
                        connection,
                        request as SmbReadRequestPacket, new byte[0]);
                    break;
                case SmbCommand.SMB_COM_WRITE:
                    response = this.CreateWriteResponse(
                        connection, request as SmbWriteRequestPacket);
                    break;
                case SmbCommand.SMB_COM_LOCK_byte_RANGE:
                    response = this.CreateLockByteRangeResponse(
                        connection, request as SmbLockByteRangeRequestPacket);
                    break;
                case SmbCommand.SMB_COM_UNLOCK_byte_RANGE:
                    response = this.CreateUnlockByteRangeResponse(
                        connection, request as SmbUnlockByteRangeRequestPacket);
                    break;
                case SmbCommand.SMB_COM_CREATE_TEMPORARY:
                    response = this.CreateCreateTemporaryResponse(
                        connection,
                        request as SmbCreateTemporaryRequestPacket, "temp");
                    break;
                case SmbCommand.SMB_COM_CREATE_NEW:
                    response = this.CreateCreateNewResponse(
                        connection, request as SmbCreateNewRequestPacket);
                    break;
                case SmbCommand.SMB_COM_CHECK_DIRECTORY:
                    response = this.CreateCheckDirectoryResponse(
                        connection, request as SmbCheckDirectoryRequestPacket);
                    break;
                case SmbCommand.SMB_COM_PROCESS_EXIT:
                    response = this.CreateProcessExitResponse(
                        connection, request as SmbProcessExitRequestPacket);
                    break;
                case SmbCommand.SMB_COM_SEEK:
                    response = this.CreateSeekResponse(
                        connection, request as SmbSeekRequestPacket);
                    break;
                case SmbCommand.SMB_COM_LOCK_AND_READ:
                    response = this.CreateLockAndReadResponse(
                        connection,
                        request as SmbLockAndReadRequestPacket,
                        new byte[0]);
                    break;
                case SmbCommand.SMB_COM_WRITE_AND_UNLOCK:
                    response = this.CreateWriteAndUnlockResponse(
                        connection, request as SmbWriteAndUnlockRequestPacket);
                    break;
                case SmbCommand.SMB_COM_READ_RAW:
                    response = this.CreateReadRawResponse(new byte[0]);
                    break;
                case SmbCommand.SMB_COM_READ_MPX:
                    response = this.CreateReadMpxResponse(
                        connection,
                        request as SmbReadMpxRequestPacket,
                        0x0,
                        0x0,
                        0x0,
                        new byte[0]);
                    break;
                case SmbCommand.SMB_COM_WRITE_RAW:
                    response = this.CreateWriteRawFinalResponse(
                        connection,
                        request as SmbWriteRawRequestPacket, 0x0);
                    break;
                case SmbCommand.SMB_COM_WRITE_MPX:
                    response = this.CreateWriteMpxResponse(
                        connection, request as SmbWriteMpxRequestPacket);
                    break;
                case SmbCommand.SMB_COM_QUERY_SERVER:
                    response = this.CreateQueryServerResponse(
                        connection, request as SmbQueryServerRequestPacket);
                    break;
                case SmbCommand.SMB_COM_SET_INFORMATION2:
                    response = this.CreateSetInformation2Response(
                        connection, request as SmbSetInformation2RequestPacket);
                    break;
                case SmbCommand.SMB_COM_QUERY_INFORMATION2:
                    response = this.CreateQueryInformation2Response(
                        connection,
                        request as SmbQueryInformation2RequestPacket,
                        SmbDate.Now,
                        SmbTime.Now,
                        SmbDate.Now,
                        SmbTime.Now,
                        SmbDate.Now,
                        SmbTime.Now,
                        0x0,
                        0x0,
                        SmbFileAttributes.SMB_FILE_ATTRIBUTE_NORMAL);
                    break;
                case SmbCommand.SMB_COM_LOCKING_ANDX:
                    SmbLockingAndxRequestPacket lockingAndxRequest = request as SmbLockingAndxRequestPacket;
                    response = this.CreateLockingAndxResponse(
                        connection,
                        lockingAndxRequest,
                        this.CreateDefaultResponseWithCallBack(connection, lockingAndxRequest.AndxPacket, callBack));
                    break;
                case SmbCommand.SMB_COM_IOCTL:
                    response = this.CreateIoctlResponse(
                        connection,
                        request as SmbIoctlRequestPacket,
                        null,
                        null);
                    break;
                case SmbCommand.SMB_COM_COPY:
                    response = this.CreateCopyResponse(
                        connection, request as SmbCopyRequestPacket);
                    break;
                case SmbCommand.SMB_COM_MOVE:
                    response = this.CreateMoveResponse(
                        connection, request as SmbMoveRequestPacket);
                    break;
                case SmbCommand.SMB_COM_ECHO:
                    response = this.CreateEchoResponse(
                        connection, request as SmbEchoRequestPacket);
                    break;
                case SmbCommand.SMB_COM_WRITE_AND_CLOSE:
                    response = this.CreateWriteAndCloseResponse(
                        connection, request as SmbWriteAndCloseRequestPacket);
                    break;
                case SmbCommand.SMB_COM_OPEN_ANDX:
                    SmbOpenAndxRequestPacket openAndxRequest = request as SmbOpenAndxRequestPacket;
                    response = this.CreateOpenAndxResponse(
                        connection,
                        openAndxRequest,
                        0x0,
                        0x0,
                        AccessRightsValue.SMB_DA_ACCESS_READ,
                        ResourceTypeValue.FileTypeDisk,
                        SMB_NMPIPE_STATUS.Endpoint,
                        OpenResultsValues.LockStatus,
                        this.CreateDefaultResponseWithCallBack(connection, openAndxRequest.AndxPacket, callBack));
                    break;
                case SmbCommand.SMB_COM_READ_ANDX:
                    SmbReadAndxRequestPacket readAndxRequest = request as SmbReadAndxRequestPacket;
                    response = this.CreateReadAndxResponse(
                        connection,
                        readAndxRequest,
                        0xffff,
                        new byte[0],
                        this.CreateDefaultResponseWithCallBack(connection, readAndxRequest.AndxPacket, callBack));
                    break;
                case SmbCommand.SMB_COM_WRITE_ANDX:
                    SmbWriteAndxRequestPacket writeAndxRequest = request as SmbWriteAndxRequestPacket;
                    response = this.CreateWriteAndxResponse(
                        connection,
                        writeAndxRequest,
                        0xffff,
                        this.CreateDefaultResponseWithCallBack(connection, writeAndxRequest.AndxPacket, callBack));
                    break;
                case SmbCommand.SMB_COM_NEW_FILE_SIZE:
                    response = this.CreateNewFileSizeResponse(
                        connection, request as SmbNewFileSizeRequestPacket);
                    break;
                case SmbCommand.SMB_COM_CLOSE_AND_TREE_DISC:
                    response = this.CreateCloseAndTreeDiscResponse(
                        connection, request as SmbCloseAndTreeDiscRequestPacket);
                    break;
                case SmbCommand.SMB_COM_FIND_CLOSE2:
                    response = this.CreateFindClose2Response(
                        connection, request as SmbFindClose2RequestPacket);
                    break;
                case SmbCommand.SMB_COM_FIND_NOTIFY_CLOSE:
                    response = this.CreateFindNotifyCloseResponse(
                        connection, request as SmbFindNotifyCloseRequestPacket);
                    break;
                case SmbCommand.SMB_COM_TREE_CONNECT:
                    response = this.CreateTreeConnectResponse(
                        connection, request as SmbTreeConnectRequestPacket);
                    break;
                case SmbCommand.SMB_COM_TREE_DISCONNECT:
                    response = this.CreateTreeDisconnectResponse(
                        connection, request as SmbTreeDisconnectRequestPacket);
                    break;
                case SmbCommand.SMB_COM_NEGOTIATE:
                    SecurityModes securityModes = SecurityModes.NEGOTIATE_USER_SECURITY;

                    if ((this.context.MessageSigningPolicy & MessageSigningPolicyValues.MessageSigningEnabled)
                        == MessageSigningPolicyValues.MessageSigningEnabled)
                    {
                        securityModes |= SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
                    }
                    if ((this.context.MessageSigningPolicy & MessageSigningPolicyValues.MessageSigningRequired)
                        == MessageSigningPolicyValues.MessageSigningRequired)
                    {
                        securityModes |= SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
                    }
                    if (this.context.NtlmAuthenticationPolicy != NTLMAuthenticationPolicyValues.Disabled
                    && this.context.PlaintextAuthenticationPolicy != PlaintextAuthenticationPolicyValues.Enabled)
                    {
                        securityModes |= SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS;
                    }
                    response = this.CreateNegotiateResponse(
                        connection,
                        request as SmbNegotiateRequestPacket,
                        securityModes);
                    break;
                case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:
                    ActionValues action = ActionValues.NONE;
                    SmbSessionSetupAndxRequestPacket sessionAndxRequest = request as SmbSessionSetupAndxRequestPacket;

                    if (!string.IsNullOrEmpty(CifsMessageUtils.PlainTextAuthenticate(sessionAndxRequest,
                         this.context.AccountCredentials)))
                    {
                        action = ActionValues.GuestAccess;
                    }

                    if (CifsMessageUtils.NTLMAuthenticate(sessionAndxRequest,
                        this.context.NlmpServerSecurityContexts, connection.NegotiateTime.Time) == null)
                    {
                        // If clear, the NTLM user session key will be used for message signing (if enabled).
                        // If set, the LM session key will be used for message signing.
                        action = ActionValues.LmSigning;
                    }

                    response = this.CreateSessionSetupAndxResponse(
                        connection,
                        sessionAndxRequest,
                        action,
                        this.CreateDefaultResponseWithCallBack(connection, sessionAndxRequest.AndxPacket, callBack));
                    break;
                case SmbCommand.SMB_COM_LOGOFF_ANDX:
                    SmbLogoffAndxRequestPacket logoffAndxRequest = request as SmbLogoffAndxRequestPacket;
                    response = this.CreateLogoffAndxResponse(
                        connection,
                        logoffAndxRequest,
                        this.CreateDefaultResponseWithCallBack(connection, logoffAndxRequest.AndxPacket, callBack));
                    break;
                case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:
                    SmbTreeConnectAndxRequestPacket treeConnectAndxRequest = request as SmbTreeConnectAndxRequestPacket;
                    response = this.CreateTreeConnectAndxResponse(
                        connection,
                        treeConnectAndxRequest,
                        OptionalSupport.NONE,
                        CifsMessageUtils.TREE_CONNECT_SERVICE,
                        this.CreateDefaultResponseWithCallBack(connection, treeConnectAndxRequest.AndxPacket, callBack));
                    break;
                case SmbCommand.SMB_COM_SECURITY_PACKAGE_ANDX:
                    response = this.CreateSecurityPackageAndxResponse(
                        connection,
                        request as SmbSecurityPackageAndxRequestPacket);
                    break;
                case SmbCommand.SMB_COM_QUERY_INFORMATION_DISK:
                    response = this.CreateQueryInformationDiskResponse(
                        connection,
                        request as SmbQueryInformationDiskRequestPacket,
                        0x0,
                        0x0,
                        0x0,
                        0x0);
                    break;
                case SmbCommand.SMB_COM_SEARCH:
                    response = this.CreateSearchResponse(
                        connection,
                        request as SmbSearchRequestPacket, null);
                    break;
                case SmbCommand.SMB_COM_FIND:
                    response = this.CreateFindResponse(
                        connection,
                        request as SmbFindRequestPacket, null);
                    break;
                case SmbCommand.SMB_COM_FIND_UNIQUE:
                    response = this.CreateFindUniqueResponse(
                        connection,
                        request as SmbFindUniqueRequestPacket, null);
                    break;
                case SmbCommand.SMB_COM_FIND_CLOSE:
                    response = this.CreateFindCloseResponse(
                        connection, request as SmbFindCloseRequestPacket);
                    break;
                case SmbCommand.SMB_COM_NT_CREATE_ANDX:
                    SmbNtCreateAndxRequestPacket createAndxRequest = request as SmbNtCreateAndxRequestPacket;
                    response = this.CreateNtCreateAndxResponse(
                        connection,
                        createAndxRequest,
                        OplockLevelValue.None,
                        0x0,
                        0x0,
                        FileTypeValue.FileTypeDisk,
                        SMB_NMPIPE_STATUS.Endpoint,
                        0x0,
                        this.CreateDefaultResponseWithCallBack(connection, createAndxRequest.AndxPacket, callBack));
                    break;
                case SmbCommand.SMB_COM_NT_RENAME:
                    response = this.CreateNtRenameResponse(
                        connection, request as SmbNtRenameRequestPacket);
                    break;
                case SmbCommand.SMB_COM_OPEN_PRINT_FILE:
                    response = this.CreateOpenPrintFileResponse(
                        connection, request as SmbOpenPrintFileRequestPacket);
                    break;
                case SmbCommand.SMB_COM_WRITE_PRINT_FILE:
                    response = this.CreateWritePrintFileResponse(
                        connection, request as SmbWritePrintFileRequestPacket);
                    break;
                case SmbCommand.SMB_COM_CLOSE_PRINT_FILE:
                    response = this.CreateClosePrintFileResponse(
                        connection, request as SmbClosePrintFileRequestPacket);
                    break;
                case SmbCommand.SMB_COM_GET_PRINT_QUEUE:
                    response = this.CreateGetPrintQueueResponse(
                        connection, request as SmbGetPrintQueueRequestPacket);
                    break;
                case SmbCommand.SMB_COM_READ_BULK:
                    response = this.CreateReadBulkResponse(
                        connection, request as SmbReadBulkRequestPacket);
                    break;
                case SmbCommand.SMB_COM_WRITE_BULK:
                    response = this.CreateWriteBulkResponse(
                        connection, request as SmbWriteBulkRequestPacket);
                    break;
                case SmbCommand.SMB_COM_WRITE_BULK_DATA:
                    response = this.CreateWriteBulkDataResponse(
                        connection, request as SmbWriteBulkDataRequestPacket);
                    break;
                case SmbCommand.SMB_COM_INVALID:
                    response = this.CreateInvalidResponse(
                        connection, request as SmbInvalidRequestPacket);
                    break;
                case SmbCommand.SMB_COM_NO_ANDX_COMMAND:
                    response = this.CreateNoAndxCommandResponse(
                        connection,
                        request as SmbNoAndxCommandRequestPacket);
                    break;
                case SmbCommand.SMB_COM_TRANSACTION:
                    response = this.CreateDefaultTransResponse(
                        connection, request as SmbTransactionRequestPacket);
                    break;
                case SmbCommand.SMB_COM_TRANSACTION2:
                    response = this.CreateDefaultTrans2Response(
                        connection, request as SmbTransaction2RequestPacket);
                    break;
                case SmbCommand.SMB_COM_NT_TRANSACT:
                    response = this.CreateDefaultNtTransResponse(
                        connection, request as SmbNtTransactRequestPacket);
                    break;
                default:
                    break;
            }

            //The request did not pass the signature verification when decoding.
            if (connection.IsSigningActive && !request.IsSignatureCorrect)
            {
                SmbHeader smbHeader = response.SmbHeader;
                smbHeader.Status = (uint)NtStatus.STATUS_ACCESS_DENIED;
                response.SmbHeader = smbHeader;
                return response;
            }

            return response;
        }
        /// <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 not started. Please invoke Start() first
        /// </exception>
        /// <exception cref="InvalidCastException">Unknown object received from transport.</exception>
        public virtual SmbPacket ExpectPacket(TimeSpan timeout, out CifsServerPerConnection connection)
        {
            if (this.isRunning == false)
            {
                throw new InvalidOperationException(
                    "The transport is not started. Please invoke Start() first.");
            }

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

            switch(transportEvent.EventType)
            {
                case EventType.ReceivedPacket:
                    if (this.context.ConnectionTable.ContainsKey(transportEvent.RemoteEndPoint))
                    {
                        connection = this.context.ConnectionTable[transportEvent.RemoteEndPoint]
                            as CifsServerPerConnection;
                    }
                    return (SmbPacket)transportEvent.EventObject;
                case EventType.Exception:
                case EventType.Disconnected:
                    {
                        throw transportEvent.EventObject as Exception;
                    }
                default:
                    throw new InvalidCastException("Unknown object received from transport.");
            }
        }
        public SmbWriteAndxResponsePacket CreateWriteAndxResponse(
            CifsServerPerConnection connection,
            SmbWriteAndxRequestPacket request,
            ushort available,
            SmbPacket andxPacket)
        {
            SmbWriteAndxResponsePacket response = new SmbWriteAndxResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            SMB_COM_WRITE_ANDX_Response_SMB_Parameters smbParameters = response.SmbParameters;
            smbParameters.AndXCommand =
                andxPacket != null ? andxPacket.SmbHeader.Command : SmbCommand.SMB_COM_NO_ANDX_COMMAND;
            smbParameters.AndXOffset = (ushort)(response.HeaderSize + Marshal.SizeOf(response.SmbParameters)
                    + Marshal.SizeOf(response.SmbData));
            smbParameters.Count = (ushort)request.SmbData.Data.Length;
            smbParameters.Available = available;
            smbParameters.AndXReserved = 0x00;
            smbParameters.WordCount = (byte)(TypeMarshal.GetBlockMemorySize(smbParameters) / 2);
            response.SmbParameters = smbParameters;

            response.AndxPacket = andxPacket;
            response.UpdateHeader();

            return response;
        }
        /// <summary>
        /// Expect a client connect event
        /// </summary>
        /// <param name="timeout">time to wait if no response</param>
        /// <returns>true for success and false for failure</returns>
        /// <exception cref="InvalidOperationException">
        /// The transport is not started. Please invoke Start() first.
        /// </exception>
        /// <exception cref="InvalidCastException">Unknown object received in transport.</exception>
        public virtual CifsServerPerConnection ExpectConnect(TimeSpan timeout)
        {
            if (this.isRunning == false)
            {
                throw new InvalidOperationException(
                    "The transport is not started. Please invoke Start() first.");
            }

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

            if (transportEvent.EventType == EventType.Connected)
            {
                CifsServerPerConnection connection = new CifsServerPerConnection();
                connection.Identity = transportEvent.EndPoint;
                this.context.AddConnection(connection);

                return connection;
            }
            else if (transportEvent.EventType == EventType.Exception)
            {
                throw transportEvent.EventObject as Exception;
            }
            else
            {
                throw new InvalidCastException("Unknown object received in transport.");
            }
        }
        public SmbTreeConnectResponsePacket CreateTreeConnectResponse(
            CifsServerPerConnection connection,
            SmbTreeConnectRequestPacket request)
        {
            SmbTreeConnectResponsePacket response = new SmbTreeConnectResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            SMB_COM_TREE_CONNECT_Response_SMB_Parameters smbParameters = response.SmbParameters;
            smbParameters.MaxBufferSize = (ushort)this.context.MaxBufferSize;
            smbParameters.TID = (ushort)connection.GenerateTID();
            smbParameters.WordCount = (byte)(TypeMarshal.GetBlockMemorySize(smbParameters) / 2);
            response.SmbParameters = smbParameters;

            return response;
        }
        public SmbWriteResponsePacket CreateWriteResponse(
            CifsServerPerConnection connection,
            SmbWriteRequestPacket request)
        {
            SmbWriteResponsePacket response = new SmbWriteResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            SMB_COM_WRITE_Response_SMB_Parameters smbParameters = response.SmbParameters;

            smbParameters.CountOfBytesWritten = request.SmbParameters.CountOfBytesToWrite;
            smbParameters.WordCount = (byte)(TypeMarshal.GetBlockMemorySize(smbParameters) / 2);
            response.SmbParameters = smbParameters;

            return response;
        }
 /// <summary>
 /// disconnect the connection
 /// </summary>
 /// <param name="connection">the connection to disconnect</param>
 /// <exception cref="ArgumentNullException">the connection is null</exception>
 public virtual void Disconnect(CifsServerPerConnection connection)
 {
     if (connection == null)
     {
         throw new ArgumentException("The connection is null.");
     }
     this.transport.Disconnect(connection.Identity);
     this.context.RemoveConnection(connection.Identity);
 }
        /// <summary>
        /// remove request and sequence if the response is the final response.
        /// </summary>
        /// <param name="connection">the connection on which to remove the request and sequence</param>
        /// <param name="response">the response for which to remove the request and sequence</param>
        protected virtual void RemoveRequestAndSequence(CifsServerPerConnection connection, SmbPacket response)
        {
            if (response is SmbWriteRawInterimResponsePacket
                || response is SmbNtTransactInterimResponsePacket
                || response is SmbTransactionInterimResponsePacket
                || response is SmbTransaction2InterimResponsePacket)
            {
                return;
            }

            connection.RemovePendingRequest(response.SmbHeader.Mid);
            connection.RemoveSequenceNumber(response);
        }
        public SmbFindUniqueResponsePacket CreateFindUniqueResponse(
            CifsServerPerConnection connection,
            SmbFindUniqueRequestPacket request,
            SMB_Directory_Information[] directoryInformationData)
        {
            directoryInformationData = directoryInformationData ?? new SMB_Directory_Information[0];
            SmbFindUniqueResponsePacket response = new SmbFindUniqueResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            SMB_COM_FIND_UNIQUE_Response_SMB_Parameters smbParameters = response.SmbParameters;
            smbParameters.Count = (ushort)directoryInformationData.Length;
            smbParameters.WordCount = (byte)(TypeMarshal.GetBlockMemorySize(smbParameters) / 2);
            response.SmbParameters = smbParameters;

            ushort dataLength = 0;
            foreach (SMB_Directory_Information info in directoryInformationData)
            {
                dataLength += (ushort)TypeMarshal.GetBlockMemorySize(info);
            }
            SMB_COM_FIND_UNIQUE_Response_SMB_Data smbData = response.SmbData;
            smbData.BufferFormat = 0x05;
            smbData.DirectoryInformationData = directoryInformationData;
            smbData.DataLength = dataLength;
            smbData.ByteCount = (ushort)(dataLength + 0x03);
            response.SmbData = smbData;

            return response;
        }
 /// <summary>
 /// Send bytes to specific connected client.
 /// Sdk won't update context because it doesn't know what message will be sent.
 /// please set IsContextUpdateEnabled false, and update context manually.
 /// </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, CifsServerPerConnection connection)
 {
     if (connection == null)
     {
         throw new ArgumentNullException("connection");
     }
     this.transport.SendBytes(connection.Identity, bytes);
 }
        /// <summary>
        /// Add a connection into ConnectionTable
        /// </summary>
        /// <param name="connection">The connection to be added or updated.</param>
        /// <exception cref="ArgumentNullException">The connection is null</exception>
        /// <exception cref="ArgumentException">The connection already exists</exception>
        public void AddConnection(CifsServerPerConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentException("The connection is null.");
            }

            lock (this.globalTables)
            {
                this.globalTables.ConnectionTable.Add(connection.Identity, connection);
            }
        }
        /// <summary>
        /// Update the context of cifs server
        /// </summary>
        /// <param name="connection">The connection between client and server.</param>
        /// <param name="packet">The sent or received packet in stack transport.</param>
        public virtual void UpdateRoleContext(CifsServerPerConnection connection, SmbPacket packet)
        {
            if (connection == null || packet == null)
            {
                return;
            }

            if (packet is SmbReadRawResponsePacket)
            {
                if (connection.PendingRequestTable.Count != 1)
                {
                    return;
                }
                SmbPacket request = connection.PendingRequestTable[0] as SmbPacket;
                this.UpdateResponseRoleContext(connection, request, packet);
                connection.RemovePendingRequest(request.SmbHeader.Mid);
                connection.RemoveSequenceNumber(packet);
                return;
            }
            else
            {
                switch(packet.PacketType)
                {
                    case SmbPacketType.BatchedRequest:
                    case SmbPacketType.SingleRequest:
                        if (connection.IsSigningActive)
                        {
                            packet.IsSignatureCorrect = CifsMessageUtils.VerifySignature(packet,
                                connection.SigningSessionKey, connection.ServerNextReceiveSequenceNumber,
                                connection.SigningChallengeResponse);
                        }
                        this.UpdateRequestRoleConext(connection, packet);
                        break;
                    case SmbPacketType.BatchedResponse:
                    case SmbPacketType.SingleResponse:
                        SmbPacket request = connection.GetPendingRequest(packet.SmbHeader.Mid);
                        this.UpdateResponseRoleContext(connection, request, packet);
                        this.RemoveRequestAndSequence(connection, packet);
                        break;
                    default:
                        break;
                }
            }
        }
        public SmbFindClose2ResponsePacket CreateFindClose2Response(
            CifsServerPerConnection connection,
            SmbFindClose2RequestPacket request)
        {
            SmbFindClose2ResponsePacket response = new SmbFindClose2ResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            return response;
        }
        public SmbWriteRawInterimResponsePacket CreateWriteRawInterimResponse(
            CifsServerPerConnection connection,
            SmbWriteRawRequestPacket request,
            ushort available)
        {
            SmbWriteRawInterimResponsePacket response = new SmbWriteRawInterimResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            SMB_COM_WRITE_RAW_InterimResponse_SMB_Parameters smbParameters = response.SmbParameters;
            smbParameters.Available = available;
            smbParameters.WordCount = (byte)(TypeMarshal.GetBlockMemorySize(smbParameters) / 2);
            response.SmbParameters = smbParameters;

            return response;
        }
        public SmbFindCloseResponsePacket CreateFindCloseResponse(
            CifsServerPerConnection connection,
            SmbFindCloseRequestPacket request)
        {
            SmbFindCloseResponsePacket response = new SmbFindCloseResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            SMB_COM_FIND_CLOSE_Response_SMB_Parameters smbParameters = response.SmbParameters;
            smbParameters.Count = 0x00;
            smbParameters.WordCount = (byte)(TypeMarshal.GetBlockMemorySize(smbParameters) / 2);
            response.SmbParameters = smbParameters;

            SMB_COM_FIND_CLOSE_Response_SMB_Data smbData = response.SmbData;
            smbData.BufferFormat = 0x05;
            smbData.DataLength = 0x0000;
            smbData.ByteCount = 0x0003;
            response.SmbData = smbData;

            return response;
        }
        public SmbTransWaitNmpipeSuccessResponsePacket CreateTransWaitNmpipeSuccessResponse(
            CifsServerPerConnection connection,
            SmbTransWaitNmpipeRequestPacket request)
        {
            SmbTransWaitNmpipeSuccessResponsePacket response = new SmbTransWaitNmpipeSuccessResponsePacket();
            response.SmbHeader = CifsMessageUtils.CreateSmbHeader(connection, request);

            response.UpdateCountAndOffset();

            return response;
        }