OpenAndXHelper.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Text;
  11. using SMBLibrary.Services;
  12. using SMBLibrary.SMB1;
  13. using Utilities;
  14. namespace SMBLibrary.Server.SMB1
  15. {
  16. public class OpenAndXHelper
  17. {
  18. internal static SMB1Command GetOpenAndXResponse(SMB1Header header, OpenAndXRequest request, ISMBShare share, SMB1ConnectionState state)
  19. {
  20. SMB1Session session = state.GetSession(header.UID);
  21. bool isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0;
  22. string path = request.FileName;
  23. FileAccess fileAccess = ToFileAccess(request.AccessMode.AccessMode);
  24. if (share is FileSystemShare)
  25. {
  26. if (!((FileSystemShare)share).HasAccess(session.UserName, path, fileAccess, state.ClientEndPoint))
  27. {
  28. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  29. return new ErrorResponse(request.CommandName);
  30. }
  31. }
  32. if (share is NamedPipeShare)
  33. {
  34. Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
  35. if (pipeStream != null)
  36. {
  37. ushort? fileID = session.AddOpenFile(path, pipeStream);
  38. if (!fileID.HasValue)
  39. {
  40. header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
  41. return new ErrorResponse(request.CommandName);
  42. }
  43. if (isExtended)
  44. {
  45. return CreateResponseExtendedForNamedPipe(fileID.Value);
  46. }
  47. else
  48. {
  49. return CreateResponseForNamedPipe(fileID.Value);
  50. }
  51. }
  52. header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
  53. return new ErrorResponse(request.CommandName);
  54. }
  55. else // FileSystemShare
  56. {
  57. FileSystemShare fileSystemShare = (FileSystemShare)share;
  58. IFileSystem fileSystem = fileSystemShare.FileSystem;
  59. OpenResult openResult;
  60. FileSystemEntry entry = fileSystem.GetEntry(path);
  61. if (entry != null)
  62. {
  63. if (request.OpenMode.FileExistsOpts == FileExistsOpts.ReturnError)
  64. {
  65. header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
  66. return new ErrorResponse(request.CommandName);
  67. }
  68. else if (request.OpenMode.FileExistsOpts == FileExistsOpts.TruncateToZero)
  69. {
  70. try
  71. {
  72. Stream temp = fileSystem.OpenFile(path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite);
  73. temp.Close();
  74. }
  75. catch (IOException ex)
  76. {
  77. ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
  78. if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
  79. {
  80. header.Status = NTStatus.STATUS_SHARING_VIOLATION;
  81. return new ErrorResponse(request.CommandName);
  82. }
  83. else
  84. {
  85. header.Status = NTStatus.STATUS_DATA_ERROR;
  86. return new ErrorResponse(request.CommandName);
  87. }
  88. }
  89. catch (UnauthorizedAccessException)
  90. {
  91. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  92. return new ErrorResponse(request.CommandName);
  93. }
  94. openResult = OpenResult.FileExistedAndWasTruncated;
  95. }
  96. else // FileExistsOpts.Append
  97. {
  98. openResult = OpenResult.FileExistedAndWasOpened;
  99. }
  100. }
  101. else
  102. {
  103. if (request.OpenMode.CreateFile == CreateFile.ReturnErrorIfNotExist)
  104. {
  105. header.Status = NTStatus.STATUS_NO_SUCH_FILE;
  106. return new ErrorResponse(request.CommandName);
  107. }
  108. if ((request.FileAttrs & SMBFileAttributes.Directory) > 0)
  109. {
  110. state.LogToServer(Severity.Information, "OpenAndX: Creating directory '{0}'", path);
  111. entry = fileSystem.CreateDirectory(path);
  112. }
  113. else
  114. {
  115. state.LogToServer(Severity.Information, "OpenAndX: Creating file '{0}'", path);
  116. entry = fileSystem.CreateFile(path);
  117. }
  118. openResult = OpenResult.NotExistedAndWasCreated;
  119. }
  120. FileShare fileShare = ToFileShare(request.AccessMode.SharingMode);
  121. Stream stream = null;
  122. if (!entry.IsDirectory)
  123. {
  124. bool buffered = (request.AccessMode.CachedMode == CachedMode.CachingAllowed && request.AccessMode.WriteThroughMode == WriteThroughMode.Disabled);
  125. state.LogToServer(Severity.Verbose, "OpenAndX: Opening '{0}', Access={1}, Share={2}, Buffered={3}", path, fileAccess, fileShare, buffered);
  126. stream = fileSystem.OpenFile(path, FileMode.Open, fileAccess, fileShare);
  127. if (buffered)
  128. {
  129. stream = new PrefetchedStream(stream);
  130. }
  131. }
  132. ushort? fileID = session.AddOpenFile(path, stream);
  133. if (!fileID.HasValue)
  134. {
  135. header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
  136. return new ErrorResponse(request.CommandName);
  137. }
  138. if (isExtended)
  139. {
  140. return CreateResponseExtendedFromFileSystemEntry(entry, fileID.Value, openResult);
  141. }
  142. else
  143. {
  144. return CreateResponseFromFileSystemEntry(entry, fileID.Value, openResult);
  145. }
  146. }
  147. }
  148. private static FileAccess ToFileAccess(AccessMode accessMode)
  149. {
  150. if (accessMode == AccessMode.Write)
  151. {
  152. return FileAccess.Write;
  153. }
  154. else if (accessMode == AccessMode.ReadWrite)
  155. {
  156. return FileAccess.ReadWrite;
  157. }
  158. else
  159. {
  160. return FileAccess.Read;
  161. }
  162. }
  163. private static FileShare ToFileShare(SharingMode sharingMode)
  164. {
  165. if (sharingMode == SharingMode.DenyReadWriteExecute)
  166. {
  167. return FileShare.None;
  168. }
  169. else if (sharingMode == SharingMode.DenyWrite)
  170. {
  171. return FileShare.Read;
  172. }
  173. else if (sharingMode == SharingMode.DenyReadExecute)
  174. {
  175. return FileShare.Write;
  176. }
  177. else
  178. {
  179. return FileShare.ReadWrite;
  180. }
  181. }
  182. private static OpenAndXResponse CreateResponseForNamedPipe(ushort fileID)
  183. {
  184. OpenAndXResponse response = new OpenAndXResponse();
  185. response.FID = fileID;
  186. response.AccessRights = AccessRights.SMB_DA_ACCESS_READ_WRITE;
  187. response.ResourceType = ResourceType.FileTypeMessageModePipe;
  188. response.NMPipeStatus.ICount = 255;
  189. response.NMPipeStatus.ReadMode = ReadMode.MessageMode;
  190. response.NMPipeStatus.NamedPipeType = NamedPipeType.MessageNodePipe;
  191. return response;
  192. }
  193. private static OpenAndXResponseExtended CreateResponseExtendedForNamedPipe(ushort fileID)
  194. {
  195. OpenAndXResponseExtended response = new OpenAndXResponseExtended();
  196. response.FID = fileID;
  197. response.AccessRights = AccessRights.SMB_DA_ACCESS_READ_WRITE;
  198. response.ResourceType = ResourceType.FileTypeMessageModePipe;
  199. response.NMPipeStatus.ICount = 255;
  200. response.NMPipeStatus.ReadMode = ReadMode.MessageMode;
  201. response.NMPipeStatus.NamedPipeType = NamedPipeType.MessageNodePipe;
  202. return response;
  203. }
  204. private static OpenAndXResponse CreateResponseFromFileSystemEntry(FileSystemEntry entry, ushort fileID, OpenResult openResult)
  205. {
  206. OpenAndXResponse response = new OpenAndXResponse();
  207. if (entry.IsDirectory)
  208. {
  209. response.FileAttrs = SMBFileAttributes.Directory;
  210. }
  211. else
  212. {
  213. response.FileAttrs = SMBFileAttributes.Normal;
  214. }
  215. response.FID = fileID;
  216. response.LastWriteTime = entry.LastWriteTime;
  217. response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
  218. response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
  219. response.ResourceType = ResourceType.FileTypeDisk;
  220. response.OpenResults.OpenResult = openResult;
  221. return response;
  222. }
  223. private static OpenAndXResponseExtended CreateResponseExtendedFromFileSystemEntry(FileSystemEntry entry, ushort fileID, OpenResult openResult)
  224. {
  225. OpenAndXResponseExtended response = new OpenAndXResponseExtended();
  226. if (entry.IsDirectory)
  227. {
  228. response.FileAttrs = SMBFileAttributes.Directory;
  229. }
  230. else
  231. {
  232. response.FileAttrs = SMBFileAttributes.Normal;
  233. }
  234. response.FID = fileID;
  235. response.LastWriteTime = entry.LastWriteTime;
  236. response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
  237. response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
  238. response.ResourceType = ResourceType.FileTypeDisk;
  239. response.OpenResults.OpenResult = openResult;
  240. response.MaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_APPEND_DATA |
  241. FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA |
  242. FileAccessMask.FILE_EXECUTE |
  243. FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES |
  244. FileAccessMask.DELETE | FileAccessMask.READ_CONTROL | FileAccessMask.WRITE_DAC | FileAccessMask.WRITE_OWNER | FileAccessMask.SYNCHRONIZE;
  245. response.GuestMaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA |
  246. FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA |
  247. FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES |
  248. FileAccessMask.READ_CONTROL | FileAccessMask.SYNCHRONIZE;
  249. return response;
  250. }
  251. }
  252. }