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)); }
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)); }
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); }