internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session = state.GetSession(header.UID);

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, request.OldFileName))
                {
                    state.LogToServer(Severity.Verbose, "Rename '{0}{1}' to '{0}{2}' failed. User '{3}' was denied access.", share.Name, request.OldFileName, request.NewFileName, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
                if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, request.NewFileName))
                {
                    state.LogToServer(Severity.Verbose, "Rename '{0}{1}' to '{0}{2}' failed. User '{3}' was denied access.", share.Name, request.OldFileName, request.NewFileName, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
            }

            header.Status = SMB1FileStoreHelper.Rename(share.FileStore, request.OldFileName, request.NewFileName, request.SearchAttributes, session.SecurityContext);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "Rename '{0}{1}' to '{0}{2}' failed. NTStatus: {3}.", share.Name, request.OldFileName, request.NewFileName, header.Status);
                return(new ErrorResponse(request.CommandName));
            }
            state.LogToServer(Severity.Verbose, "Rename: User '{0}' renamed '{1}{2}' to '{1}{3}'.", session.UserName, share.Name, request.OldFileName, request.NewFileName);
            return(new RenameResponse());
        }
        internal static SMB1Command GetSetInformation2Response(SMB1Header header, SetInformation2Request request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session    session  = state.GetSession(header.UID);
            OpenFileObject openFile = session.GetOpenFileObject(request.FID);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "Set Information 2 failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, request.FID);
                header.Status = NTStatus.STATUS_SMB_BAD_FID;
                return(new ErrorResponse(request.CommandName));
            }

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, openFile.Path))
                {
                    state.LogToServer(Severity.Verbose, "Set Information 2 on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
            }

            header.Status = SMB1FileStoreHelper.SetInformation2(share.FileStore, openFile.Handle, request.CreationDateTime, request.LastAccessDateTime, request.LastWriteDateTime);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "Set Information 2 on '{0}{1}' failed. NTStatus: {2}", share.Name, openFile.Path, header.Status);
                return(new ErrorResponse(request.CommandName));
            }

            state.LogToServer(Severity.Verbose, "Set Information 2 on '{0}{1}' succeeded.", share.Name, openFile.Path);
            return(new SetInformation2Response());
        }
        internal static SMB1Command GetQueryInformationResponse(SMB1Header header, QueryInformationRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session = state.GetSession(header.UID);
            string      path    = request.FileName;

            if (!path.StartsWith(@"\"))
            {
                path = @"\" + path;
            }

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, path))
                {
                    state.LogToServer(Severity.Verbose, "Query Information on '{0}{1}' failed. User '{2}' was denied access.", share.Name, path, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
            }

            FileNetworkOpenInformation fileInfo;

            header.Status = SMB1FileStoreHelper.QueryInformation(out fileInfo, share.FileStore, path, session.SecurityContext);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                return(new ErrorResponse(request.CommandName));
            }

            QueryInformationResponse response = new QueryInformationResponse();

            response.FileAttributes = SMB1FileStoreHelper.GetFileAttributes(fileInfo.FileAttributes);
            response.LastWriteTime  = fileInfo.LastWriteTime;
            response.FileSize       = (uint)Math.Min(UInt32.MaxValue, fileInfo.EndOfFile);
            return(response);
        }
        internal static SMB1Command GetCheckDirectoryResponse(SMB1Header header, CheckDirectoryRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session = state.GetSession(header.UID);
            string      path    = request.DirectoryName;

            if (!path.StartsWith(@"\"))
            {
                path = @"\" + path;
            }

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, path))
                {
                    state.LogToServer(Severity.Verbose, "Check Directory '{0}{1}' failed. User '{2}' was denied access.", share.Name, path, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
            }

            header.Status = SMB1FileStoreHelper.CheckDirectory(share.FileStore, path, session.SecurityContext);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                return(new ErrorResponse(request.CommandName));
            }

            return(new CheckDirectoryResponse());
        }
Beispiel #5
0
        internal static Transaction2QueryFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFileInformationRequest subcommand, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session    session  = state.GetSession(header.UID);
            OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "QueryFileInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID);
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path))
                {
                    state.LogToServer(Severity.Verbose, "QueryFileInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(null);
                }
            }

            Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse();

            if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass != FileInformationClass.FileAllInformation)
            {
                FileInformation fileInfo;
                NTStatus        status = share.FileStore.GetFileInformation(out fileInfo, openFile.Handle, subcommand.FileInformationClass);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.FileInformationClass, status, subcommand.FID);
                    header.Status = status;
                    return(null);
                }
                state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information class: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.FileInformationClass, subcommand.FID);
                response.SetFileInformation(fileInfo);
            }
            else
            {
                // The FILE_ALL_INFORMATION structure described in [MS-FSCC], is NOT used by [MS-SMB]
                if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass == FileInformationClass.FileAllInformation)
                {
                    subcommand.QueryInformationLevel = QueryInformationLevel.SMB_QUERY_FILE_ALL_INFO;
                }
                QueryInformation queryInformation;
                NTStatus         status = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, openFile.Handle, subcommand.QueryInformationLevel);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.QueryInformationLevel, status, subcommand.FID);
                    header.Status = status;
                    return(null);
                }
                state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information level: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.QueryInformationLevel, subcommand.FID);
                response.SetQueryInformation(queryInformation);
            }
            return(response);
        }
Beispiel #6
0
        internal static Transaction2QueryPathInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryPathInformationRequest subcommand, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session = state.GetSession(header.UID);
            string      path    = subcommand.FileName;

            if (!path.StartsWith(@"\"))
            {
                path = @"\" + path;
            }

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, path))
                {
                    state.LogToServer(Severity.Verbose, "QueryPathInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, path, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(null);
                }
            }

            Transaction2QueryPathInformationResponse response = new Transaction2QueryPathInformationResponse();

            if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass != FileInformationClass.FileAllInformation)
            {
                FileInformation fileInfo;
                NTStatus        status = SMB1FileStoreHelper.GetFileInformation(out fileInfo, share.FileStore, path, subcommand.FileInformationClass, session.SecurityContext);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}", share.Name, path, subcommand.FileInformationClass, status);
                    header.Status = status;
                    return(null);
                }
                state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information class: {2}", share.Name, path, subcommand.FileInformationClass);
                response.SetFileInformation(fileInfo);
            }
            else
            {
                // The FILE_ALL_INFORMATION structure described in [MS-FSCC], is NOT used by [MS-SMB]
                if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass == FileInformationClass.FileAllInformation)
                {
                    subcommand.QueryInformationLevel = QueryInformationLevel.SMB_QUERY_FILE_ALL_INFO;
                }
                QueryInformation queryInformation;
                NTStatus         status = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, path, subcommand.QueryInformationLevel, session.SecurityContext);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}", share.Name, path, subcommand.QueryInformationLevel, status);
                    header.Status = status;
                    return(null);
                }
                state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information level: {2}", share.Name, path, subcommand.QueryInformationLevel);
                response.SetQueryInformation(queryInformation);
            }
            return(response);
        }
Beispiel #7
0
        private static OpenAndXResponse CreateResponseFromFileInfo(FileNetworkOpenInformation fileInfo, ushort fileID, OpenResult openResult)
        {
            OpenAndXResponse response = new OpenAndXResponse();

            response.FID                    = fileID;
            response.FileAttrs              = SMB1FileStoreHelper.GetFileAttributes(fileInfo.FileAttributes);
            response.LastWriteTime          = fileInfo.LastWriteTime;
            response.FileDataSize           = (uint)Math.Min(UInt32.MaxValue, fileInfo.EndOfFile);
            response.AccessRights           = AccessRights.SMB_DA_ACCESS_READ;
            response.ResourceType           = ResourceType.FileTypeDisk;
            response.OpenResults.OpenResult = openResult;
            return(response);
        }
Beispiel #8
0
        internal static Transaction2QueryFSInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFSInformationRequest subcommand, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session = state.GetSession(header.UID);

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, @"\"))
                {
                    state.LogToServer(Severity.Verbose, "QueryFileSystemInformation on '{0}' failed. User '{1}' was denied access.", share.Name, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(null);
                }
            }

            Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse();

            if (subcommand.IsPassthroughInformationLevel)
            {
                FileSystemInformation fileSystemInfo;
                NTStatus status = share.FileStore.GetFileSystemInformation(out fileSystemInfo, subcommand.FileSystemInformationClass);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: {2}", share.Name, subcommand.FileSystemInformationClass, status);
                    header.Status = status;
                    return(null);
                }
                state.LogToServer(Severity.Information, "GetFileSystemInformation on '{0}' succeeded. Information class: {1}", share.Name, subcommand.FileSystemInformationClass);
                response.SetFileSystemInformation(fileSystemInfo);
            }
            else
            {
                QueryFSInformation queryFSInformation;
                NTStatus           status = SMB1FileStoreHelper.GetFileSystemInformation(out queryFSInformation, share.FileStore, subcommand.QueryFSInformationLevel);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", share.Name, subcommand.QueryFSInformationLevel, status);
                    header.Status = status;
                    return(null);
                }
                state.LogToServer(Severity.Information, "GetFileSystemInformation on '{0}' succeeded. Information level: {1}", share.Name, subcommand.QueryFSInformationLevel);
                response.SetQueryFSInformation(queryFSInformation, header.UnicodeFlag);
            }
            return(response);
        }
Beispiel #9
0
        private static OpenAndXResponseExtended CreateResponseExtendedFromFileInfo(FileNetworkOpenInformation fileInfo, ushort fileID, OpenResult openResult)
        {
            OpenAndXResponseExtended response = new OpenAndXResponseExtended();

            response.FID                    = fileID;
            response.FileAttrs              = SMB1FileStoreHelper.GetFileAttributes(fileInfo.FileAttributes);
            response.LastWriteTime          = fileInfo.LastWriteTime;
            response.FileDataSize           = (uint)Math.Min(UInt32.MaxValue, fileInfo.EndOfFile);
            response.AccessRights           = AccessRights.SMB_DA_ACCESS_READ;
            response.ResourceType           = ResourceType.FileTypeDisk;
            response.OpenResults.OpenResult = openResult;
            response.MaximalAccessRights    = (AccessMask)(FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_APPEND_DATA |
                                                           FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA |
                                                           FileAccessMask.FILE_EXECUTE |
                                                           FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES) |
                                              AccessMask.DELETE | AccessMask.READ_CONTROL | AccessMask.WRITE_DAC | AccessMask.WRITE_OWNER | AccessMask.SYNCHRONIZE;
            response.GuestMaximalAccessRights = (AccessMask)(FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA |
                                                             FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA |
                                                             FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES) |
                                                AccessMask.READ_CONTROL | AccessMask.SYNCHRONIZE;
            return(response);
        }
        internal static SMB1Command GetDeleteDirectoryResponse(SMB1Header header, DeleteDirectoryRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session = state.GetSession(header.UID);

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, request.DirectoryName))
                {
                    state.LogToServer(Severity.Verbose, "Delete Directory '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.DirectoryName, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
            }

            header.Status = SMB1FileStoreHelper.DeleteDirectory(share.FileStore, request.DirectoryName, session.SecurityContext);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "Delete Directory '{0}{1}' failed. NTStatus: {2}.", share.Name, request.DirectoryName, header.Status);
                return(new ErrorResponse(request.CommandName));
            }
            state.LogToServer(Severity.Verbose, "Delete Directory: User '{0}' deleted '{1}{2}'.", session.UserName, share.Name, request.DirectoryName);
            return(new DeleteDirectoryResponse());
        }
        internal static SMB1Command GetSetInformationResponse(SMB1Header header, SetInformationRequest request, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session = state.GetSession(header.UID);

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, request.FileName))
                {
                    state.LogToServer(Severity.Verbose, "Set Information on '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.FileName, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(new ErrorResponse(request.CommandName));
                }
            }

            header.Status = SMB1FileStoreHelper.SetInformation(share.FileStore, request.FileName, request.FileAttributes, request.LastWriteTime, session.SecurityContext);
            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "Set Information on '{0}{1}' failed. NTStatus: {2}", share.Name, request.FileName, header.Status);
                return(new ErrorResponse(request.CommandName));
            }

            state.LogToServer(Severity.Verbose, "Set Information on '{0}{1}' succeeded.", share.Name, request.FileName);
            return(new SetInformationResponse());
        }
Beispiel #12
0
        internal static Transaction2SetFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2SetFileInformationRequest subcommand, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session    session  = state.GetSession(header.UID);
            OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);

            if (openFile == null)
            {
                state.LogToServer(Severity.Verbose, "SetFileInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID);
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }

            if (share is FileSystemShare)
            {
                if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, openFile.Path))
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName);
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(null);
                }
            }

            if (subcommand.IsPassthroughInformationLevel)
            {
                FileInformation fileInfo;
                try
                {
                    fileInfo = FileInformation.GetFileInformation(subcommand.InformationBytes, 0, subcommand.FileInformationClass);
                }
                catch (UnsupportedInformationLevelException)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_OS2_INVALID_LEVEL.", share.Name, openFile.Path, subcommand.FileInformationClass);
                    header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
                    return(null);
                }
                catch (Exception)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path, subcommand.FileInformationClass);
                    header.Status = NTStatus.STATUS_INVALID_PARAMETER;
                    return(null);
                }

                NTStatus status = share.FileStore.SetFileInformation(openFile.Handle, fileInfo);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.FileInformationClass, status, subcommand.FID);
                    header.Status = status;
                    return(null);
                }
                state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information class: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.FileInformationClass, subcommand.FID);
            }
            else
            {
                SetInformation information;
                try
                {
                    information = SetInformation.GetSetInformation(subcommand.InformationBytes, subcommand.SetInformationLevel);
                }
                catch (UnsupportedInformationLevelException)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: STATUS_OS2_INVALID_LEVEL.", share.Name, openFile.Path, subcommand.SetInformationLevel);
                    header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
                    return(null);
                }
                catch (Exception)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path, subcommand.SetInformationLevel);
                    header.Status = NTStatus.STATUS_INVALID_PARAMETER;
                    return(null);
                }

                NTStatus status = SMB1FileStoreHelper.SetFileInformation(share.FileStore, openFile.Handle, information);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SetInformationLevel, status, subcommand.FID);
                    header.Status = status;
                    return(null);
                }
                state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information level: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.SetInformationLevel, subcommand.FID);
            }
            Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse();

            return(response);
        }
Beispiel #13
0
        internal static Transaction2FindFirst2Response GetSubcommandResponse(SMB1Header header, uint maxDataCount, Transaction2FindFirst2Request subcommand, ISMBShare share, SMB1ConnectionState state)
        {
            SMB1Session session         = state.GetSession(header.UID);
            string      fileNamePattern = subcommand.FileName;

            if (!fileNamePattern.StartsWith(@"\"))
            {
                fileNamePattern = @"\" + fileNamePattern;
            }

            List <QueryDirectoryFileInformation> entries;
            FileInformationClass informationClass;

            try
            {
                informationClass = FindInformationHelper.ToFileInformationClass(subcommand.InformationLevel);
            }
            catch (UnsupportedInformationLevelException)
            {
                state.LogToServer(Severity.Verbose, "FindFirst2: Unsupported information level: {0}.", subcommand.InformationLevel);
                header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
                return(null);
            }

            NTStatus searchStatus = SMB1FileStoreHelper.QueryDirectory(out entries, share.FileStore, fileNamePattern, informationClass, session.SecurityContext);

            if (searchStatus != NTStatus.STATUS_SUCCESS)
            {
                state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}{1}', NTStatus: {2}", share.Name, fileNamePattern, searchStatus.ToString());
                header.Status = searchStatus;
                return(null);
            }
            // We ignore SearchAttributes
            state.LogToServer(Severity.Information, "FindFirst2: Searched for '{0}{1}', found {2} matching entries", share.Name, fileNamePattern, entries.Count);

            // [MS-CIFS] If no matching entries are found, the server SHOULD fail the request with STATUS_NO_SUCH_FILE.
            if (entries.Count == 0)
            {
                header.Status = NTStatus.STATUS_NO_SUCH_FILE;
                return(null);
            }

            bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
            int  entriesToReturn  = Math.Min(subcommand.SearchCount, entries.Count);
            List <QueryDirectoryFileInformation> segment = entries.GetRange(0, entriesToReturn);
            int maxLength = (int)maxDataCount;
            FindInformationList findInformationList;

            try
            {
                findInformationList = FindInformationHelper.ToFindInformationList(segment, header.UnicodeFlag, maxLength);
            }
            catch (UnsupportedInformationLevelException)
            {
                state.LogToServer(Severity.Verbose, "FindFirst2: Unsupported information level: {0}.", subcommand.InformationLevel);
                header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
                return(null);
            }
            int returnCount = findInformationList.Count;
            Transaction2FindFirst2Response response = new Transaction2FindFirst2Response();

            response.SetFindInformationList(findInformationList, header.UnicodeFlag);
            response.EndOfSearch = (returnCount == entries.Count);
            // If [..] the search fit within a single response and SMB_FIND_CLOSE_AT_EOS is set in the Flags field,
            // or if SMB_FIND_CLOSE_AFTER_REQUEST is set in the request,
            // the server SHOULD return a SID field value of zero.
            // This indicates that the search has been closed and is no longer active on the server.
            if ((response.EndOfSearch && subcommand.CloseAtEndOfSearch) || subcommand.CloseAfterRequest)
            {
                response.SID = 0;
            }
            else
            {
                ushort?searchHandle = session.AddOpenSearch(entries, returnCount);
                if (!searchHandle.HasValue)
                {
                    header.Status = NTStatus.STATUS_OS2_NO_MORE_SIDS;
                    return(null);
                }
                response.SID = searchHandle.Value;
            }
            return(response);
        }