FileSystemResponseHelper.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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.SMB1;
  12. using Utilities;
  13. namespace SMBLibrary.Server.SMB1
  14. {
  15. public class FileSystemResponseHelper
  16. {
  17. internal static SMB1Command GetCreateDirectoryResponse(SMB1Header header, CreateDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
  18. {
  19. SMB1Session session = state.GetSession(header.UID);
  20. if (!share.HasWriteAccess(session.UserName, request.DirectoryName, state.ClientEndPoint))
  21. {
  22. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  23. return new ErrorResponse(request.CommandName);
  24. }
  25. IFileSystem fileSystem = share.FileSystem;
  26. try
  27. {
  28. fileSystem.CreateDirectory(request.DirectoryName);
  29. }
  30. catch (IOException)
  31. {
  32. state.LogToServer(Severity.Debug, "CreateDirectory: Cannot create '{0}'", request.DirectoryName);
  33. header.Status = NTStatus.STATUS_OBJECT_NAME_INVALID;
  34. return new ErrorResponse(request.CommandName);
  35. }
  36. catch (UnauthorizedAccessException)
  37. {
  38. state.LogToServer(Severity.Debug, "CreateDirectory: Cannot create '{0}', Access Denied", request.DirectoryName);
  39. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  40. return new ErrorResponse(request.CommandName);
  41. }
  42. return new CreateDirectoryResponse();
  43. }
  44. internal static SMB1Command GetDeleteDirectoryResponse(SMB1Header header, DeleteDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
  45. {
  46. SMB1Session session = state.GetSession(header.UID);
  47. if (!share.HasWriteAccess(session.UserName, request.DirectoryName, state.ClientEndPoint))
  48. {
  49. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  50. return new ErrorResponse(request.CommandName);
  51. }
  52. IFileSystem fileSystem = share.FileSystem;
  53. FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName);
  54. if (entry == null)
  55. {
  56. header.Status = NTStatus.STATUS_NO_SUCH_FILE;
  57. return new ErrorResponse(request.CommandName);
  58. }
  59. if (!entry.IsDirectory)
  60. {
  61. header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
  62. return new ErrorResponse(request.CommandName);
  63. }
  64. try
  65. {
  66. fileSystem.Delete(request.DirectoryName);
  67. return new DeleteDirectoryResponse();
  68. }
  69. catch (IOException)
  70. {
  71. state.LogToServer(Severity.Debug, "DeleteDirectory: Cannot delete '{0}'", request.DirectoryName);
  72. header.Status = NTStatus.STATUS_CANNOT_DELETE;
  73. return new ErrorResponse(request.CommandName);
  74. }
  75. catch (UnauthorizedAccessException)
  76. {
  77. state.LogToServer(Severity.Debug, "DeleteDirectory: Cannot delete '{0}', Access Denied", request.DirectoryName);
  78. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  79. return new ErrorResponse(request.CommandName);
  80. }
  81. }
  82. internal static SMB1Command GetCheckDirectoryResponse(SMB1Header header, CheckDirectoryRequest request, FileSystemShare share)
  83. {
  84. IFileSystem fileSystem = share.FileSystem;
  85. FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName);
  86. if (entry == null || !entry.IsDirectory)
  87. {
  88. header.Status = NTStatus.STATUS_NO_SUCH_FILE;
  89. return new ErrorResponse(request.CommandName);
  90. }
  91. return new CheckDirectoryResponse();
  92. }
  93. internal static SMB1Command GetDeleteResponse(SMB1Header header, DeleteRequest request, FileSystemShare share, SMB1ConnectionState state)
  94. {
  95. SMB1Session session = state.GetSession(header.UID);
  96. if (!share.HasWriteAccess(session.UserName, request.FileName, state.ClientEndPoint))
  97. {
  98. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  99. return new ErrorResponse(request.CommandName);
  100. }
  101. IFileSystem fileSystem = share.FileSystem;
  102. FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
  103. if (entry == null)
  104. {
  105. header.Status = NTStatus.STATUS_NO_SUCH_FILE;
  106. return new ErrorResponse(request.CommandName);
  107. }
  108. if (!entry.IsDirectory && (request.SearchAttributes & SMBFileAttributes.Directory) > 0
  109. || entry.IsDirectory && (request.SearchAttributes & SMBFileAttributes.Directory) == 0)
  110. {
  111. header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
  112. return new ErrorResponse(request.CommandName);
  113. }
  114. try
  115. {
  116. fileSystem.Delete(request.FileName);
  117. return new DeleteResponse();
  118. }
  119. catch (IOException)
  120. {
  121. state.LogToServer(Severity.Debug, "Delete: Cannot delete '{0}'", request.FileName);
  122. header.Status = NTStatus.STATUS_CANNOT_DELETE;
  123. return new ErrorResponse(request.CommandName);
  124. }
  125. catch (UnauthorizedAccessException)
  126. {
  127. state.LogToServer(Severity.Debug, "DeleteDirectory: Cannot delete '{0}', Access Denied", request.FileName);
  128. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  129. return new ErrorResponse(request.CommandName);
  130. }
  131. }
  132. internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, FileSystemShare share, SMB1ConnectionState state)
  133. {
  134. SMB1Session session = state.GetSession(header.UID);
  135. if (!share.HasWriteAccess(session.UserName, request.OldFileName, state.ClientEndPoint))
  136. {
  137. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  138. return new ErrorResponse(request.CommandName);
  139. }
  140. if (!share.HasWriteAccess(session.UserName, request.NewFileName, state.ClientEndPoint))
  141. {
  142. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  143. return new ErrorResponse(request.CommandName);
  144. }
  145. IFileSystem fileSystem = share.FileSystem;
  146. FileSystemEntry sourceEntry = fileSystem.GetEntry(request.OldFileName);
  147. if (sourceEntry == null)
  148. {
  149. header.Status = NTStatus.STATUS_NO_SUCH_FILE;
  150. return new ErrorResponse(request.CommandName);
  151. }
  152. // The file must not already exist unless we just want to upcase / downcase a filename letter
  153. FileSystemEntry destinationEntry = fileSystem.GetEntry(request.NewFileName);
  154. if (destinationEntry != null &&
  155. !String.Equals(request.OldFileName, request.NewFileName, StringComparison.InvariantCultureIgnoreCase))
  156. {
  157. // The new file already exists.
  158. header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
  159. return new ErrorResponse(request.CommandName);
  160. }
  161. try
  162. {
  163. fileSystem.Move(request.OldFileName, request.NewFileName);
  164. return new RenameResponse();
  165. }
  166. catch (IOException)
  167. {
  168. state.LogToServer(Severity.Debug, "Rename: Sharing violation renaming '{0}'", request.OldFileName);
  169. header.Status = NTStatus.STATUS_SHARING_VIOLATION;
  170. return new ErrorResponse(request.CommandName);
  171. }
  172. catch (UnauthorizedAccessException)
  173. {
  174. state.LogToServer(Severity.Debug, "Rename: Cannot rename '{0}', Access Denied", request.OldFileName);
  175. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  176. return new ErrorResponse(request.CommandName);
  177. }
  178. }
  179. internal static SMB1Command GetQueryInformationResponse(SMB1Header header, QueryInformationRequest request, FileSystemShare share)
  180. {
  181. IFileSystem fileSystem = share.FileSystem;
  182. FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
  183. if (entry == null)
  184. {
  185. header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
  186. return new ErrorResponse(request.CommandName);
  187. }
  188. QueryInformationResponse response = new QueryInformationResponse();
  189. response.FileAttributes = SMB1FileSystemHelper.GetFileAttributes(entry);
  190. response.LastWriteTime = entry.LastWriteTime;
  191. response.FileSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
  192. return response;
  193. }
  194. internal static SMB1Command GetSetInformationResponse(SMB1Header header, SetInformationRequest request, FileSystemShare share, SMB1ConnectionState state)
  195. {
  196. SMB1Session session = state.GetSession(header.UID);
  197. if (!share.HasWriteAccess(session.UserName, request.FileName, state.ClientEndPoint))
  198. {
  199. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  200. return new ErrorResponse(request.CommandName);
  201. }
  202. IFileSystem fileSystem = share.FileSystem;
  203. FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
  204. if (entry == null)
  205. {
  206. header.Status = NTStatus.STATUS_NO_SUCH_FILE;
  207. return new ErrorResponse(request.CommandName);
  208. }
  209. bool? isHidden = null;
  210. bool? isReadOnly = null;
  211. bool? isArchived = null;
  212. if ((request.FileAttributes & SMBFileAttributes.Hidden) > 0)
  213. {
  214. isHidden = true;
  215. }
  216. if ((request.FileAttributes & SMBFileAttributes.ReadOnly) > 0)
  217. {
  218. isReadOnly = true;
  219. }
  220. if ((request.FileAttributes & SMBFileAttributes.Archive) > 0)
  221. {
  222. isArchived = true;
  223. }
  224. fileSystem.SetAttributes(request.FileName, isHidden, isReadOnly, isArchived);
  225. if (request.LastWriteTime.HasValue)
  226. {
  227. fileSystem.SetDates(request.FileName, null, request.LastWriteTime, null);
  228. }
  229. return new SetInformationResponse();
  230. }
  231. internal static SMB1Command GetSetInformation2Response(SMB1Header header, SetInformation2Request request, FileSystemShare share, SMB1ConnectionState state)
  232. {
  233. SMB1Session session = state.GetSession(header.UID);
  234. OpenFileObject openFile = session.GetOpenFileObject(request.FID);
  235. if (openFile == null)
  236. {
  237. header.Status = NTStatus.STATUS_SMB_BAD_FID;
  238. return new ErrorResponse(request.CommandName);
  239. }
  240. if (!share.HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
  241. {
  242. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  243. return new ErrorResponse(request.CommandName);
  244. }
  245. IFileSystem fileSystem = share.FileSystem;
  246. fileSystem.SetDates(openFile.Path, request.CreationDateTime, request.LastWriteDateTime, request.LastAccessDateTime);
  247. return new SetInformation2Response();
  248. }
  249. }
  250. }