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.

1195 lines
31 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. tftp.c
  5. Abstract:
  6. Boot loader TFTP routines.
  7. Author:
  8. Chuck Lenzmeier (chuckl) December 27, 1996
  9. Revision History:
  10. Notes:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //
  15. // This removes macro redefinitions which appear because we define __RPC_DOS__,
  16. // but rpc.h defines __RPC_WIN32__
  17. //
  18. #pragma warning(disable:4005)
  19. //
  20. // As of 12/17/98, SECURITY_DOS is *not* defined - adamba
  21. //
  22. #if defined(SECURITY_DOS)
  23. //
  24. // These appear because we defined SECURITY_DOS
  25. //
  26. #define __far
  27. #define __pascal
  28. #define __loadds
  29. #endif
  30. #include <security.h>
  31. #include <rpc.h>
  32. #include <spseal.h>
  33. #if defined(_X86_)
  34. #include <bldrx86.h>
  35. #endif
  36. #if defined(SECURITY_DOS)
  37. //
  38. // PSECURITY_STRING is not supposed to be used when SECURITY_DOS is
  39. // defined -- it should be a WCHAR*. Unfortunately ntlmsp.h breaks
  40. // this rule and even uses the SECURITY_STRING structure, which there
  41. // is really no equivalent for in 16-bit mode.
  42. //
  43. typedef SEC_WCHAR * SECURITY_STRING; // more-or-less the intention where it is used
  44. typedef SEC_WCHAR * PSECURITY_STRING;
  45. #endif
  46. #include <ntlmsp.h>
  47. #if DBG
  48. ULONG NetDebugFlag =
  49. DEBUG_ERROR |
  50. DEBUG_CONN_ERROR |
  51. //DEBUG_LOUD |
  52. //DEBUG_REAL_LOUD |
  53. //DEBUG_STATISTICS |
  54. //DEBUG_SEND_RECEIVE |
  55. //DEBUG_TRACE |
  56. //DEBUG_ARP |
  57. //DEBUG_INITIAL_BREAK |
  58. 0;
  59. #endif
  60. //
  61. // Global variables
  62. //
  63. CONNECTION NetTftpConnection;
  64. UCHAR NetTftpPacket[3][MAXIMUM_TFTP_PACKET_LENGTH];
  65. #if defined(REMOTE_BOOT_SECURITY)
  66. //
  67. // Globals used during login.
  68. //
  69. static CHAR OutgoingMessage[1024];
  70. static CHAR IncomingMessage[1024];
  71. static CredHandle CredentialHandle;
  72. static BOOLEAN CredentialHandleValid = FALSE;
  73. CtxtHandle TftpClientContextHandle;
  74. BOOLEAN TftpClientContextHandleValid = FALSE;
  75. #endif // defined(REMOTE_BOOT_SECURITY)
  76. //
  77. // Local declarations.
  78. //
  79. NTSTATUS
  80. TftpGet (
  81. IN PCONNECTION Connection,
  82. IN PTFTP_REQUEST Request
  83. );
  84. NTSTATUS
  85. TftpPut (
  86. IN PCONNECTION Connection,
  87. IN PTFTP_REQUEST Request
  88. );
  89. NTSTATUS
  90. TftpGetPut (
  91. IN PTFTP_REQUEST Request
  92. )
  93. {
  94. NTSTATUS status;
  95. PCONNECTION connection = NULL;
  96. ULONG FileSize;
  97. ULONG basePage;
  98. #if 0 && DBG
  99. LARGE_INTEGER startTime;
  100. LARGE_INTEGER endTime;
  101. LARGE_INTEGER elapsedTime;
  102. LARGE_INTEGER frequency;
  103. ULONG seconds;
  104. ULONG secondsFraction;
  105. ULONG bps;
  106. ULONG bpsFraction;
  107. #endif
  108. #if defined(REMOTE_BOOT)
  109. if (!NetworkBootRom) {
  110. // Booting from the hard disk cache because server is not available
  111. return STATUS_UNSUCCESSFUL;
  112. }
  113. #endif // defined(REMOTE_BOOT)
  114. #ifndef EFI
  115. //
  116. // We don't need to do any of this initialization if
  117. // we're in EFI.
  118. //
  119. FileSize = Request->MaximumLength;
  120. status = ConnInitialize(
  121. &connection,
  122. Request->Operation,
  123. Request->ServerIpAddress,
  124. TFTP_PORT,
  125. Request->RemoteFileName,
  126. 0,
  127. #if defined(REMOTE_BOOT_SECURITY)
  128. &Request->SecurityHandle, // will be set to 0 if security negotiation fails
  129. #endif // defined(REMOTE_BOOT_SECURITY)
  130. &FileSize
  131. );
  132. if ( !NT_SUCCESS(status) ) {
  133. return status;
  134. }
  135. #if 0 && DBG
  136. IF_DEBUG(STATISTICS) {
  137. startTime = KeQueryPerformanceCounter( &frequency );
  138. }
  139. #endif
  140. if ( Request->Operation == TFTP_RRQ ) {
  141. if ( Request->MemoryAddress != NULL ) {
  142. if ( Request->MaximumLength < FileSize ) {
  143. ConnError(
  144. connection,
  145. connection->RemoteHost,
  146. connection->RemotePort,
  147. TFTP_ERROR_UNDEFINED,
  148. "File too big"
  149. );
  150. return STATUS_INSUFFICIENT_RESOURCES;
  151. }
  152. } else {
  153. //
  154. // NB: (ChuckL) Removed code added by MattH to check for
  155. // allocation >= 1/3 of (BlUsableLimit - BlUsableBase)
  156. // because calling code now sets BlUsableLimit to 1 GB
  157. // or higher.
  158. //
  159. status = BlAllocateAlignedDescriptor(
  160. Request->MemoryType,
  161. 0,
  162. BYTES_TO_PAGES(FileSize),
  163. 0,
  164. &basePage
  165. );
  166. if (status != ESUCCESS) {
  167. ConnError(
  168. connection,
  169. connection->RemoteHost,
  170. connection->RemotePort,
  171. TFTP_ERROR_UNDEFINED,
  172. "File too big"
  173. );
  174. return STATUS_INSUFFICIENT_RESOURCES;
  175. }
  176. Request->MemoryAddress = (PUCHAR)ULongToPtr( (basePage << PAGE_SHIFT) );
  177. Request->MaximumLength = FileSize;
  178. DPRINT( REAL_LOUD, ("TftpGetPut: allocated %d bytes at 0x%08x\n",
  179. Request->MaximumLength, Request->MemoryAddress) );
  180. }
  181. status = TftpGet( connection, Request );
  182. } else {
  183. status = TftpPut( connection, Request );
  184. }
  185. #else // #ifndef EFI
  186. if ( Request->Operation == TFTP_RRQ ) {
  187. status = TftpGet( connection, Request );
  188. } else {
  189. status = TftpPut( connection, Request );
  190. }
  191. if( status != STATUS_SUCCESS ) {
  192. status = STATUS_INSUFFICIENT_RESOURCES;
  193. }
  194. #endif // #ifndef EFI
  195. if ( !NT_SUCCESS(status) ) {
  196. return status;
  197. }
  198. return status;
  199. } // TftpGetPut
  200. #ifdef EFI
  201. extern VOID
  202. FlipToPhysical (
  203. );
  204. extern VOID
  205. FlipToVirtual (
  206. );
  207. NTSTATUS
  208. TftpGet (
  209. IN OUT PCONNECTION Connection,
  210. IN PTFTP_REQUEST Request
  211. )
  212. {
  213. EFI_STATUS Status;
  214. CHAR16 *Size = NULL;
  215. PVOID MyBuffer = NULL;
  216. EFI_IP_ADDRESS MyServerIpAddress;
  217. INTN Count = 0;
  218. INTN BufferSizeX = sizeof(CHAR16);
  219. ULONG basePage;
  220. UINTN BlockSize = 512;
  221. //
  222. // They sent us an IP address as a ULONG. We need to convert
  223. // that into an EFI_IP_ADDRESS.
  224. //
  225. for( Count = 0; Count < 4; Count++ ) {
  226. MyServerIpAddress.v4.Addr[Count] = PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr[Count];
  227. }
  228. //
  229. // Get the file size, allocate some memory, then get the file.
  230. //
  231. FlipToPhysical();
  232. Status = PXEClient->Mtftp( PXEClient,
  233. EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
  234. Size,
  235. TRUE,
  236. &BufferSizeX,
  237. &BlockSize,
  238. &MyServerIpAddress,
  239. Request->RemoteFileName,
  240. 0,
  241. FALSE );
  242. FlipToVirtual();
  243. if( Status != EFI_SUCCESS ) {
  244. return (NTSTATUS)Status;
  245. }
  246. Status = BlAllocateAlignedDescriptor(
  247. Request->MemoryType,
  248. 0,
  249. (ULONG) BYTES_TO_PAGES(BufferSizeX),
  250. 0,
  251. &basePage
  252. );
  253. if ( Status != ESUCCESS ) {
  254. if( BdDebuggerEnabled ) {
  255. DbgPrint( "TftpGet: BlAllocate failed! (%d)\n", Status );
  256. }
  257. return STATUS_INSUFFICIENT_RESOURCES;
  258. }
  259. Request->MemoryAddress = (PUCHAR)ULongToPtr( (basePage << PAGE_SHIFT) );
  260. Request->MaximumLength = (ULONG)BufferSizeX;
  261. //
  262. // Make sure we send EFI a physical address.
  263. //
  264. MyBuffer = (PVOID)((ULONGLONG)(Request->MemoryAddress) & ~KSEG0_BASE);
  265. FlipToPhysical();
  266. Status = PXEClient->Mtftp( PXEClient,
  267. EFI_PXE_BASE_CODE_TFTP_READ_FILE,
  268. MyBuffer,
  269. TRUE,
  270. &BufferSizeX,
  271. NULL,
  272. &MyServerIpAddress,
  273. Request->RemoteFileName,
  274. 0,
  275. FALSE );
  276. FlipToVirtual();
  277. if( Status != EFI_SUCCESS ) {
  278. if( BdDebuggerEnabled ) {
  279. DbgPrint( "TftpGet: GetFile failed! (%d)\n", Status );
  280. }
  281. return (NTSTATUS)Status;
  282. }
  283. Request->BytesTransferred = (ULONG)BufferSizeX;
  284. return (NTSTATUS)Status;
  285. } // TftpGet
  286. NTSTATUS
  287. TftpPut (
  288. IN OUT PCONNECTION Connection,
  289. IN PTFTP_REQUEST Request
  290. )
  291. {
  292. EFI_STATUS Status;
  293. EFI_IP_ADDRESS MyServerIpAddress;
  294. INTN Count = 0;
  295. PVOID MyBuffer = NULL;
  296. //
  297. // They sent us an IP address as a ULONG. We need to convert
  298. // that into an EFI_IP_ADDRESS.
  299. //
  300. for( Count = 0; Count < 4; Count++ ) {
  301. MyServerIpAddress.v4.Addr[Count] = PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr[Count];
  302. }
  303. //
  304. // Make sure we send EFI a physical address.
  305. //
  306. MyBuffer = (PVOID)((ULONGLONG)(Request->MemoryAddress) & ~KSEG0_BASE);
  307. FlipToPhysical();
  308. Status = PXEClient->Mtftp( PXEClient,
  309. EFI_PXE_BASE_CODE_TFTP_WRITE_FILE,
  310. MyBuffer,
  311. TRUE,
  312. (UINTN *)(&Request->MaximumLength),
  313. NULL,
  314. &MyServerIpAddress,
  315. Request->RemoteFileName,
  316. 0,
  317. FALSE );
  318. FlipToVirtual();
  319. if( Status != EFI_SUCCESS ) {
  320. if( BdDebuggerEnabled ) {
  321. DbgPrint( "TftpPut: WriteFile failed! (%d)\n", Status );
  322. }
  323. }
  324. return (NTSTATUS)Status;
  325. } // TftpPut
  326. #else // #ifdef EFI
  327. NTSTATUS
  328. TftpGet (
  329. IN OUT PCONNECTION Connection,
  330. IN PTFTP_REQUEST Request
  331. )
  332. {
  333. NTSTATUS status;
  334. PTFTP_PACKET packet;
  335. ULONG length;
  336. ULONG offset;
  337. PUCHAR packetData;
  338. ULONG lastProgressPercent = -1;
  339. ULONG currentProgressPercent;
  340. #if defined(REMOTE_BOOT_SECURITY)
  341. UCHAR Sign[NTLMSSP_MESSAGE_SIGNATURE_SIZE];
  342. SecBufferDesc SignMessage;
  343. SecBuffer SigBuffers[2];
  344. SECURITY_STATUS SecStatus;
  345. #endif // defined(REMOTE_BOOT_SECURITY)
  346. DPRINT( TRACE, ("TftpGet\n") );
  347. #if defined(REMOTE_BOOT)
  348. if (!NetworkBootRom) {
  349. // Booting from the hard disk cache because server is not available
  350. return STATUS_UNSUCCESSFUL;
  351. }
  352. #endif // defined(REMOTE_BOOT)
  353. offset = 0;
  354. if ( Request->ShowProgress ) {
  355. BlUpdateProgressBar(0);
  356. }
  357. do {
  358. status = ConnReceive( Connection, &packet );
  359. if ( !NT_SUCCESS(status) ) {
  360. break;
  361. }
  362. length = Connection->CurrentLength - 4;
  363. #if defined(REMOTE_BOOT_SECURITY)
  364. //
  365. // If we are doing a security transfer, then the first packet
  366. // has the sign in it, so put that in the Sign buffer first.
  367. //
  368. if (Request->SecurityHandle && (offset == 0)) {
  369. if (length < NTLMSSP_MESSAGE_SIGNATURE_SIZE) {
  370. status = STATUS_UNEXPECTED_NETWORK_ERROR;
  371. break;
  372. }
  373. memcpy(Sign, packet->Data, NTLMSSP_MESSAGE_SIGNATURE_SIZE);
  374. packetData = packet->Data + NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  375. length -= NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  376. } else
  377. #endif // defined(REMOTE_BOOT_SECURITY)
  378. {
  379. packetData = packet->Data;
  380. }
  381. if ( (offset + length) > Request->MaximumLength ) {
  382. length = Request->MaximumLength - offset;
  383. }
  384. RtlCopyMemory( Request->MemoryAddress + offset, packetData, length );
  385. offset += length;
  386. if ( Request->ShowProgress ) {
  387. currentProgressPercent = (ULONG)(((ULONGLONG)offset * 100) / Request->MaximumLength);
  388. if ( currentProgressPercent != lastProgressPercent ) {
  389. BlUpdateProgressBar( currentProgressPercent );
  390. }
  391. lastProgressPercent = currentProgressPercent;
  392. }
  393. //
  394. // End the loop when we get a packet smaller than the max size --
  395. // the extra check is to handle the first packet (length == offset)
  396. // since we get NTLMSSP_MESSAGE_SIGNATURE_SIZE bytes less.
  397. //
  398. } while ( (length == Connection->BlockSize)
  399. #if defined(REMOTE_BOOT_SECURITY)
  400. || ((length == offset) &&
  401. (length == (Connection->BlockSize - NTLMSSP_MESSAGE_SIGNATURE_SIZE)))
  402. #endif // defined(REMOTE_BOOT_SECURITY)
  403. );
  404. #if defined(REMOTE_BOOT_SECURITY)
  405. if (Request->SecurityHandle) {
  406. //
  407. // Unseal the message if it was encrypted.
  408. //
  409. SigBuffers[1].pvBuffer = Sign;
  410. SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  411. SigBuffers[1].BufferType = SECBUFFER_TOKEN;
  412. SigBuffers[0].pvBuffer = Request->MemoryAddress;
  413. SigBuffers[0].cbBuffer = offset;
  414. SigBuffers[0].BufferType = SECBUFFER_DATA;
  415. SignMessage.pBuffers = SigBuffers;
  416. SignMessage.cBuffers = 2;
  417. SignMessage.ulVersion = 0;
  418. ASSERT (TftpClientContextHandleValid);
  419. SecStatus = UnsealMessage(
  420. &TftpClientContextHandle,
  421. &SignMessage,
  422. 0,
  423. 0 );
  424. if ( SecStatus != SEC_E_OK ) {
  425. DPRINT( ERROR, ("TftpGet: UnsealMessage failed %x\n", SecStatus) );
  426. status = STATUS_UNEXPECTED_NETWORK_ERROR;
  427. }
  428. }
  429. #endif // defined(REMOTE_BOOT_SECURITY)
  430. Request->BytesTransferred = offset;
  431. return status;
  432. } // TftpGet
  433. NTSTATUS
  434. TftpPut (
  435. IN OUT PCONNECTION Connection,
  436. IN PTFTP_REQUEST Request
  437. )
  438. {
  439. NTSTATUS status;
  440. PTFTP_PACKET packet;
  441. ULONG length;
  442. ULONG offset;
  443. DPRINT( TRACE, ("TftpPut\n") );
  444. #if defined(REMOTE_BOOT)
  445. if (!NetworkBootRom) {
  446. // Booting from the hard disk cache because server is not available
  447. return STATUS_UNSUCCESSFUL;
  448. }
  449. #endif // defined(REMOTE_BOOT)
  450. offset = 0;
  451. do {
  452. packet = ConnPrepareSend( Connection );
  453. length = Connection->BlockSize;
  454. if ( (offset + length) > Request->MaximumLength ) {
  455. length = Request->MaximumLength - offset;
  456. }
  457. RtlCopyMemory( packet->Data, Request->MemoryAddress + offset, length );
  458. status = ConnSend( Connection, length );
  459. if ( !NT_SUCCESS(status) ) {
  460. break;
  461. }
  462. offset += length;
  463. } while ( length == Connection->BlockSize );
  464. Request->BytesTransferred = offset;
  465. if ( NT_SUCCESS(status) ) {
  466. status = ConnWaitForFinalAck( Connection );
  467. }
  468. return status;
  469. } // TftpPut
  470. #endif // #if defined(_IA64_)
  471. #if defined(REMOTE_BOOT_SECURITY)
  472. NTSTATUS
  473. UdpSendAndReceiveForTftp(
  474. IN PVOID SendBuffer,
  475. IN ULONG SendBufferLength,
  476. IN ULONG SendRemoteHost,
  477. IN USHORT SendRemotePort,
  478. IN ULONG SendRetryCount,
  479. IN PVOID ReceiveBuffer,
  480. IN ULONG ReceiveBufferLength,
  481. OUT PULONG ReceiveRemoteHost,
  482. OUT PUSHORT ReceiveRemotePort,
  483. IN ULONG ReceiveTimeout,
  484. IN USHORT ReceiveSequenceNumber
  485. )
  486. {
  487. ULONG i, j;
  488. ULONG length;
  489. //
  490. // Try sending the packet SendRetryCount times, until we receive
  491. // a response with the right sequence number, waiting ReceiveTimeout
  492. // each time.
  493. //
  494. for (i = 0; i < SendRetryCount; i++) {
  495. length = UdpSend(
  496. SendBuffer,
  497. SendBufferLength,
  498. SendRemoteHost,
  499. SendRemotePort);
  500. if ( length != SendBufferLength ) {
  501. DPRINT( ERROR, ("UdpSend only sent %d bytes, not %d\n", length, SendBufferLength) );
  502. return STATUS_UNEXPECTED_NETWORK_ERROR;
  503. }
  504. ReReceive:
  505. //
  506. // NULL out the first 12 bytes in case we get shorter data.
  507. //
  508. memset(ReceiveBuffer, 0x0, 12);
  509. length = UdpReceive(
  510. ReceiveBuffer,
  511. ReceiveBufferLength,
  512. ReceiveRemoteHost,
  513. ReceiveRemotePort,
  514. ReceiveTimeout);
  515. if ( length == 0 ) {
  516. DPRINT( ERROR, ("UdpReceive timed out sending %d, %d sends\n", SendBufferLength, i) );
  517. continue;
  518. }
  519. //
  520. // Make sure that it is a TFTP security packet.
  521. //
  522. if (((USHORT UNALIGNED *)ReceiveBuffer)[0] != SWAP_WORD(0x10)) {
  523. DPRINT( ERROR, ("UdpReceive not a TFTP packet\n") );
  524. continue;
  525. }
  526. //
  527. // Make sure that the sequence number is correct -- what we
  528. // expect, or 0xffff.
  529. //
  530. if ((((USHORT UNALIGNED *)ReceiveBuffer)[1] == SWAP_WORD(0xffff)) ||
  531. (((USHORT UNALIGNED *)ReceiveBuffer)[1] == SWAP_WORD(ReceiveSequenceNumber))) {
  532. return STATUS_SUCCESS;
  533. } else {
  534. DPRINT( ERROR, ("UdpReceive expected seq %d, got %d\n",
  535. ReceiveSequenceNumber, ((UCHAR *)ReceiveBuffer)[3]) );
  536. }
  537. DPRINT( ERROR, ("UdpReceive got wrong signature\n") );
  538. // CLEAN THIS UP -- but the idea is not to UdpSend again just
  539. // because we got a bad signature. Still need to respect the
  540. // original ReceiveTimeout however!
  541. goto ReReceive;
  542. }
  543. //
  544. // We timed out.
  545. //
  546. return STATUS_TIMEOUT;
  547. }
  548. NTSTATUS
  549. TftpLogin (
  550. IN PUCHAR Domain,
  551. IN PUCHAR Name,
  552. IN PUCHAR OwfPassword,
  553. IN ULONG ServerIpAddress,
  554. OUT PULONG LoginHandle
  555. )
  556. {
  557. NTSTATUS status;
  558. ARC_STATUS Status;
  559. SECURITY_STATUS SecStatus;
  560. NTSTATUS remoteStatus;
  561. SecBufferDesc NegotiateDesc;
  562. SecBuffer NegotiateBuffer;
  563. SecBufferDesc ChallengeDesc;
  564. SecBuffer ChallengeBuffer;
  565. SecBufferDesc AuthenticateDesc;
  566. SecBuffer AuthenticateBuffer;
  567. ULONG ContextAttributes;
  568. SEC_WINNT_AUTH_IDENTITY AuthIdentity;
  569. TimeStamp Lifetime;
  570. ULONG RemoteHost;
  571. USHORT RemotePort;
  572. ULONG LoginHeaderLength;
  573. USHORT LocalPort;
  574. PUCHAR OptionLoc;
  575. ULONG MaxToken;
  576. PSecPkgInfo PackageInfo;
  577. #if defined(REMOTE_BOOT)
  578. if (!NetworkBootRom) {
  579. // Booting from the hard disk cache because server is not available
  580. return STATUS_UNSUCCESSFUL;
  581. }
  582. #endif // defined(REMOTE_BOOT)
  583. //
  584. // Get ourselves a UDP port.
  585. //
  586. LocalPort = UdpAssignUnicastPort();
  587. //
  588. // Delete both contexts if needed.
  589. //
  590. if (TftpClientContextHandleValid) {
  591. SecStatus = DeleteSecurityContext( &TftpClientContextHandle );
  592. TftpClientContextHandleValid = FALSE;
  593. }
  594. if (CredentialHandleValid) {
  595. SecStatus = FreeCredentialsHandle( &CredentialHandle );
  596. CredentialHandleValid = FALSE;
  597. }
  598. //
  599. // Get info about the security packages.
  600. //
  601. SecStatus = QuerySecurityPackageInfoA( NTLMSP_NAME_A, &PackageInfo );
  602. if ( SecStatus != SEC_E_OK ) {
  603. DPRINT( ERROR, ("QuerySecurityPackageInfo failed %d", SecStatus) );
  604. return (RtlMapSecurityErrorToNtStatus(SecStatus));
  605. }
  606. MaxToken = PackageInfo->cbMaxToken;
  607. FreeContextBuffer(PackageInfo);
  608. //
  609. // Acquire a credential handle for the client side
  610. //
  611. RtlZeroMemory( &AuthIdentity, sizeof(AuthIdentity) );
  612. AuthIdentity.Domain = Domain;
  613. AuthIdentity.User = Name;
  614. AuthIdentity.Password = OwfPassword;
  615. SecStatus = AcquireCredentialsHandleA(
  616. NULL, // New principal
  617. NTLMSP_NAME_A, // Package Name
  618. SECPKG_CRED_OUTBOUND | SECPKG_CRED_OWF_PASSWORD,
  619. NULL,
  620. &AuthIdentity,
  621. NULL,
  622. NULL,
  623. &CredentialHandle,
  624. &Lifetime );
  625. if ( SecStatus != SEC_E_OK ) {
  626. DPRINT( ERROR, ("AcquireCredentialsHandle failed: %s ", SecStatus) );
  627. return (RtlMapSecurityErrorToNtStatus(SecStatus));
  628. }
  629. CredentialHandleValid = TRUE;
  630. //
  631. // Get the NegotiateMessage (ClientSide)
  632. //
  633. ((USHORT UNALIGNED *)OutgoingMessage)[0] = SWAP_WORD(0x10); // TFTP packet type 16
  634. memcpy(OutgoingMessage+2, "login", 6); // copy the final \0 also
  635. strcpy(OutgoingMessage+8, NTLMSP_NAME_A);
  636. NegotiateDesc.ulVersion = 0;
  637. NegotiateDesc.cBuffers = 1;
  638. NegotiateDesc.pBuffers = &NegotiateBuffer;
  639. NegotiateBuffer.cbBuffer = MaxToken;
  640. NegotiateBuffer.BufferType = SECBUFFER_TOKEN;
  641. // allow 8 for the type and "login", then NTLMSP_NAME_A + 1 for the \0,
  642. // plus four bytes for the length.
  643. LoginHeaderLength = 8 + strlen(NTLMSP_NAME_A) + 1;
  644. NegotiateBuffer.pvBuffer = OutgoingMessage + LoginHeaderLength + 4;
  645. SecStatus = InitializeSecurityContextA(
  646. &CredentialHandle,
  647. NULL, // No Client context yet
  648. NULL,
  649. ISC_REQ_SEQUENCE_DETECT,
  650. 0, // Reserved 1
  651. SECURITY_NATIVE_DREP,
  652. NULL, // No initial input token
  653. 0, // Reserved 2
  654. &TftpClientContextHandle,
  655. &NegotiateDesc,
  656. &ContextAttributes,
  657. &Lifetime );
  658. if ( (SecStatus != SEC_E_OK) && (SecStatus != SEC_I_CONTINUE_NEEDED) ) {
  659. DPRINT( ERROR, ("InitializeSecurityContext (negotiate): %d", SecStatus) );
  660. return (RtlMapSecurityErrorToNtStatus(SecStatus));
  661. }
  662. TftpClientContextHandleValid = TRUE;
  663. //
  664. // Send the negotiate buffer to the server and wait for a response.
  665. //
  666. *((ULONG UNALIGNED *)(OutgoingMessage + LoginHeaderLength)) =
  667. SWAP_DWORD(NegotiateBuffer.cbBuffer);
  668. Status = UdpSendAndReceiveForTftp(
  669. OutgoingMessage,
  670. NegotiateBuffer.cbBuffer + LoginHeaderLength + 4,
  671. ServerIpAddress,
  672. TFTP_PORT,
  673. 10, // retry count
  674. IncomingMessage,
  675. MaxToken + 8,
  676. &RemoteHost,
  677. &RemotePort,
  678. 3, // receive timeout
  679. 0); // sequence number);
  680. if ( !NT_SUCCESS(Status) ) {
  681. DPRINT( ERROR, ("UdpSendAndReceiveForTftp status is %x\n", Status) );
  682. return Status;
  683. }
  684. //
  685. // Get the AuthenticateMessage (ClientSide)
  686. //
  687. AuthenticateDesc.ulVersion = 0;
  688. AuthenticateDesc.cBuffers = 1;
  689. AuthenticateDesc.pBuffers = &AuthenticateBuffer;
  690. AuthenticateBuffer.cbBuffer = MaxToken;
  691. AuthenticateBuffer.BufferType = SECBUFFER_TOKEN;
  692. AuthenticateBuffer.pvBuffer = OutgoingMessage + 8;
  693. ChallengeDesc.ulVersion = 0;
  694. ChallengeDesc.cBuffers = 1;
  695. ChallengeDesc.pBuffers = &ChallengeBuffer;
  696. ChallengeBuffer.cbBuffer = SWAP_DWORD(((ULONG UNALIGNED *)IncomingMessage)[1]);
  697. ChallengeBuffer.BufferType = SECBUFFER_TOKEN | SECBUFFER_READONLY;
  698. ChallengeBuffer.pvBuffer = IncomingMessage + 8;
  699. SecStatus = InitializeSecurityContextA(
  700. NULL,
  701. &TftpClientContextHandle,
  702. NULL,
  703. 0,
  704. 0, // Reserved 1
  705. SECURITY_NATIVE_DREP,
  706. &ChallengeDesc,
  707. 0, // Reserved 2
  708. &TftpClientContextHandle,
  709. &AuthenticateDesc,
  710. &ContextAttributes,
  711. &Lifetime );
  712. if ( (SecStatus != SEC_E_OK) ) {
  713. DPRINT( ERROR, ("InitializeSecurityContext (Authenticate): %d\n", SecStatus) );
  714. return (RtlMapSecurityErrorToNtStatus(SecStatus));
  715. }
  716. //
  717. // Send the authenticate buffer to the server and wait for the response.
  718. //
  719. ((USHORT UNALIGNED *)OutgoingMessage)[0] = SWAP_WORD(0x10); // TFTP packet type 16
  720. ((USHORT UNALIGNED *)OutgoingMessage)[1] = SWAP_WORD(0x00); // sequence number 0
  721. ((ULONG UNALIGNED *)OutgoingMessage)[1] = SWAP_DWORD(AuthenticateBuffer.cbBuffer);
  722. Status = UdpSendAndReceiveForTftp(
  723. OutgoingMessage,
  724. AuthenticateBuffer.cbBuffer + 8,
  725. ServerIpAddress,
  726. RemotePort, // send it to whatever port he sent from
  727. 10, // retry count
  728. IncomingMessage,
  729. MaxToken + 8,
  730. &RemoteHost,
  731. &RemotePort,
  732. 5, // receive timeout
  733. 1); // sequence number (but we really expect 0xffff)
  734. if ( !NT_SUCCESS(Status) ) {
  735. DPRINT( ERROR, ("UdpSendAndReceiveForTftp status is %x\n", Status) );
  736. return Status;
  737. }
  738. if (((USHORT UNALIGNED *)IncomingMessage)[1] == SWAP_WORD(0xffff)) {
  739. //
  740. // Send a response to the server, but don't bother trying to
  741. // resend it, since if he doesn't see it he eventually
  742. // times out.
  743. //
  744. ((USHORT UNALIGNED *)OutgoingMessage)[0] = SWAP_WORD(0x10); // TFTP packet type 16
  745. ((USHORT UNALIGNED *)OutgoingMessage)[1] = SWAP_WORD(0xffff); // sequence number 0
  746. UdpSend(
  747. OutgoingMessage,
  748. 4,
  749. ServerIpAddress,
  750. RemotePort);
  751. //
  752. // Parse the result to see if we succeeded.
  753. //
  754. OptionLoc = IncomingMessage + 4;
  755. if (memcmp(OptionLoc, "status", 6) != 0) {
  756. DPRINT( ERROR, ("Login response has no status!!\n") );
  757. status = STATUS_UNEXPECTED_NETWORK_ERROR;
  758. }
  759. OptionLoc += strlen("status") + 1;
  760. remoteStatus = ConnSafeAtol(OptionLoc, OptionLoc+20); // end doesn't matter because it is NULL-terminated
  761. if (remoteStatus == STATUS_SUCCESS) {
  762. OptionLoc += strlen(OptionLoc) + 1;
  763. if (memcmp(OptionLoc, "handle", 6) != 0) {
  764. DPRINT( ERROR, ("Login success response has no handle!!\n") );
  765. status = STATUS_UNEXPECTED_NETWORK_ERROR;
  766. } else {
  767. OptionLoc += strlen("handle") + 1;
  768. *LoginHandle = ConnSafeAtol(OptionLoc, OptionLoc+20); // end doesn't matter because it is NULL-terminated
  769. DPRINT( ERROR, ("TftpLogin SUCCESS, remoteHandle %d\n", *LoginHandle) );
  770. status = STATUS_SUCCESS;
  771. }
  772. } else {
  773. DPRINT( ERROR, ("Login reported failure %x\n", remoteStatus) );
  774. status = remoteStatus;
  775. }
  776. } else {
  777. DPRINT( ERROR, ("Got strange response to negotiate!!\n") );
  778. status = STATUS_UNEXPECTED_NETWORK_ERROR;
  779. }
  780. return status;
  781. } // TftpLogin
  782. NTSTATUS
  783. TftpLogoff (
  784. IN ULONG ServerIpAddress,
  785. IN ULONG LoginHandle
  786. )
  787. {
  788. SECURITY_STATUS SecStatus;
  789. NTSTATUS status;
  790. ULONG Status;
  791. ULONG stringSize;
  792. PUCHAR options;
  793. ULONG length;
  794. ULONG RemoteHost;
  795. USHORT RemotePort;
  796. #if defined(REMOTE_BOOT)
  797. if (!NetworkBootRom) {
  798. // Booting from the hard disk cache because server is not available
  799. return STATUS_UNSUCCESSFUL;
  800. }
  801. #endif // defined(REMOTE_BOOT)
  802. //
  803. // Delete both contexts if needed.
  804. //
  805. if (TftpClientContextHandleValid) {
  806. SecStatus = DeleteSecurityContext( &TftpClientContextHandle );
  807. TftpClientContextHandleValid = FALSE;
  808. }
  809. if (CredentialHandleValid) {
  810. SecStatus = FreeCredentialsHandle( &CredentialHandle );
  811. CredentialHandleValid = FALSE;
  812. }
  813. //
  814. // Send the logoff message to the server.
  815. //
  816. ((USHORT UNALIGNED *)OutgoingMessage)[0] = SWAP_WORD(0x10); // TFTP packet type 16
  817. memcpy(OutgoingMessage+2, "logoff", 7); // copy the final \0 also
  818. strcpy(OutgoingMessage+9, NTLMSP_NAME_A);
  819. // allow 9 for the type and "logoff", then NTLMSP_NAME_A + 1 for the \0.
  820. length= 9 + strlen(NTLMSP_NAME_A) + 1;
  821. options = OutgoingMessage + length;
  822. strcpy( options, "security" );
  823. length += sizeof("security");
  824. options += sizeof("security");
  825. stringSize = ConnItoa( LoginHandle, options );
  826. length += stringSize;
  827. options += stringSize;
  828. Status = UdpSendAndReceiveForTftp(
  829. OutgoingMessage,
  830. length,
  831. ServerIpAddress,
  832. TFTP_PORT,
  833. 3, // retry count
  834. IncomingMessage,
  835. 512, // size - we don't expect a big response
  836. &RemoteHost,
  837. &RemotePort,
  838. 2, // receive timeout
  839. 0); // sequence number (but we really expect 0xffff)
  840. if ( !NT_SUCCESS(Status) ) {
  841. DPRINT( ERROR, ("UdpSendAndReceiveForTftp status is %d\n", Status) );
  842. return STATUS_UNEXPECTED_NETWORK_ERROR;
  843. }
  844. if (((USHORT UNALIGNED *)IncomingMessage)[1] == SWAP_WORD(0xffff)) {
  845. //
  846. // Send a response to the server, but don't bother trying to
  847. // resend it, since if he doesn't see it he eventually
  848. // times out.
  849. //
  850. ((USHORT UNALIGNED *)OutgoingMessage)[0] = SWAP_WORD(0x10); // TFTP packet type 16
  851. ((USHORT UNALIGNED *)OutgoingMessage)[1] = SWAP_WORD(0xffff); // sequence number 0
  852. UdpSend(
  853. OutgoingMessage,
  854. 4,
  855. ServerIpAddress,
  856. RemotePort);
  857. //
  858. // The status code follows the 0xffff, but for the moment we
  859. // don't care.
  860. //
  861. DPRINT( ERROR, ("TftpLogoff SUCCESS, remoteHandle %d\n", LoginHandle) );
  862. status = STATUS_SUCCESS;
  863. } else {
  864. DPRINT( ERROR, ("Got strange response to logoff!!\n") );
  865. status = STATUS_UNEXPECTED_NETWORK_ERROR;
  866. }
  867. return status;
  868. } // TftpLogoff
  869. NTSTATUS
  870. TftpSignString (
  871. IN PUCHAR String,
  872. OUT PUCHAR * Sign,
  873. OUT ULONG * SignLength
  874. )
  875. {
  876. SECURITY_STATUS SecStatus;
  877. SecBufferDesc SignMessage;
  878. SecBuffer SigBuffers[2];
  879. static UCHAR StaticSign[NTLMSSP_MESSAGE_SIGNATURE_SIZE];
  880. //
  881. // Sign the name and send that, to make sure it is not changed.
  882. //
  883. SigBuffers[1].pvBuffer = StaticSign;
  884. SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  885. SigBuffers[1].BufferType = SECBUFFER_TOKEN;
  886. SigBuffers[0].pvBuffer = String;
  887. SigBuffers[0].cbBuffer = strlen(String);
  888. SigBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  889. SignMessage.pBuffers = SigBuffers;
  890. SignMessage.cBuffers = 2;
  891. SignMessage.ulVersion = 0;
  892. ASSERT (TftpClientContextHandleValid);
  893. SecStatus = MakeSignature(
  894. &TftpClientContextHandle,
  895. 0,
  896. &SignMessage,
  897. 0 );
  898. if ( SecStatus != SEC_E_OK ) {
  899. DPRINT( ERROR, ("TftpSignString: MakeSignature: %lx\n", SecStatus) );
  900. return STATUS_UNEXPECTED_NETWORK_ERROR;
  901. }
  902. *Sign = StaticSign;
  903. *SignLength = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  904. return STATUS_SUCCESS;
  905. }
  906. #endif // defined(REMOTE_BOOT_SECURITY)