Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

599 lines
21 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. write.c
  5. Abstract:
  6. This module contains functions to manage TFTP write requests
  7. to the service from a client.
  8. Author:
  9. Jeffrey C. Venable, Sr. (jeffv) 01-Jun-2001
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. PTFTPD_BUFFER
  14. TftpdWriteSendAck(PTFTPD_BUFFER buffer) {
  15. PTFTPD_CONTEXT context = buffer->internal.context;
  16. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  17. "TftpdWriteSendAck(buffer = %p): context = %p.\n",
  18. buffer, context));
  19. // NOTE: 'context' must be referenced before this call!
  20. ASSERT(context != NULL);
  21. // If we've gotten all of the data that the client is going to send,
  22. // we should close the file now before sending the final ACK because
  23. // if the client races back and asks for the file in a read request,
  24. // it mail fail due to a sharing violation (we have it open for write).
  25. if ((buffer->message.opcode != TFTPD_WRQ) &&
  26. (TFTPD_DATA_AMOUNT_RECEIVED(buffer) < context->blksize))
  27. TftpdContextKill(context);
  28. // Build the ACK.
  29. buffer->message.opcode = htons(TFTPD_ACK);
  30. buffer->message.ack.block = htons(context->block);
  31. buffer->internal.io.bytes = TFTPD_ACK_SIZE;
  32. // Complete the operation so we can receive the next DATA packet
  33. // if the client responds faster than we can exit sending the ACK.
  34. if (!TftpdProcessComplete(buffer))
  35. goto exit_send_ack;
  36. // Send the ACK.
  37. buffer = TftpdIoSendPacket(buffer);
  38. exit_send_ack :
  39. return (buffer);
  40. } // TftpdWriteSendAck()
  41. void CALLBACK
  42. TftpdWriteOverlappedCompletion(PTFTPD_BUFFER buffer, BOOLEAN timedOut) {
  43. PTFTPD_CONTEXT context = buffer->internal.context;
  44. if (InterlockedCompareExchangePointer(&context->wWait,
  45. INVALID_HANDLE_VALUE, NULL) == NULL)
  46. return;
  47. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  48. "TftpdWriteOverlappedCompletion(buffer = %p, context = %p).\n",
  49. buffer, context));
  50. ASSERT(context->wWait != NULL);
  51. if (!UnregisterWait(context->wWait)) {
  52. DWORD error;
  53. if ((error = GetLastError()) != ERROR_IO_PENDING) {
  54. TFTPD_DEBUG((TFTPD_DBG_PROCESS,
  55. "TftpdWriteOverlappedCompletion(buffer = %p, context = %p): "
  56. "UnregisterWait() failed, error 0x%08X.\n",
  57. buffer, context, error));
  58. TftpdContextKill(context);
  59. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNDEFINED, "Out of memory");
  60. goto exit_write_completion;
  61. }
  62. }
  63. context->wWait = NULL;
  64. if (context->state & TFTPD_STATE_DEAD)
  65. goto exit_write_completion;
  66. context->fileOffset.QuadPart += (context->blksize - context->translationOffset.QuadPart);
  67. buffer = TftpdWriteSendAck(buffer);
  68. exit_write_completion :
  69. if (buffer != NULL)
  70. TftpdIoPostReceiveBuffer(buffer->internal.socket, buffer);
  71. TftpdContextRelease(context);
  72. } // TftpdWriteOverlappedCompletion()
  73. void
  74. TftpdWriteTranslateText(PTFTPD_BUFFER buffer, PDWORD bytes) {
  75. PTFTPD_CONTEXT context = buffer->internal.context;
  76. char *start, *end, *p, *q;
  77. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  78. "TftpdWriteTranslateText(buffer = %p, context = %p): bytes = %d.\n",
  79. buffer, context, *bytes));
  80. // NOTE: 'context' must be referenced before this call!
  81. ASSERT(context != NULL);
  82. ASSERT(*bytes > 0);
  83. //
  84. // Text (translated) mode :
  85. // The data received is in NVT-ASCII format. There should be no solitary LF's
  86. // to worry about, and solitary CR's would have had a '\0' appended to them.
  87. // Cases to worry about:
  88. // (a) CR + '\0' -> CR (strip '\0')
  89. // (b) Dangling CR at the end of a previously converted buffer which affects
  90. // the output of the first character of the following buffer.
  91. // We can do the conversion in-place.
  92. //
  93. // Convert the data in-place.
  94. start = (char *)&buffer->message.data.data;
  95. end = (start + *bytes);
  96. p = q = start;
  97. context->translationOffset.QuadPart = 0;
  98. if (start == end)
  99. return;
  100. if (context->danglingCR) {
  101. context->danglingCR = FALSE;
  102. if (*p == '\0') {
  103. p++; // This is a CR + '\0' combination, strip the '\0'.
  104. // Count the lost byte.
  105. context->translationOffset.QuadPart++;
  106. (*bytes)--;
  107. }
  108. }
  109. while (p < end) {
  110. while ((p < end) && (*p != '\0')) { *q++ = *p++; }
  111. if (p == end)
  112. break;
  113. if ((p > start) && (*(p - 1) == '\r')) {
  114. p++; // This is a CR + '\0' combination, strip the '\0'.
  115. // Count the lost byte.
  116. context->translationOffset.QuadPart++;
  117. (*bytes)--;
  118. continue;
  119. }
  120. // This is a solitary '\0', just copy it.
  121. *q++ = *p++;
  122. } // while (p < end)
  123. if (*(end - 1) == '\r')
  124. context->danglingCR = TRUE;
  125. } // TftpdWriteTranslateText()
  126. PTFTPD_BUFFER
  127. TftpdWriteResume(PTFTPD_BUFFER buffer) {
  128. PTFTPD_CONTEXT context = buffer->internal.context;
  129. DWORD error = NO_ERROR, size = 0;
  130. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  131. "TftpdWriteResume(buffer = %p, context = %p).\n",
  132. buffer, context));
  133. // NOTE: 'context' must be referenced before this call!
  134. ASSERT(context != NULL);
  135. // If we need to start the transfer with an OACK, do so now.
  136. if (context->options) {
  137. buffer = TftpdUtilSendOackPacket(buffer);
  138. goto exit_resume_write;
  139. }
  140. if (buffer->message.opcode == TFTPD_WRQ)
  141. goto send_ack;
  142. // Determine size of data to write.
  143. ASSERT(buffer->internal.io.bytes >= TFTPD_MIN_RECEIVED_DATA);
  144. size = TFTPD_DATA_AMOUNT_RECEIVED(buffer);
  145. if (size == 0)
  146. goto send_ack;
  147. if (context->mode == TFTPD_MODE_TEXT)
  148. TftpdWriteTranslateText(buffer, &size);
  149. // Prepare the overlapped write.
  150. buffer->internal.io.overlapped.OffsetHigh = context->fileOffset.HighPart;
  151. buffer->internal.io.overlapped.Offset = context->fileOffset.LowPart;
  152. buffer->internal.io.overlapped.hEvent = context->hWait;
  153. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  154. "TftpdWriteResume(buffer = %p): "
  155. "WriteFile(bytes = %d, offset = %d).\n",
  156. buffer, size, context->fileOffset.LowPart));
  157. // Perform the write operation.
  158. if (!WriteFile(context->hFile,
  159. &buffer->message.data.data,
  160. size,
  161. NULL,
  162. &buffer->internal.io.overlapped))
  163. error = GetLastError();
  164. if ((error != NO_ERROR) && (error != ERROR_IO_PENDING)) {
  165. TFTPD_DEBUG((TFTPD_DBG_PROCESS,
  166. "TftpdWriteResume(context = %p, buffer = %p): "
  167. "WriteFile() failed, error 0x%08X.\n",
  168. context, buffer, error));
  169. TftpdContextKill(context);
  170. TftpdIoSendErrorPacket(buffer,
  171. TFTPD_ERROR_DISK_FULL,
  172. "Disk full or allocation exceeded");
  173. goto exit_resume_write;
  174. }
  175. if (error == ERROR_IO_PENDING) {
  176. HANDLE wait = NULL;
  177. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  178. "TftpdWriteResume(buffer = %p): ERROR_IO_PENDING.\n",
  179. buffer));
  180. // Keep an overlapped-operation reference to the context (ie, don't release context).
  181. TftpdContextAddReference(context);
  182. // Register a wait for completion.
  183. ASSERT(context->wWait == NULL);
  184. if (!RegisterWaitForSingleObject(&wait,
  185. context->hWait,
  186. (WAITORTIMERCALLBACKFUNC)TftpdWriteOverlappedCompletion,
  187. buffer,
  188. INFINITE,
  189. (WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE))) {
  190. TFTPD_DEBUG((TFTPD_DBG_PROCESS,
  191. "TftpdWriteResume(context = %p, buffer = %p): "
  192. "RegisterWaitForSingleObject() failed, error 0x%08X.\n",
  193. context, buffer, GetLastError()));
  194. // Reclaim the overlapped operation reference.
  195. TftpdContextKill(context);
  196. TftpdContextRelease(context);
  197. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNDEFINED, "Out of memory");
  198. // Buffer will get leaked.
  199. buffer = NULL; // Buffer is being used for overlapped operation.
  200. goto exit_resume_write;
  201. }
  202. // Did the completion callback already fire before we could save the wait handle
  203. // into the context so it cannot deregister the wait?
  204. if (InterlockedExchangePointer(&context->wWait, wait) != INVALID_HANDLE_VALUE) {
  205. buffer = NULL; // Buffer is being used for overlapped operation.
  206. goto exit_resume_write;
  207. }
  208. // Reclaim the overlapped operation reference.
  209. TftpdContextRelease(context);
  210. if (!UnregisterWait(context->wWait)) {
  211. if ((error = GetLastError()) != ERROR_IO_PENDING) {
  212. TFTPD_DEBUG((TFTPD_DBG_PROCESS,
  213. "TftpdWriteResume(context = %p, buffer = %p): "
  214. "UnregisterWait() failed, error 0x%08X.\n",
  215. context, buffer, error));
  216. TftpdContextKill(context);
  217. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNDEFINED, "Out of memory");
  218. // TftpdContextLeak(context);
  219. buffer = NULL; // Buffer is being used for overlapped operation.
  220. goto exit_resume_write;
  221. }
  222. }
  223. context->wWait = NULL;
  224. // Whoever deregisters the wait proceeds with the operation.
  225. } // if (error == ERROR_IO_PENDING)
  226. //
  227. // Write file completed immediately.
  228. //
  229. context->fileOffset.QuadPart += (context->blksize - context->translationOffset.QuadPart);
  230. send_ack :
  231. buffer = TftpdWriteSendAck(buffer);
  232. exit_resume_write :
  233. return (buffer);
  234. } // TftpdWriteResume()
  235. PTFTPD_BUFFER
  236. TftpdWriteData(PTFTPD_BUFFER buffer) {
  237. PTFTPD_CONTEXT context = NULL;
  238. // Ensure that a DATA isn't send to the master socket.
  239. if (buffer->internal.socket == &globals.io.master) {
  240. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_ILLEGAL_OPERATION, "Illegal TFTP operation");
  241. goto exit_data;
  242. }
  243. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  244. "TftpdWriteData(buffer = %p): bytes = %d.\n",
  245. buffer, buffer->internal.io.bytes));
  246. //
  247. // Validate context.
  248. //
  249. context = TftpdContextAquire(&buffer->internal.io.peer);
  250. if (context == NULL) {
  251. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  252. "TftpdWriteData(buffer = %p): Received DATA for non-existant context.\n",
  253. buffer));
  254. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNKNOWN_TRANSFER_ID, "Unknown transfer ID");
  255. goto exit_data;
  256. }
  257. // Is this a WRQ context?
  258. if (context->type != TFTPD_WRQ) {
  259. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  260. "TftpdWriteData(buffer = %p): Received DATA for non-WRQ context.\n",
  261. buffer));
  262. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNKNOWN_TRANSFER_ID, "Unknown transfer ID");
  263. goto exit_data;
  264. }
  265. //
  266. // Validate DATA packet.
  267. //
  268. // If we sent an OACK, the DATA had better be block 1.
  269. if (context->options && (buffer->message.data.block != 1)) {
  270. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  271. "TftpdWriteData: Ignoring DATA buffer = %p, "
  272. "expected block 1 for acknowledgement of issued OACK.\n",
  273. buffer));
  274. goto exit_data;
  275. }
  276. //
  277. // Aquire busy-sending state.
  278. //
  279. do {
  280. USHORT block = context->block;
  281. if (context->state & (TFTPD_STATE_BUSY | TFTPD_STATE_DEAD))
  282. goto exit_data;
  283. // Is it for the correct block? The client can send DATA following
  284. // the ACK we just sent, or it could resend DATA which would cause us
  285. // to resend that ACK again meaning it never saw the ACK we just sent
  286. // in which case we just need to resend it. If the DATA block is
  287. // equal to our internal block number, we just need to resend it.
  288. // If the DATA block is equal to our internal block number plus one,
  289. // it's new DATA so increment our internal block number and
  290. // ACK it. Note that a DATA to our OACK will be with block 1.
  291. if ((buffer->message.data.block != block) &&
  292. (buffer->message.data.block != (USHORT)(block + 1)))
  293. goto exit_data;
  294. } while (InterlockedCompareExchange(&context->state, TFTPD_STATE_BUSY, 0) != 0);
  295. //
  296. // Update state.
  297. //
  298. // Prevent the transmission of an OACK.
  299. context->options = 0;
  300. // Client has responded to us with acceptable DATA packet, reset timeout counter.
  301. context->retransmissions = 0;
  302. //
  303. // Write data and/or send ACK.
  304. //
  305. // Keep track of the context for the pending ACK we need to issue.
  306. buffer->internal.context = context;
  307. if (buffer->message.data.block == (USHORT)(context->block + 1)) {
  308. context->block++;
  309. context->sorcerer = buffer->message.data.block;
  310. buffer = TftpdWriteResume(buffer);
  311. } else {
  312. // RFC 1123. This is a DATA for the previous block number.
  313. // Our ACK packet may have been lost, or is merely taking the
  314. // scenic route through the network. Go ahead and resend a
  315. // ACK packet in response to this DATA, however record the
  316. // block number for which this occurred as a form of history
  317. // tracking. Should this occur again in the following block
  318. // number, we've fallen into the "Sorcerer's Apprentice" bug,
  319. // and we will break it by ignoring the secondary DATA of the
  320. // sequence. However, we must be careful not to break
  321. // authentic resend requests, so after dropping an DATA in
  322. // an attempt to break the "Sorcerer's Apprentice" bug, we
  323. // will resume sending ACK packets in response and then
  324. // revert back to watching for the bug again.
  325. if (buffer->message.data.block == context->sorcerer) {
  326. #if defined(DBG)
  327. InterlockedIncrement(&globals.performance.sorcerersApprentice);
  328. #endif // defined(DBG)
  329. context->sorcerer--;
  330. // Do NOT send the ACK this time.
  331. buffer->internal.context = context;
  332. TftpdProcessComplete(buffer);
  333. goto exit_data;
  334. } else {
  335. context->sorcerer = buffer->message.data.block;
  336. }
  337. buffer = TftpdWriteSendAck(buffer);
  338. } // if (buffer->message.data.block == (USHORT)(context->block + 1))
  339. exit_data :
  340. if (context != NULL)
  341. TftpdContextRelease(context);
  342. return (buffer);
  343. } // TftpdWriteData()
  344. PTFTPD_BUFFER
  345. TftpdWriteRequest(PTFTPD_BUFFER buffer) {
  346. PTFTPD_CONTEXT context = NULL;
  347. NTSTATUS status;
  348. // Ensure that a WRQ is from the master socket only.
  349. if (buffer->internal.socket != &globals.io.master) {
  350. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_ILLEGAL_OPERATION,
  351. "Illegal TFTP operation");
  352. goto exit_write_request;
  353. }
  354. // Is this a duplicate request? Do we ignore it or send an error?
  355. if ((context = TftpdContextAquire(&buffer->internal.io.peer)) != NULL) {
  356. if (context->block > 0)
  357. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_ILLEGAL_OPERATION,
  358. "Illegal TFTP operation");
  359. TftpdContextRelease(context);
  360. context = NULL;
  361. goto exit_write_request;
  362. }
  363. // Allocate a context for this request (this gives us a reference to it as well).
  364. if ((context = (PTFTPD_CONTEXT)TftpdContextAllocate()) == NULL)
  365. goto exit_write_request;
  366. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  367. "TftpdWriteRequest(buffer = %p): context = %p.\n",
  368. buffer, context));
  369. // Initialize the context.
  370. context->type = TFTPD_WRQ;
  371. context->state = TFTPD_STATE_BUSY;
  372. CopyMemory(&context->peer, &buffer->internal.io.peer, sizeof(context->peer));
  373. // Obtain and validate the requested filename, mode, and options.
  374. if (!TftpdUtilGetFileModeAndOptions(context, buffer)) {
  375. TFTPD_DEBUG((TFTPD_DBG_PROCESS,
  376. "TftpdWriteRequest(buffer = %p): Invalid file mode = %d.\n",
  377. buffer, context->mode));
  378. goto exit_write_request;
  379. }
  380. // Figure out which socket to use for this request (based on blksize).
  381. if (!TftpdIoAssignSocket(context, buffer)) {
  382. TFTPD_DEBUG((TFTPD_DBG_PROCESS,
  383. "TftpdWriteRequest(buffer = %p): "
  384. "TftpdIoAssignSocket() failed.\n",
  385. buffer));
  386. goto exit_write_request;
  387. }
  388. // Check whether access is permitted.
  389. if (!TftpdUtilMatch(globals.parameters.validMasters, inet_ntoa(context->peer.sin_addr)) ||
  390. !TftpdUtilMatch(globals.parameters.validWriteFiles, context->filename)) {
  391. TFTPD_DEBUG((TFTPD_DBG_PROCESS,
  392. "TftpdWriteRequest(buffer = %p): Access denied.\n",
  393. buffer));
  394. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_ACCESS_VIOLATION,
  395. "Access violation");
  396. goto exit_write_request;
  397. }
  398. // Open the file.
  399. context->hFile = CreateFile(context->filename, GENERIC_WRITE, 0, NULL, CREATE_NEW,
  400. FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED, NULL);
  401. if (context->hFile == INVALID_HANDLE_VALUE) {
  402. TFTPD_DEBUG((TFTPD_DBG_PROCESS,
  403. "TftpdWriteRequest(buffer = %p): "
  404. "File name = %s not found, error = 0x%08X.\n",
  405. buffer, context->filename, GetLastError()));
  406. if (GetLastError() == ERROR_ALREADY_EXISTS)
  407. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_FILE_EXISTS, "Cannot overwrite file.");
  408. else
  409. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_ACCESS_VIOLATION, "Access violation.");
  410. context->hFile = NULL;
  411. goto exit_write_request;
  412. }
  413. // Create the WriteFile() wait event.
  414. if ((context->hWait = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
  415. TFTPD_DEBUG((TFTPD_DBG_PROCESS,
  416. "TftpdWriteRequest(buffer = %p): "
  417. "CreateEvent() failed, error = %d.\n",
  418. buffer, GetLastError()));
  419. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNDEFINED, "Out of memory");
  420. goto exit_write_request;
  421. }
  422. // Insert the context into the hash-table.
  423. if (!TftpdContextAdd(context)) {
  424. TFTPD_DEBUG((TFTPD_TRACE_PROCESS,
  425. "TftpdWriteRequest(buffer = %p): "
  426. "Dropping request as we're already servicing it.\n",
  427. buffer));
  428. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNDEFINED,
  429. "Illegal TFTP operation");
  430. goto exit_write_request;
  431. }
  432. // Start the retransmission timer.
  433. if (!CreateTimerQueueTimer(&context->hTimer,
  434. globals.io.hTimerQueue,
  435. (WAITORTIMERCALLBACKFUNC)TftpdProcessTimeout,
  436. context,
  437. context->timeout,
  438. 720000,
  439. WT_EXECUTEINIOTHREAD)) {
  440. TftpdContextKill(context);
  441. context = NULL;
  442. TftpdIoSendErrorPacket(buffer, TFTPD_ERROR_UNDEFINED,
  443. "Unable to initiate timeout timer.");
  444. goto exit_write_request;
  445. } // if (NT_SUCCESS(status))
  446. // Add our own reference to the context.
  447. TftpdContextAddReference(context);
  448. // If 'context->options' is non-zero, TftpdResumeWrite() will issue an OACK
  449. // instead of an ACK packet. The subsquent DATA to the OACK will clear the
  450. // flags which will allow it to begin issuing subsequent ACK packets.
  451. buffer->internal.context = context;
  452. buffer = TftpdWriteResume(buffer);
  453. // Free our own reference to the context.
  454. TftpdContextRelease(context);
  455. // If buffer != NULL, it gets recycled if possible.
  456. return (buffer);
  457. exit_write_request :
  458. if (context != NULL)
  459. TftpdContextFree(context);
  460. // If buffer != NULL, it gets recycled if possible.
  461. return (buffer);
  462. } // TftpdWriteRequest()