Example #1
0
        internal static SMBCommand GetTreeConnectResponse(SMBHeader header, TreeConnectAndXRequest request, StateObject state, ShareCollection shares)
        {
            bool   isExtended   = (request.Flags & TreeConnectFlags.ExtendedResponse) > 0;
            string relativePath = ServerPathUtils.GetRelativeServerPath(request.Path);

            if (String.Equals(relativePath, "\\IPC$", StringComparison.InvariantCultureIgnoreCase))
            {
                header.TID = state.AddConnectedTree(relativePath);
                if (isExtended)
                {
                    return(CreateTreeConnectResponseExtended(ServiceName.NamedPipe));
                }
                else
                {
                    return(CreateTreeConnectResponse(ServiceName.NamedPipe));
                }
            }
            else
            {
                FileSystemShare share = shares.GetShareFromRelativePath(relativePath);
                if (share == null)
                {
                    header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
                    return(new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX));
                }
                else
                {
                    string userName = state.GetConnectedUserName(header.UID);
                    if (!share.HasReadAccess(userName))
                    {
                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
                        return(new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX));
                    }
                    else
                    {
                        header.TID = state.AddConnectedTree(relativePath);
                        if (isExtended)
                        {
                            return(CreateTreeConnectResponseExtended(ServiceName.DiskShare));
                        }
                        else
                        {
                            return(CreateTreeConnectResponse(ServiceName.DiskShare));
                        }
                    }
                }
            }
        }
        internal static Transaction2QueryFileInformationResponse GetSubcommandResponse(SMBHeader header, Transaction2QueryFileInformationRequest subcommand, FileSystemShare share, StateObject state)
        {
            IFileSystem fileSystem     = share.FileSystem;
            string      openedFilePath = state.GetOpenedFilePath(subcommand.FID);

            if (openedFilePath == null)
            {
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }

            FileSystemEntry entry = fileSystem.GetEntry(openedFilePath);

            if (entry == null)
            {
                header.Status = NTStatus.STATUS_NO_SUCH_FILE;
                return(null);
            }
            Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse();

            response.QueryInfo = InfoHelper.FromFileSystemEntry(entry, subcommand.InformationLevel);

            return(response);
        }
        internal static Transaction2QueryPathInformationResponse GetSubcommandResponse(SMBHeader header, Transaction2QueryPathInformationRequest subcommand, FileSystemShare share)
        {
            IFileSystem     fileSystem = share.FileSystem;
            string          path       = subcommand.FileName;
            FileSystemEntry entry      = fileSystem.GetEntry(path);

            if (entry == null)
            {
                // Windows Server 2003 will return STATUS_OBJECT_NAME_NOT_FOUND
                // Returning STATUS_NO_SUCH_FILE caused an issue when executing ImageX.exe from WinPE 3.0 (32-bit)
                header.Status = NTStatus.STATUS_OBJECT_NAME_NOT_FOUND;
                return(null);
            }
            Transaction2QueryPathInformationResponse response = new Transaction2QueryPathInformationResponse();

            response.QueryInfo = InfoHelper.FromFileSystemEntry(entry, subcommand.InformationLevel);

            return(response);
        }
        internal static Transaction2FindFirst2Response GetSubcommandResponse(SMBHeader header, Transaction2FindFirst2Request subcommand, FileSystemShare share, StateObject state)
        {
            IFileSystem fileSystem = share.FileSystem;
            Transaction2FindFirst2Response response = new Transaction2FindFirst2Response();
            string path = subcommand.FileName;
            // '\Directory' - Get the directory info
            // '\Directory\*' - List the directory files
            // '\Directory\s*' - List the directory files starting with s (cmd.exe will use this syntax when entering 's' and hitting tab for autocomplete)
            // '\Directory\<.inf' (Update driver will use this syntax)
            // '\Directory\exefile"*' (cmd.exe will use this syntax when entering an exe without its extension, explorer will use this opening a directory from the run menu)
            bool   isDirectoryEnumeration = false;
            string searchPattern          = String.Empty;

            if (path.Contains("*") || path.Contains("<"))
            {
                isDirectoryEnumeration = true;
                int separatorIndex = path.LastIndexOf('\\');
                searchPattern = path.Substring(separatorIndex + 1);
                path          = path.Substring(0, separatorIndex + 1);
            }
            bool exactNameWithoutExtension = searchPattern.Contains("\"");

            FileSystemEntry entry = fileSystem.GetEntry(path);

            if (entry == null)
            {
                header.Status = NTStatus.STATUS_NO_SUCH_FILE;
                return(null);
            }

            List <FileSystemEntry> entries;

            if (isDirectoryEnumeration)
            {
                try
                {
                    entries = fileSystem.ListEntriesInDirectory(path);
                }
                catch (UnauthorizedAccessException)
                {
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(null);
                }

                if (searchPattern != String.Empty)
                {
                    entries = GetFiltered(entries, searchPattern);
                }

                if (!exactNameWithoutExtension)
                {
                    if (IncludeParentDirectoryInResults)
                    {
                        entries.Insert(0, fileSystem.GetEntry(FileSystem.GetParentDirectory(path)));
                        entries[0].Name = "..";
                    }
                    if (IncludeCurrentDirectoryInResults)
                    {
                        entries.Insert(0, fileSystem.GetEntry(path));
                        entries[0].Name = ".";
                    }
                }

                // 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);
                }
            }
            else
            {
                entries = new List <FileSystemEntry>();
                entries.Add(entry);
            }

            bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
            int  entriesToReturn  = Math.Min(subcommand.SearchCount, entries.Count);

            // We ignore SearchAttributes
            for (int index = 0; index < entriesToReturn; index++)
            {
                FindInformationEntry infoEntry = InfoHelper.FromFileSystemEntry(entries[index], subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys);
                response.FindInfoList.Add(infoEntry);
                if (response.FindInfoList.GetLength(header.UnicodeFlag) > state.GetMaxDataCount(header.PID))
                {
                    response.FindInfoList.RemoveAt(response.FindInfoList.Count - 1);
                    break;
                }
            }
            int returnCount = response.FindInfoList.Count;

            response.EndOfSearch = (returnCount == entries.Count) && (entries.Count <= subcommand.SearchCount);
            response.SID         = state.AllocateSearchHandle();
            entries.RemoveRange(0, returnCount);
            state.OpenSearches.Add(response.SID, entries);
            return(response);
        }
        internal static Transaction2QueryFSInformationResponse GetSubcommandResponse(SMBHeader header, Transaction2QueryFSInformationRequest subcommand, FileSystemShare share)
        {
            Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse();

            response.QueryFSInfo = InfoHelper.GetFSInformation(subcommand.InformationLevel, share.FileSystem);
            return(response);
        }
        internal static Transaction2FindNext2Response GetSubcommandResponse(SMBHeader header, Transaction2FindNext2Request subcommand, FileSystemShare share, StateObject state)
        {
            Transaction2FindNext2Response response = new Transaction2FindNext2Response();

            if (!state.OpenSearches.ContainsKey(subcommand.SID))
            {
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }

            bool returnResumeKeys          = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
            List <FileSystemEntry> entries = state.OpenSearches[subcommand.SID];

            for (int index = 0; index < entries.Count; index++)
            {
                FindInformationEntry infoEntry = InfoHelper.FromFileSystemEntry(entries[index], subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys);
                response.FindInfoList.Add(infoEntry);
                if (response.FindInfoList.GetLength(header.UnicodeFlag) > state.GetMaxDataCount(header.PID))
                {
                    response.FindInfoList.RemoveAt(response.FindInfoList.Count - 1);
                    break;
                }
            }
            int returnCount = response.FindInfoList.Count;

            entries.RemoveRange(0, returnCount);
            state.OpenSearches[subcommand.SID] = entries;
            response.SearchCount = (ushort)returnCount;
            response.EndOfSearch = (returnCount == entries.Count) && (entries.Count <= subcommand.SearchCount);
            return(response);
        }
Example #7
0
        internal static SMBCommand GetNTCreateResponse(SMBHeader header, NTCreateAndXRequest request, object share, StateObject state)
        {
            bool   isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0;
            string path       = request.FileName;

            if (share is NamedPipeShare)
            {
                RemoteService service = ((NamedPipeShare)share).GetService(path);
                if (service != null)
                {
                    ushort fileID = state.AddOpenedFile(path);
                    if (isExtended)
                    {
                        return(CreateResponseExtendedForNamedPipe(fileID));
                    }
                    else
                    {
                        return(CreateResponseForNamedPipe(fileID));
                    }
                }

                header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
                return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
            }
            else // FileSystemShare
            {
                FileSystemShare fileSystemShare = (FileSystemShare)share;
                IFileSystem     fileSystem      = fileSystemShare.FileSystem;
                bool            forceDirectory  = (request.CreateOptions & CreateOptions.FILE_DIRECTORY_FILE) > 0;
                bool            forceFile       = (request.CreateOptions & CreateOptions.FILE_NON_DIRECTORY_FILE) > 0;

                if (forceDirectory & (request.CreateDisposition != CreateDisposition.FILE_CREATE &&
                                      request.CreateDisposition != CreateDisposition.FILE_OPEN &&
                                      request.CreateDisposition != CreateDisposition.FILE_OPEN_IF))
                {
                    header.Status = NTStatus.STATUS_INVALID_PARAMETER;
                    return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                }

                // Windows will try to access named streams (alternate data streams) regardless of the FILE_NAMED_STREAMS flag, we need to prevent this behaviour.
                if (path.Contains(":"))
                {
                    // Windows Server 2003 will return STATUS_OBJECT_NAME_NOT_FOUND
                    header.Status = NTStatus.STATUS_NO_SUCH_FILE;
                    return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                }

                FileSystemEntry entry = fileSystem.GetEntry(path);
                if (request.CreateDisposition == CreateDisposition.FILE_OPEN)
                {
                    if (entry == null)
                    {
                        header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
                        return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                    }

                    if (entry.IsDirectory && forceFile)
                    {
                        header.Status = NTStatus.STATUS_FILE_IS_A_DIRECTORY;
                        return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                    }

                    if (!entry.IsDirectory && forceDirectory)
                    {
                        // Not sure if that's the correct response
                        header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
                        return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                    }
                }
                else if (request.CreateDisposition == CreateDisposition.FILE_CREATE)
                {
                    if (entry != null)
                    {
                        // File already exists, fail the request
                        header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
                        return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                    }

                    string userName = state.GetConnectedUserName(header.UID);
                    if (!fileSystemShare.HasWriteAccess(userName))
                    {
                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
                        return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                    }

                    try
                    {
                        if (forceDirectory)
                        {
                            entry = fileSystem.CreateDirectory(path);
                        }
                        else
                        {
                            entry = fileSystem.CreateFile(path);
                        }
                    }
                    catch (IOException ex)
                    {
                        ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
                        if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
                        {
                            header.Status = NTStatus.STATUS_SHARING_VIOLATION;
                            return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                        }
                        else
                        {
                            header.Status = NTStatus.STATUS_DATA_ERROR;
                            return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                        }
                    }
                    catch (UnauthorizedAccessException)
                    {
                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
                        return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                    }
                }
                else if (request.CreateDisposition == CreateDisposition.FILE_OPEN_IF ||
                         request.CreateDisposition == CreateDisposition.FILE_OVERWRITE ||
                         request.CreateDisposition == CreateDisposition.FILE_OVERWRITE_IF ||
                         request.CreateDisposition == CreateDisposition.FILE_SUPERSEDE)
                {
                    entry = fileSystem.GetEntry(path);
                    if (entry == null)
                    {
                        if (request.CreateDisposition == CreateDisposition.FILE_OVERWRITE)
                        {
                            header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
                            return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                        }

                        string userName = state.GetConnectedUserName(header.UID);
                        if (!fileSystemShare.HasWriteAccess(userName))
                        {
                            header.Status = NTStatus.STATUS_ACCESS_DENIED;
                            return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                        }

                        try
                        {
                            if (forceDirectory)
                            {
                                entry = fileSystem.CreateDirectory(path);
                            }
                            else
                            {
                                entry = fileSystem.CreateFile(path);
                            }
                        }
                        catch (IOException ex)
                        {
                            ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
                            if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
                            {
                                header.Status = NTStatus.STATUS_SHARING_VIOLATION;
                                return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                            }
                            else
                            {
                                header.Status = NTStatus.STATUS_DATA_ERROR;
                                return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                            }
                        }
                        catch (UnauthorizedAccessException)
                        {
                            header.Status = NTStatus.STATUS_ACCESS_DENIED;
                            return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                        }
                    }
                    else
                    {
                        if (request.CreateDisposition == CreateDisposition.FILE_OVERWRITE ||
                            request.CreateDisposition == CreateDisposition.FILE_OVERWRITE_IF ||
                            request.CreateDisposition == CreateDisposition.FILE_SUPERSEDE)
                        {
                            string userName = state.GetConnectedUserName(header.UID);
                            if (!fileSystemShare.HasWriteAccess(userName))
                            {
                                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                                return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                            }

                            // Truncate the file
                            try
                            {
                                Stream stream = fileSystem.OpenFile(path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite);
                                stream.Close();
                            }
                            catch (IOException ex)
                            {
                                ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
                                if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
                                {
                                    header.Status = NTStatus.STATUS_SHARING_VIOLATION;
                                    return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                                }
                                else
                                {
                                    header.Status = NTStatus.STATUS_DATA_ERROR;
                                    return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                                }
                            }
                            catch (UnauthorizedAccessException)
                            {
                                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                                return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX));
                            }
                        }
                    }
                }
                else
                {
                    throw new InvalidRequestException();
                }
                bool   isSequentialAccess = (request.CreateOptions & CreateOptions.FILE_SEQUENTIAL_ONLY) > 0;
                ushort fileID             = state.AddOpenedFile(path, isSequentialAccess);
                if (isExtended)
                {
                    NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileSystemEntry(entry, fileID);
                    if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
                    {
                        response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
                    }
                    return(response);
                }
                else
                {
                    NTCreateAndXResponse response = CreateResponseFromFileSystemEntry(entry, fileID);
                    if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
                    {
                        response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
                    }
                    return(response);
                }
            }
        }
Example #8
0
        public static uint PerformWrite(SMBHeader header, object share, ushort FID, ulong offset, byte[] data, StateObject state)
        {
            OpenedFileObject openedFile = state.GetOpenedFileObject(FID);

            if (openedFile == null)
            {
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(0);
            }
            string openedFilePath = openedFile.Path;

            if (share is NamedPipeShare)
            {
                RemoteService service = ((NamedPipeShare)share).GetService(openedFilePath);
                if (service != null)
                {
                    RPCPDU rpcRequest = RPCPDU.GetPDU(data);
                    RPCPDU rpcReply   = RemoteServiceHelper.GetRPCReply(rpcRequest, service);
                    byte[] replyData  = rpcReply.GetBytes();
                    state.StoreNamedPipeReply(FID, replyData);
                    return((uint)data.Length);
                }

                // This code should not execute unless the SMB request (sequence) is invalid
                header.Status = NTStatus.STATUS_INVALID_SMB;
                return(0);
            }
            else // FileSystemShare
            {
                FileSystemShare fileSystemShare = (FileSystemShare)share;
                IFileSystem     fileSystem      = fileSystemShare.FileSystem;

                if (openedFile.IsSequentialAccess && openedFile.Cache.Length > 0)
                {
                    openedFile.Cache = new byte[0]; // Empty cache
                }

                try
                {
                    Stream stream = fileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
                    stream.Seek((long)offset, SeekOrigin.Begin);
                    stream.Write(data, 0, data.Length);
                    stream.Close();
                    return((uint)data.Length);
                }
                catch (IOException ex)
                {
                    ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
                    if (errorCode == (ushort)Win32Error.ERROR_DISK_FULL)
                    {
                        header.Status = NTStatus.STATUS_DISK_FULL;
                        return(0);
                    }
                    else if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
                    {
                        // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid
                        header.Status = NTStatus.STATUS_SHARING_VIOLATION;
                        return(0);
                    }
                    else
                    {
                        header.Status = NTStatus.STATUS_DATA_ERROR;
                        return(0);
                    }
                }
                catch (ArgumentOutOfRangeException)
                {
                    header.Status = NTStatus.STATUS_DATA_ERROR;
                    return(0);
                }
                catch (UnauthorizedAccessException)
                {
                    // The user may have tried to write to a readonly file
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(0);
                }
            }
        }
Example #9
0
        internal static SMBCommand GetDeleteDirectoryResponse(SMBHeader header, DeleteDirectoryRequest request, FileSystemShare share, StateObject state)
        {
            string userName = state.GetConnectedUserName(header.UID);

            if (!share.HasWriteAccess(userName))
            {
                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY));
            }
            IFileSystem fileSystem = share.FileSystem;

            FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName);

            if (entry == null)
            {
                header.Status = NTStatus.STATUS_NO_SUCH_FILE;
                return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY));
            }

            if (!entry.IsDirectory)
            {
                header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
                return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY));
            }

            try
            {
                fileSystem.Delete(request.DirectoryName);
                return(new DeleteDirectoryResponse());
            }
            catch (IOException)
            {
                header.Status = NTStatus.STATUS_CANNOT_DELETE;
                return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY));
            }
            catch (UnauthorizedAccessException)
            {
                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY));
            }
        }
Example #10
0
        internal static SMBCommand GetSetInformation2Response(SMBHeader header, SetInformation2Request request, FileSystemShare share, StateObject state)
        {
            string openedFilePath = state.GetOpenedFilePath(request.FID);

            if (openedFilePath == null)
            {
                header.Status = NTStatus.STATUS_SMB_BAD_FID;
                return(new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2));
            }

            string userName = state.GetConnectedUserName(header.UID);

            if (!share.HasWriteAccess(userName))
            {
                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                return(new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2));
            }
            IFileSystem fileSystem = share.FileSystem;

            fileSystem.SetDates(openedFilePath, request.CreationDateTime, request.LastWriteDateTime, request.LastAccessDateTime);
            return(new SetInformation2Response());
        }
Example #11
0
        internal static SMBCommand GetSetInformationResponse(SMBHeader header, SetInformationRequest request, FileSystemShare share, StateObject state)
        {
            string userName = state.GetConnectedUserName(header.UID);

            if (!share.HasWriteAccess(userName))
            {
                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                return(new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2));
            }
            IFileSystem fileSystem = share.FileSystem;

            FileSystemEntry entry = fileSystem.GetEntry(request.FileName);

            if (entry == null)
            {
                header.Status = NTStatus.STATUS_NO_SUCH_FILE;
                return(new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION));
            }

            bool?isHidden   = null;
            bool?isReadOnly = null;
            bool?isArchived = null;

            if ((request.FileAttributes & SMBLibrary.SMB1.FileAttributes.Hidden) > 0)
            {
                isHidden = true;
            }
            if ((request.FileAttributes & SMBLibrary.SMB1.FileAttributes.ReadOnly) > 0)
            {
                isReadOnly = true;
            }
            if ((request.FileAttributes & SMBLibrary.SMB1.FileAttributes.Archive) > 0)
            {
                isArchived = true;
            }
            fileSystem.SetAttributes(request.FileName, isHidden, isReadOnly, isArchived);

            if (request.LastWriteTime != SMBHelper.UTimeNotSpecified)
            {
                fileSystem.SetDates(request.FileName, null, request.LastWriteTime, null);
            }

            return(new SetInformationResponse());
        }
Example #12
0
        internal static SMBCommand GetQueryInformationResponse(SMBHeader header, QueryInformationRequest request, FileSystemShare share)
        {
            IFileSystem     fileSystem = share.FileSystem;
            FileSystemEntry entry      = fileSystem.GetEntry(request.FileName);

            if (entry == null)
            {
                header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
                return(new ErrorResponse(CommandName.SMB_COM_QUERY_INFORMATION));
            }

            QueryInformationResponse response = new QueryInformationResponse();

            response.FileAttributes = InfoHelper.GetFileAttributes(entry);
            response.LastWriteTime  = entry.LastWriteTime;
            response.FileSize       = (uint)Math.Min(UInt32.MaxValue, entry.Size);

            return(response);
        }
Example #13
0
        internal static SMBCommand GetCreateDirectoryResponse(SMBHeader header, CreateDirectoryRequest request, FileSystemShare share, StateObject state)
        {
            string userName = state.GetConnectedUserName(header.UID);

            if (!share.HasWriteAccess(userName))
            {
                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                return(new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY));
            }
            IFileSystem fileSystem = share.FileSystem;

            try
            {
                fileSystem.CreateDirectory(request.DirectoryName);
            }
            catch (IOException)
            {
                header.Status = NTStatus.STATUS_OBJECT_NAME_INVALID;
                return(new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY));
            }
            catch (UnauthorizedAccessException)
            {
                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                return(new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY));
            }

            return(new CreateDirectoryResponse());
        }
Example #14
0
        internal static SMBCommand GetRenameResponse(SMBHeader header, RenameRequest request, FileSystemShare share, StateObject state)
        {
            string userName = state.GetConnectedUserName(header.UID);

            if (!share.HasWriteAccess(userName))
            {
                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                return(new ErrorResponse(CommandName.SMB_COM_RENAME));
            }
            IFileSystem fileSystem = share.FileSystem;

            FileSystemEntry sourceEntry = fileSystem.GetEntry(request.OldFileName);

            if (sourceEntry == null)
            {
                header.Status = NTStatus.STATUS_NO_SUCH_FILE;
                return(new ErrorResponse(CommandName.SMB_COM_RENAME));
            }

            // The file must not already exist unless we just want to upcase / downcase a filename letter
            FileSystemEntry destinationEntry = fileSystem.GetEntry(request.NewFileName);

            if (destinationEntry != null &&
                !String.Equals(request.OldFileName, request.NewFileName, StringComparison.InvariantCultureIgnoreCase))
            {
                // The new file already exists.
                header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
                return(new ErrorResponse(CommandName.SMB_COM_RENAME));
            }

            try
            {
                fileSystem.Move(request.OldFileName, request.NewFileName);
                return(new RenameResponse());
            }
            catch (IOException)
            {
                header.Status = NTStatus.STATUS_SHARING_VIOLATION;
                return(new ErrorResponse(CommandName.SMB_COM_RENAME));
            }
            catch (UnauthorizedAccessException)
            {
                header.Status = NTStatus.STATUS_ACCESS_DENIED;
                return(new ErrorResponse(CommandName.SMB_COM_RENAME));
            }
        }
        internal static Transaction2SetFileInformationResponse GetSubcommandResponse(SMBHeader header, Transaction2SetFileInformationRequest subcommand, FileSystemShare share, StateObject state)
        {
            string openedFilePath = state.GetOpenedFilePath(subcommand.FID);

            if (openedFilePath == null)
            {
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }

            Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse();

            switch (subcommand.InformationLevel)
            {
            case SetInformationLevel.SMB_INFO_STANDARD:
            {
                return(response);
            }

            case SetInformationLevel.SMB_INFO_SET_EAS:
            {
                throw new NotImplementedException();
            }

            case SetInformationLevel.SMB_SET_FILE_BASIC_INFO:
            {
                string userName = state.GetConnectedUserName(header.UID);
                if (!share.HasWriteAccess(userName))
                {
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(null);
                }

                SetFileBasicInfo info       = (SetFileBasicInfo)subcommand.SetInfo;
                bool             isHidden   = (info.ExtFileAttributes & ExtendedFileAttributes.Hidden) > 0;
                bool             isReadonly = (info.ExtFileAttributes & ExtendedFileAttributes.Readonly) > 0;
                bool             isArchived = (info.ExtFileAttributes & ExtendedFileAttributes.Archive) > 0;
                try
                {
                    share.FileSystem.SetAttributes(openedFilePath, isHidden, isReadonly, isArchived);
                }
                catch (UnauthorizedAccessException)
                {
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(null);
                }

                DateTime?creationTime   = null;
                DateTime?lastWriteDT    = null;
                DateTime?lastAccessTime = null;
                if (info.CreationTime != SMBHelper.FileTimeNotSpecified)
                {
                    creationTime = info.CreationTime;
                }
                if (info.LastWriteTime != SMBHelper.FileTimeNotSpecified)
                {
                    lastWriteDT = info.LastWriteTime;
                }
                if (info.LastAccessTime != SMBHelper.FileTimeNotSpecified)
                {
                    lastAccessTime = info.LastAccessTime;
                }

                try
                {
                    share.FileSystem.SetDates(openedFilePath, creationTime, lastWriteDT, lastAccessTime);
                }
                catch (IOException ex)
                {
                    ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
                    if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
                    {
                        // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid
                        header.Status = NTStatus.STATUS_SHARING_VIOLATION;
                        return(null);
                    }
                    else
                    {
                        header.Status = NTStatus.STATUS_DATA_ERROR;
                        return(null);
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    header.Status = NTStatus.STATUS_ACCESS_DENIED;
                    return(null);
                }
                return(response);
            }

            case SetInformationLevel.SMB_SET_FILE_DISPOSITION_INFO:
            {
                if (((SetFileDispositionInfo)subcommand.SetInfo).DeletePending)
                {
                    // We're supposed to delete the file on close, but it's too late to report errors at this late stage
                    string userName = state.GetConnectedUserName(header.UID);
                    if (!share.HasWriteAccess(userName))
                    {
                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
                        return(null);
                    }

                    try
                    {
                        share.FileSystem.Delete(openedFilePath);
                    }
                    catch (IOException)
                    {
                        header.Status = NTStatus.STATUS_FILE_LOCK_CONFLICT;
                        return(null);
                    }
                    catch (UnauthorizedAccessException)
                    {
                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
                        return(null);
                    }
                }
                return(response);
            }

            case SetInformationLevel.SMB_SET_FILE_ALLOCATION_INFO:
            {
                // This subcommand is used to set the file length in bytes.
                // Note: the input will NOT be a multiple of the cluster size / bytes per sector.
                ulong allocationSize = ((SetFileAllocationInfo)subcommand.SetInfo).AllocationSize;
                try
                {
                    Stream stream = share.FileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
                    stream.SetLength((long)allocationSize);
                    stream.Close();
                }
                catch
                {
                }
                return(response);
            }

            case SetInformationLevel.SMB_SET_FILE_END_OF_FILE_INFO:
            {
                ulong endOfFile = ((SetFileEndOfFileInfo)subcommand.SetInfo).EndOfFile;
                try
                {
                    Stream stream = share.FileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
                    stream.SetLength((long)endOfFile);
                    stream.Close();
                }
                catch
                {
                }
                return(response);
            }

            default:
            {
                throw new InvalidRequestException();
            }
            }
        }
        internal static SMBCommand GetCompleteTransaction2Response(SMBHeader header, byte[] requestSetup, byte[] requestParameters, byte[] requestData, object share, StateObject state, List <SMBCommand> sendQueue)
        {
            Transaction2Subcommand subcommand         = Transaction2Subcommand.GetSubcommandRequest(requestSetup, requestParameters, requestData, header.UnicodeFlag);
            Transaction2Subcommand subcommandResponse = null;

            if (!(share is FileSystemShare))
            {
                header.Status = NTStatus.STATUS_SMB_BAD_COMMAND;
                return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION2));
            }

            FileSystemShare fileSystemShare = (FileSystemShare)share;

            if (subcommand is Transaction2FindFirst2Request)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindFirst2Request)subcommand, fileSystemShare, state);
            }
            else if (subcommand is Transaction2FindNext2Request)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindNext2Request)subcommand, fileSystemShare, state);
            }
            else if (subcommand is Transaction2QueryFSInformationRequest)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryFSInformationRequest)subcommand, fileSystemShare);
            }
            else if (subcommand is Transaction2QueryPathInformationRequest)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryPathInformationRequest)subcommand, fileSystemShare);
            }
            else if (subcommand is Transaction2SetPathInformationRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is Transaction2QueryFileInformationRequest)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryFileInformationRequest)subcommand, fileSystemShare, state);
            }
            else if (subcommand is Transaction2SetFileInformationRequest)
            {
                subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2SetFileInformationRequest)subcommand, fileSystemShare, state);
            }
            else if (subcommand is Transaction2CreateDirectoryRequest)
            {
                header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
            }
            else if (subcommand is Transaction2GetDfsReferralRequest)
            {
                header.Status = NTStatus.STATUS_NO_SUCH_DEVICE;
            }
            else
            {
                header.Status = NTStatus.STATUS_SMB_BAD_COMMAND;
            }

            if (header.Status != NTStatus.STATUS_SUCCESS)
            {
                return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION2));
            }

            byte[] responseSetup          = subcommandResponse.GetSetup();
            byte[] responseParameters     = subcommandResponse.GetParameters(header.UnicodeFlag);
            byte[] responseData           = subcommandResponse.GetData(header.UnicodeFlag);
            Transaction2Response response = new Transaction2Response();

            PrepareResponse(response, responseSetup, responseParameters, responseData, state.MaxBufferSize, sendQueue);
            return(response);
        }
Example #17
0
        internal static SMBCommand GetCheckDirectoryResponse(SMBHeader header, CheckDirectoryRequest request, FileSystemShare share)
        {
            IFileSystem     fileSystem = share.FileSystem;
            FileSystemEntry entry      = fileSystem.GetEntry(request.DirectoryName);

            if (entry == null || !entry.IsDirectory)
            {
                header.Status = NTStatus.STATUS_NO_SUCH_FILE;
                return(new ErrorResponse(CommandName.SMB_COM_CHECK_DIRECTORY));
            }

            return(new CheckDirectoryResponse());
        }
Example #18
0
        public static byte[] PerformRead(SMBHeader header, object share, ushort FID, long offset, int maxCount, StateObject state)
        {
            OpenedFileObject openedFile = state.GetOpenedFileObject(FID);

            if (openedFile == null)
            {
                header.Status = NTStatus.STATUS_INVALID_HANDLE;
                return(null);
            }
            string openedFilePath = openedFile.Path;

            if (share is NamedPipeShare)
            {
                return(state.RetrieveNamedPipeReply(FID));
            }
            else // FileSystemShare
            {
                FileSystemShare fileSystemShare = (FileSystemShare)share;
                IFileSystem     fileSystem      = fileSystemShare.FileSystem;
                if (openedFile.IsSequentialAccess)
                {
                    bool isInCache = (offset >= openedFile.CacheOffset) && (offset + maxCount <= openedFile.CacheOffset + openedFile.Cache.Length);
                    if (!isInCache)
                    {
                        int bytesRead;
                        try
                        {
                            Stream stream = fileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                            stream.Seek(offset, SeekOrigin.Begin);
                            openedFile.CacheOffset = offset;
                            openedFile.Cache       = new byte[OpenedFileObject.CacheSize];
                            bytesRead = stream.Read(openedFile.Cache, 0, OpenedFileObject.CacheSize);
                            stream.Close();
                        }
                        catch (IOException ex)
                        {
                            ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
                            if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
                            {
                                // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid
                                header.Status = NTStatus.STATUS_SHARING_VIOLATION;
                                return(null);
                            }
                            else
                            {
                                header.Status = NTStatus.STATUS_DATA_ERROR;
                                return(null);
                            }
                        }
                        catch (UnauthorizedAccessException)
                        {
                            header.Status = NTStatus.STATUS_ACCESS_DENIED;
                            return(null);
                        }

                        if (bytesRead < OpenedFileObject.CacheSize)
                        {
                            // EOF, we must trim the response data array
                            byte[] buffer = new byte[bytesRead];
                            Array.Copy(openedFile.Cache, 0, buffer, 0, bytesRead);
                            openedFile.Cache = buffer;
                        }
                    }

                    int    offsetInCache = (int)(offset - openedFile.CacheOffset);
                    int    bytesRemained = openedFile.Cache.Length - offsetInCache;
                    int    dataLength    = Math.Min(maxCount, bytesRemained);
                    byte[] data          = new byte[dataLength];
                    Array.Copy(openedFile.Cache, offsetInCache, data, 0, dataLength);
                    return(data);
                }
                else
                {
                    int    bytesRead;
                    byte[] data;
                    try
                    {
                        Stream stream = fileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                        stream.Seek(offset, SeekOrigin.Begin);
                        data      = new byte[maxCount];
                        bytesRead = stream.Read(data, 0, maxCount);
                        stream.Close();
                    }
                    catch (IOException ex)
                    {
                        ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
                        if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
                        {
                            // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid
                            header.Status = NTStatus.STATUS_SHARING_VIOLATION;
                            return(null);
                        }
                        else
                        {
                            header.Status = NTStatus.STATUS_DATA_ERROR;
                            return(null);
                        }
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        header.Status = NTStatus.STATUS_DATA_ERROR;
                        return(null);
                    }
                    catch (UnauthorizedAccessException)
                    {
                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
                        return(null);
                    }

                    if (bytesRead < maxCount)
                    {
                        // EOF, we must trim the response data array
                        byte[] buffer = new byte[bytesRead];
                        Array.Copy(data, 0, buffer, 0, bytesRead);
                        data = buffer;
                    }
                    return(data);
                }
            }
        }
Example #19
0
        internal static SMBCommand GetOpenAndXResponse(SMBHeader header, OpenAndXRequest request, object share, StateObject state)
        {
            bool   isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0;
            string path       = request.FileName;

            if (share is NamedPipeShare)
            {
                RemoteService service = ((NamedPipeShare)share).GetService(path);
                if (service != null)
                {
                    ushort fileID = state.AddOpenedFile(path);
                    if (isExtended)
                    {
                        return(CreateResponseExtendedForNamedPipe(fileID));
                    }
                    else
                    {
                        CreateResponseForNamedPipe(fileID);
                    }
                }

                header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
                return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX));
            }
            else // FileSystemShare
            {
                FileSystemShare fileSystemShare = (FileSystemShare)share;
                string          userName        = state.GetConnectedUserName(header.UID);
                bool            hasWriteAccess  = fileSystemShare.HasWriteAccess(userName);
                IFileSystem     fileSystem      = fileSystemShare.FileSystem;

                OpenResult      openResult;
                FileSystemEntry entry = fileSystem.GetEntry(path);
                if (entry != null)
                {
                    if (!hasWriteAccess && request.AccessMode.AccessMode == AccessMode.Write || request.AccessMode.AccessMode == AccessMode.ReadWrite)
                    {
                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
                        return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX));
                    }

                    if (request.OpenMode.FileExistsOpts == FileExistsOpts.ReturnError)
                    {
                        header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
                        return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX));
                    }
                    else if (request.OpenMode.FileExistsOpts == FileExistsOpts.TruncateToZero)
                    {
                        try
                        {
                            Stream stream = fileSystem.OpenFile(path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite);
                            stream.Close();
                        }
                        catch (IOException ex)
                        {
                            ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
                            if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
                            {
                                header.Status = NTStatus.STATUS_SHARING_VIOLATION;
                                return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX));
                            }
                            else
                            {
                                header.Status = NTStatus.STATUS_DATA_ERROR;
                                return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX));
                            }
                        }
                        catch (UnauthorizedAccessException)
                        {
                            header.Status = NTStatus.STATUS_ACCESS_DENIED;
                            return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX));
                        }
                        openResult = OpenResult.FileExistedAndWasTruncated;
                    }
                    else // FileExistsOpts.Append
                    {
                        openResult = OpenResult.FileExistedAndWasOpened;
                    }
                }
                else
                {
                    if (request.OpenMode.CreateFile == CreateFile.ReturnErrorIfNotExist)
                    {
                        header.Status = NTStatus.STATUS_NO_SUCH_FILE;
                        return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX));
                    }

                    entry      = fileSystem.CreateFile(path);
                    openResult = OpenResult.NotExistedAndWasCreated;
                }

                ushort fileID = state.AddOpenedFile(path, true);
                if (isExtended)
                {
                    return(CreateResponseFromFileSystemEntry(entry, fileID, openResult));
                }
                else
                {
                    return(CreateResponseExtendedFromFileSystemEntry(entry, fileID, openResult));
                }
            }
        }