The SMB2 Packet Header - SYNC packet is the header of all SMB 2.0 Protocol packets. If the SMB2_FLAGS_ASYNC_COMMAND is not set in Flags, the header takes the following form:
        public void ComNegotiateRequest(Sequence<string> dialects)
        {
            Packet_Header responseHeader = new Packet_Header();
            DialectRevision selectedDialect = DialectRevision.Smb2Unknown;
            NEGOTIATE_Response responsePayload = new NEGOTIATE_Response();
            byte[] smb2ClientGssToken;
            ModelSmb2Status status = ModelSmb2Status.STATUS_SUCCESS;

            try
            {
                status = (ModelSmb2Status)smb2Client.MultiProtocolNegotiate(dialects.ToArray(), out selectedDialect, out smb2ClientGssToken, out responseHeader, out responsePayload);
                if (status != ModelSmb2Status.STATUS_SUCCESS)
                {
                    selectedDialect = DialectRevision.Smb2Unknown;
                }
                this.NegotiateResponse(status, selectedDialect);
                if (selectedDialect == DialectRevision.Smb2Wildcard)
                {
                    messageId = 1;
                }
            }
            catch
            {
            }
        }
        public void NegotiateRequest(Sequence<DialectRevision> dialects)
        {
            Packet_Header responseHeader = new Packet_Header();
            DialectRevision selectedDialect = DialectRevision.Smb2Unknown;
            NEGOTIATE_Response responsePayload = new NEGOTIATE_Response();
            byte[] smb2ClientGssToken;
            ModelSmb2Status status = ModelSmb2Status.STATUS_SUCCESS;

            try
            {
                status = (ModelSmb2Status)smb2Client.Negotiate(0, 1, Packet_Header_Flags_Values.NONE, messageId++, dialects.ToArray(), SecurityMode_Values.NONE, Capabilities_Values.NONE, Guid.NewGuid(),
                    out selectedDialect, out smb2ClientGssToken, out responseHeader, out responsePayload);
                if (status != ModelSmb2Status.STATUS_SUCCESS)
                {
                    selectedDialect = DialectRevision.Smb2Unknown;
                }
                this.NegotiateResponse(status, selectedDialect);
            }
            catch
            {
            }
        }
        /// <summary>
        /// Get the real sessionId granted by server.
        /// </summary>
        /// <param name="header">The header of packet</param>
        /// <returns>The real sessionId</returns>
        private ulong GetRealSessionId(Packet_Header header)
        {
            ulong sessionId = header.SessionId;

            if ((header.Flags & Packet_Header_Flags_Values.FLAGS_RELATED_OPERATIONS)
                == Packet_Header_Flags_Values.FLAGS_RELATED_OPERATIONS)
            {
                if (header.SessionId == ulong.MaxValue)
                {
                    for (int i = packets.Count - 1; i >= 0; i--)
                    {
                        if (packets[i].Header.SessionId != ulong.MaxValue)
                        {
                            sessionId = packets[i].Header.SessionId;
                            break;
                        }
                    }
                }
            }

            return sessionId;
        }
 protected virtual uint TreeConnect(
     ushort creditCharge,
     ushort creditRequest,
     Packet_Header_Flags_Values flags,
     ulong messageId,
     ulong sessionId,
     string server,
     string share,
     out Packet_Header header,
     out TREE_CONNECT_Response response)
 {
     return client.TreeConnect(
                 creditCharge,
                 creditRequest,
                 flags,
                 messageId,
                 sessionId,
                 string.Format(@"\\{0}\{1}", server, share),
                 out treeId,
                 out header,
                 out response);
 }
 private void OnLeaseBreakNotificationReceived(Packet_Header header, OPLOCK_BREAK_Notification_Packet notification)
 {
     breakType = ModelBreakType.OplockBreak;
     oplockClient.OplockAcknowledgement(treeIdOplock, notification.FileId, (OPLOCK_BREAK_Acknowledgment_OplockLevel_Values)notification.OplockLevel);
 }
 private void OnLeaseBreakNotificationReceived(Packet_Header header, LEASE_BREAK_Notification_Packet notification)
 {
     // Set Lease breake state
     leaseBreakState = LeaseBreakState.LeaseBreakExisted;
 }
        void PrintSequenceWindow(Packet_Header header)
        {
            Site.Log.Add(LogEntryKind.Debug, "Server grants {0} credits after {1}:", header.CreditRequestResponse, header.Command);
            Site.Log.Add(LogEntryKind.Debug, "SequenceWindow after {0}:", header.Command);

            foreach (var item in testClient.SequenceWindow)
            {
                Site.Log.Add(LogEntryKind.Debug, "\t{0}", item);
            }
        }
        private void OnLeaseBreakNotificationReceived(Packet_Header respHeader, LEASE_BREAK_Notification_Packet leaseBreakNotify)
        {
            Site.Log.Add(LogEntryKind.Debug, "LeaseBreakNotification was received from server");

            Site.Assert.AreEqual<Smb2Command>(Smb2Command.OPLOCK_BREAK, respHeader.Command, "Expect that the Command MUST be OPLOCK_BREAK.");
            Site.Assert.AreEqual<ulong>(0xFFFFFFFFFFFFFFFF, respHeader.MessageId, "Expect that the field MessageId MUST be set to 0xFFFFFFFFFFFFFFFF.");
            Site.Assert.AreEqual<ulong>(0, respHeader.SessionId, "Expect that the field SessionId MUST be set to 0.");
            Site.Assert.AreEqual<uint>(0, respHeader.TreeId, "Expect that the field TreeId MUST be set to 0.");

            Site.CaptureRequirementIfAreEqual<ushort>((ushort)44, leaseBreakNotify.StructureSize,
                        RequirementCategory.MUST_BE_SPECIFIED_VALUE.Id,
                        RequirementCategory.MUST_BE_SPECIFIED_VALUE.Description);
            Site.Assert.AreEqual<Guid>(LeaseKey, leaseBreakNotify.LeaseKey, "Expect that the field LeaseKey equals {0}.", LeaseKey.ToString());
            Site.CaptureRequirementIfAreEqual<uint>(0, leaseBreakNotify.BreakReason,
                        RequirementCategory.MUST_BE_ZERO.Id,
                        RequirementCategory.MUST_BE_ZERO.Description);
            Site.CaptureRequirementIfAreEqual<uint>(0, leaseBreakNotify.AccessMaskHint,
                        RequirementCategory.MUST_BE_ZERO.Id,
                        RequirementCategory.MUST_BE_ZERO.Description);
            Site.CaptureRequirementIfAreEqual<uint>(0, leaseBreakNotify.ShareMaskHint,
                        RequirementCategory.MUST_BE_ZERO.Id,
                        RequirementCategory.MUST_BE_ZERO.Description);

            Site.Log.Add(LogEntryKind.Debug, "Current lease state: \t{0}", leaseBreakNotify.CurrentLeaseState);
            Site.Log.Add(LogEntryKind.Debug, "New lease state: \t{0}", leaseBreakNotify.NewLeaseState);
            Site.Log.Add(LogEntryKind.Debug, "New epoch: \t{0}", leaseBreakNotify.NewEpoch);

            this.OnLeaseBreakNotification(leaseBreakNotify.NewEpoch, leaseBreakNotify.Flags, (uint)leaseBreakNotify.CurrentLeaseState,
                (uint)leaseBreakNotify.NewLeaseState);
        }
        /// <summary>
        /// Handle the lease break notification.
        /// </summary>
        /// <param name="respHeader">The SMB2 header included in the notification.</param>
        /// <param name="leaseBreakNotify">Lease break notification payload in the notification.</param>
        private void OnLeaseBreakNotificationReceived(Packet_Header respHeader, LEASE_BREAK_Notification_Packet leaseBreakNotify)
        {
            Smb2FunctionalClient client = null;
            if (smb2ClientMainChannel != null)
            {
                client = smb2ClientMainChannel;
            }
            else if (smb2ClientAlternativeChannel != null)
            {
                client = smb2ClientAlternativeChannel;
            }

            if (client != null)
            {
                Site.Log.Add(LogEntryKind.Debug, "Receive a lease break notification and will send lease break acknowledgment.");
                client.LeaseBreakAcknowledgment(
                    treeIdMainChannel,
                    leaseKeyMainChannel,
                    leaseBreakNotify.NewLeaseState);
            }
        }
        private void CheckIoCtlResponse(Packet_Header header, IOCTL_Response response)
        {
            if (header.Status != Smb2Status.STATUS_SUCCESS) return;

            FILEID ioCtlFileId;
            ioCtlFileId.Persistent = 0xFFFFFFFFFFFFFFFF;
            ioCtlFileId.Volatile = 0xFFFFFFFFFFFFFFFF;
            Site.Assert.AreEqual(ioCtlFileId, response.FileId, "FileId MUST be set to { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF }.");
            Site.Assert.AreEqual(0, (int)response.Flags, "Flags MUST be set to zero.");
            Site.Assert.AreEqual((uint)CtlCode_Values.FSCTL_VALIDATE_NEGOTIATE_INFO, response.CtlCode, "CtlCode MUST be set to FSCTL_VALIDATE_NEGOTIATE_INFO.");
        }
            protected override uint TreeConnect(ushort creditCharge, ushort creditRequest, Packet_Header_Flags_Values flags, ulong messageId, ulong sessionId, 
                string server, string share, out Packet_Header header, out TREE_CONNECT_Response response)
            {
                uint treeConnectResponseCode = base.TreeConnect(creditCharge, creditRequest, flags, messageId, sessionId, server, share, out header, out response);

                if (supportV1)
                {
                    testSite.Assert.IsTrue(
                    response.ShareFlags.HasFlag(ShareFlags_Values.SHAREFLAG_ENABLE_HASH_V1),
                    "The share content should enable hash v1");
                }
                if (supportV2)
                {
                    testSite.Assert.IsTrue(
                    response.ShareFlags.HasFlag(ShareFlags_Values.SHAREFLAG_ENABLE_HASH_V2),
                    "The share content should enable hash v2");
                }

                return treeConnectResponseCode;
            }
 protected override uint Negotiate(ushort creditCharge, ushort creditRequest, ulong messageId, Guid clientGuid, 
     out DialectRevision selectedDialect, out byte[] gssToken, out Packet_Header responseHeader, out NEGOTIATE_Response responsePayload)
 {
     if (supportV2)
     {
         return client.Negotiate(
         creditCharge,
         creditRequest,
         Packet_Header_Flags_Values.NONE,
         messageId,
         new DialectRevision[] { DialectRevision.Smb30 },
         SecurityMode_Values.NONE,
         Capabilities_Values.NONE,
         clientGuid,
         out selectedDialect,
         out gssToken,
         out responseHeader,
         out responsePayload);
     }
     else
     {
         return client.Negotiate(
         creditCharge,
         creditRequest,
         Packet_Header_Flags_Values.NONE,
         messageId,
         new DialectRevision[] { DialectRevision.Smb21 },
         SecurityMode_Values.NONE,
         Capabilities_Values.NONE,
         clientGuid,
         out selectedDialect,
         out gssToken,
         out responseHeader,
         out responsePayload);
     }
 }
 /// <summary>
 /// Check the status code of create response
 /// </summary>
 /// <param name="isNonAdmin">true for non admin credential</param>
 /// <param name="createOption">The create option set in create request</param>
 /// <param name="accessMask">The access mark set in create request</param>
 /// <param name="header">Header of create response</param>
 /// <param name="response">create response</param>
 /// <param name="fileNameType">file name type</param>
 private void CheckCreateResponse(bool isNonAdmin, CreateOptions_Values createOption, AccessMask accessMask, Packet_Header header, CREATE_Response response, FileNameType fileNameType)
 {
     switch (fileNameType)
     {
         case FileNameType.SymbolicLinkInMiddle:
             {
                 BaseTestSite.Assert.AreEqual(
                     Smb2Status.STATUS_STOPPED_ON_SYMLINK,
                     header.Status,
                     "3.3.5.9: If any intermediate component of the path specified in the create request is a symbolic link, " +
                     "the server MUST return an error as specified in section 2.2.2.1. " +
                     "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                 break;
             }
         case FileNameType.SymbolicLinkAtLast:
             {
                 if (!createOption.HasFlag(CreateOptions_Values.FILE_OPEN_REPARSE_POINT))
                 {
                     BaseTestSite.Assert.AreEqual(
                         Smb2Status.STATUS_STOPPED_ON_SYMLINK,
                         header.Status,
                         "3.3.5.9: If the final component of the path is a symbolic link, the server behavior depends on whether the flag FILE_OPEN_REPARSE_POINT was specified in the CreateOptions field of the request. " +
                         "If FILE_OPEN_REPARSE_POINT was specified, the server MUST open the underlying file or directory and return a handle to it. " +
                         "Otherwise, the server MUST return an error as specified in section 2.2.2.1. " +
                         "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                 }
                 break;
             }
         case FileNameType.InvalidSymbolicLink:
             {
                 BaseTestSite.Assert.AreEqual(
                     Smb2Status.STATUS_STOPPED_ON_SYMLINK,
                     header.Status,
                     "3.3.5.9: If the underlying object store returns a failure indicating that the attempted open operation failed due to the presence of a symbolic link in the target path name, " +
                     "the server MUST fail the create operation with the error code STATUS_STOPPED_ON_SYMLINK. " +
                     "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                 break;
             }
         case FileNameType.NotExistedValidFileName:
             {
                 if (createOption.HasFlag(CreateOptions_Values.FILE_DELETE_ON_CLOSE)
                     && !(accessMask.HasFlag(AccessMask.DELETE) || accessMask.HasFlag(AccessMask.GENERIC_ALL)))
                 {
                     if (testConfig.Platform == Platform.NonWindows)
                     {
                         BaseTestSite.Assert.AreNotEqual(
                             Smb2Status.STATUS_SUCCESS,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "DesiredAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                     else if (testConfig.Platform == Platform.WindowsServer2008
                         || testConfig.Platform == Platform.WindowsServer2008R2)
                     {
                         //TD does not specify the behavior of windows 2008 and 2008R2, not check here
                     }
                     else if(testConfig.Platform == Platform.WindowsServer2012)
                     {
                         //For platform windows 2012
                         BaseTestSite.Assert.AreEqual(
                             Smb2Status.STATUS_INVALID_PARAMETER,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "DesiredAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                     else
                     {
                         //For platform windows 2012R2 and above
                         BaseTestSite.Assert.AreEqual(
                             Smb2Status.STATUS_ACCESS_DENIED,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "DesiredAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                 }
                 else if (createOption.HasFlag(CreateOptions_Values.FILE_DELETE_ON_CLOSE) && isNonAdmin)
                 {
                     //NonAdminAccountCredential does not include DELETE or GENERIC_ALL in MaximalAccess
                     if (testConfig.Platform == Platform.NonWindows)
                     {
                         BaseTestSite.Assert.AreNotEqual(
                             Smb2Status.STATUS_SUCCESS,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "Treeconnect.MaximalAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                     else if (testConfig.Platform == Platform.WindowsServer2008
                         || testConfig.Platform == Platform.WindowsServer2008R2)
                     {
                         //TD does not specify te behavior of windows 2008 and 2008R2, not check here
                     }
                     else
                     {
                         //For platform win2012 and 2012R2
                         BaseTestSite.Assert.AreEqual(
                             Smb2Status.STATUS_ACCESS_DENIED,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "Treeconnect.MaximalAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                 }
                 else
                 {
                     BaseTestSite.Assert.AreEqual(
                         Smb2Status.STATUS_SUCCESS,
                         header.Status,
                         "{0} should be successful, actually server returns with {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));
                 }
                 break;
             }
         case FileNameType.ExistedValidFileName:
             {
                 BaseTestSite.Assert.AreEqual(
                         Smb2Status.STATUS_SUCCESS,
                         header.Status,
                         "{0} should be successful, actually server returns with {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));
             }
             break;
         default:
             throw new ArgumentException("fileNameType");
     }
 }
 /// <summary>
 /// Get treeId from the async packet
 /// </summary>
 /// <param name="header">The packet header</param>
 /// <returns>The treeId</returns>
 private uint GetTreeIdFromAsyncPacket(Packet_Header header)
 {
     throw new NotImplementedException();
 }
        /// <summary>
        /// Get the real treeId granted by server.
        /// </summary>
        /// <param name="header">The header of packet</param>
        /// <returns>The real treeId</returns>
        private uint GetRealTreeId(Packet_Header header)
        {
            uint treeId = header.TreeId;

            if ((header.Flags & Packet_Header_Flags_Values.FLAGS_ASYNC_COMMAND)
                == Packet_Header_Flags_Values.FLAGS_ASYNC_COMMAND)
            {
                treeId = GetTreeIdFromAsyncPacket(header);
            }

            if ((header.Flags & Packet_Header_Flags_Values.FLAGS_RELATED_OPERATIONS)
                == Packet_Header_Flags_Values.FLAGS_RELATED_OPERATIONS)
            {
                if (treeId == uint.MaxValue)
                {
                    for (int i = packets.Count - 1; i >= 0; i--)
                    {
                        if ((packets[i].Header.Flags & Packet_Header_Flags_Values.FLAGS_ASYNC_COMMAND)
                            == Packet_Header_Flags_Values.FLAGS_ASYNC_COMMAND)
                        {
                            treeId = GetTreeIdFromAsyncPacket(packets[i].Header);
                        }
                        else
                        {
                            treeId = packets[i].Header.TreeId;
                        }

                        //0xffffffff is not a real treeId
                        //keep searching the real treeId if it
                        //is oxffffffff
                        if (treeId != uint.MaxValue)
                        {
                            break;
                        }
                    }
                }
            }

            return treeId;
        }
        private void OnOplockBreakNotificationReceived(Packet_Header header, OPLOCK_BREAK_Notification_Packet packet)
        {
            Site.Log.Add(LogEntryKind.Debug, "OplockBreakNotification was received from server");

            Site.Assert.AreEqual(
                Smb2Command.OPLOCK_BREAK,
                header.Command,
                "The server MUST set the Command in the SMB2 header to SMB2 OPLOCK_BREAK");

            Site.Assert.AreEqual(
                0xFFFFFFFFFFFFFFFF,
                header.MessageId,
                "The server MUST set the MessageId to 0xFFFFFFFFFFFFFFFF");

            Site.Assert.AreEqual(
                (ulong)0,
                header.SessionId,
                "The server MUST set the SessionId to 0");

            Site.Assert.AreEqual(
                (uint)0,
                header.TreeId,
                "The server MUST set the TreeId to 0");

            Site.Assert.AreEqual(
                fileId,
                packet.FileId,
                "The FileId field of the response structure MUST be set to the values from the Open structure, with the volatile part set to Open.FileId and the persistent part set to Open.DurableFileId");

            // Verify signature is set to 0 if it's not signed
            Site.Assert.AreEqual(
                true,
                BitConverter.ToUInt64(header.Signature, 0) == 0 && BitConverter.ToUInt64(header.Signature, 8) == 0,
                "The SMB2 Oplock Break Notification is sent to the client. The message MUST NOT be signed, as specified in section 3.3.4.1.1");

            OplockBreakNotification(packet.OplockLevel);
        }
        private void InitializeClient(LeasingClientInfo clientInfo, ModelDialectRevision dialect, bool isClientSupportDirectoryLeasing = false)
        {
            #region Connect to server
            switch (testConfig.UnderlyingTransport)
            {
                case Smb2TransportType.Tcp:
                    Site.Assert.IsTrue(
                        testConfig.SutIPAddress != null && testConfig.SutIPAddress != System.Net.IPAddress.None,
                        "Server IP should not be empty when transport type is TCP.");
                    Site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over TCP", testConfig.SutIPAddress.ToString());
                    clientInfo.Client.ConnectOverTCP(testConfig.SutIPAddress);
                    break;
                case Smb2TransportType.NetBios:
                    Site.Assert.IsFalse(string.IsNullOrEmpty(testConfig.SutComputerName), "Server name should not be null when transport type is NetBIOS.");
                    Site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over NetBios", testConfig.SutComputerName);
                    clientInfo.Client.ConnectOverNetbios(testConfig.SutComputerName);
                    break;
                default:
                    Site.Assert.Fail("The transport type is {0}, but currently only Tcp and NetBIOS are supported.", testConfig.UnderlyingTransport);
                    break;
            }
            #endregion

            uint status = 0;
            Packet_Header responseHeader = new Packet_Header();
            DialectRevision selectedDialect;
            DialectRevision[] dialects = Smb2Utility.GetDialects(ModelUtility.GetDialectRevision(dialect));
            NEGOTIATE_Response negotiatePayload;

            #region Negotiate
            status = clientInfo.Client.Negotiate(0, 1, Packet_Header_Flags_Values.NONE, clientInfo.MessageId++,
                dialects, SecurityMode_Values.NONE, isClientSupportDirectoryLeasing ? Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING : Capabilities_Values.NONE,
                clientInfo.ClientGuid,
                out selectedDialect,
                out clientInfo.ServerGssToken,
                out responseHeader,
                out negotiatePayload);
            Site.Assert.AreEqual(ModelUtility.GetDialectRevision(dialect), negotiatePayload.DialectRevision,
                "DialectRevision 0x{0:x4} is expected.", (ushort)ModelUtility.GetDialectRevision(dialect));
            Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Negotiation is expected success");
            clientInfo.Dialect = selectedDialect;

            #region Validate Negotiate Response
            if (Smb2Utility.IsSmb3xFamily(selectedDialect))
            {
                Site.Assert.AreEqual<bool>(leasingConfig.IsLeasingSupported,
                    negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING),
                    "Expect that the Capabilities in the response {0} SMB2_GLOBAL_CAP_LEASING 0x00000002.", leasingConfig.IsLeasingSupported ? "contains" : "does not contain");
                Site.Assert.AreEqual<bool>(leasingConfig.IsDirectoryLeasingSupported & isClientSupportDirectoryLeasing,
                    negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING),
                    "Expect that the Capabilities in the response {0} SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020.",
                    leasingConfig.IsDirectoryLeasingSupported & isClientSupportDirectoryLeasing ? "contains" : "does not contain");
            }
            else if (selectedDialect == DialectRevision.Smb21)
            {
                Site.Assert.AreEqual<bool>(leasingConfig.IsLeasingSupported,
                    negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING),
                    "Expect that the Capabilities in the response {0} SMB2_GLOBAL_CAP_LEASING 0x00000002.", leasingConfig.IsLeasingSupported ? "contains" : "does not contain");
                Site.Assert.IsFalse(negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING),
                    "Expect that the Capabilities in the response does not contain SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020.");
            }
            else
            {
                Site.Assert.IsFalse(negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING),
                    "Expect that the Capabilities in the response does not contain SMB2_GLOBAL_CAP_LEASING 0x00000002.");
                Site.Assert.IsFalse(negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING),
                    "Expect that the Capabilities in the response does not contain SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020.");
            }
            #endregion
            #endregion

            #region SESSION_SETUP
            Packet_Header header;
            SESSION_SETUP_Response sessionSetupResponse;

            SspiClientSecurityContext sspiClientGss =
                new SspiClientSecurityContext(
                    testConfig.DefaultSecurityPackage,
                    testConfig.AccountCredential,
                    Smb2Utility.GetCifsServicePrincipalName(testConfig.SutComputerName),
                    ClientSecurityContextAttribute.None,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            // Server GSS token is used only for Negotiate authentication when enabled
            if (testConfig.DefaultSecurityPackage == SecurityPackageType.Negotiate && testConfig.UseServerGssToken)
                sspiClientGss.Initialize(clientInfo.ServerGssToken);
            else
                sspiClientGss.Initialize(null);

            do
            {
                status = clientInfo.Client.SessionSetup(
                    1,
                    64,
                    Packet_Header_Flags_Values.NONE,
                    clientInfo.MessageId++,
                    clientInfo.SessionId,
                    SESSION_SETUP_Request_Flags.NONE,
                    SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    SESSION_SETUP_Request_Capabilities_Values.NONE,
                    0,
                    sspiClientGss.Token,
                    out clientInfo.SessionId,
                    out clientInfo.ServerGssToken,
                    out header,
                    out sessionSetupResponse);

                if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) &&
                    clientInfo.ServerGssToken != null && clientInfo.ServerGssToken.Length > 0)
                {
                    sspiClientGss.Initialize(clientInfo.ServerGssToken);
                }
            } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

            if (status == Smb2Status.STATUS_SUCCESS)
            {
                clientInfo.SessionKey = sspiClientGss.SessionKey;
                clientInfo.Client.GenerateCryptoKeys(clientInfo.SessionId, clientInfo.SessionKey, true, false);
            }

            clientInfo.GrantedCredit = header.CreditRequestResponse;
            Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "SessionSetup should succeed, actual status is {0}", Smb2Status.GetStatusCode(status));
            #endregion

            #region TREE_CONNECT to share
            TREE_CONNECT_Response treeConnectPayload;
            status = clientInfo.Client.TreeConnect(1, 1, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, uncSharePath,
                out clientInfo.TreeId, out header, out treeConnectPayload);
            Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "TreeConnect to {0} should succeed, actual status is {1}", uncSharePath, Smb2Status.GetStatusCode(status));
            if (treeConnectPayload.ShareFlags.HasFlag(ShareFlags_Values.SHAREFLAG_FORCE_LEVELII_OPLOCK))
            {
                Site.Assert.Inconclusive("This test case is not applicable for the share whose ShareFlags includes SHAREFLAG_FORCE_LEVELII_OPLOCK.");
            }
            if (treeConnectPayload.Capabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_SCALEOUT))
            {
                Site.Assert.Inconclusive("This test case is not applicable for the share whose Capabilities includes SHARE_CAP_SCALEOUT.");
            }
            #endregion
        }
        /// <summary>
        /// Handle the oplock break notification.
        /// </summary>
        /// <param name="respHeader">The SMB2 header included in the notification.</param>
        /// <param name="oplockBreakNotify">Oplock break notification payload in the notification.</param>
        private void OnOplockBreakNotificationReceived(Packet_Header respHeader, OPLOCK_BREAK_Notification_Packet oplockBreakNotify)
        {
            Smb2FunctionalClient client = null;
            if (smb2ClientMainChannel != null)
            {
                client = smb2ClientMainChannel;
            }
            else if (smb2ClientAlternativeChannel != null)
            {
                client = smb2ClientAlternativeChannel;
            }

            if (client != null)
            {
                Site.Log.Add(LogEntryKind.Debug, "Receive an oplock break notification and will send oplock break acknowledgment.");
                client.OplockAcknowledgement(
                    treeIdMainChannel,
                    fileIdMainChannel,
                    (OPLOCK_BREAK_Acknowledgment_OplockLevel_Values)oplockBreakNotify.OplockLevel,
                    checker: (responseHeader, response) => { }
                    );
            }
        }
        /// <summary>
        /// Handle the lease break notification.
        /// </summary>
        /// <param name="respHeader">The SMB2 header included in the notification.</param>
        /// <param name="leaseBreakNotify">Lease break notification payload in the notification.</param>
        public void OnLeaseBreakNotificationReceived(Packet_Header respHeader, LEASE_BREAK_Notification_Packet leaseBreakNotify)
        {
            uint status = 0;
            Packet_Header header;
            LEASE_BREAK_Response leaseBreakResp;

            status = Client.LeaseBreakAcknowledgment(1, 1, Flags, MessageId++, SessionId,
                TreeId, leaseBreakNotify.LeaseKey, leaseBreakNotify.NewLeaseState, out header, out leaseBreakResp);
        }
 protected override void OnLeaseBreakNotificationReceived(Packet_Header respHeader, LEASE_BREAK_Notification_Packet leaseBreakNotify)
 {
     BaseTestSite.Log.Add(LogEntryKind.Debug, "LeaseBreakNotification was received from server");
     isLeaseBreakReceived = true;
 }
        /// <summary>
        /// Handler when receive a LeaseBreakNotification
        /// </summary>
        /// <param name="respHeader">Packet header of LeaseBreakNotification</param>
        /// <param name="leaseBreakNotify">Received LeaseBreakNotification</param>
        protected override void OnLeaseBreakNotificationReceived(Packet_Header respHeader, LEASE_BREAK_Notification_Packet leaseBreakNotify)
        {
            BaseTestSite.Log.Add(
                LogEntryKind.Comment,
                "LeaseBreakNotification with LeaseKey \"{0}\" was received from server", leaseBreakNotify.LeaseKey.ToString());
            lock (breakNotifications)
            {
                breakNotifications.Add(leaseBreakNotify.LeaseKey, leaseBreakNotify);
            }

            receivedLeaseBreakNotify = leaseBreakNotify;

            BaseTestSite.Assert.AreEqual<ulong>(
                0xFFFFFFFFFFFFFFFF,
                respHeader.MessageId,
                "Expect that the field MessageId is set to 0xFFFFFFFFFFFFFFFF.");
            BaseTestSite.Assert.AreEqual<ulong>(
                0,
                respHeader.SessionId,
                "Expect that the field SessionId is set to 0.");
            BaseTestSite.Assert.AreEqual<uint>(
                0,
                respHeader.TreeId,
                "Expect that the field TreeId is set to 0.");

            BaseTestSite.Assert.AreEqual(
                expectedNewLeaseStates[leaseBreakNotify.LeaseKey],
                leaseBreakNotify.NewLeaseState,
                "NewLeaseState in LeaseBreakNotification from server should be {0}", expectedNewLeaseStates[leaseBreakNotify.LeaseKey]);
            // NewEpoch should be 2 based on assumption that no lease state change before this break since server initially granted
            BaseTestSite.Assert.AreEqual(
                2,
                leaseBreakNotify.NewEpoch,
                "NewEpoch in LeaseBreakNotification from server should be 2");
            BaseTestSite.Assert.AreEqual<uint>(
                0,
                leaseBreakNotify.BreakReason,
                "Expect that the field BreakReason is set to 0.");
            BaseTestSite.Assert.AreEqual<uint>(
                0,
                leaseBreakNotify.AccessMaskHint,
                "Expect that the field AccessMaskHint is set to 0.");
            BaseTestSite.Assert.AreEqual<uint>(
                0,
                leaseBreakNotify.ShareMaskHint,
                "Expect that the field ShareMaskHint is set to 0.");

            notificationsReceived[leaseBreakNotify.LeaseKey].Set();
        }
        private void OnOpLockBreakNotificationReceived(Packet_Header respHeader, OPLOCK_BREAK_Notification_Packet OpLockBreakNotify)
        {
            BaseTestSite.Log.Add(
                LogEntryKind.Comment,
                "OpLockBreakNotification was received from server");
            OpLockBreakNotifyReceived = OpLockBreakNotify;

            ///The FileId field of the response structure MUST be set to the values from the Open structure,
            ///with the volatile part set to Open.FileId and the persistent part set to Open.DurableFileId.
            BaseTestSite.Assert.AreEqual(fileId, OpLockBreakNotify.FileId, "FileId should be identical");

            BaseTestSite.Assert.IsTrue(
                OpLockBreakNotify.OplockLevel == OPLOCK_BREAK_Notification_Packet_OplockLevel_Values.OPLOCK_LEVEL_II ||
                OpLockBreakNotify.OplockLevel == OPLOCK_BREAK_Notification_Packet_OplockLevel_Values.OPLOCK_LEVEL_NONE,
                "The new oplock level MUST be either SMB2_OPLOCK_LEVEL_NONE or SMB2_OPLOCK_LEVEL_II.");
            OpLockNotificationReceived.Set();
        }
 private void OnLeaseBreakNotificationReceived(Packet_Header header, LEASE_BREAK_Notification_Packet notification)
 {
     // Set Lease break state
     breakType = ModelBreakType.LeaseBreak;
     leaseClient.LeaseBreakAcknowledgment(treeIdLease, notification.LeaseKey, notification.NewLeaseState);
 }
Exemplo n.º 24
0
 private void OnChangeNotifyResponseReceived(FILE_NOTIFY_INFORMATION[] fileNotifyInfo, Packet_Header respHeader, CHANGE_NOTIFY_Response changeNotify)
 {
     BaseTestSite.Log.Add(
         LogEntryKind.Debug,
         "Client1 receives the response of CHANGE_NOTIFY");
     receivedChangeNotify = changeNotify;
     receivedFileNotifyInfo = fileNotifyInfo;
     receivedChangeNotifyHeader = respHeader;
     changeNotificationReceived.Set();
 }
        private void CheckNegotiateResponse(
            Packet_Header header,
            NEGOTIATE_Response response,
            DialectRevision clientMaxDialectSupported,
            EncryptionAlgorithm[] encryptionAlgs)
        {
            DialectRevision expectedDialect = clientMaxDialectSupported < TestConfig.MaxSmbVersionSupported
                        ? clientMaxDialectSupported : TestConfig.MaxSmbVersionSupported;

            BaseTestSite.Assert.AreEqual(
                                Smb2Status.STATUS_SUCCESS,
                                header.Status,
                                "{0} should succeed, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));
            BaseTestSite.Assert.AreEqual(expectedDialect, response.DialectRevision, "Selected dialect should be {0}", expectedDialect);

            if (expectedDialect >= DialectRevision.Smb311)
            {
                BaseTestSite.Assert.AreEqual(
                    PreauthIntegrityHashID.SHA_512,
                    client.SelectedPreauthIntegrityHashID,
                    "[MS-SMB2] 3.3.5.4 The server MUST set Connection.PreauthIntegrityHashId to one of the hash algorithms " +
                    "in the client's SMB2_PREAUTH_INTEGRITY_CAPABILITIES HashAlgorithms array. ");

                if (encryptionAlgs != null)
                {
                    EncryptionAlgorithm expectedEnAlg = EncryptionAlgorithm.ENCRYPTION_NONE;
                    foreach (var alg in encryptionAlgs)
                    {
                        if (TestConfig.SupportedEncryptionAlgorithmList.Contains(alg))
                        {
                            expectedEnAlg = alg;
                            break;
                        }
                    }
                    BaseTestSite.Assert.AreEqual(
                        expectedEnAlg,
                        client.SelectedCipherID,
                        "[MS-SMB2] 3.3.5.4 The server MUST set Connection.CipherId to one of the ciphers in the client's " +
                        "SMB2_ENCRYPTION_CAPABILITIES Ciphers array in an implementation-specific manner.");
                }
                else
                {
                    BaseTestSite.Assert.AreEqual(
                        EncryptionAlgorithm.ENCRYPTION_NONE,
                        client.SelectedCipherID,
                        "[MS-SMB2] if client doesn't present SMB2_ENCRYPTION_CAPABILITIES context in negotiate request, " +
                        "server should not present this context in negotiate response.");
                }
            }
            else
            {
                // If server supported dialect version is lower than 3.11, server should ignore the negotiate contexts.
                BaseTestSite.Assert.AreEqual(
                    PreauthIntegrityHashID.HashAlgorithm_NONE,
                    client.SelectedPreauthIntegrityHashID,
                    "[MS-SMB2] The server must ignore the SMB2_PREAUTH_INTEGRITY_CAPABILITIES context if Connection.Dialect is less than 3.11. ");
                BaseTestSite.Assert.AreEqual(
                    EncryptionAlgorithm.ENCRYPTION_NONE,
                    client.SelectedCipherID,
                    "[MS-SMB2] The server must ignore the SMB2_ENCRYPTION_CAPABILITIES context if Connection.Dialect is less than 3.11. ");
            }
        }
        /// <summary>
        /// Handler when receive LeaseBreakNotification
        /// </summary>
        /// <param name="respHeader">Packet header in LeaseBreakNotification</param>
        /// <param name="leaseBreakNotify">Received LeaseBreakNotification</param>
        protected virtual void OnLeaseBreakNotificationReceived(Packet_Header respHeader, LEASE_BREAK_Notification_Packet leaseBreakNotify)
        {
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "LeaseBreakNotification was received from server");
            receivedLeaseBreakNotify = leaseBreakNotify;

            BaseTestSite.Assert.AreEqual<ulong>(
                0xFFFFFFFFFFFFFFFF,
                respHeader.MessageId,
                "Expect that the field MessageId is set to 0xFFFFFFFFFFFFFFFF.");
            BaseTestSite.Assert.AreEqual<ulong>(
                0,
                respHeader.SessionId,
                "Expect that the field SessionId is set to 0.");
            BaseTestSite.Assert.AreEqual<uint>(
                0,
                respHeader.TreeId,
                "Expect that the field TreeId is set to 0.");
            BaseTestSite.Assert.AreEqual(
                expectedNewLeaseState,
                leaseBreakNotify.NewLeaseState,
                "NewLeaseState in LeaseBreakNotification from server should be {0}", expectedNewLeaseState);
            BaseTestSite.Assert.AreEqual<uint>(
                0,
                leaseBreakNotify.BreakReason,
                "Expect that the field BreakReason is set to 0.");
            BaseTestSite.Assert.AreEqual<uint>(
                0,
                leaseBreakNotify.AccessMaskHint,
                "Expect that the field AccessMaskHint is set to 0.");
            BaseTestSite.Assert.AreEqual<uint>(
                0,
                leaseBreakNotify.ShareMaskHint,
                "Expect that the field ShareMaskHint is set to 0.");

            notificationReceived.Set();
        }
        protected virtual uint Negotiate(
            ushort creditCharge,
            ushort creditRequest,
            ulong messageId,
            Guid clientGuid,
            out DialectRevision selectedDialect,
            out byte[] gssToken,
            out Packet_Header responseHeader,
            out NEGOTIATE_Response responsePayload)
        {
            uint status = client.Negotiate(
                            creditCharge,
                            creditRequest,
                            Packet_Header_Flags_Values.NONE,
                            messageId,
                            new DialectRevision[] { DialectRevision.Smb2002 },
                            SecurityMode_Values.NONE,
                            Capabilities_Values.NONE,
                            clientGuid,
                            out selectedDialect,
                            out gssToken,
                            out responseHeader,
                            out responsePayload);

            negotiatedDialect = selectedDialect;

            serverCapabilities = (Capabilities_Values)responsePayload.Capabilities;

            return status;
        }
        private bool IsErrorPacket(Packet_Header header)
        {
            switch (header.Status)
            {
                case Smb2Status.STATUS_SUCCESS:
                    return false;

                case Smb2Status.STATUS_MORE_PROCESSING_REQUIRED:
                    return (header.Command != Smb2Command.SESSION_SETUP) ? true : false;

                case Smb2Status.STATUS_BUFFER_OVERFLOW:
                    // STATUS_BUFFER_OVERFLOW is not an error packet because:
                    // (1) The Sev bit is STATUS_SEVERITY_WARNING, not error (According to [MS-ERREF] 2.3 NTSTATUS.)
                    // (2) It contains response data in its payload data.
                    return false;

                case Smb2Status.STATUS_NOTIFY_ENUM_DIR:
                case Smb2Status.STATUS_NOTIFY_CLEANUP:
                    return header.Command != Smb2Command.CHANGE_NOTIFY;

                default:
                    //other error response like STATUS_INVALID_PARAMETER
                    return true;
            }
        }
        /// <summary>
        /// This method will send ComNegotiate request before sending a Negotiate request to simulate windows client behaviour.
        /// If ComNegotiate failed, the Negotiate request will still be sent.      
        /// </summary>
        public uint MultiProtocolNegotiate(
            Smb2Client client,
            ushort creditCharge,
            ushort creditRequest,
            Packet_Header_Flags_Values flags,
            ulong messageId,
            DialectRevision[] dialects,
            SecurityMode_Values securityMode,
            Capabilities_Values capabilities,
            Guid clientGuid,
            out DialectRevision selectedDialect,
            out byte[] gssToken,
            out Packet_Header responseHeader,
            out NEGOTIATE_Response responsePayload)
        {
            uint status = client.MultiProtocolNegotiate(
                    new string[] { "SMB 2.002", "SMB 2.???" },
                    out selectedDialect,
                    out gssToken,
                    out responseHeader,
                    out responsePayload);

            if (responseHeader.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("ComNegotiate", responseHeader.Status);
            }

            // If server only supports Smb2002, no further SMB2 negotiate needed
            if (selectedDialect == DialectRevision.Smb2002)
            {
                return status;
            }

            PreauthIntegrityHashID[] preauthHashAlgs = null;
            EncryptionAlgorithm[] encryptionAlgs = null;

            // For back compatibility, if dialects contains SMB 3.11, preauthentication integrity context should be present.
            if (Array.IndexOf(dialects, DialectRevision.Smb311) >= 0)
            {
                preauthHashAlgs = new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 };
                encryptionAlgs = new EncryptionAlgorithm[] {
                EncryptionAlgorithm.ENCRYPTION_AES128_GCM,
                EncryptionAlgorithm.ENCRYPTION_AES128_CCM };
            }

            status = client.Negotiate(
                creditCharge,
                creditRequest,
                flags,
                messageId,
                dialects,
                securityMode,
                capabilities,
                clientGuid,
                out selectedDialect,
                out gssToken,
                out responseHeader,
                out responsePayload,
                0,
                preauthHashAlgs,
                encryptionAlgs);

            return status;
        }
        /// <summary>
        /// Delegate to check negotiate response header and payload in this class.
        /// </summary>
        /// <param name="responseHeader">Response header to be checked</param>
        /// <param name="response">Negotiate response payload to be checked</param>
        public void ReplayNegotiateResponseChecker(Packet_Header responseHeader, NEGOTIATE_Response response)
        {
            BaseTestSite.Assert.AreEqual(
                Smb2Status.STATUS_SUCCESS,
                responseHeader.Status,
                "Negotiation should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(responseHeader.Status));

            TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL, response);
        }