NTCreateHelper.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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 NTCreateHelper
  17. {
  18. internal static SMB1Command GetNTCreateResponse(SMB1Header header, NTCreateAndXRequest request, ISMBShare share, SMB1ConnectionState state)
  19. {
  20. SMB1Session session = state.GetSession(header.UID);
  21. bool isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0;
  22. string path = request.FileName;
  23. if (share is NamedPipeShare)
  24. {
  25. Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
  26. if (pipeStream != null)
  27. {
  28. ushort? fileID = session.AddOpenFile(path, pipeStream);
  29. if (!fileID.HasValue)
  30. {
  31. header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
  32. return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
  33. }
  34. if (isExtended)
  35. {
  36. return CreateResponseExtendedForNamedPipe(fileID.Value);
  37. }
  38. else
  39. {
  40. return CreateResponseForNamedPipe(fileID.Value);
  41. }
  42. }
  43. header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
  44. return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
  45. }
  46. else // FileSystemShare
  47. {
  48. FileSystemShare fileSystemShare = (FileSystemShare)share;
  49. string userName = session.UserName;
  50. FileSystemEntry entry;
  51. NTStatus createStatus = NTFileSystemHelper.CreateFile(out entry, fileSystemShare, userName, path, request.CreateDisposition, request.CreateOptions, request.DesiredAccess, state);
  52. if (createStatus != NTStatus.STATUS_SUCCESS)
  53. {
  54. header.Status = createStatus;
  55. return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
  56. }
  57. FileAccess fileAccess = NTFileSystemHelper.ToFileAccess(request.DesiredAccess);
  58. Stream stream;
  59. bool deleteOnClose = false;
  60. if (fileAccess == (FileAccess)0 || entry.IsDirectory)
  61. {
  62. stream = null;
  63. }
  64. else
  65. {
  66. IFileSystem fileSystem = fileSystemShare.FileSystem;
  67. // When FILE_OPEN_REPARSE_POINT is specified, the operation should continue normally if the file is not a reparse point.
  68. // FILE_OPEN_REPARSE_POINT is a hint that the caller does not intend to actually read the file, with the exception
  69. // of a file copy operation (where the caller will attempt to simply copy the reparse point).
  70. deleteOnClose = (request.CreateOptions & CreateOptions.FILE_DELETE_ON_CLOSE) > 0;
  71. bool openReparsePoint = (request.CreateOptions & CreateOptions.FILE_OPEN_REPARSE_POINT) > 0;
  72. bool disableBuffering = (request.CreateOptions & CreateOptions.FILE_NO_INTERMEDIATE_BUFFERING) > 0;
  73. bool buffered = (request.CreateOptions & CreateOptions.FILE_SEQUENTIAL_ONLY) > 0 && !disableBuffering && !openReparsePoint;
  74. NTStatus openStatus = NTFileSystemHelper.OpenFile(out stream, fileSystem, path, fileAccess, request.ShareAccess, buffered, state);
  75. if (openStatus != NTStatus.STATUS_SUCCESS)
  76. {
  77. header.Status = openStatus;
  78. return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
  79. }
  80. }
  81. ushort? fileID = session.AddOpenFile(path, stream, deleteOnClose);
  82. if (!fileID.HasValue)
  83. {
  84. header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
  85. return new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX);
  86. }
  87. if (isExtended)
  88. {
  89. NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileSystemEntry(entry, fileID.Value);
  90. if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
  91. {
  92. response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
  93. }
  94. return response;
  95. }
  96. else
  97. {
  98. NTCreateAndXResponse response = CreateResponseFromFileSystemEntry(entry, fileID.Value);
  99. if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
  100. {
  101. response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
  102. }
  103. return response;
  104. }
  105. }
  106. }
  107. private static NTCreateAndXResponse CreateResponseForNamedPipe(ushort fileID)
  108. {
  109. NTCreateAndXResponse response = new NTCreateAndXResponse();
  110. response.FID = fileID;
  111. response.CreateDisposition = CreateDisposition.FILE_OPEN;
  112. response.ExtFileAttributes = ExtendedFileAttributes.Normal;
  113. response.ResourceType = ResourceType.FileTypeMessageModePipe;
  114. response.NMPipeStatus.ICount = 255;
  115. response.NMPipeStatus.ReadMode = ReadMode.MessageMode;
  116. response.NMPipeStatus.NamedPipeType = NamedPipeType.MessageNodePipe;
  117. return response;
  118. }
  119. private static NTCreateAndXResponseExtended CreateResponseExtendedForNamedPipe(ushort fileID)
  120. {
  121. NTCreateAndXResponseExtended response = new NTCreateAndXResponseExtended();
  122. response.FID = fileID;
  123. response.CreateDisposition = CreateDisposition.FILE_OPEN;
  124. response.ExtFileAttributes = ExtendedFileAttributes.Normal;
  125. response.ResourceType = ResourceType.FileTypeMessageModePipe;
  126. NamedPipeStatus status = new NamedPipeStatus();
  127. status.ICount = 255;
  128. status.ReadMode = ReadMode.MessageMode;
  129. status.NamedPipeType = NamedPipeType.MessageNodePipe;
  130. response.NMPipeStatus = status;
  131. response.MaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_APPEND_DATA |
  132. FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA |
  133. FileAccessMask.FILE_EXECUTE |
  134. FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES |
  135. FileAccessMask.DELETE | FileAccessMask.READ_CONTROL | FileAccessMask.WRITE_DAC | FileAccessMask.WRITE_OWNER | FileAccessMask.SYNCHRONIZE;
  136. response.GuestMaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA |
  137. FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA |
  138. FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES |
  139. FileAccessMask.READ_CONTROL | FileAccessMask.SYNCHRONIZE;
  140. return response;
  141. }
  142. private static NTCreateAndXResponse CreateResponseFromFileSystemEntry(FileSystemEntry entry, ushort fileID)
  143. {
  144. NTCreateAndXResponse response = new NTCreateAndXResponse();
  145. if (entry.IsDirectory)
  146. {
  147. response.ExtFileAttributes = ExtendedFileAttributes.Directory;
  148. response.Directory = true;
  149. }
  150. else
  151. {
  152. response.ExtFileAttributes = ExtendedFileAttributes.Normal;
  153. }
  154. response.FID = fileID;
  155. response.CreateDisposition = CreateDisposition.FILE_OPEN;
  156. response.AllocationSize = NTFileSystemHelper.GetAllocationSize(entry.Size);
  157. response.EndOfFile = entry.Size;
  158. response.CreateTime = entry.CreationTime;
  159. response.LastAccessTime = entry.LastAccessTime;
  160. response.LastWriteTime = entry.LastWriteTime;
  161. response.LastChangeTime = entry.LastWriteTime;
  162. response.ResourceType = ResourceType.FileTypeDisk;
  163. return response;
  164. }
  165. private static NTCreateAndXResponseExtended CreateResponseExtendedFromFileSystemEntry(FileSystemEntry entry, ushort fileID)
  166. {
  167. NTCreateAndXResponseExtended response = new NTCreateAndXResponseExtended();
  168. if (entry.IsDirectory)
  169. {
  170. response.ExtFileAttributes = ExtendedFileAttributes.Directory;
  171. response.Directory = true;
  172. }
  173. else
  174. {
  175. response.ExtFileAttributes = ExtendedFileAttributes.Normal;
  176. }
  177. response.FID = fileID;
  178. response.CreateTime = entry.CreationTime;
  179. response.LastAccessTime = entry.LastAccessTime;
  180. response.LastWriteTime = entry.LastWriteTime;
  181. response.LastChangeTime = entry.LastWriteTime;
  182. response.CreateDisposition = CreateDisposition.FILE_OPEN;
  183. response.AllocationSize = NTFileSystemHelper.GetAllocationSize(entry.Size);
  184. response.EndOfFile = entry.Size;
  185. response.ResourceType = ResourceType.FileTypeDisk;
  186. response.FileStatus = FileStatus.NO_EAS | FileStatus.NO_SUBSTREAMS | FileStatus.NO_REPARSETAG;
  187. response.MaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_APPEND_DATA |
  188. FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA |
  189. FileAccessMask.FILE_EXECUTE |
  190. FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES |
  191. FileAccessMask.DELETE | FileAccessMask.READ_CONTROL | FileAccessMask.WRITE_DAC | FileAccessMask.WRITE_OWNER | FileAccessMask.SYNCHRONIZE;
  192. response.GuestMaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA |
  193. FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA |
  194. FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES |
  195. FileAccessMask.READ_CONTROL | FileAccessMask.SYNCHRONIZE;
  196. return response;
  197. }
  198. }
  199. }