Exemple #1
0
        internal static SMB2Command GetSetInfoResponse(SetInfoRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session    session  = state.GetSession(request.Header.SessionID);
            OpenFileObject openFile = null;

            if (request.InfoType == InfoType.File || request.InfoType == InfoType.Security)
            {
                openFile = session.GetOpenFileObject(request.FileId);
                if (openFile == null)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
                }

                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);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }
                }
            }
            else if (request.InfoType == InfoType.FileSystem)
            {
                if (share is FileSystemShare)
                {
                    if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, @"\"))
                    {
                        state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. User '{1}' was denied access.", share.Name, session.UserName);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }
                }
            }

            if (request.InfoType == InfoType.File)
            {
                FileInformation information;
                try
                {
                    information = FileInformation.GetFileInformation(request.Buffer, 0, request.FileInformationClass);
                }
                catch (UnsupportedInformationLevelException)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_INVALID_INFO_CLASS.", share.Name, openFile.Path, request.FileInformationClass);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_INFO_CLASS));
                }
                catch (NotImplementedException)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_NOT_SUPPORTED.", share.Name, openFile.Path, request.FileInformationClass);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED));
                }
                catch (Exception)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path, request.FileInformationClass);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                }

                if ((share is FileSystemShare) && (information is FileRenameInformationType2))
                {
                    string newFileName = ((FileRenameInformationType2)information).FileName;
                    if (!newFileName.StartsWith(@"\"))
                    {
                        newFileName = @"\" + newFileName;
                    }
                    if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, newFileName))
                    {
                        state.LogToServer(Severity.Verbose, "SetFileInformation: Rename '{0}{1}' to '{0}{2}' failed. User '{3}' was denied access.", share.Name, openFile.Path, newFileName, session.UserName);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }
                }

                NTStatus status = share.FileStore.SetFileInformation(openFile.Handle, information);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}. (FileId: {4})", share.Name, openFile.Path, request.FileInformationClass, status, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, status));
                }

                if (information is FileRenameInformationType2)
                {
                    string newFileName = ((FileRenameInformationType2)information).FileName;
                    if (!newFileName.StartsWith(@"\"))
                    {
                        newFileName = @"\" + newFileName;
                    }
                    state.LogToServer(Severity.Verbose, "SetFileInformation: Rename '{0}{1}' to '{0}{2}' succeeded. (FileId: {3})", share.Name, openFile.Path, newFileName, request.FileId.Volatile);
                    openFile.Path = newFileName;
                }
                else
                {
                    state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information class: {2}. (FileId: {3})", share.Name, openFile.Path, request.FileInformationClass, request.FileId.Volatile);
                }
                return(new SetInfoResponse());
            }
            else if (request.InfoType == InfoType.FileSystem)
            {
                FileSystemInformation fileSystemInformation;
                try
                {
                    fileSystemInformation = FileSystemInformation.GetFileSystemInformation(request.Buffer, 0, request.FileSystemInformationClass);
                }
                catch (UnsupportedInformationLevelException)
                {
                    state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: STATUS_INVALID_INFO_CLASS.", share.Name, request.FileSystemInformationClass);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_INFO_CLASS));
                }
                catch (Exception)
                {
                    state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, request.FileSystemInformationClass);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                }

                NTStatus status = share.FileStore.SetFileSystemInformation(fileSystemInformation);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: {2}.", share.Name, request.FileSystemInformationClass, status);
                    return(new ErrorResponse(request.CommandName, status));
                }

                state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' succeeded. Information class: {1}.", share.Name, request.FileSystemInformationClass);
                return(new SetInfoResponse());
            }
            else if (request.InfoType == InfoType.Security)
            {
                SecurityDescriptor securityDescriptor;
                try
                {
                    securityDescriptor = new SecurityDescriptor(request.Buffer, 0);
                }
                catch
                {
                    state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' failed. NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                }

                NTStatus status = share.FileStore.SetSecurityInformation(openFile, request.SecurityInformation, securityDescriptor);
                if (status != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FileId: {4})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), status, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, status));
                }

                state.LogToServer(Severity.Information, "SetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FileId: {3})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), request.FileId.Volatile);
                return(new SetInfoResponse());
            }
            return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED));
        }
Exemple #2
0
        internal static SMB2Command GetQueryInfoResponse(QueryInfoRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session session = state.GetSession(request.Header.SessionID);

            if (request.InfoType == InfoType.File)
            {
                OpenFileObject openFile = session.GetOpenFileObject(request.FileId);
                if (openFile == null)
                {
                    state.LogToServer(Severity.Verbose, "GetFileInformation failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
                }

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

                FileInformation fileInformation;
                NTStatus        queryStatus = share.FileStore.GetFileInformation(out fileInformation, openFile.Handle, request.FileInformationClass);
                if (queryStatus != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}. (FileId: {4})", share.Name, openFile.Path, request.FileInformationClass, queryStatus, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, queryStatus));
                }

                state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information class: {2}. (FileId: {3})", share.Name, openFile.Path, request.FileInformationClass, request.FileId.Volatile);
                QueryInfoResponse response = new QueryInfoResponse();
                response.SetFileInformation(fileInformation);
                if (response.OutputBuffer.Length > request.OutputBufferLength)
                {
                    response.Header.Status = NTStatus.STATUS_BUFFER_OVERFLOW;
                    response.OutputBuffer  = ByteReader.ReadBytes(response.OutputBuffer, 0, (int)request.OutputBufferLength);
                }
                return(response);
            }
            else if (request.InfoType == InfoType.FileSystem)
            {
                if (share is FileSystemShare)
                {
                    if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, @"\"))
                    {
                        state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. User '{1}' was denied access.", share.Name, session.UserName);
                        return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED));
                    }

                    FileSystemInformation fileSystemInformation;
                    NTStatus queryStatus = share.FileStore.GetFileSystemInformation(out fileSystemInformation, request.FileSystemInformationClass);
                    if (queryStatus != NTStatus.STATUS_SUCCESS)
                    {
                        state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: {2}", share.Name, request.FileSystemInformationClass, queryStatus);
                        return(new ErrorResponse(request.CommandName, queryStatus));
                    }

                    state.LogToServer(Severity.Information, "GetFileSystemInformation on '{0}' succeeded. Information class: {1}", share.Name, request.FileSystemInformationClass);
                    QueryInfoResponse response = new QueryInfoResponse();
                    response.SetFileSystemInformation(fileSystemInformation);
                    if (response.OutputBuffer.Length > request.OutputBufferLength)
                    {
                        response.Header.Status = NTStatus.STATUS_BUFFER_OVERFLOW;
                        response.OutputBuffer  = ByteReader.ReadBytes(response.OutputBuffer, 0, (int)request.OutputBufferLength);
                    }

                    return(response);
                }
            }
            else if (request.InfoType == InfoType.Security)
            {
                OpenFileObject openFile = session.GetOpenFileObject(request.FileId);
                if (openFile == null)
                {
                    state.LogToServer(Severity.Verbose, "GetSecurityInformation failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
                }

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

                SecurityDescriptor securityDescriptor;
                NTStatus           queryStatus = share.FileStore.GetSecurityInformation(out securityDescriptor, openFile.Handle, request.SecurityInformation);
                if (queryStatus != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FileId: {4})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), queryStatus, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, queryStatus));
                }

                if (securityDescriptor.Length > request.OutputBufferLength)
                {
                    state.LogToServer(Severity.Information, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: STATUS_BUFFER_TOO_SMALL. (FileId: {3})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), request.FileId.Volatile);
                    byte[] errorData = LittleEndianConverter.GetBytes((uint)securityDescriptor.Length);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_BUFFER_TOO_SMALL, errorData));
                }

                state.LogToServer(Severity.Information, "GetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FileId: {3})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), request.FileId.Volatile);
                QueryInfoResponse response = new QueryInfoResponse();
                response.SetSecurityInformation(securityDescriptor);
                return(response);
            }
            return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED));
        }
Exemple #3
0
        internal static SMB2Command GetQueryDirectoryResponse(QueryDirectoryRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session    session  = state.GetSession(request.Header.SessionID);
            OpenFileObject openFile = session.GetOpenFileObject(request.FileId);

            if (openFile == null)
            {
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
            }

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

            FileSystemShare fileSystemShare = (FileSystemShare)share;

            FileID     fileID     = request.FileId;
            OpenSearch openSearch = session.GetOpenSearch(fileID);

            if (openSearch == null || request.Reopen)
            {
                if (request.Reopen)
                {
                    session.RemoveOpenSearch(fileID);
                }
                List <QueryDirectoryFileInformation> entries;
                NTStatus searchStatus = share.FileStore.QueryDirectory(out entries, openFile.Handle, request.FileName, request.FileInformationClass);
                if (searchStatus != NTStatus.STATUS_SUCCESS)
                {
                    state.LogToServer(Severity.Verbose, "Query Directory on '{0}{1}', Searched for '{2}', NTStatus: {3}", share.Name, openFile.Path, request.FileName, searchStatus.ToString());
                    return(new ErrorResponse(request.CommandName, searchStatus));
                }
                state.LogToServer(Severity.Information, "Query Directory on '{0}{1}', Searched for '{2}', found {3} matching entries", share.Name, openFile.Path, request.FileName, entries.Count);
                openSearch = session.AddOpenSearch(fileID, entries, 0);
            }

            if (request.Restart || request.Reopen)
            {
                openSearch.EnumerationLocation = 0;
            }

            if (openSearch.Entries.Count == 0)
            {
                // [MS-SMB2] If there are no entries to return [..] the server MUST fail the request with STATUS_NO_SUCH_FILE.
                session.RemoveOpenSearch(fileID);
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NO_SUCH_FILE));
            }

            if (openSearch.EnumerationLocation == openSearch.Entries.Count)
            {
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NO_MORE_FILES));
            }

            List <QueryDirectoryFileInformation> page = new List <QueryDirectoryFileInformation>();
            int pageLength = 0;

            for (int index = openSearch.EnumerationLocation; index < openSearch.Entries.Count; index++)
            {
                QueryDirectoryFileInformation fileInformation = openSearch.Entries[index];
                if (fileInformation.FileInformationClass != request.FileInformationClass)
                {
                    // We do not support changing FileInformationClass during a search (unless SMB2_REOPEN is set).
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                }

                if (pageLength + fileInformation.Length <= request.OutputBufferLength)
                {
                    page.Add(fileInformation);
                    pageLength += fileInformation.Length;
                    openSearch.EnumerationLocation = index + 1;
                }
                else
                {
                    break;
                }

                if (request.ReturnSingleEntry)
                {
                    break;
                }
            }

            QueryDirectoryResponse response = new QueryDirectoryResponse();

            response.SetFileInformationList(page);
            return(response);
        }
        internal static SMB2Command GetIOCtlResponse(IOCtlRequest request, ISMBShare share, SMB2ConnectionState state)
        {
            SMB2Session session = state.GetSession(request.Header.SessionID);
            string      ctlCode = Enum.IsDefined(typeof(IoControlCode), request.CtlCode) ? ((IoControlCode)request.CtlCode).ToString() : ("0x" + request.CtlCode.ToString("X8"));

            if (!request.IsFSCtl)
            {
                // [MS-SMB2] If the Flags field of the request is not SMB2_0_IOCTL_IS_FSCTL the server MUST fail the request with STATUS_NOT_SUPPORTED.
                state.LogToServer(Severity.Verbose, "IOCTL: Non-FSCTL requests are not supported. CTL Code: {0}", ctlCode);
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED));
            }

            if (request.CtlCode == (uint)IoControlCode.FSCTL_DFS_GET_REFERRALS ||
                request.CtlCode == (uint)IoControlCode.FSCTL_DFS_GET_REFERRALS_EX)
            {
                // [MS-SMB2] 3.3.5.15.2 Handling a DFS Referral Information Request
                state.LogToServer(Severity.Verbose, "IOCTL failed. CTL Code: {0}. NTStatus: STATUS_FS_DRIVER_REQUIRED.", ctlCode);
                return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FS_DRIVER_REQUIRED));
            }

            object handle;

            if (request.CtlCode == (uint)IoControlCode.FSCTL_PIPE_WAIT ||
                request.CtlCode == (uint)IoControlCode.FSCTL_VALIDATE_NEGOTIATE_INFO ||
                request.CtlCode == (uint)IoControlCode.FSCTL_QUERY_NETWORK_INTERFACE_INFO)
            {
                // [MS-SMB2] 3.3.5.15 - FSCTL_PIPE_WAIT / FSCTL_QUERY_NETWORK_INTERFACE_INFO /
                // FSCTL_VALIDATE_NEGOTIATE_INFO requests MUST have FileId set to 0xFFFFFFFFFFFFFFFF.
                if (request.FileId.Persistent != 0xFFFFFFFFFFFFFFFF || request.FileId.Volatile != 0xFFFFFFFFFFFFFFFF)
                {
                    state.LogToServer(Severity.Verbose, "IOCTL failed. CTL Code: {0}. FileId MUST be 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ctlCode);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER));
                }
                handle = null;
            }
            else
            {
                OpenFileObject openFile = session.GetOpenFileObject(request.FileId);
                if (openFile == null)
                {
                    state.LogToServer(Severity.Verbose, "IOCTL failed. CTL Code: {0}. Invalid FileId. (SessionID: {1}, TreeID: {2}, FileId: {3})", ctlCode, request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile);
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED));
                }
                handle = openFile.Handle;
            }

            int maxOutputLength = (int)request.MaxOutputResponse;

            byte[]   output;
            NTStatus status = share.FileStore.DeviceIOControl(handle, request.CtlCode, request.Input, out output, maxOutputLength);

            if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.STATUS_BUFFER_OVERFLOW)
            {
                state.LogToServer(Severity.Verbose, "IOCTL failed. CTL Code: {0}. NTStatus: {1}.", ctlCode, status);
                return(new ErrorResponse(request.CommandName, status));
            }

            state.LogToServer(Severity.Verbose, "IOCTL succeeded. CTL Code: {0}.", ctlCode);
            IOCtlResponse response = new IOCtlResponse();

            response.Header.Status = status;
            response.CtlCode       = request.CtlCode;
            response.FileId        = request.FileId;
            response.Output        = output;
            return(response);
        }