FileSystemResponseHelper.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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. string userName = state.GetConnectedUserName(header.UID);
  20. if (!share.HasWriteAccess(userName))
  21. {
  22. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  23. return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
  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(CommandName.SMB_COM_CREATE_DIRECTORY);
  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(CommandName.SMB_COM_CREATE_DIRECTORY);
  41. }
  42. return new CreateDirectoryResponse();
  43. }
  44. internal static SMB1Command GetDeleteDirectoryResponse(SMB1Header header, DeleteDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
  45. {
  46. string userName = state.GetConnectedUserName(header.UID);
  47. if (!share.HasWriteAccess(userName))
  48. {
  49. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  50. return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
  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(CommandName.SMB_COM_DELETE_DIRECTORY);
  58. }
  59. if (!entry.IsDirectory)
  60. {
  61. header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
  62. return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
  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(CommandName.SMB_COM_DELETE_DIRECTORY);
  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(CommandName.SMB_COM_DELETE_DIRECTORY);
  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(CommandName.SMB_COM_CHECK_DIRECTORY);
  90. }
  91. return new CheckDirectoryResponse();
  92. }
  93. internal static SMB1Command GetDeleteResponse(SMB1Header header, DeleteRequest request, FileSystemShare share, SMB1ConnectionState state)
  94. {
  95. string userName = state.GetConnectedUserName(header.UID);
  96. if (!share.HasWriteAccess(userName))
  97. {
  98. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  99. return new ErrorResponse(CommandName.SMB_COM_DELETE);
  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(CommandName.SMB_COM_DELETE);
  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(CommandName.SMB_COM_DELETE);
  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(CommandName.SMB_COM_DELETE);
  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(CommandName.SMB_COM_DELETE);
  130. }
  131. }
  132. internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, FileSystemShare share, SMB1ConnectionState state)
  133. {
  134. string userName = state.GetConnectedUserName(header.UID);
  135. if (!share.HasWriteAccess(userName))
  136. {
  137. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  138. return new ErrorResponse(CommandName.SMB_COM_RENAME);
  139. }
  140. IFileSystem fileSystem = share.FileSystem;
  141. FileSystemEntry sourceEntry = fileSystem.GetEntry(request.OldFileName);
  142. if (sourceEntry == null)
  143. {
  144. header.Status = NTStatus.STATUS_NO_SUCH_FILE;
  145. return new ErrorResponse(CommandName.SMB_COM_RENAME);
  146. }
  147. // The file must not already exist unless we just want to upcase / downcase a filename letter
  148. FileSystemEntry destinationEntry = fileSystem.GetEntry(request.NewFileName);
  149. if (destinationEntry != null &&
  150. !String.Equals(request.OldFileName, request.NewFileName, StringComparison.InvariantCultureIgnoreCase))
  151. {
  152. // The new file already exists.
  153. header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
  154. return new ErrorResponse(CommandName.SMB_COM_RENAME);
  155. }
  156. try
  157. {
  158. fileSystem.Move(request.OldFileName, request.NewFileName);
  159. return new RenameResponse();
  160. }
  161. catch (IOException)
  162. {
  163. state.LogToServer(Severity.Debug, "Rename: Sharing violation renaming '{0}'", request.OldFileName);
  164. header.Status = NTStatus.STATUS_SHARING_VIOLATION;
  165. return new ErrorResponse(CommandName.SMB_COM_RENAME);
  166. }
  167. catch (UnauthorizedAccessException)
  168. {
  169. state.LogToServer(Severity.Debug, "Rename: Cannot rename '{0}', Access Denied", request.OldFileName);
  170. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  171. return new ErrorResponse(CommandName.SMB_COM_RENAME);
  172. }
  173. }
  174. internal static SMB1Command GetQueryInformationResponse(SMB1Header header, QueryInformationRequest request, FileSystemShare share)
  175. {
  176. IFileSystem fileSystem = share.FileSystem;
  177. FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
  178. if (entry == null)
  179. {
  180. header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
  181. return new ErrorResponse(CommandName.SMB_COM_QUERY_INFORMATION);
  182. }
  183. QueryInformationResponse response = new QueryInformationResponse();
  184. response.FileAttributes = InfoHelper.GetFileAttributes(entry);
  185. response.LastWriteTime = entry.LastWriteTime;
  186. response.FileSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
  187. return response;
  188. }
  189. internal static SMB1Command GetSetInformationResponse(SMB1Header header, SetInformationRequest request, FileSystemShare share, SMB1ConnectionState state)
  190. {
  191. string userName = state.GetConnectedUserName(header.UID);
  192. if (!share.HasWriteAccess(userName))
  193. {
  194. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  195. return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
  196. }
  197. IFileSystem fileSystem = share.FileSystem;
  198. FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
  199. if (entry == null)
  200. {
  201. header.Status = NTStatus.STATUS_NO_SUCH_FILE;
  202. return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION);
  203. }
  204. bool? isHidden = null;
  205. bool? isReadOnly = null;
  206. bool? isArchived = null;
  207. if ((request.FileAttributes & SMBFileAttributes.Hidden) > 0)
  208. {
  209. isHidden = true;
  210. }
  211. if ((request.FileAttributes & SMBFileAttributes.ReadOnly) > 0)
  212. {
  213. isReadOnly = true;
  214. }
  215. if ((request.FileAttributes & SMBFileAttributes.Archive) > 0)
  216. {
  217. isArchived = true;
  218. }
  219. fileSystem.SetAttributes(request.FileName, isHidden, isReadOnly, isArchived);
  220. if (request.LastWriteTime != SMB1Helper.UTimeNotSpecified)
  221. {
  222. fileSystem.SetDates(request.FileName, null, request.LastWriteTime, null);
  223. }
  224. return new SetInformationResponse();
  225. }
  226. internal static SMB1Command GetSetInformation2Response(SMB1Header header, SetInformation2Request request, FileSystemShare share, SMB1ConnectionState state)
  227. {
  228. string openedFilePath = state.GetOpenedFilePath(request.FID);
  229. if (openedFilePath == null)
  230. {
  231. header.Status = NTStatus.STATUS_SMB_BAD_FID;
  232. return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
  233. }
  234. string userName = state.GetConnectedUserName(header.UID);
  235. if (!share.HasWriteAccess(userName))
  236. {
  237. header.Status = NTStatus.STATUS_ACCESS_DENIED;
  238. return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
  239. }
  240. IFileSystem fileSystem = share.FileSystem;
  241. fileSystem.SetDates(openedFilePath, request.CreationDateTime, request.LastWriteDateTime, request.LastAccessDateTime);
  242. return new SetInformation2Response();
  243. }
  244. }
  245. }