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

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