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.

4815 lines
153 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation
  3. Module Name:
  4. osc.c
  5. Abstract:
  6. This module contains the code to process OS Chooser message
  7. for the BINL server.
  8. Author:
  9. Adam Barr (adamba) 9-Jul-1997
  10. Geoff Pease (gpease) 10-Nov-1997
  11. Environment:
  12. User Mode - Win32
  13. Revision History:
  14. --*/
  15. #include "binl.h"
  16. #pragma hdrstop
  17. #include <dns.h>
  18. #include <aclapi.h>
  19. #ifdef TEST_FAILURE
  20. BOOL FailFirstChallenge = TRUE;
  21. BOOL FailFirstResult = TRUE;
  22. BOOL FailFirstResponse = TRUE;
  23. BOOL FailFirstFragment = TRUE;
  24. #endif
  25. //
  26. // Flag indicating whether OscInitialize has been called.
  27. //
  28. BOOLEAN OscInitialized = FALSE;
  29. //
  30. // The list of clients.
  31. //
  32. LIST_ENTRY ClientsQueue;
  33. //
  34. // This guards access to ClientsQueue.
  35. //
  36. CRITICAL_SECTION ClientsCriticalSection;
  37. //
  38. // This is a temporary hack to serialize all calls to the
  39. // NetUserSetInfo/NetUserModalsGet pair. See discussion in
  40. // bug 319962.
  41. //
  42. CRITICAL_SECTION HackWorkaroundCriticalSection;
  43. //
  44. // CurrentClientCount-er access guard
  45. //
  46. CRITICAL_SECTION g_CurrentClientCountCritSect;
  47. //
  48. // Guards creation of the \remoteinstall\tmp directory.
  49. //
  50. CRITICAL_SECTION g_TmpDirectoryCriticalSection;
  51. //
  52. // Credential handle from SSPI
  53. //
  54. CredHandle CredentialHandle;
  55. //
  56. // Info on the NTLMSSP security package.
  57. //
  58. PSecPkgInfo PackageInfo = NULL;
  59. #if DBG
  60. CHAR OscWatchVariable[32] = "";
  61. #endif
  62. DWORD
  63. OscCheckTmpDirectory(
  64. VOID
  65. )
  66. /*++
  67. Routine Description:
  68. This function verifies that the \remoteinstall\tmp directory
  69. is there, if not it creates it.
  70. Arguments:
  71. None.
  72. Return Value:
  73. Windows Error.
  74. --*/
  75. {
  76. DWORD Error = ERROR_SUCCESS;
  77. WCHAR TmpPath[ MAX_PATH ];
  78. DWORD FileAttributes;
  79. BOOL InCriticalSection = FALSE;
  80. PSID pEveryoneSID = NULL;
  81. PACL pACL = NULL;
  82. PSECURITY_DESCRIPTOR pSD = NULL;
  83. BOOL b;
  84. if ( _snwprintf( TmpPath,
  85. sizeof(TmpPath) / sizeof(TmpPath[0]),
  86. L"%ws\\%ws",
  87. IntelliMirrorPathW,
  88. TEMP_DIRECTORY
  89. ) == -1 ) {
  90. Error = ERROR_BAD_PATHNAME;
  91. goto Cleanup;
  92. }
  93. FileAttributes = GetFileAttributes(TmpPath);
  94. if (FileAttributes == 0xFFFFFFFF) {
  95. EXPLICIT_ACCESS ea;
  96. SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
  97. SECURITY_ATTRIBUTES sa;
  98. //
  99. // Get the critical section if we are going to try to create it.
  100. //
  101. InCriticalSection = TRUE;
  102. EnterCriticalSection(&g_TmpDirectoryCriticalSection);
  103. //
  104. // Make sure it still needs to be created.
  105. //
  106. FileAttributes = GetFileAttributes(TmpPath);
  107. if (FileAttributes == 0xFFFFFFFF) {
  108. // Create a well-known SID for the Everyone group.
  109. if(! AllocateAndInitializeSid( &SIDAuthWorld, 1,
  110. SECURITY_WORLD_RID,
  111. 0, 0, 0, 0, 0, 0, 0,
  112. &pEveryoneSID) ) {
  113. Error = GetLastError();
  114. BinlPrintDbg(( DEBUG_INIT, "AllocateAndInitializeSid failed: %lx\n", Error ));
  115. goto Cleanup;
  116. }
  117. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  118. // The ACE will allow Everyone all access to the directory.
  119. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
  120. ea.grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
  121. ea.grfAccessMode = SET_ACCESS;
  122. ea.grfInheritance= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
  123. ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  124. ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  125. ea.Trustee.ptstrName = (LPTSTR) pEveryoneSID;
  126. // Create a new ACL that contains the new ACE.
  127. Error = SetEntriesInAcl(1, &ea, NULL, &pACL);
  128. if (Error != ERROR_SUCCESS) {
  129. BinlPrintDbg(( DEBUG_INIT, "SetEntriesInAcl failed lx\n", Error ));
  130. goto Cleanup;
  131. }
  132. // Initialize a security descriptor.
  133. pSD = (PSECURITY_DESCRIPTOR) BinlAllocateMemory(SECURITY_DESCRIPTOR_MIN_LENGTH);
  134. if (pSD == NULL) {
  135. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  136. BinlPrintDbg(( DEBUG_INIT, "Allocate SECURITY_DESCRIPTOR failed\n"));
  137. goto Cleanup;
  138. }
  139. if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
  140. Error = GetLastError();
  141. BinlPrintDbg(( DEBUG_INIT, "InitializeSecurityDescriptor failed: %lx\n", Error ));
  142. goto Cleanup;
  143. }
  144. // Add the ACL to the security descriptor.
  145. if (!SetSecurityDescriptorDacl(pSD,
  146. TRUE, // fDaclPresent flag
  147. pACL,
  148. FALSE)) // not a default DACL
  149. {
  150. Error = GetLastError();
  151. BinlPrintDbg(( DEBUG_INIT, "SetSecurityDescriptorDacl failed: %lx\n", Error ));
  152. goto Cleanup;
  153. }
  154. // Initialize a security attributes structure.
  155. sa.nLength = sizeof (SECURITY_ATTRIBUTES);
  156. sa.lpSecurityDescriptor = pSD;
  157. sa.bInheritHandle = FALSE;
  158. b = CreateDirectory(TmpPath, &sa);
  159. if (!b) {
  160. Error = GetLastError();
  161. BinlPrintDbg(( DEBUG_INIT, "CreateDirectory failed: %lx\n", Error ));
  162. goto Cleanup;
  163. }
  164. }
  165. } else if ((FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  166. Error = ERROR_FILE_EXISTS;
  167. goto Cleanup;
  168. }
  169. Cleanup:
  170. if (InCriticalSection) {
  171. LeaveCriticalSection(&g_TmpDirectoryCriticalSection);
  172. }
  173. if (pEveryoneSID) {
  174. FreeSid(pEveryoneSID);
  175. }
  176. if (pACL) {
  177. BinlFreeMemory(pACL);
  178. }
  179. if (pSD) {
  180. BinlFreeMemory(pSD);
  181. }
  182. return Error;
  183. }
  184. DWORD
  185. OscInitialize(
  186. VOID
  187. )
  188. /*++
  189. Routine Description:
  190. This function initializes the OSChooser server.
  191. Arguments:
  192. None.
  193. Return Value:
  194. Windows Error.
  195. --*/
  196. {
  197. DWORD Error = ERROR_SUCCESS;
  198. SECURITY_STATUS SecStatus;
  199. ULONG PackageCount;
  200. TimeStamp Lifetime;
  201. LPSHARE_INFO_2 psi;
  202. NET_API_STATUS netStatus;
  203. TraceFunc("OscInitialize( )\n");
  204. if ( !OscInitialized ) {
  205. InitializeListHead(&ClientsQueue);
  206. InitializeCriticalSection(&ClientsCriticalSection);
  207. InitializeCriticalSection(&HackWorkaroundCriticalSection);
  208. InitializeCriticalSection(&g_CurrentClientCountCritSect);
  209. InitializeCriticalSection(&g_TmpDirectoryCriticalSection);
  210. CredentialHandle.dwLower = 0;
  211. CredentialHandle.dwUpper = 0;
  212. OscInitialized = TRUE;
  213. }
  214. //
  215. // Retrieve the path to the remote install directory
  216. //
  217. netStatus = NetShareGetInfo(NULL, L"REMINST", 2, (LPBYTE *)&psi);
  218. if ( netStatus == ERROR_SUCCESS )
  219. {
  220. wcscpy( IntelliMirrorPathW, psi->shi2_path );
  221. NetApiBufferFree(psi);
  222. }
  223. else
  224. {
  225. BinlPrintDbg(( DEBUG_MISC, "NetShareGetInfo( ) returned 0x%08x\n", netStatus));
  226. BinlServerEventLog(
  227. EVENT_SERVER_OSC_NO_DEFAULT_SHARE_FOUND,
  228. EVENTLOG_ERROR_TYPE,
  229. netStatus );
  230. Error = ERROR_BINL_SHARE_NOT_FOUND;
  231. goto Cleanup;
  232. }
  233. //
  234. // Translate this to ANSI once, use many...
  235. //
  236. wcstombs( IntelliMirrorPathA, IntelliMirrorPathW, wcslen(IntelliMirrorPathW) +1 );
  237. //
  238. // Make sure there is a tmp directory below it.
  239. //
  240. Error = OscCheckTmpDirectory();
  241. if (Error != ERROR_SUCCESS) {
  242. BinlPrintDbg(( DEBUG_INIT, "OscCheckTempDirectory failed lx\n", Error ));
  243. goto Cleanup;
  244. }
  245. //
  246. // Get info about the security packages.
  247. //
  248. SecStatus = EnumerateSecurityPackages( &PackageCount, &PackageInfo );
  249. if ( SecStatus != STATUS_SUCCESS ) {
  250. BinlPrintDbg(( DEBUG_INIT, "EnumerateSecurityPackages failed: %lx\n", SecStatus ));
  251. Error = ERROR_NO_SUCH_PACKAGE;
  252. goto Cleanup;
  253. }
  254. //
  255. // Get info about the security packages.
  256. //
  257. SecStatus = QuerySecurityPackageInfo( NTLMSP_NAME, &PackageInfo );
  258. if ( SecStatus != STATUS_SUCCESS ) {
  259. BinlPrintDbg(( DEBUG_INIT, "QuerySecurityPackageInfo failed: %lx\n", SecStatus ));
  260. Error = ERROR_NO_SUCH_PACKAGE;
  261. goto Cleanup;
  262. }
  263. //
  264. // Acquire a credential handle for the server side
  265. //
  266. SecStatus = AcquireCredentialsHandle(
  267. NULL, // New principal
  268. NTLMSP_NAME, // Package Name
  269. SECPKG_CRED_INBOUND,
  270. NULL,
  271. NULL,
  272. NULL,
  273. NULL,
  274. &CredentialHandle,
  275. &Lifetime );
  276. if ( SecStatus != STATUS_SUCCESS ) {
  277. BinlPrintDbg(( DEBUG_INIT, "AcquireCredentialsHandle failed: %lx\n", SecStatus ));
  278. Error = SecStatus;
  279. }
  280. Cleanup:
  281. return Error;
  282. }
  283. VOID
  284. OscUninitialize(
  285. VOID
  286. )
  287. /*++
  288. Routine Description:
  289. This function uninitializes the OSChooser server.
  290. Arguments:
  291. None.
  292. Return Value:
  293. None.
  294. --*/
  295. {
  296. SECURITY_STATUS SecStatus;
  297. TraceFunc("OscUninitialize( )\n");
  298. if ( OscInitialized ) {
  299. OscFreeClients();
  300. DeleteCriticalSection(&ClientsCriticalSection);
  301. DeleteCriticalSection(&HackWorkaroundCriticalSection);
  302. DeleteCriticalSection(&g_CurrentClientCountCritSect);
  303. DeleteCriticalSection(&g_TmpDirectoryCriticalSection);
  304. SecStatus = FreeCredentialsHandle( &CredentialHandle );
  305. if ( SecStatus != STATUS_SUCCESS ) {
  306. BinlPrintDbg(( DEBUG_OSC_ERROR, "FreeCredentialsHandle failed: %lx\n", SecStatus ));
  307. }
  308. if ( BinlOscClientDSHandle != NULL ) {
  309. DsUnBind( &BinlOscClientDSHandle );
  310. BinlOscClientDSHandle = NULL;
  311. }
  312. OscInitialized = FALSE;
  313. }
  314. }
  315. DWORD
  316. OscProcessMessage(
  317. LPBINL_REQUEST_CONTEXT RequestContext
  318. )
  319. /*++
  320. Routine Description:
  321. This function dispatches the processing of a received OS chooser message.
  322. The handler functions will send response messages if necessary.
  323. Arguments:
  324. RequestContext - A pointer to the BinlRequestContext block for
  325. this request.
  326. Return Value:
  327. Windows Error.
  328. --*/
  329. {
  330. SIGNED_PACKET UNALIGNED * loginMessage = (SIGNED_PACKET UNALIGNED *)RequestContext->ReceiveBuffer;
  331. DWORD Error;
  332. PCLIENT_STATE clientState = NULL;
  333. ULONG RemoteIp;
  334. BOOL FreeClientState;
  335. BOOL IsLogoffMessage;
  336. BOOL IsNetcardRequestMessage;
  337. BOOL IsHalRequestMessage;
  338. BOOL IsNegotiateMessage;
  339. BOOL IsAuthenicateMessage;
  340. TraceFunc("OscProcessMessage( )\n");
  341. BinlPrintDbg(( DEBUG_OSC, "Received message, length %d, data %.3s\n",
  342. RequestContext->ReceiveMessageSize,
  343. ((PUCHAR)loginMessage)+1));
  344. //
  345. // Extract the IP address of the client.
  346. //
  347. RemoteIp = ((struct sockaddr_in *)&RequestContext->SourceName)->sin_addr.s_addr;
  348. //
  349. // IsLogoffMessage will be TRUE if the signature is equal to LogoffSignature.
  350. //
  351. IsLogoffMessage = (BOOL)(memcmp(loginMessage->Signature, LogoffSignature, 4) == 0);
  352. //
  353. // IsNetcardRequestMessage will be TRUE if the signature is equal to NetcardRequestSignature.
  354. //
  355. IsNetcardRequestMessage = (BOOL)(memcmp(loginMessage->Signature, NetcardRequestSignature, 4) == 0);
  356. //
  357. // IsHalRequestMessage will be TRUE if the signature is equal to HalRequestSignature.
  358. //
  359. IsHalRequestMessage = (BOOL)(memcmp(loginMessage->Signature, HalRequestSignature, 4) == 0);
  360. //
  361. // IsNegotiateMessage will be TRUE if the signature is equal to a NegotiateSignature.
  362. //
  363. IsNegotiateMessage = (BOOL)(memcmp(loginMessage->Signature, NegotiateSignature, 4) == 0);
  364. //
  365. // IsAuthenicateMessage will be TRUE if the signature is equal to an AuthenticateSignature
  366. // or AuthenticateFlippedSignature.
  367. //
  368. IsAuthenicateMessage = (BOOL)((memcmp(loginMessage->Signature, AuthenticateSignature, 4) == 0) ||
  369. (memcmp(loginMessage->Signature, AuthenticateFlippedSignature, 4) == 0));
  370. //
  371. // All messages except netcard queries need to use a CLIENT_STATE.
  372. //
  373. if (!IsNetcardRequestMessage)
  374. {
  375. //
  376. // If IsLogoffMessage is FALSE, this finds an old CLIENT_STATE or creates
  377. // a new one. If IsLogoffMessage is TRUE, this removes CLIENT_STATE from
  378. // the database if it finds it.
  379. // In both cases, if successful, it adds one to the PositiveRefCount.
  380. //
  381. Error = OscFindClient(RemoteIp, IsLogoffMessage, &clientState);
  382. if (Error == ERROR_NOT_ENOUGH_SERVER_MEMORY)
  383. {
  384. CLIENT_STATE TempClientState;
  385. SIGNED_PACKET TempLoginPacket;
  386. BinlPrint(( DEBUG_OSC_ERROR, "Could not get client state for %s\n", inet_ntoa(*(struct in_addr *)&RemoteIp) ));
  387. //
  388. // Send a NAK back to the client. We use a local CLIENT_STATE
  389. // since this did not allocate one.
  390. //
  391. TempClientState.LastResponse = (PUCHAR)&TempLoginPacket;
  392. TempClientState.LastResponseLength = SIGNED_PACKET_DATA_OFFSET;
  393. memcpy(TempLoginPacket.Signature, NegativeAckSignature, 4);
  394. TempLoginPacket.Length = 0;
  395. Error = SendUdpMessage(RequestContext, &TempClientState, FALSE, FALSE);
  396. if (Error != ERROR_SUCCESS)
  397. {
  398. BinlPrint(( DEBUG_OSC_ERROR, "Could not send NAK message %d\n", Error));
  399. }
  400. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  401. }
  402. else if (Error == ERROR_BUSY) {
  403. //
  404. // If it is likely that another thread is processing a request
  405. // for this client, then just exit quietly.
  406. //
  407. BinlPrintDbg((DEBUG_OSC, "clientState = 0x%08x busy, exiting\n", clientState ));
  408. return ERROR_SUCCESS;
  409. } if ( clientState == NULL ) {
  410. BinlPrintDbg((DEBUG_OSC, "clientState not found, exiting\n" ));
  411. return ERROR_SUCCESS;
  412. }
  413. EnterCriticalSection(&clientState->CriticalSection);
  414. clientState->CriticalSectionHeld = TRUE;
  415. BinlPrintDbg((DEBUG_OSC, "Entering CS for clientState = 0x%08x\n", clientState ));
  416. }
  417. if (IsNegotiateMessage)
  418. {
  419. //
  420. // This is an initial negotiate request.
  421. //
  422. Error = OscProcessNegotiate( RequestContext, clientState );
  423. }
  424. else if (IsAuthenicateMessage)
  425. {
  426. //
  427. // This has the authenticate message.
  428. //
  429. Error = OscProcessAuthenticate( RequestContext, clientState );
  430. }
  431. else if (memcmp(loginMessage->Signature, RequestUnsignedSignature, 4) == 0)
  432. {
  433. //
  434. // This is an unsigned request.
  435. //
  436. // Format is:
  437. //
  438. // "RQU"
  439. // length (not including "RQU" and this)
  440. // sequence number
  441. // fragment count/total
  442. // sign length
  443. // sign
  444. // data
  445. //
  446. Error = OscProcessRequestUnsigned( RequestContext, clientState );
  447. }
  448. else if (memcmp(loginMessage->Signature, RequestSignedSignature, 4) == 0)
  449. {
  450. //
  451. // This is a signed request.
  452. //
  453. // Format is:
  454. //
  455. // "REQ"
  456. // length (not including "REQ" and this)
  457. // sequence number
  458. // fragment count/total
  459. // sign length
  460. // sign
  461. // data
  462. //
  463. Error = OscProcessRequestSigned( RequestContext, clientState );
  464. }
  465. else if (memcmp(loginMessage->Signature, SetupRequestSignature, 4) == 0)
  466. {
  467. //
  468. // This is a request by a textmode setup.
  469. //
  470. // Format is defined in SPUDP_PACKET in oskpkt.h
  471. //
  472. Error = OscProcessSetupRequest( RequestContext, clientState );
  473. }
  474. else if (IsLogoffMessage)
  475. {
  476. //
  477. // This is a logoff request. clientState has
  478. // already been removed from the database.
  479. //
  480. Error = OscProcessLogoff( RequestContext, clientState );
  481. }
  482. else if (IsNetcardRequestMessage)
  483. {
  484. //
  485. // This is a netcard request, which needs no client state.
  486. //
  487. Error = OscProcessNetcardRequest( RequestContext );
  488. }
  489. else if (IsHalRequestMessage)
  490. {
  491. //
  492. // This is a hal request
  493. //
  494. Error = OscProcessHalRequest( RequestContext, clientState );
  495. }
  496. else
  497. {
  498. BinlPrintDbg(( DEBUG_OSC_ERROR, "Received unknown message!\n" ));
  499. Error = ERROR_INVALID_FUNCTION;
  500. }
  501. if ( clientState ) {
  502. clientState->LastUpdate = GetTickCount();
  503. if (!IsNetcardRequestMessage) {
  504. //
  505. // We processed a packet, so if we get a first request for this
  506. // client state (meaning the client has rebooted), we need to
  507. // reinitialize it.
  508. //
  509. clientState->InitializeOnFirstRequest = TRUE;
  510. ++clientState->NegativeRefCount;
  511. //
  512. // FreeClientState will be TRUE if the two refcounts are equal.
  513. //
  514. FreeClientState = (BOOL)(clientState->PositiveRefCount == clientState->NegativeRefCount);
  515. clientState->CriticalSectionHeld = FALSE;
  516. LeaveCriticalSection(&clientState->CriticalSection);
  517. BinlPrintDbg((DEBUG_OSC, "Leaving CS for clientState = 0x%08x\n", clientState ));
  518. if (FreeClientState)
  519. {
  520. FreeClient(clientState);
  521. }
  522. }
  523. }
  524. return Error;
  525. }
  526. DWORD
  527. OscVerifyLastResponseSize(
  528. PCLIENT_STATE clientState
  529. )
  530. /*++
  531. Routine Description:
  532. This function checks that the LastResponse buffer is big enough,
  533. if not it reallocates it. The algorithm used is to keep increasing
  534. the size of the buffer, but not to try to shrink it.
  535. Arguments:
  536. clientState - The client state for the remote. clientState->
  537. LastResponseLength should be set to the needed size.
  538. Return Value:
  539. Windows Error.
  540. --*/
  541. {
  542. DWORD Error = ERROR_SUCCESS;
  543. TraceFunc("OscVerifyLastResponseSize( )\n");
  544. if (clientState->LastResponseAllocated < clientState->LastResponseLength) {
  545. if (clientState->LastResponse) {
  546. BinlFreeMemory(clientState->LastResponse);
  547. }
  548. clientState->LastResponse = BinlAllocateMemory(clientState->LastResponseLength);
  549. if (clientState->LastResponse == NULL) {
  550. clientState->LastResponseAllocated = 0;
  551. BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not grow LastResponse to %ld bytes\n", clientState->LastResponseLength ));
  552. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  553. } else {
  554. clientState->LastResponseAllocated = clientState->LastResponseLength;
  555. }
  556. }
  557. return Error;
  558. }
  559. DWORD
  560. OscProcessNegotiate(
  561. LPBINL_REQUEST_CONTEXT RequestContext,
  562. PCLIENT_STATE clientState
  563. )
  564. /*++
  565. Routine Description:
  566. This function processes a negotiate message.
  567. IT IS CALLED WITH clientState->CriticalSection HELD.
  568. Arguments:
  569. RequestContext - A pointer to the BinlRequestContext block for
  570. this request.
  571. clientState - The client state for the remote.
  572. Return Value:
  573. Windows Error.
  574. --*/
  575. {
  576. DWORD Error;
  577. SECURITY_STATUS SecStatus;
  578. SecBufferDesc NegotiateDesc;
  579. SecBuffer NegotiateBuffer;
  580. SecBufferDesc ChallengeDesc;
  581. SecBuffer ChallengeBuffer;
  582. TimeStamp Lifetime;
  583. LOGIN_PACKET UNALIGNED * loginMessage = (LOGIN_PACKET UNALIGNED *)RequestContext->ReceiveBuffer;
  584. PUCHAR TempChallengeBuffer;
  585. LOGIN_PACKET UNALIGNED * SendLoginMessage;
  586. TraceFunc("OscProcessNegotiate( )\n");
  587. //
  588. // First free anything we have allocated for this client. We
  589. // assume that each negotiate is a new request since the client
  590. // may have rebooted, so we don't resend the last response.
  591. //
  592. if (clientState->AuthenticatedDCLdapHandle) {
  593. // Reconnecting again. Use new credentials.
  594. ldap_unbind(clientState->AuthenticatedDCLdapHandle);
  595. clientState->AuthenticatedDCLdapHandle = NULL;
  596. }
  597. if (clientState->UserToken) {
  598. CloseHandle(clientState->UserToken);
  599. clientState->UserToken = NULL;
  600. }
  601. if (clientState->NegotiateProcessed) {
  602. BinlPrintDbg(( DEBUG_OSC, "Got negotiate from client, reinitializing negotiate\n" ));
  603. SecStatus = DeleteSecurityContext( &clientState->ServerContextHandle );
  604. if ( SecStatus != STATUS_SUCCESS ) {
  605. BinlPrintDbg(( DEBUG_OSC_ERROR, "DeleteSecurityContext failed: %lx\n", SecStatus ));
  606. // This seems to fail if a previous logon failed, so ignore errors
  607. // return SecStatus;
  608. }
  609. clientState->NegotiateProcessed = FALSE;
  610. }
  611. if (clientState->AuthenticateProcessed) {
  612. BinlPrintDbg(( DEBUG_OSC, "Got negotiate from client, reinitializing authenticate\n"));
  613. clientState->AuthenticateProcessed = FALSE;
  614. }
  615. //
  616. // Once the client has logged in we need to worry about resending screens
  617. // if the client issues the request again. 0 is an invalid sequence
  618. // number, so set this to 0 to ensure that any stale LastResponse is
  619. // not resent.
  620. //
  621. clientState->LastSequenceNumber = 0;
  622. //
  623. // Get the ChallengeMessage (ServerSide)
  624. //
  625. ChallengeDesc.ulVersion = 0;
  626. ChallengeDesc.cBuffers = 1;
  627. ChallengeDesc.pBuffers = &ChallengeBuffer;
  628. TempChallengeBuffer = (PUCHAR)BinlAllocateMemory(PackageInfo->cbMaxToken);
  629. if (TempChallengeBuffer == NULL) {
  630. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  631. BinlPrintDbg(( DEBUG_OSC, "Allocate TempChallengeBuffer failed\n"));
  632. return Error;
  633. }
  634. ChallengeBuffer.pvBuffer = TempChallengeBuffer;
  635. ChallengeBuffer.cbBuffer = PackageInfo->cbMaxToken;
  636. ChallengeBuffer.BufferType = SECBUFFER_TOKEN;
  637. NegotiateDesc.ulVersion = 0;
  638. NegotiateDesc.cBuffers = 1;
  639. NegotiateDesc.pBuffers = &NegotiateBuffer;
  640. NegotiateBuffer.cbBuffer = loginMessage->Length;
  641. NegotiateBuffer.BufferType = SECBUFFER_TOKEN | SECBUFFER_READONLY;
  642. NegotiateBuffer.pvBuffer = loginMessage->Data;
  643. SecStatus = AcceptSecurityContext(
  644. &CredentialHandle,
  645. NULL, // No Server context yet
  646. &NegotiateDesc,
  647. ISC_REQ_SEQUENCE_DETECT | ASC_REQ_ALLOW_NON_USER_LOGONS,
  648. SECURITY_NATIVE_DREP,
  649. &clientState->ServerContextHandle,
  650. &ChallengeDesc,
  651. &clientState->ContextAttributes,
  652. &Lifetime );
  653. if ( SecStatus != STATUS_SUCCESS ) {
  654. if ( !NT_SUCCESS(SecStatus) ) {
  655. BinlPrintDbg(( DEBUG_OSC_ERROR, "AcceptSecurityContext (Challenge): %lx", SecStatus ));
  656. BinlFreeMemory(TempChallengeBuffer);
  657. return SecStatus;
  658. }
  659. }
  660. //
  661. // Send the challenge message back to the client.
  662. //
  663. clientState->LastResponseLength = ChallengeBuffer.cbBuffer + LOGIN_PACKET_DATA_OFFSET;
  664. Error = OscVerifyLastResponseSize(clientState);
  665. if (Error != ERROR_SUCCESS) {
  666. BinlFreeMemory(TempChallengeBuffer);
  667. return Error;
  668. }
  669. SendLoginMessage = (LOGIN_PACKET UNALIGNED *)(clientState->LastResponse);
  670. memcpy(SendLoginMessage->Signature, ChallengeSignature, 4);
  671. SendLoginMessage->Length = ChallengeBuffer.cbBuffer;
  672. memcpy(SendLoginMessage->Data, ChallengeBuffer.pvBuffer, ChallengeBuffer.cbBuffer);
  673. BinlFreeMemory(TempChallengeBuffer);
  674. #ifdef TEST_FAILURE
  675. if (FailFirstChallenge) {
  676. BinlPrintDbg(( DEBUG_OSC, "NOT Sending CHL, %d bytes\n", clientState->LastResponseLength));
  677. FailFirstChallenge = FALSE;
  678. Error = ERROR_SUCCESS;
  679. } else
  680. #endif
  681. Error = SendUdpMessage(RequestContext, clientState, FALSE, FALSE);
  682. if (Error != ERROR_SUCCESS) {
  683. BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not send CHAL message %d\n", Error));
  684. }
  685. clientState->NegotiateProcessed = TRUE;
  686. return Error;
  687. }
  688. DWORD
  689. OscProcessAuthenticate(
  690. LPBINL_REQUEST_CONTEXT RequestContext,
  691. PCLIENT_STATE clientState
  692. )
  693. /*++
  694. Routine Description:
  695. This function processes an authenticate message.
  696. IT IS CALLED WITH clientState->CriticalSection HELD.
  697. Arguments:
  698. RequestContext - A pointer to the BinlRequestContext block for
  699. this request.
  700. clientState - The client state for the remote.
  701. Return Value:
  702. Windows Error.
  703. --*/
  704. {
  705. DWORD Error;
  706. SECURITY_STATUS SecStatus;
  707. SecBufferDesc AuthenticateDesc;
  708. SecBuffer AuthenticateBuffer;
  709. TimeStamp Lifetime;
  710. LOGIN_PACKET UNALIGNED * loginMessage = (LOGIN_PACKET UNALIGNED *)RequestContext->ReceiveBuffer;
  711. ULONG FlipServerListLength;
  712. LOGIN_PACKET UNALIGNED * SendLoginMessage;
  713. UCHAR TempServerList[MAX_FLIP_SERVER_COUNT*4];
  714. TraceFunc("OscProcessAuthenticate( )\n");
  715. //
  716. // Make sure we have gotten a negotiate.
  717. //
  718. if (!clientState->NegotiateProcessed) {
  719. BinlPrintDbg(( DEBUG_OSC_ERROR, "Received AUTH without NEG?\n"));
  720. return ERROR_INVALID_DATA;
  721. }
  722. //
  723. // If we have already responsed to this, just resend with the
  724. // same status.
  725. //
  726. if (clientState->AuthenticateProcessed) {
  727. SecStatus = clientState->AuthenticateStatus;
  728. BinlPrintDbg(( DEBUG_OSC, "Got authenticate from client, resending\n"));
  729. } else {
  730. //
  731. // Finally authenticate the user (ServerSide)
  732. //
  733. AuthenticateDesc.ulVersion = 0;
  734. AuthenticateDesc.cBuffers = 1;
  735. AuthenticateDesc.pBuffers = &AuthenticateBuffer;
  736. AuthenticateBuffer.cbBuffer = loginMessage->Length;
  737. AuthenticateBuffer.BufferType = SECBUFFER_TOKEN | SECBUFFER_READONLY;
  738. AuthenticateBuffer.pvBuffer = loginMessage->Data;
  739. SecStatus = AcceptSecurityContext(
  740. NULL,
  741. &clientState->ServerContextHandle,
  742. &AuthenticateDesc,
  743. ASC_REQ_ALLOW_NON_USER_LOGONS,
  744. SECURITY_NATIVE_DREP,
  745. &clientState->ServerContextHandle,
  746. NULL,
  747. &clientState->ContextAttributes,
  748. &Lifetime );
  749. FlipServerListLength = 0;
  750. if ( SecStatus != STATUS_SUCCESS ) {
  751. BinlPrintDbg(( DEBUG_OSC_ERROR, "AcceptSecurityContext (Challenge): %lx\n", SecStatus ));
  752. } else {
  753. #if 0
  754. //
  755. // Impersonate the client.
  756. //
  757. SecStatus = ImpersonateSecurityContext( &clientState->ServerContextHandle );
  758. if ( SecStatus != STATUS_SUCCESS ) {
  759. BinlPrintDbg(( DEBUG_OSC_ERROR, "ImpersonateSecurityContext: %lx\n", SecStatus ));
  760. if ( !NT_SUCCESS(SecStatus) ) {
  761. return SecStatus;
  762. }
  763. }
  764. #endif
  765. #if 0
  766. //
  767. // If the client is not indicating that he has been flipped, then
  768. // look for a flip list. The client indicates that he has been
  769. // flipped by using a signature of "AU2" instead of "AUT".
  770. //
  771. if (memcmp(loginMessage->Signature, AuthenticateFlippedSignature, 4) != 0) {
  772. OscGetFlipServerList(
  773. TempServerList,
  774. &FlipServerListLength
  775. );
  776. }
  777. #endif
  778. #if 0
  779. //
  780. // Revert to ourselves.
  781. //
  782. SecStatus = RevertSecurityContext( &clientState->ServerContextHandle );
  783. if ( SecStatus != STATUS_SUCCESS ) {
  784. BinlPrintDbg(( DEBUG_OSC_ERROR, "RevertSecurityContext: %lx\n", SecStatus ));
  785. if ( !NT_SUCCESS(SecStatus) ) {
  786. return SecStatus;
  787. }
  788. }
  789. #endif
  790. }
  791. //
  792. // Send the result back to the client. If there is a flip server
  793. // list, it has already been stored after g_LoginMessage->Status and
  794. // FlipServerListLength reflects its length.
  795. //
  796. clientState->LastResponseLength = LOGIN_PACKET_DATA_OFFSET + sizeof(ULONG) + FlipServerListLength;
  797. Error = OscVerifyLastResponseSize(clientState);
  798. if (Error != ERROR_SUCCESS) {
  799. return Error;
  800. }
  801. SendLoginMessage = (LOGIN_PACKET UNALIGNED *)(clientState->LastResponse);
  802. memcpy(SendLoginMessage->Signature, ResultSignature, 4);
  803. SendLoginMessage->Length = 4 + FlipServerListLength;
  804. SendLoginMessage->Status = SecStatus;
  805. memcpy((PUCHAR)(&SendLoginMessage->Status) + sizeof(ULONG), TempServerList, FlipServerListLength);
  806. clientState->AuthenticateProcessed = TRUE;
  807. clientState->AuthenticateStatus = SecStatus;
  808. }
  809. #ifdef TEST_FAILURE
  810. if (FailFirstResult) {
  811. BinlPrintDbg(( DEBUG_OSC, "NOT Sending OK, %d bytes\n", clientState->LastResponseLength));
  812. FailFirstResult = FALSE;
  813. Error = ERROR_SUCCESS;
  814. } else
  815. #endif
  816. Error = SendUdpMessage(RequestContext, clientState, FALSE, FALSE);
  817. if (Error != ERROR_SUCCESS) {
  818. BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not send OK message %d\n", Error));
  819. }
  820. return Error;
  821. }
  822. //
  823. //
  824. //
  825. DWORD
  826. OscProcessScreenArguments(
  827. LPBINL_REQUEST_CONTEXT RequestContext,
  828. PCLIENT_STATE clientState,
  829. PUCHAR *NameLoc
  830. )
  831. {
  832. SIGNED_PACKET UNALIGNED * signedMessage = (SIGNED_PACKET UNALIGNED *)RequestContext->ReceiveBuffer;
  833. PCHAR packetEnd = signedMessage->Data + signedMessage->Length - SIGNED_PACKET_EMPTY_LENGTH;
  834. DWORD Error = ERROR_SUCCESS;
  835. PCHAR Args;
  836. BOOLEAN GuidSent = FALSE;
  837. PDS_NAME_RESULTA pResults = NULL;
  838. TraceFunc("OscProcessScreenArguments( )\n");
  839. //
  840. // Find out the screen name and how long it is
  841. //
  842. *NameLoc = signedMessage->Data;
  843. Args = FindNext( *NameLoc, '\n', packetEnd );
  844. if ( Args == NULL )
  845. {
  846. BinlPrintDbg((DEBUG_OSC, "Could not determine the screen name."));
  847. *NameLoc = NULL;
  848. Error = ERROR_INVALID_DATA;
  849. }
  850. else
  851. {
  852. *Args = '\0'; // terminate
  853. //
  854. // The name can't have a ".." part in it.
  855. //
  856. if ((memcmp(*NameLoc, "..\\", 3) == 0) ||
  857. (strstr(*NameLoc, "\\..\\") != NULL)) {
  858. BinlPrintDbg((DEBUG_OSC, "Name <%s> has .. in it.", *NameLoc));
  859. *NameLoc = NULL;
  860. Error = ERROR_INVALID_DATA;
  861. } else {
  862. Args++; // skip the NULL char
  863. //
  864. // Munge any variables that might have been passed back with it.
  865. // They come in like this:
  866. // NextScreenName\nvariable=response\n....\nvariable=response\n\0
  867. //
  868. // If no arguments, it comes like:
  869. // NextScreenName\n\0
  870. //
  871. while ( *Args )
  872. {
  873. PCHAR NextArg;
  874. PCHAR Response;
  875. PCHAR EncodedResponse;
  876. //
  877. // Find the variable name
  878. //
  879. Response = FindNext( Args, '=', packetEnd );
  880. if ( Response == NULL )
  881. {
  882. BinlPrintDbg((DEBUG_OSC, "Could not find <variable>.\n" ));
  883. Error = ERROR_INVALID_DATA;
  884. break;
  885. }
  886. //
  887. // Find the variable response value
  888. //
  889. NextArg = FindNext( Response, '\n', packetEnd );
  890. if ( NextArg == NULL )
  891. {
  892. BinlPrintDbg((DEBUG_OSC, "Could not find <response>.\n" ));
  893. Error = ERROR_INVALID_DATA;
  894. break;
  895. }
  896. //
  897. // Terminate strings
  898. //
  899. *NextArg = '\0';
  900. *Response = '\0';
  901. //
  902. // Point to response
  903. //
  904. Response++;
  905. NextArg++;
  906. //
  907. //
  908. // Add them to the Variable table.
  909. // If the variable starts with a '*', encode it first.
  910. //
  911. if (Args[0] == '*') {
  912. Error = OscRunEncode(clientState, Response, &EncodedResponse);
  913. if (Error == ERROR_SUCCESS) {
  914. Error = OscAddVariableA( clientState, Args, EncodedResponse );
  915. BinlFreeMemory(EncodedResponse);
  916. }
  917. } else {
  918. //
  919. // Check whether this is the GUID variable. If it is, we'll
  920. // need to do some special processing later. See below.
  921. //
  922. if ( Response[0] != '\0'
  923. && StrCmpIA( Args, "GUID" ) == 0 )
  924. {
  925. GuidSent = TRUE;
  926. }
  927. // HACKHACK: Special case "MACHINEOU" for translation from canonical form
  928. // to 1779 so we can use it later.
  929. if ( Response[0] != '\0'
  930. && StrCmpIA( Args, "MACHINEOU" ) == 0 )
  931. {
  932. BOOL FirstTime = TRUE;
  933. invalid_ds_handle:
  934. // Make sure the handle is initialized
  935. if ( BinlOscClientDSHandle == NULL )
  936. {
  937. HANDLE hTemp;
  938. Error = DsBind(NULL, NULL, &hTemp);
  939. InterlockedCompareExchangePointer( (void**)&BinlOscClientDSHandle, hTemp, NULL );
  940. if ( BinlOscClientDSHandle != hTemp )
  941. {
  942. DsUnBind( &hTemp );
  943. }
  944. }
  945. if ( Error == ERROR_SUCCESS )
  946. {
  947. Error = DsCrackNamesA( BinlOscClientDSHandle,
  948. DS_NAME_NO_FLAGS,
  949. DS_UNKNOWN_NAME,
  950. DS_FQDN_1779_NAME,
  951. 1,
  952. &Response,
  953. &pResults );
  954. BinlAssertMsg( Error == ERROR_SUCCESS, "Error in DsCrackNames\n" );
  955. if ( Error == ERROR_SUCCESS ) {
  956. if ( pResults->cItems == 1
  957. && pResults->rItems[0].status == DS_NAME_NO_ERROR
  958. && pResults->rItems[0].pName ) { // paranoid
  959. Response = pResults->rItems[0].pName;
  960. } else {
  961. //
  962. // check if we have an "external trust"
  963. // problem. if that's the case, then we
  964. // need to bind to a DC in the domain we
  965. // care about and retrieve the information
  966. // from there.
  967. //
  968. if (pResults->cItems == 1 && pResults->rItems[0].status == DS_NAME_ERROR_DOMAIN_ONLY) {
  969. HANDLE hDC;
  970. Error = MyGetDcHandle(clientState, pResults->rItems[0].pDomain,&hDC);
  971. if (Error == ERROR_SUCCESS) {
  972. DsFreeNameResultA( pResults );
  973. pResults = NULL;
  974. Error = DsCrackNamesA(
  975. hDC,
  976. DS_NAME_NO_FLAGS,
  977. DS_UNKNOWN_NAME,
  978. DS_FQDN_1779_NAME,
  979. 1,
  980. &Response,
  981. &pResults );
  982. DsUnBindA(&hDC);
  983. if (Error != ERROR_SUCCESS) {
  984. BinlPrintDbg((
  985. DEBUG_OSC_ERROR,
  986. "DsCrackNames failed, ec = %d.\n",
  987. Error ));
  988. }
  989. if (Error == ERROR_SUCCESS ) {
  990. if ( pResults->cItems == 1
  991. && pResults->rItems[0].status == DS_NAME_NO_ERROR
  992. && pResults->rItems[0].pName ) { // paranoid
  993. Response = pResults->rItems[0].pName;
  994. } else {
  995. BinlPrintDbg((
  996. DEBUG_OSC,
  997. "pResults->rItems[0].status = %u\n",
  998. pResults->rItems[0].status ));
  999. Error = pResults->rItems[0].status;
  1000. }
  1001. }
  1002. }
  1003. }
  1004. }
  1005. }
  1006. }
  1007. // DsCrackNamesA seems to return either ERROR_INVALID_HANDLE or RPC_S_CALL_FAILED
  1008. // if the server is unavailable. If we get either of these, assume the handle is
  1009. // stale and needs to be refreshed before we try again.
  1010. if ( (Error == ERROR_INVALID_HANDLE) ||
  1011. (Error == RPC_S_CALL_FAILED) ) {
  1012. HANDLE hTemp;
  1013. BinlPrintDbg((
  1014. DEBUG_ERRORS,
  1015. "DsCrackNames returned a semi-expected error code. Need to refresh handle.\n"
  1016. ));
  1017. hTemp = InterlockedExchangePointer( (void**)&BinlOscClientDSHandle, NULL);
  1018. DsUnBind( &hTemp );
  1019. if (FirstTime) {
  1020. FirstTime = FALSE;
  1021. goto invalid_ds_handle;
  1022. }
  1023. }
  1024. if ( Error != ERROR_SUCCESS ) {
  1025. OscAddVariableA( clientState, "SUBERROR", Response );
  1026. return ERROR_BINL_UNABLE_TO_CONVERT_TO_DN;
  1027. }
  1028. }
  1029. Error = OscAddVariableA( clientState, Args, Response );
  1030. }
  1031. if ( Error != ERROR_SUCCESS ) {
  1032. BinlPrintDbg(( DEBUG_OSC_ERROR,
  1033. "!!Error 0x%08x - Could not add argument '%s' = '%s'\n",
  1034. Error, Args, Response));
  1035. break;
  1036. }
  1037. BinlPrintDbg(( DEBUG_OSC, "Got argument '%s' = '%s'\n", Args, Response));
  1038. if (pResults) {
  1039. DsFreeNameResultA( pResults );
  1040. pResults = NULL;
  1041. }
  1042. Args = NextArg;
  1043. }
  1044. }
  1045. }
  1046. //
  1047. // If the GUID was sent in this message, check to see if it's all zeroes
  1048. // or all FFs. If it is, substitute a MAC address-based GUID. This is the
  1049. // same thing that we do when we receive DHCP packets with bogus GUIDs.
  1050. // We need to do this here, otherwise we end up adding the client to the
  1051. // DS with a bogus GUID. It seems that PXE 2.0 clients always send the
  1052. // GUID option even when they have no real machine GUID.
  1053. //
  1054. // Note that we can't do this substitution in the loop above because we
  1055. // might not have process the MAC address variable yet. (Currently
  1056. // OSChooser always puts the MAC address ahead of the GUID in the packet,
  1057. // but we don't want to depend on that.)
  1058. //
  1059. if ( GuidSent ) {
  1060. //
  1061. // A GUID was sent. Retrieve it. It should be there, but if it
  1062. // isn't, just bail.
  1063. //
  1064. LPSTR guid = OscFindVariableA( clientState, "GUID" );
  1065. DWORD length;
  1066. if ( (guid != NULL) && ((length = strlen(guid)) != 0) ) {
  1067. //
  1068. // Check the GUID for all zeroes or all FFs.
  1069. //
  1070. if ( (strspn( guid, "0" ) == length) ||
  1071. (strspn( guid, "F" ) == length) ) {
  1072. //
  1073. // The GUID is bogus. Substitute a MAC address GUID.
  1074. // We should have the MAC address at this point, but
  1075. // if we don't, just bail.
  1076. //
  1077. LPSTR mac = OscFindVariableA( clientState, "MAC" );
  1078. if ( mac != NULL ) {
  1079. //
  1080. // The generated GUID is zeroes followed by the
  1081. // MAC address. (In other words, the MAC address
  1082. // is right-justified in a 32-character string.)
  1083. //
  1084. UCHAR guidString[(BINL_GUID_LENGTH * 2) + 1];
  1085. length = strlen(mac);
  1086. if ( length > BINL_GUID_LENGTH * 2 ) {
  1087. //
  1088. // We have an unusually long MAC address.
  1089. // Use the last 32 characters.
  1090. //
  1091. mac = mac + length - (BINL_GUID_LENGTH * 2);
  1092. length = BINL_GUID_LENGTH * 2;
  1093. }
  1094. if ( length < BINL_GUID_LENGTH * 2 ) {
  1095. //
  1096. // Write zeroes in front of the MAC address.
  1097. //
  1098. memset( guidString, '0', (BINL_GUID_LENGTH * 2) - length );
  1099. }
  1100. //
  1101. // Copy the MAC address into the GUID (including the
  1102. // null terminator).
  1103. //
  1104. strcpy( guidString + (BINL_GUID_LENGTH * 2) - length, mac );
  1105. //
  1106. // Set the new GUID.
  1107. //
  1108. OscAddVariableA( clientState, "GUID", guidString );
  1109. }
  1110. }
  1111. }
  1112. }
  1113. return Error;
  1114. }
  1115. //
  1116. //
  1117. //
  1118. DWORD
  1119. OscProcessRequestUnsigned(
  1120. LPBINL_REQUEST_CONTEXT RequestContext,
  1121. PCLIENT_STATE clientState
  1122. )
  1123. /*++
  1124. Routine Description:
  1125. This function processes a request message.
  1126. IT IS CALLED WITH clientState->CriticalSection HELD.
  1127. Arguments:
  1128. RequestContext - A pointer to the BinlRequestContext block for
  1129. this request.
  1130. clientState - The client state for the remote.
  1131. Return Value:
  1132. Windows Error.
  1133. --*/
  1134. {
  1135. DWORD Error = ERROR_SUCCESS;
  1136. SIGNED_PACKET UNALIGNED * signedMessage = (SIGNED_PACKET UNALIGNED *)RequestContext->ReceiveBuffer;
  1137. PCHAR RspMessage = NULL;
  1138. ULONG RspMessageLength = 0;
  1139. ULONG k;
  1140. WCHAR FilePath[ MAX_PATH ];
  1141. HANDLE hfile;
  1142. PCHAR NameLoc;
  1143. TraceFunc("OscProcessRequestUnsigned( )\n");
  1144. //
  1145. // All clients start with at least one unsigned request. When we get an
  1146. // unsigned request, the client may have rebooted and be asking for a
  1147. // different screen with the same sequence number. To avoid having
  1148. // to check for this, we don't bother resending unsigned screens. We
  1149. // do save the incoming sequence number since we use that for sending
  1150. // the response.
  1151. //
  1152. clientState->LastSequenceNumber = signedMessage->SequenceNumber;
  1153. //
  1154. // We have a valid request for a screen, process incoming arguments.
  1155. //
  1156. Error = OscProcessScreenArguments( RequestContext, clientState, &NameLoc );
  1157. if ( Error != ERROR_SUCCESS ) {
  1158. goto SendScreen;
  1159. } else {
  1160. //
  1161. // If NULL message, then send down the welcome screen.
  1162. //
  1163. if ( NameLoc == NULL || *NameLoc == '\0' )
  1164. {
  1165. if ( _snwprintf( FilePath,
  1166. sizeof(FilePath) / sizeof(FilePath[0]),
  1167. L"%ws\\OSChooser\\%s",
  1168. IntelliMirrorPathW,
  1169. DEFAULT_SCREEN_NAME
  1170. ) == -1 ) {
  1171. Error = ERROR_BAD_PATHNAME;
  1172. goto SendScreen;
  1173. }
  1174. BinlPrint(( DEBUG_OSC, "NULL screen name so we are retrieving the Welcome Screen.\n"));
  1175. //
  1176. // This is the first request a client makes, which is a good
  1177. // time to clean up the client state, unless we don't need to
  1178. // (because the client state is new).
  1179. //
  1180. if (clientState->InitializeOnFirstRequest) {
  1181. if (!OscInitializeClientVariables(clientState)) {
  1182. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1183. goto SendScreen;
  1184. }
  1185. }
  1186. }
  1187. else
  1188. {
  1189. WCHAR NameLocW[ MAX_PATH ];
  1190. ULONG NameLocLength;
  1191. //
  1192. // Create path to possible OSC file. Should look something like:
  1193. // "D:\RemoteInstall\OSChooser\English\NameLoc.OSC"
  1194. BinlAssert( NameLoc );
  1195. NameLocLength = strlen(NameLoc) + 1;
  1196. if (NameLocLength > MAX_PATH) {
  1197. NameLocLength = MAX_PATH-1;
  1198. NameLocW[ MAX_PATH-1 ] = L'\0';
  1199. }
  1200. mbstowcs( NameLocW, NameLoc, NameLocLength );
  1201. if ( _snwprintf( FilePath,
  1202. sizeof(FilePath) / sizeof(FilePath[0]),
  1203. L"%ws\\OSChooser\\%ws\\%ws.OSC",
  1204. IntelliMirrorPathW,
  1205. OscFindVariableW( clientState, "LANGUAGE" ),
  1206. NameLocW
  1207. ) == -1 ) {
  1208. Error = ERROR_BAD_PATHNAME;
  1209. goto SendScreen;
  1210. }
  1211. }
  1212. BinlPrint(( DEBUG_OSC, "Retrieving screen file: '%ws'\n", FilePath));
  1213. }
  1214. //
  1215. // If we find the file, load it into memory.
  1216. //
  1217. hfile = CreateFile( FilePath, GENERIC_READ,
  1218. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1219. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  1220. if ( hfile != INVALID_HANDLE_VALUE )
  1221. {
  1222. DWORD FileSize;
  1223. //
  1224. // Find out how big this screen is, if bigger than 0xFFFFFFFF we won't
  1225. // display it.
  1226. //
  1227. FileSize = GetFileSize( hfile, NULL );
  1228. if ( FileSize != 0xFFFFffff )
  1229. {
  1230. DWORD dwRead = 0;
  1231. RspMessage = BinlAllocateMemory( FileSize + 3 );
  1232. if ( RspMessage == NULL )
  1233. {
  1234. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1235. }
  1236. else
  1237. {
  1238. RspMessageLength = 0;
  1239. RspMessage[0] = '\0';
  1240. while ( dwRead != FileSize )
  1241. {
  1242. BOOL b;
  1243. DWORD dw;
  1244. b = ReadFile( hfile, &RspMessage[dwRead], FileSize - dwRead, &dw, NULL );
  1245. if (!b)
  1246. {
  1247. BinlPrintDbg(( DEBUG_OSC_ERROR, "Error reading screen file: Seek=%u, Size=%u, File=%ws\n",
  1248. dwRead, FileSize - dwRead, FilePath ));
  1249. Error = GetLastError( );
  1250. break;
  1251. }
  1252. dwRead += dw;
  1253. }
  1254. RspMessageLength = dwRead;
  1255. }
  1256. }
  1257. else
  1258. {
  1259. BinlPrintDbg((DEBUG_OSC, "!!Error - Could not determine file size.\n"));
  1260. Error = GetLastError();
  1261. }
  1262. CloseHandle( hfile );
  1263. }
  1264. else
  1265. {
  1266. BinlPrintDbg((DEBUG_OSC, "!!Error - Did not find screen file: '%ws'\n", FilePath));
  1267. Error = GetLastError();
  1268. OscAddVariableW( clientState, "SUBERROR", FilePath );
  1269. }
  1270. SendScreen:
  1271. //
  1272. // If there were any errors, switch to the error screen.
  1273. //
  1274. if ( Error != ERROR_SUCCESS )
  1275. {
  1276. //
  1277. // Send down message about the failure.
  1278. //
  1279. if ( RspMessage )
  1280. {
  1281. BinlFreeMemory( RspMessage );
  1282. RspMessage = NULL; // paranoid
  1283. }
  1284. BinlPrintDbg((DEBUG_OSC, "!!Error - Sending error screen back to client. Server error=0x%08x\n", Error));
  1285. Error = GenerateErrorScreen( &RspMessage,
  1286. &RspMessageLength,
  1287. Error,
  1288. clientState );
  1289. BinlAssert( Error == ERROR_SUCCESS );
  1290. if ( Error != ERROR_SUCCESS ) {
  1291. goto Cleanup;
  1292. }
  1293. //
  1294. // Require them to re-login.
  1295. //
  1296. // clientState->AuthenticateProcessed = FALSE;
  1297. }
  1298. if (RspMessage) {
  1299. // Do replacements for dynamic screens or error screens
  1300. SearchAndReplace( clientState->Variables,
  1301. &RspMessage,
  1302. clientState->nVariables,
  1303. RspMessageLength,
  1304. 0);
  1305. RspMessageLength = strlen( RspMessage ) + 1;
  1306. RspMessage[RspMessageLength-1] = '\0'; // paranoid
  1307. }
  1308. //
  1309. // Send out a signed response
  1310. //
  1311. BinlAssert( RspMessage );
  1312. // BinlPrint((DEBUG_OSC, "Sending Unsigned:\n%s\n", RspMessage));
  1313. OscSendUnsignedMessage( RequestContext, clientState, RspMessage, RspMessageLength );
  1314. Cleanup:
  1315. //
  1316. // Free any memory the we allocated for the screen.
  1317. //
  1318. if ( RspMessage ) {
  1319. BinlFreeMemory( RspMessage );
  1320. }
  1321. return Error;
  1322. }
  1323. //
  1324. //
  1325. //
  1326. OscInstallClient(
  1327. LPBINL_REQUEST_CONTEXT RequestContext,
  1328. PCLIENT_STATE clientState,
  1329. PCREATE_DATA createData )
  1330. {
  1331. DWORD Error;
  1332. //
  1333. // Client wants to create a machine account and run setup.
  1334. //
  1335. Error = OscSetupClient( clientState, TRUE );
  1336. if ( Error == ERROR_SUCCESS )
  1337. {
  1338. //
  1339. // Only create the account if the setup went OK.
  1340. //
  1341. RetryCreateAccount:
  1342. Error = OscCreateAccount( clientState, createData );
  1343. switch ( Error )
  1344. {
  1345. case ERROR_BINL_DUPLICATE_MACHINE_NAME_FOUND:
  1346. if ( clientState->fAutomaticMachineName ) {
  1347. // Try generating another name
  1348. Error = GenerateMachineName( clientState );
  1349. if ( Error == ERROR_SUCCESS ) {
  1350. goto RetryCreateAccount;
  1351. }
  1352. BinlPrint(( DEBUG_OSC_ERROR, "!!Error 0x%08x - Failed to generate machine name\n" ));
  1353. }
  1354. break;
  1355. default:
  1356. break;
  1357. }
  1358. }
  1359. #ifdef SET_ACLS_ON_CLIENT_DIRS
  1360. if ( Error == ERROR_SUCCESS )
  1361. {
  1362. //
  1363. // Change the ACL permission of the client machine's root directory
  1364. //
  1365. Error = OscSetClientDirectoryPermissions( clientState );
  1366. }
  1367. #endif // SET_ACLS_ON_CLIENT_DIRS
  1368. if ( Error != ERROR_SUCCESS )
  1369. {
  1370. OscUndoSetupClient( clientState );
  1371. BinlPrint((DEBUG_OSC,
  1372. "!!Error 0x%08x - Error setting up the client for Setup.\n",
  1373. Error ));
  1374. }
  1375. return Error;
  1376. }
  1377. //
  1378. // OscGetCreateData( )
  1379. //
  1380. // Queries the DS to get the information required to create
  1381. // the CreateData secret and then builds one.
  1382. //
  1383. DWORD
  1384. OscGetCreateData(
  1385. LPBINL_REQUEST_CONTEXT RequestContext,
  1386. PCLIENT_STATE clientState,
  1387. PCREATE_DATA CreateData)
  1388. {
  1389. DWORD Error = ERROR_BINL_INVALID_BINL_CLIENT;
  1390. PCHAR pGuid;
  1391. PWCHAR pGuidW;
  1392. UCHAR Guid[ BINL_GUID_LENGTH ];
  1393. WCHAR BootFilePath[MAX_PATH];
  1394. PMACHINE_INFO pMachineInfo = NULL;
  1395. WCHAR MachinePassword[LM20_PWLEN + 1];
  1396. WCHAR SifPath[MAX_PATH];
  1397. WCHAR SifFile[(BINL_GUID_LENGTH*2)+(sizeof(TEMP_DIRECTORY)/sizeof(WCHAR))+6];
  1398. DWORD FileAttributes;
  1399. ULONG MachinePasswordLength;
  1400. DWORD dwRequestedInfo = MI_NAME | MI_BOOTFILENAME | MI_MACHINEDN | MI_SAMNAME;
  1401. PWCHAR pszOU;
  1402. USHORT SystemArchitecture;
  1403. DWORD OldFlags;
  1404. ULONG lenIntelliMirror = wcslen(IntelliMirrorPathW) + 1;
  1405. pGuid = OscFindVariableA( clientState, "GUID" );
  1406. if ( pGuid[0] == '\0' ) {
  1407. BinlPrintDbg((DEBUG_OSC_ERROR, "OscGetCreateData: could not find GUID" ));
  1408. OscAddVariableA( clientState, "SUBERROR", "GUID" );
  1409. Error = ERROR_BINL_MISSING_VARIABLE;
  1410. goto e0;
  1411. }
  1412. pGuidW = OscFindVariableW( clientState, "GUID" );
  1413. if ( pGuidW[0] == L'\0' ) {
  1414. BinlPrintDbg((DEBUG_OSC_ERROR, "OscGetCreateData: could not find GUID (unicode)" ));
  1415. OscAddVariableA( clientState, "SUBERROR", "GUID" );
  1416. Error = ERROR_BINL_MISSING_VARIABLE;
  1417. goto e0;
  1418. }
  1419. Error = OscGuidToBytes( pGuid, Guid );
  1420. if ( Error != ERROR_SUCCESS ) {
  1421. BinlPrintDbg((DEBUG_OSC_ERROR, "OscGetCreateData: OscGuidToBytes failed" ));
  1422. goto e0;
  1423. }
  1424. SystemArchitecture = OscPlatformToArchitecture(clientState);
  1425. Error = GetBootParameters( Guid,
  1426. &pMachineInfo,
  1427. dwRequestedInfo,
  1428. SystemArchitecture,
  1429. FALSE );
  1430. if ( Error != ERROR_SUCCESS ) {
  1431. BinlPrintDbg((DEBUG_OSC_ERROR, "OscGetCreateData: GetBootParameters failed %lx", Error ));
  1432. goto e0;
  1433. }
  1434. BinlAssertMsg(( pMachineInfo->dwFlags & dwRequestedInfo )== dwRequestedInfo, "Missing info." );
  1435. //
  1436. // The SIF file is named GUID.sif, and it must exist (the SIF
  1437. // files go in a tmp directory so an admin may have cleaned it
  1438. // out).
  1439. //
  1440. wsprintf( SifFile, L"%ws\\%ws.sif", TEMP_DIRECTORY, pGuidW );
  1441. if ( _snwprintf( SifPath,
  1442. sizeof(SifPath) / sizeof(SifPath[0]),
  1443. L"%ws\\%ws",
  1444. IntelliMirrorPathW,
  1445. SifFile
  1446. ) == -1 ) {
  1447. Error = ERROR_BAD_PATHNAME;
  1448. goto e0;
  1449. }
  1450. FileAttributes = GetFileAttributes(SifPath);
  1451. if (FileAttributes == 0xFFFFFFFF) {
  1452. BinlPrintDbg((DEBUG_OSC_ERROR, "OscGetCreateData: SifFile not found" ));
  1453. OscAddVariableW( clientState, "SUBERROR", SifPath );
  1454. Error = ERROR_BINL_SIFFILE_NOT_FOUND;
  1455. goto e0;
  1456. }
  1457. //
  1458. // The bootfile stored in pMachineInfo->BootFileName will point to
  1459. // oschooser, so we parse the SIF to find the setupldr boot file.
  1460. //
  1461. BootFilePath[0] = L'\0';
  1462. GetPrivateProfileString( OSCHOOSER_SIF_SECTIONW,
  1463. L"LaunchFile",
  1464. BootFilePath, // default
  1465. BootFilePath,
  1466. MAX_PATH,
  1467. SifPath );
  1468. //
  1469. // This might fail to add if it is too long due to bogus data in the .sif.
  1470. //
  1471. Error = OscAddVariableW( clientState, "BOOTFILE", BootFilePath );
  1472. if ( Error != ERROR_SUCCESS ) {
  1473. goto e0;
  1474. }
  1475. //
  1476. // This might fail to add if it is too long due to bogus data in the DS.
  1477. //
  1478. if (pMachineInfo->dwFlags & MI_SIFFILENAME_ALLOC) {
  1479. Error = OscAddVariableW( clientState, "FORCESIFFILE", pMachineInfo->ForcedSifFileName );
  1480. if ( Error != ERROR_SUCCESS ) {
  1481. goto e0;
  1482. }
  1483. }
  1484. //
  1485. // These next two shouldn't fail unless someone has modified the DS by
  1486. // hand, since they are checked when the accounts are generated, but
  1487. // best to be safe.
  1488. //
  1489. Error = OscAddVariableW( clientState, "NETBIOSNAME", pMachineInfo->SamName );
  1490. if ( Error != ERROR_SUCCESS) {
  1491. goto e0;
  1492. }
  1493. Error = OscAddVariableW( clientState, "MACHINENAME", pMachineInfo->Name );
  1494. if ( Error != ERROR_SUCCESS) {
  1495. goto e0;
  1496. }
  1497. //
  1498. // Shouldn't fail unless the IntelliMirrorPathW is too long.
  1499. //
  1500. Error = OscAddVariableW( clientState, "SIFFILE", &SifPath[lenIntelliMirror] );
  1501. if ( Error != ERROR_SUCCESS) {
  1502. goto e0;
  1503. }
  1504. pszOU = wcschr( pMachineInfo->MachineDN, L',' );
  1505. if (pszOU)
  1506. {
  1507. pszOU++;
  1508. Error = OscAddVariableW( clientState, "MACHINEOU", pszOU );
  1509. if ( Error != ERROR_SUCCESS ) {
  1510. goto e0;
  1511. }
  1512. }
  1513. Error = OscSetupMachinePassword( clientState, SifPath );
  1514. if (Error != ERROR_SUCCESS) {
  1515. goto e0;
  1516. }
  1517. //
  1518. // save off the old flags so we can update the machine account information
  1519. //
  1520. OldFlags = pMachineInfo->dwFlags;
  1521. pMachineInfo->dwFlags = MI_PASSWORD | MI_MACHINEDN;
  1522. pMachineInfo->Password = clientState->MachineAccountPassword;
  1523. pMachineInfo->PasswordLength = clientState->MachineAccountPasswordLength;
  1524. Error = UpdateAccount( clientState, pMachineInfo, FALSE );
  1525. if ( Error != LDAP_SUCCESS ) {
  1526. BinlPrintDbg(( DEBUG_OSC_ERROR, "!! LdapError 0x%08x - UpdateAccount( ) failed.\n", Error ));
  1527. goto e0;
  1528. }
  1529. pMachineInfo->dwFlags |= OldFlags; // add them back
  1530. Error = OscConstructSecret(
  1531. clientState,
  1532. clientState->MachineAccountPassword,
  1533. clientState->MachineAccountPasswordLength,
  1534. CreateData );
  1535. if ( Error != ERROR_SUCCESS ) {
  1536. BinlPrintDbg((DEBUG_OSC_ERROR, "OscGetCreateData: OscConstructSecret failed %lx", Error ));
  1537. goto e0;
  1538. }
  1539. e0:
  1540. if (pMachineInfo) {
  1541. BinlDoneWithCacheEntry( pMachineInfo, FALSE );
  1542. }
  1543. return Error;
  1544. }
  1545. //
  1546. //
  1547. //
  1548. DWORD
  1549. OscProcessRequestSigned(
  1550. LPBINL_REQUEST_CONTEXT RequestContext,
  1551. PCLIENT_STATE clientState
  1552. )
  1553. /*++
  1554. Routine Description:
  1555. This function processes a request message.
  1556. IT IS CALLED WITH clientState->CriticalSection HELD.
  1557. Arguments:
  1558. RequestContext - A pointer to the BinlRequestContext block for
  1559. this request.
  1560. clientState - The client state for the remote.
  1561. Return Value:
  1562. Windows Error.
  1563. --*/
  1564. {
  1565. DWORD Error = ERROR_SUCCESS;
  1566. SIGNED_PACKET UNALIGNED * signedMessage = (SIGNED_PACKET UNALIGNED *)RequestContext->ReceiveBuffer;
  1567. PCHAR RspMessage = NULL;
  1568. ULONG RspMessageLength = 0;
  1569. PCHAR RspBinaryData = NULL;
  1570. ULONG RspBinaryDataLength = 0;
  1571. ULONG k;
  1572. DWORD dwErr;
  1573. WCHAR FilePath[ MAX_PATH ];
  1574. CHAR TmpName[ 16 ];
  1575. HANDLE hfile;
  1576. PCHAR NameLoc;
  1577. LPSTR psz;
  1578. TraceFunc("OscProcessRequestSigned( )\n");
  1579. if ( clientState->AuthenticateProcessed == FALSE )
  1580. {
  1581. SIGNED_PACKET UNALIGNED * SendSignedMessage;
  1582. //
  1583. // This may happen if we reboot the server -- send an ERRS
  1584. // and the client should reconnect OK.
  1585. //
  1586. BinlPrintDbg(( DEBUG_OSC_ERROR, "Got REQ but not authenticated, sending UNR\n" ));
  1587. clientState->LastResponseLength = SIGNED_PACKET_ERROR_LENGTH;
  1588. Error = OscVerifyLastResponseSize(clientState);
  1589. if (Error != ERROR_SUCCESS) {
  1590. return Error;
  1591. }
  1592. SendSignedMessage =
  1593. (SIGNED_PACKET UNALIGNED *)(clientState->LastResponse);
  1594. memcpy(SendSignedMessage->Signature, UnrecognizedClientSignature, 4);
  1595. SendSignedMessage->Length = 4;
  1596. SendSignedMessage->SequenceNumber = signedMessage->SequenceNumber;
  1597. Error = SendUdpMessage( RequestContext, clientState, FALSE, FALSE );
  1598. return Error;
  1599. }
  1600. if ( signedMessage->SequenceNumber == clientState->LastSequenceNumber )
  1601. {
  1602. //
  1603. // Is the signature the same as the last one we sent out? If so,
  1604. // then just resend (we'll do that after we leave this if
  1605. // statement).
  1606. //
  1607. if ( clientState->LastResponse )
  1608. {
  1609. BinlPrintDbg(( DEBUG_OSC, "Resending last message\n" ));
  1610. }
  1611. else
  1612. {
  1613. //
  1614. // We were unable to save the last response -- we are hosed!
  1615. //
  1616. BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not resend last message\n" ));
  1617. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1618. }
  1619. //
  1620. // Resend last response
  1621. //
  1622. return SendUdpMessage( RequestContext,
  1623. clientState,
  1624. TRUE,
  1625. TRUE );
  1626. }
  1627. else if ( signedMessage->SequenceNumber != ((clientState->LastSequenceNumber % 0x2000) + 1))
  1628. {
  1629. //
  1630. // It's not the next message - ignore it.
  1631. //
  1632. BinlPrintDbg(( DEBUG_OSC, "got bogus sequence number: Got %u. Expected: %u\n",
  1633. signedMessage->SequenceNumber , ((clientState->LastSequenceNumber % 0x2000) + 1)));
  1634. return ERROR_INVALID_DATA;
  1635. }
  1636. //
  1637. // Advance the clientState sequence counter
  1638. //
  1639. clientState->LastSequenceNumber = signedMessage->SequenceNumber;
  1640. //
  1641. // Verify packet signature
  1642. //
  1643. Error = OscVerifySignature( clientState, signedMessage );
  1644. if ( Error != STATUS_SUCCESS )
  1645. return Error;
  1646. //
  1647. // We have a valid request for a screen.
  1648. //
  1649. if (signedMessage->Length == (SIGNED_PACKET_EMPTY_LENGTH))
  1650. {
  1651. //
  1652. // An empty packet indicates to us to send down the Welcome screen.
  1653. //
  1654. if ( _snwprintf( FilePath,
  1655. sizeof(FilePath) / sizeof(FilePath[0]),
  1656. L"%ws\\OSChooser\\%s",
  1657. IntelliMirrorPathW,
  1658. DEFAULT_SCREEN_NAME
  1659. ) == -1 ) {
  1660. Error = ERROR_BAD_PATHNAME;
  1661. } else {
  1662. BinlPrintDbg(( DEBUG_OSC, "Retrieving Welcome Screen: %ws\n", FilePath));
  1663. }
  1664. }
  1665. else
  1666. {
  1667. //
  1668. // Process incoming arguments and get the next screen's name
  1669. //
  1670. Error = OscProcessScreenArguments( RequestContext, clientState, &NameLoc );
  1671. GrabAnotherScreen:
  1672. //
  1673. // Process special responses.
  1674. //
  1675. // INSTALL: Indicates that user wants to create a new machine.
  1676. // RESTART: Indicates the client wants to restart setup.
  1677. //
  1678. if ( Error == ERROR_SUCCESS )
  1679. {
  1680. PWCHAR pCheckDomain = OscFindVariableW( clientState, "CHECKDOMAIN" );
  1681. if (pCheckDomain[0] == L'1')
  1682. {
  1683. //
  1684. // After the first login, the client will set this to
  1685. // tell us to verify that the domain name used in this
  1686. // context matches what the user requested. This will
  1687. // prevent an invalid domain from being let through
  1688. // due to SSPI using the default domain in that case.
  1689. //
  1690. BOOLEAN failedCheck = FALSE;
  1691. DWORD impersonateError;
  1692. PWCHAR pUserDomain = OscFindVariableW( clientState, "USERDOMAIN" );
  1693. if ( pUserDomain[0] != L'\0' )
  1694. {
  1695. SecPkgCredentials_Names names;
  1696. SECURITY_STATUS secStatus;
  1697. PWCHAR backslash;
  1698. PWSTR netbiosUserDomain = NULL;
  1699. DWORD Flags;
  1700. secStatus = QueryContextAttributes(
  1701. &clientState->ServerContextHandle,
  1702. SECPKG_CRED_ATTR_NAMES,
  1703. &names);
  1704. if (secStatus == STATUS_SUCCESS) {
  1705. //
  1706. // The part up to the '\\' is the domain.
  1707. //
  1708. backslash = wcschr(names.sUserName, L'\\');
  1709. if (backslash != NULL) {
  1710. *backslash = L'\0';
  1711. }
  1712. if (ERROR_SUCCESS != GetDomainNetBIOSName(pUserDomain,&netbiosUserDomain)) {
  1713. Error = ERROR_BINL_USER_LOGIN_FAILED;
  1714. failedCheck = TRUE;
  1715. } else {
  1716. //
  1717. // If the domain names don't match, then the login
  1718. // succeeded due to the security package trying the
  1719. // server's domain name. We don't want to let those
  1720. // through since the LogonUser call will eventually
  1721. // fail. So fail right here.
  1722. //
  1723. if (_wcsicmp(netbiosUserDomain, names.sUserName) != 0) {
  1724. Error = ERROR_BINL_USER_LOGIN_FAILED;
  1725. failedCheck = TRUE;
  1726. }
  1727. }
  1728. if (netbiosUserDomain) {
  1729. BinlFreeMemory( netbiosUserDomain );
  1730. }
  1731. FreeContextBuffer(names.sUserName);
  1732. }
  1733. }
  1734. //
  1735. // If we haven't already failed, try to impersonate and
  1736. // revert. This verifies that the user has batch logon
  1737. // permission.
  1738. //
  1739. if (!failedCheck) {
  1740. impersonateError = OscImpersonate(clientState);
  1741. if (impersonateError != ERROR_SUCCESS) {
  1742. if ( impersonateError == ERROR_LOGON_TYPE_NOT_GRANTED )
  1743. {
  1744. BinlPrint(( DEBUG_OSC_ERROR,
  1745. "!!Error 0x%08x - CheckDomain: Batch Logon type not granted\n",
  1746. impersonateError ));
  1747. Error = ERROR_BINL_LOGON_TYPE_NOT_GRANTED;
  1748. }
  1749. else
  1750. {
  1751. BinlPrint(( DEBUG_OSC_ERROR, "!!Error 0x%08x - CheckDomain: login failed\n", impersonateError ));
  1752. Error = ERROR_BINL_USER_LOGIN_FAILED;
  1753. }
  1754. } else {
  1755. OscRevert(clientState);
  1756. }
  1757. }
  1758. //
  1759. // Once we've done this once, don't need to do it again.
  1760. //
  1761. if ( OscAddVariableW( clientState, "CHECKDOMAIN", L"0" ) != ERROR_SUCCESS )
  1762. {
  1763. // don't overwrite the "Error" value unless we need to
  1764. Error = OscAddVariableW( clientState, "CHECKDOMAIN", L"0" );
  1765. }
  1766. }
  1767. if ( lstrcmpiA( NameLoc, "INSTALL" ) == 0 )
  1768. {
  1769. RspBinaryData = BinlAllocateMemory( sizeof(CREATE_DATA) );
  1770. if (RspBinaryData == NULL) {
  1771. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1772. goto SendResponse; // skip the rest and just send it.
  1773. }
  1774. RspBinaryDataLength = sizeof(CREATE_DATA);
  1775. //
  1776. // This will fill in RspBinaryData with the CREATE_DATA
  1777. // information.
  1778. //
  1779. Error = OscInstallClient( RequestContext, clientState, (PCREATE_DATA)RspBinaryData );
  1780. }
  1781. else if ( lstrcmpiA( NameLoc, "LAUNCH" ) == 0 )
  1782. {
  1783. //
  1784. // Launch the "LaunchFile" indicated in a SIF. Mainly used to
  1785. // launch tools and other real-mode utilities. In the case of
  1786. // the command console, we need to copy this sif and fix it up
  1787. // so that it looks like a textmode setup.
  1788. //
  1789. PCHAR pTemplatePath = OscFindVariableA( clientState, "SIF" );
  1790. PCREATE_DATA pCreate;
  1791. if ( pTemplatePath[0] == '\0' ) {
  1792. BinlPrint(( DEBUG_OSC_ERROR, "Missing SIF variable\n" ));
  1793. OscAddVariableA( clientState, "SUBERROR", "SIF" );
  1794. Error = ERROR_BINL_MISSING_VARIABLE;
  1795. goto SendResponse; // skip the rest and just send it.
  1796. }
  1797. if (RspMessage != NULL) {
  1798. BinlFreeMemory(RspMessage);
  1799. }
  1800. RspMessageLength = strlen("LAUNCH") + 1 + sizeof(CREATE_DATA);
  1801. RspMessage = BinlAllocateMemory( RspMessageLength );
  1802. if ( RspMessage == NULL ) {
  1803. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1804. goto SendResponse; // skip the rest and just send it.
  1805. }
  1806. strcpy(RspMessage, "LAUNCH");
  1807. RspBinaryData = BinlAllocateMemory( sizeof(CREATE_DATA) );
  1808. if (RspBinaryData == NULL) {
  1809. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1810. goto SendResponse; // skip the rest and just send it.
  1811. }
  1812. ZeroMemory( RspBinaryData, sizeof(CREATE_DATA) );
  1813. pCreate = (PCREATE_DATA)RspBinaryData;
  1814. pCreate->VersionNumber = OSC_CREATE_DATA_VERSION;
  1815. if (OscSifIsCmdConsA(pTemplatePath)) {
  1816. //
  1817. // Setup the client for an install
  1818. //
  1819. Error = OscSetupClient( clientState, FALSE );
  1820. if (Error != ERROR_SUCCESS) {
  1821. goto SendResponse;
  1822. }
  1823. pTemplatePath = (PCHAR)FilePath;
  1824. strcpy(pTemplatePath, IntelliMirrorPathA);
  1825. strcat(pTemplatePath, "\\");
  1826. strcat(pTemplatePath, OscFindVariableA( clientState, "SIFFILE" ));
  1827. pCreate->RebootParameter = OSC_REBOOT_COMMAND_CONSOLE_ONLY;
  1828. }
  1829. if (OscSifIsASR(pTemplatePath)) {
  1830. PSTR pGuid,pPathToAsrFile;
  1831. //
  1832. // Setup the client for an install
  1833. //
  1834. Error = OscSetupClient( clientState, FALSE );
  1835. if (Error != ERROR_SUCCESS) {
  1836. goto SendResponse;
  1837. }
  1838. pTemplatePath = (PCHAR)FilePath;
  1839. strcpy(pTemplatePath, IntelliMirrorPathA);
  1840. strcat(pTemplatePath, "\\");
  1841. strcat(pTemplatePath, OscFindVariableA( clientState, "SIFFILE" ));
  1842. #if 0
  1843. pGuid = OscFindVariableA( clientState, "GUID" );
  1844. pPathToAsrFile = BinlAllocateMemory( sizeof("ASRFiles\\") + strlen(pGuid) + sizeof(".sif") + 1 );
  1845. if (pPathToAsrFile) {
  1846. strcat(pPathToAsrFile, "ASRFiles\\");
  1847. strcat(pPathToAsrFile, pGuid );
  1848. strcat(pPathToAsrFile, ".sif" );
  1849. WritePrivateProfileStringA(
  1850. OSCHOOSER_SIF_SECTIONA,
  1851. "ASRFile",
  1852. pPathToAsrFile,
  1853. pTemplatePath );
  1854. BinlFreeMemory( pPathToAsrFile );
  1855. }
  1856. #endif
  1857. pCreate->RebootParameter = OSC_REBOOT_ASR;
  1858. }
  1859. GetPrivateProfileStringA( OSCHOOSER_SIF_SECTIONA,
  1860. "LaunchFile",
  1861. "",
  1862. pCreate->NextBootfile,
  1863. sizeof(pCreate->NextBootfile),
  1864. pTemplatePath );
  1865. strcpy(pCreate->SifFile, pTemplatePath + strlen(IntelliMirrorPathA) + 1); // skip the next backslash
  1866. BinlPrint(( DEBUG_OSC_ERROR, "Client will use SIF file %s\n", pCreate->SifFile ));
  1867. BinlPrint(( DEBUG_OSC_ERROR, "Client rebooting to %s\n", pCreate->NextBootfile ));
  1868. RspBinaryDataLength = sizeof(CREATE_DATA);
  1869. goto SendResponse; // skip the rest and just send it.
  1870. }
  1871. else if ( lstrcmpiA( NameLoc, "RESTART" ) == 0 )
  1872. {
  1873. //
  1874. // NOTE: This is very similar to the GETCREATE processing
  1875. // except for the error case. We send down a packet with
  1876. // only the create data in it.
  1877. //
  1878. //
  1879. // Make RspMessage be NULL.
  1880. //
  1881. if (RspMessage != NULL) {
  1882. BinlFreeMemory(RspMessage);
  1883. RspMessage = NULL;
  1884. }
  1885. RspMessageLength = 0;
  1886. RspBinaryData = BinlAllocateMemory( sizeof(CREATE_DATA) );
  1887. if (RspBinaryData == NULL) {
  1888. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1889. goto SendResponse; // skip the rest and just send it.
  1890. }
  1891. Error = OscGetCreateData( RequestContext, clientState, (PCREATE_DATA)RspBinaryData );
  1892. if ( Error == ERROR_SUCCESS ) {
  1893. RspBinaryDataLength = sizeof(CREATE_DATA);
  1894. goto SendResponse; // skip the rest and just send it.
  1895. } else {
  1896. BinlAssert( sizeof(TmpName) >= sizeof("RSTRTERR") );
  1897. BinlFreeMemory(RspBinaryData);
  1898. RspBinaryData = NULL;
  1899. strcpy(TmpName, "RSTRTERR");
  1900. NameLoc = TmpName;
  1901. Error = ERROR_SUCCESS;
  1902. }
  1903. }
  1904. }
  1905. //
  1906. // Try to retrieve the next screen
  1907. //
  1908. if ( Error == ERROR_SUCCESS )
  1909. {
  1910. //
  1911. // If NULL message, then send down the welcome screen.
  1912. //
  1913. if ( NameLoc == NULL || *NameLoc == '\0' )
  1914. {
  1915. if ( _snwprintf( FilePath,
  1916. sizeof(FilePath) / sizeof(FilePath[0]),
  1917. L"%ws\\OSChooser\\%s",
  1918. IntelliMirrorPathW,
  1919. DEFAULT_SCREEN_NAME
  1920. ) == -1 ) {
  1921. Error = ERROR_BAD_PATHNAME;
  1922. } else {
  1923. BinlPrint(( DEBUG_OSC, "NULL screen name so we are retrieving the Welcome Screen.\n"));
  1924. }
  1925. }
  1926. else
  1927. {
  1928. WCHAR NameLocW[ MAX_PATH ];
  1929. ULONG NameLocLength;
  1930. //
  1931. // Create path to possible OSC file. Should look something like:
  1932. // "D:\RemoteInstall\OSChooser\English\NameLoc.OSC"
  1933. BinlAssert( NameLoc );
  1934. NameLocLength = strlen(NameLoc) + 1;
  1935. if (NameLocLength > MAX_PATH) {
  1936. NameLocLength = MAX_PATH-1;
  1937. NameLocW[ MAX_PATH-1 ] = L'\0';
  1938. }
  1939. mbstowcs( NameLocW, NameLoc, NameLocLength );
  1940. #if DBG
  1941. if (OscWatchVariable[0] != '\0') {
  1942. DbgPrint("Looking for screen <%ws>\n", NameLocW);
  1943. }
  1944. #endif
  1945. if ( _snwprintf( FilePath,
  1946. sizeof(FilePath) / sizeof(FilePath[0]),
  1947. L"%ws\\OSChooser\\%ws\\%ws.OSC",
  1948. IntelliMirrorPathW,
  1949. OscFindVariableW( clientState, "LANGUAGE" ),
  1950. NameLocW
  1951. ) == -1 ) {
  1952. Error = ERROR_BAD_PATHNAME;
  1953. }
  1954. }
  1955. }
  1956. }
  1957. if ( Error == ERROR_SUCCESS )
  1958. {
  1959. //
  1960. // If we find the file, load it into memory.
  1961. //
  1962. BinlPrint(( DEBUG_OSC, "Retrieving screen file: '%ws'\n", FilePath));
  1963. hfile = CreateFile( FilePath, GENERIC_READ,
  1964. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1965. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  1966. if ( hfile != INVALID_HANDLE_VALUE )
  1967. {
  1968. DWORD FileSize;
  1969. //
  1970. // Find out how big this screen is, if bigger than 0xFFFFFFFF we won't
  1971. // display it.
  1972. //
  1973. FileSize = GetFileSize( hfile, NULL );
  1974. if ( FileSize != 0xFFFFffff )
  1975. {
  1976. DWORD dwRead = 0;
  1977. //
  1978. // This might be non-NULL if we looped back to GrabAnotherScreen.
  1979. //
  1980. if (RspMessage != NULL) {
  1981. BinlFreeMemory(RspMessage);
  1982. }
  1983. RspMessage = BinlAllocateMemory( FileSize + RspBinaryDataLength + 3 );
  1984. if ( RspMessage == NULL )
  1985. {
  1986. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1987. }
  1988. else
  1989. {
  1990. RspMessageLength = 0;
  1991. RspMessage[0] = '\0';
  1992. while ( dwRead != FileSize )
  1993. {
  1994. BOOL b;
  1995. DWORD dw;
  1996. b = ReadFile( hfile, &RspMessage[dwRead], FileSize - dwRead, &dw, NULL );
  1997. if (!b)
  1998. {
  1999. BinlPrint(( DEBUG_OSC_ERROR, "Error reading screen file: Seek=%u, Size=%u, File=%ws\n",
  2000. dwRead, FileSize - dwRead, FilePath ));
  2001. Error = GetLastError( );
  2002. break;
  2003. }
  2004. dwRead += dw;
  2005. }
  2006. RspMessageLength = FileSize + 1;
  2007. RspMessage[RspMessageLength - 1] = '\0';
  2008. }
  2009. }
  2010. else
  2011. {
  2012. BinlPrintDbg((DEBUG_OSC, "!!Error - Could not determine file size.\n"));
  2013. Error = GetLastError();
  2014. }
  2015. CloseHandle( hfile );
  2016. }
  2017. else
  2018. {
  2019. BinlPrint((DEBUG_OSC, "!!Error - Did not find screen file: '%ws'\n", FilePath));
  2020. Error = GetLastError();
  2021. OscAddVariableW( clientState, "SUBERROR", FilePath );
  2022. }
  2023. }
  2024. //
  2025. // Check the outgoing screen for special NAMEs
  2026. //
  2027. if ( Error == ERROR_SUCCESS )
  2028. {
  2029. //
  2030. // Read the screen name from the "NAME" section of the file. This allows
  2031. // the admin to have different screens with the same "NAME" section but
  2032. // that have a different layout and/or text associated with them.
  2033. //
  2034. PCHAR ServerMeta = RspMessage;
  2035. while ( ServerMeta && !!*ServerMeta )
  2036. {
  2037. CHAR tmpCh = '>'; // save (default)
  2038. LPSTR EndofLine;
  2039. ServerMeta = StrStrIA( ServerMeta, "<META " );
  2040. if ( !ServerMeta )
  2041. break;
  2042. // Find the end of the meta line
  2043. EndofLine = StrChrA( ServerMeta, '>' );
  2044. if ( !EndofLine )
  2045. break;
  2046. *EndofLine = '\0'; // terminate
  2047. // Is it a server side meta?
  2048. ServerMeta = StrStrIA( ServerMeta, "SERVER" );
  2049. if ( !ServerMeta )
  2050. goto SkipLine; // nope, skip it
  2051. // Find the action
  2052. ServerMeta = StrStrIA( ServerMeta, "ACTION=" );
  2053. if ( !ServerMeta )
  2054. goto SkipLine; // nothing to do, skip it
  2055. ServerMeta += sizeof("ACTION=") - sizeof("");
  2056. // If the ACTION encapsulated in a pair of quotes, the only use
  2057. // the part that is within the quotes.
  2058. if ( *ServerMeta == '\"' ) {
  2059. *EndofLine = '>'; // restore
  2060. ServerMeta++;
  2061. EndofLine = StrChrA( ServerMeta, '\"' );
  2062. if ( EndofLine ) {
  2063. tmpCh = '\"'; // save
  2064. } else {
  2065. EndofLine = StrChrA( ServerMeta, '>' );
  2066. }
  2067. *EndofLine = '\0'; // terminate
  2068. }
  2069. BinlPrintDbg(( DEBUG_OSC, "Processing SERVER side ACTION: %s\n", ServerMeta ));
  2070. if ( StrCmpNIA( ServerMeta, "ENUM ", sizeof("ENUM ")-sizeof("") ) == 0 )
  2071. {
  2072. PCHAR pOptionBuffer;
  2073. ULONG OptionBufferLength;
  2074. PCHAR pOptionBufferTemp;
  2075. ULONG OptionBufferLengthTemp;
  2076. PCHAR pCurOptionBuffer;
  2077. PCHAR pDirToEnum;
  2078. CHAR SaveChar;
  2079. //
  2080. // They are asking for the screen that has the listing
  2081. // of the different types of network booted installations.
  2082. //
  2083. ServerMeta += sizeof("ENUM ") - sizeof("");
  2084. OscResetVariable( clientState, "OPTIONS" );
  2085. while (*ServerMeta != '\0') {
  2086. //
  2087. // Skip leading blanks
  2088. //
  2089. while (*ServerMeta == ' ') {
  2090. ServerMeta++;
  2091. }
  2092. if (*ServerMeta == '\0') {
  2093. break;
  2094. }
  2095. //
  2096. // Save beginning of the dir
  2097. //
  2098. pDirToEnum = ServerMeta;
  2099. //
  2100. // Skip to the end of the word
  2101. //
  2102. while ((*ServerMeta != ' ') &&
  2103. (*ServerMeta != '\"') &&
  2104. (*ServerMeta != '>') &&
  2105. (*ServerMeta != '\0')){
  2106. ServerMeta++;
  2107. }
  2108. //
  2109. // Temporarily terminate the word, we will restore it in this loop.
  2110. //
  2111. SaveChar = *ServerMeta;
  2112. *ServerMeta = '\0';
  2113. BinlPrintDbg(( DEBUG_OSC, "Processing SERVER side ACTION: ENUM, directory %s\n", pDirToEnum));
  2114. //
  2115. // Start a buffer for this directory
  2116. //
  2117. OptionBufferLengthTemp = 512;
  2118. pOptionBufferTemp = BinlAllocateMemory( OptionBufferLengthTemp );
  2119. if ( pOptionBufferTemp == NULL )
  2120. {
  2121. OscResetVariable( clientState, "OPTIONS" );
  2122. *ServerMeta = SaveChar;
  2123. if (SaveChar != '\0') {
  2124. ServerMeta++;
  2125. }
  2126. break;
  2127. }
  2128. BinlAssert(RspBinaryData == NULL);
  2129. *pOptionBufferTemp = '\0';
  2130. SearchAndGenerateOSMenu( &pOptionBufferTemp,
  2131. &OptionBufferLengthTemp,
  2132. pDirToEnum,
  2133. clientState
  2134. );
  2135. if (*pOptionBufferTemp == '\0') {
  2136. BinlFreeMemory( pOptionBufferTemp );
  2137. *ServerMeta = SaveChar;
  2138. if (SaveChar != '\0') {
  2139. ServerMeta++;
  2140. }
  2141. continue;
  2142. }
  2143. pCurOptionBuffer = OscFindVariableA( clientState, "OPTIONS" );
  2144. OptionBufferLength = strlen(pCurOptionBuffer) + sizeof("");
  2145. pOptionBuffer = BinlAllocateMemory( OptionBufferLength + OptionBufferLengthTemp );
  2146. if (pOptionBuffer == NULL) {
  2147. BinlFreeMemory( pOptionBufferTemp );
  2148. OscResetVariable( clientState, "OPTIONS" );
  2149. *ServerMeta = SaveChar;
  2150. if (SaveChar != '\0') {
  2151. ServerMeta++;
  2152. }
  2153. break;
  2154. }
  2155. strcpy( pOptionBuffer, pCurOptionBuffer );
  2156. strcat( pOptionBuffer, pOptionBufferTemp);
  2157. OscAddVariableA( clientState, "OPTIONS", pOptionBuffer );
  2158. BinlFreeMemory( pOptionBuffer );
  2159. BinlFreeMemory( pOptionBufferTemp );
  2160. *ServerMeta = SaveChar;
  2161. if (SaveChar != '\0') {
  2162. ServerMeta++;
  2163. }
  2164. }
  2165. //
  2166. // If this generated no options, send down the
  2167. // NOOSES screen.
  2168. //
  2169. pOptionBuffer = OscFindVariableA( clientState, "OPTIONS" );
  2170. if (*pOptionBuffer == '\0') {
  2171. BinlAssert( sizeof(TmpName) >= sizeof("NOOSES") );
  2172. strcpy(TmpName, "NOOSES");
  2173. NameLoc = TmpName;
  2174. goto GrabAnotherScreen;
  2175. }
  2176. }
  2177. else if ( StrCmpNIA( ServerMeta, "WARNING", sizeof("WARNING")-sizeof("") ) == 0 )
  2178. {
  2179. LPSTR pszSIF = OscFindVariableA( clientState, "SIF" );
  2180. if ( pszSIF )
  2181. {
  2182. //
  2183. // lets check if we're repartitioning or not. if we aren't,
  2184. // then there's no need to show the warning screen.
  2185. //
  2186. CHAR szRepartition[ 64 ];
  2187. BOOL DoRepartitionWarning = TRUE;
  2188. GetPrivateProfileStringA( "RemoteInstall",
  2189. "Repartition",
  2190. "Yes",
  2191. szRepartition,
  2192. sizeof(szRepartition)/sizeof(szRepartition[0]),
  2193. pszSIF );
  2194. if ( StrCmpIA( szRepartition, "no") != 0) {
  2195. LPSTR pszPart;
  2196. //
  2197. // check if 'repartition' points to an OSC variable
  2198. //
  2199. if (szRepartition[0] = '%' && szRepartition[strlen(szRepartition)-1] == '%') {
  2200. szRepartition[strlen(szRepartition)-1] = '\0';
  2201. pszPart= OscFindVariableA( clientState, &szRepartition[1] );
  2202. if (StrCmpIA( pszPart, "no") == 0) {
  2203. DoRepartitionWarning = FALSE;
  2204. }
  2205. }
  2206. } else {
  2207. DoRepartitionWarning = FALSE;
  2208. }
  2209. if ( DoRepartitionWarning == FALSE ) {
  2210. // skip the warning screen
  2211. BinlPrintDbg(( DEBUG_OSC, "Repartition == NO. Skipping WARNING screen.\n" ));
  2212. *EndofLine = '>'; // restore
  2213. ServerMeta = StrStrIA( RspMessage, "ENTER" );
  2214. if ( ServerMeta )
  2215. {
  2216. ServerMeta = StrStrIA( ServerMeta, "HREF=" );
  2217. ServerMeta += sizeof("HREF=") - sizeof("");
  2218. // If the HREF encapsulated in a pair of quotes, the only use
  2219. // the part that is within the quotes.
  2220. if ( *ServerMeta == '\"' ) {
  2221. ServerMeta ++;
  2222. EndofLine = StrChrA( ServerMeta, '\"' );
  2223. if ( !EndofLine) {
  2224. EndofLine = StrChrA( ServerMeta, '>' );
  2225. }
  2226. if ( EndofLine ) {
  2227. *EndofLine = '\0'; // terminate
  2228. }
  2229. }
  2230. NameLoc = ServerMeta;
  2231. goto GrabAnotherScreen;
  2232. }
  2233. }
  2234. }
  2235. }
  2236. else if ( StrCmpNIA( ServerMeta, "FILTER ", sizeof("FILTER ")-sizeof("") ) == 0 )
  2237. {
  2238. ULONG OptionCount;
  2239. //
  2240. // The options on the form on this screen are supposed
  2241. // to be filtered by looking at the GPO list for this
  2242. // client. This call may modify RspMessageLength, but
  2243. // it will only shorten it.
  2244. //
  2245. // NOTE: We assume that the data we want to modify is after
  2246. // the META SERVER ACTION tag. This assumption shows up in
  2247. // two ways:
  2248. // a) The second parameter to FilterFormOptions is the place
  2249. // to start filtering -- we pass it EndOfLine+1 (that is,
  2250. // the point right after the FILTER name) because
  2251. // we have put a NULL character at EndOfLine. But this means
  2252. // it won't process any of the screen before the META tag.
  2253. // b) FilterFormOptions may remove parts of the message at
  2254. // any place after the "start filtering" location -- so in
  2255. // order for the code below after SkipLine: to still work,
  2256. // we have to assume that the place in the message that
  2257. // EndOfLine points to has not changed.
  2258. //
  2259. OptionCount = FilterFormOptions(
  2260. RspMessage, // start of message
  2261. EndofLine+1, // where we start filtering -- after the FILTER name,
  2262. // since that is NULL-terminated.
  2263. &RspMessageLength,
  2264. ServerMeta + sizeof("FILTER ") - sizeof(""),
  2265. clientState);
  2266. //
  2267. // If the result of the filtering is no options, then
  2268. // send down the NOCHOICE screen.
  2269. //
  2270. if (OptionCount == 0) {
  2271. BinlAssert( sizeof(TmpName) >= sizeof("NOCHOICE") );
  2272. strcpy(TmpName, "NOCHOICE");
  2273. NameLoc = TmpName;
  2274. goto GrabAnotherScreen;
  2275. }
  2276. }
  2277. else if ( StrCmpNIA( ServerMeta, "CHECKGUID ", sizeof("CHECKGUID ")-sizeof("") ) == 0 )
  2278. {
  2279. //
  2280. // Search the DS for accounts that have this same GUID and
  2281. // fill in the form with all the dups. If it's fatal, tell
  2282. // them so here, otherwise allow them to continue warned.
  2283. //
  2284. PCHAR successScreen;
  2285. PCHAR failureScreen;
  2286. Error = OscCheckMachineDN( clientState );
  2287. //
  2288. // If there are DN warnings, then the text is saved off in
  2289. // %SUBERROR% string.
  2290. //
  2291. ServerMeta += sizeof("CHECKGUID ") - sizeof("");
  2292. successScreen = ServerMeta;
  2293. while (*successScreen == ' ') {
  2294. successScreen++;
  2295. }
  2296. failureScreen = successScreen;
  2297. while (*failureScreen != ' ' &&
  2298. *failureScreen != '>' &&
  2299. *failureScreen != '\0' ) {
  2300. failureScreen++;
  2301. }
  2302. if (*failureScreen == ' ') {
  2303. // terminate the success screen name
  2304. *failureScreen = '\0';
  2305. failureScreen++;
  2306. //
  2307. // if they neglected to put a second parameter, then they
  2308. // must not care about the warning case.
  2309. //
  2310. while (*failureScreen == ' ') {
  2311. failureScreen++;
  2312. }
  2313. }
  2314. if ((*failureScreen == '>') || (*failureScreen == '\0')) {
  2315. failureScreen = successScreen;
  2316. }
  2317. if (Error == ERROR_BINL_DUPLICATE_MACHINE_NAME_FOUND) {
  2318. //
  2319. // in the case of failure, we grab the second parameter
  2320. // to CHECKGUID as the warning screen.
  2321. //
  2322. NameLoc = failureScreen;
  2323. } else if (Error != ERROR_SUCCESS) {
  2324. goto SendResponse;
  2325. } else {
  2326. NameLoc = successScreen;
  2327. }
  2328. //
  2329. // in the case of success, we grab the first parameter
  2330. // to CHECKGUID as the success screen.
  2331. //
  2332. Error = ERROR_SUCCESS;
  2333. goto GrabAnotherScreen;
  2334. }
  2335. else if ( StrCmpNIA( ServerMeta, "DNRESET", sizeof("DNRESET")-sizeof("") ) == 0 )
  2336. {
  2337. //
  2338. // the client went back to select between auto and custom,
  2339. // therefore we need to reset machineou, machinename,
  2340. // machinedn, and machinedomain
  2341. //
  2342. clientState->fHaveSetupMachineDN = FALSE;
  2343. OscResetVariable( clientState, "MACHINEOU" );
  2344. OscResetVariable( clientState, "MACHINENAME" );
  2345. OscResetVariable( clientState, "MACHINEDN" );
  2346. OscResetVariable( clientState, "MACHINEDOMAIN" );
  2347. OscResetVariable( clientState, "NETBIOSNAME" );
  2348. OscResetVariable( clientState, "DEFAULTDOMAINOU" );
  2349. }
  2350. SkipLine:
  2351. *EndofLine = tmpCh; // restore
  2352. EndofLine++;
  2353. ServerMeta = EndofLine;
  2354. }
  2355. }
  2356. SendResponse:
  2357. //
  2358. // If there were any errors, switch to the error screen.
  2359. //
  2360. if ( Error != ERROR_SUCCESS )
  2361. {
  2362. //
  2363. // Send down message about account creation failure.
  2364. //
  2365. if ( RspMessage )
  2366. {
  2367. BinlFreeMemory( RspMessage );
  2368. RspMessage = NULL; // paranoid
  2369. }
  2370. if ( RspBinaryData )
  2371. {
  2372. BinlFreeMemory( RspBinaryData );
  2373. RspBinaryData = NULL; // paranoid
  2374. }
  2375. Error = GenerateErrorScreen( &RspMessage,
  2376. &RspMessageLength,
  2377. Error,
  2378. clientState );
  2379. BinlAssert( Error == ERROR_SUCCESS );
  2380. if ( Error != ERROR_SUCCESS )
  2381. goto Cleanup;
  2382. // Don't send this
  2383. RspBinaryDataLength = 0;
  2384. }
  2385. //
  2386. // Make some adjustments to the outgoing screen
  2387. //
  2388. if ( Error == ERROR_SUCCESS )
  2389. {
  2390. if (RspMessage) {
  2391. //
  2392. // Do replacements for dynamic screens
  2393. //
  2394. SearchAndReplace( clientState->Variables,
  2395. &RspMessage,
  2396. clientState->nVariables,
  2397. RspMessageLength,
  2398. RspBinaryDataLength);
  2399. RspMessageLength = strlen( RspMessage ) + 1;
  2400. //
  2401. // NULL terminate RspMessage, and copy binary data if any exists.
  2402. //
  2403. RspMessage[RspMessageLength-1] = '\0';
  2404. if (RspBinaryDataLength) {
  2405. memcpy(RspMessage + RspMessageLength, RspBinaryData, RspBinaryDataLength);
  2406. RspMessageLength += RspBinaryDataLength;
  2407. }
  2408. } else {
  2409. //
  2410. // No RspMessage, RspBinaryData must be the entire thing.
  2411. //
  2412. BinlAssert( RspBinaryData );
  2413. RspMessage = RspBinaryData;
  2414. RspBinaryData = NULL;
  2415. RspMessageLength = RspBinaryDataLength;
  2416. RspBinaryDataLength = 0;
  2417. }
  2418. }
  2419. //
  2420. // Send out a signed response
  2421. //
  2422. BinlAssert( RspMessage );
  2423. // BinlPrint((DEBUG_OSC, "Sending Signed:\n%s\n", RspMessage));
  2424. #if DBG
  2425. if (OscWatchVariable[0] != '\0') {
  2426. DbgPrint("VALUE OF <%s> IS <%ws>\n", OscWatchVariable, OscFindVariableW(clientState, OscWatchVariable));
  2427. }
  2428. #endif
  2429. Error = OscSendSignedMessage( RequestContext, clientState, RspMessage, RspMessageLength );
  2430. Cleanup:
  2431. //
  2432. // Free any memory the we allocated for the screen.
  2433. //
  2434. if ( RspMessage ) {
  2435. BinlFreeMemory( RspMessage );
  2436. }
  2437. if ( RspBinaryData ) {
  2438. BinlFreeMemory( RspBinaryData );
  2439. }
  2440. // Clear the unencrypted buffer to ensure private data is erased.
  2441. ZeroMemory(&signedMessage->SequenceNumber, signedMessage->Length);
  2442. return Error;
  2443. }
  2444. //
  2445. //
  2446. //
  2447. DWORD
  2448. OscProcessSetupRequest(
  2449. LPBINL_REQUEST_CONTEXT RequestContext,
  2450. PCLIENT_STATE clientState
  2451. )
  2452. /*++
  2453. Routine Description:
  2454. This function processes a request message sent by textmode setup on a client.
  2455. IT IS CALLED WITH clientState->CriticalSection HELD.
  2456. Arguments:
  2457. RequestContext - A pointer to the BinlRequestContext block for
  2458. this request.
  2459. clientState - The client state for the remote.
  2460. Return Value:
  2461. Windows Error.
  2462. --*/
  2463. {
  2464. DWORD Error = ERROR_SUCCESS;
  2465. SPUDP_PACKET UNALIGNED * Message = (SPUDP_PACKET UNALIGNED *)RequestContext->ReceiveBuffer;
  2466. PCHAR RspMessage = NULL;
  2467. PSPUDP_PACKET SuccessPacket;
  2468. SPUDP_PACKET ErrorResponsePacket;
  2469. CLIENT_STATE TempClientState; // used to call UdpSendMessage
  2470. ULONG SuccessPacketLength;
  2471. PNETCARD_RESPONSE_DATABASE pInfEntry = NULL;
  2472. PSP_NETCARD_INFO_REQ pReqData;
  2473. PSP_NETCARD_INFO_RSP pRspData;
  2474. PLIST_ENTRY CopyHead;
  2475. PLIST_ENTRY CopyListEntry;
  2476. PNETCARD_FILECOPY_PARAMETERS cpyParam;
  2477. PWCHAR pTmp;
  2478. TraceFunc("OscProcessSetupRequest( )\n");
  2479. //
  2480. // All clients start with at least one unsigned request. When we get an
  2481. // unsigned request, the client may have rebooted and be asking for a
  2482. // different request with the same sequence number. To avoid having
  2483. // to check for this, we don't bother resending unsigned messages. We
  2484. // do save the incoming sequence number since we use that for sending
  2485. // the response.
  2486. //
  2487. clientState->LastSequenceNumber = Message->SequenceNumber;
  2488. //
  2489. // Get info from the INF file.
  2490. //
  2491. pReqData = (PSP_NETCARD_INFO_REQ)(&(Message->Data[0]));
  2492. Error = NetInfFindNetcardInfo(pReqData->SetupPath,
  2493. pReqData->Architecture,
  2494. pReqData->Version,
  2495. &pReqData->CardInfo,
  2496. NULL,
  2497. &pInfEntry
  2498. );
  2499. if (Error != ERROR_SUCCESS) {
  2500. BinlPrint(( DEBUG_OSC_ERROR, "OscProcessSetupRequest( Card not found ) \n"));
  2501. SendErrorResponse:
  2502. BinlPrintDbg(( DEBUG_OSC_ERROR, "OscProcessSetupRequest( ) sending Error response \n"));
  2503. memcpy(ErrorResponsePacket.Signature, NetcardErrorSignature, 4);
  2504. ErrorResponsePacket.Length = sizeof(ULONG) * 2;
  2505. ErrorResponsePacket.RequestType = Message->RequestType;
  2506. ErrorResponsePacket.Status = STATUS_INVALID_PARAMETER;
  2507. TempClientState.LastResponse = (PUCHAR)&ErrorResponsePacket;
  2508. TempClientState.LastResponseLength = 12;
  2509. Error = SendUdpMessage(RequestContext, &TempClientState, FALSE, FALSE);
  2510. goto CleanUp;
  2511. }
  2512. //
  2513. // We found a match, so construct a response. We first need to
  2514. // calculate how big the buffer needs to be.
  2515. //
  2516. CopyHead = &pInfEntry->FileCopyList;
  2517. SuccessPacketLength = sizeof(SP_NETCARD_INFO_RSP) - sizeof(WCHAR); // everything except the data
  2518. SuccessPacketLength += sizeof(WCHAR) * (wcslen(pInfEntry->DriverName) +
  2519. wcslen(pInfEntry->InfFileName) + 4);
  2520. CopyListEntry = CopyHead->Flink;
  2521. while (CopyListEntry != CopyHead) {
  2522. cpyParam = (PNETCARD_FILECOPY_PARAMETERS) CONTAINING_RECORD(CopyListEntry,
  2523. NETCARD_FILECOPY_PARAMETERS,
  2524. FileCopyListEntry
  2525. );
  2526. SuccessPacketLength += cpyParam->SourceFile.Length;
  2527. if (cpyParam->SourceFile.Buffer[cpyParam->SourceFile.Length / sizeof(WCHAR)] != UNICODE_NULL) {
  2528. SuccessPacketLength += sizeof(WCHAR);
  2529. }
  2530. if (cpyParam->DestFile.Buffer == NULL) {
  2531. SuccessPacketLength += sizeof(UNICODE_NULL);
  2532. } else {
  2533. SuccessPacketLength += cpyParam->DestFile.Length;
  2534. if (cpyParam->DestFile.Buffer[cpyParam->DestFile.Length / sizeof(WCHAR)] != UNICODE_NULL) {
  2535. SuccessPacketLength += sizeof(WCHAR);
  2536. }
  2537. }
  2538. CopyListEntry = CopyListEntry->Flink;
  2539. }
  2540. //
  2541. // Build response message
  2542. //
  2543. RspMessage = BinlAllocateMemory(SuccessPacketLength);
  2544. if (RspMessage == NULL) {
  2545. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2546. goto SendErrorResponse;
  2547. }
  2548. pRspData = (PSP_NETCARD_INFO_RSP)RspMessage;
  2549. pRspData->cFiles = 0;
  2550. pTmp = &(pRspData->MultiSzFiles[0]);
  2551. CopyListEntry = CopyHead->Flink;
  2552. while (CopyListEntry != CopyHead) {
  2553. pRspData->cFiles++;
  2554. cpyParam = (PNETCARD_FILECOPY_PARAMETERS) CONTAINING_RECORD(CopyListEntry,
  2555. NETCARD_FILECOPY_PARAMETERS,
  2556. FileCopyListEntry
  2557. );
  2558. RtlCopyMemory(pTmp, cpyParam->SourceFile.Buffer, cpyParam->SourceFile.Length);
  2559. pTmp = &(pTmp[cpyParam->SourceFile.Length / sizeof(WCHAR)]);
  2560. if (*pTmp != UNICODE_NULL) {
  2561. pTmp++;
  2562. *pTmp = UNICODE_NULL;
  2563. }
  2564. pTmp++;
  2565. if (cpyParam->DestFile.Buffer == NULL) {
  2566. *pTmp = UNICODE_NULL;
  2567. pTmp++;
  2568. } else {
  2569. RtlCopyMemory(pTmp, cpyParam->DestFile.Buffer, cpyParam->DestFile.Length);
  2570. pTmp = &(pTmp[cpyParam->DestFile.Length / sizeof(WCHAR)]);
  2571. if (*pTmp != UNICODE_NULL) {
  2572. pTmp++;
  2573. *pTmp = UNICODE_NULL;
  2574. }
  2575. pTmp++;
  2576. }
  2577. CopyListEntry = CopyListEntry->Flink;
  2578. }
  2579. //
  2580. // Add the driver name and INF file to the list
  2581. //
  2582. wcscpy(pTmp, pInfEntry->DriverName);
  2583. pTmp = pTmp + (wcslen(pTmp) + 1);
  2584. *pTmp = UNICODE_NULL;
  2585. pTmp++;
  2586. wcscpy(pTmp, pInfEntry->InfFileName);
  2587. pTmp = pTmp + (wcslen(pTmp) + 1);
  2588. *pTmp = UNICODE_NULL;
  2589. pTmp++;
  2590. pRspData->cFiles += 2;
  2591. //
  2592. // Send out a response
  2593. //
  2594. BinlAssert(RspMessage);
  2595. Error = OscSendSetupMessage(RequestContext,
  2596. clientState,
  2597. Message->RequestType,
  2598. RspMessage,
  2599. SuccessPacketLength
  2600. );
  2601. CleanUp:
  2602. //
  2603. // Free any memory the we allocated for the screen.
  2604. //
  2605. if (pInfEntry) {
  2606. NetInfDereferenceNetcardEntry(pInfEntry);
  2607. }
  2608. if (RspMessage) {
  2609. BinlFreeMemory(RspMessage);
  2610. }
  2611. return Error;
  2612. }
  2613. DWORD
  2614. OscProcessLogoff(
  2615. LPBINL_REQUEST_CONTEXT RequestContext,
  2616. PCLIENT_STATE clientState
  2617. )
  2618. /*++
  2619. Routine Description:
  2620. This function processes a logoff message.
  2621. IT IS CALLED WITH clientState->CriticalSection HELD.
  2622. Arguments:
  2623. RequestContext - A pointer to the BinlRequestContext block for
  2624. this request.
  2625. clientState - The client state for the remote.
  2626. Return Value:
  2627. Windows Error.
  2628. --*/
  2629. {
  2630. //
  2631. // clientState will already have been removed from the
  2632. // client database. All we need to do is add one to the
  2633. // NegativeRefCount and the client will then be deleted
  2634. // once everyone else is done using it.
  2635. //
  2636. TraceFunc("OscProcessLogoff( )\n");
  2637. ++clientState->NegativeRefCount;
  2638. if (clientState->PositiveRefCount != (clientState->NegativeRefCount+1)) {
  2639. BinlPrintDbg(( DEBUG_OSC_ERROR, "Refcount not equal at logoff for %s\n", inet_ntoa(*(struct in_addr *)&(clientState->RemoteIp)) ));
  2640. }
  2641. return ERROR_SUCCESS;
  2642. }
  2643. DWORD
  2644. OscProcessNetcardRequest(
  2645. LPBINL_REQUEST_CONTEXT RequestContext
  2646. )
  2647. /*++
  2648. Routine Description:
  2649. This function processes requests from clients for information
  2650. about network cards.
  2651. Arguments:
  2652. RequestContext - A pointer to the BinlRequestContext block for
  2653. this request.
  2654. Return Value:
  2655. Windows Error.
  2656. --*/
  2657. {
  2658. NETCARD_REQUEST_PACKET UNALIGNED * netcardRequestMessage = (NETCARD_REQUEST_PACKET UNALIGNED *)RequestContext->ReceiveBuffer;
  2659. NETCARD_RESPONSE_PACKET ErrorResponsePacket;
  2660. PNETCARD_RESPONSE_PACKET SuccessResponsePacket;
  2661. ULONG SuccessResponsePacketLength;
  2662. CLIENT_STATE TempClientState; // used to call UdpSendMessage
  2663. PWCHAR driverPath = NULL;
  2664. PWCHAR setupPath = NULL;
  2665. PCHAR ansiSetupPath = NULL;
  2666. ULONG ansiSetupLength;
  2667. DWORD Error;
  2668. ULONG i;
  2669. PNETCARD_RESPONSE_DATABASE pInfEntry = NULL;
  2670. TraceFunc("OscProcessNetcardRequest( )\n");
  2671. if (netcardRequestMessage->Version != OSCPKT_NETCARD_REQUEST_VERSION) {
  2672. Error = STATUS_INVALID_PARAMETER;
  2673. TraceFunc("OscProcessNetcardRequest( Version not correct ) \n");
  2674. goto sendErrorResponse;
  2675. }
  2676. if (RequestContext->ReceiveMessageSize < sizeof(NETCARD_REQUEST_PACKET)) {
  2677. Error = STATUS_INVALID_PARAMETER;
  2678. TraceFunc("OscProcessNetcardRequest( Message too short ) \n");
  2679. goto sendErrorResponse;
  2680. }
  2681. if ((netcardRequestMessage->SetupDirectoryLength >
  2682. RequestContext->ReceiveMessageSize -
  2683. sizeof(NETCARD_REQUEST_PACKET))
  2684. ) {
  2685. Error = STATUS_INVALID_PARAMETER;
  2686. TraceFunc("OscProcessNetcardRequest( setup path length invalid ) \n");
  2687. goto sendErrorResponse;
  2688. }
  2689. ansiSetupLength = netcardRequestMessage->SetupDirectoryLength;
  2690. ansiSetupPath = BinlAllocateMemory( ansiSetupLength + 1 );
  2691. if (ansiSetupPath == NULL) {
  2692. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2693. TraceFunc("OscProcessNetcardRequest( couldn't allocate temp buffer ) \n");
  2694. goto sendErrorResponse;
  2695. }
  2696. //
  2697. // convert the setup path to unicode safely
  2698. //
  2699. memcpy( ansiSetupPath,
  2700. &netcardRequestMessage->SetupDirectoryPath[0],
  2701. ansiSetupLength );
  2702. *(ansiSetupPath + ansiSetupLength) = '\0';
  2703. setupPath = (PWCHAR) BinlAllocateMemory( (ansiSetupLength + 1) * sizeof(WCHAR) );
  2704. if (setupPath == NULL) {
  2705. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2706. TraceFunc("OscProcessNetcardRequest( couldn't allocate setup path buffer ) \n");
  2707. goto sendErrorResponse;
  2708. }
  2709. mbstowcs( setupPath,
  2710. ansiSetupPath,
  2711. ansiSetupLength + 1); // include null
  2712. BinlFreeMemory( ansiSetupPath );
  2713. //
  2714. // Make sure this is a PCI card and the client request structure
  2715. // is version 0.
  2716. //
  2717. BinlPrintDbg(( DEBUG_OSC, "Searching %ws for NIC INF...\n", setupPath ));
  2718. Error = NetInfFindNetcardInfo( setupPath,
  2719. netcardRequestMessage->Architecture,
  2720. netcardRequestMessage->Version,
  2721. &netcardRequestMessage->CardInfo,
  2722. NULL,
  2723. &pInfEntry );
  2724. BinlAssert (pInfEntry != NULL || Error != ERROR_SUCCESS);
  2725. if (Error != ERROR_SUCCESS) {
  2726. BinlPrint(( DEBUG_OSC_ERROR, "OscProcessNetcardRequest( Card not found ) \n"));
  2727. sendErrorResponse:
  2728. BinlPrintDbg(( DEBUG_OSC_ERROR, "OscProcessNetcardRequest( ) sending Error response \n"));
  2729. memcpy(ErrorResponsePacket.Signature, NetcardErrorSignature, 4);
  2730. ErrorResponsePacket.Length = sizeof(ULONG);
  2731. ErrorResponsePacket.Status = STATUS_INVALID_PARAMETER;
  2732. TempClientState.LastResponse = (PUCHAR)&ErrorResponsePacket;
  2733. TempClientState.LastResponseLength = 12;
  2734. Error = SendUdpMessage(RequestContext, &TempClientState, FALSE, FALSE);
  2735. } else {
  2736. //
  2737. // We found a match, so construct a response. We first need to
  2738. // calculate how bit the buffer needs to be.
  2739. //
  2740. PLIST_ENTRY registryHead;
  2741. PLIST_ENTRY registryListEntry;
  2742. PNETCARD_REGISTRY_PARAMETERS regParam;
  2743. ULONG registryLength = 0;
  2744. registryHead = &pInfEntry->Registry;
  2745. SuccessResponsePacketLength = sizeof(NETCARD_RESPONSE_PACKET) +
  2746. + (( lstrlenW( pInfEntry->HardwareId ) + 1 ) * sizeof(WCHAR)) +
  2747. + (( lstrlenW( pInfEntry->DriverName ) + 1 ) * sizeof(WCHAR)) +
  2748. + (( lstrlenW( pInfEntry->ServiceName ) + 1 ) * sizeof(WCHAR)) +
  2749. sizeof(WCHAR); // termination for registry field
  2750. registryListEntry = registryHead->Flink;
  2751. while (registryListEntry != registryHead) {
  2752. //
  2753. // each entry is a field name, field type (2 = string, 1 = int)
  2754. // and field value. All of these are unicode strings terminated
  2755. // with a unicode null.
  2756. //
  2757. regParam = (PNETCARD_REGISTRY_PARAMETERS) CONTAINING_RECORD(
  2758. registryListEntry,
  2759. NETCARD_REGISTRY_PARAMETERS,
  2760. RegistryListEntry );
  2761. registryLength += regParam->Parameter.Length + 1;
  2762. registryLength += 2; // field type
  2763. registryLength += regParam->Value.Length + 1;
  2764. registryListEntry = registryListEntry->Flink;
  2765. }
  2766. registryLength += sizeof("Description");
  2767. registryLength += 2; // field type
  2768. registryLength += lstrlenW( pInfEntry->DriverDescription ) + 1;
  2769. SuccessResponsePacket = (PNETCARD_RESPONSE_PACKET)
  2770. BinlAllocateMemory(
  2771. SuccessResponsePacketLength +
  2772. registryLength );
  2773. if (SuccessResponsePacket == NULL) {
  2774. BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not allocate SuccessResponsePacket of %ld bytes\n",
  2775. SuccessResponsePacketLength + registryLength));
  2776. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2777. goto sendErrorResponse;
  2778. } else {
  2779. PWCHAR nextWideField;
  2780. PCHAR nextField;
  2781. PCHAR startOfRegistry;
  2782. ANSI_STRING aString;
  2783. UNICODE_STRING descriptionString;
  2784. RtlZeroMemory(SuccessResponsePacket,
  2785. SuccessResponsePacketLength + registryLength);
  2786. memcpy(SuccessResponsePacket->Signature, NetcardResponseSignature, 4);
  2787. SuccessResponsePacket->Status = STATUS_SUCCESS;
  2788. SuccessResponsePacket->Version = OSCPKT_NETCARD_REQUEST_VERSION;
  2789. nextWideField = (PWCHAR)(PCHAR)((PCHAR) &SuccessResponsePacket->RegistryOffset
  2790. + sizeof(ULONG));
  2791. lstrcpyW( nextWideField, pInfEntry->HardwareId );
  2792. SuccessResponsePacket->HardwareIdOffset = (ULONG)((PCHAR) nextWideField - (PCHAR) SuccessResponsePacket);
  2793. nextWideField += lstrlenW( pInfEntry->HardwareId ) + 1;
  2794. lstrcpyW( nextWideField, pInfEntry->DriverName );
  2795. SuccessResponsePacket->DriverNameOffset = (ULONG)((PCHAR) nextWideField - (PCHAR) SuccessResponsePacket);
  2796. nextWideField += lstrlenW( pInfEntry->DriverName ) + 1;
  2797. lstrcpyW( nextWideField, pInfEntry->ServiceName );
  2798. SuccessResponsePacket->ServiceNameOffset = (ULONG)((PCHAR) nextWideField - (PCHAR) SuccessResponsePacket);
  2799. nextWideField += lstrlenW( pInfEntry->ServiceName ) + 1;
  2800. SuccessResponsePacket->RegistryOffset = (ULONG)((PCHAR) nextWideField - (PCHAR) SuccessResponsePacket);
  2801. startOfRegistry = nextField = (PCHAR) nextWideField;
  2802. //
  2803. // the first registry value should be description, otherwise
  2804. // bad things happen in NDIS on the client.
  2805. //
  2806. strcpy( nextField, "Description" );
  2807. nextField += sizeof("Description");
  2808. //
  2809. // then copy in the type of the field, int or string
  2810. //
  2811. *(nextField++) = NETCARD_REGISTRY_TYPE_STRING;
  2812. *(nextField++) = '\0';
  2813. //
  2814. // then copy in the registry value
  2815. //
  2816. RtlInitUnicodeString( &descriptionString, pInfEntry->DriverDescription );
  2817. aString.Buffer = nextField;
  2818. aString.Length = 0;
  2819. aString.MaximumLength = ( descriptionString.Length + 1 ) * sizeof(WCHAR);
  2820. RtlUnicodeStringToAnsiString( &aString,
  2821. &descriptionString,
  2822. FALSE );
  2823. nextField += aString.Length + 1;
  2824. registryListEntry = registryHead->Flink;
  2825. while (registryListEntry != registryHead) {
  2826. //
  2827. // each entry is a field name, field type (2 = string, 1 = int)
  2828. // and field value. All of these are unicode strings terminated
  2829. // with a unicode null.
  2830. //
  2831. regParam = (PNETCARD_REGISTRY_PARAMETERS) CONTAINING_RECORD(
  2832. registryListEntry,
  2833. NETCARD_REGISTRY_PARAMETERS,
  2834. RegistryListEntry );
  2835. if (regParam->Parameter.Length > 0) {
  2836. //
  2837. // first copy in the registry value name
  2838. //
  2839. aString.Buffer = nextField;
  2840. aString.Length = 0;
  2841. aString.MaximumLength = ( regParam->Parameter.Length + 1 ) * sizeof(WCHAR);
  2842. RtlUnicodeStringToAnsiString( &aString,
  2843. &regParam->Parameter,
  2844. FALSE );
  2845. nextField += aString.Length + 1;
  2846. //
  2847. // then copy in the type of the field, int or string
  2848. //
  2849. *(nextField++) = (UCHAR) regParam->Type;
  2850. *(nextField++) = '\0';
  2851. //
  2852. // then copy in the registry value
  2853. //
  2854. aString.Buffer = nextField;
  2855. aString.Length = 0;
  2856. aString.MaximumLength = ( regParam->Value.Length + 1 ) * sizeof(WCHAR);
  2857. RtlUnicodeStringToAnsiString( &aString,
  2858. &regParam->Value,
  2859. FALSE );
  2860. nextField += aString.Length + 1;
  2861. }
  2862. registryListEntry = registryListEntry->Flink;
  2863. }
  2864. //
  2865. // put in extra null terminator for end of registry section
  2866. //
  2867. *nextField = '\0';
  2868. nextField++;
  2869. SuccessResponsePacket->RegistryLength = (ULONG) (nextField - startOfRegistry);
  2870. SuccessResponsePacketLength += SuccessResponsePacket->RegistryLength;
  2871. //
  2872. // The length field in the packet is set to the length of the
  2873. // packet starting at the Status field. If we put in a field
  2874. // between LENGTH and STATUS, we need to update this code.
  2875. //
  2876. SuccessResponsePacket->Length = (ULONG)((PCHAR) nextField -
  2877. (PCHAR) &SuccessResponsePacket->Status);
  2878. TempClientState.LastResponse = (PUCHAR)SuccessResponsePacket;
  2879. TempClientState.LastResponseLength = SuccessResponsePacketLength;
  2880. Error = SendUdpMessage(RequestContext, &TempClientState, FALSE, FALSE);
  2881. BinlFreeMemory(SuccessResponsePacket);
  2882. }
  2883. }
  2884. if (pInfEntry) {
  2885. NetInfDereferenceNetcardEntry( pInfEntry );
  2886. }
  2887. if (driverPath) {
  2888. BinlFreeMemory( driverPath );
  2889. }
  2890. if (setupPath) {
  2891. BinlFreeMemory( setupPath );
  2892. }
  2893. return Error;
  2894. }
  2895. DWORD
  2896. OscProcessHalRequest(
  2897. LPBINL_REQUEST_CONTEXT RequestContext,
  2898. PCLIENT_STATE clientState
  2899. )
  2900. /*++
  2901. Routine Description:
  2902. This function processes requests from clients for taking a
  2903. detected HAL name string and mapping it to a <hal>.dll name
  2904. and then copying that hal to the machine directory.
  2905. Arguments:
  2906. RequestContext - A pointer to the BinlRequestContext block for
  2907. this request.
  2908. clientState - contains client state for the remote machine
  2909. Return Value:
  2910. Windows Error.
  2911. --*/
  2912. {
  2913. HAL_REQUEST_PACKET UNALIGNED * halRequestMessage = (HAL_REQUEST_PACKET UNALIGNED *)RequestContext->ReceiveBuffer;
  2914. HAL_RESPONSE_PACKET responsePacket;
  2915. CLIENT_STATE TempClientState; // used to call UdpSendMessage
  2916. DWORD Error;
  2917. WCHAR MachinePath[MAX_PATH];
  2918. WCHAR SrcPath[MAX_PATH];
  2919. WCHAR DestPath[MAX_PATH];
  2920. WCHAR HalName[MAX_HAL_NAME_LENGTH+1];
  2921. WCHAR HalInfo[MAX_PATH];
  2922. ULONG HalNameLength;
  2923. ULONG len, index;
  2924. BOOL b;
  2925. PMACHINE_INFO pMachineInfo = NULL;
  2926. USHORT SystemArchitecture;
  2927. TraceFunc("OscProcessHalRequest( )\n");
  2928. //
  2929. // Find the length of the HAL name. To avoid overflowing past the
  2930. // end of the received message, check it ourselves.
  2931. //
  2932. HalNameLength = 0;
  2933. while (halRequestMessage->HalName[HalNameLength] != '\0') {
  2934. ++HalNameLength;
  2935. if (HalNameLength >= sizeof(HalName)/sizeof(WCHAR)) {
  2936. Error = ERROR_INVALID_DATA;
  2937. TraceFunc("OscProcessHalRequest( Exit 0 ) \n");
  2938. goto SendResponse;
  2939. }
  2940. }
  2941. ++HalNameLength; // convert the '\0' also
  2942. mbstowcs( HalName, halRequestMessage->HalName, HalNameLength );
  2943. SystemArchitecture = OscPlatformToArchitecture( clientState );
  2944. //
  2945. // Retrieve information from the DS
  2946. //
  2947. Error = GetBootParameters( halRequestMessage->Guid,
  2948. &pMachineInfo,
  2949. MI_NAME | MI_SETUPPATH | MI_HOSTNAME,
  2950. SystemArchitecture,
  2951. FALSE );
  2952. if (Error != ERROR_SUCCESS) {
  2953. TraceFunc("OscProcessHalRequest( Exit 1 ) \n");
  2954. goto SendResponse;
  2955. }
  2956. //
  2957. // Find the HAL
  2958. //
  2959. //
  2960. // Resulting string should be something like:
  2961. // "\\ADAMBA4\REMINST\Setup\English\Images\NTWKS5.0\i386\txtsetup.sif"
  2962. if ( _snwprintf( SrcPath,
  2963. sizeof(SrcPath) / sizeof(SrcPath[0]),
  2964. L"%ws\\txtsetup.sif",
  2965. pMachineInfo->SetupPath
  2966. ) == -1 ) {
  2967. Error = ERROR_BAD_PATHNAME;
  2968. goto SendResponse;
  2969. }
  2970. len = GetPrivateProfileString(L"hal",
  2971. HalName,
  2972. L"",
  2973. HalInfo,
  2974. sizeof(HalInfo)/sizeof(HalInfo[0]),
  2975. SrcPath
  2976. );
  2977. if (len == 0) {
  2978. TraceFunc("OscProcessHalRequest( Exit 3 ) \n");
  2979. goto SendResponse;
  2980. }
  2981. //
  2982. // Parse the response which should be in the form:
  2983. // "newhal.dll,2,hal.dll"
  2984. //
  2985. index = 0;
  2986. while ( HalInfo[index] )
  2987. {
  2988. if (HalInfo[index] == L' ' || HalInfo[index] == L',' )
  2989. break;
  2990. index++;
  2991. }
  2992. HalInfo[index] = L'\0';
  2993. if (HalInfo[0] == L'\0' ) {
  2994. Error = ERROR_BINL_HAL_NOT_FOUND;
  2995. goto SendResponse;
  2996. }
  2997. //
  2998. // Copy the HAL to the machine directory
  2999. //
  3000. if ( _snwprintf( SrcPath,
  3001. sizeof(SrcPath) / sizeof(SrcPath[0]),
  3002. L"%ws\\%ws",
  3003. pMachineInfo->SetupPath,
  3004. HalInfo
  3005. ) == -1 ) {
  3006. Error = ERROR_BAD_PATHNAME;
  3007. goto SendResponse;
  3008. }
  3009. if ( _snwprintf( DestPath,
  3010. sizeof(DestPath) / sizeof(DestPath[0]),
  3011. L"%ws\\winnt\\system32\\hal.dll",
  3012. MachinePath
  3013. ) == -1 ) {
  3014. Error = ERROR_BAD_PATHNAME;
  3015. goto SendResponse;
  3016. }
  3017. BinlPrintDbg((DEBUG_OSC, "Copying %ws to %ws...\n", SrcPath, DestPath));
  3018. b = CopyFile( SrcPath, DestPath, FALSE );
  3019. if (!b) {
  3020. Error = ERROR_BINL_HAL_NOT_FOUND;
  3021. TraceFunc("OscProcessHalRequest( Exit 4 ) \n");
  3022. goto SendResponse;
  3023. }
  3024. //
  3025. // Find which kernel to copy
  3026. //
  3027. index = wcslen(HalName);
  3028. while (index > 0) {
  3029. index--;
  3030. if (HalName[index] == L'_') {
  3031. index++;
  3032. break;
  3033. }
  3034. }
  3035. if ((index == 0) || (index == wcslen(HalName))) {
  3036. Error = ERROR_SERVER_KERNEL_NOT_FOUND;
  3037. goto SendResponse;
  3038. }
  3039. //
  3040. // Copy that too
  3041. //
  3042. if ((HalName[index] == L'u') ||
  3043. (HalName[index] == L'U')) {
  3044. if ( _snwprintf( SrcPath,
  3045. sizeof(SrcPath) / sizeof(SrcPath[0]),
  3046. L"%ws\\ntoskrnl.exe",
  3047. pMachineInfo->SetupPath
  3048. ) == -1 ) {
  3049. Error = ERROR_BAD_PATHNAME;
  3050. goto SendResponse;
  3051. }
  3052. } else {
  3053. if ( _snwprintf( SrcPath,
  3054. sizeof(SrcPath) / sizeof(SrcPath[0]),
  3055. L"%ws\\ntkrnlmp.exe",
  3056. pMachineInfo->SetupPath
  3057. ) == -1 ) {
  3058. Error = ERROR_BAD_PATHNAME;
  3059. goto SendResponse;
  3060. }
  3061. }
  3062. if ( _snwprintf( DestPath,
  3063. sizeof(DestPath) / sizeof(DestPath[0]),
  3064. L"%s\\winnt\\system32\\ntoskrnl.exe",
  3065. MachinePath
  3066. ) == -1 ) {
  3067. Error = ERROR_BAD_PATHNAME;
  3068. goto SendResponse;
  3069. }
  3070. BinlPrintDbg((DEBUG_OSC, "Copying %ws to %ws...\n", SrcPath, DestPath));
  3071. b = CopyFile( SrcPath, DestPath, FALSE );
  3072. if (!b) {
  3073. Error = ERROR_SERVER_KERNEL_NOT_FOUND;
  3074. TraceFunc("OscProcessHalRequest( Exit 5 ) \n");
  3075. goto SendResponse;
  3076. }
  3077. Error = ERROR_SUCCESS;
  3078. TraceFunc("OscProcessHalRequest( SUCCESS ) \n");
  3079. SendResponse:
  3080. if ( pMachineInfo ) {
  3081. BinlDoneWithCacheEntry( pMachineInfo, FALSE );
  3082. }
  3083. memcpy(responsePacket.Signature, HalResponseSignature, 4);
  3084. responsePacket.Length = sizeof(ULONG);
  3085. responsePacket.Status = (Error == ERROR_SUCCESS) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  3086. TempClientState.LastResponse = (PUCHAR)&responsePacket;
  3087. TempClientState.LastResponseLength = sizeof(responsePacket);
  3088. Error = SendUdpMessage(RequestContext, &TempClientState, FALSE, FALSE);
  3089. return Error;
  3090. }
  3091. //
  3092. // Process WINNT.SIF file for the client setup
  3093. //
  3094. DWORD
  3095. OscProcessSifFile(
  3096. PCLIENT_STATE clientState,
  3097. LPWSTR TemplateFile,
  3098. LPWSTR WinntSifPath )
  3099. {
  3100. DWORD dwErr = ERROR_SUCCESS;
  3101. DWORD len;
  3102. HANDLE hFile = INVALID_HANDLE_VALUE;
  3103. SECURITY_ATTRIBUTES SecurityAttributes;
  3104. EXPLICIT_ACCESS ExplicitAccessList[2];
  3105. PACL pAcl;
  3106. PSID pSid;
  3107. PWCHAR pszUserName;
  3108. PWCHAR pszDomainName;
  3109. WCHAR UniqueUdbPath[ MAX_PATH ]; // ie "D:\RemoteInstall\Setup\English\Images\NT50.WKS\i386\Templates\unique.udb"
  3110. SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_NT_AUTHORITY;
  3111. PSECURITY_DESCRIPTOR pSd;
  3112. TraceFunc("OscProcessSifFile( )\n");
  3113. //
  3114. // Impersonate while opening the file, in case the administrator messed
  3115. // up and didn't give local system permission.
  3116. //
  3117. dwErr = OscImpersonate(clientState);
  3118. if (dwErr == ERROR_SUCCESS) {
  3119. LPWSTR uniqueUdbId = OscFindVariableW( clientState, "UNIQUEUDBID" );
  3120. if (uniqueUdbId[0] != L'\0') {
  3121. //
  3122. // See if a unique.udb file name was specified in the template file.
  3123. // The default name is "unique.udb".
  3124. //
  3125. len = GetPrivateProfileStringW(OSCHOOSER_SIF_SECTIONW,
  3126. L"UniqueUdbFile",
  3127. L"unique.udb", // default
  3128. UniqueUdbPath,
  3129. sizeof(UniqueUdbPath)/sizeof(UniqueUdbPath[0]),
  3130. TemplateFile
  3131. );
  3132. if (len == 0) {
  3133. UniqueUdbPath[0] = L'\0'; // means not to process it
  3134. } else {
  3135. //
  3136. // Prepend the path to our template file to UniqueUdbPath.
  3137. //
  3138. PWCHAR EndOfTemplatePath = wcsrchr(TemplateFile, L'\\');
  3139. if (EndOfTemplatePath != NULL) {
  3140. DWORD PathLength = (DWORD)(EndOfTemplatePath - TemplateFile + 1);
  3141. DWORD FileNameLength = wcslen(UniqueUdbPath) + 1;
  3142. if (PathLength + FileNameLength <= MAX_PATH) {
  3143. memmove(UniqueUdbPath + PathLength, UniqueUdbPath, FileNameLength * sizeof(WCHAR));
  3144. memmove(UniqueUdbPath, TemplateFile, PathLength * sizeof(WCHAR));
  3145. }
  3146. }
  3147. }
  3148. }
  3149. //
  3150. // Open the template file
  3151. //
  3152. hFile = CreateFile( TemplateFile,
  3153. GENERIC_READ,
  3154. FILE_SHARE_READ,
  3155. NULL, // security attribs
  3156. OPEN_EXISTING,
  3157. FILE_ATTRIBUTE_NORMAL, // maybe FILE_ATTRIBUTE_HIDDEN(?)
  3158. NULL ); // template
  3159. OscRevert(clientState);
  3160. if ( hFile != INVALID_HANDLE_VALUE )
  3161. {
  3162. DWORD dwFileSize = GetFileSize( hFile, NULL );
  3163. if ( dwFileSize != -1 )
  3164. {
  3165. LPSTR pBuffer = BinlAllocateMemory( dwFileSize + 1); // SIF file buffer
  3166. if ( pBuffer )
  3167. {
  3168. DWORD dw;
  3169. //
  3170. // Read the file in
  3171. //
  3172. ReadFile( hFile, pBuffer, dwFileSize, &dw, NULL );
  3173. CloseHandle( hFile );
  3174. pBuffer[ dwFileSize ] = '\0'; // terminate
  3175. //
  3176. // Process the unique.udb overlay. We change the
  3177. // in-memory version of the file in pBuffer. NOTE
  3178. // we do this before calling SearchAndReplace in
  3179. // case unique.udb has any variables in it, or
  3180. // has a hard-coded value for something that it
  3181. // normally a variable in the file.
  3182. //
  3183. if ((uniqueUdbId[0] != L'\0') &&
  3184. (UniqueUdbPath[0] != L'\0')) {
  3185. ProcessUniqueUdb( &pBuffer,
  3186. dwFileSize + 1,
  3187. UniqueUdbPath,
  3188. uniqueUdbId );
  3189. dwFileSize = strlen( pBuffer );
  3190. }
  3191. //
  3192. // search and replace defined macros
  3193. //
  3194. SearchAndReplace( clientState->Variables,
  3195. &pBuffer,
  3196. clientState->nVariables,
  3197. dwFileSize + 1,
  3198. 0 );
  3199. dwFileSize = strlen( pBuffer );
  3200. //
  3201. // HACK:
  3202. // If there is a line 'FullName = " "' in the SIF, get rid
  3203. // of the space in the quotes. This deals with the case
  3204. // where the template SIF had something like:
  3205. // FullName = "%USERFIRSTNAME% %USERLASTNAME%"
  3206. // and OscGetUserDetails() was unable to get the necessary
  3207. // user information from the DS. If we leave the space in
  3208. // there, setup won't prompt for the user name.
  3209. //
  3210. #define BLANK_FULL_NAME "FullName = \" \"\r\n"
  3211. {
  3212. LPSTR p = pBuffer;
  3213. while ( *p != 0 ) {
  3214. if ( StrCmpNIA( p, BLANK_FULL_NAME, strlen(BLANK_FULL_NAME) ) == 0 ) {
  3215. p = p + strlen(BLANK_FULL_NAME) - 4;
  3216. memmove( p, p+1, dwFileSize - (p - pBuffer) ); // move terminator too
  3217. dwFileSize--;
  3218. break;
  3219. }
  3220. while ( (*p != 0) && (*p != '\r') && (*p != '\n') ) {
  3221. p++;
  3222. }
  3223. while ( (*p != 0) && ((*p == '\r') || (*p == '\n')) ) {
  3224. p++;
  3225. }
  3226. }
  3227. }
  3228. //
  3229. // Setup the ACL for this file, first is to grant admins all rights.
  3230. //
  3231. if (!AllocateAndInitializeSid(&SidAuthority,
  3232. 2,
  3233. SECURITY_BUILTIN_DOMAIN_RID,
  3234. DOMAIN_ALIAS_RID_ADMINS,
  3235. 0, 0, 0, 0, 0, 0,
  3236. &pSid
  3237. )) {
  3238. OscCreateWin32SubError( clientState, GetLastError( ) );
  3239. dwErr = ERROR_BINL_FAILED_TO_CREATE_TEMP_SIF;
  3240. BinlFreeMemory(pBuffer);
  3241. return dwErr;
  3242. }
  3243. ExplicitAccessList[0].grfAccessMode = SET_ACCESS;
  3244. ExplicitAccessList[0].grfAccessPermissions = GENERIC_READ | GENERIC_WRITE | DELETE;
  3245. ExplicitAccessList[0].grfInheritance = NO_INHERITANCE;
  3246. ExplicitAccessList[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  3247. ExplicitAccessList[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  3248. ExplicitAccessList[0].Trustee.ptstrName = pSid;
  3249. //
  3250. // Now grant the user all rights.
  3251. //
  3252. pszUserName = OscFindVariableW(clientState, "USERNAME");
  3253. pszDomainName = OscFindVariableW(clientState, "USERDOMAIN");
  3254. if (pszUserName[0] == L'\0') {
  3255. dwErr = ERROR_BINL_FAILED_TO_CREATE_TEMP_SIF;
  3256. FreeSid(pSid);
  3257. BinlFreeMemory(pBuffer);
  3258. return dwErr;
  3259. }
  3260. if (pszDomainName[0] != L'\0') {
  3261. swprintf(UniqueUdbPath, L"%s\\", pszDomainName);
  3262. } else {
  3263. UniqueUdbPath[0] = L'\0';
  3264. }
  3265. wcscat(UniqueUdbPath, pszUserName);
  3266. ExplicitAccessList[1].grfAccessMode = SET_ACCESS;
  3267. ExplicitAccessList[1].grfAccessPermissions = GENERIC_READ | GENERIC_WRITE | DELETE;
  3268. ExplicitAccessList[1].grfInheritance = NO_INHERITANCE;
  3269. ExplicitAccessList[1].Trustee.TrusteeType = TRUSTEE_IS_USER;
  3270. ExplicitAccessList[1].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
  3271. ExplicitAccessList[1].Trustee.ptstrName = UniqueUdbPath;
  3272. //
  3273. // Create an ACL with these two.
  3274. //
  3275. dwErr = SetEntriesInAcl(2, ExplicitAccessList, NULL, &pAcl);
  3276. if (dwErr != ERROR_SUCCESS) {
  3277. OscCreateWin32SubError( clientState, GetLastError( ) );
  3278. dwErr = ERROR_BINL_FAILED_TO_CREATE_TEMP_SIF;
  3279. FreeSid(pSid);
  3280. BinlFreeMemory(pBuffer);
  3281. return dwErr;
  3282. }
  3283. //
  3284. // Create an SD for this ACL
  3285. //
  3286. pSd = BinlAllocateMemory(SECURITY_DESCRIPTOR_MIN_LENGTH);
  3287. if (pSd == NULL) {
  3288. dwErr = ERROR_BINL_FAILED_TO_CREATE_TEMP_SIF;
  3289. FreeSid(pSid);
  3290. BinlFreeMemory(pBuffer);
  3291. return dwErr;
  3292. }
  3293. if (!InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION) ||
  3294. !SetSecurityDescriptorDacl(pSd, TRUE, pAcl, FALSE)) {
  3295. OscCreateWin32SubError( clientState, GetLastError( ) );
  3296. dwErr = ERROR_BINL_FAILED_TO_CREATE_TEMP_SIF;
  3297. FreeSid(pSid);
  3298. BinlFreeMemory(pBuffer);
  3299. return dwErr;
  3300. }
  3301. SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  3302. SecurityAttributes.lpSecurityDescriptor = pSd;
  3303. SecurityAttributes.bInheritHandle = FALSE;
  3304. //
  3305. // Create the destination file
  3306. //
  3307. hFile = CreateFile( WinntSifPath,
  3308. GENERIC_WRITE | GENERIC_READ | DELETE,
  3309. FILE_SHARE_READ,
  3310. &SecurityAttributes,
  3311. CREATE_ALWAYS,
  3312. FILE_ATTRIBUTE_NORMAL,
  3313. NULL ); // template
  3314. BinlFreeMemory(pSd);
  3315. FreeSid(pSid);
  3316. LocalFree(pAcl);
  3317. if ( hFile != INVALID_HANDLE_VALUE )
  3318. {
  3319. //
  3320. // Write it all at once
  3321. //
  3322. if (!WriteFile( hFile, pBuffer, dwFileSize, &dw, NULL )) {
  3323. OscCreateWin32SubError( clientState, GetLastError( ) );
  3324. dwErr = ERROR_BINL_FAILED_TO_CREATE_TEMP_SIF;
  3325. }
  3326. CloseHandle( hFile );
  3327. }
  3328. else
  3329. {
  3330. OscCreateWin32SubError( clientState, GetLastError( ) );
  3331. dwErr = ERROR_BINL_FAILED_TO_CREATE_TEMP_SIF;
  3332. }
  3333. BinlFreeMemory(pBuffer);
  3334. } else {
  3335. CloseHandle( hFile );
  3336. OscCreateWin32SubError( clientState, GetLastError( ) );
  3337. dwErr = ERROR_BINL_FAILED_TO_CREATE_TEMP_SIF;
  3338. }
  3339. } else {
  3340. CloseHandle( hFile );
  3341. }
  3342. }
  3343. else
  3344. {
  3345. dwErr = GetLastError( );
  3346. }
  3347. }
  3348. else
  3349. {
  3350. OscCreateWin32SubError( clientState, GetLastError( ) );
  3351. dwErr = ERROR_BINL_FAILED_TO_CREATE_TEMP_SIF;
  3352. }
  3353. return dwErr;
  3354. }
  3355. //
  3356. // Creates the client image directory, copy the files needed to run
  3357. // launch text mode setup, munges Winnt.Sif, more...
  3358. //
  3359. DWORD
  3360. OscSetupClient(
  3361. PCLIENT_STATE clientState,
  3362. BOOLEAN ErrorDuplicateName
  3363. )
  3364. {
  3365. DWORD dwErr = ERROR_SUCCESS;
  3366. WCHAR SetupPath[ MAX_PATH ]; // ie "D:\RemoteInstall\Setup\English\Images\NT50.WKS\i386"
  3367. PWCHAR pTemplatePath; // ie "D:\RemoteInstall\Setup\English\Images\NT50.WKS\i386\Templates\RemBoot.SIF"
  3368. WCHAR WinntSifPath[ MAX_PATH ]; // ie "D:\RemoteInstall\Clients\NP00805F7F4C85$\winnt.sif"
  3369. PWCHAR pwc; // parsing pointer
  3370. WCHAR wch; // temp wide char
  3371. PWCHAR pMachineName; // Pointer to Machine Name variable value
  3372. PWCHAR pMachineOU; // Pointer to where the MAO will be created
  3373. PWCHAR pDomain; // Pointer to Domain variable name
  3374. PWCHAR pGuid; // Pointer to Guid variable name
  3375. WCHAR Path[MAX_PATH]; // general purpose path buffer
  3376. WCHAR TmpPath[MAX_PATH]; // general purpose path buffer
  3377. ULONG lenIntelliMirror; // Lenght of IntelliMirrorPath (eg "D:\RemoteInstall")
  3378. HANDLE hDir; // Directory handle
  3379. ULONG i; // general counter
  3380. BOOL b; // general purpose BOOLean.
  3381. BOOLEAN ExactMatch;
  3382. UINT uSize;
  3383. LARGE_INTEGER KernelVersion;
  3384. WCHAR VersionString[20];
  3385. PCHAR pszGuid;
  3386. UCHAR Guid[ BINL_GUID_LENGTH ];
  3387. USHORT SystemArchitecture;
  3388. PMACHINE_INFO pMachineInfo = NULL;
  3389. TraceFunc("OscSetupClient( )\n");
  3390. lenIntelliMirror = wcslen(IntelliMirrorPathW) + 1;
  3391. dwErr = OscCheckMachineDN( clientState );
  3392. if ((dwErr == ERROR_BINL_DUPLICATE_MACHINE_NAME_FOUND) && !ErrorDuplicateName) {
  3393. dwErr = ERROR_SUCCESS;
  3394. }
  3395. if (dwErr != ERROR_SUCCESS) {
  3396. BinlPrintDbg(( DEBUG_OSC_ERROR, "OscCheckMachineDN returned 0x%x\n", dwErr ));
  3397. goto e0;
  3398. }
  3399. //
  3400. // Get the machine GUID and get any overriding parameters.
  3401. //
  3402. pszGuid = OscFindVariableA( clientState, "GUID" );
  3403. if ( pszGuid[0] == '\0' ) {
  3404. BinlPrintDbg((DEBUG_OSC_ERROR, "OscSetupClient: could not find GUID" ));
  3405. OscAddVariableA( clientState, "SUBERROR", "GUID" );
  3406. dwErr = ERROR_BINL_MISSING_VARIABLE;
  3407. goto e0;
  3408. }
  3409. pGuid = OscFindVariableW( clientState, "GUID" );
  3410. if ( pGuid[0] == L'\0' ) {
  3411. OscAddVariableA( clientState, "SUBERROR", "GUID" );
  3412. dwErr = ERROR_BINL_MISSING_VARIABLE;
  3413. goto e0;
  3414. }
  3415. dwErr = OscGuidToBytes( pszGuid, Guid );
  3416. if ( dwErr != ERROR_SUCCESS ) {
  3417. BinlPrintDbg((DEBUG_OSC_ERROR, "OscSetupClient: OscGuidToBytes failed\n" ));
  3418. goto e0;
  3419. }
  3420. SystemArchitecture = OscPlatformToArchitecture(clientState);
  3421. dwErr = GetBootParameters( Guid,
  3422. &pMachineInfo,
  3423. MI_SIFFILENAME_ALLOC,
  3424. SystemArchitecture,
  3425. FALSE );
  3426. if ( dwErr == ERROR_SUCCESS ) {
  3427. //
  3428. // Set default values
  3429. //
  3430. if (pMachineInfo->dwFlags & MI_SIFFILENAME_ALLOC) {
  3431. dwErr = OscAddVariableW( clientState, "FORCESIFFILE", pMachineInfo->ForcedSifFileName );
  3432. if ( dwErr != ERROR_SUCCESS ) {
  3433. goto e0;
  3434. }
  3435. }
  3436. }
  3437. //
  3438. // Get SIF File name.
  3439. //
  3440. pTemplatePath = OscFindVariableW( clientState, "SIF" );
  3441. if ( pTemplatePath[0] == L'\0' ) {
  3442. BinlPrint(( DEBUG_OSC_ERROR, "Missing SIF variable\n" ));
  3443. OscAddVariableA( clientState, "SUBERROR", "SIF" );
  3444. dwErr = ERROR_BINL_MISSING_VARIABLE;
  3445. goto e0;
  3446. }
  3447. //
  3448. // validate the machine name. Note the extra check for a
  3449. // period that DnsValidateDnsName_W won't catch for us.
  3450. //
  3451. pMachineName = OscFindVariableW( clientState, "MACHINENAME" );
  3452. if ( pMachineName[0] == L'\0' ) {
  3453. OscAddVariableA( clientState, "SUBERROR", "MACHINENAME" );
  3454. dwErr = ERROR_BINL_MISSING_VARIABLE;
  3455. goto e0;
  3456. } else if ( DnsValidateDnsName_W( pMachineName ) != ERROR_SUCCESS ) {
  3457. dwErr = ERROR_BINL_INVALID_MACHINE_NAME;
  3458. OscAddVariableA( clientState, "SUBERROR", " " );
  3459. goto e0;
  3460. } else if ( StrStrI( pMachineName,L".")) {
  3461. dwErr = ERROR_BINL_INVALID_MACHINE_NAME;
  3462. OscAddVariableA( clientState, "SUBERROR", " " );
  3463. goto e0;
  3464. }
  3465. pMachineOU = OscFindVariableW( clientState, "MACHINEOU" );
  3466. if ( pMachineOU[0] == L'\0' ) {
  3467. OscAddVariableA( clientState, "SUBERROR", "MACHINEOU" );
  3468. dwErr = ERROR_BINL_MISSING_VARIABLE;
  3469. goto e0;
  3470. }
  3471. // Do we have a domain yet?
  3472. pDomain = OscFindVariableW( clientState, "MACHINEDOMAIN" );
  3473. if ( pDomain[0] == L'\0' ) {
  3474. OscAddVariableA( clientState, "SUBERROR", "MACHINEDOMAIN" );
  3475. dwErr = ERROR_BINL_MISSING_VARIABLE;
  3476. goto e0;
  3477. }
  3478. if (OscSifIsSysPrep(pTemplatePath)) {
  3479. DWORD SysPrepSku;
  3480. //
  3481. // Get the system path from the SIF file
  3482. //
  3483. dwErr = GetPrivateProfileStringW(OSCHOOSER_SIF_SECTIONW,
  3484. L"SysPrepSystemRoot",
  3485. L"",
  3486. TmpPath,
  3487. sizeof(TmpPath)/sizeof(TmpPath[0]),
  3488. pTemplatePath
  3489. );
  3490. if (dwErr == 0) {
  3491. dwErr = ERROR_BINL_CD_IMAGE_NOT_FOUND;
  3492. goto e0;
  3493. }
  3494. SysPrepSku = GetPrivateProfileInt(
  3495. OSCHOOSER_SIF_SECTIONW,
  3496. L"ProductType",
  3497. 0,
  3498. pTemplatePath );
  3499. //
  3500. // Get the root of the mirror directory from the template path.
  3501. //
  3502. // pTemplatePath looks like
  3503. // "D:\RemoteInstall\Setup\English\Images\NT50.Prep\i386\templates\riprep.sif",
  3504. // truncate it temporarily to
  3505. // "D:\RemoteInstall\Setup\English\Images\NT50.Prep\i386"
  3506. // by NULLing out the second-to-last '\'.
  3507. //
  3508. pwc = pTemplatePath + wcslen( pTemplatePath );
  3509. for ( i = 0; i < 2; i++ )
  3510. {
  3511. while ( pwc > pTemplatePath && *pwc != L'\\' )
  3512. pwc--;
  3513. pwc--;
  3514. }
  3515. pwc++;
  3516. wch = *pwc; // remember
  3517. *pwc = L'\0'; // terminate
  3518. //
  3519. // Now make Path be something like
  3520. // "D:\RemoteInstall\Setup\English\Images\NT50.Prep\i386\Mirror1\UserData\WINNT\system32"
  3521. // which is where the ntoskrnl.exe whose version we want is located.
  3522. //
  3523. // Make sure there is room for pTemplatePath + "\" (1 byte) +
  3524. // TmpPath + "\system32" (9 bytes) + '\0' (1 byte).
  3525. //
  3526. if (wcslen(pTemplatePath) + wcslen(TmpPath) + 11 > sizeof(Path)/sizeof(Path[0])) {
  3527. dwErr = ERROR_BAD_PATHNAME;
  3528. goto e0;
  3529. }
  3530. wcscpy(Path, pTemplatePath);
  3531. wcscat(Path, L"\\");
  3532. wcscat(Path, TmpPath);
  3533. wcscat(Path, L"\\system32");
  3534. //
  3535. // For NT 5.0, we'll bomb out if it's not an exact match.
  3536. //
  3537. if (!OscGetClosestNt(
  3538. Path,
  3539. SysPrepSku,
  3540. clientState,
  3541. SetupPath,
  3542. &ExactMatch) ||
  3543. ( ExactMatch == FALSE )) {
  3544. dwErr = ERROR_BINL_CD_IMAGE_NOT_FOUND;
  3545. goto e0;
  3546. }
  3547. //
  3548. // SetupPath comes back as a path like
  3549. // "D:\RemoteInstall\Setup\English\Images\nt5.0\i386",
  3550. // If there was an exact match, we want SYSPREPDRIVERS to just be
  3551. // "Setup\English\Images\nt5.0\i386"
  3552. // otherwise we want it to be blank.
  3553. //
  3554. if (ExactMatch) {
  3555. OscAddVariableW(clientState, "SYSPREPDRIVERS", &(SetupPath[lenIntelliMirror]));
  3556. } else {
  3557. OscAddVariableW(clientState, "SYSPREPDRIVERS", L"");
  3558. }
  3559. //
  3560. // SYSPREPPATH will be the truncated pTemplatePath, without the
  3561. // local path at the front, something like
  3562. // "Setup\English\Images\NT50.Prep\i386".
  3563. //
  3564. OscAddVariableW(clientState, "SYSPREPPATH", &pTemplatePath[lenIntelliMirror]);
  3565. //
  3566. // Now restore pTemplatePath to what it was originally.
  3567. //
  3568. *pwc = wch;
  3569. dwErr = ERROR_SUCCESS;
  3570. } else {
  3571. //
  3572. // create the setup path to the workstation installation by stripping off
  3573. // the SIF filename. We'll search backwards for the first 2nd "\".
  3574. //
  3575. // "D:\RemoteInstall\Setup\English\NetBootOs\NT50.WKS\i386"
  3576. pwc = pTemplatePath + wcslen( pTemplatePath );
  3577. for ( i = 0; i < 2; i++ )
  3578. {
  3579. while ( pwc > pTemplatePath && *pwc != L'\\' )
  3580. pwc--;
  3581. pwc--;
  3582. }
  3583. pwc++;
  3584. wch = *pwc; // remember
  3585. *pwc = L'\0'; // terminate
  3586. wcscpy( SetupPath, pTemplatePath ); // copy
  3587. *pwc = wch; // restore
  3588. }
  3589. //
  3590. // Figure out the INSTALLPATH. This is the SetupPath minus the
  3591. // "D:\RemoteInstall" and should be:
  3592. // "Setup\English\Images\NT50.WKS"
  3593. wcscpy( Path, &SetupPath[lenIntelliMirror] );
  3594. Path[ wcslen(Path) - 1
  3595. - strlen( OscFindVariableA( clientState, "MACHINETYPE" ) ) ] = '\0';
  3596. dwErr = OscAddVariableW( clientState, "INSTALLPATH", Path );
  3597. if ( dwErr != ERROR_SUCCESS ) {
  3598. goto e0;
  3599. }
  3600. //
  3601. // record the build and version of the OS we're installing.
  3602. // if it fails, just fall back to NT 5.0.
  3603. //
  3604. if(!OscGetNtVersionInfo((PULONGLONG)&KernelVersion, SetupPath, clientState )) {
  3605. KernelVersion.LowPart = MAKELONG(0,2195);
  3606. KernelVersion.HighPart = MAKELONG(0,5);
  3607. }
  3608. wsprintf(VersionString,L"%d.%d", HIWORD(KernelVersion.HighPart), LOWORD(KernelVersion.HighPart));
  3609. OscAddVariableW( clientState, "IMAGEVERSION", VersionString );
  3610. wsprintf(VersionString,L"%d", HIWORD(KernelVersion.LowPart));
  3611. OscAddVariableW( clientState, "IMAGEBUILD", VersionString );
  3612. //
  3613. // Create the default path to the image
  3614. //
  3615. if ( _snwprintf( Path,
  3616. sizeof(Path) / sizeof(Path[0]),
  3617. L"%ws\\%ws\\templates",
  3618. OscFindVariableW( clientState, "INSTALLPATH" ),
  3619. OscFindVariableW( clientState, "MACHINETYPE" )
  3620. ) == -1 ) {
  3621. dwErr = ERROR_BAD_PATHNAME;
  3622. goto e0;
  3623. }
  3624. //
  3625. // Create destination SIF file path.
  3626. //
  3627. if ( _snwprintf( WinntSifPath,
  3628. sizeof(WinntSifPath) / sizeof(WinntSifPath[0]),
  3629. L"%ws\\%ws\\%ws.sif",
  3630. IntelliMirrorPathW,
  3631. TEMP_DIRECTORY,
  3632. pGuid
  3633. ) == -1 ) {
  3634. dwErr = ERROR_BAD_PATHNAME;
  3635. goto e0;
  3636. }
  3637. //
  3638. // Make sure there is a tmp directory below \remoteinstall.
  3639. //
  3640. dwErr = OscCheckTmpDirectory();
  3641. if (dwErr != ERROR_SUCCESS) {
  3642. goto e0;
  3643. }
  3644. //
  3645. // generate a machine password that we'll use in the SIF file and when
  3646. // setting up the MAO
  3647. //
  3648. wcscpy(TmpPath, Path );
  3649. dwErr = OscSetupMachinePassword( clientState, pTemplatePath );
  3650. if (dwErr != ERROR_SUCCESS) {
  3651. goto e0;
  3652. }
  3653. //
  3654. // Copy and process the selected SIF file
  3655. //
  3656. dwErr = OscProcessSifFile( clientState, pTemplatePath, WinntSifPath );
  3657. if ( dwErr != ERROR_SUCCESS ) {
  3658. goto e0;
  3659. }
  3660. //
  3661. // Get the boot file name
  3662. //
  3663. // Make sure there is room for Path + "\startrom.com" + NULL (so
  3664. // use sizeof to include the NULL).
  3665. //
  3666. if (wcslen(Path) + sizeof("\\startrom.com") > sizeof(Path)/sizeof(Path[0])) {
  3667. dwErr = ERROR_BAD_PATHNAME;
  3668. goto e0;
  3669. }
  3670. //
  3671. // construct default path in case the LaunchFile entry isn't
  3672. // found in the SIF file.
  3673. //
  3674. switch ( SystemArchitecture ) {
  3675. case DHCP_OPTION_CLIENT_ARCHITECTURE_IA64:
  3676. wcscat( Path, L"\\setupldr.efi" );
  3677. break;
  3678. default:
  3679. wcscat( Path, L"\\startrom.com" ); // construct default path
  3680. }
  3681. GetPrivateProfileString( OSCHOOSER_SIF_SECTIONW,
  3682. L"LaunchFile",
  3683. Path, // default
  3684. Path,
  3685. MAX_PATH,
  3686. WinntSifPath );
  3687. dwErr = OscAddVariableW( clientState, "BOOTFILE", Path );
  3688. if ( dwErr != ERROR_SUCCESS ) {
  3689. goto e0;
  3690. }
  3691. //
  3692. // Get the SIF file name
  3693. //
  3694. dwErr = OscAddVariableW( clientState, "SIFFILE", &WinntSifPath[lenIntelliMirror] );
  3695. if ( dwErr != ERROR_SUCCESS ) {
  3696. goto e0;
  3697. }
  3698. e0:
  3699. if (pMachineInfo != NULL) {
  3700. BinlDoneWithCacheEntry( pMachineInfo, FALSE );
  3701. }
  3702. return dwErr;
  3703. }
  3704. //
  3705. // Undoes whatever permanent things OscSetupClient does.
  3706. //
  3707. VOID
  3708. OscUndoSetupClient(
  3709. PCLIENT_STATE clientState
  3710. )
  3711. {
  3712. WCHAR WinntSifPath[ MAX_PATH ]; // ie "D:\RemoteInstall\tmp\NP00805F7F4C85$.sif"
  3713. PWCHAR pSifFile;
  3714. DWORD dwErr;
  3715. TraceFunc("OscUndoSetupClient( )\n");
  3716. pSifFile = OscFindVariableW( clientState, "SIFFILE" );
  3717. if ( pSifFile[0] == L'\0' ) {
  3718. return;
  3719. }
  3720. //
  3721. // Create destination SIF file path.
  3722. //
  3723. if ( _snwprintf( WinntSifPath,
  3724. sizeof(WinntSifPath) / sizeof(WinntSifPath[0]),
  3725. L"%ws\\%ws",
  3726. IntelliMirrorPathW,
  3727. pSifFile
  3728. ) == -1 ) {
  3729. return;
  3730. }
  3731. //
  3732. // Impersonate so that we can get correct permissions to delete the file.
  3733. //
  3734. dwErr = OscImpersonate(clientState);
  3735. if (dwErr == ERROR_SUCCESS) {
  3736. //
  3737. // Delete the template file
  3738. //
  3739. DeleteFile( WinntSifPath );
  3740. OscRevert(clientState);
  3741. }
  3742. }
  3743. USHORT
  3744. OscPlatformToArchitecture(
  3745. PCLIENT_STATE clientState
  3746. )
  3747. /*++
  3748. Routine Description:
  3749. Translates the client architecture string value to a
  3750. DHCP_OPTION_CLIENT_ARCHITECTURE_*** flag.
  3751. Arguments:
  3752. ClientState - The client state. It's assumed that the MACHINETYPE
  3753. OSC variable has been set when you call this function. This occurs
  3754. after OSCHOICE logs on the user.
  3755. Return Value:
  3756. DHCP_OPTION_CLIENT_ARCHITECTURE_*** flag.
  3757. --*/
  3758. {
  3759. PCWSTR pArch;
  3760. pArch = OscFindVariableW( clientState, "MACHINETYPE");
  3761. if (!pArch) {
  3762. //
  3763. // if we have no architecture, just assume x86
  3764. //
  3765. return DHCP_OPTION_CLIENT_ARCHITECTURE_X86;
  3766. }
  3767. if (_wcsicmp(pArch, L"ia64") == 0) {
  3768. return DHCP_OPTION_CLIENT_ARCHITECTURE_IA64;
  3769. } else if (_wcsicmp(pArch, L"i386") == 0) {
  3770. return DHCP_OPTION_CLIENT_ARCHITECTURE_X86;
  3771. }
  3772. return DHCP_OPTION_CLIENT_ARCHITECTURE_X86;
  3773. }
  3774. DWORD
  3775. OscSetupMachinePassword(
  3776. IN PCLIENT_STATE clientState,
  3777. IN PCWSTR SifFile
  3778. )
  3779. /*++
  3780. Routine Description:
  3781. Generates and stores the machine password for later use.
  3782. Arguments:
  3783. ClientState - The client state.
  3784. SifFile - path to unattend SIF file.
  3785. Return Value:
  3786. DWORD Win32Error code indicating status of the operation.
  3787. --*/
  3788. {
  3789. WCHAR MachinePassword[LM20_PWLEN+1];
  3790. DWORD MachinePasswordLength;
  3791. PWCHAR pMachineName;
  3792. BOOL SecuredJoin;
  3793. PWCHAR pVersion;
  3794. WCHAR Answer[20];
  3795. //
  3796. // Figure out if we should be doing a secure domain join.
  3797. // In Win2K, there is no such thing, so we do the old
  3798. // style domain join with a weaker password. In all other
  3799. // cases, we use the secure domain join method.
  3800. //
  3801. pVersion = OscFindVariableW( clientState, "IMAGEVERSION" );
  3802. if (pVersion && (wcscmp(pVersion,L"5.0") == 0)) {
  3803. SecuredJoin = FALSE;
  3804. } else {
  3805. if (!GetPrivateProfileString( L"Identification",
  3806. L"DoOldStyleDomainJoin",
  3807. L"", // default
  3808. Answer,
  3809. 20,
  3810. SifFile ) ||
  3811. 0 == _wcsicmp(Answer, L"Yes" )) {
  3812. SecuredJoin = FALSE;
  3813. } else {
  3814. SecuredJoin = TRUE;
  3815. }
  3816. }
  3817. //
  3818. // Set up the password. For diskless clients it is the machine name
  3819. // in lowercase, for disked clients we generate a random one, making
  3820. // sure it has no NULLs in it.
  3821. //
  3822. //
  3823. // We have to change the password for DISKED machines, since
  3824. // they will have a random password that we can't query.
  3825. //
  3826. //
  3827. // Windows 2000 machines have to have the "well-known-password"
  3828. // Machine passwords are just the "MachineName" (without the "$")
  3829. //
  3830. if (!SecuredJoin) {
  3831. UINT i;
  3832. pMachineName = OscFindVariableW( clientState, "MACHINENAME" );
  3833. if (!pMachineName) {
  3834. return ERROR_INVALID_DATA;
  3835. }
  3836. memset( MachinePassword, 0, sizeof(MachinePassword) );
  3837. MachinePasswordLength = wcslen( pMachineName ) * sizeof(WCHAR);
  3838. if ( MachinePasswordLength > (LM20_PWLEN * sizeof(WCHAR)) ) {
  3839. MachinePasswordLength = LM20_PWLEN * sizeof(WCHAR);
  3840. }
  3841. //
  3842. // Lower-case the NT password.
  3843. //
  3844. for (i = 0; i < MachinePasswordLength / sizeof(WCHAR); i++) {
  3845. MachinePassword[i] = towlower(pMachineName[i]);
  3846. }
  3847. BinlPrintDbg(( DEBUG_OSC, "Using WKP\n" ));
  3848. } else {
  3849. PUCHAR psz = (PUCHAR) &MachinePassword[0];
  3850. UINT i;
  3851. OscGeneratePassword(MachinePassword, &MachinePasswordLength );
  3852. #if 0 && DBG
  3853. BinlPrintDbg(( DEBUG_OSC, "Generated password: " ));
  3854. for ( i = 0; i < MachinePasswordLength / sizeof(WCHAR); i++ ) {
  3855. BinlPrintDbg(( DEBUG_OSC, "x%02x ", psz[i] ));
  3856. }
  3857. BinlPrintDbg(( DEBUG_OSC, "\n" ));
  3858. #endif
  3859. }
  3860. RtlCopyMemory(clientState->MachineAccountPassword,MachinePassword, MachinePasswordLength);
  3861. clientState->MachineAccountPasswordLength = MachinePasswordLength;
  3862. //
  3863. // the password always consists of printable characters since it must be
  3864. // substituted into a text file.
  3865. //
  3866. OscAddVariableW( clientState, "MACHINEPASSWORD", clientState->MachineAccountPassword );
  3867. return(ERROR_SUCCESS);
  3868. }