internal static void ProcessNTTransactNotifyChangeRequest(SMB1Header header, uint maxParameterCount, NTTransactNotifyChangeRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); SMB1AsyncContext context = state.CreateAsyncContext(header.UID, header.TID, header.PID, header.MID, subcommand.FID, state); // We wish to make sure that the 'Monitoring started' will appear before the 'Monitoring completed' in the log lock (context) { header.Status = share.FileStore.NotifyChange(out context.IORequest, openFile.Handle, subcommand.CompletionFilter, subcommand.WatchTree, (int)maxParameterCount, OnNotifyChangeCompleted, context); if (header.Status == NTStatus.STATUS_PENDING) { state.LogToServer(Severity.Verbose, "NotifyChange: Monitoring of '{0}{1}' started. PID: {2}. MID: {3}.", share.Name, openFile.Path, context.PID, context.MID); } else if (header.Status == NTStatus.STATUS_NOT_SUPPORTED) { // [MS-CIFS] If the server does not support the NT_TRANSACT_NOTIFY_CHANGE subcommand, it can return an // error response with STATUS_NOT_IMPLEMENTED [..] in response to an NT_TRANSACT_NOTIFY_CHANGE Request. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } } }
internal static List <SMB1Command> GetCompleteNTTransactResponse(SMB1Header header, uint maxParameterCount, uint maxDataCount, NTTransactSubcommandName subcommandName, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state) { NTTransactSubcommand subcommand; try { subcommand = NTTransactSubcommand.GetSubcommandRequest(subcommandName, requestSetup, requestParameters, requestData, header.UnicodeFlag); } catch { // [MS-CIFS] If the Function code is not defined, the server MUST return STATUS_INVALID_SMB. header.Status = NTStatus.STATUS_INVALID_SMB; return(new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT)); } state.LogToServer(Severity.Verbose, "Received complete SMB_COM_NT_TRANSACT subcommand: {0}", subcommand.SubcommandName); NTTransactSubcommand subcommandResponse = null; if (subcommand is NTTransactCreateRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is NTTransactIOCTLRequest) { subcommandResponse = GetSubcommandResponse(header, maxDataCount, (NTTransactIOCTLRequest)subcommand, share, state); } else if (subcommand is NTTransactSetSecurityDescriptorRequest) { subcommandResponse = GetSubcommandResponse(header, (NTTransactSetSecurityDescriptorRequest)subcommand, share, state); } else if (subcommand is NTTransactNotifyChangeRequest) { NotifyChangeHelper.ProcessNTTransactNotifyChangeRequest(header, maxParameterCount, (NTTransactNotifyChangeRequest)subcommand, share, state); if (header.Status == NTStatus.STATUS_PENDING) { return(new List <SMB1Command>()); } } else if (subcommand is NTTransactQuerySecurityDescriptorRequest) { subcommandResponse = GetSubcommandResponse(header, maxDataCount, (NTTransactQuerySecurityDescriptorRequest)subcommand, share, state); } else { // [MS-CIFS] If the Function code is defined but not implemented, the server MUST return STATUS_SMB_BAD_COMMAND. header.Status = NTStatus.STATUS_SMB_BAD_COMMAND; } if (subcommandResponse == null) { return(new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT)); } byte[] responseSetup = subcommandResponse.GetSetup(); byte[] responseParameters = subcommandResponse.GetParameters(header.UnicodeFlag); byte[] responseData = subcommandResponse.GetData(); return(GetNTTransactResponse(responseSetup, responseParameters, responseData, state.MaxBufferSize)); }
internal static TransactionTransactNamedPipeResponse GetSubcommandResponse(SMB1Header header, TransactionTransactNamedPipeRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); if (openFile == null) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } int maxOutputLength = UInt16.MaxValue; byte[] output; header.Status = share.FileStore.DeviceIOControl(openFile.Handle, (uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE, subcommand.WriteData, out output, maxOutputLength); if (header.Status != NTStatus.STATUS_SUCCESS) { return(null); } TransactionTransactNamedPipeResponse response = new TransactionTransactNamedPipeResponse(); response.ReadData = output; return(response); }
private static NTTransactSetSecurityDescriptorResponse GetSubcommandResponse(SMB1Header header, NTTransactSetSecurityDescriptorRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "SetSecurityInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } header.Status = share.FileStore.SetSecurityInformation(openFile.Handle, subcommand.SecurityInformation, subcommand.SecurityDescriptor); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SecurityInformation.ToString("X"), header.Status, subcommand.FID); return(null); } state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FID: {3})", share.Name, openFile.Path, subcommand.SecurityInformation.ToString("X"), subcommand.FID); NTTransactSetSecurityDescriptorResponse response = new NTTransactSetSecurityDescriptorResponse(); return(response); }
private static NTTransactQuerySecurityDescriptorResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, NTTransactQuerySecurityDescriptorRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "GetSecurityInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } int maxOutputLength = (int)maxDataCount; SecurityDescriptor securityDescriptor; header.Status = share.FileStore.GetSecurityInformation(out securityDescriptor, openFile.Handle, subcommand.SecurityInfoFields); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SecurityInfoFields.ToString("X"), header.Status, subcommand.FID); return(null); } NTTransactQuerySecurityDescriptorResponse response = new NTTransactQuerySecurityDescriptorResponse(); response.LengthNeeded = (uint)securityDescriptor.Length; if (response.LengthNeeded <= maxDataCount) { state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FID: {3})", share.Name, openFile.Path, subcommand.SecurityInfoFields.ToString("X"), subcommand.FID); response.SecurityDescriptor = securityDescriptor; } else { state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: STATUS_BUFFER_TOO_SMALL. (FID: {3})", share.Name, openFile.Path, subcommand.SecurityInfoFields.ToString("X"), subcommand.FID); header.Status = NTStatus.STATUS_BUFFER_TOO_SMALL; } return(response); }
internal static List <SMB1Command> GetCompleteTransaction2Response(SMB1Header header, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state) { Transaction2Subcommand subcommand; try { subcommand = Transaction2Subcommand.GetSubcommandRequest(requestSetup, requestParameters, requestData, header.UnicodeFlag); } catch { header.Status = NTStatus.STATUS_INVALID_SMB; return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION2)); } Transaction2Subcommand subcommandResponse = null; if (subcommand is Transaction2FindFirst2Request) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindFirst2Request)subcommand, share, state); } else if (subcommand is Transaction2FindNext2Request) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindNext2Request)subcommand, share, state); } else if (subcommand is Transaction2QueryFSInformationRequest) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryFSInformationRequest)subcommand, share, state); } else if (subcommand is Transaction2QueryPathInformationRequest) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryPathInformationRequest)subcommand, share, state); } else if (subcommand is Transaction2SetPathInformationRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is Transaction2QueryFileInformationRequest) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryFileInformationRequest)subcommand, share, state); } else if (subcommand is Transaction2SetFileInformationRequest) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2SetFileInformationRequest)subcommand, share, 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); return(GetTransactionResponse(true, responseSetup, responseParameters, responseData, state.MaxBufferSize)); }
/// <summary> /// There are no secondary response messages. /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request. /// The server MUST respond to the transaction request as a whole. /// </summary> internal static List <SMB1Command> GetTransactionResponse(SMB1Header header, TransactionSecondaryRequest request, ISMBShare share, SMB1ConnectionState state) { ProcessStateObject processState = state.GetProcessState(header.PID); if (processState == null) { throw new InvalidRequestException(); } ByteWriter.WriteBytes(processState.TransactionParameters, request.ParameterDisplacement, request.TransParameters); ByteWriter.WriteBytes(processState.TransactionData, request.DataDisplacement, request.TransData); processState.TransactionParametersReceived += request.TransParameters.Length; processState.TransactionDataReceived += request.TransData.Length; if (processState.TransactionParametersReceived < processState.TransactionParameters.Length || processState.TransactionDataReceived < processState.TransactionData.Length) { return(new List <SMB1Command>()); } else { // We have a complete command if (request is Transaction2SecondaryRequest) { return(GetCompleteTransaction2Response(header, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state)); } else { return(GetCompleteTransactionResponse(header, processState.Name, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state)); } } }
internal static SMB1Command GetWriteResponse(SMB1Header header, WriteAndXRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(request.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "Write failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, request.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(new ErrorResponse(request.CommandName)); } if (share is FileSystemShare) { if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "Write to '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } int numberOfBytesWritten; header.Status = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, (long)request.Offset, request.Data); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Write to '{0}{1}' failed. NTStatus: {2}. (FID: {3})", share.Name, openFile.Path, header.Status, request.FID); return(new ErrorResponse(request.CommandName)); } WriteAndXResponse response = new WriteAndXResponse(); response.Count = (uint)numberOfBytesWritten; if (share is FileSystemShare) { // If the client wrote to a disk file, this field MUST be set to 0xFFFF. response.Available = 0xFFFF; } return(response); }
internal static SMB1Command GetFlushResponse(SMB1Header header, FlushRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); if (request.FID == 0xFFFF) { // [MS-CIFS] If the FID is 0xFFFF, the Server.Connection.FileOpenTable MUST be scanned for // all files that were opened by the PID listed in the request header. // The server MUST attempt to flush each Server.Open so listed. return(new FlushResponse()); } OpenFileObject openFile = session.GetOpenFileObject(request.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "Flush failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, request.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(new ErrorResponse(request.CommandName)); } header.Status = share.FileStore.FlushFileBuffers(openFile.Handle); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Flush '{0}{1}' failed. NTStatus: {2}. (FID: {3})", share.Name, openFile.Path, header.Status, request.FID); return(new ErrorResponse(request.CommandName)); } return(new FlushResponse()); }
internal static SMB1Command GetReadResponse(SMB1Header header, ReadAndXRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(request.FID); if (openFile == null) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } if (share is FileSystemShare) { if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "ReadAndX from '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } uint maxCount = request.MaxCount; if ((share is FileSystemShare) && state.LargeRead) { maxCount = request.MaxCountLarge; } byte[] data; header.Status = share.FileStore.ReadFile(out data, openFile.Handle, (long)request.Offset, (int)maxCount); if (header.Status != NTStatus.STATUS_SUCCESS) { return(new ErrorResponse(request.CommandName)); } ReadAndXResponse response = new ReadAndXResponse(); if (share is FileSystemShare) { // If the client reads from a disk file, this field MUST be set to -1 (0xFFFF) response.Available = 0xFFFF; } response.Data = data; return(response); }
internal static SMB1Command GetWriteResponse(SMB1Header header, WriteRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(request.FID); if (openFile == null) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(new ErrorResponse(request.CommandName)); } if (share is FileSystemShare) { if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "Write to '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } int numberOfBytesWritten; header.Status = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, request.WriteOffsetInBytes, request.Data); if (header.Status != NTStatus.STATUS_SUCCESS) { return(new ErrorResponse(request.CommandName)); } WriteResponse response = new WriteResponse(); response.CountOfBytesWritten = (ushort)numberOfBytesWritten; return(response); }
internal static List <SMB1Command> GetCompleteNTTransactResponse(SMB1Header header, NTTransactSubcommandName subcommandName, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state) { NTTransactSubcommand subcommand = NTTransactSubcommand.GetSubcommandRequest(subcommandName, requestSetup, requestParameters, requestData, header.UnicodeFlag); NTTransactSubcommand subcommandResponse = null; if (subcommand is NTTransactCreateRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is NTTransactIOCTLRequest) { subcommandResponse = GetSubcommandResponse(header, (NTTransactIOCTLRequest)subcommand, share, state); } else if (subcommand is NTTransactSetSecurityDescriptor) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is NTTransactNotifyChangeRequest) { // [MS-CIFS] If the server does not support the NT_TRANSACT_NOTIFY_CHANGE subcommand, it can return an // error response with STATUS_NOT_IMPLEMENTED [..] in response to an NT_TRANSACT_NOTIFY_CHANGE Request. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is NTTransactQuerySecurityDescriptorRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else { header.Status = NTStatus.STATUS_SMB_BAD_COMMAND; } if (header.Status != NTStatus.STATUS_SUCCESS) { return(new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT)); } byte[] responseSetup = subcommandResponse.GetSetup(); byte[] responseParameters = subcommandResponse.GetParameters(header.UnicodeFlag); byte[] responseData = subcommandResponse.GetData(); return(GetNTTransactResponse(responseSetup, responseParameters, responseData, state.MaxBufferSize)); }
private static NTTransactIOCTLResponse GetSubcommandResponse(SMB1Header header, NTTransactIOCTLRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); NTTransactIOCTLResponse response = new NTTransactIOCTLResponse(); if (subcommand.IsFsctl) { OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); if (openFile == null) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } int maxOutputLength = UInt16.MaxValue; byte[] output; header.Status = share.FileStore.DeviceIOControl(openFile.Handle, subcommand.FunctionCode, subcommand.Data, out output, maxOutputLength); if (header.Status != NTStatus.STATUS_SUCCESS) { return(null); } response.Data = output; return(response); } else { // [MS-SMB] If the IsFsctl field is set to zero, the server SHOULD fail the request with STATUS_NOT_SUPPORTED header.Status = NTStatus.STATUS_NOT_SUPPORTED; return(null); } }
private static void OnNotifyChangeCompleted(NTStatus status, byte[] buffer, object context) { SMB1AsyncContext asyncContext = (SMB1AsyncContext)context; // Wait until the 'Monitoring started' will be written to the log lock (asyncContext) { SMB1ConnectionState connection = asyncContext.Connection; connection.RemoveAsyncContext(asyncContext); SMB1Session session = connection.GetSession(asyncContext.UID); if (session != null) { OpenFileObject openFile = session.GetOpenFileObject(asyncContext.FileID); if (openFile != null) { connection.LogToServer(Severity.Verbose, "NotifyChange: Monitoring of '{0}{1}' completed. NTStatus: {2}. PID: {3}. MID: {4}.", openFile.ShareName, openFile.Path, status, asyncContext.PID, asyncContext.MID); } SMB1Header header = new SMB1Header(); header.Command = CommandName.SMB_COM_NT_TRANSACT; header.Status = status; header.Flags = HeaderFlags.CaseInsensitive | HeaderFlags.CanonicalizedPaths | HeaderFlags.Reply; // [MS-CIFS] SMB_FLAGS2_LONG_NAMES SHOULD be set to 1 when the negotiated dialect is NT LANMAN. // [MS-CIFS] SMB_FLAGS2_UNICODE SHOULD be set to 1 when the negotiated dialect is NT LANMAN. // [MS-CIFS] The Windows NT Server implementation of NT_TRANSACT_NOTIFY_CHANGE always returns the names of changed files in Unicode format. header.Flags2 = HeaderFlags2.LongNamesAllowed | HeaderFlags2.NTStatusCode | HeaderFlags2.Unicode; header.UID = asyncContext.UID; header.TID = asyncContext.TID; header.PID = asyncContext.PID; header.MID = asyncContext.MID; if (status == NTStatus.STATUS_SUCCESS) { NTTransactNotifyChangeResponse notifyChangeResponse = new NTTransactNotifyChangeResponse(); notifyChangeResponse.FileNotifyInformationBytes = buffer; byte[] responseSetup = notifyChangeResponse.GetSetup(); byte[] responseParameters = notifyChangeResponse.GetParameters(false); byte[] responseData = notifyChangeResponse.GetData(); List <SMB1Command> responseList = NTTransactHelper.GetNTTransactResponse(responseSetup, responseParameters, responseData, asyncContext.Connection.MaxBufferSize); if (responseList.Count == 1) { SMB1Message reply = new SMB1Message(); reply.Header = header; reply.Commands.Add(responseList[0]); SMBServer.EnqueueMessage(asyncContext.Connection, reply); } else { // [MS-CIFS] In the event that the number of changes exceeds [..] the maximum size of the NT_Trans_Parameter block in // the response [..] the NT Trans subsystem MUST return an error response with a Status value of STATUS_NOTIFY_ENUM_DIR. header.Status = NTStatus.STATUS_NOTIFY_ENUM_DIR; ErrorResponse response = new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT); SMB1Message reply = new SMB1Message(); reply.Header = header; reply.Commands.Add(response); SMBServer.EnqueueMessage(asyncContext.Connection, reply); } } else { // Windows Server 2008 SP1 Will use ErrorResponse to return any status other than STATUS_SUCCESS (including STATUS_CANCELLED and STATUS_DELETE_PENDING). // // [MS-CIFS] In the event that the number of changes exceeds the size of the change notify buffer [..] // the NT Trans subsystem MUST return an error response with a Status value of STATUS_NOTIFY_ENUM_DIR. ErrorResponse response = new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT); SMB1Message reply = new SMB1Message(); reply.Header = header; reply.Commands.Add(response); SMBServer.EnqueueMessage(asyncContext.Connection, reply); } } } }
internal static SMB1Command GetNTCreateResponse(SMB1Header header, NTCreateAndXRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); bool isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0; string path = request.FileName; if (!path.StartsWith(@"\")) { path = @"\" + path; } FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition); if (share is FileSystemShare) { if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess)) { state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.FileName, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } object handle; FileStatus fileStatus; FileAttributes fileAttributes = ToFileAttributes(request.ExtFileAttributes); // GetFileInformation/FileNetworkOpenInformation requires FILE_READ_ATTRIBUTES AccessMask desiredAccess = request.DesiredAccess | (AccessMask)FileAccessMask.FILE_READ_ATTRIBUTES; NTStatus createStatus = share.FileStore.CreateFile(out handle, out fileStatus, path, desiredAccess, fileAttributes, request.ShareAccess, request.CreateDisposition, request.CreateOptions, session.SecurityContext); if (createStatus != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. NTStatus: {2}.", share.Name, path, createStatus); header.Status = createStatus; return(new ErrorResponse(request.CommandName)); } FileAccess fileAccess = NTFileStoreHelper.ToFileAccess(desiredAccess); ushort? fileID = session.AddOpenFile(header.TID, share.Name, path, handle, fileAccess); if (!fileID.HasValue) { share.FileStore.CloseFile(handle); state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. Too many open files.", share.Name, path); header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES; return(new ErrorResponse(request.CommandName)); } string fileAccessString = fileAccess.ToString().Replace(", ", "|"); string shareAccessString = request.ShareAccess.ToString().Replace(", ", "|"); state.LogToServer(Severity.Verbose, "Create: Opened '{0}{1}', FileAccess: {2}, ShareAccess: {3}. (UID: {4}, TID: {5}, FID: {6})", share.Name, path, fileAccessString, shareAccessString, header.UID, header.TID, fileID.Value); if (share is NamedPipeShare) { if (isExtended) { return(CreateResponseExtendedForNamedPipe(fileID.Value, FileStatus.FILE_OPENED)); } else { return(CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED)); } } else // FileSystemShare { FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle); if (isExtended) { NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileInformation(fileInfo, fileID.Value, fileStatus); return(response); } else { NTCreateAndXResponse response = CreateResponseFromFileInformation(fileInfo, fileID.Value, fileStatus); return(response); } } }
internal static SMB1Command GetReadResponse(SMB1Header header, ReadRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(request.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "Read failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, request.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(new ErrorResponse(request.CommandName)); } if (share is FileSystemShare) { if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "Read from '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } byte[] data; header.Status = share.FileStore.ReadFile(out data, openFile.Handle, request.ReadOffsetInBytes, request.CountOfBytesToRead); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Read from '{0}{1}' failed. NTStatus: {2}. (FID: {3})", share.Name, openFile.Path, header.Status, request.FID); return(new ErrorResponse(request.CommandName)); } ReadResponse response = new ReadResponse(); response.Bytes = data; response.CountOfBytesReturned = (ushort)data.Length; return(response); }
internal static List <SMB1Command> GetCompleteTransactionResponse(SMB1Header header, string name, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state) { if (String.Equals(name, @"\pipe\lanman", StringComparison.InvariantCultureIgnoreCase)) { // [MS-RAP] Remote Administration Protocol request state.LogToServer(Severity.Debug, "Remote Administration Protocol requests are not implemented"); header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION)); } TransactionSubcommand subcommand; try { subcommand = TransactionSubcommand.GetSubcommandRequest(requestSetup, requestParameters, requestData, header.UnicodeFlag); } catch { header.Status = NTStatus.STATUS_INVALID_SMB; return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION)); } TransactionSubcommand subcommandResponse = null; if (subcommand is TransactionSetNamedPipeStateRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is TransactionRawReadNamedPipeRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is TransactionQueryNamedPipeStateRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is TransactionQueryNamedPipeInfoRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is TransactionPeekNamedPipeRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is TransactionTransactNamedPipeRequest) { subcommandResponse = TransactionSubcommandHelper.GetSubcommandResponse(header, (TransactionTransactNamedPipeRequest)subcommand, share, state); } else if (subcommand is TransactionRawWriteNamedPipeRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is TransactionReadNamedPipeRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is TransactionWriteNamedPipeRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is TransactionWaitNamedPipeRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is TransactionCallNamedPipeRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else { header.Status = NTStatus.STATUS_SMB_BAD_COMMAND; } if (header.Status != NTStatus.STATUS_SUCCESS) { return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION)); } byte[] responseSetup = subcommandResponse.GetSetup(); byte[] responseParameters = subcommandResponse.GetParameters(header.UnicodeFlag); byte[] responseData = subcommandResponse.GetData(); return(GetTransactionResponse(false, responseSetup, responseParameters, responseData, state.MaxBufferSize)); }
internal static SMB1Command GetReadResponse(SMB1Header header, ReadAndXRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(request.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "Read failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, request.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(new ErrorResponse(request.CommandName)); } if (share is FileSystemShare) { if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "Read from '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } uint maxCount = request.MaxCount; if ((share is FileSystemShare) && state.LargeRead) { maxCount = request.MaxCountLarge; } byte[] data; header.Status = share.FileStore.ReadFile(out data, openFile.Handle, (long)request.Offset, (int)maxCount); if (header.Status == NTStatus.STATUS_END_OF_FILE) { // [MS-CIFS] Windows servers set the DataLength field to 0x0000 and return STATUS_SUCCESS. // JCIFS expects the same response. data = new byte[0]; header.Status = NTStatus.STATUS_SUCCESS; } else if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Read from '{0}{1}' failed. NTStatus: {2}. (FID: {3})", share.Name, openFile.Path, header.Status, request.FID); return(new ErrorResponse(request.CommandName)); } ReadAndXResponse response = new ReadAndXResponse(); if (share is FileSystemShare) { // If the client reads from a disk file, this field MUST be set to -1 (0xFFFF) response.Available = 0xFFFF; } response.Data = data; return(response); }
/// <summary> /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request. /// The server MUST respond to the transaction request as a whole. /// </summary> internal static List <SMB1Command> GetTransactionResponse(SMB1Header header, TransactionRequest request, ISMBShare share, SMB1ConnectionState state) { ProcessStateObject processState = state.ObtainProcessState(header.PID); processState.MaxDataCount = request.MaxDataCount; if (request.TransParameters.Length < request.TotalParameterCount || request.TransData.Length < request.TotalDataCount) { // A secondary transaction request is pending processState.Name = request.Name; processState.TransactionSetup = request.Setup; processState.TransactionParameters = new byte[request.TotalParameterCount]; processState.TransactionData = new byte[request.TotalDataCount]; ByteWriter.WriteBytes(processState.TransactionParameters, 0, request.TransParameters); ByteWriter.WriteBytes(processState.TransactionData, 0, request.TransData); processState.TransactionParametersReceived += request.TransParameters.Length; processState.TransactionDataReceived += request.TransData.Length; if (request is Transaction2Request) { return(new Transaction2InterimResponse()); } else { return(new TransactionInterimResponse()); } } else { // We have a complete command if (request is Transaction2Request) { return(GetCompleteTransaction2Response(header, request.Setup, request.TransParameters, request.TransData, share, state)); } else { return(GetCompleteTransactionResponse(header, request.Name, request.Setup, request.TransParameters, request.TransData, share, state)); } } }
internal static TransactionTransactNamedPipeResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, TransactionTransactNamedPipeRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "TransactNamedPipe failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } int maxOutputLength = (int)maxDataCount; byte[] output; header.Status = share.FileStore.DeviceIOControl(openFile.Handle, (uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE, subcommand.WriteData, out output, maxOutputLength); if (header.Status != NTStatus.STATUS_SUCCESS && header.Status != NTStatus.STATUS_BUFFER_OVERFLOW) { state.LogToServer(Severity.Verbose, "TransactNamedPipe failed. NTStatus: {0}.", header.Status); return(null); } TransactionTransactNamedPipeResponse response = new TransactionTransactNamedPipeResponse(); response.ReadData = output; return(response); }
private static NTTransactIOCTLResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, NTTransactIOCTLRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); string ctlCode = Enum.IsDefined(typeof(IoControlCode), subcommand.FunctionCode) ? ((IoControlCode)subcommand.FunctionCode).ToString() : ("0x" + subcommand.FunctionCode.ToString("X8")); if (!subcommand.IsFsctl) { // [MS-SMB] If the IsFsctl field is set to zero, the server SHOULD fail the request with STATUS_NOT_SUPPORTED state.LogToServer(Severity.Verbose, "IOCTL: Non-FSCTL requests are not supported. CTL Code: {0}", ctlCode); header.Status = NTStatus.STATUS_NOT_SUPPORTED; return(null); } OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "IOCTL failed. CTL Code: {0}. Invalid FID. (UID: {1}, TID: {2}, FID: {3})", ctlCode, header.UID, header.TID, subcommand.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } int maxOutputLength = (int)maxDataCount; byte[] output; header.Status = share.FileStore.DeviceIOControl(openFile.Handle, subcommand.FunctionCode, subcommand.Data, out output, maxOutputLength); if (header.Status != NTStatus.STATUS_SUCCESS && header.Status != NTStatus.STATUS_BUFFER_OVERFLOW) { state.LogToServer(Severity.Verbose, "IOCTL failed. CTL Code: {0}. NTStatus: {1}. (FID: {2})", ctlCode, header.Status, subcommand.FID); return(null); } state.LogToServer(Severity.Verbose, "IOCTL succeeded. CTL Code: {0}. (FID: {1})", ctlCode, subcommand.FID); NTTransactIOCTLResponse response = new NTTransactIOCTLResponse(); response.Data = output; return(response); }
internal static void ProcessSubcommand(SMB1Header header, uint timeout, string name, TransactionWaitNamedPipeRequest subcommand, ISMBShare share, SMB1ConnectionState state) { if (!name.StartsWith(@"\PIPE\", StringComparison.OrdinalIgnoreCase)) { // [MS-CIFS] The name field MUST be set to the name of the pipe being waited for, in the format \PIPE\<pipename> state.LogToServer(Severity.Verbose, "TransactWaitNamedPipe failed. Invalid pipe name: {0}.", name); header.Status = NTStatus.STATUS_INVALID_SMB; } string pipeName = name.Substring(6); PipeWaitRequest pipeWaitRequest = new PipeWaitRequest(); pipeWaitRequest.Timeout = timeout; pipeWaitRequest.TimeSpecified = true; pipeWaitRequest.Name = pipeName; byte[] input = pipeWaitRequest.GetBytes(); byte[] output; header.Status = share.FileStore.DeviceIOControl(null, (uint)IoControlCode.FSCTL_PIPE_WAIT, input, out output, 0); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "TransactWaitNamedPipe failed. Pipe name: {0}. NTStatus: {1}.", pipeName, header.Status); } else { state.LogToServer(Severity.Verbose, "TransactWaitNamedPipe succeeded. Pipe name: {0}.", pipeName); } }
/// <summary> /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request. /// </summary> internal static List <SMB1Command> GetNTTransactResponse(SMB1Header header, NTTransactRequest request, ISMBShare share, SMB1ConnectionState state) { if (request.TransParameters.Length < request.TotalParameterCount || request.TransData.Length < request.TotalDataCount) { // A secondary transaction request is pending ProcessStateObject processState = state.CreateProcessState(header.PID); processState.SubcommandID = (ushort)request.Function; processState.MaxParameterCount = request.MaxParameterCount; processState.MaxDataCount = request.MaxDataCount; processState.TransactionSetup = request.Setup; processState.TransactionParameters = new byte[request.TotalParameterCount]; processState.TransactionData = new byte[request.TotalDataCount]; ByteWriter.WriteBytes(processState.TransactionParameters, 0, request.TransParameters); ByteWriter.WriteBytes(processState.TransactionData, 0, request.TransData); processState.TransactionParametersReceived += request.TransParameters.Length; processState.TransactionDataReceived += request.TransData.Length; return(new NTTransactInterimResponse()); } else { // We have a complete command return(GetCompleteNTTransactResponse(header, request.MaxParameterCount, request.MaxDataCount, request.Function, request.Setup, request.TransParameters, request.TransData, share, state)); } }
internal static List <SMB1Command> GetLockingAndXResponse(SMB1Header header, LockingAndXRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(request.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "Locking failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, request.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(new ErrorResponse(request.CommandName)); } if ((request.TypeOfLock & LockType.CHANGE_LOCKTYPE) > 0) { // [MS-CIFS] Windows NT Server does not support the CHANGE_LOCKTYPE flag of TypeOfLock. state.LogToServer(Severity.Verbose, "Locking failed. CHANGE_LOCKTYPE is not supported."); header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; return(new ErrorResponse(request.CommandName)); } if (request.Unlocks.Count == 0 && request.Locks.Count == 0) { // [MS-CIFS] If NumberOfRequestedUnlocks and NumberOfRequestedLocks are both zero [..] the server MUST NOT send an SMB_COM_LOCKING_ANDX Response. return(new List <SMB1Command>()); } // [MS-CIFS] If the CANCEL_LOCK bit is set, Windows NT servers cancel only the first lock request range listed in the lock array. for (int lockIndex = 0; lockIndex < request.Unlocks.Count; lockIndex++) { LockingRange lockingRange = request.Unlocks[lockIndex]; header.Status = share.FileStore.UnlockFile(openFile.Handle, (long)lockingRange.ByteOffset, (long)lockingRange.LengthInBytes); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Locking: Unlocking '{0}{1}' failed. Offset: {2}, Length: {3}. NTStatus: {4}.", share.Name, openFile.Path, lockingRange.ByteOffset, lockingRange.LengthInBytes, header.Status); return(new ErrorResponse(request.CommandName)); } state.LogToServer(Severity.Verbose, "Locking: Unlocking '{0}{1}' succeeded. Offset: {2}, Length: {3}.", share.Name, openFile.Path, lockingRange.ByteOffset, lockingRange.LengthInBytes); } for (int lockIndex = 0; lockIndex < request.Locks.Count; lockIndex++) { LockingRange lockingRange = request.Locks[lockIndex]; bool exclusiveLock = (request.TypeOfLock & LockType.SHARED_LOCK) == 0; header.Status = share.FileStore.LockFile(openFile.Handle, (long)lockingRange.ByteOffset, (long)lockingRange.LengthInBytes, exclusiveLock); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Locking: Locking '{0}{1}' failed. Offset: {2}, Length: {3}. NTStatus: {4}.", share.Name, openFile.Path, lockingRange.ByteOffset, lockingRange.LengthInBytes, header.Status); // [MS-CIFS] This client request is atomic. If the area to be locked is already locked or the // lock request otherwise fails, no other ranges specified in the client request are locked. for (int index = 0; index < lockIndex; index++) { share.FileStore.UnlockFile(openFile.Handle, (long)request.Locks[index].ByteOffset, (long)request.Locks[index].LengthInBytes); } return(new ErrorResponse(request.CommandName)); } state.LogToServer(Severity.Verbose, "Locking: Locking '{0}{1}' succeeded. Offset: {2}, Length: {3}.", share.Name, openFile.Path, lockingRange.ByteOffset, lockingRange.LengthInBytes); } return(new LockingAndXResponse()); }
/// <summary> /// There are no secondary response messages. /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request. /// </summary> internal static List <SMB1Command> GetNTTransactResponse(SMB1Header header, NTTransactSecondaryRequest request, ISMBShare share, SMB1ConnectionState state) { ProcessStateObject processState = state.GetProcessState(header.PID); if (processState == null) { throw new InvalidDataException(); } ByteWriter.WriteBytes(processState.TransactionParameters, (int)request.ParameterDisplacement, request.TransParameters); ByteWriter.WriteBytes(processState.TransactionData, (int)request.DataDisplacement, request.TransData); processState.TransactionParametersReceived += request.TransParameters.Length; processState.TransactionDataReceived += request.TransData.Length; if (processState.TransactionParametersReceived < processState.TransactionParameters.Length || processState.TransactionDataReceived < processState.TransactionData.Length) { return(new List <SMB1Command>()); } else { // We have a complete command state.RemoveProcessState(header.PID); return(GetCompleteNTTransactResponse(header, processState.MaxParameterCount, processState.MaxDataCount, (NTTransactSubcommandName)processState.SubcommandID, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state)); } }
internal static SMB1Command GetCloseResponse(SMB1Header header, CloseRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(request.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "Close failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, request.FID); header.Status = NTStatus.STATUS_SMB_BAD_FID; return(new ErrorResponse(request.CommandName)); } header.Status = share.FileStore.CloseFile(openFile.Handle); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Information, "Close: Closing '{0}{1}' failed. NTStatus: {2}. (UID: {3}, TID: {4}, FID: {5})", share.Name, openFile.Path, header.Status, header.UID, header.TID, request.FID); return(new ErrorResponse(request.CommandName)); } state.LogToServer(Severity.Information, "Close: Closed '{0}{1}'. (UID: {2}, TID: {3}, FID: {4})", share.Name, openFile.Path, header.UID, header.TID, request.FID); session.RemoveOpenFile(request.FID); return(new CloseResponse()); }
internal static SMB1Command GetNTCreateResponse(SMB1Header header, NTCreateAndXRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); bool isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0; string path = request.FileName; FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition); if (share is FileSystemShare) { if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess)) { state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.FileName, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } object handle; FileStatus fileStatus; NTStatus createStatus = share.FileStore.CreateFile(out handle, out fileStatus, path, request.DesiredAccess, request.ShareAccess, request.CreateDisposition, request.CreateOptions, session.SecurityContext); if (createStatus != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. NTStatus: '{2}'.", share.Name, path, createStatus); header.Status = createStatus; return(new ErrorResponse(request.CommandName)); } state.LogToServer(Severity.Verbose, "Create: Opened '{0}{1}'.", share.Name, path); ushort?fileID = session.AddOpenFile(header.TID, path, handle); if (!fileID.HasValue) { share.FileStore.CloseFile(handle); header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES; return(new ErrorResponse(request.CommandName)); } if (share is NamedPipeShare) { if (isExtended) { return(CreateResponseExtendedForNamedPipe(fileID.Value, FileStatus.FILE_OPENED)); } else { return(CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED)); } } else // FileSystemShare { FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle); if (isExtended) { NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileInformation(fileInfo, fileID.Value, fileStatus); if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0) { response.OpLockLevel = OpLockLevel.BatchOpLockGranted; } return(response); } else { NTCreateAndXResponse response = CreateResponseFromFileInformation(fileInfo, fileID.Value, fileStatus); if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0) { response.OpLockLevel = OpLockLevel.BatchOpLockGranted; } return(response); } } }
internal static SMB1Command GetFindClose2Response(SMB1Header header, FindClose2Request request, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); session.RemoveOpenSearch(request.SearchHandle); return(new FindClose2Response()); }
internal static SMB1Command GetOpenAndXResponse(SMB1Header header, OpenAndXRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); bool isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0; string path = request.FileName; if (!path.StartsWith(@"\")) { path = @"\" + path; } AccessMask desiredAccess; ShareAccess shareAccess; CreateDisposition createDisposition; try { desiredAccess = ToAccessMask(request.AccessMode.AccessMode); shareAccess = ToShareAccess(request.AccessMode.SharingMode); createDisposition = ToCreateDisposition(request.OpenMode); } catch (ArgumentException) { // Invalid input according to MS-CIFS header.Status = NTStatus.STATUS_OS2_INVALID_ACCESS; return(new ErrorResponse(request.CommandName)); } CreateOptions createOptions = ToCreateOptions(request.AccessMode); FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(desiredAccess, createDisposition); if (share is FileSystemShare) { if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess)) { state.LogToServer(Severity.Verbose, "OpenAndX: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.FileName, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } object handle; FileStatus fileStatus; header.Status = share.FileStore.CreateFile(out handle, out fileStatus, path, desiredAccess, 0, shareAccess, createDisposition, createOptions, session.SecurityContext); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "OpenAndX: Opening '{0}{1}' failed. NTStatus: {2}.", share.Name, path, header.Status); return(new ErrorResponse(request.CommandName)); } FileAccess fileAccess = ToFileAccess(request.AccessMode.AccessMode); ushort? fileID = session.AddOpenFile(header.TID, share.Name, path, handle, fileAccess); if (!fileID.HasValue) { share.FileStore.CloseFile(handle); state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. Too many open files.", share.Name, path); header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES; return(new ErrorResponse(request.CommandName)); } state.LogToServer(Severity.Verbose, "OpenAndX: Opened '{0}{1}'. (UID: {2}, TID: {3}, FID: {4})", share.Name, path, header.UID, header.TID, fileID.Value); OpenResult openResult = ToOpenResult(fileStatus); if (share is NamedPipeShare) { if (isExtended) { return(CreateResponseExtendedForNamedPipe(fileID.Value, openResult)); } else { return(CreateResponseForNamedPipe(fileID.Value, openResult)); } } else // FileSystemShare { FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle); if (isExtended) { return(CreateResponseExtendedFromFileInfo(fileInfo, fileID.Value, openResult)); } else { return(CreateResponseFromFileInfo(fileInfo, fileID.Value, openResult)); } } }
internal static Transaction2SetFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2SetFileInformationRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "SetFileInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } if (share is FileSystemShare) { if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } } if (subcommand.IsPassthroughInformationLevel) { FileInformation fileInfo; try { fileInfo = FileInformation.GetFileInformation(subcommand.InformationBytes, 0, subcommand.FileInformationClass); } catch (UnsupportedInformationLevelException) { state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_OS2_INVALID_LEVEL.", share.Name, openFile.Path, subcommand.FileInformationClass); header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL; return(null); } catch (Exception) { state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path, subcommand.FileInformationClass); header.Status = NTStatus.STATUS_INVALID_PARAMETER; return(null); } NTStatus status = share.FileStore.SetFileInformation(openFile.Handle, fileInfo); if (status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.FileInformationClass, status, subcommand.FID); header.Status = status; return(null); } state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information class: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.FileInformationClass, subcommand.FID); } else { SetInformation information; try { information = SetInformation.GetSetInformation(subcommand.InformationBytes, subcommand.SetInformationLevel); } catch (UnsupportedInformationLevelException) { state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: STATUS_OS2_INVALID_LEVEL.", share.Name, openFile.Path, subcommand.SetInformationLevel); header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL; return(null); } catch (Exception) { state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path, subcommand.SetInformationLevel); header.Status = NTStatus.STATUS_INVALID_PARAMETER; return(null); } NTStatus status = SMB1FileStoreHelper.SetFileInformation(share.FileStore, openFile.Handle, information); if (status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SetInformationLevel, status, subcommand.FID); header.Status = status; return(null); } state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information level: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.SetInformationLevel, subcommand.FID); } Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse(); return(response); }