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); }
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) { 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, request.WriteOffsetInBytes, 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)); } WriteResponse response = new WriteResponse(); response.CountOfBytesWritten = (ushort)numberOfBytesWritten; 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) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } 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) { return(new ErrorResponse(request.CommandName)); } ReadResponse response = new ReadResponse(); response.Bytes = data; response.CountOfBytesReturned = (ushort)data.Length; return(response); }
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); } }
internal static Transaction2QueryFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFileInformationRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); if (openFile == null) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } if (share is FileSystemShare) { if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "QueryFileInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } } Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse(); QueryInformation queryInformation; NTStatus queryStatus = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, openFile.Handle, subcommand.InformationLevel); if (queryStatus != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}", share.Name, openFile.Path, subcommand.InformationLevel, queryStatus); header.Status = queryStatus; return(null); } state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information level: {2}", share.Name, openFile.Path, subcommand.InformationLevel); response.SetQueryInformation(queryInformation); return(response); }
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()); }
internal static SMB1Command GetSetInformation2Response(SMB1Header header, SetInformation2Request request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(request.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "Set Information 2 failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, request.FID); header.Status = NTStatus.STATUS_SMB_BAD_FID; return(new ErrorResponse(request.CommandName)); } if (share is FileSystemShare) { if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "Set Information 2 on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } header.Status = SMB1FileStoreHelper.SetInformation2(share.FileStore, openFile.Handle, request.CreationDateTime, request.LastAccessDateTime, request.LastWriteDateTime); if (header.Status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Set Information 2 on '{0}{1}' failed. NTStatus: {2}", share.Name, openFile.Path, header.Status); return(new ErrorResponse(request.CommandName)); } state.LogToServer(Severity.Verbose, "Set Information 2 on '{0}{1}' succeeded.", share.Name, openFile.Path); return(new SetInformation2Response()); }
internal static SMB1Command 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 Transaction2QueryFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFileInformationRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); if (openFile == null) { state.LogToServer(Severity.Verbose, "QueryFileInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID); header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } if (share is FileSystemShare) { if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "QueryFileInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } } Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse(); if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass != FileInformationClass.FileAllInformation) { FileInformation fileInfo; NTStatus status = share.FileStore.GetFileInformation(out fileInfo, openFile.Handle, subcommand.FileInformationClass); if (status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.FileInformationClass, status, subcommand.FID); header.Status = status; return(null); } state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information class: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.FileInformationClass, subcommand.FID); response.SetFileInformation(fileInfo); } else { // The FILE_ALL_INFORMATION structure described in [MS-FSCC], is NOT used by [MS-SMB] if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass == FileInformationClass.FileAllInformation) { subcommand.QueryInformationLevel = QueryInformationLevel.SMB_QUERY_FILE_ALL_INFO; } QueryInformation queryInformation; NTStatus status = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, openFile.Handle, subcommand.QueryInformationLevel); if (status != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.QueryInformationLevel, status, subcommand.FID); header.Status = status; return(null); } state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information level: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.QueryInformationLevel, subcommand.FID); response.SetQueryInformation(queryInformation); } return(response); }
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); }
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) { 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); } } SetInformation information; try { information = SetInformation.GetSetInformation(subcommand.InformationBytes, subcommand.InformationLevel); } catch (UnsupportedInformationLevelException) { state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: STATUS_OS2_INVALID_LEVEL", share.Name, openFile.Path, subcommand.InformationLevel); 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.InformationLevel); 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}", share.Name, openFile.Path, subcommand.InformationLevel, status); header.Status = status; return(null); } state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information level: {2}", share.Name, openFile.Path, subcommand.InformationLevel); Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse(); return(response); }
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 void ProcessNTCancelRequest(SMB1Header header, NTCancelRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); SMB1AsyncContext context = state.GetAsyncContext(header.UID, header.TID, header.PID, header.MID); if (context != null) { NTStatus status = share.FileStore.Cancel(context.IORequest); OpenFileObject openFile = session.GetOpenFileObject(context.FileID); if (openFile != null) { state.LogToServer(Severity.Information, "Cancel: Requested cancel on '{0}{1}', NTStatus: {2}. PID: {3}. MID: {4}.", share.Name, openFile.Path, status, context.PID, context.MID); } if (status == NTStatus.STATUS_SUCCESS || status == NTStatus.STATUS_CANCELLED) { state.RemoveAsyncContext(context); } } }
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) { header.Status = NTStatus.STATUS_SMB_BAD_FID; return(new ErrorResponse(request.CommandName)); } state.LogToServer(Severity.Information, "Close: Closing '{0}{1}'", share.Name, openFile.Path); header.Status = share.FileStore.CloseFile(openFile.Handle); if (header.Status != NTStatus.STATUS_SUCCESS) { return(new ErrorResponse(request.CommandName)); } session.RemoveOpenFile(request.FID); return(new CloseResponse()); }
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; } } }
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 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) { 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, "WriteAndX 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) { 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 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()); }
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 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 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); } } } }