/// <summary>
        /// Build a Smb2ErrorResponsePacket from a byte array
        /// </summary>
        /// <param name="data">The byte array</param>
        /// <param name="consumedLen">The consumed data length</param>
        /// <param name="expectedLen">The expected data length</param>
        internal override void FromBytes(byte[] data, out int consumedLen, out int expectedLen)
        {
            consumedLen = 0;
            this.Header = TypeMarshal.ToStruct <Packet_Header>(data, ref consumedLen);

            this.PayLoad.StructureSize = TypeMarshal.ToStruct <ushort>(data.Skip(consumedLen).Take(2).ToArray());
            consumedLen += 2;

            this.PayLoad.ErrorContextCount = TypeMarshal.ToStruct <byte>(data.Skip(consumedLen).Take(1).ToArray());
            consumedLen += 1;

            this.PayLoad.Reserved = TypeMarshal.ToStruct <byte>(data.Skip(consumedLen).Take(1).ToArray());
            consumedLen          += 1;

            this.PayLoad.ByteCount = TypeMarshal.ToStruct <uint>(data.Skip(consumedLen).Take(4).ToArray());
            consumedLen           += 4;

            if (this.PayLoad.ErrorContextCount > 0) //smb311
            {
                List <Error_Context> errorContextList = new List <Error_Context>();
                for (int i = 0; i < this.PayLoad.ErrorContextCount; i++)
                {
                    Error_Context tempContext = new Error_Context();
                    tempContext.ErrorDataLength = TypeMarshal.ToStruct <uint>(data.Skip(consumedLen).Take(4).ToArray());
                    consumedLen        += 4;
                    tempContext.ErrorId = TypeMarshal.ToStruct <uint>(data.Skip(consumedLen).Take(4).ToArray());
                    consumedLen        += 4;
                    switch (this.Header.Status)
                    {
                    case Smb2Status.STATUS_STOPPED_ON_SYMLINK:
                        tempContext.ErrorData.SymbolicLinkErrorResponse = TypeMarshal.ToStruct <Symbolic_Link_Error_Response>(data.Skip(consumedLen).Take((int)tempContext.ErrorDataLength).ToArray());
                        break;

                    case Smb2Status.STATUS_BUFFER_TOO_SMALL:
                        tempContext.ErrorData.BufferTooSmallErrorResponse = data.Skip(consumedLen).Take((int)tempContext.ErrorDataLength).ToArray();
                        break;
                    }
                    consumedLen += (int)tempContext.ErrorDataLength;
                    errorContextList.Add(tempContext);
                }

                this.PayLoad.ErrorContextErrorData = errorContextList.ToArray();
            }
            else
            {
                // If the ByteCount field is zero then the server MUST supply an ErrorData field that is one byte in length, and SHOULD set that byte to zero
                int byteCountValue = (int)(this.PayLoad.ByteCount == 0 ? 1 : this.PayLoad.ByteCount);
                this.PayLoad.ErrorData = data.Skip(consumedLen).Take(byteCountValue).ToArray();
                consumedLen           += byteCountValue;
            }
            expectedLen = 0;
        }
Beispiel #2
0
        /// <summary>
        /// Verify behavior of redirect to owner specified in MS-SMB2 section 3.3.5.7
        /// </summary>
        /// <param name="sofsHostedNode">ScaleOutFS hosted node</param>
        /// <param name="nonSofsHostedNode">Non ScaleOutFS hosted node</param>
        /// <returns>Redirect to owner is tested or not</returns>
        private bool TestRedirectToOwner(string sofsHostedNode, string nonSofsHostedNode)
        {
            bool isRedirectToOwnerTested = false;

            #region Get IP address list from ScaleOutFS
            string      server       = TestConfig.ClusteredScaleOutFileServerName;
            IPAddress[] accessIpList = Dns.GetHostEntry(server).AddressList;
            #endregion

            #region Get IP address from nonSofsHostedNode
            IPAddress   currentAccessIpAddr       = null;
            IPAddress[] accessIpListNonSoftHosted = Dns.GetHostEntry(nonSofsHostedNode).AddressList;
            for (int i = 0; i < accessIpList.Length; i++)
            {
                for (int j = 0; j < accessIpListNonSoftHosted.Length; j++)
                {
                    // Make sure to get IP address from nonSofsHostedNode
                    if (accessIpList[i].Address.Equals(accessIpListNonSoftHosted[j].Address))
                    {
                        currentAccessIpAddr = accessIpList[i];
                        break;
                    }
                }
            }
            BaseTestSite.Assert.IsNotNull(
                currentAccessIpAddr,
                "currentAccessIpAddr should be set as IP of nonSofsHostedNode {0}", nonSofsHostedNode);
            #endregion

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a client by sending the following requests: NEGOTIATE; SESSION_SETUP");
            Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            client.ConnectToServer(TestConfig.UnderlyingTransport, server, currentAccessIpAddr);
            client.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled);
            client.SessionSetup(TestConfig.DefaultSecurityPackage, server, TestConfig.AccountCredential, false);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends TREE_CONNECT request with flag SMB2_SHAREFLAG_REDIRECT_TO_OWNER.");
            string uncSharePath = Smb2Utility.GetUncPath(server, testConfig.CAShareName);
            uint   treeId;
            Share_Capabilities_Values shareCap = Share_Capabilities_Values.NONE;
            uint status = client.TreeConnect(
                uncSharePath,
                out treeId,
                (header, response) =>
            {
                if (header.Status == Smb2Status.STATUS_SUCCESS)
                {
                    shareCap = response.Capabilities;
                }
            },
                TreeConnect_Flags.SMB2_SHAREFLAG_REDIRECT_TO_OWNER);

            if (status != Smb2Status.STATUS_SUCCESS &&
                client.Smb2Client.Error != null)
            {
                ERROR_Response_packet error = client.Smb2Client.Error.PayLoad;
                if (error.ErrorContextCount > 0)
                {
                    for (int i = 0; i < error.ErrorContextCount; i++)
                    {
                        Error_Context ctx = error.ErrorContextErrorData[i];
                        if (ctx.ErrorId == Error_Id.ERROR_ID_SHARE_REDIRECT)
                        {
                            Share_Capabilities_Values shareCaps = GetShareCapabilities(sofsHostedNode, uncSharePath, TreeConnect_Flags.SMB2_SHAREFLAG_REDIRECT_TO_OWNER);
                            if (!shareCaps.HasFlag(Share_Capabilities_Values.SHARE_CAP_REDIRECT_TO_OWNER))
                            {
                                BaseTestSite.Assert.Inconclusive(
                                    "The share {0} does not have the capability SHARE_CAP_REDIRECT_TO_OWNER",
                                    Smb2Utility.GetUncPath(TestConfig.ClusteredScaleOutFileServerName, testConfig.CAShareName)
                                    );
                            }

                            BaseTestSite.Assert.AreEqual(
                                Smb2Status.STATUS_BAD_NETWORK_NAME,
                                status,
                                "If TreeConnect.Share.Type includes STYPE_CLUSTER_SOFS," +
                                "Connection.Dialect is \"3.1.1\" and" +
                                "the SMB2_TREE_CONNECT_FLAG_REDIRECT_TO_OWNER bit is set" +
                                "in the Flags field of the SMB2 TREE_CONNECT request," +
                                "the server MUST query the underlying object store in an implementation-specific manner " +
                                "to determine whether the share is hosted on this node." +
                                "If not, the server MUST return error data as specified in section 2.2.2" +
                                "with ErrorData set to SMB2 ERROR Context response formatted as ErrorId" +
                                "set to SMB2_ERROR_ID_SHARE_REDIRECT, and ErrorContextData set to the Share Redirect error context data" +
                                "as specified in section 2.2.2.2.2 with IPAddrMoveList set to" +
                                "the list of IP addresses obtained in an implementation-specific manner." +
                                "Actually server returns {0}.", Smb2Status.GetStatusCode(status)
                                );
                            verifyErrorContext(ctx, uncSharePath, sofsHostedNode);
                            isRedirectToOwnerTested = true;
                        }
                    }
                }
            }

            if (status == Smb2Status.STATUS_SUCCESS)
            {
                if (!shareCap.HasFlag(Share_Capabilities_Values.SHARE_CAP_REDIRECT_TO_OWNER))
                {
                    BaseTestSite.Assert.Inconclusive(
                        "The share {0} does not have the capability SHARE_CAP_REDIRECT_TO_OWNER",
                        Smb2Utility.GetUncPath(TestConfig.ClusteredScaleOutFileServerName, testConfig.CAShareName)
                        );
                }
                client.TreeDisconnect(treeId);
            }
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: LOG_OFF; DISCONNECT.");
            client.LogOff();
            client.Disconnect();
            return(isRedirectToOwnerTested);
        }
Beispiel #3
0
        /// <summary>
        /// Verify members in Error_Context
        /// </summary>
        /// <param name="ctx">Error_Context in Error Response</param>
        /// <param name="uncSharePath">uncSharePath</param>
        /// <param name="sofsHostedNode">ScaleOutFS hosted node</param>
        private void verifyErrorContext(Error_Context ctx, string uncSharePath, string sofsHostedNode)
        {
            #region Verify Error_Context
            BaseTestSite.Assert.AreEqual(
                Error_Id.ERROR_ID_SHARE_REDIRECT,
                ctx.ErrorId,
                "The Error ID should be SMB2_ERROR_ID_SHARE_REDIRECT, actually server returns {0}", ctx.ErrorId);
            BaseTestSite.Assert.IsTrue(
                ctx.ErrorDataLength > 0,
                "The length, in bytes, of the ErrorContextData field should be greater than 0. Actually server returns {0}.", ctx.ErrorDataLength);
            #endregion

            #region Verify Share_Reditect_Error_Context_Response
            Share_Redirect_Error_Context_Response errCtx = ctx.ErrorData.ShareRedirectErrorContextResponse;
            BaseTestSite.Assert.IsTrue(
                errCtx.StructureSize > 0,
                "This field (StructureSize) MUST be set to the size of the structure. Actually server returns {0}.", errCtx.StructureSize);
            BaseTestSite.Assert.AreEqual(
                (uint)3,
                errCtx.NotificationType,
                "This field (NotificationType) MUST be set to 3. Actually server returns {0}.", errCtx.NotificationType);
            byte[] uncSharePathToByte = Encoding.Unicode.GetBytes(uncSharePath);
            BaseTestSite.Assert.AreEqual(
                (uint)uncSharePathToByte.Length,
                errCtx.ResourceNameLength,
                "The length of the share name provided in the ResourceName field, in bytes, should be the length of {0}. Actually server returns {1}.", uncSharePathToByte.Length, errCtx.ResourceNameLength);
            BaseTestSite.Assert.AreEqual(
                0,
                errCtx.Flags,
                "This field (Flags) MUST be set to zero. Actually server returns {0}.", errCtx.Flags);
            BaseTestSite.Assert.AreEqual(
                0,
                errCtx.TargetType,
                "This field (TargetType) MUST be set to zero. Actually server returns {0}.", errCtx.TargetType);
            BaseTestSite.Assert.IsTrue(
                errCtx.IPAddrCount > 0,
                "The number of MOVE_DST_IPADDR structures in the IPAddrMoveList field should be greater than 0. Actually server returns {0}.", errCtx.IPAddrCount);
            IPAddress[] ipv4AddressList = Dns.GetHostEntry(sofsHostedNode).AddressList;
            System.Net.Sockets.AddressFamily addressFamily = ipv4AddressList[0].AddressFamily;

            for (int i = 0; i < errCtx.IPAddrCount; i++)
            {
                Move_Dst_IpAddr dstMoveIpAddr = errCtx.IPAddrMoveList[i];
                BaseTestSite.Assert.AreEqual(
                    (uint)0,
                    dstMoveIpAddr.Reserved,
                    "The server SHOULD set this field to zero, and the client MUST ignore it on receipt. Actually server returns {0}", dstMoveIpAddr.Reserved);
                if (addressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                    BaseTestSite.Assert.AreEqual(
                        Move_Dst_IpAddr_Type.MOVE_DST_IPADDR_V4,
                        dstMoveIpAddr.Type,
                        "Type of destination IP address should be MOVE_DST_IPADDR_V4, actually server returns {0}", dstMoveIpAddr.Type);
                    // Check Reserved2 field (offset from 4 to 15) is 0
                    for (int k = 4; k < 16; k++)
                    {
                        BaseTestSite.Assert.IsTrue(
                            dstMoveIpAddr.IPv6Address[k] == 0,
                            "The client MUST set this (Reserved2) to 0.");
                    }
                }
                else if (addressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                {
                    BaseTestSite.Assert.AreEqual(
                        Move_Dst_IpAddr_Type.MOVE_DST_IPADDR_V6,
                        dstMoveIpAddr.Type,
                        "Type of destination IP address should be MOVE_DST_IPADDR_V6, actually server returns {0}", dstMoveIpAddr.Type);
                }
            }

            // Verify all IP addresses for this node are in IPAddrMoveList
            if (addressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            {
                for (int i = 0; i < ipv4AddressList.Length; i++)
                {
                    IPAddress curAddr        = ipv4AddressList[i];
                    bool      isIpAddrInList = false;
                    for (int j = 0; j < errCtx.IPAddrMoveList.Length; j++)
                    {
                        Move_Dst_IpAddr dstMoveIpAddr = errCtx.IPAddrMoveList[j];
                        uint            ipAddr        = BitConverter.ToUInt32(dstMoveIpAddr.IPv6Address, 0);
                        if (ipAddr == (uint)curAddr.Address)
                        {
                            isIpAddrInList = true;
                            break;
                        }
                    }
                    BaseTestSite.Assert.IsTrue(isIpAddrInList, "IP address of sofsHostedNode {0} is not in IPAddrMoveList.", curAddr.ToString());
                }
            }

            string resourceName = Encoding.Unicode.GetString(errCtx.ResourceName, 0, (int)errCtx.ResourceNameLength);
            BaseTestSite.Assert.IsTrue(
                uncSharePath.ToLower().Contains(resourceName.ToLower()),
                "ResourceName should be the same as uncSharePath. Actually server returns {0}.", resourceName);
            #endregion
        }
        /// <summary>
        /// Build a Smb2ErrorResponsePacket from a byte array
        /// </summary>
        /// <param name="data">The byte array</param>
        /// <param name="consumedLen">The consumed data length</param>
        /// <param name="expectedLen">The expected data length</param>
        internal override void FromBytes(byte[] data, out int consumedLen, out int expectedLen)
        {
            consumedLen = 0;
            this.Header = TypeMarshal.ToStruct <Packet_Header>(data, ref consumedLen);

            this.PayLoad.StructureSize = TypeMarshal.ToStruct <ushort>(data.Skip(consumedLen).Take(2).ToArray());
            consumedLen += 2;

            this.PayLoad.ErrorContextCount = TypeMarshal.ToStruct <byte>(data.Skip(consumedLen).Take(1).ToArray());
            consumedLen += 1;

            this.PayLoad.Reserved = TypeMarshal.ToStruct <byte>(data.Skip(consumedLen).Take(1).ToArray());
            consumedLen          += 1;

            this.PayLoad.ByteCount = TypeMarshal.ToStruct <uint>(data.Skip(consumedLen).Take(4).ToArray());
            consumedLen           += 4;

            if (this.PayLoad.ErrorContextCount > 0) //smb311
            {
                List <Error_Context> errorContextList = new List <Error_Context>();
                for (int i = 0; i < this.PayLoad.ErrorContextCount; i++)
                {
                    Error_Context tempContext = new Error_Context();
                    tempContext.ErrorDataLength = TypeMarshal.ToStruct <uint>(data.Skip(consumedLen).Take(4).ToArray());
                    consumedLen        += 4;
                    tempContext.ErrorId = TypeMarshal.ToStruct <Error_Id>(data.Skip(consumedLen).Take(4).ToArray());
                    consumedLen        += 4;
                    switch (this.Header.Status)
                    {
                    case Smb2Status.STATUS_STOPPED_ON_SYMLINK:
                        tempContext.ErrorData.SymbolicLinkErrorResponse = TypeMarshal.ToStruct <Symbolic_Link_Error_Response>(data.Skip(consumedLen).Take((int)tempContext.ErrorDataLength).ToArray());
                        break;

                    case Smb2Status.STATUS_BAD_NETWORK_NAME:
                        if (tempContext.ErrorId == Error_Id.ERROR_ID_SHARE_REDIRECT)
                        {
                            tempContext.ErrorData.ShareRedirectErrorContextResponse = TypeMarshal.ToStruct <Share_Redirect_Error_Context_Response>(data.Skip(consumedLen).Take((int)tempContext.ErrorDataLength).ToArray());
                            tempContext.ErrorData.ShareRedirectErrorContextResponse.ResourceName = data.Skip(consumedLen + (int)tempContext.ErrorData.ShareRedirectErrorContextResponse.ResourceNameOffset).Take((int)tempContext.ErrorData.ShareRedirectErrorContextResponse.ResourceNameLength).ToArray();

                            for (int j = 0; j < tempContext.ErrorData.ShareRedirectErrorContextResponse.IPAddrCount; j += 1)
                            {
                                if (tempContext.ErrorData.ShareRedirectErrorContextResponse.IPAddrMoveList[j].Type == Move_Dst_IpAddr_Type.MOVE_DST_IPADDR_V4)
                                {
                                    // If the value of the Type field is MOVE_DST_IPADDR_V4, this field is the IPv4Address field followed by Reserved2 fields.
                                    // Reserved2 (12 bytes): The client MUST set this to 0, and the server MUST ignore it on receipt
                                    for (int z = 4; z < 16; z += 1)
                                    {
                                        tempContext.ErrorData.ShareRedirectErrorContextResponse.IPAddrMoveList[j].IPv6Address[z] = 0;
                                    }
                                }
                            }
                        }
                        break;

                    case Smb2Status.STATUS_BUFFER_TOO_SMALL:
                        tempContext.ErrorData.BufferTooSmallErrorResponse = data.Skip(consumedLen).Take((int)tempContext.ErrorDataLength).ToArray();
                        break;
                    }
                    consumedLen += (int)tempContext.ErrorDataLength;
                    errorContextList.Add(tempContext);
                }

                this.PayLoad.ErrorContextErrorData = errorContextList.ToArray();
            }
            else
            {
                // If the ByteCount field is zero then the server MUST supply an ErrorData field that is one byte in length, and SHOULD set that byte to zero
                int byteCountValue = (int)(this.PayLoad.ByteCount == 0 ? 1 : this.PayLoad.ByteCount);
                this.PayLoad.ErrorData = data.Skip(consumedLen).Take(byteCountValue).ToArray();
                consumedLen           += byteCountValue;
            }
            expectedLen = 0;
        }
        /// <summary>
        /// Verify members in Error_Context
        /// </summary>
        /// <param name="ctx">Error_Context in Error Response</param>
        /// <param name="uncSharePath">uncSharePath</param>
        /// <param name="sofsHostedNode">ScaleOutFS hosted node</param>
        private void verifyErrorContext(Error_Context ctx, string uncSharePath, string sofsHostedNode)
        {
            #region Verify Error_Context
            BaseTestSite.Assert.AreEqual(
                Error_Id.ERROR_ID_SHARE_REDIRECT,
                ctx.ErrorId,
                "The Error ID should be SMB2_ERROR_ID_SHARE_REDIRECT, actually server returns {0}", ctx.ErrorId);
            BaseTestSite.Assert.IsTrue(
                ctx.ErrorDataLength > 0,
                "The length, in bytes, of the ErrorContextData field should be greater than 0. Actually server returns {0}.", ctx.ErrorDataLength);
            #endregion

            #region Verify Share_Reditect_Error_Context_Response
            Share_Redirect_Error_Context_Response errCtx = ctx.ErrorData.ShareRedirectErrorContextResponse;
            BaseTestSite.Assert.IsTrue(
                errCtx.StructureSize > 0,
                "This field (StructureSize) MUST be set to the size of the structure. Actually server returns {0}.", errCtx.StructureSize);
            BaseTestSite.Assert.AreEqual(
                (uint)3,
                errCtx.NotificationType,
                "This field (NotificationType) MUST be set to 3. Actually server returns {0}.", errCtx.NotificationType);

            BaseTestSite.Assert.AreEqual(
                0,
                errCtx.Flags,
                "This field (Flags) MUST be set to zero. Actually server returns {0}.", errCtx.Flags);
            BaseTestSite.Assert.AreEqual(
                0,
                errCtx.TargetType,
                "This field (TargetType) MUST be set to zero. Actually server returns {0}.", errCtx.TargetType);
            BaseTestSite.Assert.IsTrue(
                errCtx.IPAddrCount > 0,
                "The number of MOVE_DST_IPADDR structures in the IPAddrMoveList field should be greater than 0. Actually server returns {0}.", errCtx.IPAddrCount);
            IPAddress[] ipv4AddressList = Dns.GetHostAddresses(sofsHostedNode);
            System.Net.Sockets.AddressFamily addressFamily = ipv4AddressList[0].AddressFamily;

            for (int i = 0; i < errCtx.IPAddrCount; i++)
            {
                Move_Dst_IpAddr dstMoveIpAddr = errCtx.IPAddrMoveList[i];
                BaseTestSite.Assert.AreEqual(
                    (uint)0,
                    dstMoveIpAddr.Reserved,
                    "The server SHOULD set this field to zero, and the client MUST ignore it on receipt. Actually server returns {0}", dstMoveIpAddr.Reserved);
                if (addressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                    BaseTestSite.Assert.AreEqual(
                        Move_Dst_IpAddr_Type.MOVE_DST_IPADDR_V4,
                        dstMoveIpAddr.Type,
                        "Type of destination IP address should be MOVE_DST_IPADDR_V4, actually server returns {0}", dstMoveIpAddr.Type);
                    // Check Reserved2 field (offset from 4 to 15) is 0
                    for (int k = 4; k < 16; k++)
                    {
                        BaseTestSite.Assert.IsTrue(
                            dstMoveIpAddr.IPv6Address[k] == 0,
                            "The client MUST set this (Reserved2) to 0.");
                    }
                }
                else if (addressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                {
                    BaseTestSite.Assert.AreEqual(
                        Move_Dst_IpAddr_Type.MOVE_DST_IPADDR_V6,
                        dstMoveIpAddr.Type,
                        "Type of destination IP address should be MOVE_DST_IPADDR_V6, actually server returns {0}", dstMoveIpAddr.Type);
                }
            }

            // Verify all IP addresses for this node are in IPAddrMoveList
            if (addressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            {
                for (int i = 0; i < ipv4AddressList.Length; i++)
                {
                    IPAddress curAddr        = ipv4AddressList[i];
                    bool      isIpAddrInList = false;
                    for (int j = 0; j < errCtx.IPAddrMoveList.Length; j++)
                    {
                        Move_Dst_IpAddr dstMoveIpAddr = errCtx.IPAddrMoveList[j];
                        uint            ipAddr        = BitConverter.ToUInt32(dstMoveIpAddr.IPv6Address, 0);
                        if (ipAddr == (uint)curAddr.Address)
                        {
                            isIpAddrInList = true;
                            break;
                        }
                    }
                    BaseTestSite.Assert.IsTrue(isIpAddrInList, "IP address of sofsHostedNode {0} is not in IPAddrMoveList.", curAddr.ToString());
                }
            }

            var resourceName = Encoding.Unicode.GetString(errCtx.ResourceName, 0, (int)errCtx.ResourceNameLength);
            BaseTestSite.Log.Add(LogEntryKind.Debug, $"uncSharePath: {uncSharePath}");
            BaseTestSite.Log.Add(LogEntryKind.Debug, $"ResourceName: {resourceName}");

            BaseTestSite.Assert.IsTrue(
                CompareUNCSharePathAndResourceName(uncSharePath.ToLower(), resourceName.ToLower()),
                "ResourceName should indicate the same share as what uncSharePath indicates. Actually server returns {0}.", resourceName);

            bool CompareUNCSharePathAndResourceName(string uncSharePath, string resourceName)
            {
                var pathRegex = @"\\\\(?<serverName>.+)\\(?<shareName>.+)";
                var regex     = new Regex(pathRegex);

                var uncSharePathMatch = regex.Match(uncSharePath);
                var shareServer       = ExtractServerName(uncSharePathMatch.Groups["serverName"].Value);
                var shareName         = uncSharePathMatch.Groups["shareName"].Value;

                var resourceNameMatch   = regex.Match(resourceName);
                var resourceShareServer = ExtractServerName(resourceNameMatch.Groups["serverName"].Value);
                var resourceShareName   = resourceNameMatch.Groups["shareName"].Value;

                return(shareServer == resourceShareServer && shareName == resourceShareName);

                string ExtractServerName(string matchedGroupValue)
                {
                    // If the matched value is not an FQDN (e.g. computer name or IP address), return it directly.
                    // If the matched value is an FQDN, extract the server name from it.
                    if (!matchedGroupValue.Contains(TestConfig.DomainName, StringComparison.OrdinalIgnoreCase))
                    {
                        return(matchedGroupValue);
                    }
                    else
                    {
                        return(matchedGroupValue.Substring(0, matchedGroupValue.IndexOf(TestConfig.DomainName, StringComparison.OrdinalIgnoreCase) - 1));
                    }
                }
            }

            #endregion
        }