SMB1Client.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. /* Copyright (C) 2014-2020 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.Diagnostics;
  10. using System.Net;
  11. using System.Net.Sockets;
  12. using System.Threading;
  13. using SMBLibrary.Authentication.NTLM;
  14. using SMBLibrary.NetBios;
  15. using SMBLibrary.Services;
  16. using SMBLibrary.SMB1;
  17. using Utilities;
  18. namespace SMBLibrary.Client
  19. {
  20. public class SMB1Client : ISMBClient
  21. {
  22. private const string NTLanManagerDialect = "NT LM 0.12";
  23. public static readonly int NetBiosOverTCPPort = 139;
  24. public static readonly int DirectTCPPort = 445;
  25. private static readonly ushort ClientMaxBufferSize = 65535; // Valid range: 512 - 65535
  26. private static readonly ushort ClientMaxMpxCount = 1;
  27. private SMBTransportType m_transport;
  28. private bool m_isConnected;
  29. private bool m_isLoggedIn;
  30. private Socket m_clientSocket;
  31. private bool m_forceExtendedSecurity;
  32. private bool m_unicode;
  33. private bool m_largeFiles;
  34. private bool m_infoLevelPassthrough;
  35. private bool m_largeRead;
  36. private bool m_largeWrite;
  37. private uint m_serverMaxBufferSize;
  38. private ushort m_maxMpxCount;
  39. private object m_incomingQueueLock = new object();
  40. private List<SMB1Message> m_incomingQueue = new List<SMB1Message>();
  41. private EventWaitHandle m_incomingQueueEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
  42. private SessionPacket m_sessionResponsePacket;
  43. private EventWaitHandle m_sessionResponseEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
  44. private ushort m_userID;
  45. private byte[] m_serverChallenge;
  46. private byte[] m_securityBlob;
  47. private byte[] m_sessionKey;
  48. public SMB1Client()
  49. {
  50. }
  51. public bool Connect(IPAddress serverAddress, SMBTransportType transport)
  52. {
  53. return Connect(serverAddress, transport, true);
  54. }
  55. public bool Connect(IPAddress serverAddress, SMBTransportType transport, bool forceExtendedSecurity)
  56. {
  57. m_transport = transport;
  58. if (!m_isConnected)
  59. {
  60. m_forceExtendedSecurity = forceExtendedSecurity;
  61. int port;
  62. if (transport == SMBTransportType.NetBiosOverTCP)
  63. {
  64. port = NetBiosOverTCPPort;
  65. }
  66. else
  67. {
  68. port = DirectTCPPort;
  69. }
  70. if (!ConnectSocket(serverAddress, port))
  71. {
  72. return false;
  73. }
  74. if (transport == SMBTransportType.NetBiosOverTCP)
  75. {
  76. SessionRequestPacket sessionRequest = new SessionRequestPacket();
  77. sessionRequest.CalledName = NetBiosUtils.GetMSNetBiosName("*SMBSERVER", NetBiosSuffix.FileServiceService);
  78. sessionRequest.CallingName = NetBiosUtils.GetMSNetBiosName(Environment.MachineName, NetBiosSuffix.WorkstationService);
  79. TrySendPacket(m_clientSocket, sessionRequest);
  80. SessionPacket sessionResponsePacket = WaitForSessionResponsePacket();
  81. if (!(sessionResponsePacket is PositiveSessionResponsePacket))
  82. {
  83. m_clientSocket.Disconnect(false);
  84. if (!ConnectSocket(serverAddress, port))
  85. {
  86. return false;
  87. }
  88. NameServiceClient nameServiceClient = new NameServiceClient(serverAddress);
  89. string serverName = nameServiceClient.GetServerName();
  90. if (serverName == null)
  91. {
  92. return false;
  93. }
  94. sessionRequest.CalledName = serverName;
  95. TrySendPacket(m_clientSocket, sessionRequest);
  96. sessionResponsePacket = WaitForSessionResponsePacket();
  97. if (!(sessionResponsePacket is PositiveSessionResponsePacket))
  98. {
  99. return false;
  100. }
  101. }
  102. }
  103. bool supportsDialect = NegotiateDialect(m_forceExtendedSecurity);
  104. if (!supportsDialect)
  105. {
  106. m_clientSocket.Close();
  107. }
  108. else
  109. {
  110. m_isConnected = true;
  111. }
  112. }
  113. return m_isConnected;
  114. }
  115. private bool ConnectSocket(IPAddress serverAddress, int port)
  116. {
  117. m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  118. try
  119. {
  120. m_clientSocket.Connect(serverAddress, port);
  121. }
  122. catch (SocketException)
  123. {
  124. return false;
  125. }
  126. ConnectionState state = new ConnectionState(m_clientSocket);
  127. NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
  128. m_clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
  129. return true;
  130. }
  131. public void Disconnect()
  132. {
  133. if (m_isConnected)
  134. {
  135. m_clientSocket.Disconnect(false);
  136. m_isConnected = false;
  137. }
  138. }
  139. private bool NegotiateDialect(bool forceExtendedSecurity)
  140. {
  141. NegotiateRequest request = new NegotiateRequest();
  142. request.Dialects.Add(NTLanManagerDialect);
  143. TrySendMessage(request);
  144. SMB1Message reply = WaitForMessage(CommandName.SMB_COM_NEGOTIATE);
  145. if (reply == null)
  146. {
  147. return false;
  148. }
  149. if (reply.Commands[0] is NegotiateResponse && !forceExtendedSecurity)
  150. {
  151. NegotiateResponse response = (NegotiateResponse)reply.Commands[0];
  152. m_unicode = ((response.Capabilities & Capabilities.Unicode) > 0);
  153. m_largeFiles = ((response.Capabilities & Capabilities.LargeFiles) > 0);
  154. bool ntSMB = ((response.Capabilities & Capabilities.NTSMB) > 0);
  155. bool rpc = ((response.Capabilities & Capabilities.RpcRemoteApi) > 0);
  156. bool ntStatusCode = ((response.Capabilities & Capabilities.NTStatusCode) > 0);
  157. m_infoLevelPassthrough = ((response.Capabilities & Capabilities.InfoLevelPassthrough) > 0);
  158. m_largeRead = ((response.Capabilities & Capabilities.LargeRead) > 0);
  159. m_largeWrite = ((response.Capabilities & Capabilities.LargeWrite) > 0);
  160. m_serverMaxBufferSize = response.MaxBufferSize;
  161. m_maxMpxCount = Math.Min(response.MaxMpxCount, ClientMaxMpxCount);
  162. m_serverChallenge = response.Challenge;
  163. return ntSMB && rpc && ntStatusCode;
  164. }
  165. else if (reply.Commands[0] is NegotiateResponseExtended)
  166. {
  167. NegotiateResponseExtended response = (NegotiateResponseExtended)reply.Commands[0];
  168. m_unicode = ((response.Capabilities & Capabilities.Unicode) > 0);
  169. m_largeFiles = ((response.Capabilities & Capabilities.LargeFiles) > 0);
  170. bool ntSMB = ((response.Capabilities & Capabilities.NTSMB) > 0);
  171. bool rpc = ((response.Capabilities & Capabilities.RpcRemoteApi) > 0);
  172. bool ntStatusCode = ((response.Capabilities & Capabilities.NTStatusCode) > 0);
  173. m_infoLevelPassthrough = ((response.Capabilities & Capabilities.InfoLevelPassthrough) > 0);
  174. m_largeRead = ((response.Capabilities & Capabilities.LargeRead) > 0);
  175. m_largeWrite = ((response.Capabilities & Capabilities.LargeWrite) > 0);
  176. m_serverMaxBufferSize = response.MaxBufferSize;
  177. m_maxMpxCount = Math.Min(response.MaxMpxCount, ClientMaxMpxCount);
  178. m_securityBlob = response.SecurityBlob;
  179. return ntSMB && rpc && ntStatusCode;
  180. }
  181. else
  182. {
  183. return false;
  184. }
  185. }
  186. public NTStatus Login(string domainName, string userName, string password)
  187. {
  188. return Login(domainName, userName, password, AuthenticationMethod.NTLMv2);
  189. }
  190. public NTStatus Login(string domainName, string userName, string password, AuthenticationMethod authenticationMethod)
  191. {
  192. if (!m_isConnected)
  193. {
  194. throw new InvalidOperationException("A connection must be successfully established before attempting login");
  195. }
  196. Capabilities clientCapabilities = Capabilities.NTSMB | Capabilities.RpcRemoteApi | Capabilities.NTStatusCode | Capabilities.NTFind;
  197. if (m_unicode)
  198. {
  199. clientCapabilities |= Capabilities.Unicode;
  200. }
  201. if (m_largeFiles)
  202. {
  203. clientCapabilities |= Capabilities.LargeFiles;
  204. }
  205. if (m_largeRead)
  206. {
  207. clientCapabilities |= Capabilities.LargeRead;
  208. }
  209. if (m_serverChallenge != null)
  210. {
  211. SessionSetupAndXRequest request = new SessionSetupAndXRequest();
  212. request.MaxBufferSize = ClientMaxBufferSize;
  213. request.MaxMpxCount = m_maxMpxCount;
  214. request.Capabilities = clientCapabilities;
  215. request.AccountName = userName;
  216. request.PrimaryDomain = domainName;
  217. byte[] clientChallenge = new byte[8];
  218. new Random().NextBytes(clientChallenge);
  219. if (authenticationMethod == AuthenticationMethod.NTLMv1)
  220. {
  221. request.OEMPassword = NTLMCryptography.ComputeLMv1Response(m_serverChallenge, password);
  222. request.UnicodePassword = NTLMCryptography.ComputeNTLMv1Response(m_serverChallenge, password);
  223. }
  224. else if (authenticationMethod == AuthenticationMethod.NTLMv1ExtendedSessionSecurity)
  225. {
  226. // [MS-CIFS] CIFS does not support Extended Session Security because there is no mechanism in CIFS to negotiate Extended Session Security
  227. throw new ArgumentException("SMB Extended Security must be negotiated in order for NTLMv1 Extended Session Security to be used");
  228. }
  229. else // NTLMv2
  230. {
  231. // Note: NTLMv2 over non-extended security session setup is not supported under Windows Vista and later which will return STATUS_INVALID_PARAMETER.
  232. // https://msdn.microsoft.com/en-us/library/ee441701.aspx
  233. // https://msdn.microsoft.com/en-us/library/cc236700.aspx
  234. request.OEMPassword = NTLMCryptography.ComputeLMv2Response(m_serverChallenge, clientChallenge, password, userName, domainName);
  235. NTLMv2ClientChallenge clientChallengeStructure = new NTLMv2ClientChallenge(DateTime.UtcNow, clientChallenge, AVPairUtils.GetAVPairSequence(domainName, Environment.MachineName));
  236. byte[] temp = clientChallengeStructure.GetBytesPadded();
  237. byte[] proofStr = NTLMCryptography.ComputeNTLMv2Proof(m_serverChallenge, temp, password, userName, domainName);
  238. request.UnicodePassword = ByteUtils.Concatenate(proofStr, temp);
  239. }
  240. TrySendMessage(request);
  241. SMB1Message reply = WaitForMessage(CommandName.SMB_COM_SESSION_SETUP_ANDX);
  242. if (reply != null)
  243. {
  244. m_isLoggedIn = (reply.Header.Status == NTStatus.STATUS_SUCCESS);
  245. return reply.Header.Status;
  246. }
  247. return NTStatus.STATUS_INVALID_SMB;
  248. }
  249. else // m_securityBlob != null
  250. {
  251. byte[] negotiateMessage = NTLMAuthenticationHelper.GetNegotiateMessage(m_securityBlob, domainName, authenticationMethod);
  252. if (negotiateMessage == null)
  253. {
  254. return NTStatus.SEC_E_INVALID_TOKEN;
  255. }
  256. SessionSetupAndXRequestExtended request = new SessionSetupAndXRequestExtended();
  257. request.MaxBufferSize = ClientMaxBufferSize;
  258. request.MaxMpxCount = m_maxMpxCount;
  259. request.Capabilities = clientCapabilities;
  260. request.SecurityBlob = negotiateMessage;
  261. TrySendMessage(request);
  262. SMB1Message reply = WaitForMessage(CommandName.SMB_COM_SESSION_SETUP_ANDX);
  263. if (reply != null)
  264. {
  265. if (reply.Header.Status == NTStatus.STATUS_MORE_PROCESSING_REQUIRED && reply.Commands[0] is SessionSetupAndXResponseExtended)
  266. {
  267. SessionSetupAndXResponseExtended response = (SessionSetupAndXResponseExtended)reply.Commands[0];
  268. byte[] authenticateMessage = NTLMAuthenticationHelper.GetAuthenticateMessage(response.SecurityBlob, domainName, userName, password, authenticationMethod, out m_sessionKey);
  269. if (authenticateMessage == null)
  270. {
  271. return NTStatus.SEC_E_INVALID_TOKEN;
  272. }
  273. m_userID = reply.Header.UID;
  274. request = new SessionSetupAndXRequestExtended();
  275. request.MaxBufferSize = ClientMaxBufferSize;
  276. request.MaxMpxCount = m_maxMpxCount;
  277. request.Capabilities = clientCapabilities;
  278. request.SecurityBlob = authenticateMessage;
  279. TrySendMessage(request);
  280. reply = WaitForMessage(CommandName.SMB_COM_SESSION_SETUP_ANDX);
  281. if (reply != null)
  282. {
  283. m_isLoggedIn = (reply.Header.Status == NTStatus.STATUS_SUCCESS);
  284. return reply.Header.Status;
  285. }
  286. }
  287. else
  288. {
  289. return reply.Header.Status;
  290. }
  291. }
  292. return NTStatus.STATUS_INVALID_SMB;
  293. }
  294. }
  295. public NTStatus Logoff()
  296. {
  297. if (!m_isConnected)
  298. {
  299. throw new InvalidOperationException("A login session must be successfully established before attempting logoff");
  300. }
  301. LogoffAndXRequest request = new LogoffAndXRequest();
  302. TrySendMessage(request);
  303. SMB1Message reply = WaitForMessage(CommandName.SMB_COM_LOGOFF_ANDX);
  304. if (reply != null)
  305. {
  306. m_isLoggedIn = (reply.Header.Status != NTStatus.STATUS_SUCCESS);
  307. return reply.Header.Status;
  308. }
  309. return NTStatus.STATUS_INVALID_SMB;
  310. }
  311. public List<string> ListShares(out NTStatus status)
  312. {
  313. if (!m_isConnected || !m_isLoggedIn)
  314. {
  315. throw new InvalidOperationException("A login session must be successfully established before retrieving share list");
  316. }
  317. SMB1FileStore namedPipeShare = TreeConnect("IPC$", ServiceName.NamedPipe, out status);
  318. if (namedPipeShare == null)
  319. {
  320. return null;
  321. }
  322. List<string> shares = ServerServiceHelper.ListShares(namedPipeShare, ShareType.DiskDrive, out status);
  323. namedPipeShare.Disconnect();
  324. return shares;
  325. }
  326. public ISMBFileStore TreeConnect(string shareName, out NTStatus status)
  327. {
  328. return TreeConnect(shareName, ServiceName.AnyType, out status);
  329. }
  330. public SMB1FileStore TreeConnect(string shareName, ServiceName serviceName, out NTStatus status)
  331. {
  332. if (!m_isConnected || !m_isLoggedIn)
  333. {
  334. throw new InvalidOperationException("A login session must be successfully established before connecting to a share");
  335. }
  336. TreeConnectAndXRequest request = new TreeConnectAndXRequest();
  337. request.Path = shareName;
  338. request.Service = serviceName;
  339. TrySendMessage(request);
  340. SMB1Message reply = WaitForMessage(CommandName.SMB_COM_TREE_CONNECT_ANDX);
  341. if (reply != null)
  342. {
  343. status = reply.Header.Status;
  344. if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is TreeConnectAndXResponse)
  345. {
  346. TreeConnectAndXResponse response = (TreeConnectAndXResponse)reply.Commands[0];
  347. return new SMB1FileStore(this, reply.Header.TID);
  348. }
  349. }
  350. else
  351. {
  352. status = NTStatus.STATUS_INVALID_SMB;
  353. }
  354. return null;
  355. }
  356. private void OnClientSocketReceive(IAsyncResult ar)
  357. {
  358. ConnectionState state = (ConnectionState)ar.AsyncState;
  359. Socket clientSocket = state.ClientSocket;
  360. if (!clientSocket.Connected)
  361. {
  362. return;
  363. }
  364. int numberOfBytesReceived = 0;
  365. try
  366. {
  367. numberOfBytesReceived = clientSocket.EndReceive(ar);
  368. }
  369. catch (ArgumentException) // The IAsyncResult object was not returned from the corresponding synchronous method on this class.
  370. {
  371. return;
  372. }
  373. catch (ObjectDisposedException)
  374. {
  375. Log("[ReceiveCallback] EndReceive ObjectDisposedException");
  376. return;
  377. }
  378. catch (SocketException ex)
  379. {
  380. Log("[ReceiveCallback] EndReceive SocketException: " + ex.Message);
  381. return;
  382. }
  383. if (numberOfBytesReceived == 0)
  384. {
  385. m_isConnected = false;
  386. }
  387. else
  388. {
  389. NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
  390. buffer.SetNumberOfBytesReceived(numberOfBytesReceived);
  391. ProcessConnectionBuffer(state);
  392. try
  393. {
  394. clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
  395. }
  396. catch (ObjectDisposedException)
  397. {
  398. m_isConnected = false;
  399. Log("[ReceiveCallback] BeginReceive ObjectDisposedException");
  400. }
  401. catch (SocketException ex)
  402. {
  403. m_isConnected = false;
  404. Log("[ReceiveCallback] BeginReceive SocketException: " + ex.Message);
  405. }
  406. }
  407. }
  408. private void ProcessConnectionBuffer(ConnectionState state)
  409. {
  410. NBTConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;
  411. while (receiveBuffer.HasCompletePacket())
  412. {
  413. SessionPacket packet = null;
  414. try
  415. {
  416. packet = receiveBuffer.DequeuePacket();
  417. }
  418. catch (Exception)
  419. {
  420. state.ClientSocket.Close();
  421. break;
  422. }
  423. if (packet != null)
  424. {
  425. ProcessPacket(packet, state);
  426. }
  427. }
  428. }
  429. private void ProcessPacket(SessionPacket packet, ConnectionState state)
  430. {
  431. if (packet is SessionMessagePacket)
  432. {
  433. SMB1Message message;
  434. try
  435. {
  436. message = SMB1Message.GetSMB1Message(packet.Trailer);
  437. }
  438. catch (Exception ex)
  439. {
  440. Log("Invalid SMB1 message: " + ex.Message);
  441. state.ClientSocket.Close();
  442. m_isConnected = false;
  443. return;
  444. }
  445. // [MS-CIFS] 3.2.5.1 - If the MID value is the reserved value 0xFFFF, the message can be an OpLock break
  446. // sent by the server. Otherwise, if the PID and MID values of the received message are not found in the
  447. // Client.Connection.PIDMIDList, the message MUST be discarded.
  448. if ((message.Header.MID == 0xFFFF && message.Header.Command == CommandName.SMB_COM_LOCKING_ANDX) ||
  449. (message.Header.PID == 0 && message.Header.MID == 0))
  450. {
  451. lock (m_incomingQueueLock)
  452. {
  453. m_incomingQueue.Add(message);
  454. m_incomingQueueEventHandle.Set();
  455. }
  456. }
  457. }
  458. else if ((packet is PositiveSessionResponsePacket || packet is NegativeSessionResponsePacket) && m_transport == SMBTransportType.NetBiosOverTCP)
  459. {
  460. m_sessionResponsePacket = packet;
  461. m_sessionResponseEventHandle.Set();
  462. }
  463. else if (packet is SessionKeepAlivePacket && m_transport == SMBTransportType.NetBiosOverTCP)
  464. {
  465. // [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer
  466. }
  467. else
  468. {
  469. Log("Inappropriate NetBIOS session packet");
  470. state.ClientSocket.Close();
  471. }
  472. }
  473. internal SMB1Message WaitForMessage(CommandName commandName)
  474. {
  475. const int TimeOut = 5000;
  476. Stopwatch stopwatch = new Stopwatch();
  477. stopwatch.Start();
  478. while (stopwatch.ElapsedMilliseconds < TimeOut)
  479. {
  480. lock (m_incomingQueueLock)
  481. {
  482. for (int index = 0; index < m_incomingQueue.Count; index++)
  483. {
  484. SMB1Message message = m_incomingQueue[index];
  485. if (message.Commands[0].CommandName == commandName)
  486. {
  487. m_incomingQueue.RemoveAt(index);
  488. return message;
  489. }
  490. }
  491. }
  492. m_incomingQueueEventHandle.WaitOne(100);
  493. }
  494. return null;
  495. }
  496. internal SessionPacket WaitForSessionResponsePacket()
  497. {
  498. const int TimeOut = 5000;
  499. Stopwatch stopwatch = new Stopwatch();
  500. stopwatch.Start();
  501. while (stopwatch.ElapsedMilliseconds < TimeOut)
  502. {
  503. if (m_sessionResponsePacket != null)
  504. {
  505. SessionPacket result = m_sessionResponsePacket;
  506. m_sessionResponsePacket = null;
  507. return result;
  508. }
  509. m_sessionResponseEventHandle.WaitOne(100);
  510. }
  511. return null;
  512. }
  513. private void Log(string message)
  514. {
  515. System.Diagnostics.Debug.Print(message);
  516. }
  517. internal void TrySendMessage(SMB1Command request)
  518. {
  519. TrySendMessage(request, 0);
  520. }
  521. internal void TrySendMessage(SMB1Command request, ushort treeID)
  522. {
  523. SMB1Message message = new SMB1Message();
  524. message.Header.UnicodeFlag = m_unicode;
  525. message.Header.ExtendedSecurityFlag = m_forceExtendedSecurity;
  526. message.Header.Flags2 |= HeaderFlags2.LongNamesAllowed | HeaderFlags2.LongNameUsed | HeaderFlags2.NTStatusCode;
  527. message.Header.UID = m_userID;
  528. message.Header.TID = treeID;
  529. message.Commands.Add(request);
  530. TrySendMessage(m_clientSocket, message);
  531. }
  532. public bool Unicode
  533. {
  534. get
  535. {
  536. return m_unicode;
  537. }
  538. }
  539. public bool LargeFiles
  540. {
  541. get
  542. {
  543. return m_largeFiles;
  544. }
  545. }
  546. public bool InfoLevelPassthrough
  547. {
  548. get
  549. {
  550. return m_infoLevelPassthrough;
  551. }
  552. }
  553. public bool LargeRead
  554. {
  555. get
  556. {
  557. return m_largeRead;
  558. }
  559. }
  560. public bool LargeWrite
  561. {
  562. get
  563. {
  564. return m_largeWrite;
  565. }
  566. }
  567. public uint ServerMaxBufferSize
  568. {
  569. get
  570. {
  571. return m_serverMaxBufferSize;
  572. }
  573. }
  574. public int MaxMpxCount
  575. {
  576. get
  577. {
  578. return m_maxMpxCount;
  579. }
  580. }
  581. public uint MaxReadSize
  582. {
  583. get
  584. {
  585. return (uint)ClientMaxBufferSize - (SMB1Header.Length + 3 + ReadAndXResponse.ParametersLength);
  586. }
  587. }
  588. public uint MaxWriteSize
  589. {
  590. get
  591. {
  592. uint result = ServerMaxBufferSize - (SMB1Header.Length + 3 + WriteAndXRequest.ParametersFixedLength + 4);
  593. if (m_unicode)
  594. {
  595. result--;
  596. }
  597. return result;
  598. }
  599. }
  600. public static void TrySendMessage(Socket socket, SMB1Message message)
  601. {
  602. SessionMessagePacket packet = new SessionMessagePacket();
  603. packet.Trailer = message.GetBytes();
  604. TrySendPacket(socket, packet);
  605. }
  606. public static void TrySendPacket(Socket socket, SessionPacket packet)
  607. {
  608. try
  609. {
  610. byte[] packetBytes = packet.GetBytes();
  611. socket.Send(packetBytes);
  612. }
  613. catch (SocketException)
  614. {
  615. }
  616. catch (ObjectDisposedException)
  617. {
  618. }
  619. }
  620. }
  621. }