Source code of Windows XP (NT5)
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.

4471 lines
117 KiB

  1. /*++
  2. Copyright (c) 1992-1996 Microsoft Corporation
  3. Module Name:
  4. tftpd.c
  5. Abstract:
  6. This implements an RFC 783 tftp daemon. The tftp daemon listens on it's
  7. well-known port waiting for requests. When a valid request comes in, it
  8. spawns a thread to process the request.
  9. Functions Defined:
  10. TftpdErrorPacket - sends an error reply.
  11. TftpdDoRead - read from file and convert.
  12. TftpdHandleRead - incoming read file request.
  13. read file => sendto.
  14. TftpdDoWrite - convert and write to file.
  15. TftpdHandleWrite - incoming write file request, calls TftpdDoWrite().
  16. Author: Sam Patton (sampa) 08-apr-1992
  17. Revision History:
  18. MohsinA, 02-Dec-96.
  19. --*/
  20. #include "tftpd.h"
  21. #if defined(REMOTE_BOOT_SECURITY)
  22. #include <ipsec.h>
  23. #endif // defined(REMOTE_BOOT_SECURITY)
  24. extern TFTP_GLOBALS Globals;
  25. char * ErrorString[NUM_TFTP_ERROR_CODES] =
  26. {
  27. "Error undefined",
  28. "File not found",
  29. "Access violation",
  30. "Disk full or allocation exceeded",
  31. "Illegal TFTP operation",
  32. "Unknown transfer ID",
  33. "File already exists",
  34. "No such user",
  35. "Option negotiation failure"
  36. };
  37. #if defined(REMOTE_BOOT_SECURITY)
  38. //
  39. // These routines manage the security info structures for clients
  40. // thay have logged in. I put all the code that deals with how the
  41. // structures are actually stored in these functions, in case I
  42. // change it.
  43. //
  44. PTFTPD_SECURITY SecurityArray = NULL;
  45. USHORT SecurityArrayLength = 0;
  46. USHORT SecurityValidation;
  47. CRITICAL_SECTION SecurityCriticalSection;
  48. #define INITIAL_SECURITY_ARRAY_SIZE 8
  49. UCHAR
  50. TftpdHexDigitToChar(
  51. PUCHAR HexDigit
  52. )
  53. {
  54. UCHAR Nibble;
  55. UCHAR ReturnValue = 0;
  56. int i;
  57. for (i = 0; i < 2; i++) {
  58. if ((HexDigit[i] >= '0') && (HexDigit[i] <= '9')) {
  59. Nibble = (UCHAR)(HexDigit[i] - '0');
  60. } else if ((HexDigit[i] >= 'a') && (HexDigit[i] <= 'f')) {
  61. Nibble = (UCHAR)(HexDigit[i] - 'a' + 10);
  62. } else if ((HexDigit[i] >= 'A') && (HexDigit[i] <= 'F')) {
  63. Nibble = (UCHAR)(HexDigit[i] - 'A' + 10);
  64. } else {
  65. Nibble = 0;
  66. }
  67. ReturnValue = (UCHAR)((ReturnValue << 4) + Nibble);
  68. }
  69. return ReturnValue;
  70. }
  71. BOOL
  72. TftpdInitSecurityArray(
  73. VOID
  74. )
  75. {
  76. int i;
  77. SecurityArray = (PTFTPD_SECURITY)malloc(sizeof(TFTPD_SECURITY) * INITIAL_SECURITY_ARRAY_SIZE);
  78. if (SecurityArray == NULL) {
  79. DbgPrint("TftpdInitSecurityArray: cannot allocate security array\n");
  80. return FALSE;
  81. }
  82. for (i = 0; i < INITIAL_SECURITY_ARRAY_SIZE; i++) {
  83. SecurityArray[i].Validation = 0; // means this entry is free
  84. SecurityArray[i].LastFileRead[0] = '\0';
  85. }
  86. SecurityArrayLength = INITIAL_SECURITY_ARRAY_SIZE;
  87. srand((unsigned)time(NULL));
  88. SecurityValidation = (USHORT)rand();
  89. RtlInitializeCriticalSection(&SecurityCriticalSection);
  90. return TRUE;
  91. }
  92. VOID
  93. TftpdUninitSecurityArray(
  94. VOID
  95. )
  96. {
  97. free(SecurityArray);
  98. }
  99. BOOL
  100. TftpdAllocateSecurityEntry(
  101. PUSHORT Index,
  102. PTFTPD_SECURITY Security
  103. )
  104. {
  105. USHORT i, j;
  106. RtlEnterCriticalSection (&SecurityCriticalSection);
  107. for (i = 0; i < SecurityArrayLength; i++) {
  108. if (SecurityArray[i].Validation == 0) {
  109. break;
  110. }
  111. }
  112. if (i == SecurityArrayLength) {
  113. PTFTPD_SECURITY NewSecurity;
  114. USHORT NewSecurityLength;
  115. //
  116. // Could not find a spot, double the array.
  117. //
  118. if (SecurityArrayLength < 0x8000) {
  119. NewSecurityLength = SecurityArrayLength * 2;
  120. } else {
  121. NewSecurityLength = 0xffff;
  122. }
  123. NewSecurity = malloc(sizeof(TFTPD_SECURITY) * NewSecurityLength);
  124. if (NewSecurity == NULL) {
  125. RtlLeaveCriticalSection (&SecurityCriticalSection);
  126. return FALSE;
  127. }
  128. memcpy(NewSecurity, SecurityArray, sizeof(TFTPD_SECURITY) * SecurityArrayLength);
  129. i = SecurityArrayLength;
  130. for (j = SecurityArrayLength; j < NewSecurityLength; j++) {
  131. NewSecurity[j].Validation = 0; // means this entry is free
  132. NewSecurity[j].LastFileRead[0] = '\0';
  133. }
  134. SecurityArray = NewSecurity;
  135. SecurityArrayLength = NewSecurityLength;
  136. }
  137. SecurityArray[i].Validation = SecurityValidation;
  138. SecurityArray[i].CredentialsHandleValid = FALSE;
  139. SecurityArray[i].ServerContextHandleValid = FALSE;
  140. SecurityArray[i].GeneratedKey = FALSE;
  141. SecurityValidation = (SecurityValidation % 10000) + 1;
  142. *Security = SecurityArray[i];
  143. RtlLeaveCriticalSection (&SecurityCriticalSection);
  144. *Index = i;
  145. return TRUE;
  146. }
  147. VOID
  148. TftpdFreeSecurityEntry(
  149. USHORT Index
  150. )
  151. {
  152. TFTPD_SECURITY TempSecurity; // save it so we can leave the critical section
  153. RtlEnterCriticalSection (&SecurityCriticalSection);
  154. if (Index < SecurityArrayLength) {
  155. TempSecurity = SecurityArray[Index];
  156. SecurityArray[Index].Validation = 0; // this marks it as free
  157. RtlLeaveCriticalSection (&SecurityCriticalSection);
  158. if (TempSecurity.ServerContextHandleValid) {
  159. DeleteSecurityContext(&TempSecurity.ServerContextHandle);
  160. }
  161. if (TempSecurity.CredentialsHandleValid) {
  162. FreeCredentialsHandle(&TempSecurity.CredentialsHandle);
  163. }
  164. } else {
  165. RtlLeaveCriticalSection (&SecurityCriticalSection);
  166. }
  167. }
  168. VOID
  169. TftpdGetSecurityEntry(
  170. USHORT Index,
  171. PTFTPD_SECURITY Security
  172. )
  173. {
  174. RtlEnterCriticalSection (&SecurityCriticalSection);
  175. if (Index < SecurityArrayLength) {
  176. *Security = SecurityArray[Index];
  177. } else {
  178. memset(Security, 0, sizeof(TFTPD_SECURITY));
  179. }
  180. RtlLeaveCriticalSection (&SecurityCriticalSection);
  181. }
  182. VOID
  183. TftpdStoreSecurityEntry(
  184. USHORT Index,
  185. PTFTPD_SECURITY Security
  186. )
  187. {
  188. RtlEnterCriticalSection (&SecurityCriticalSection);
  189. if (Index < SecurityArrayLength) {
  190. SecurityArray[Index] = *Security;
  191. }
  192. RtlLeaveCriticalSection (&SecurityCriticalSection);
  193. }
  194. VOID
  195. TftpdGenerateKeyForSecurityEntry(
  196. USHORT Index,
  197. PTFTPD_SECURITY Security
  198. )
  199. {
  200. SecBufferDesc SignMessage;
  201. SecBuffer SigBuffers[2];
  202. SECURITY_STATUS SecStatus;
  203. LARGE_INTEGER SystemTime;
  204. RtlEnterCriticalSection (&SecurityCriticalSection);
  205. if (Index < SecurityArrayLength) {
  206. if (!SecurityArray[Index].GeneratedKey) {
  207. //
  208. // Generate and sign a key.
  209. //
  210. NtQuerySystemTime(&SystemTime);
  211. SecurityArray[Index].Key = (ULONG)(SystemTime.QuadPart % SecurityArray[Index].ForeignAddress.sin_addr.s_addr);
  212. *(PULONG)(SecurityArray[Index].SignedKey) = SecurityArray[Index].Key;
  213. SigBuffers[0].pvBuffer = SecurityArray[Index].SignedKey;
  214. SigBuffers[0].cbBuffer = sizeof(SecurityArray[Index].SignedKey);
  215. SigBuffers[0].BufferType = SECBUFFER_DATA;
  216. SigBuffers[1].pvBuffer = SecurityArray[Index].Sign;
  217. SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  218. SigBuffers[1].BufferType = SECBUFFER_TOKEN;
  219. SignMessage.pBuffers = SigBuffers;
  220. SignMessage.cBuffers = 2;
  221. SignMessage.ulVersion = 0;
  222. SecStatus = SealMessage(
  223. &(SecurityArray[Index].ServerContextHandle),
  224. 0,
  225. &SignMessage,
  226. 0 );
  227. if (SecStatus == STATUS_SUCCESS) {
  228. SecurityArray[Index].GeneratedKey = TRUE;
  229. }
  230. }
  231. *Security = SecurityArray[Index];
  232. } else {
  233. memset(Security, 0, sizeof(TFTPD_SECURITY));
  234. }
  235. RtlLeaveCriticalSection (&SecurityCriticalSection);
  236. }
  237. SECURITY_STATUS
  238. TftpdVerifyFileSignature(
  239. USHORT Index,
  240. USHORT Validation,
  241. PTFTPD_SECURITY Security,
  242. char * FileName,
  243. char * Sign,
  244. USHORT ClientPort
  245. )
  246. {
  247. unsigned long FileNameLength;
  248. char * CompareFileName;
  249. SecBufferDesc SignMessage;
  250. SecBuffer SigBuffers[2];
  251. SECURITY_STATUS SecStatus;
  252. PTFTPD_SECURITY TmpSecurity; // points to the real location in the array
  253. //
  254. // First figure out where the last 64 characters of the
  255. // requested filename are since that is all we save.
  256. //
  257. FileNameLength = strlen(FileName);
  258. if (FileNameLength < sizeof(Security->LastFileRead)) {
  259. CompareFileName = FileName;
  260. } else {
  261. CompareFileName = FileName + (FileNameLength + 1 - sizeof(Security->LastFileRead));
  262. }
  263. //
  264. // Make sure that the sign for the filename is valid. If this
  265. // is the same as the last filename requested for this security
  266. // entry, and it is coming in on the same port as before,
  267. // then we assume the client is retransmitting the request,
  268. // so therefore has not re-generated the sign, so we just compare
  269. // the sign with the one he sent last time instead of calling
  270. // VerifySignature again (to prevent us getting unbalanced with
  271. // his MakeSignature call).
  272. //
  273. RtlEnterCriticalSection (&SecurityCriticalSection);
  274. if ((Index < SecurityArrayLength) &&
  275. (SecurityArray[Index].Validation == Validation)) {
  276. TmpSecurity = &SecurityArray[Index];
  277. } else {
  278. memset(Security, 0, sizeof(TFTPD_SECURITY));
  279. return (SECURITY_STATUS)STATUS_INVALID_HANDLE;
  280. }
  281. if ((strcmp(CompareFileName, TmpSecurity->LastFileRead) == 0) &&
  282. (ClientPort == TmpSecurity->LastFileReadPort)) {
  283. //
  284. // Compare them, and fake a security error if they don't match.
  285. //
  286. if (memcmp(TmpSecurity->LastFileSign, Sign, NTLMSSP_MESSAGE_SIGNATURE_SIZE) == 0) {
  287. SecStatus = SEC_E_OK;
  288. } else {
  289. SecStatus = SEC_E_MESSAGE_ALTERED;
  290. }
  291. } else {
  292. //
  293. // Save the values in case this request is resent.
  294. //
  295. strcpy(TmpSecurity->LastFileRead, CompareFileName);
  296. memcpy(TmpSecurity->LastFileSign, Sign, NTLMSSP_MESSAGE_SIGNATURE_SIZE);
  297. TmpSecurity->LastFileReadPort = ClientPort;
  298. //
  299. // Now make sure the signature is correct.
  300. //
  301. SigBuffers[1].pvBuffer = Sign;
  302. SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  303. SigBuffers[1].BufferType = SECBUFFER_TOKEN;
  304. SigBuffers[0].pvBuffer = FileName;
  305. SigBuffers[0].cbBuffer = FileNameLength;
  306. SigBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  307. SignMessage.pBuffers = SigBuffers;
  308. SignMessage.cBuffers = 2;
  309. SignMessage.ulVersion = 0;
  310. SecStatus = VerifySignature(
  311. &TmpSecurity->ServerContextHandle,
  312. &SignMessage,
  313. 0,
  314. 0 );
  315. }
  316. *Security = *TmpSecurity;
  317. RtlLeaveCriticalSection (&SecurityCriticalSection);
  318. return SecStatus;
  319. }
  320. #endif // defined(REMOTE_BOOT_SECURITY)
  321. // ========================================================================
  322. VOID
  323. TftpdErrorPacket(
  324. struct sockaddr * PeerAddress,
  325. char * RequestPacket,
  326. SOCKET LocalSocket,
  327. unsigned short ErrorCode,
  328. char * ErrorMessage OPTIONAL
  329. )
  330. /*++
  331. Routine Description:
  332. This sends an error packet back to the person who sent the request. The
  333. RequestPacket is used to select an appropriate error code.
  334. Arguments:
  335. PeerAddress - The remote address
  336. RequestPacket - packet making the request
  337. LocalSocket - socket to send error from
  338. Return Value:
  339. None
  340. Error?
  341. --*/
  342. {
  343. char ErrorPacket[MAX_TFTP_DATAGRAM];
  344. int err;
  345. int errorLength;
  346. ((unsigned short *) ErrorPacket)[0] = htons(TFTPD_ERROR);
  347. ((unsigned short *) ErrorPacket)[1] = htons(ErrorCode);
  348. DbgPrint("TftpdError: Sending error packet Error Code: %d",ErrorCode);
  349. if ( ErrorMessage != NULL ) {
  350. strcpy(&ErrorPacket[4], ErrorMessage);
  351. errorLength = strlen(ErrorMessage);
  352. } else {
  353. if (ErrorCode >= NUM_TFTP_ERROR_CODES) {
  354. DbgPrint("TftpdErrorPacket: Unknown ErrorCode=%d.\n",
  355. ErrorCode );
  356. ErrorCode = 0;
  357. }
  358. strcpy(&ErrorPacket[4], ErrorString[ErrorCode]);
  359. errorLength = strlen(ErrorString[ErrorCode]);
  360. }
  361. err = sendto(
  362. LocalSocket,
  363. ErrorPacket,
  364. 5 + errorLength,
  365. 0,
  366. PeerAddress,
  367. sizeof(struct sockaddr_in));
  368. if( SOCKET_ERROR == err ){
  369. DbgPrint("TftpdErrorPacket: sendto failed=%d\n",
  370. WSAGetLastError() );
  371. }
  372. return;
  373. }
  374. #if defined(REMOTE_BOOT_SECURITY)
  375. int
  376. TftpdProcessOptionsPhase1(
  377. PTFTP_REQUEST Request,
  378. PUCHAR Options,
  379. int Opcode
  380. )
  381. {
  382. int i;
  383. //
  384. // Assume default values.
  385. //
  386. Request->SecurityHandle = 0;
  387. //
  388. // Walk through the remainder of the request packet, looking for options
  389. // that we need to process in phase 1.
  390. //
  391. while ( *Options != 0 ) {
  392. if ( _stricmp(Options, "security") == 0 ) {
  393. Options += sizeof("security");
  394. if ( Opcode == TFTPD_RRQ ) {
  395. Request->SecurityHandle = atoi(Options);
  396. }
  397. Options += strlen(Options) + 1;
  398. } else if ( _stricmp(Options, "sign") == 0 ) {
  399. Options += sizeof("sign");
  400. if ( Opcode == TFTPD_RRQ ) {
  401. for (i = 0; i < NTLMSSP_MESSAGE_SIGNATURE_SIZE; i++) {
  402. Request->Sign[i] = TftpdHexDigitToChar(&Options[i*2]);
  403. }
  404. }
  405. Options += strlen(Options) + 1;
  406. } else {
  407. //
  408. // Unrecognized option. Skip the option ID and the value.
  409. //
  410. Options += strlen(Options) + 1;
  411. if ( *Options != 0 ) {
  412. Options += strlen(Options) + 1;
  413. }
  414. }
  415. }
  416. return 0;
  417. }
  418. #endif // defined(REMOTE_BOOT_SECURITY)
  419. int
  420. TftpdProcessOptionsPhase2(
  421. PTFTP_REQUEST Request,
  422. PUCHAR Options,
  423. int Opcode,
  424. int *OackLength,
  425. char *PacketBuffer,
  426. BOOL *ReceivedTimeoutOption
  427. )
  428. {
  429. PUCHAR oack;
  430. //
  431. // Assume default values.
  432. //
  433. Request->BlockSize = MAX_OACK_PACKET_LENGTH - 4; // Save an alloc mem by default to the current packet size.
  434. Request->Timeout = 10;
  435. *ReceivedTimeoutOption=FALSE;
  436. //
  437. // Build the OACK header.
  438. //
  439. memset( PacketBuffer, 0, MAX_OACK_PACKET_LENGTH );
  440. ((unsigned short *)PacketBuffer)[0] = htons(TFTPD_OACK);
  441. oack = &PacketBuffer[2];
  442. //
  443. // Walk through the remainder of the request packet, looking for options
  444. // that we understand.
  445. //
  446. while ( *Options != 0 ) {
  447. if ( _stricmp(Options, "blksize") == 0 ) {
  448. strcpy( oack, Options );
  449. oack += sizeof("blksize");
  450. Options += sizeof("blksize");
  451. Request->BlockSize = atoi(Options);
  452. if ( (Request->BlockSize < 8) ||
  453. (Request->BlockSize > 65464) ) {
  454. DbgPrint("TftpdProcessOptionsPhase2: invalid blksize=%s\n", Options );
  455. TftpdErrorPacket(
  456. (struct sockaddr *)&Request->ForeignAddress,
  457. Request->Packet2,
  458. Request->TftpdPort,
  459. TFTPD_ERROR_OPTION_NEGOT_FAILED,
  460. NULL);
  461. return -1;
  462. }
  463. //
  464. // Workaround for problem in .98 version of ROM, which
  465. // doesn't like our OACK response. If the requested blksize is
  466. // 1456, pretend that the option wasn't specified. In the case
  467. // of the ROM's TFTP layer, this is the only option specified,
  468. // so ignoring it will mean that we don't send an OACK, and the
  469. // ROM will deign to talk to us. Note that our TFTP code uses
  470. // a blksize of 1432, so this workaround won't affect us.
  471. //
  472. if ( Request->BlockSize == 1456 ) {
  473. Request->BlockSize = MAX_OACK_PACKET_LENGTH - 4;
  474. oack -= sizeof("blksize");
  475. Options += strlen(Options) + 1;
  476. continue;
  477. }
  478. if ( Request->BlockSize > MAX_TFTP_DATA ) {
  479. Request->BlockSize = MAX_TFTP_DATA;
  480. }
  481. _itoa( Request->BlockSize, oack, 10 );
  482. oack += strlen(oack) + 1;
  483. Options += strlen(Options) + 1;
  484. } else if ( _stricmp(Options, "timeout") == 0 ) {
  485. strcpy( oack, Options );
  486. oack += sizeof("timeout");
  487. Options += sizeof("timeout");
  488. Request->Timeout = atoi(Options);
  489. if ( (Request->Timeout < 1) ||
  490. (Request->Timeout > 255) ) {
  491. DbgPrint("TftpdProcessOptionsPhase2: invalid timeout=%s\n", Options );
  492. TftpdErrorPacket(
  493. (struct sockaddr *)&Request->ForeignAddress,
  494. Request->Packet2,
  495. Request->TftpdPort,
  496. TFTPD_ERROR_OPTION_NEGOT_FAILED,
  497. NULL);
  498. return -1;
  499. }
  500. *ReceivedTimeoutOption = TRUE;
  501. strcpy( oack, Options );
  502. oack += strlen(Options) + 1;
  503. Options += strlen(Options) + 1;
  504. } else if ( _stricmp(Options, "tsize") == 0 ) {
  505. strcpy( oack, Options );
  506. oack += sizeof("tsize");
  507. Options += sizeof("tsize");
  508. if ( Opcode == TFTPD_WRQ ) {
  509. strcpy( oack, Options );
  510. oack += strlen(Options) + 1;
  511. Options += strlen(Options) + 1;
  512. } else {
  513. _itoa( Request->FileSize, oack, 10 );
  514. oack += strlen(oack) + 1;
  515. Options += strlen(Options) + 1;
  516. }
  517. #if defined(REMOTE_BOOT_SECURITY)
  518. } else if ( _stricmp(Options, "security") == 0 ) {
  519. //
  520. // We process this just so that we can copy it to the OACK.
  521. //
  522. // Should really copy over Request->Security, in case
  523. // it has since become 0, to show the client we reject the
  524. // security option for some reason.
  525. //
  526. strcpy( oack, Options );
  527. oack += sizeof("security");
  528. Options += sizeof("security");
  529. if ( Opcode == TFTPD_RRQ ) {
  530. strcpy( oack, Options );
  531. oack += strlen(Options) + 1;
  532. }
  533. Options += strlen(Options) + 1;
  534. #endif //defined (REMOTE_BOOT_SECURITY)
  535. } else {
  536. //
  537. // Unrecognized option. Skip the option ID and the value.
  538. //
  539. Options += strlen(Options) + 1;
  540. if ( *Options != 0 ) {
  541. Options += strlen(Options) + 1;
  542. }
  543. }
  544. }
  545. *OackLength =(int)(oack - PacketBuffer);
  546. if ( *OackLength == 2 ) {
  547. *OackLength = 0;
  548. }
  549. return 0;
  550. }
  551. #define IS_SEPARATOR(c) (((c) == '\\') || ((c) == '/'))
  552. BOOL
  553. TftpdCanonicalizeFileName(
  554. IN OUT PUCHAR FileName
  555. )
  556. {
  557. PUCHAR destination;
  558. PUCHAR source;
  559. PUCHAR lastComponent;
  560. //
  561. // The canonicalization is done in place. Initialize the source and
  562. // destination pointers to point to the same place.
  563. //
  564. source = FileName;
  565. destination = FileName;
  566. //
  567. // The lastComponent variable is used as a placeholder when
  568. // backtracking over trailing blanks and dots. It points to the
  569. // first character after the last directory separator or the
  570. // beginning of the pathname.
  571. //
  572. lastComponent = FileName;
  573. //
  574. // Get rid of leading directory separators.
  575. //
  576. while ( (*source != 0) && IS_SEPARATOR(*source) ) {
  577. source++;
  578. }
  579. //
  580. // Walk through the pathname until we reach the zero terminator. At
  581. // the start of this loop, Input points to the first charaecter
  582. // after a directory separator or the first character of the
  583. // pathname.
  584. //
  585. while ( *source != 0 ) {
  586. if ( *source == '.' ) {
  587. //
  588. // If we see a dot, look at the next character.
  589. //
  590. if ( IS_SEPARATOR(*(source+1)) ) {
  591. //
  592. // If the next character is a directory separator,
  593. // advance the source pointer to the directory
  594. // separator.
  595. //
  596. source++;
  597. } else if ( (*(source+1) == '.') && IS_SEPARATOR(*(source+2)) ) {
  598. //
  599. // If the following characters are ".\", we have a "..\".
  600. // Advance the source pointer to the "\".
  601. //
  602. source += 2;
  603. //
  604. // Move the destination pointer to the character before the
  605. // last directory separator in order to prepare for backing
  606. // up. This may move the pointer before the beginning of
  607. // the name pointer.
  608. //
  609. destination -= 2;
  610. //
  611. // If destination points before the beginning of the name
  612. // pointer, fail because the user is attempting to go
  613. // to a higher directory than the TFTPD root. This is
  614. // the equivalent of a leading "..\", but may result from
  615. // a case like "dir\..\..\file".
  616. //
  617. if ( destination <= FileName ) {
  618. return FALSE;
  619. }
  620. //
  621. // Back up the destination pointer to after the last
  622. // directory separator or to the beginning of the pathname.
  623. // Backup to the beginning of the pathname will occur
  624. // in a case like "dir\..\file".
  625. //
  626. while ( destination >= FileName && !IS_SEPARATOR(*destination) ) {
  627. destination--;
  628. }
  629. //
  630. // destination points to \ or character before name; we
  631. // want it to point to character after last \.
  632. //
  633. destination++;
  634. } else {
  635. //
  636. // The characters after the dot are not "\" or ".\", so
  637. // so just copy source to destination until we reach a
  638. // directory separator character. This will occur in
  639. // a case like ".file" (filename starts with a dot).
  640. //
  641. do {
  642. *destination++ = *source++;
  643. } while ( (*source != 0) && !IS_SEPARATOR(*source) );
  644. }
  645. } else { // if ( *source == '.' )
  646. //
  647. // source does not point to a dot, so copy source to
  648. // destination until we get to a directory separator.
  649. //
  650. while ( (*source != 0) && !IS_SEPARATOR(*source) ) {
  651. *destination++ = *source++;
  652. }
  653. }
  654. //
  655. // Truncate trailing blanks. destination should point to the last
  656. // character before the directory separator, so back up over blanks.
  657. //
  658. while ( (destination > lastComponent) && (*(destination-1) == ' ') ) {
  659. destination--;
  660. }
  661. //
  662. // At this point, source points to a directory separator or to
  663. // a zero terminator. If it is a directory separator, put one
  664. // in the destination.
  665. //
  666. if ( IS_SEPARATOR(*source) ) {
  667. //
  668. // If we haven't put the directory separator in the path name,
  669. // put it in.
  670. //
  671. if ( (destination != FileName) && !IS_SEPARATOR(*(destination-1)) ) {
  672. *destination++ = '\\';
  673. }
  674. //
  675. // It is legal to have multiple directory separators, so get
  676. // rid of them here. Example: "dir\\\\\\\\file".
  677. //
  678. do {
  679. source++;
  680. } while ( (source != 0) && IS_SEPARATOR(*source) );
  681. //
  682. // Make lastComponent point to the character after the directory
  683. // separator.
  684. //
  685. lastComponent = destination;
  686. }
  687. }
  688. //
  689. // We're just about done. If there was a trailing .. (example:
  690. // "file\.."), trailing . ("file\."), or multiple trailing
  691. // separators ("file\\\\"), then back up one since separators are
  692. // illegal at the end of a pathname.
  693. //
  694. if ( (destination != FileName) && IS_SEPARATOR(*(destination-1)) ) {
  695. destination--;
  696. }
  697. //
  698. // Terminate the destination string.
  699. //
  700. *destination = L'\0';
  701. return TRUE;
  702. }
  703. BOOL
  704. TftpdPrependStringToFileName(
  705. IN OUT PUCHAR FileName,
  706. IN ULONG FileNameLength,
  707. IN PCHAR Prefix
  708. )
  709. {
  710. BOOL prefixHasSeparator;
  711. BOOL currentFileNameHasSeparator;
  712. ULONG prefixLength;
  713. ULONG separatorLength;
  714. ULONG currentFileNameLength;
  715. prefixLength = strlen( Prefix );
  716. currentFileNameLength = strlen( FileName );
  717. prefixHasSeparator = (BOOL)(Prefix[prefixLength - 1] == '\\');
  718. currentFileNameHasSeparator = (BOOL)(FileName[0] == '\\');
  719. if ( prefixHasSeparator || currentFileNameHasSeparator ) {
  720. separatorLength = 0;
  721. if ( prefixHasSeparator && currentFileNameHasSeparator ) {
  722. prefixLength--;
  723. }
  724. } else {
  725. separatorLength = 1;
  726. }
  727. if ( (prefixLength + separatorLength + currentFileNameLength) > (FileNameLength - 1) ) {
  728. return FALSE;
  729. }
  730. //
  731. // Move the existing string down to make room for the prefix.
  732. //
  733. memmove( FileName + prefixLength + separatorLength, FileName, currentFileNameLength + 1 );
  734. //
  735. // Move the prefix into place.
  736. //
  737. memcpy( FileName, Prefix, prefixLength );
  738. //
  739. // If necessary, insert a backslash between the prefix and the file name.
  740. //
  741. if ( separatorLength != 0 ) {
  742. FileName[prefixLength] = '\\';
  743. }
  744. return TRUE;
  745. }
  746. BOOL
  747. TftpdGetNextReadPacket(
  748. PTFTP_READ_CONTEXT Context,
  749. PTFTP_REQUEST Request
  750. )
  751. /*++
  752. Routine Description:
  753. Arguments:
  754. Return Value:
  755. TRUE: got next packet into Context-Packet
  756. FALSE : error packet in Request->Packet2
  757. --*/
  758. {
  759. #if defined(REMOTE_BOOT_SECURITY)
  760. SECURITY_STATUS SecStatus;
  761. #endif //defined(REMOTE_BOOT_SECURITY)
  762. if ( Context->oackLength != 0 ) {
  763. //
  764. // The first "data packet" sent will really be the OACK.
  765. //
  766. Context->packetLength = Context->oackLength;
  767. Context->oackLength = 0;
  768. Context->BlockNumber = 0;
  769. Context->BytesRead = Request->BlockSize; // to prevent exit condition from being true
  770. } else {
  771. ((unsigned short *) Context->Packet)[0] = htons(TFTPD_DATA);
  772. ((unsigned short *) Context->Packet)[1] = htons(Context->BlockNumber);
  773. #if defined(REMOTE_BOOT_SECURITY)
  774. if (Request->SecurityHandle) {
  775. if (Context->EncryptBytesSent == 0) {
  776. //
  777. // Read the file before sending the first data packet.
  778. //
  779. Context->BytesRead = _read(
  780. Context->fd,
  781. Context->EncryptFileBuffer + NTLMSSP_MESSAGE_SIGNATURE_SIZE,
  782. Request->FileSize);
  783. if (Context->BytesRead != Request->FileSize) {
  784. DbgPrint("TftpdHandleRead: Could not read EncryptFileBuffer=%d.\n", errno);
  785. TftpdErrorPacket(
  786. (struct sockaddr *) &Request->ForeignAddress,
  787. Request->Packet2,
  788. Request->TftpdPort,
  789. TFTPD_ERROR_UNDEFINED,
  790. "Insufficient resources");
  791. goto cleanup;
  792. }
  793. //
  794. // We have it in memory, so encrypt it.
  795. //
  796. Context->SigBuffers[0].pvBuffer = Context->EncryptFileBuffer + NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  797. Context->SigBuffers[0].cbBuffer = Request->FileSize;
  798. Context->SigBuffers[0].BufferType = SECBUFFER_DATA;
  799. Context->SigBuffers[1].pvBuffer = Context->EncryptFileBuffer;
  800. Context->SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  801. Context->SigBuffers[1].BufferType = SECBUFFER_TOKEN;
  802. Context->SignMessage.pBuffers = Context->SigBuffers;
  803. Context->SignMessage.cBuffers = 2;
  804. Context->SignMessage.ulVersion = 0;
  805. SecStatus = SealMessage(
  806. &Context->Security.ServerContextHandle,
  807. 0,
  808. &Context->SignMessage,
  809. 0 );
  810. if (SecStatus != STATUS_SUCCESS) {
  811. DbgPrint("TftpdHandleRead: Could not seal message=%d.\n", SecStatus);
  812. TftpdErrorPacket(
  813. (struct sockaddr *) &Request->ForeignAddress,
  814. Request->Packet2,
  815. Request->TftpdPort,
  816. TFTPD_ERROR_UNDEFINED,
  817. "Encryption error");
  818. goto cleanup;
  819. }
  820. }
  821. if ((Context->EncryptBytesSent + Request->BlockSize) <= (int)(Request->FileSize + NTLMSSP_MESSAGE_SIGNATURE_SIZE)) {
  822. Context->BytesRead = Request->BlockSize;
  823. } else {
  824. Context->BytesRead = (Request->FileSize + NTLMSSP_MESSAGE_SIGNATURE_SIZE) - Context->EncryptBytesSent;
  825. }
  826. memcpy(
  827. &Context->Packet[4],
  828. Context->EncryptFileBuffer + Context->EncryptBytesSent,
  829. Context->BytesRead);
  830. Context->EncryptBytesSent += Context->BytesRead;
  831. } else
  832. #endif //defined(REMOTE_BOOT_SECURITY)
  833. {
  834. //
  835. // read BlockSize bytes (or whatever's left)
  836. //
  837. Context->BytesRead = _read(
  838. Context->fd,
  839. &Context->Packet[4],
  840. Request->BlockSize);
  841. if( Context->BytesRead == -1 ){
  842. DbgPrint("TftpdHandleRead: read failed=%d\n", errno );
  843. SetLastError( errno );
  844. goto cleanup;
  845. }
  846. if (Context->BytesRead != Request->BlockSize) {
  847. DbgPrint("GetNextReadPacket read %d bytes\n",Context->BytesRead);
  848. }
  849. }
  850. Context->packetLength = 4 + Context->BytesRead;
  851. }
  852. return TRUE;
  853. cleanup:
  854. return FALSE;
  855. }
  856. DWORD
  857. TftpdAddContextToList(PLIST_ENTRY pEntry)
  858. {
  859. EnterCriticalSection(&Globals.Lock);
  860. InsertHeadList(&Globals.WorkList,pEntry);
  861. DbgPrint("Adding 0x%X to global list\n", pEntry);
  862. LeaveCriticalSection(&Globals.Lock);
  863. return TRUE;
  864. }
  865. PVOID
  866. TftpdFindContextInList(SOCKET Sock)
  867. /*++
  868. Routine Description:
  869. Look for context based upon Socket descriptor. If found, return pointer to context with lock held
  870. You must release the lock via a call to TftpdReleaseContextLock().
  871. For now, simple linked list walk. Move to hash table if time permits.
  872. Arguments:
  873. Argument - socket
  874. Return Value:
  875. NULL, failed to find context
  876. --*/
  877. {
  878. PLIST_ENTRY pEntry;
  879. PTFTP_CONTEXT_HEADER Context;
  880. EnterCriticalSection(&Globals.Lock);
  881. for ( pEntry = Globals.WorkList.Flink;
  882. pEntry != &Globals.WorkList;
  883. pEntry = pEntry->Flink) {
  884. Context=CONTAINING_RECORD(pEntry, TFTP_CONTEXT_HEADER, ContextLinkage);
  885. if (Context->Sock == Sock) {
  886. // Found it
  887. EnterCriticalSection(&Context->Lock);
  888. if (!Context->Closing) {
  889. Context->RefCount++;
  890. } else {
  891. LeaveCriticalSection(&Context->Lock);
  892. Context = NULL;
  893. }
  894. LeaveCriticalSection(&Globals.Lock);
  895. return (Context);
  896. }
  897. }
  898. LeaveCriticalSection(&Globals.Lock);
  899. return(NULL);
  900. }
  901. void
  902. TftpdReleaseContextLock(
  903. PTFTP_CONTEXT_HEADER Context
  904. )
  905. /*++
  906. Routine Description:
  907. Used to leave any context critical section entered via TftpdFindContextInList().
  908. Arguments:
  909. Argument - Context
  910. Return Value:
  911. None.
  912. --*/
  913. {
  914. assert(Context->RefCount > 0);
  915. Context->RefCount--;
  916. if (Context->Closing && (Context->RefCount == 0)) {
  917. Context->IdleCount=0;
  918. LeaveCriticalSection(&Context->Lock);
  919. TftpdRemoveContextFromList((PTFTP_CONTEXT_HEADER)Context);
  920. } else {
  921. LeaveCriticalSection(&Context->Lock);
  922. }
  923. }
  924. VOID
  925. TftpdRemoveContextFromList(PTFTP_CONTEXT_HEADER Context)
  926. /*++
  927. Routine Description:
  928. Look for context. If found, remove it, free all resources
  929. For now, simple linked list walk. Move to hash table if time permits.
  930. Arguments:
  931. Argument - socket
  932. Return Value:
  933. --*/
  934. {
  935. PLIST_ENTRY pEntry;
  936. PLIST_ENTRY pNextEntry;
  937. PTFTP_CONTEXT_HEADER LocalContext;
  938. EnterCriticalSection(&Globals.Lock);
  939. pEntry=Globals.WorkList.Flink;
  940. while (pEntry != &Globals.WorkList)
  941. {
  942. LocalContext=CONTAINING_RECORD(pEntry, TFTP_CONTEXT_HEADER, ContextLinkage);
  943. pNextEntry=pEntry->Flink;
  944. if (Context == LocalContext) {
  945. // Found it
  946. assert(Context->Closing);
  947. assert(Context->RefCount == 0);
  948. RemoveEntryList(pEntry);
  949. DbgPrint("Removing 0x%X from global list\n", pEntry);
  950. LeaveCriticalSection(&Globals.Lock);
  951. DbgPrint("Removing connection to port %d\n",htons(Context->ForeignAddress.sin_port));
  952. TftpdFreeContext(Context);
  953. return;
  954. }
  955. pEntry=pNextEntry;
  956. }
  957. LeaveCriticalSection(&Globals.Lock);
  958. }
  959. VOID
  960. TftpdFreeGeneralContextFields(PTFTP_CONTEXT_HEADER Context)
  961. {
  962. if (Context->Sock != INVALID_SOCKET) {
  963. closesocket(Context->Sock);
  964. DbgPrint("TftpdFreeGeneralContextFields: Close Socket %d\n",Context->Sock);
  965. }
  966. if (Context->TimerHandle) {
  967. RtlDeleteTimer(Globals.TimerQueueHandle,Context->TimerHandle,NULL);
  968. }
  969. Context->TimerHandle = 0;
  970. if (Context->Packet != NULL) {
  971. free(Context->Packet);
  972. Context->Packet = NULL;
  973. }
  974. RtlDeregisterWaitEx(Context->WaitEvent,NULL);
  975. CloseHandle(Context->SocketEvent);
  976. DeleteCriticalSection(&Context->Lock);
  977. }
  978. VOID
  979. TftpdFreeReadContext(PTFTP_READ_CONTEXT Context)
  980. {
  981. #if defined(REMOTE_BOOT_SECURITY)
  982. if (Context->EncryptFileBuffer) {
  983. free(Context->EncryptFileBuffer);
  984. }
  985. #endif //defined(REMOTE_BOOT_SECURITY)
  986. if (Context->fd != -1) {
  987. _close(Context->fd);
  988. }
  989. free(Context);
  990. }
  991. VOID
  992. TftpdFreeWriteContext(PTFTP_WRITE_CONTEXT Context)
  993. {
  994. if (Context->fd != -1) {
  995. _close(Context->fd);
  996. }
  997. free(Context);
  998. }
  999. VOID
  1000. TftpdFreeLoginContext(PTFTP_LOGIN_CONTEXT Context)
  1001. {
  1002. }
  1003. VOID
  1004. TftpdFreeKeyContext(PTFTP_KEY_CONTEXT Context)
  1005. {
  1006. }
  1007. VOID
  1008. TftpdFreeContext(PTFTP_CONTEXT_HEADER Context)
  1009. {
  1010. if (Context == NULL) {
  1011. DbgPrint("TftpdFreeContext: Called with Null context");
  1012. return;
  1013. }
  1014. TftpdFreeGeneralContextFields(Context);
  1015. switch (Context->ContextType) {
  1016. case READ_CONTEXT:
  1017. TftpdFreeReadContext((PTFTP_READ_CONTEXT)Context);
  1018. break;
  1019. case WRITE_CONTEXT:
  1020. TftpdFreeWriteContext((PTFTP_WRITE_CONTEXT)Context);
  1021. break;
  1022. case LOGIN_CONTEXT:
  1023. TftpdFreeLoginContext((PTFTP_LOGIN_CONTEXT)Context);
  1024. break;
  1025. case KEY_CONTEXT:
  1026. TftpdFreeKeyContext((PTFTP_KEY_CONTEXT)Context);
  1027. break;
  1028. }
  1029. }
  1030. VOID
  1031. TftpdReaper(PVOID ReaperContext,
  1032. BOOLEAN Flag)
  1033. /*++
  1034. Routine Description:
  1035. Walk WorkList looking for inactive Contexts
  1036. Arguments:
  1037. Return Value:
  1038. --*/
  1039. {
  1040. PLIST_ENTRY pEntry;
  1041. PLIST_ENTRY pNextEntry;
  1042. PTFTP_CONTEXT_HEADER Context;
  1043. EnterCriticalSection(&Globals.Lock);
  1044. pEntry = Globals.WorkList.Flink;
  1045. while (pEntry != &Globals.WorkList)
  1046. {
  1047. Context=CONTAINING_RECORD(pEntry, TFTP_CONTEXT_HEADER, ContextLinkage);
  1048. EnterCriticalSection(&Context->Lock);
  1049. pNextEntry=pEntry->Flink;
  1050. Context->IdleCount++;
  1051. if ((Context->IdleCount >= DEAD_CONTEXT_COUNT) &&
  1052. !Context->Closing &&
  1053. (Context->RefCount == 0)) {
  1054. // Context is dead.
  1055. Context->Closing = TRUE;
  1056. DbgPrint("Reaping connection to port %d",htons(Context->ForeignAddress.sin_port));
  1057. LeaveCriticalSection(&Context->Lock);
  1058. LeaveCriticalSection(&Globals.Lock);
  1059. TftpdRemoveContextFromList((PTFTP_CONTEXT_HEADER)Context);
  1060. EnterCriticalSection(&Globals.Lock);
  1061. } else {
  1062. LeaveCriticalSection(&Context->Lock);
  1063. }
  1064. pEntry=pNextEntry;
  1065. }
  1066. LeaveCriticalSection(&Globals.Lock);
  1067. TftpdCleanHeap();
  1068. }
  1069. VOID
  1070. TftpdRetransmit(PVOID RetransContext,
  1071. BOOLEAN Flag)
  1072. {
  1073. PTFTP_READ_WRITE_CONTEXT_HEADER Context;
  1074. BOOL Status;
  1075. NTSTATUS ntStatus;
  1076. Context=(PTFTP_READ_WRITE_CONTEXT_HEADER)TftpdFindContextInList((SOCKET)RetransContext);
  1077. if (Context == NULL) {
  1078. DbgPrint("TftpdRetransmit: Unable to find context\n");
  1079. return;
  1080. }
  1081. if (Context->RetransmissionCount < MAX_TFTPD_RETRIES) {
  1082. if (Context->RetransmissionCount > 5) {
  1083. SYSTEMTIME _st;
  1084. GetLocalTime(&_st);
  1085. DbgPrint("%2d-%02d: %02d:%02d:%02d TftpdRetransmit: Socket %d DstPort %d Count %d BlkNum %d\n",
  1086. _st.wMonth,_st.wDay,_st.wHour,_st.wMinute,_st.wSecond,
  1087. (DWORD)((DWORD_PTR)RetransContext),
  1088. ntohs(Context->ForeignAddress.sin_port),
  1089. Context->RetransmissionCount,
  1090. htons(((unsigned short*)(Context->Packet))[1]));
  1091. }
  1092. Status = sendto(
  1093. Context->Sock,
  1094. Context->Packet,
  1095. Context->packetLength,
  1096. 0,
  1097. (struct sockaddr *) &Context->ForeignAddress,
  1098. sizeof(struct sockaddr_in));
  1099. if( SOCKET_ERROR == Status ){
  1100. DbgPrint("TftpdHandleRead: sendto failed=%d\n",
  1101. WSAGetLastError() );
  1102. }
  1103. Context->RetransmissionCount++;
  1104. Context->IdleCount = 0; // don't accidently reap this connection during retransmit tries.
  1105. if (Context->TimerHandle) {
  1106. if (!Context->FixedTimer) {
  1107. Context->DueTime *= 2;
  1108. if (Context->DueTime > (TFTPD_MAX_TIMEOUT * 1000)) {
  1109. Context->DueTime = (TFTPD_MAX_TIMEOUT * 1000);
  1110. }
  1111. }
  1112. ntStatus=RtlUpdateTimer(Globals.TimerQueueHandle,
  1113. Context->TimerHandle,
  1114. Context->DueTime,
  1115. Context->DueTime);
  1116. if (ntStatus != STATUS_SUCCESS) {
  1117. DbgPrint("TftpdRetransmit: UpdateTimerFailed %d",GetLastError());
  1118. }
  1119. }
  1120. } else {
  1121. //Send timeout
  1122. TftpdErrorPacket((struct sockaddr *) &Context->ForeignAddress,
  1123. NULL,
  1124. Context->Sock,
  1125. TFTPD_ERROR_UNDEFINED,
  1126. "Timeout"
  1127. );
  1128. Context->Closing = TRUE;
  1129. }
  1130. TftpdReleaseContextLock((PTFTP_CONTEXT_HEADER)Context);
  1131. }
  1132. DWORD
  1133. TftpdResumeRead(
  1134. PTFTP_READ_CONTEXT Context,
  1135. PTFTP_REQUEST Request
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Resumes processing of existing read request. Context lock held when function is called.
  1140. Arguments:
  1141. Argument - buffer containing the read request datagram
  1142. Return Value:
  1143. Exit status
  1144. 0 == success
  1145. 1 == failure
  1146. N >0 failure
  1147. s--*/
  1148. {
  1149. BOOL Acked=FALSE;
  1150. BOOL Status=FALSE;
  1151. int SendStatus=0;
  1152. BOOL Retrans=FALSE;
  1153. NTSTATUS Stat;
  1154. //
  1155. // Parse the request
  1156. //
  1157. DbgPrint("TftpdResumeRead BlockNum %d\n",Context->BlockNumber);
  1158. Request->BlockSize=Context->BlockSize;
  1159. if (CHECK_ACK(Request->Packet1, TFTPD_ACK, Context->BlockNumber)) {
  1160. Acked = TRUE;
  1161. Context->RetransmissionCount=0;
  1162. } else {
  1163. DbgPrint("Ack failed: Expect Blk %d Received Blk %d OpCode %d",
  1164. Context->BlockNumber,
  1165. ntohs((((unsigned short *)Request->Packet1)[1])),
  1166. htons(*((unsigned short *) (Request->Packet1))));
  1167. if (CHECK_ACK(Request->Packet1, TFTPD_ACK, Context->BlockNumber-1)) {
  1168. Retrans=TRUE;
  1169. }
  1170. }
  1171. if (Acked) {
  1172. if (Context->Done) {
  1173. Context->Closing = TRUE;
  1174. return 0;
  1175. }
  1176. if (++Context->BlockNumber == 0)
  1177. Context->BlockNumber = 1; // 32 MB file roll-over.
  1178. Status=TftpdGetNextReadPacket(Context,Request);
  1179. if (!Status) {
  1180. DbgPrint("GetNextPacketFailed %d",ntohs(Request->ForeignAddress.sin_port));
  1181. return 0;
  1182. }
  1183. Context->RetransmissionCount=0;
  1184. Context->IdleCount=0;
  1185. if (!Context->FixedTimer) {
  1186. // received new packet, reset timer
  1187. Context->DueTime=TFTPD_INITIAL_TIMEOUT*1000;
  1188. }
  1189. if (Context->TimerHandle) {
  1190. Stat=RtlUpdateTimer(Globals.TimerQueueHandle,
  1191. Context->TimerHandle,
  1192. Context->DueTime,
  1193. Context->DueTime);
  1194. if (!NT_SUCCESS(Stat)) {
  1195. DbgPrint("Failed to Update Timer");
  1196. }
  1197. }
  1198. //
  1199. // If we've sent the whole file, exit the loop. Note that we
  1200. // don't send an error packet if there is a timeout on the last
  1201. // data packet, because the receiver might have only sent the
  1202. // ACK once, then forgotten about this transfer.
  1203. //
  1204. if (Context->BytesRead < Request->BlockSize) {
  1205. SOCKET Sock;
  1206. DbgPrint("We're done with %d\n",ntohs(Request->ForeignAddress.sin_port));
  1207. Context->Done=TRUE;
  1208. }
  1209. }
  1210. if (Status) {
  1211. // Got a valid packet to send
  1212. DbgPrint("TftpdResumeRead: Sending data BlkNumber %d Socket %d PeerPort %d Size %d\n",Context->BlockNumber, Context->Sock, ntohs(Request->ForeignAddress.sin_port), Context->packetLength);
  1213. SendStatus = sendto(
  1214. Context->Sock,
  1215. Context->Packet,
  1216. Context->packetLength,
  1217. 0,
  1218. (struct sockaddr *) &Request->ForeignAddress,
  1219. sizeof(struct sockaddr_in));
  1220. if( SOCKET_ERROR == SendStatus ){
  1221. DbgPrint("TftpdHandleRead: sendto failed=%d\n",
  1222. WSAGetLastError() );
  1223. goto cleanup;
  1224. }
  1225. }
  1226. return 0;
  1227. cleanup:
  1228. return 1;
  1229. }
  1230. DWORD
  1231. TftpdResumeWrite(
  1232. PTFTP_WRITE_CONTEXT Context,
  1233. PTFTP_REQUEST Request
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. Resumes processing of existing write request. Context lock held when function is called.
  1238. Arguments:
  1239. Argument - buffer containing the write request datagram
  1240. Return Value:
  1241. Exit status
  1242. 0 == success
  1243. 1 == failure
  1244. N >0 failure
  1245. --*/
  1246. {
  1247. BOOL NewData=FALSE;
  1248. char State;
  1249. int BytesWritten;
  1250. int Status;
  1251. NTSTATUS Stat;
  1252. DbgPrint("Request Blocksize %d Context Blocksize %d\n",Request->BlockSize,Context->BlockSize);
  1253. Request->BlockSize=Context->BlockSize;
  1254. DbgPrint("TftpdResumeWrite: PktNum %d DataSize %d\n",Context->BlockNumber+1,Request->DataSize-4);
  1255. if (CHECK_ACK(Request->Packet1, TFTPD_DATA, Context->BlockNumber+1)) {
  1256. NewData = TRUE;
  1257. Context->BlockNumber++;
  1258. Context->IdleCount=0;
  1259. } else {
  1260. if (CHECK_ACK(Request->Packet1, TFTPD_DATA, Context->BlockNumber)) {
  1261. // resend ack
  1262. ((unsigned short *) Context->Packet)[0] = htons(TFTPD_ACK);
  1263. ((unsigned short *) Context->Packet)[1] = htons(Context->BlockNumber);
  1264. Status =
  1265. sendto(
  1266. Context->Sock,
  1267. Context->Packet,
  1268. 4,
  1269. 0,
  1270. (struct sockaddr *) &Request->ForeignAddress,
  1271. sizeof(struct sockaddr_in));
  1272. DbgPrint("TftpdResumeWrite: Resending Ack %d\n",Context->BlockNumber);
  1273. if( SOCKET_ERROR == Status ){
  1274. DbgPrint("TftpdHandleWrite: sendto failed=%d\n",
  1275. WSAGetLastError() );
  1276. }
  1277. return 0;
  1278. }
  1279. }
  1280. State = '\0';
  1281. if (NewData) {
  1282. BytesWritten =
  1283. TftpdDoWrite(Context->fd, &Request->Packet1[4], Request->DataSize - 4, Context->FileMode, &State);
  1284. }
  1285. if (!NewData) {
  1286. DbgPrint("TftpdHandleWrite: Timed out waiting for ack\n");
  1287. /*
  1288. TftpdErrorPacket(
  1289. (struct sockaddr *) &Request->ForeignAddress,
  1290. Request->Packet2,
  1291. Request->TftpdPort,
  1292. TFTPD_ERROR_UNDEFINED,
  1293. "Timeout");
  1294. */
  1295. goto cleanup;
  1296. } else if (BytesWritten < 0) {
  1297. DbgPrint("TftpdHandleWrite: disk full?\n");
  1298. TftpdErrorPacket(
  1299. (struct sockaddr *) &Request->ForeignAddress,
  1300. Request->Packet2,
  1301. Request->TftpdPort,
  1302. TFTPD_ERROR_DISK_FULL,
  1303. NULL);
  1304. goto cleanup;
  1305. } else if (Request->DataSize - 4 <= Request->BlockSize ) {
  1306. //
  1307. // Ack the last packet
  1308. //
  1309. ((unsigned short *) Context->Packet)[0] = htons(TFTPD_ACK);
  1310. ((unsigned short *) Context->Packet)[1] = htons(Context->BlockNumber);
  1311. Status =
  1312. sendto(
  1313. Context->Sock,
  1314. Context->Packet,
  1315. 4,
  1316. 0,
  1317. (struct sockaddr *) &Request->ForeignAddress,
  1318. sizeof(struct sockaddr_in));
  1319. DbgPrint("TftpdResumeWrite: Sending Ack %d\n",Context->BlockNumber);
  1320. if (Context->TimerHandle) {
  1321. Context->RetransmissionCount=0;
  1322. if (!Context->FixedTimer) {
  1323. // received new packet, reset timer
  1324. Context->DueTime=TFTPD_INITIAL_TIMEOUT*1000;
  1325. }
  1326. Stat=RtlUpdateTimer(Globals.TimerQueueHandle,
  1327. Context->TimerHandle,
  1328. Context->DueTime,
  1329. Context->DueTime);
  1330. if (!NT_SUCCESS(Stat)) {
  1331. DbgPrint("Failed to Update Timer");
  1332. }
  1333. }
  1334. if( SOCKET_ERROR == Status ){
  1335. DbgPrint("TftpdHandleWrite: sendto failed=%d\n",
  1336. WSAGetLastError() );
  1337. }
  1338. if (Request->DataSize - 4 < Request->BlockSize ) {
  1339. // we're done. flag for speedy cleanup
  1340. Context->Closing = TRUE;
  1341. }
  1342. }
  1343. return 0;
  1344. cleanup:
  1345. return 1;
  1346. }
  1347. DWORD
  1348. TftpdResumeLogin(
  1349. PTFTP_LOGIN_CONTEXT Context,
  1350. PTFTP_REQUEST Request
  1351. )
  1352. /*++
  1353. Routine Description:
  1354. Resumes processing of existing login request. Context lock held when function is called. Lock released upon exiting.
  1355. Arguments:
  1356. Argument - buffer containing the login request datagram
  1357. Return Value:
  1358. Exit status
  1359. 0 == success
  1360. 1 == failure
  1361. N >0 failure
  1362. --*/
  1363. {
  1364. return 0;
  1365. }
  1366. DWORD
  1367. TftpdResumeKey(
  1368. PTFTP_KEY_CONTEXT Context,
  1369. PTFTP_REQUEST Request
  1370. )
  1371. /*++
  1372. Routine Description:
  1373. Resumes processing of existing key request. Context lock held when function is called. Lock released upon exiting.
  1374. Arguments:
  1375. Argument - buffer containing the key request datagram
  1376. Return Value:
  1377. Exit status
  1378. 0 == success
  1379. 1 == failure
  1380. N >0 failure
  1381. --*/
  1382. {
  1383. return 0;
  1384. }
  1385. VOID
  1386. TftpdResumeProcessing(PVOID Argument)
  1387. /*++
  1388. Routine Description:
  1389. Resume work, if possible
  1390. Arguments:
  1391. Argument - buffer containing the incoming datagram
  1392. Return Value:
  1393. --*/
  1394. {
  1395. PTFTP_REQUEST Request=(PTFTP_REQUEST)Argument;
  1396. PTFTP_CONTEXT_HEADER Context;
  1397. DWORD Status;
  1398. Context=(PTFTP_CONTEXT_HEADER)TftpdFindContextInList(Request->TftpdPort);
  1399. if (Context == NULL) {
  1400. DbgPrint("Invalid request on port %d", Request->TftpdPort);
  1401. return;
  1402. }
  1403. if ((Context->ForeignAddress.sin_family != Request->ForeignAddress.sin_family) ||
  1404. (Context->ForeignAddress.sin_addr.s_addr != Request->ForeignAddress.sin_addr.s_addr) ||
  1405. (Context->ForeignAddress.sin_port != Request->ForeignAddress.sin_port)) {
  1406. TftpdReleaseContextLock(Context);
  1407. DbgPrint("Invalid request on port %d", Request->TftpdPort);
  1408. return;
  1409. }
  1410. switch (Context->ContextType) {
  1411. case READ_CONTEXT:
  1412. Status=TftpdResumeRead((PTFTP_READ_CONTEXT)Context, Request);
  1413. break;
  1414. case WRITE_CONTEXT:
  1415. TftpdResumeWrite((PTFTP_WRITE_CONTEXT)Context, Request);
  1416. break;
  1417. case LOGIN_CONTEXT:
  1418. TftpdResumeLogin((PTFTP_LOGIN_CONTEXT)Context, Request);
  1419. break;
  1420. case KEY_CONTEXT:
  1421. TftpdResumeKey((PTFTP_KEY_CONTEXT)Context, Request);
  1422. break;
  1423. }
  1424. TftpdReleaseContextLock(Context);
  1425. return;
  1426. }
  1427. /*
  1428. Make sure incoming name is null terminated
  1429. */
  1430. BOOL IsFileNameValid(char* FileName, DWORD MaxLen)
  1431. {
  1432. DWORD i;
  1433. // Make sure Filename has null terminator
  1434. for (i=0; i < MaxLen; i++) {
  1435. if (FileName[i] == (char)0 ) {
  1436. return TRUE;
  1437. }
  1438. }
  1439. return FALSE;
  1440. }
  1441. // ========================================================================
  1442. DWORD
  1443. TftpdHandleRead(
  1444. PVOID Argument
  1445. )
  1446. /*++
  1447. Routine Description:
  1448. This handles an incoming read file request.
  1449. Arguments:
  1450. Argument - buffer containing the read request datagram
  1451. Return Value:
  1452. Exit status
  1453. 0 == success
  1454. 1 == failure
  1455. N >0 failure
  1456. --*/
  1457. {
  1458. BOOL Acked;
  1459. int AddressLength;
  1460. int BytesAck;
  1461. int BytesRead;
  1462. char * CharPtr;
  1463. struct fd_set exceptfds;
  1464. int FileMode;
  1465. char * FileName;
  1466. char * ReadMode;
  1467. char * NewPacket;
  1468. struct sockaddr_in ReadAddress;
  1469. struct fd_set readfds;
  1470. SOCKET ReadPort = INVALID_SOCKET;
  1471. PTFTP_REQUEST Request;
  1472. int Status, err;
  1473. struct timeval timeval;
  1474. char * client_ipaddr;
  1475. short client_port;
  1476. BOOL LockHeld=FALSE;
  1477. BOOL AddedContext=FALSE;
  1478. int length;
  1479. #if defined(REMOTE_BOOT_SECURITY)
  1480. SECURITY_STATUS SecStatus;
  1481. #endif //REMOTE_BOOT_SECURITY)
  1482. PTFTP_READ_CONTEXT Context = NULL;
  1483. NTSTATUS ntStatus;
  1484. //
  1485. // Parse the request
  1486. //
  1487. DbgPrint("Entered Handle read\n");
  1488. Request = (PTFTP_REQUEST) Argument;
  1489. FileName = &Request->Packet1[2];
  1490. if (!IsFileNameValid(FileName,MAX_TFTP_DATAGRAM-2)) {
  1491. goto cleanup;
  1492. }
  1493. ReadMode = FileName + (length = strlen(FileName)) + 1;
  1494. // Make sure ReadMode is NUL terminated.
  1495. if (!IsFileNameValid(ReadMode, MAX_TFTP_DATAGRAM - (length + 1))) {
  1496. DbgPrint("TftpdHandleRead: invalid ReadMode\n");
  1497. TftpdErrorPacket(
  1498. (struct sockaddr *) &Request->ForeignAddress,
  1499. Request->Packet2,
  1500. Request->TftpdPort,
  1501. TFTPD_ERROR_ILLEGAL_OPERATION,
  1502. NULL);
  1503. goto cleanup;
  1504. }
  1505. // Set up context.
  1506. Context=(PTFTP_READ_CONTEXT)malloc(sizeof(TFTP_READ_CONTEXT));
  1507. if (Context == NULL) {
  1508. goto cleanup;
  1509. }
  1510. memset(Context,0,sizeof(TFTP_READ_CONTEXT));
  1511. Context->Packet = (char *)malloc(MAX_OACK_PACKET_LENGTH);
  1512. if (Context->Packet == NULL) {
  1513. goto cleanup;
  1514. }
  1515. //
  1516. // Profile data.
  1517. //
  1518. client_ipaddr = inet_ntoa( Request->ForeignAddress.sin_addr );
  1519. if (client_ipaddr == NULL)
  1520. client_ipaddr = "";
  1521. client_port = htons( Request->ForeignAddress.sin_port );
  1522. DbgPrint("TftpdHandleRead: FileName=%s, ReadMode=%s, from=%s:%d.\n",
  1523. FileName, ReadMode,
  1524. client_ipaddr,
  1525. client_port );
  1526. //
  1527. // Convert the mode to all lower case for comparison
  1528. //
  1529. for (CharPtr = ReadMode; *CharPtr; CharPtr++) {
  1530. *CharPtr = (char)tolower(*CharPtr);
  1531. }
  1532. if (strcmp(ReadMode, "netascii") == 0) {
  1533. FileMode = O_TEXT;
  1534. DbgPrint("TftpdHandleRead: netascii mode.\n");
  1535. } else if (strcmp(ReadMode, "octet") == 0) {
  1536. FileMode = O_BINARY;
  1537. DbgPrint("TftpdHandleRead: binary mode.\n");
  1538. } else {
  1539. DbgPrint("TftpdHandleRead: invalid ReadMode=%s?\n", ReadMode );
  1540. TftpdErrorPacket(
  1541. (struct sockaddr *) &Request->ForeignAddress,
  1542. Request->Packet2,
  1543. Request->TftpdPort,
  1544. TFTPD_ERROR_ILLEGAL_OPERATION,
  1545. NULL);
  1546. goto cleanup;
  1547. }
  1548. #if defined(REMOTE_BOOT_SECURITY)
  1549. err = TftpdProcessOptionsPhase1( Request, CharPtr + 1, TFTPD_RRQ );
  1550. if ( err != 0 ) {
  1551. goto cleanup;
  1552. }
  1553. if (Request->SecurityHandle) {
  1554. //
  1555. // This returns TRUE (and the security entry) if the sign
  1556. // for this file is valid.
  1557. //
  1558. SecStatus = TftpdVerifyFileSignature(
  1559. (USHORT)(Request->SecurityHandle >> 16), // index
  1560. (USHORT)(Request->SecurityHandle & 0xffff), // validation
  1561. &Context->Security,
  1562. FileName,
  1563. Request->Sign,
  1564. client_port);
  1565. //
  1566. // This error code is known to mean an invalid security handle.
  1567. //
  1568. if ( SecStatus == (SECURITY_STATUS)STATUS_INVALID_HANDLE ) {
  1569. DbgPrint("TftpdHandleRead: SecurityHandle %x is invalid.\n",
  1570. Request->SecurityHandle);
  1571. TftpdErrorPacket(
  1572. (struct sockaddr *) &Request->ForeignAddress,
  1573. Request->Packet2,
  1574. Request->TftpdPort,
  1575. TFTPD_ERROR_UNDEFINED,
  1576. "Invalid security handle");
  1577. goto cleanup;
  1578. } else if ( SecStatus != SEC_E_OK ) {
  1579. DbgPrint("TftpdHandleRead: sign is invalid.\n");
  1580. TftpdErrorPacket(
  1581. (struct sockaddr *) &Request->ForeignAddress,
  1582. Request->Packet2,
  1583. Request->TftpdPort,
  1584. TFTPD_ERROR_UNDEFINED,
  1585. "Invalid sign");
  1586. goto cleanup;
  1587. }
  1588. }
  1589. #endif // defined(REMOTE_BOOT_SECURITY)
  1590. //
  1591. // Canonicalize the file name.
  1592. //
  1593. DbgPrint("TftpdHandleRead: Canonicalizing name.\n");
  1594. strcpy( Request->Packet3, FileName );
  1595. if ( !TftpdCanonicalizeFileName(Request->Packet3) ) {
  1596. DbgPrint("TftpdHandleRead: invalid FileName=%s\n", FileName );
  1597. TftpdErrorPacket(
  1598. (struct sockaddr *) &Request->ForeignAddress,
  1599. Request->Packet2,
  1600. Request->TftpdPort,
  1601. TFTPD_ERROR_UNDEFINED,
  1602. "Malformed file name");
  1603. goto cleanup;
  1604. }
  1605. //
  1606. // Check whether this access is permitted.
  1607. //
  1608. if( !( match( ValidClients, client_ipaddr )
  1609. || match( ValidMasters, client_ipaddr ) )
  1610. || !match( ValidReadFiles, Request->Packet3 )
  1611. ){
  1612. DbgPrint("TftpdHandleRead: cannot open file=%s, errno=%d.\n"
  1613. " client %s:%d,\n"
  1614. " ValidReadFiles=%s, ValidClients=%s, ValidMasters=%s,\n"
  1615. ,
  1616. Request->Packet3, errno,
  1617. client_ipaddr, client_port,
  1618. ValidReadFiles, ValidClients, ValidMasters
  1619. );
  1620. TftpdErrorPacket(
  1621. (struct sockaddr *) &Request->ForeignAddress,
  1622. Request->Packet2,
  1623. Request->TftpdPort,
  1624. TFTPD_ERROR_ACCESS_VIOLATION,
  1625. NULL);
  1626. goto cleanup;
  1627. }
  1628. //
  1629. // Prepend the start directory to the file name.
  1630. //
  1631. DbgPrint("TftpdHandleRead: Prepending directory name.\n");
  1632. if ( !TftpdPrependStringToFileName(
  1633. Request->Packet3,
  1634. sizeof(Request->Packet3),
  1635. StartDirectory) ) {
  1636. DbgPrint("TftpdHandleRead: too long FileName=%s\n", FileName );
  1637. TftpdErrorPacket(
  1638. (struct sockaddr *) &Request->ForeignAddress,
  1639. Request->Packet2,
  1640. Request->TftpdPort,
  1641. TFTPD_ERROR_UNDEFINED,
  1642. "File name too long");
  1643. goto cleanup;
  1644. }
  1645. //
  1646. // Open the file.
  1647. //
  1648. DbgPrint("TftpdHandleRead: opening file <%s>\n", Request->Packet3 );
  1649. Context->fd = _open(Request->Packet3, O_RDONLY | O_BINARY);
  1650. if (Context->fd == -1) {
  1651. SetLastError( errno );
  1652. DbgPrint("TftpdHandleRead: cannot open file %s, errno=%d.\n", Request->Packet3, errno );
  1653. TftpdErrorPacket(
  1654. (struct sockaddr *) &Request->ForeignAddress,
  1655. Request->Packet2,
  1656. Request->TftpdPort,
  1657. TFTPD_ERROR_FILE_NOT_FOUND,
  1658. NULL);
  1659. goto cleanup;
  1660. }
  1661. err = _lseek(Context->fd, 0, SEEK_END);
  1662. if ( err != -1 ) {
  1663. Request->FileSize = err;
  1664. err = _lseek(Context->fd, 0, SEEK_SET);
  1665. }
  1666. if( err == -1 ){
  1667. DbgPrint("TftpdHandleRead: lseek failed, errno=%d\n",
  1668. errno );
  1669. SetLastError( errno );
  1670. TftpdErrorPacket(
  1671. (struct sockaddr *) &Request->ForeignAddress,
  1672. Request->Packet2,
  1673. Request->TftpdPort,
  1674. TFTPD_ERROR_UNDEFINED,
  1675. "Insufficient resources");
  1676. goto cleanup;
  1677. }
  1678. //
  1679. // Open a new socket for this request
  1680. //
  1681. ReadPort =
  1682. socket(
  1683. AF_INET,
  1684. SOCK_DGRAM,
  1685. 0);
  1686. DbgPrint("TftpdHandleRead: New Socket %d\n",ReadPort);
  1687. if (ReadPort == INVALID_SOCKET) {
  1688. DbgPrint("TftpdHandleRead: cannot open socket, Error=%d\n",
  1689. WSAGetLastError() );
  1690. TftpdErrorPacket(
  1691. (struct sockaddr *) &Request->ForeignAddress,
  1692. Request->Packet2,
  1693. Request->TftpdPort,
  1694. TFTPD_ERROR_UNDEFINED,
  1695. "Insufficient resources");
  1696. goto cleanup;
  1697. }
  1698. //
  1699. // Bind to a random address
  1700. //
  1701. ReadAddress.sin_family = AF_INET;
  1702. ReadAddress.sin_port = 0;
  1703. ReadAddress.sin_addr.s_addr = Request->MyAddr;
  1704. Status =
  1705. bind(
  1706. ReadPort,
  1707. (struct sockaddr *) &ReadAddress,
  1708. sizeof(ReadAddress)
  1709. );
  1710. if (Status) {
  1711. DbgPrint("TftpdHandleRead: cannot bind socket, error=%d.\n",
  1712. WSAGetLastError() );
  1713. TftpdErrorPacket(
  1714. (struct sockaddr *) &Request->ForeignAddress,
  1715. Request->Packet2,
  1716. Request->TftpdPort,
  1717. TFTPD_ERROR_UNDEFINED,
  1718. "Insufficient resources");
  1719. goto cleanup;
  1720. }
  1721. Request->TftpdPort = ReadPort;
  1722. // Enter Context into list now that we know the port
  1723. InitializeCriticalSection(&Context->Lock);
  1724. Context->Sock=ReadPort;
  1725. memcpy(&Context->ForeignAddress,&Request->ForeignAddress,sizeof(struct sockaddr_in));
  1726. Context->SocketEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
  1727. if (Context->SocketEvent == NULL) {
  1728. DbgPrint("Failed to create socket event %d",GetLastError());
  1729. goto cleanup;
  1730. }
  1731. Context->WaitEvent=RegisterSocket(ReadPort,Context->SocketEvent,REG_CONTINUE_SOCKET);
  1732. if (Context->WaitEvent == NULL) {
  1733. DbgPrint("Failed to create socket event %d",GetLastError());
  1734. goto cleanup;
  1735. }
  1736. // Insert Context
  1737. TftpdAddContextToList(&Context->ContextLinkage);
  1738. AddedContext=TRUE;
  1739. Context=(PTFTP_READ_CONTEXT)TftpdFindContextInList(ReadPort);
  1740. if (Context == NULL) {
  1741. DbgPrint("Failed to Lookup ReadContext");
  1742. goto cleanup;
  1743. }
  1744. LockHeld=TRUE;
  1745. err = TftpdProcessOptionsPhase2( Request, CharPtr + 1, TFTPD_RRQ, &Context->oackLength,Context->Packet,
  1746. &Context->FixedTimer);
  1747. if ( err != 0 ) {
  1748. goto cleanup;
  1749. }
  1750. // Start retransmission timer
  1751. if (Context->FixedTimer) {
  1752. Context->DueTime=Request->Timeout*1000;
  1753. } else {
  1754. Context->DueTime=TFTPD_INITIAL_TIMEOUT*1000;
  1755. }
  1756. DbgPrint("TftpdHandleRead: Timer Interval %d msecs",Context->DueTime);
  1757. ntStatus=RtlCreateTimer(Globals.TimerQueueHandle,
  1758. &Context->TimerHandle,
  1759. TftpdRetransmit,
  1760. (PVOID)Context->Sock,
  1761. Context->DueTime,
  1762. Context->DueTime,
  1763. 0);
  1764. if (!NT_SUCCESS(ntStatus)) {
  1765. DbgPrint("Failed to Arm Timer %d",ntStatus);
  1766. }
  1767. Context->ContextType=READ_CONTEXT;
  1768. Context->BlockSize=Request->BlockSize;
  1769. if (Context->BlockSize > MAX_OACK_PACKET_LENGTH - 4) {
  1770. DbgPrint("TftpdHandleRead: Reallocating packet.\n");
  1771. NewPacket = (char *)realloc(Context->Packet, Context->BlockSize + 4);
  1772. if (NewPacket == NULL) {
  1773. goto cleanup;
  1774. }
  1775. Context->Packet = NewPacket;
  1776. }
  1777. #if defined(REMOTE_BOOT_SECURITY)
  1778. if (Request->SecurityHandle) {
  1779. //
  1780. // For secure mode, we read the whole file in at once so
  1781. // we can encrypt it. For large files like ntoskrnl.exe,
  1782. // will this work? If we get errors here, we could
  1783. // just change the oack to say "security 0" and then send
  1784. // down the unencrypted file -- maybe we should also do this
  1785. // for files beyond a certain size.
  1786. //
  1787. Context->EncryptFileBuffer = malloc(Request->FileSize + NTLMSSP_MESSAGE_SIGNATURE_SIZE);
  1788. if (Context->EncryptFileBuffer == NULL) {
  1789. DbgPrint("TftpdHandleRead: Could not allocate EncryptFileBuffer length %d.\n",
  1790. Request->FileSize + NTLMSSP_MESSAGE_SIGNATURE_SIZE);
  1791. TftpdErrorPacket(
  1792. (struct sockaddr *) &Request->ForeignAddress,
  1793. Request->Packet2,
  1794. Request->TftpdPort,
  1795. TFTPD_ERROR_UNDEFINED,
  1796. "Insufficient resources");
  1797. goto cleanup;
  1798. }
  1799. //
  1800. // We don't actually read/seal until later -- this is so we can
  1801. // send the OACK out right now to prevent more threads from
  1802. // being spawned if he resends the initial request.
  1803. //
  1804. Context->EncryptBytesSent = 0;
  1805. }
  1806. #endif //defined(REMOTE_BOOT_SECURITY)
  1807. //
  1808. // Ready to read and send file in blocks.
  1809. //
  1810. Context->BlockNumber = 1;
  1811. Status=TftpdGetNextReadPacket(Context,Request);
  1812. Context->RetransmissionCount=0;
  1813. if (Status) {
  1814. // Got a valid packet to send
  1815. Status = sendto(
  1816. ReadPort,
  1817. Context->Packet,
  1818. Context->packetLength,
  1819. 0,
  1820. (struct sockaddr *) &Request->ForeignAddress,
  1821. sizeof(struct sockaddr_in));
  1822. if (Context->BytesRead < Request->BlockSize) {
  1823. Context->Done=TRUE;
  1824. }
  1825. } else {
  1826. // send error packet
  1827. Status = sendto(
  1828. ReadPort,
  1829. Request->Packet2,
  1830. Context->packetLength,
  1831. 0,
  1832. (struct sockaddr *) &Request->ForeignAddress,
  1833. sizeof(struct sockaddr_in));
  1834. }
  1835. if( SOCKET_ERROR == Status ){
  1836. DbgPrint("TftpdHandleRead: sendto failed=%d\n",
  1837. WSAGetLastError() );
  1838. goto cleanup;
  1839. }
  1840. cleanup:
  1841. if (Context != NULL) {
  1842. if (LockHeld) {
  1843. TftpdReleaseContextLock((PTFTP_CONTEXT_HEADER)Context);
  1844. }
  1845. if (!AddedContext) {
  1846. free(Context);
  1847. }
  1848. }
  1849. return 0;
  1850. }
  1851. // ========================================================================
  1852. /*++
  1853. Routine Description:
  1854. This handles an incoming write file request.
  1855. Arguments:
  1856. Argument - buffer containing the write request
  1857. Return Value:
  1858. Exit status
  1859. 0 == success
  1860. >0 == failure
  1861. --*/
  1862. DWORD
  1863. TftpdHandleWrite(
  1864. PVOID Argument
  1865. )
  1866. {
  1867. int AddressLength;
  1868. int BytesRead;
  1869. int BytesWritten;
  1870. char * CharPtr;
  1871. struct fd_set exceptfds;
  1872. char * FileName;
  1873. char * NewPacket;
  1874. BOOL NewData;
  1875. struct sockaddr_in ReadAddress;
  1876. struct fd_set readfds;
  1877. SOCKET ReadPort = INVALID_SOCKET;
  1878. int Retry;
  1879. char State;
  1880. int Status, err;
  1881. struct timeval timeval;
  1882. char * WriteMode;
  1883. PTFTP_REQUEST Request;
  1884. int oackLength;
  1885. int packetLength;
  1886. char * client_ipaddr;
  1887. short client_port;
  1888. BOOL LockHeld=FALSE;
  1889. BOOL AddedContext=FALSE;
  1890. int length;
  1891. PTFTP_WRITE_CONTEXT Context = NULL;
  1892. NTSTATUS ntStatus;
  1893. // Set up context.
  1894. Context=(PTFTP_WRITE_CONTEXT)malloc(sizeof(TFTP_WRITE_CONTEXT));
  1895. if (Context == NULL) {
  1896. goto cleanup;
  1897. }
  1898. memset(Context,0,sizeof(TFTP_WRITE_CONTEXT));
  1899. Context->Packet = (char *)malloc(MAX_OACK_PACKET_LENGTH);
  1900. if (Context->Packet == NULL) {
  1901. goto cleanup;
  1902. }
  1903. //
  1904. // Parse the request
  1905. //
  1906. Request = (PTFTP_REQUEST) Argument;
  1907. FileName = &Request->Packet1[2];
  1908. if (!IsFileNameValid(FileName,MAX_TFTP_DATAGRAM-2)) {
  1909. goto cleanup;
  1910. }
  1911. WriteMode = FileName + (length = strlen(FileName)) + 1;
  1912. // Make sure WriteMode is NUL terminated.
  1913. if (!IsFileNameValid(WriteMode, MAX_TFTP_DATAGRAM - (length + 1))) {
  1914. DbgPrint("TftpdHandleWrite: invalid WriteMode\n");
  1915. TftpdErrorPacket(
  1916. (struct sockaddr *) &Request->ForeignAddress,
  1917. Request->Packet2,
  1918. Request->TftpdPort,
  1919. TFTPD_ERROR_ILLEGAL_OPERATION,
  1920. NULL);
  1921. goto cleanup;
  1922. }
  1923. //
  1924. // Profile data.
  1925. //
  1926. client_ipaddr = inet_ntoa( Request->ForeignAddress.sin_addr );
  1927. if (client_ipaddr == NULL)
  1928. client_ipaddr = "";
  1929. client_port = htons( Request->ForeignAddress.sin_port );
  1930. DbgPrint("TftpdHandleWrite: FileName=%s, WriteMode=%s, from=%s:%d.\n",
  1931. FileName, WriteMode,
  1932. client_ipaddr, client_port
  1933. );
  1934. for (CharPtr = WriteMode; *CharPtr; CharPtr ++) {
  1935. *CharPtr = isupper(*CharPtr) ? tolower(*CharPtr) : *CharPtr;
  1936. }
  1937. if (strcmp(WriteMode, "netascii") == 0) {
  1938. Context->FileMode = O_TEXT;
  1939. } else if (strcmp(WriteMode, "octet") == 0) {
  1940. Context->FileMode = O_BINARY;
  1941. } else {
  1942. DbgPrint("TftpdHandleWrite: invalid WriteMode=%s\n", WriteMode );
  1943. TftpdErrorPacket(
  1944. (struct sockaddr *) &Request->ForeignAddress,
  1945. Request->Packet2,
  1946. Request->TftpdPort,
  1947. TFTPD_ERROR_ILLEGAL_OPERATION,
  1948. NULL);
  1949. goto cleanup;
  1950. }
  1951. #if defined(REMOTE_BOOT_SECURITY)
  1952. err = TftpdProcessOptionsPhase1( Request, CharPtr + 1, TFTPD_WRQ );
  1953. if ( err != 0 ) {
  1954. goto cleanup;
  1955. }
  1956. #endif //defined(REMOTE_BOOT_SECURITY)
  1957. //
  1958. // Canonicalize the file name.
  1959. //
  1960. strcpy( Request->Packet3, FileName );
  1961. if ( !TftpdCanonicalizeFileName(Request->Packet3) ) {
  1962. DbgPrint("TftpdHandleWrite: invalid FileName=%s\n", FileName );
  1963. TftpdErrorPacket(
  1964. (struct sockaddr *) &Request->ForeignAddress,
  1965. Request->Packet2,
  1966. Request->TftpdPort,
  1967. TFTPD_ERROR_UNDEFINED,
  1968. "Malformed file name");
  1969. goto cleanup;
  1970. }
  1971. //
  1972. // Check whether this access is permitted.
  1973. //
  1974. if( !match( ValidMasters, client_ipaddr )
  1975. || !match( ValidWriteFiles, FileName )
  1976. ){
  1977. DbgPrint("TftpdHandleWrite: cannot open file=%s, errno=%d.\n"
  1978. " client %s:%d,\n"
  1979. " ValidWriteFiles=%s, ValidClients=%s, ValidMasters=%s,\n"
  1980. ,
  1981. Request->Packet3, errno,
  1982. client_ipaddr, client_port,
  1983. ValidWriteFiles, ValidClients, ValidMasters
  1984. );
  1985. TftpdErrorPacket(
  1986. (struct sockaddr *) &Request->ForeignAddress,
  1987. Request->Packet2,
  1988. Request->TftpdPort,
  1989. TFTPD_ERROR_ACCESS_VIOLATION,
  1990. NULL);
  1991. goto cleanup;
  1992. }
  1993. //
  1994. // Prepend the start directory to the file name.
  1995. //
  1996. if ( !TftpdPrependStringToFileName(
  1997. Request->Packet3,
  1998. sizeof(Request->Packet3),
  1999. StartDirectory) ) {
  2000. DbgPrint("TftpdHandleWrite: too long FileName=%s\n", FileName );
  2001. TftpdErrorPacket(
  2002. (struct sockaddr *) &Request->ForeignAddress,
  2003. Request->Packet2,
  2004. Request->TftpdPort,
  2005. TFTPD_ERROR_UNDEFINED,
  2006. "File name too long");
  2007. goto cleanup;
  2008. }
  2009. //
  2010. // Open the file.
  2011. //
  2012. DbgPrint("TftpdHandleWrite: opening file <%s>\n", Request->Packet3 );
  2013. Context->fd = _open(Request->Packet3, _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC,
  2014. _S_IREAD | _S_IWRITE);
  2015. if (Context->fd == -1) {
  2016. DbgPrint("TftpdHandleWrite: cannot open file=%s, errno=%d.\n"
  2017. " client %s:%d,\n"
  2018. " ValidWriteFiles=%s, ValidClients=%s, ValidMasters=%s,\n"
  2019. ,
  2020. FileName, errno,
  2021. client_ipaddr, client_port,
  2022. ValidWriteFiles, ValidClients, ValidMasters
  2023. );
  2024. SetLastError( errno );
  2025. TftpdErrorPacket(
  2026. (struct sockaddr *) &Request->ForeignAddress,
  2027. Request->Packet2,
  2028. Request->TftpdPort,
  2029. TFTPD_ERROR_ACCESS_VIOLATION,
  2030. NULL);
  2031. goto cleanup;
  2032. }
  2033. //
  2034. // Open a new socket for this request
  2035. //
  2036. ReadPort =
  2037. socket(
  2038. AF_INET,
  2039. SOCK_DGRAM,
  2040. 0);
  2041. if( ReadPort == INVALID_SOCKET ){
  2042. DbgPrint("TftpdHandleWrite: cannot open socket, Error=%d.\n",
  2043. WSAGetLastError() );
  2044. TftpdErrorPacket(
  2045. (struct sockaddr *) &Request->ForeignAddress,
  2046. Request->Packet2,
  2047. Request->TftpdPort,
  2048. TFTPD_ERROR_UNDEFINED,
  2049. "Insufficient resources");
  2050. goto cleanup;
  2051. }
  2052. //
  2053. // Bind to a random address
  2054. //
  2055. ReadAddress.sin_family = AF_INET;
  2056. ReadAddress.sin_port = 0;
  2057. ReadAddress.sin_addr.s_addr = Request->MyAddr;
  2058. Status = bind(
  2059. ReadPort,
  2060. (struct sockaddr *) &ReadAddress,
  2061. sizeof(ReadAddress));
  2062. if (Status) {
  2063. DbgPrint("TftpdHandleWrite: cannot bind socket, Error=%d.\n",
  2064. WSAGetLastError() );
  2065. TftpdErrorPacket(
  2066. (struct sockaddr *) &Request->ForeignAddress,
  2067. Request->Packet2,
  2068. Request->TftpdPort,
  2069. TFTPD_ERROR_UNDEFINED,
  2070. "Insufficient resources");
  2071. goto cleanup;
  2072. }
  2073. Request->TftpdPort = ReadPort;
  2074. err = TftpdProcessOptionsPhase2( Request, CharPtr + 1, TFTPD_WRQ, &Context->oackLength,Context->Packet,
  2075. &Context->FixedTimer);
  2076. if ( err != 0 ) {
  2077. goto cleanup;
  2078. }
  2079. State = '\0';
  2080. // Enter Context into list now that we know the port
  2081. InitializeCriticalSection(&Context->Lock);
  2082. Context->Sock=ReadPort;
  2083. memcpy(&Context->ForeignAddress,&Request->ForeignAddress,sizeof(struct sockaddr_in));
  2084. Context->SocketEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
  2085. if (Context->SocketEvent == NULL) {
  2086. DbgPrint("Failed to create socket event %d",GetLastError());
  2087. goto cleanup;
  2088. }
  2089. Context->WaitEvent=RegisterSocket(ReadPort,Context->SocketEvent,REG_CONTINUE_SOCKET);
  2090. if (Context->WaitEvent == NULL) {
  2091. DbgPrint("Failed to create socket event %d",GetLastError());
  2092. goto cleanup;
  2093. }
  2094. // Insert Context
  2095. TftpdAddContextToList(&Context->ContextLinkage);
  2096. AddedContext=TRUE;
  2097. Context=(PTFTP_WRITE_CONTEXT)TftpdFindContextInList(ReadPort);
  2098. if (Context == NULL) {
  2099. DbgPrint("Failed to Lookup ReadContext");
  2100. goto cleanup;
  2101. }
  2102. LockHeld=TRUE;
  2103. // Start retransmission timer
  2104. if (Context->FixedTimer) {
  2105. Context->DueTime=Request->Timeout*1000;
  2106. } else {
  2107. Context->DueTime=TFTPD_INITIAL_TIMEOUT*1000;
  2108. }
  2109. DbgPrint("TftpdHandleWrite: Timer Interval %d msecs\n",Context->DueTime);
  2110. ntStatus=RtlCreateTimer(Globals.TimerQueueHandle,
  2111. &Context->TimerHandle,
  2112. TftpdRetransmit,
  2113. (PVOID)Context->Sock,
  2114. Context->DueTime,
  2115. Context->DueTime,
  2116. 0);
  2117. if (!NT_SUCCESS(ntStatus)) {
  2118. DbgPrint("Failed to Arm Timer %d",ntStatus);
  2119. }
  2120. Context->ContextType=WRITE_CONTEXT;
  2121. Context->BlockSize=Request->BlockSize;
  2122. if (Context->BlockSize > MAX_OACK_PACKET_LENGTH - 4) {
  2123. NewPacket = (char *)realloc(Context->Packet, Context->BlockSize + 4);
  2124. if (NewPacket == NULL) {
  2125. goto cleanup;
  2126. }
  2127. Context->Packet = NewPacket;
  2128. }
  2129. if ( Context->oackLength != 0 ) {
  2130. Context->packetLength = Context->oackLength;
  2131. Context->oackLength = 0;
  2132. } else {
  2133. ((unsigned short *) Context->Packet)[0] = htons(TFTPD_ACK);
  2134. ((unsigned short *) Context->Packet)[1] = htons(Context->BlockNumber);
  2135. Context->packetLength = 4;
  2136. }
  2137. Status =
  2138. sendto(
  2139. ReadPort,
  2140. Context->Packet,
  2141. Context->packetLength,
  2142. 0,
  2143. (struct sockaddr *) &Request->ForeignAddress,
  2144. sizeof(struct sockaddr_in)
  2145. );
  2146. if( SOCKET_ERROR == Status ){
  2147. DbgPrint("TftpdHandleWrite: sendto failed=%d\n",
  2148. WSAGetLastError() );
  2149. goto cleanup;
  2150. }
  2151. cleanup:
  2152. if (Context != NULL) {
  2153. if (LockHeld) {
  2154. TftpdReleaseContextLock((PTFTP_CONTEXT_HEADER)Context);
  2155. }
  2156. if (!AddedContext) {
  2157. free(Context);
  2158. }
  2159. }
  2160. // _chmod(Request->Packet3, _S_IWRITE);
  2161. return 0;
  2162. }
  2163. // End function TftpdHandleWrite.
  2164. // ========================================================================
  2165. #if defined(REMOTE_BOOT_SECURITY)
  2166. DWORD
  2167. TftpdHandleLogin(
  2168. PVOID Argument
  2169. )
  2170. /*++
  2171. Routine Description:
  2172. This handles an incoming login request.
  2173. Arguments:
  2174. Argument - buffer containing the read request datagram
  2175. freed when done.
  2176. Return Value:
  2177. Exit status
  2178. 0 == success
  2179. 1 == failure
  2180. N >0 failure
  2181. --*/
  2182. {
  2183. int packetLength;
  2184. int Retry;
  2185. int Status, err;
  2186. struct timeval timeval;
  2187. struct sockaddr_in LoginAddress;
  2188. BOOL Acked;
  2189. int AddressLength;
  2190. char * CharPtr;
  2191. PTFTP_REQUEST Request;
  2192. char * OperationType;
  2193. char * PackageName;
  2194. char * SecurityString;
  2195. char * Options;
  2196. SECURITY_STATUS SecStatus;
  2197. PSecPkgInfo PackageInfo = NULL;
  2198. USHORT Index = -1;
  2199. ULONG MaxToken;
  2200. TFTPD_SECURITY Security;
  2201. ULONG SecurityHandle;
  2202. USHORT LastMessageSequence; // sequence number of the last message sent
  2203. SOCKET LoginPort = INVALID_SOCKET;
  2204. char * IncomingMessage;
  2205. SecBufferDesc IncomingDesc;
  2206. SecBuffer IncomingBuffer;
  2207. SecBufferDesc OutgoingDesc;
  2208. SecBuffer OutgoingBuffer;
  2209. BOOL FirstChallenge;
  2210. struct fd_set exceptfds;
  2211. struct fd_set loginfds;
  2212. TimeStamp Lifetime;
  2213. int BytesAck;
  2214. //
  2215. // Parse the request. The initial request should always be a
  2216. // "login".
  2217. //
  2218. Request = (PTFTP_REQUEST) Argument;
  2219. OperationType = &Request->Packet1[2];
  2220. //
  2221. // Convert the operation to all lower case for comparison
  2222. //
  2223. for (CharPtr = OperationType; *CharPtr; CharPtr ++) {
  2224. *CharPtr = (char)tolower(*CharPtr);
  2225. }
  2226. if (strcmp(OperationType, "login") == 0) {
  2227. PackageName = OperationType + strlen(OperationType) + 1;
  2228. //
  2229. // Profile data.
  2230. //
  2231. DbgPrint("TftpdHandleLogin: OperationType=%s, Package=%s, from=%s.\n",
  2232. OperationType, PackageName,
  2233. inet_ntoa( Request->ForeignAddress.sin_addr )
  2234. );
  2235. //
  2236. // Check that the security package is known.
  2237. //
  2238. SecStatus = QuerySecurityPackageInfoA( PackageName, &PackageInfo );
  2239. if (SecStatus != STATUS_SUCCESS) {
  2240. DbgPrint("TftpdHandleLogin: invalid PackageName=%s?\n", PackageName );
  2241. TftpdErrorPacket(
  2242. (struct sockaddr *) &Request->ForeignAddress,
  2243. Request->Packet2,
  2244. Request->TftpdPort,
  2245. TFTPD_ERROR_ILLEGAL_OPERATION,
  2246. "invalid security package");
  2247. goto cleanup;
  2248. }
  2249. MaxToken = PackageInfo->cbMaxToken;
  2250. FreeContextBuffer(PackageInfo);
  2251. //
  2252. // Things look OK so far, so let's find a spot in the array of
  2253. // security information to store this client.
  2254. //
  2255. if (!TftpdAllocateSecurityEntry(&Index, &Security)) {
  2256. DbgPrint("TftpdHandleLogin: could not allocate security entry\n" );
  2257. TftpdErrorPacket(
  2258. (struct sockaddr *) &Request->ForeignAddress,
  2259. Request->Packet2,
  2260. Request->TftpdPort,
  2261. TFTPD_ERROR_UNDEFINED,
  2262. "insufficient resources");
  2263. goto cleanup;
  2264. }
  2265. //
  2266. // Acquire a credential handle for the server side.
  2267. //
  2268. SecStatus = AcquireCredentialsHandleA(
  2269. NULL, // New principal
  2270. PackageName, // Package Name
  2271. SECPKG_CRED_INBOUND,
  2272. NULL,
  2273. NULL,
  2274. NULL,
  2275. NULL,
  2276. &(Security.CredentialsHandle),
  2277. &Lifetime );
  2278. if ( SecStatus != STATUS_SUCCESS ) {
  2279. DbgPrint("TftpdHandleLogin: AcquireCredentialsHandle failed %x\n", SecStatus );
  2280. TftpdErrorPacket(
  2281. (struct sockaddr *) &Request->ForeignAddress,
  2282. Request->Packet2,
  2283. Request->TftpdPort,
  2284. TFTPD_ERROR_UNDEFINED,
  2285. "insufficient resources");
  2286. goto cleanup;
  2287. }
  2288. Security.CredentialsHandleValid = TRUE;
  2289. //
  2290. // Open a new socket for this request
  2291. //
  2292. LoginPort =
  2293. socket(
  2294. AF_INET,
  2295. SOCK_DGRAM,
  2296. 0);
  2297. if (LoginPort == INVALID_SOCKET) {
  2298. DbgPrint("TftpdHandleLogin: cannot open socket, Error=%d\n",
  2299. WSAGetLastError() );
  2300. TftpdErrorPacket(
  2301. (struct sockaddr *) &Request->ForeignAddress,
  2302. Request->Packet2,
  2303. Request->TftpdPort,
  2304. TFTPD_ERROR_UNDEFINED,
  2305. "Insufficient resources");
  2306. goto cleanup;
  2307. }
  2308. //
  2309. // Bind to a random address
  2310. //
  2311. LoginAddress.sin_family = AF_INET;
  2312. LoginAddress.sin_port = 0;
  2313. LoginAddress.sin_addr.s_addr = INADDR_ANY;
  2314. Status =
  2315. bind(
  2316. LoginPort,
  2317. (struct sockaddr *) &LoginAddress,
  2318. sizeof(LoginAddress)
  2319. );
  2320. if (Status) {
  2321. DbgPrint("TftpdHandleLogin: cannot bind socket, error=%d.\n",
  2322. WSAGetLastError() );
  2323. TftpdErrorPacket(
  2324. (struct sockaddr *) &Request->ForeignAddress,
  2325. Request->Packet2,
  2326. Request->TftpdPort,
  2327. TFTPD_ERROR_UNDEFINED,
  2328. "Insufficient resources");
  2329. goto cleanup;
  2330. }
  2331. Request->TftpdPort = LoginPort;
  2332. Request->Timeout = 10; // let client set this in login packet?
  2333. //
  2334. // Ready to do exchanges until login is complete.
  2335. //
  2336. LastMessageSequence = (USHORT)-1;
  2337. FirstChallenge = TRUE;
  2338. IncomingMessage = PackageName + strlen(PackageName) + 1;
  2339. while (1) {
  2340. IncomingDesc.ulVersion = 0;
  2341. IncomingDesc.cBuffers = 1;
  2342. IncomingDesc.pBuffers = &IncomingBuffer;
  2343. IncomingBuffer.cbBuffer = (ntohl)(((unsigned long UNALIGNED *)IncomingMessage)[0]);
  2344. IncomingBuffer.BufferType = SECBUFFER_TOKEN | SECBUFFER_READONLY;
  2345. IncomingBuffer.pvBuffer = IncomingMessage + 4;
  2346. OutgoingDesc.ulVersion = 0;
  2347. OutgoingDesc.cBuffers = 1;
  2348. OutgoingDesc.pBuffers = &OutgoingBuffer;
  2349. OutgoingBuffer.cbBuffer = MaxToken;
  2350. OutgoingBuffer.BufferType = SECBUFFER_TOKEN;
  2351. OutgoingBuffer.pvBuffer = Request->Packet2 + 8;
  2352. //
  2353. // Pass the client buffer to the security system -- the first time
  2354. // we don't have a valid SecurityContextHandle, so we pass the
  2355. // CredentialsHandle instead.
  2356. //
  2357. SecStatus = AcceptSecurityContext(
  2358. FirstChallenge ? &(Security.CredentialsHandle) : NULL,
  2359. FirstChallenge ? NULL : &(Security.ServerContextHandle),
  2360. &IncomingDesc,
  2361. FirstChallenge ?
  2362. ISC_REQ_SEQUENCE_DETECT | ASC_REQ_ALLOW_NON_USER_LOGONS :
  2363. ASC_REQ_ALLOW_NON_USER_LOGONS,
  2364. SECURITY_NATIVE_DREP,
  2365. &(Security.ServerContextHandle),
  2366. &OutgoingDesc,
  2367. &(Security.ContextAttributes),
  2368. &Lifetime );
  2369. if (FirstChallenge) {
  2370. Security.ServerContextHandleValid = TRUE;
  2371. }
  2372. FirstChallenge = FALSE;
  2373. if (SecStatus != SEC_I_CONTINUE_NEEDED) {
  2374. //
  2375. // The login has been accepted or rejected.
  2376. //
  2377. ((unsigned short *) Request->Packet2)[0] = htons(TFTPD_LOGIN);
  2378. ((unsigned short *) Request->Packet2)[1] = htons((USHORT)-1);
  2379. if (SecStatus == STATUS_SUCCESS) {
  2380. sprintf(Request->Packet2+4, "status %u handle %d ",
  2381. SecStatus, (Index << 16) + Security.Validation);
  2382. } else {
  2383. sprintf(Request->Packet2+4, "status %u ", SecStatus);
  2384. }
  2385. packetLength = 4 + strlen(Request->Packet2+4);
  2386. for (CharPtr = Request->Packet2+4; *CharPtr; CharPtr ++) {
  2387. if (*CharPtr == ' ') {
  2388. *CharPtr = '\0';
  2389. }
  2390. }
  2391. Security.LoginComplete = TRUE;
  2392. Security.LoginStatus = SecStatus;
  2393. Security.ForeignAddress = Request->ForeignAddress;
  2394. TftpdStoreSecurityEntry(Index, &Security);
  2395. LastMessageSequence = (USHORT)-1;
  2396. } else if (SecStatus == SEC_I_CONTINUE_NEEDED) {
  2397. //
  2398. // Need to exchange with the client. Note that the response
  2399. // message has already been stored at Request->Packet2 + 8.
  2400. //
  2401. ++LastMessageSequence;
  2402. ((unsigned short *) Request->Packet2)[0] = htons(TFTPD_LOGIN);
  2403. ((unsigned short *) Request->Packet2)[1] = htons(LastMessageSequence);
  2404. ((unsigned long UNALIGNED *) Request->Packet2)[1] = htonl(OutgoingBuffer.cbBuffer);
  2405. packetLength = 8 + OutgoingBuffer.cbBuffer;
  2406. }
  2407. Acked = FALSE;
  2408. Retry = 0;
  2409. while (!Acked && (Retry < MAX_TFTPD_RETRIES) ){
  2410. //
  2411. // send the data
  2412. //
  2413. Status = sendto(
  2414. LoginPort,
  2415. Request->Packet2,
  2416. packetLength,
  2417. 0,
  2418. (struct sockaddr *) &Request->ForeignAddress,
  2419. sizeof(struct sockaddr_in));
  2420. if( SOCKET_ERROR == Status ){
  2421. DbgPrint("TftpdHandleLogin: sendto failed=%d\n",
  2422. WSAGetLastError() );
  2423. goto cleanup;
  2424. }
  2425. //
  2426. // wait for the ack
  2427. //
  2428. FD_ZERO( &loginfds );
  2429. FD_ZERO( &exceptfds );
  2430. FD_SET( LoginPort, &loginfds );
  2431. FD_SET( LoginPort, &exceptfds );
  2432. timeval.tv_sec = Request->Timeout;
  2433. timeval.tv_usec = 0;
  2434. Status = select(0, &loginfds, NULL, &exceptfds, &timeval);
  2435. if( SOCKET_ERROR == Status ){
  2436. DbgPrint("TftpdHandleLogin: select failed=%d\n",
  2437. WSAGetLastError() );
  2438. goto cleanup;
  2439. }
  2440. if ((Status > 0) && (FD_ISSET(LoginPort, &loginfds))) {
  2441. //
  2442. // Got response, maybe
  2443. //
  2444. AddressLength = sizeof(LoginAddress);
  2445. BytesAck =
  2446. recvfrom(
  2447. LoginPort,
  2448. Request->Packet1,
  2449. sizeof(Request->Packet1),
  2450. 0,
  2451. (struct sockaddr *) &LoginAddress,
  2452. &AddressLength);
  2453. if( SOCKET_ERROR == BytesAck ){
  2454. DbgPrint("TftpdHandleLogin: recvfrom failed=%d\n",
  2455. WSAGetLastError() );
  2456. goto cleanup;
  2457. }
  2458. if (CHECK_ACK(Request->Packet1, TFTPD_LOGIN, LastMessageSequence)) {
  2459. Acked = TRUE;
  2460. }
  2461. }
  2462. Retry ++;
  2463. } // end while.
  2464. if (!Acked) {
  2465. DbgPrint("TftpdHandleLogin: Timed out waiting for ack\n");
  2466. TftpdErrorPacket(
  2467. (struct sockaddr *) &Request->ForeignAddress,
  2468. Request->Packet2,
  2469. Request->TftpdPort,
  2470. TFTPD_ERROR_UNDEFINED,
  2471. "Timeout");
  2472. goto cleanup;
  2473. }
  2474. if (LastMessageSequence == (USHORT)-1) {
  2475. //
  2476. // If we got an ack for the last sequence number, then
  2477. // break.
  2478. //
  2479. break;
  2480. } else {
  2481. //
  2482. // Loop back and process this message.
  2483. //
  2484. IncomingMessage = Request->Packet1 + 4;
  2485. }
  2486. } // end while 1.
  2487. } else if (strcmp(OperationType, "logoff") == 0) {
  2488. PackageName = OperationType + strlen(OperationType) + 1;
  2489. //
  2490. // Don't bother checking the package name.
  2491. //
  2492. SecurityString = PackageName + strlen(PackageName) + 1;
  2493. for (CharPtr = SecurityString; *CharPtr; CharPtr ++) {
  2494. *CharPtr = (char)tolower(*CharPtr);
  2495. }
  2496. if (strcmp(SecurityString, "security") != 0) {
  2497. DbgPrint("TftpdHandleLogin: invalid logoff handle %s\n", SecurityString );
  2498. TftpdErrorPacket(
  2499. (struct sockaddr *) &Request->ForeignAddress,
  2500. Request->Packet2,
  2501. Request->TftpdPort,
  2502. TFTPD_ERROR_ILLEGAL_OPERATION,
  2503. "invalid security handle");
  2504. goto cleanup;
  2505. }
  2506. //
  2507. // Open a new socket for this request
  2508. //
  2509. LoginPort =
  2510. socket(
  2511. AF_INET,
  2512. SOCK_DGRAM,
  2513. 0);
  2514. if (LoginPort == INVALID_SOCKET) {
  2515. DbgPrint("TftpdHandleLogin: cannot open socket, Error=%d\n",
  2516. WSAGetLastError() );
  2517. TftpdErrorPacket(
  2518. (struct sockaddr *) &Request->ForeignAddress,
  2519. Request->Packet2,
  2520. Request->TftpdPort,
  2521. TFTPD_ERROR_UNDEFINED,
  2522. "Insufficient resources");
  2523. goto cleanup;
  2524. }
  2525. //
  2526. // Bind to a random address
  2527. //
  2528. LoginAddress.sin_family = AF_INET;
  2529. LoginAddress.sin_port = 0;
  2530. LoginAddress.sin_addr.s_addr = INADDR_ANY;
  2531. Status =
  2532. bind(
  2533. LoginPort,
  2534. (struct sockaddr *) &LoginAddress,
  2535. sizeof(LoginAddress)
  2536. );
  2537. if (Status) {
  2538. DbgPrint("TftpdHandleLogin: cannot bind socket, error=%d.\n",
  2539. WSAGetLastError() );
  2540. TftpdErrorPacket(
  2541. (struct sockaddr *) &Request->ForeignAddress,
  2542. Request->Packet2,
  2543. Request->TftpdPort,
  2544. TFTPD_ERROR_UNDEFINED,
  2545. "Insufficient resources");
  2546. goto cleanup;
  2547. }
  2548. //
  2549. // Start to prepare the response.
  2550. //
  2551. ((unsigned short *) Request->Packet2)[0] = htons(TFTPD_LOGIN);
  2552. ((unsigned short *) Request->Packet2)[1] = htons((USHORT)-1);
  2553. //
  2554. // Now get the handle and delete the security entry if it is valid.
  2555. //
  2556. Options = SecurityString + strlen(SecurityString) + 1;
  2557. SecurityHandle = atoi(Options);
  2558. TftpdGetSecurityEntry((USHORT)(SecurityHandle >> 16), &Security);
  2559. if (Security.Validation == ((SecurityHandle) & 0xffff)) {
  2560. TftpdFreeSecurityEntry((USHORT)(SecurityHandle >> 16));
  2561. sprintf(Request->Packet2+4, "status %u ", 0);
  2562. } else {
  2563. sprintf(Request->Packet2+4, "status %u ", STATUS_INVALID_HANDLE);
  2564. }
  2565. packetLength = 4 + strlen(Request->Packet2+4);
  2566. for (CharPtr = Request->Packet2+4; *CharPtr; CharPtr ++) {
  2567. if (*CharPtr == ' ') {
  2568. *CharPtr = '\0';
  2569. }
  2570. }
  2571. //
  2572. // Wait for his ack, but not for too long.
  2573. //
  2574. Acked = FALSE;
  2575. Retry = 0;
  2576. while (!Acked && (Retry < 3) ){
  2577. //
  2578. // send the data
  2579. //
  2580. Status = sendto(
  2581. LoginPort,
  2582. Request->Packet2,
  2583. packetLength,
  2584. 0,
  2585. (struct sockaddr *) &Request->ForeignAddress,
  2586. sizeof(struct sockaddr_in));
  2587. if( SOCKET_ERROR == Status ){
  2588. DbgPrint("TftpdHandleLogin: sendto failed=%d\n",
  2589. WSAGetLastError() );
  2590. goto cleanup;
  2591. }
  2592. //
  2593. // wait for the ack
  2594. //
  2595. FD_ZERO( &loginfds );
  2596. FD_ZERO( &exceptfds );
  2597. FD_SET( LoginPort, &loginfds );
  2598. FD_SET( LoginPort, &exceptfds );
  2599. timeval.tv_sec = 2;
  2600. timeval.tv_usec = 0;
  2601. Status = select(0, &loginfds, NULL, &exceptfds, &timeval);
  2602. if( SOCKET_ERROR == Status ){
  2603. DbgPrint("TftpdHandleLogin: select failed=%d\n",
  2604. WSAGetLastError() );
  2605. goto cleanup;
  2606. }
  2607. if ((Status > 0) && (FD_ISSET(LoginPort, &loginfds))) {
  2608. //
  2609. // Got response, maybe
  2610. //
  2611. AddressLength = sizeof(LoginAddress);
  2612. BytesAck =
  2613. recvfrom(
  2614. LoginPort,
  2615. Request->Packet1,
  2616. sizeof(Request->Packet1),
  2617. 0,
  2618. (struct sockaddr *) &LoginAddress,
  2619. &AddressLength);
  2620. if( SOCKET_ERROR == BytesAck ){
  2621. DbgPrint("TftpdHandleLogin: recvfrom failed=%d\n",
  2622. WSAGetLastError() );
  2623. goto cleanup;
  2624. }
  2625. if (CHECK_ACK(Request->Packet1, TFTPD_LOGIN, (USHORT)-1)) {
  2626. Acked = TRUE;
  2627. }
  2628. }
  2629. Retry ++;
  2630. } // end while.
  2631. //
  2632. // If the ack timed out, don't worry about it.
  2633. //
  2634. } else {
  2635. DbgPrint("TftpdHandleLogin: invalid OperationType=%s?\n", OperationType );
  2636. TftpdErrorPacket(
  2637. (struct sockaddr *) &Request->ForeignAddress,
  2638. Request->Packet2,
  2639. Request->TftpdPort,
  2640. TFTPD_ERROR_ILLEGAL_OPERATION,
  2641. NULL);
  2642. goto cleanup;
  2643. }
  2644. cleanup:
  2645. if (LoginPort != INVALID_SOCKET) {
  2646. closesocket(LoginPort);
  2647. }
  2648. // free(Request);
  2649. return 0;
  2650. }
  2651. #endif //defined(REMOTE_BOOT_SECURITY)
  2652. #if defined(REMOTE_BOOT_SECURITY)
  2653. DWORD
  2654. TftpdHandleKey(
  2655. PVOID Argument
  2656. )
  2657. /*++
  2658. Routine Description:
  2659. This handles an incoming key.
  2660. Arguments:
  2661. Argument - buffer containing the read request datagram
  2662. freed when done.
  2663. Return Value:
  2664. Exit status
  2665. 0 == success
  2666. 1 == failure
  2667. N >0 failure
  2668. --*/
  2669. {
  2670. int Status, err;
  2671. int packetLength;
  2672. struct timeval timeval;
  2673. struct sockaddr_in LoginAddress;
  2674. BOOL Acked;
  2675. int AddressLength;
  2676. char * CharPtr;
  2677. PTFTP_REQUEST Request;
  2678. char * OperationType;
  2679. char * SpiString;
  2680. char * SecurityString;
  2681. ULONG SpiValue;
  2682. ULONG KeyValue;
  2683. ULONG SecurityHandle;
  2684. SOCKET LoginPort = INVALID_SOCKET;
  2685. HANDLE IpsecHandle = INVALID_HANDLE_VALUE;
  2686. BOOL IOStatus;
  2687. char PolicyBuffer[sizeof(IPSEC_SET_POLICY) + sizeof(IPSEC_POLICY_INFO)];
  2688. PIPSEC_SET_POLICY SetPolicy = (PIPSEC_SET_POLICY)PolicyBuffer;
  2689. IPSEC_FILTER OutboundFilter;
  2690. IPSEC_FILTER InboundFilter;
  2691. IPSEC_GET_SPI GetSpi;
  2692. char SaBuffer[sizeof(IPSEC_ADD_UPDATE_SA) + (6 * sizeof(ULONG))];
  2693. PIPSEC_ADD_UPDATE_SA AddUpdateSa;
  2694. IPSEC_DELETE_POLICY DeletePolicy;
  2695. // char EnumPolicyBuffer[(UINT)(FIELD_OFFSET(IPSEC_ENUM_POLICY, pInfo[0]))];
  2696. char EnumPolicyBuffer[2 * sizeof(DWORD)];
  2697. PIPSEC_ENUM_POLICY EnumPolicy;
  2698. DWORD EnumPolicySize;
  2699. char MyName[80];
  2700. PHOSTENT Host;
  2701. DWORD BytesReturned;
  2702. DWORD i;
  2703. LARGE_INTEGER SystemTime;
  2704. TFTPD_SECURITY Security;
  2705. //
  2706. // Parse the request. The initial request should always be a
  2707. // "spi".
  2708. //
  2709. Request = (PTFTP_REQUEST) Argument;
  2710. OperationType = &Request->Packet1[4];
  2711. //
  2712. // Convert the operation to all lower case for comparison
  2713. //
  2714. for (CharPtr = OperationType; *CharPtr; CharPtr ++) {
  2715. *CharPtr = (char)tolower(*CharPtr);
  2716. }
  2717. if (strcmp(OperationType, "spi") == 0) {
  2718. SpiString = OperationType + sizeof("spi");
  2719. SpiValue = atoi(SpiString);
  2720. OperationType = SpiString + strlen(SpiString) + 1;
  2721. //
  2722. // See if the client request encryption of the key.
  2723. //
  2724. if (strcmp(OperationType, "security") == 0) {
  2725. SecurityString = OperationType + sizeof("security");
  2726. SecurityHandle = atoi(SecurityString);
  2727. //
  2728. // High 16 bits of handle is index, low 16 bits is validation.
  2729. //
  2730. TftpdGenerateKeyForSecurityEntry((USHORT)(SecurityHandle >> 16), &Security);
  2731. if ((Security.Validation != ((Request->SecurityHandle) & 0xffff)) ||
  2732. (!Security.GeneratedKey)) {
  2733. DbgPrint("TftpdHandleRead: SecurityHandle %x is invalid.\n",
  2734. Request->SecurityHandle);
  2735. TftpdErrorPacket(
  2736. (struct sockaddr *) &Request->ForeignAddress,
  2737. Request->Packet2,
  2738. Request->TftpdPort,
  2739. TFTPD_ERROR_UNDEFINED,
  2740. "Invalid security handle");
  2741. goto cleanup;
  2742. }
  2743. KeyValue = Security.Key;
  2744. DbgPrint("TftpdHandleKey: SPI %lx, retrieved secure key %lx\n", SpiValue, KeyValue);
  2745. } else {
  2746. NtQuerySystemTime(&SystemTime);
  2747. KeyValue = (ULONG)(SystemTime.QuadPart % Request->ForeignAddress.sin_addr.s_addr);
  2748. SecurityHandle = 0;
  2749. DbgPrint("TftpdHandleKey: SPI %lx, generated key %lx\n", SpiValue, KeyValue);
  2750. }
  2751. //
  2752. // Open IPSEC so we can send down IOCTLS.
  2753. //
  2754. IpsecHandle = CreateFileW(
  2755. DD_IPSEC_DOS_NAME, // IPSEC device name
  2756. GENERIC_READ | GENERIC_WRITE, // access (read-write) mode
  2757. 0, // share mode
  2758. NULL, // pointer to security attributes
  2759. OPEN_EXISTING, // how to create
  2760. 0, // file attributes
  2761. NULL); // handle to file with attributes to copy
  2762. if (IpsecHandle == INVALID_HANDLE_VALUE) {
  2763. DbgPrint("TftpdHandleKey: Could not open <%ws>\n", DD_IPSEC_DOS_NAME);
  2764. TftpdErrorPacket(
  2765. (struct sockaddr *) &Request->ForeignAddress,
  2766. Request->Packet2,
  2767. Request->TftpdPort,
  2768. TFTPD_ERROR_UNDEFINED,
  2769. "Insufficient resources");
  2770. goto cleanup;
  2771. }
  2772. //
  2773. // See how many policies are defined. First send down a buffer
  2774. // with room for no policies, to see how many there are.
  2775. //
  2776. EnumPolicy = (PIPSEC_ENUM_POLICY)EnumPolicyBuffer;
  2777. memset(EnumPolicy, 0, sizeof(EnumPolicyBuffer));
  2778. IOStatus = DeviceIoControl(
  2779. IpsecHandle, // Driver handle
  2780. IOCTL_IPSEC_ENUM_POLICIES, // Control code
  2781. EnumPolicy, // Input buffer
  2782. sizeof(EnumPolicyBuffer), // Input buffer size
  2783. EnumPolicy, // Output buffer
  2784. sizeof(EnumPolicyBuffer), // Output buffer size
  2785. &BytesReturned,
  2786. NULL);
  2787. if (!IOStatus) {
  2788. if (GetLastError() != ERROR_MORE_DATA) {
  2789. DbgPrint("TftpdHandleKey: IOCTL_IPSEC_ENUM_POLICY #1 failed %x\n", GetLastError());
  2790. TftpdErrorPacket(
  2791. (struct sockaddr *) &Request->ForeignAddress,
  2792. Request->Packet2,
  2793. Request->TftpdPort,
  2794. TFTPD_ERROR_UNDEFINED,
  2795. "IOCTL_IPSEC_ENUM_POLICIES");
  2796. goto cleanup;
  2797. }
  2798. EnumPolicySize = FIELD_OFFSET(IPSEC_ENUM_POLICY, pInfo[0]) +
  2799. sizeof(IPSEC_POLICY_INFO) * EnumPolicy->NumEntriesPresent;
  2800. EnumPolicy = malloc(EnumPolicySize);
  2801. if (EnumPolicy == NULL) {
  2802. DbgPrint("TftpdHandleKey: alloc ENUM_POLICIES buffer failed %x\n", GetLastError());
  2803. TftpdErrorPacket(
  2804. (struct sockaddr *) &Request->ForeignAddress,
  2805. Request->Packet2,
  2806. Request->TftpdPort,
  2807. TFTPD_ERROR_UNDEFINED,
  2808. "IOCTL_IPSEC_ENUM_POLICIES");
  2809. goto cleanup;
  2810. }
  2811. //
  2812. // Re-submit the IOCTL.
  2813. //
  2814. memset(EnumPolicy, 0, EnumPolicySize);
  2815. IOStatus = DeviceIoControl(
  2816. IpsecHandle, // Driver handle
  2817. IOCTL_IPSEC_ENUM_POLICIES, // Control code
  2818. EnumPolicy, // Input buffer
  2819. EnumPolicySize, // Input buffer size
  2820. EnumPolicy, // Output buffer
  2821. EnumPolicySize, // Output buffer size
  2822. &BytesReturned,
  2823. NULL);
  2824. //
  2825. // We may get MORE_DATA if someone just added a policy, but
  2826. // that is OK since it won't be for this remote.
  2827. //
  2828. if (!IOStatus && (GetLastError() != ERROR_MORE_DATA)) {
  2829. DbgPrint("TftpdHandleKey: IOCTL_IPSEC_ENUM_POLICY #2 failed %x\n", GetLastError());
  2830. TftpdErrorPacket(
  2831. (struct sockaddr *) &Request->ForeignAddress,
  2832. Request->Packet2,
  2833. Request->TftpdPort,
  2834. TFTPD_ERROR_UNDEFINED,
  2835. "IOCTL_IPSEC_ENUM_POLICIES");
  2836. free(EnumPolicy);
  2837. goto cleanup;
  2838. }
  2839. //
  2840. // Display all the policies.
  2841. //
  2842. // Delete any policies involving the remote machine.
  2843. //
  2844. for (i = 0; i < EnumPolicy->NumEntriesPresent; i++) {
  2845. if ((EnumPolicy->pInfo[i].AssociatedFilter.SrcAddr ==
  2846. Request->ForeignAddress.sin_addr.s_addr) ||
  2847. (EnumPolicy->pInfo[i].AssociatedFilter.DestAddr ==
  2848. Request->ForeignAddress.sin_addr.s_addr)) {
  2849. DeletePolicy.NumEntries = 1;
  2850. DeletePolicy.pInfo[0] = EnumPolicy->pInfo[i];
  2851. IOStatus = DeviceIoControl(
  2852. IpsecHandle, // Driver handle
  2853. IOCTL_IPSEC_DELETE_POLICY, // Control code
  2854. &DeletePolicy, // Input buffer
  2855. sizeof(IPSEC_DELETE_POLICY), // Input buffer size
  2856. NULL, // Output buffer
  2857. 0, // Output buffer size
  2858. &BytesReturned,
  2859. NULL);
  2860. if (!IOStatus) {
  2861. DbgPrint("TftpdHandleKey: IOCTL_IPSEC_DELETE_POLICY(%lx, %lx) failed %x\n",
  2862. EnumPolicy->pInfo[i].AssociatedFilter.SrcAddr,
  2863. EnumPolicy->pInfo[i].AssociatedFilter.DestAddr,
  2864. GetLastError());
  2865. }
  2866. }
  2867. }
  2868. free(EnumPolicy);
  2869. } else {
  2870. //
  2871. // If the call succeeds, we don't need to do anything, since
  2872. // there should have been 0 policies returned.
  2873. //
  2874. }
  2875. //
  2876. // Get our local IP address.
  2877. //
  2878. gethostname(MyName, sizeof(MyName));
  2879. Host = gethostbyname(MyName);
  2880. //
  2881. // Set the policy. We need two filters, one for outbound and
  2882. // one for inbound.
  2883. //
  2884. memset(&OutboundFilter, 0, sizeof(IPSEC_FILTER));
  2885. memset(&InboundFilter, 0, sizeof(IPSEC_FILTER));
  2886. OutboundFilter.SrcAddr = *(DWORD *)Host->h_addr;
  2887. OutboundFilter.SrcMask = 0xffffffff;
  2888. // OutboundFilter.SrcPort = 0x8B; // netbios session port
  2889. OutboundFilter.DestAddr = Request->ForeignAddress.sin_addr.s_addr;
  2890. OutboundFilter.DestMask = 0xffffffff;
  2891. OutboundFilter.Protocol = 0x6; // TCP
  2892. InboundFilter.SrcAddr = Request->ForeignAddress.sin_addr.s_addr;
  2893. InboundFilter.SrcMask = 0xffffffff;
  2894. InboundFilter.DestAddr = *(DWORD *)Host->h_addr;
  2895. InboundFilter.DestMask = 0xffffffff;
  2896. // InboundFilter.DestPort = 0x8B; // netbios session port
  2897. InboundFilter.Protocol = 0x6; // TCP
  2898. memset(SetPolicy, 0, sizeof(PolicyBuffer));
  2899. SetPolicy->NumEntries = 2;
  2900. SetPolicy->pInfo[0].Index = 1;
  2901. SetPolicy->pInfo[0].AssociatedFilter = OutboundFilter;
  2902. SetPolicy->pInfo[1].Index = 2;
  2903. SetPolicy->pInfo[1].AssociatedFilter = InboundFilter;
  2904. IOStatus = DeviceIoControl(
  2905. IpsecHandle, // Driver handle
  2906. IOCTL_IPSEC_SET_POLICY, // Control code
  2907. SetPolicy, // Input buffer
  2908. sizeof(PolicyBuffer), // Input buffer size
  2909. NULL, // Output buffer
  2910. 0, // Output buffer size
  2911. &BytesReturned,
  2912. NULL);
  2913. if (!IOStatus) {
  2914. DbgPrint("TftpdHandleKey: IOCTL_IPSEC_SET_POLICY failed %x\n", GetLastError());
  2915. TftpdErrorPacket(
  2916. (struct sockaddr *) &Request->ForeignAddress,
  2917. Request->Packet2,
  2918. Request->TftpdPort,
  2919. TFTPD_ERROR_UNDEFINED,
  2920. "IOCTL_IPSEC_SET_POLICY");
  2921. goto cleanup;
  2922. }
  2923. //
  2924. // Now get an SPI to give to the remote.
  2925. //
  2926. GetSpi.Context = 0;
  2927. GetSpi.InstantiatedFilter = InboundFilter;
  2928. IOStatus = DeviceIoControl(
  2929. IpsecHandle, // Driver handle
  2930. IOCTL_IPSEC_GET_SPI, // Control code
  2931. &GetSpi, // Input buffer
  2932. sizeof(IPSEC_GET_SPI), // Input buffer size
  2933. &GetSpi, // Output buffer
  2934. sizeof(IPSEC_GET_SPI), // Output buffer size
  2935. &BytesReturned,
  2936. NULL);
  2937. if (!IOStatus) {
  2938. DbgPrint("TftpdHandleKey: IOCTL_IPSEC_GET_SPI failed %x\n", GetLastError());
  2939. TftpdErrorPacket(
  2940. (struct sockaddr *) &Request->ForeignAddress,
  2941. Request->Packet2,
  2942. Request->TftpdPort,
  2943. TFTPD_ERROR_UNDEFINED,
  2944. "IOCTL_IPSEC_GET_SPI");
  2945. goto cleanup;
  2946. }
  2947. //
  2948. // Set up the security association for the outbound
  2949. // connection.
  2950. //
  2951. AddUpdateSa = (PIPSEC_ADD_UPDATE_SA)SaBuffer;
  2952. memset(AddUpdateSa, 0, sizeof(SaBuffer));
  2953. AddUpdateSa->SAInfo.Context = GetSpi.Context;
  2954. AddUpdateSa->SAInfo.NumSAs = 1;
  2955. AddUpdateSa->SAInfo.InstantiatedFilter = OutboundFilter;
  2956. AddUpdateSa->SAInfo.SecAssoc[0].Operation = Encrypt;
  2957. AddUpdateSa->SAInfo.SecAssoc[0].SPI = SpiValue;
  2958. AddUpdateSa->SAInfo.SecAssoc[0].IntegrityAlgo.algoIdentifier = IPSEC_AH_MD5;
  2959. AddUpdateSa->SAInfo.SecAssoc[0].IntegrityAlgo.algoKeylen = 4 * sizeof(ULONG);
  2960. AddUpdateSa->SAInfo.SecAssoc[0].ConfAlgo.algoIdentifier = IPSEC_ESP_DES;
  2961. AddUpdateSa->SAInfo.SecAssoc[0].ConfAlgo.algoKeylen = 2 * sizeof(ULONG);
  2962. AddUpdateSa->SAInfo.KeyLen = 6 * sizeof(ULONG);
  2963. memcpy(AddUpdateSa->SAInfo.KeyMat, &KeyValue, sizeof(ULONG));
  2964. memcpy(AddUpdateSa->SAInfo.KeyMat+sizeof(ULONG), &KeyValue, sizeof(ULONG));
  2965. memcpy(AddUpdateSa->SAInfo.KeyMat+(2*sizeof(ULONG)), &KeyValue, sizeof(ULONG));
  2966. memcpy(AddUpdateSa->SAInfo.KeyMat+(3*sizeof(ULONG)), &KeyValue, sizeof(ULONG));
  2967. memcpy(AddUpdateSa->SAInfo.KeyMat+(4*sizeof(ULONG)), &KeyValue, sizeof(ULONG));
  2968. memcpy(AddUpdateSa->SAInfo.KeyMat+(5*sizeof(ULONG)), &KeyValue, sizeof(ULONG));
  2969. IOStatus = DeviceIoControl(
  2970. IpsecHandle, // Driver handle
  2971. IOCTL_IPSEC_ADD_SA, // Control code
  2972. AddUpdateSa, // Input buffer
  2973. FIELD_OFFSET(IPSEC_ADD_UPDATE_SA, SAInfo.KeyMat[0]) +
  2974. AddUpdateSa->SAInfo.KeyLen, // Input buffer size
  2975. NULL, // Output buffer
  2976. 0, // Output buffer size
  2977. &BytesReturned,
  2978. NULL);
  2979. if (!IOStatus) {
  2980. DbgPrint("TftpdHandleKey: IOCTL_IPSEC_ADD_SA failed %x\n", GetLastError());
  2981. TftpdErrorPacket(
  2982. (struct sockaddr *) &Request->ForeignAddress,
  2983. Request->Packet2,
  2984. Request->TftpdPort,
  2985. TFTPD_ERROR_UNDEFINED,
  2986. "IOCTL_IPSEC_ADD_SA");
  2987. goto cleanup;
  2988. }
  2989. //
  2990. // Set up the security association for the inbound connection.
  2991. // If our Operation is "None", then IPSEC does this for us.
  2992. //
  2993. if (AddUpdateSa->SAInfo.SecAssoc[0].Operation != None) {
  2994. AddUpdateSa->SAInfo.SecAssoc[0].SPI = GetSpi.SPI;
  2995. AddUpdateSa->SAInfo.InstantiatedFilter = InboundFilter;
  2996. IOStatus = DeviceIoControl(
  2997. IpsecHandle, // Driver handle
  2998. IOCTL_IPSEC_UPDATE_SA, // Control code
  2999. AddUpdateSa, // Input buffer
  3000. FIELD_OFFSET(IPSEC_ADD_UPDATE_SA, SAInfo.KeyMat[0]) +
  3001. AddUpdateSa->SAInfo.KeyLen, // Input buffer size
  3002. NULL, // Output buffer
  3003. 0, // Output buffer size
  3004. &BytesReturned,
  3005. NULL);
  3006. if (!IOStatus) {
  3007. DbgPrint("TftpdHandleKey: IOCTL_IPSEC_UPDATE_SA failed %x\n", GetLastError());
  3008. TftpdErrorPacket(
  3009. (struct sockaddr *) &Request->ForeignAddress,
  3010. Request->Packet2,
  3011. Request->TftpdPort,
  3012. TFTPD_ERROR_UNDEFINED,
  3013. "IOCTL_IPSEC_UPDATE_SA");
  3014. goto cleanup;
  3015. }
  3016. }
  3017. //
  3018. // Open a new socket for this request
  3019. //
  3020. LoginPort =
  3021. socket(
  3022. AF_INET,
  3023. SOCK_DGRAM,
  3024. 0);
  3025. if (LoginPort == INVALID_SOCKET) {
  3026. DbgPrint("TftpdHandleKey: cannot open socket, Error=%d\n",
  3027. WSAGetLastError() );
  3028. TftpdErrorPacket(
  3029. (struct sockaddr *) &Request->ForeignAddress,
  3030. Request->Packet2,
  3031. Request->TftpdPort,
  3032. TFTPD_ERROR_UNDEFINED,
  3033. "Insufficient resources");
  3034. goto cleanup;
  3035. }
  3036. //
  3037. // Bind to a random address
  3038. //
  3039. LoginAddress.sin_family = AF_INET;
  3040. LoginAddress.sin_port = 0;
  3041. LoginAddress.sin_addr.s_addr = INADDR_ANY;
  3042. Status =
  3043. bind(
  3044. LoginPort,
  3045. (struct sockaddr *) &LoginAddress,
  3046. sizeof(LoginAddress)
  3047. );
  3048. if (Status) {
  3049. DbgPrint("TftpdHandleKey: cannot bind socket, error=%d.\n",
  3050. WSAGetLastError() );
  3051. TftpdErrorPacket(
  3052. (struct sockaddr *) &Request->ForeignAddress,
  3053. Request->Packet2,
  3054. Request->TftpdPort,
  3055. TFTPD_ERROR_UNDEFINED,
  3056. "Insufficient resources");
  3057. goto cleanup;
  3058. }
  3059. //
  3060. // Generate the response for the client.
  3061. //
  3062. ((unsigned short *) Request->Packet2)[0] = htons(TFTPD_KEY);
  3063. Request->Packet2[2] = Request->Packet1[2]; // copy sequence number
  3064. Request->Packet2[3] = Request->Packet1[3];
  3065. //
  3066. // They key is sent as hex digits since it might be longer
  3067. // than four bytes.
  3068. //
  3069. if (SecurityHandle == 0) {
  3070. //
  3071. // No security, send key in the clear.
  3072. //
  3073. sprintf(Request->Packet2+4, "spi %d key %2.2x%2.2x%2.2x%2.2x",
  3074. GetSpi.SPI,
  3075. ((PUCHAR)(&KeyValue))[0],
  3076. ((PUCHAR)(&KeyValue))[1],
  3077. ((PUCHAR)(&KeyValue))[2],
  3078. ((PUCHAR)(&KeyValue))[3]);
  3079. packetLength = 4 + strlen(Request->Packet2+4);
  3080. } else {
  3081. PCHAR SignLoc;
  3082. ULONG i;
  3083. //
  3084. // Security requested, so send the encrypted key and the sign.
  3085. //
  3086. sprintf(Request->Packet2+4, "spi %d security %d sign ",
  3087. GetSpi.SPI,
  3088. SecurityHandle);
  3089. packetLength = 4 + strlen(Request->Packet2+4);
  3090. SignLoc = Request->Packet2 + packetLength;
  3091. for (i = 0; i < NTLMSSP_MESSAGE_SIGNATURE_SIZE; i++) {
  3092. sprintf(SignLoc, "%2.2x", Security.Sign[i]);
  3093. SignLoc += 2;
  3094. packetLength += 2;
  3095. }
  3096. sprintf(Request->Packet2+packetLength, " key %2.2x%2.2x%2.2x%2.2x",
  3097. Security.SignedKey[0],
  3098. Security.SignedKey[1],
  3099. Security.SignedKey[2],
  3100. Security.SignedKey[3]);
  3101. packetLength += strlen(" key ") + (2 * sizeof(Security.SignedKey));
  3102. }
  3103. for (CharPtr = Request->Packet2+4; *CharPtr; CharPtr ++) {
  3104. if (*CharPtr == ' ') {
  3105. *CharPtr = '\0';
  3106. }
  3107. }
  3108. //
  3109. // Send the response back to the client.
  3110. //
  3111. Status = sendto(
  3112. LoginPort,
  3113. Request->Packet2,
  3114. packetLength,
  3115. 0,
  3116. (struct sockaddr *) &Request->ForeignAddress,
  3117. sizeof(struct sockaddr_in));
  3118. if( SOCKET_ERROR == Status ){
  3119. DbgPrint("TftpdHandleKey: sendto failed=%d\n",
  3120. WSAGetLastError() );
  3121. goto cleanup;
  3122. }
  3123. } else {
  3124. DbgPrint("TftpdHandleKey: invalid OperationType=%s?\n", OperationType );
  3125. TftpdErrorPacket(
  3126. (struct sockaddr *) &Request->ForeignAddress,
  3127. Request->Packet2,
  3128. Request->TftpdPort,
  3129. TFTPD_ERROR_ILLEGAL_OPERATION,
  3130. NULL);
  3131. goto cleanup;
  3132. }
  3133. cleanup:
  3134. if (IpsecHandle != INVALID_HANDLE_VALUE) {
  3135. CloseHandle(IpsecHandle);
  3136. }
  3137. if (LoginPort != INVALID_SOCKET) {
  3138. closesocket(LoginPort);
  3139. }
  3140. // free(Request);
  3141. return 0;
  3142. }
  3143. #endif //defined(REMOTE_BOOT_SECURITY)
  3144. // ========================================================================
  3145. int
  3146. TftpdDoRead(
  3147. int ReadFd,
  3148. char * Buffer,
  3149. int BufferSize,
  3150. int ReadMode)
  3151. /*++
  3152. Routine Description:
  3153. This does a read with the appropriate conversions for netascii or octet
  3154. modes.
  3155. Arguments:
  3156. ReadFd - file to read from
  3157. Buffer - Buffer to read into
  3158. BufferSize - size of buffer
  3159. ReadMode - O_TEXT or O_BINARY
  3160. O_TEXT means the netascii conversions must be done
  3161. O_BINARY means octet mode
  3162. Return Value:
  3163. BytesRead
  3164. Error?
  3165. --*/
  3166. {
  3167. int BytesRead;
  3168. int BytesWritten;
  3169. int BytesUsed;
  3170. char NextChar;
  3171. char State;
  3172. char LocalBuffer[MAX_TFTP_DATA];
  3173. int err;
  3174. if (ReadMode == O_BINARY) {
  3175. BytesRead = _read(ReadFd, Buffer, BufferSize);
  3176. if( BytesRead == -1 ){
  3177. DbgPrint("TftpdDoRead: read failed, errno=%d\n", errno );
  3178. SetLastError( errno );
  3179. }
  3180. return(BytesRead);
  3181. } else {
  3182. //
  3183. // Do those cr/lf conversions. A \r not followed by a \n must
  3184. // be followed by a \0.
  3185. //
  3186. BytesWritten = 0;
  3187. BytesUsed = 0;
  3188. State = '\0';
  3189. BytesRead = _read(ReadFd, LocalBuffer, sizeof(LocalBuffer));
  3190. if( BytesRead == -1 ){
  3191. DbgPrint("TftpdDoRead: read failed, errno=%d\n", errno );
  3192. SetLastError( errno );
  3193. return -1;
  3194. }
  3195. while ((BytesUsed < BytesRead) && (BytesWritten < BufferSize)) {
  3196. NextChar = LocalBuffer[BytesUsed++];
  3197. if (State == '\r') {
  3198. if (NextChar == '\n') {
  3199. Buffer[BytesWritten++] = NextChar;
  3200. State = '\0';
  3201. } else {
  3202. Buffer[BytesWritten++] = '\0';
  3203. Buffer[BytesWritten++] = NextChar;
  3204. State = '\0';
  3205. }
  3206. } else {
  3207. Buffer[BytesWritten++] = NextChar;
  3208. State = '\0';
  3209. }
  3210. if (NextChar == '\r') {
  3211. State = '\r';
  3212. }
  3213. }
  3214. err = _lseek(ReadFd, BytesUsed - BytesRead, SEEK_CUR);
  3215. if( err == -1 ){
  3216. DbgPrint("TftpdDoRead: lseek failed, errno=%d\n",
  3217. errno );
  3218. SetLastError( errno );
  3219. return -1;
  3220. }
  3221. return(BytesWritten);
  3222. }
  3223. }
  3224. // End function TftpdDoRead.
  3225. // ========================================================================
  3226. int
  3227. TftpdDoWrite(
  3228. int WriteFd,
  3229. char * Buffer,
  3230. int BufferSize,
  3231. int WriteMode,
  3232. char * State)
  3233. /*++
  3234. Routine Description:
  3235. This does a write with the appropriate conversions for netascii or octet
  3236. modes.
  3237. Arguments:
  3238. WriteFd - file to write to
  3239. Buffer - Buffer to read into
  3240. BufferSize - size of buffer
  3241. WriteMode - O_TEXT or O_BINARY
  3242. O_TEXT means the netascii conversions must be done
  3243. O_BINARY means octet mode
  3244. State - pointer to the current output state. If the last character in the
  3245. buffer is a '\r', that fact must be remembered.
  3246. Return Value:
  3247. BytesWritten
  3248. Error?
  3249. --*/
  3250. {
  3251. int BytesWritten;
  3252. int i;
  3253. char OutputBuffer[MAX_TFTP_DATA*2];
  3254. int OutputPointer;
  3255. if (WriteMode == O_BINARY) {
  3256. BytesWritten = _write(WriteFd, Buffer, BufferSize);
  3257. if( BytesWritten == -1 ){
  3258. DbgPrint("TftpdDoWrite: write failed=%d\n", errno );
  3259. SetLastError( errno );
  3260. }
  3261. } else {
  3262. //
  3263. // Do those cr/lf conversions. If a '\r' followed by a '\0' is
  3264. // followed by a '\0', the '\0' is stripped.
  3265. //
  3266. OutputPointer = 0;
  3267. for (i=0; i<BufferSize; i++) {
  3268. if ((*State == '\r') && (Buffer[i] == '\0')) {
  3269. *State = '\0';
  3270. } else {
  3271. OutputBuffer[OutputPointer ++] = Buffer[i];
  3272. if (Buffer[i] == '\r') {
  3273. *State = '\r';
  3274. }
  3275. }
  3276. }
  3277. BytesWritten = _write(WriteFd, Buffer, OutputPointer);
  3278. if( BytesWritten == -1 ){
  3279. DbgPrint("TftpdDoWrite: write failed=%d\n", errno );
  3280. SetLastError( errno );
  3281. }
  3282. }
  3283. return(BytesWritten);
  3284. }
  3285. // End function TftpdDoWrite.
  3286. // ========================================================================
  3287. // EOF.