ServerMessageBlock.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. // This code is derived from jcifs smb client library <jcifs at samba dot org>
  2. // Ported by J. Arturo <webmaster at komodosoft dot net>
  3. //
  4. // This library is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU Lesser General Public
  6. // License as published by the Free Software Foundation; either
  7. // version 2.1 of the License, or (at your option) any later version.
  8. //
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. // Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public
  15. // License along with this library; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. using System;
  18. using SharpCifs.Util;
  19. using SharpCifs.Util.Sharpen;
  20. using SharpCifs.Util.Transport;
  21. namespace SharpCifs.Smb
  22. {
  23. public abstract class ServerMessageBlock: Response
  24. {
  25. internal static LogStream Log = LogStream.GetInstance();
  26. internal static long Ticks1601 = new DateTime(1601, 1, 1).Ticks;
  27. internal static readonly byte[] Header = { 0xFF, (byte)('S'), (byte)('M'),
  28. (byte)('B'), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  29. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  30. internal static void WriteInt2(long val, byte[] dst, int dstIndex)
  31. {
  32. dst[dstIndex] = unchecked((byte)(val));
  33. dst[++dstIndex] = unchecked((byte)(val >> 8));
  34. }
  35. internal static void WriteInt4(long val, byte[] dst, int dstIndex)
  36. {
  37. dst[dstIndex] = unchecked((byte)(val));
  38. dst[++dstIndex] = unchecked((byte)(val >>= 8));
  39. dst[++dstIndex] = unchecked((byte)(val >>= 8));
  40. dst[++dstIndex] = unchecked((byte)(val >> 8));
  41. }
  42. internal static int ReadInt2(byte[] src, int srcIndex)
  43. {
  44. return unchecked(src[srcIndex] & 0xFF) + ((src[srcIndex + 1] & 0xFF) << 8);
  45. }
  46. internal static int ReadInt4(byte[] src, int srcIndex)
  47. {
  48. return unchecked(src[srcIndex] & 0xFF) + ((src[srcIndex + 1] & 0xFF) << 8) + ((src[srcIndex + 2]
  49. & 0xFF) << 16) + ((src[srcIndex + 3] & 0xFF) << 24);
  50. }
  51. internal static long ReadInt8(byte[] src, int srcIndex)
  52. {
  53. return unchecked(ReadInt4(src, srcIndex) & unchecked(0xFFFFFFFFL)) + unchecked((long)(ReadInt4
  54. (src, srcIndex + 4)) << 32);
  55. }
  56. internal static void WriteInt8(long val, byte[] dst, int dstIndex)
  57. {
  58. dst[dstIndex] = unchecked((byte)(val));
  59. dst[++dstIndex] = unchecked((byte)(val >>= 8));
  60. dst[++dstIndex] = unchecked((byte)(val >>= 8));
  61. dst[++dstIndex] = unchecked((byte)(val >>= 8));
  62. dst[++dstIndex] = unchecked((byte)(val >>= 8));
  63. dst[++dstIndex] = unchecked((byte)(val >>= 8));
  64. dst[++dstIndex] = unchecked((byte)(val >>= 8));
  65. dst[++dstIndex] = unchecked((byte)(val >> 8));
  66. }
  67. internal static long ReadTime(byte[] src, int srcIndex)
  68. {
  69. int low = ReadInt4(src, srcIndex);
  70. int hi = ReadInt4(src, srcIndex + 4);
  71. long t = ((long)hi << (int)32L) | (low & unchecked((long)(0xFFFFFFFFL)));
  72. t = (t / 10000L - SmbConstants.MillisecondsBetween1970And1601);
  73. return t;
  74. }
  75. internal static void WriteTime(long t, byte[] dst, int dstIndex)
  76. {
  77. if (t != 0L)
  78. {
  79. t = (t + SmbConstants.MillisecondsBetween1970And1601) * 10000L;
  80. }
  81. WriteInt8(t, dst, dstIndex);
  82. }
  83. internal static long ReadUTime(byte[] buffer, int bufferIndex)
  84. {
  85. return ReadInt4(buffer, bufferIndex) * 1000L;
  86. }
  87. internal static void WriteUTime(long t, byte[] dst, int dstIndex)
  88. {
  89. if (t == 0L || t == unchecked((long)(0xFFFFFFFFFFFFFFFFL)))
  90. {
  91. WriteInt4(unchecked((int)(0xFFFFFFFF)), dst, dstIndex);
  92. return;
  93. }
  94. // t isn't in DST either
  95. WriteInt4((int)(t / 1000L), dst, dstIndex);
  96. }
  97. internal const byte SmbComCreateDirectory = 0x00;
  98. internal const byte SmbComDeleteDirectory = 0x01;
  99. internal const byte SmbComClose = 0x04;
  100. internal const byte SmbComDelete = 0x06;
  101. internal const byte SmbComRename = 0x07;
  102. internal const byte SmbComQueryInformation = 0x08;
  103. internal const byte SmbComWrite = 0x0B;
  104. internal const byte SmbComCheckDirectory = 0x10;
  105. internal const byte SmbComTransaction = 0x25;
  106. internal const byte SmbComTransactionSecondary = 0x26;
  107. internal const byte SmbComMove = 0x2A;
  108. internal const byte SmbComEcho = 0x2B;
  109. internal const byte SmbComOpenAndx = 0x2D;
  110. internal const byte SmbComReadAndx = 0x2E;
  111. internal const byte SmbComWriteAndx = 0x2F;
  112. internal const byte SmbComTransaction2 = 0x32;
  113. internal const byte SmbComFindClose2 = 0x34;
  114. internal const byte SmbComTreeDisconnect = 0x71;
  115. internal const byte SmbComNegotiate = 0x72;
  116. internal const byte SmbComSessionSetupAndx = 0x73;
  117. internal const byte SmbComLogoffAndx = 0x74;
  118. internal const byte SmbComTreeConnectAndx = 0x75;
  119. internal const byte SmbComNtTransact = 0xA0;
  120. internal const byte SmbComNtTransactSecondary = 0xA1;
  121. internal const byte SmbComNtCreateAndx = 0xA2;
  122. internal byte Command;
  123. internal byte Flags;
  124. internal int HeaderStart;
  125. internal int Length;
  126. internal int BatchLevel;
  127. internal int ErrorCode;
  128. internal int Flags2;
  129. internal int Tid;
  130. internal int Pid;
  131. internal int Uid;
  132. internal int Mid;
  133. internal int WordCount;
  134. internal int ByteCount;
  135. internal bool UseUnicode;
  136. internal bool Received;
  137. internal bool ExtendedSecurity;
  138. internal long ResponseTimeout = 1;
  139. internal int SignSeq;
  140. internal bool VerifyFailed;
  141. internal NtlmPasswordAuthentication Auth = null;
  142. internal string Path;
  143. internal SigningDigest Digest;
  144. internal ServerMessageBlock Response;
  145. public ServerMessageBlock()
  146. {
  147. Flags = unchecked((byte)(SmbConstants.FlagsPathNamesCaseless | SmbConstants.FlagsPathNamesCanonicalized
  148. ));
  149. Pid = SmbConstants.Pid;
  150. BatchLevel = 0;
  151. }
  152. internal virtual void Reset()
  153. {
  154. Flags = unchecked((byte)(SmbConstants.FlagsPathNamesCaseless | SmbConstants.FlagsPathNamesCanonicalized
  155. ));
  156. Flags2 = 0;
  157. ErrorCode = 0;
  158. Received = false;
  159. Digest = null;
  160. }
  161. internal virtual int WriteString(string str, byte[] dst, int dstIndex)
  162. {
  163. return WriteString(str, dst, dstIndex, UseUnicode);
  164. }
  165. internal virtual int WriteString(string str, byte[] dst, int dstIndex, bool useUnicode
  166. )
  167. {
  168. int start = dstIndex;
  169. try
  170. {
  171. if (useUnicode)
  172. {
  173. // Unicode requires word alignment
  174. if (((dstIndex - HeaderStart) % 2) != 0)
  175. {
  176. dst[dstIndex++] = (byte)('\0');
  177. }
  178. Array.Copy(Runtime.GetBytesForString(str, SmbConstants.UniEncoding), 0, dst, dstIndex
  179. , str.Length * 2);
  180. dstIndex += str.Length * 2;
  181. dst[dstIndex++] = (byte)('\0');
  182. dst[dstIndex++] = (byte)('\0');
  183. }
  184. else
  185. {
  186. byte[] b = Runtime.GetBytesForString(str, SmbConstants.OemEncoding);
  187. Array.Copy(b, 0, dst, dstIndex, b.Length);
  188. dstIndex += b.Length;
  189. dst[dstIndex++] = (byte)('\0');
  190. }
  191. }
  192. catch (UnsupportedEncodingException uee)
  193. {
  194. if (Log.Level > 1)
  195. {
  196. Runtime.PrintStackTrace(uee, Log);
  197. }
  198. }
  199. return dstIndex - start;
  200. }
  201. internal virtual string ReadString(byte[] src, int srcIndex)
  202. {
  203. return ReadString(src, srcIndex, 256, UseUnicode);
  204. }
  205. internal virtual string ReadString(byte[] src, int srcIndex, int maxLen, bool useUnicode
  206. )
  207. {
  208. int len = 0;
  209. string str = null;
  210. try
  211. {
  212. if (useUnicode)
  213. {
  214. // Unicode requires word alignment
  215. if (((srcIndex - HeaderStart) % 2) != 0)
  216. {
  217. srcIndex++;
  218. }
  219. while (src[srcIndex + len] != 0x00 || src[srcIndex
  220. + len + 1] != 0x00)
  221. {
  222. len += 2;
  223. if (len > maxLen)
  224. {
  225. if (Log.Level > 0)
  226. {
  227. Hexdump.ToHexdump(Console.Error, src, srcIndex, maxLen < 128 ? maxLen + 8 :
  228. 128);
  229. }
  230. throw new RuntimeException("zero termination not found");
  231. }
  232. }
  233. str = Runtime.GetStringForBytes(src, srcIndex, len, SmbConstants.UniEncoding);
  234. }
  235. else
  236. {
  237. while (src[srcIndex + len] != 0x00)
  238. {
  239. len++;
  240. if (len > maxLen)
  241. {
  242. if (Log.Level > 0)
  243. {
  244. Hexdump.ToHexdump(Console.Error, src, srcIndex, maxLen < 128 ? maxLen + 8 :
  245. 128);
  246. }
  247. throw new RuntimeException("zero termination not found");
  248. }
  249. }
  250. str = Runtime.GetStringForBytes(src, srcIndex, len, SmbConstants.OemEncoding);
  251. }
  252. }
  253. catch (UnsupportedEncodingException uee)
  254. {
  255. if (Log.Level > 1)
  256. {
  257. Runtime.PrintStackTrace(uee, Log);
  258. }
  259. }
  260. return str;
  261. }
  262. internal virtual string ReadString(byte[] src, int srcIndex, int srcEnd, int maxLen
  263. , bool useUnicode)
  264. {
  265. int len = 0;
  266. string str = null;
  267. try
  268. {
  269. if (useUnicode)
  270. {
  271. // Unicode requires word alignment
  272. if (((srcIndex - HeaderStart) % 2) != 0)
  273. {
  274. srcIndex++;
  275. }
  276. for (len = 0; (srcIndex + len + 1) < srcEnd; len += 2)
  277. {
  278. if (src[srcIndex + len] == 0x00 && src[srcIndex
  279. + len + 1] == 0x00)
  280. {
  281. break;
  282. }
  283. if (len > maxLen)
  284. {
  285. if (Log.Level > 0)
  286. {
  287. Hexdump.ToHexdump(Console.Error, src, srcIndex, maxLen < 128 ? maxLen + 8 :
  288. 128);
  289. }
  290. throw new RuntimeException("zero termination not found");
  291. }
  292. }
  293. str = Runtime.GetStringForBytes(src, srcIndex, len, SmbConstants.UniEncoding);
  294. }
  295. else
  296. {
  297. for (len = 0; srcIndex < srcEnd; len++)
  298. {
  299. if (src[srcIndex + len] == 0x00)
  300. {
  301. break;
  302. }
  303. if (len > maxLen)
  304. {
  305. if (Log.Level > 0)
  306. {
  307. Hexdump.ToHexdump(Console.Error, src, srcIndex, maxLen < 128 ? maxLen + 8 :
  308. 128);
  309. }
  310. throw new RuntimeException("zero termination not found");
  311. }
  312. }
  313. str = Runtime.GetStringForBytes(src, srcIndex, len, SmbConstants.OemEncoding);
  314. }
  315. }
  316. catch (UnsupportedEncodingException uee)
  317. {
  318. if (Log.Level > 1)
  319. {
  320. Runtime.PrintStackTrace(uee, Log);
  321. }
  322. }
  323. return str;
  324. }
  325. internal virtual int StringWireLength(string str, int offset)
  326. {
  327. int len = str.Length + 1;
  328. if (UseUnicode)
  329. {
  330. len = str.Length * 2 + 2;
  331. len = (offset % 2) != 0 ? len + 1 : len;
  332. }
  333. return len;
  334. }
  335. internal virtual int ReadStringLength(byte[] src, int srcIndex, int max)
  336. {
  337. int len = 0;
  338. while (src[srcIndex + len] != 0x00)
  339. {
  340. if (len++ > max)
  341. {
  342. throw new RuntimeException("zero termination not found: " + this);
  343. }
  344. }
  345. return len;
  346. }
  347. internal virtual int Encode(byte[] dst, int dstIndex)
  348. {
  349. int start = HeaderStart = dstIndex;
  350. dstIndex += WriteHeaderWireFormat(dst, dstIndex);
  351. WordCount = WriteParameterWordsWireFormat(dst, dstIndex + 1);
  352. dst[dstIndex++] = unchecked((byte)((WordCount / 2) & 0xFF));
  353. dstIndex += WordCount;
  354. WordCount /= 2;
  355. ByteCount = WriteBytesWireFormat(dst, dstIndex + 2);
  356. dst[dstIndex++] = unchecked((byte)(ByteCount & 0xFF));
  357. dst[dstIndex++] = unchecked((byte)((ByteCount >> 8) & 0xFF));
  358. dstIndex += ByteCount;
  359. Length = dstIndex - start;
  360. if (Digest != null)
  361. {
  362. Digest.Sign(dst, HeaderStart, Length, this, Response);
  363. }
  364. return Length;
  365. }
  366. internal virtual int Decode(byte[] buffer, int bufferIndex)
  367. {
  368. int start = HeaderStart = bufferIndex;
  369. bufferIndex += ReadHeaderWireFormat(buffer, bufferIndex);
  370. WordCount = buffer[bufferIndex++];
  371. if (WordCount != 0)
  372. {
  373. int n;
  374. if ((n = ReadParameterWordsWireFormat(buffer, bufferIndex)) != WordCount * 2)
  375. {
  376. if (Log.Level >= 5)
  377. {
  378. Log.WriteLine("wordCount * 2=" + (WordCount * 2) + " but readParameterWordsWireFormat returned "
  379. + n);
  380. }
  381. }
  382. bufferIndex += WordCount * 2;
  383. }
  384. ByteCount = ReadInt2(buffer, bufferIndex);
  385. bufferIndex += 2;
  386. if (ByteCount != 0)
  387. {
  388. int n;
  389. if ((n = ReadBytesWireFormat(buffer, bufferIndex)) != ByteCount)
  390. {
  391. if (Log.Level >= 5)
  392. {
  393. Log.WriteLine("byteCount=" + ByteCount + " but readBytesWireFormat returned " + n
  394. );
  395. }
  396. }
  397. // Don't think we can rely on n being correct here. Must use byteCount.
  398. // Last paragraph of section 3.13.3 eludes to this.
  399. bufferIndex += ByteCount;
  400. }
  401. Length = bufferIndex - start;
  402. return Length;
  403. }
  404. internal virtual int WriteHeaderWireFormat(byte[] dst, int dstIndex)
  405. {
  406. Array.Copy(Header, 0, dst, dstIndex, Header.Length);
  407. dst[dstIndex + SmbConstants.CmdOffset] = Command;
  408. dst[dstIndex + SmbConstants.FlagsOffset] = Flags;
  409. WriteInt2(Flags2, dst, dstIndex + SmbConstants.FlagsOffset + 1);
  410. dstIndex += SmbConstants.TidOffset;
  411. WriteInt2(Tid, dst, dstIndex);
  412. WriteInt2(Pid, dst, dstIndex + 2);
  413. WriteInt2(Uid, dst, dstIndex + 4);
  414. WriteInt2(Mid, dst, dstIndex + 6);
  415. return SmbConstants.HeaderLength;
  416. }
  417. internal virtual int ReadHeaderWireFormat(byte[] buffer, int bufferIndex)
  418. {
  419. Command = buffer[bufferIndex + SmbConstants.CmdOffset];
  420. ErrorCode = ReadInt4(buffer, bufferIndex + SmbConstants.ErrorCodeOffset);
  421. Flags = buffer[bufferIndex + SmbConstants.FlagsOffset];
  422. Flags2 = ReadInt2(buffer, bufferIndex + SmbConstants.FlagsOffset + 1);
  423. Tid = ReadInt2(buffer, bufferIndex + SmbConstants.TidOffset);
  424. Pid = ReadInt2(buffer, bufferIndex + SmbConstants.TidOffset + 2);
  425. Uid = ReadInt2(buffer, bufferIndex + SmbConstants.TidOffset + 4);
  426. Mid = ReadInt2(buffer, bufferIndex + SmbConstants.TidOffset + 6);
  427. return SmbConstants.HeaderLength;
  428. }
  429. internal virtual bool IsResponse()
  430. {
  431. return (Flags & SmbConstants.FlagsResponse) == SmbConstants.FlagsResponse;
  432. }
  433. internal abstract int WriteParameterWordsWireFormat(byte[] dst, int dstIndex);
  434. internal abstract int WriteBytesWireFormat(byte[] dst, int dstIndex);
  435. internal abstract int ReadParameterWordsWireFormat(byte[] buffer, int bufferIndex
  436. );
  437. internal abstract int ReadBytesWireFormat(byte[] buffer, int bufferIndex);
  438. public override int GetHashCode()
  439. {
  440. return Mid;
  441. }
  442. public override bool Equals(object obj)
  443. {
  444. return obj is ServerMessageBlock && ((ServerMessageBlock)obj)
  445. .Mid == Mid;
  446. }
  447. public override string ToString()
  448. {
  449. string c;
  450. switch (Command)
  451. {
  452. case SmbComNegotiate:
  453. {
  454. c = "SMB_COM_NEGOTIATE";
  455. break;
  456. }
  457. case SmbComSessionSetupAndx:
  458. {
  459. c = "SMB_COM_SESSION_SETUP_ANDX";
  460. break;
  461. }
  462. case SmbComTreeConnectAndx:
  463. {
  464. c = "SMB_COM_TREE_CONNECT_ANDX";
  465. break;
  466. }
  467. case SmbComQueryInformation:
  468. {
  469. c = "SMB_COM_QUERY_INFORMATION";
  470. break;
  471. }
  472. case SmbComCheckDirectory:
  473. {
  474. c = "SMB_COM_CHECK_DIRECTORY";
  475. break;
  476. }
  477. case SmbComTransaction:
  478. {
  479. c = "SMB_COM_TRANSACTION";
  480. break;
  481. }
  482. case SmbComTransaction2:
  483. {
  484. c = "SMB_COM_TRANSACTION2";
  485. break;
  486. }
  487. case SmbComTransactionSecondary:
  488. {
  489. c = "SMB_COM_TRANSACTION_SECONDARY";
  490. break;
  491. }
  492. case SmbComFindClose2:
  493. {
  494. c = "SMB_COM_FIND_CLOSE2";
  495. break;
  496. }
  497. case SmbComTreeDisconnect:
  498. {
  499. c = "SMB_COM_TREE_DISCONNECT";
  500. break;
  501. }
  502. case SmbComLogoffAndx:
  503. {
  504. c = "SMB_COM_LOGOFF_ANDX";
  505. break;
  506. }
  507. case SmbComEcho:
  508. {
  509. c = "SMB_COM_ECHO";
  510. break;
  511. }
  512. case SmbComMove:
  513. {
  514. c = "SMB_COM_MOVE";
  515. break;
  516. }
  517. case SmbComRename:
  518. {
  519. c = "SMB_COM_RENAME";
  520. break;
  521. }
  522. case SmbComDelete:
  523. {
  524. c = "SMB_COM_DELETE";
  525. break;
  526. }
  527. case SmbComDeleteDirectory:
  528. {
  529. c = "SMB_COM_DELETE_DIRECTORY";
  530. break;
  531. }
  532. case SmbComNtCreateAndx:
  533. {
  534. c = "SMB_COM_NT_CREATE_ANDX";
  535. break;
  536. }
  537. case SmbComOpenAndx:
  538. {
  539. c = "SMB_COM_OPEN_ANDX";
  540. break;
  541. }
  542. case SmbComReadAndx:
  543. {
  544. c = "SMB_COM_READ_ANDX";
  545. break;
  546. }
  547. case SmbComClose:
  548. {
  549. c = "SMB_COM_CLOSE";
  550. break;
  551. }
  552. case SmbComWriteAndx:
  553. {
  554. c = "SMB_COM_WRITE_ANDX";
  555. break;
  556. }
  557. case SmbComCreateDirectory:
  558. {
  559. c = "SMB_COM_CREATE_DIRECTORY";
  560. break;
  561. }
  562. case SmbComNtTransact:
  563. {
  564. c = "SMB_COM_NT_TRANSACT";
  565. break;
  566. }
  567. case SmbComNtTransactSecondary:
  568. {
  569. c = "SMB_COM_NT_TRANSACT_SECONDARY";
  570. break;
  571. }
  572. default:
  573. {
  574. c = "UNKNOWN";
  575. break;
  576. }
  577. }
  578. string str = ErrorCode == 0 ? "0" : SmbException.GetMessageByCode(ErrorCode);
  579. return "command=" + c + ",received=" + Received + ",errorCode=" + str
  580. + ",flags=0x" + Hexdump.ToHexString(Flags & 0xFF, 4) + ",flags2=0x"
  581. + Hexdump.ToHexString(Flags2, 4) + ",signSeq=" + SignSeq + ",tid=" + Tid + ",pid="
  582. + Pid + ",uid=" + Uid + ",mid=" + Mid + ",wordCount=" + WordCount + ",byteCount="
  583. + ByteCount;
  584. }
  585. }
  586. }