Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2651 lines
70 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation
  3. Module Name:
  4. utils.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. //
  18. // When all else fails "Error screen".
  19. //
  20. CHAR ErrorScreenHeaders[] =
  21. "<OSCML>"\
  22. "<META KEY=F3 ACTION=\"REBOOT\">"
  23. "<META KEY=ENTER ACTION=\"REBOOT\">"
  24. "<TITLE> Client Installation Wizard Error "; // there is a %08x after this
  25. CHAR ErrorScreenBody[] =
  26. " </TITLE>"
  27. "<FOOTER> Press F3 to reboot</FOOTER>"
  28. "<BODY LEFT=3 RIGHT=76><BR><BR>"; // the error message is inserted here
  29. CHAR ErrorScreenTrailer[] =
  30. "An error occurred on the server. Please notify your administrator.<BR>"
  31. "%SUBERROR%<BR>"
  32. "</BODY>"
  33. "</OSCML>";
  34. void
  35. OscCreateWin32SubError(
  36. PCLIENT_STATE clientState,
  37. DWORD Error )
  38. /*++
  39. Routine Description:
  40. Create a OSC Variable SUBERROR with the actual Win32 error code that
  41. caused the BINL error.
  42. Arguments:
  43. clientState - client state to add the variable too.
  44. Error - the Win32 error that occurred.
  45. --*/
  46. {
  47. DWORD dwLen;
  48. PWCHAR ErrorResponse = NULL;
  49. PWCHAR ErrorMsg = NULL;
  50. BOOL UsedFallback = FALSE;
  51. PWCHAR pch;
  52. DWORD ErrorLength;
  53. const WCHAR UnknownErrorMsg[] = L"Unknown Error.";
  54. const WCHAR ErrorString[] = L"Error: 0x%08x - %s";
  55. TraceFunc( "OscCreateWin32SubError( )\n" );
  56. // Retrieve the error message from system resources.
  57. dwLen = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  58. FORMAT_MESSAGE_IGNORE_INSERTS |
  59. FORMAT_MESSAGE_FROM_HMODULE |
  60. FORMAT_MESSAGE_FROM_SYSTEM,
  61. NULL,
  62. Error,
  63. 0,
  64. (LPWSTR) &ErrorMsg,
  65. 0,
  66. NULL );
  67. if ( dwLen == 0 )
  68. goto Cleanup;
  69. #if DBG
  70. if ( ErrorMsg )
  71. DebugMemoryAdd( ErrorMsg, __FILE__, __LINE__, "BINL", LPTR, wcslen(ErrorMsg), "ErrorMsg" );
  72. #endif
  73. // If all else fails, just print an error code out.
  74. if ( ErrorMsg == NULL ) {
  75. UsedFallback = TRUE;
  76. ErrorMsg = (PWCHAR) &UnknownErrorMsg;
  77. dwLen = wcslen(ErrorMsg);
  78. }
  79. // The + 4 is the extra characters of the "%08x" of the generated error message.
  80. ErrorLength = dwLen + sizeof( ErrorString ) + 4;
  81. ErrorResponse = (PWCHAR) BinlAllocateMemory( ErrorLength * sizeof(WCHAR) );
  82. if ( ErrorResponse == NULL ) {
  83. goto Cleanup;
  84. }
  85. wsprintf( ErrorResponse, ErrorString, Error, ErrorMsg );
  86. // We need to go through the string and elminate any CRs or LFs that
  87. // FormatMessageA() might have introduced.
  88. pch = ErrorResponse;
  89. while ( *pch )
  90. {
  91. if ( *pch == '\r' || * pch == '\n' )
  92. *pch = 32; // change to space
  93. pch++;
  94. }
  95. OscAddVariableW( clientState, "SUBERROR", ErrorResponse );
  96. Cleanup:
  97. if ( ErrorResponse )
  98. BinlFreeMemory( ErrorResponse );
  99. if ( ErrorMsg && !UsedFallback )
  100. BinlFreeMemory( ErrorMsg );
  101. }
  102. void
  103. OscCreateLDAPSubError(
  104. PCLIENT_STATE clientState,
  105. DWORD Error )
  106. /*++
  107. Routine Description:
  108. Create a OSC Variable SUBERROR with the actual LDAP error code that
  109. caused the BINL error.
  110. Arguments:
  111. clientState - client state to add the variable too.
  112. Error - the LDAP error that occurred.
  113. --*/
  114. {
  115. DWORD dwLen;
  116. PWCHAR ErrorResponse = NULL;
  117. DWORD ErrorLength;
  118. const WCHAR LdapErrorMsg[] = L"LDAP Error: 0x%08x";
  119. TraceFunc( "OscCreateLDAPSubError( )\n" );
  120. // The + 13 is the "0x12345678 - " of the generated error message.
  121. ErrorLength = wcslen(LdapErrorMsg) + 1 + 13;
  122. ErrorResponse = (PWCHAR) BinlAllocateMemory( ErrorLength * sizeof(WCHAR) );
  123. if ( ErrorResponse == NULL ) {
  124. goto Cleanup;
  125. }
  126. wsprintf( ErrorResponse, LdapErrorMsg, Error );
  127. OscAddVariableW( clientState, "SUBERROR", ErrorResponse );
  128. Cleanup:
  129. if ( ErrorResponse )
  130. BinlFreeMemory( ErrorResponse );
  131. }
  132. //
  133. // This routine was stolen from private\ntos\rtl\sertl.c\RtlRunEncodeUnicodeString().
  134. //
  135. VOID
  136. OscGenerateSeed(
  137. UCHAR Seed[1]
  138. )
  139. /*++
  140. Routine Description:
  141. Generates a one-byte seed for use in run encoding/decoding client
  142. state variables such as passwords.
  143. Arguments:
  144. Seed - points to a single byte that holds the generated seed.
  145. Return Value:
  146. None.
  147. --*/
  148. {
  149. LARGE_INTEGER Time;
  150. PUCHAR LocalSeed;
  151. NTSTATUS Status;
  152. ULONG i;
  153. //
  154. // Use the 2nd byte of current time as the seed.
  155. // This byte seems to be sufficiently random (by observation).
  156. //
  157. Status = NtQuerySystemTime ( &Time );
  158. BinlAssert(NT_SUCCESS(Status));
  159. LocalSeed = (PUCHAR)((PVOID)&Time);
  160. i = 1;
  161. (*Seed) = LocalSeed[ i ];
  162. //
  163. // Occasionally, this byte could be zero. That would cause the
  164. // string to become un-decodable, since 0 is the magic value that
  165. // causes us to re-gen the seed. This loop makes sure that we
  166. // never end up with a zero byte (unless time is zero, as well).
  167. //
  168. while ( ((*Seed) == 0) && ( i < sizeof( Time ) ) )
  169. {
  170. (*Seed) |= LocalSeed[ i++ ] ;
  171. }
  172. if ( (*Seed) == 0 )
  173. {
  174. (*Seed) = 1;
  175. }
  176. }
  177. DWORD
  178. OscRunEncode(
  179. IN PCLIENT_STATE ClientState,
  180. IN LPSTR Data,
  181. OUT LPSTR * EncodedData
  182. )
  183. /*++
  184. Routine Description:
  185. Calls RtlRunEncodeUnicodeString for the Data, using the client
  186. state's random seed. Then convert each byte into a 2-byte
  187. value so that there are no NULLs in the result.
  188. Each byte is encoded into a 2-byte values as follows:
  189. The first byte has the low 4 bits of the byte in its low 4 bits,
  190. with 0xf in the high 4 bits
  191. The second byte has the high 4 bits of the byte in its high 4 bits,
  192. with 0xf in the low 4 bits
  193. Arguments:
  194. ClientState - the client state.
  195. Data - The data which is to be encoded.
  196. EncodedData - An allocated buffer which holds the encoded result.
  197. Return Value:
  198. The result of the operation.
  199. --*/
  200. {
  201. STRING String;
  202. ULONG i;
  203. LPSTR p;
  204. RtlInitAnsiString(&String, Data);
  205. *EncodedData = BinlAllocateMemory((String.Length * 2) + 1);
  206. if (*EncodedData == NULL) {
  207. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  208. }
  209. RtlRunEncodeUnicodeString(&ClientState->Seed, (PUNICODE_STRING)&String);
  210. for (i = 0, p = *EncodedData; i < String.Length; i++) {
  211. *(p++) = Data[i] | 0xf0;
  212. *(p++) = Data[i] | 0x0f;
  213. }
  214. *p = '\0';
  215. return ERROR_SUCCESS;
  216. }
  217. DWORD
  218. OscRunDecode(
  219. IN PCLIENT_STATE ClientState,
  220. IN LPSTR EncodedData,
  221. OUT LPSTR * Data
  222. )
  223. /*++
  224. Routine Description:
  225. Convert the encoded data (see OscRunEncode) into the real bytes,
  226. then calls RtlRunDecodeUnicodeString on that, using the client
  227. state's random seed.
  228. Arguments:
  229. ClientState - the client state.
  230. EncodedData - the encoded data from OscRunEncode.
  231. Data - An allocated buffer which holds the decoded result.
  232. Return Value:
  233. The result of the operation.
  234. --*/
  235. {
  236. STRING String;
  237. ULONG Count = strlen(EncodedData) / 2;
  238. ULONG i, j;
  239. LPSTR p;
  240. *Data = BinlAllocateMemory(Count + 1);
  241. if (*Data == NULL) {
  242. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  243. }
  244. for (i = 0, j = 0, p = *Data; i < Count; i++, j+=2) {
  245. *(p++) = (EncodedData[j] & 0x0f) | (EncodedData[j+1] & 0xf0);
  246. }
  247. *p = '\0';
  248. //
  249. // Set up the string ourselves since there may be NULLs in
  250. // the decoded data.
  251. //
  252. String.Buffer = *Data;
  253. String.Length = (USHORT)Count;
  254. String.MaximumLength = (USHORT)(Count+1);
  255. RtlRunDecodeUnicodeString(ClientState->Seed, (PUNICODE_STRING)&String);
  256. return ERROR_SUCCESS;
  257. }
  258. //
  259. // This routine was stolen from net\svcdlls\logonsrv\server\ssiauth.c.
  260. //
  261. BOOLEAN
  262. OscGenerateRandomBits(
  263. PUCHAR Buffer,
  264. ULONG BufferLen
  265. )
  266. /*++
  267. Routine Description:
  268. Generates random bits
  269. Arguments:
  270. pBuffer - Buffer to fill
  271. cbBuffer - Number of bytes in buffer
  272. Return Value:
  273. Status of the operation.
  274. --*/
  275. {
  276. BOOL Status = TRUE;
  277. HCRYPTPROV CryptProvider = 0;
  278. Status = CryptAcquireContext( &CryptProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT );
  279. if ( Status ) {
  280. Status = CryptGenRandom( CryptProvider, BufferLen, ( LPBYTE )Buffer );
  281. CryptReleaseContext( CryptProvider, 0 );
  282. } else {
  283. BinlPrintDbg((DEBUG_ERRORS, "CryptAcquireContext failed with %lu\n", GetLastError() ));
  284. }
  285. return ( Status != 0);
  286. }
  287. VOID
  288. OscGeneratePassword(
  289. OUT PWCHAR Password,
  290. OUT PULONG PasswordLength
  291. )
  292. {
  293. ULONG i;
  294. *PasswordLength = LM20_PWLEN * sizeof(WCHAR);
  295. for (i = 0; i < LM20_PWLEN; i++) {
  296. if ( Password[i] == L'\0' ) {
  297. Password[i] = 0x55;
  298. } else if ((USHORT)Password[i] < 0x20 || (USHORT)Password[i] > 0x7A) {
  299. Password[i] = Password[i] % (0x7a-0x20) + 0x20;
  300. }
  301. }
  302. Password[LM20_PWLEN] = L'\0';
  303. }
  304. //
  305. // GenerateErrorScreen( )
  306. //
  307. DWORD
  308. GenerateErrorScreen(
  309. PCHAR *OutMessage,
  310. PULONG OutMessageLength,
  311. DWORD Error,
  312. PCLIENT_STATE clientState
  313. )
  314. {
  315. DWORD Err;
  316. DWORD dwLen;
  317. PCHAR ErrorMsg;
  318. DWORD ErrorScreenLength = strlen(ErrorScreenHeaders) + strlen(ErrorScreenBody) + strlen(ErrorScreenTrailer);
  319. PCHAR pch;
  320. PCHAR RspMessage = NULL;
  321. ULONG RspMessageLength = 0;
  322. const CHAR UnknownErrorMsg[] = "Unknown Error.";
  323. TCHAR ErrorMsgFilename[ MAX_PATH ];
  324. HANDLE hfile;
  325. LPSTR Messages[5];
  326. Messages[0] = OscFindVariableA( clientState, "USERNAME" );
  327. Messages[1] = OscFindVariableA( clientState, "USERDOMAIN" );
  328. Messages[2] = OscFindVariableA( clientState, "MACHINENAME" );
  329. Messages[3] = OscFindVariableA( clientState, "SUBERROR" );
  330. Messages[4] = NULL; // paranoid
  331. if ( _snwprintf( ErrorMsgFilename,
  332. sizeof(ErrorMsgFilename) / sizeof(ErrorMsgFilename[0]),
  333. L"%ws\\OSChooser\\%ws\\%08x.OSC",
  334. IntelliMirrorPathW,
  335. OscFindVariableW( clientState, "LANGUAGE" ),
  336. Error ) != -1 ) {
  337. //
  338. // If we find the file, load it into memory.
  339. //
  340. hfile = CreateFile( ErrorMsgFilename, GENERIC_READ,
  341. FILE_SHARE_READ | FILE_SHARE_WRITE,
  342. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  343. if ( hfile != INVALID_HANDLE_VALUE )
  344. {
  345. DWORD FileSize;
  346. //
  347. // Find out how big this screen is, if bigger than 0xFFFFFFFF we won't
  348. // display it.
  349. //
  350. FileSize = GetFileSize( hfile, NULL );
  351. if ( FileSize != 0xFFFFffff )
  352. {
  353. DWORD dwRead = 0;
  354. RspMessage = BinlAllocateMemory( FileSize + 3 );
  355. if ( RspMessage == NULL )
  356. {
  357. //
  358. // Ignore error and fall thru to generate an error screen
  359. //
  360. }
  361. else
  362. {
  363. RspMessageLength = 0;
  364. RspMessage[0] = '\0';
  365. while ( dwRead != FileSize )
  366. {
  367. BOOL b;
  368. DWORD dw;
  369. b = ReadFile( hfile, &RspMessage[dwRead], FileSize - dwRead, &dw, NULL );
  370. if (!b)
  371. {
  372. PWCHAR strings[2];
  373. strings[0] = ErrorMsgFilename;
  374. strings[1] = NULL;
  375. Err = GetLastError( );
  376. BinlPrint(( DEBUG_OSC_ERROR, "Error reading screen file: Seek=%u, Size=%u, File=%ws\n",
  377. dwRead, FileSize - dwRead, ErrorMsgFilename ));
  378. BinlReportEventW( EVENT_ERROR_READING_OSC_SCREEN,
  379. EVENTLOG_ERROR_TYPE,
  380. 1,
  381. sizeof(Err),
  382. strings,
  383. &Err
  384. );
  385. break;
  386. }
  387. dwRead += dw;
  388. }
  389. RspMessageLength = dwRead;
  390. RspMessage[dwRead] = '\0'; // paranoid
  391. CloseHandle( hfile );
  392. Err = ERROR_SUCCESS;
  393. goto Cleanup;
  394. }
  395. }
  396. else
  397. {
  398. BinlPrintDbg((DEBUG_OSC_ERROR, "!!Error 0x%08x - Could not determine file size.\n", GetLastError( )));
  399. //
  400. // Ignore error and fall thru to generate an error screen
  401. //
  402. }
  403. CloseHandle( hfile );
  404. }
  405. }
  406. BinlPrintDbg((DEBUG_OSC_ERROR, "no friendly OSC error screen available.\n" ));
  407. //
  408. // See if this is a BINL error or a system error and
  409. // get the text from the error tables.
  410. //
  411. dwLen = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  412. FORMAT_MESSAGE_FROM_HMODULE |
  413. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  414. GetModuleHandle(L"BINLSVC.DLL"),
  415. Error,
  416. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  417. (LPSTR) &ErrorMsg,
  418. 0,
  419. (va_list*) &Messages );
  420. if ( dwLen == 0 )
  421. {
  422. BinlAssert( ErrorMsg == NULL );
  423. Err = GetLastError( );
  424. BinlPrintDbg((DEBUG_OSC_ERROR, "!! Error 0x%08x - no BINLSVC specific message available.\n", Err ));
  425. dwLen = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  426. FORMAT_MESSAGE_IGNORE_INSERTS |
  427. FORMAT_MESSAGE_FROM_SYSTEM,
  428. NULL,
  429. Error,
  430. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  431. (LPSTR) &ErrorMsg,
  432. 0,
  433. NULL );
  434. if ( dwLen == 0 )
  435. {
  436. BinlAssert( ErrorMsg == NULL );
  437. Err = GetLastError( );
  438. BinlPrintDbg((DEBUG_OSC_ERROR, "!! Error 0x%08x - no SYSTEM specific message available.\n", Err ));
  439. }
  440. }
  441. #if DBG
  442. if ( ErrorMsg )
  443. DebugMemoryAdd( ErrorMsg, __FILE__, __LINE__, "BINL", LPTR, lstrlenA(ErrorMsg), "ErrorMsg" );
  444. #endif
  445. //
  446. // If all else fails, just print an error code.
  447. //
  448. if ( ErrorMsg == NULL ) {
  449. BinlPrintDbg(( DEBUG_OSC_ERROR, "sending using generic error message.\n" ));
  450. ErrorMsg = (PCHAR) &UnknownErrorMsg;
  451. dwLen = strlen(ErrorMsg);
  452. }
  453. #define ERRORITEM "%s%08x%s<BR><BOLD>%s</BOLD><BR><BR>%s"
  454. //
  455. // The + 13 is the "0x12345678 - " of the generated error message.
  456. //
  457. RspMessageLength = ErrorScreenLength + strlen(ERRORITEM) + dwLen + 1 + 13;
  458. RspMessage = (PCHAR) BinlAllocateMemory( RspMessageLength );
  459. if ( RspMessage == NULL )
  460. {
  461. Err = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  462. goto Cleanup;
  463. }
  464. wsprintfA( RspMessage, ERRORITEM, ErrorScreenHeaders, Error, ErrorScreenBody, ErrorMsg, ErrorScreenTrailer );
  465. Err = ERROR_SUCCESS;
  466. Cleanup:
  467. if ( Err == ERROR_SUCCESS )
  468. {
  469. // BinlPrint(( DEBUG_OSC, "Generated Error Response:\n%s\n", RspMessage ));
  470. *OutMessage = RspMessage;
  471. *OutMessageLength = RspMessageLength;
  472. BinlReportEventA( EVENT_ERROR_SERVER_SIDE_ERROR,
  473. EVENTLOG_ERROR_TYPE,
  474. 4,
  475. sizeof(Error),
  476. Messages,
  477. &Error
  478. );
  479. }
  480. else
  481. {
  482. BinlPrintDbg(( DEBUG_OSC_ERROR, "!! Error 0x%08x - Couldn't generate error screen.\n", Err ));
  483. BinlReportEventA( EVENT_ERROR_GENERATING_SERVER_SIDE_ERROR,
  484. EVENTLOG_ERROR_TYPE,
  485. 4,
  486. sizeof(Err),
  487. Messages,
  488. &Err
  489. );
  490. *OutMessage = NULL;
  491. *OutMessageLength = 0;
  492. if ( RspMessage )
  493. {
  494. BinlFreeMemory( RspMessage );
  495. }
  496. }
  497. return Err;
  498. }
  499. //
  500. // Returns a pointer point to the next 'ch' or NULL character.
  501. //
  502. PCHAR
  503. FindNext(
  504. PCHAR Start,
  505. CHAR ch,
  506. PCHAR End
  507. )
  508. {
  509. TraceFunc("FindNext( )\n");
  510. while( Start != End && *Start && *Start !=ch )
  511. Start++;
  512. if ( Start != End && *Start ) {
  513. return Start;
  514. } else {
  515. return NULL;
  516. }
  517. }
  518. //
  519. // Finds the screen name.
  520. //
  521. PCHAR
  522. FindScreenName(
  523. PCHAR Screen
  524. )
  525. {
  526. PCHAR Name;
  527. TraceFunc("FindScreenName( )\n");
  528. Name = strstr( Screen, "NAME" );
  529. if ( Name == NULL )
  530. return NULL;
  531. Name += 5; // "Name" plus space
  532. return Name;
  533. }
  534. DWORD
  535. OscImpersonate(
  536. IN PCLIENT_STATE ClientState
  537. )
  538. /*++
  539. Routine Description:
  540. Makes the current thread impersonate the client. It is assumed
  541. that the client has already sent up a login screen. If this call
  542. succeeds, ClientState->AuthenticatedDCLdapHandle is valid.
  543. Arguments:
  544. ClientState - The client state.
  545. Return Value:
  546. Windows Error.
  547. --*/
  548. {
  549. DWORD Error = ERROR_SUCCESS;
  550. LPSTR pUserName;
  551. LPSTR pUserDomain;
  552. LPSTR pUserPassword;
  553. LPSTR pDecodedPassword = NULL;
  554. LPSTR tempptr;
  555. ULONG temp;
  556. ULONG LdapError = 0;
  557. SEC_WINNT_AUTH_IDENTITY_A authIdentity;
  558. BOOL bResult;
  559. BOOL Impersonating = FALSE;
  560. LPWSTR pCrossDsDc;
  561. TraceFunc( "OscImpersonate( ... )\n" );
  562. pCrossDsDc = OscFindVariableW( ClientState, "DCNAME" );
  563. if (*pCrossDsDc == L'\0') {
  564. //
  565. // Clean up any old client state.
  566. //
  567. if (ClientState->AuthenticatedDCLdapHandle &&
  568. ClientState->UserToken) {
  569. bResult = ImpersonateLoggedOnUser(ClientState->UserToken);
  570. if (bResult) {
  571. return STATUS_SUCCESS;
  572. }
  573. }
  574. }
  575. if (ClientState->AuthenticatedDCLdapHandle) {
  576. // Reconnecting again. Use new credentials.
  577. ldap_unbind(ClientState->AuthenticatedDCLdapHandle);
  578. ClientState->AuthenticatedDCLdapHandle = NULL;
  579. }
  580. if (ClientState->UserToken) {
  581. CloseHandle(ClientState->UserToken);
  582. ClientState->UserToken = NULL;
  583. }
  584. //
  585. // Get the login variables from the client state.
  586. //
  587. pUserName = OscFindVariableA( ClientState, "USERNAME" );
  588. pUserDomain = OscFindVariableA( ClientState, "USERDOMAIN" );
  589. pUserPassword = OscFindVariableA( ClientState, "*PASSWORD" );
  590. if (pUserName[0] == '\0') {
  591. OscAddVariableA( ClientState, "SUBERROR", "USERNAME" );
  592. Error = ERROR_BINL_MISSING_VARIABLE;
  593. goto ImpersonateFailed;
  594. }
  595. //
  596. // Decode the password.
  597. //
  598. Error = OscRunDecode(ClientState, pUserPassword, &pDecodedPassword);
  599. if (Error != ERROR_SUCCESS) {
  600. goto ImpersonateFailed;
  601. }
  602. //
  603. // if the user didn't enter a domain name, use the server's
  604. //
  605. if (pUserDomain == NULL || pUserDomain[0] == '\0') {
  606. OscAddVariableW( ClientState, "USERDOMAIN", BinlGlobalOurDomainName );
  607. pUserDomain = OscFindVariableA( ClientState, "USERDOMAIN" );
  608. }
  609. //
  610. // Do a LogonUser with the credentials, since we
  611. // need that to change the machine password (even the
  612. // authenticated LDAP handle won't do that if we don't
  613. // have 128-bit SSL setup on this machine).
  614. //
  615. bResult = LogonUserA(
  616. pUserName,
  617. pUserDomain,
  618. pDecodedPassword,
  619. LOGON32_LOGON_NETWORK_CLEARTEXT,
  620. LOGON32_PROVIDER_DEFAULT,
  621. &ClientState->UserToken);
  622. if (!bResult) {
  623. Error = GetLastError();
  624. BinlPrintDbg(( DEBUG_ERRORS, "LogonUser failed %lx\n", Error));
  625. ClientState->UserToken = NULL; // this may be set even on failure
  626. goto ImpersonateFailed;
  627. }
  628. //
  629. // if the user didn't enter a domain name, grab it out of the user token.
  630. //
  631. if (pUserDomain == NULL || pUserDomain[0] == '\0') {
  632. PTOKEN_USER userToken;
  633. DWORD tokenSize = 4096;
  634. userToken = (PTOKEN_USER) BinlAllocateMemory( tokenSize );
  635. if (userToken != NULL) {
  636. DWORD returnLength;
  637. BOOL bRC;
  638. bRC = GetTokenInformation( ClientState->UserToken,
  639. TokenUser,
  640. (LPVOID) userToken,
  641. tokenSize,
  642. &returnLength
  643. );
  644. if (bRC) {
  645. WCHAR uUser[128];
  646. DWORD cUser = 128;
  647. WCHAR uDomain[128];
  648. DWORD cDomain = 128;
  649. SID_NAME_USE peType;
  650. uDomain[0] = L'\0';
  651. uUser[0] = L'\0';
  652. bRC = LookupAccountSidW( NULL, // system name
  653. userToken->User.Sid,
  654. uUser, // user name
  655. &cUser, // user name count
  656. uDomain, // domain name
  657. &cDomain, // domain name count
  658. &peType
  659. );
  660. if (bRC && uDomain[0] != L'\0') {
  661. OscAddVariableW( ClientState, "USERDOMAIN", &uDomain[0] );
  662. }
  663. }
  664. BinlFreeMemory( userToken );
  665. }
  666. }
  667. //
  668. // Now impersonate the user.
  669. //
  670. bResult = ImpersonateLoggedOnUser(ClientState->UserToken);
  671. if (!bResult) {
  672. BinlPrintDbg(( DEBUG_ERRORS,
  673. "ImpersonateLoggedOnUser failed %x\n", GetLastError()));
  674. Error = GetLastError();
  675. goto ImpersonateFailed;
  676. }
  677. Impersonating = TRUE;
  678. //
  679. // Create authenticated DC connection for use in machine object creation
  680. // or modification.
  681. //
  682. BinlPrintDbg(( DEBUG_OSC,
  683. "ldap_init %S or %S\n", pCrossDsDc, BinlGlobalDefaultDS ));
  684. ClientState->AuthenticatedDCLdapHandle = ldap_init(
  685. (*pCrossDsDc != L'\0')
  686. ? pCrossDsDc
  687. : BinlGlobalDefaultDS,
  688. LDAP_PORT);
  689. BinlPrintDbg(( DEBUG_OSC,
  690. "ldap_init handle %x\n", ClientState->AuthenticatedDCLdapHandle ));
  691. temp = DS_DIRECTORY_SERVICE_REQUIRED | DS_IP_REQUIRED;
  692. ldap_set_option(ClientState->AuthenticatedDCLdapHandle, LDAP_OPT_GETDSNAME_FLAGS, &temp );
  693. temp = LDAP_VERSION3;
  694. ldap_set_option(ClientState->AuthenticatedDCLdapHandle, LDAP_OPT_VERSION, &temp );
  695. //
  696. // Tell LDAP to keep connections referenced after searches.
  697. //
  698. temp = (ULONG)((ULONG_PTR)LDAP_OPT_ON);
  699. ldap_set_option(ClientState->AuthenticatedDCLdapHandle, LDAP_OPT_REF_DEREF_CONN_PER_MSG, &temp);
  700. LdapError = ldap_connect(ClientState->AuthenticatedDCLdapHandle,0);
  701. if (LdapError != LDAP_SUCCESS) {
  702. BinlPrintDbg(( DEBUG_ERRORS,
  703. "this ldap_connect() failed %x\n", LdapError));
  704. goto ImpersonateFailed;
  705. }
  706. //
  707. // LDAP_AUTH_NEGOTIATE tells it to use the credentials of the user
  708. // we are impersonating.
  709. //
  710. LdapError = ldap_bind_sA(ClientState->AuthenticatedDCLdapHandle,
  711. NULL,
  712. NULL,
  713. LDAP_AUTH_NEGOTIATE);
  714. if (LdapError != LDAP_SUCCESS) {
  715. BinlPrintDbg(( DEBUG_ERRORS,
  716. "ldap_bind_s() failed %x\n", LdapError));
  717. goto ImpersonateFailed;
  718. }
  719. ImpersonateFailed:
  720. //
  721. // If we decoded the password, then erase and free it.
  722. //
  723. if (pDecodedPassword != NULL) {
  724. RtlZeroMemory(pDecodedPassword, strlen(pDecodedPassword));
  725. BinlFreeMemory(pDecodedPassword);
  726. }
  727. if (LdapError != LDAP_SUCCESS) {
  728. Error = LdapMapErrorToWin32(LdapError);
  729. }
  730. if (Error) {
  731. PWCHAR strings[3];
  732. strings[0] = OscFindVariableW( ClientState, "USERNAME" );
  733. strings[1] = OscFindVariableW( ClientState, "USERDOMAIN" );
  734. strings[2] = NULL;
  735. BinlReportEventW( ERROR_BINL_ERR_USER_LOGIN_FAILED,
  736. EVENTLOG_WARNING_TYPE,
  737. 2,
  738. sizeof(ULONG),
  739. strings,
  740. &Error
  741. );
  742. if (ClientState->AuthenticatedDCLdapHandle) {
  743. ldap_unbind(ClientState->AuthenticatedDCLdapHandle);
  744. ClientState->AuthenticatedDCLdapHandle = NULL;
  745. }
  746. if (ClientState->UserToken) {
  747. CloseHandle(ClientState->UserToken);
  748. ClientState->UserToken = NULL;
  749. }
  750. if (Impersonating) {
  751. RevertToSelf();
  752. }
  753. }
  754. return Error;
  755. }
  756. DWORD
  757. OscRevert(
  758. IN PCLIENT_STATE ClientState
  759. )
  760. /*++
  761. Routine Description:
  762. Stops the current thread impersonating.
  763. Arguments:
  764. ClientState - The client state.
  765. Return Value:
  766. Windows Error.
  767. --*/
  768. {
  769. DWORD Error = ERROR_SUCCESS;
  770. BOOL bResult;
  771. TraceFunc( "OscRevert( ... )\n" );
  772. //
  773. // We are done impersonating for the moment.
  774. //
  775. bResult = RevertToSelf();
  776. if (!bResult) {
  777. BinlPrintDbg(( DEBUG_ERRORS,
  778. "RevertToSelf failed %x\n", GetLastError()));
  779. Error = GetLastError();
  780. }
  781. // keep the ldap handle around in case we need it again.
  782. // if (ClientState->AuthenticatedDCLdapHandle) {
  783. // ldap_unbind(ClientState->AuthenticatedDCLdapHandle);
  784. // ClientState->AuthenticatedDCLdapHandle = NULL;
  785. // }
  786. // if (ClientState->UserToken) {
  787. // CloseHandle(ClientState->UserToken);
  788. // ClientState->UserToken = NULL;
  789. // }
  790. return Error;
  791. }
  792. //
  793. // OscGuidToBytes( )
  794. //
  795. // Change CHAR Guid to bytes
  796. //
  797. DWORD
  798. OscGuidToBytes(
  799. LPSTR pszGuid,
  800. LPBYTE Guid )
  801. {
  802. PCHAR psz;
  803. ULONG len;
  804. ULONG i;
  805. TraceFunc( "OscGuidToBytes( ... )\n" );
  806. len = strlen(pszGuid);
  807. BinlAssert( len == 32 );
  808. if ( len != 32 )
  809. return ERROR_BINL_INVALID_GUID;
  810. psz = pszGuid;
  811. i = 0;
  812. while ( i * 2 < 32 )
  813. {
  814. //
  815. // Upper 4-bits
  816. //
  817. CHAR c = *psz;
  818. psz++;
  819. Guid[i] = ( c > 59 ? (toupper(c) - 55) << 4 : (c - 48) << 4);
  820. //
  821. // Lower 4-bits
  822. //
  823. c = *psz;
  824. psz++;
  825. Guid[i] += ( c > 59 ? (toupper(c) - 55) : (c - 48) );
  826. //
  827. // Next byte
  828. //
  829. i++;
  830. }
  831. return ERROR_SUCCESS;
  832. }
  833. BOOLEAN
  834. OscSifIsSysPrep(
  835. LPWSTR pSysPrepSifPath
  836. )
  837. {
  838. DWORD dwErr;
  839. WCHAR Buffer[256];
  840. UNICODE_STRING UnicodeString;
  841. TraceFunc("OscSifIsSysPrep( )\n");
  842. Buffer[0] = UNICODE_NULL;
  843. GetPrivateProfileString(OSCHOOSER_SIF_SECTIONW,
  844. L"ImageType",
  845. Buffer, // default
  846. Buffer,
  847. 256,
  848. pSysPrepSifPath
  849. );
  850. RtlInitUnicodeString(&UnicodeString, Buffer);
  851. RtlUpcaseUnicodeString(&UnicodeString, &UnicodeString, FALSE);
  852. if (_wcsicmp(L"SYSPREP", Buffer)) {
  853. return FALSE;
  854. }
  855. return TRUE;
  856. }
  857. BOOLEAN
  858. OscSifIsCmdConsA(
  859. PCHAR pSifPath
  860. )
  861. {
  862. DWORD dwErr;
  863. CHAR Buffer[256];
  864. TraceFunc("OscSifIsCmdCons( )\n");
  865. Buffer[0] = UNICODE_NULL;
  866. GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA,
  867. "ImageType",
  868. Buffer, // default
  869. Buffer,
  870. 256,
  871. pSifPath
  872. );
  873. if (_stricmp("CMDCONS", Buffer)) {
  874. return FALSE;
  875. }
  876. return TRUE;
  877. }
  878. BOOLEAN
  879. OscSifIsASR(
  880. PCHAR pSifPath
  881. )
  882. {
  883. DWORD dwErr;
  884. CHAR Buffer[256];
  885. TraceFunc("OscSifIsASR( )\n");
  886. Buffer[0] = UNICODE_NULL;
  887. GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA,
  888. "ImageType",
  889. Buffer, // default
  890. Buffer,
  891. 256,
  892. pSifPath
  893. );
  894. if (_stricmp("ASR", Buffer)) {
  895. return FALSE;
  896. }
  897. return TRUE;
  898. }
  899. DWORD
  900. OscGetSkuType(
  901. PWSTR PathToTxtSetupSif
  902. )
  903. {
  904. PWSTR SifFile;
  905. DWORD SkuType = 0;
  906. SifFile = BinlAllocateMemory(
  907. (wcslen(PathToTxtSetupSif) +
  908. 1 +
  909. wcslen(L"txtsetup.sif") +
  910. 1 ) * sizeof(WCHAR));
  911. if (!SifFile) {
  912. return 0; //default to professional on failure
  913. }
  914. wcscpy(SifFile, PathToTxtSetupSif);
  915. if (SifFile[wcslen(SifFile)-1] == L'\\') {
  916. wcscat( SifFile, L"txtsetup.sif" );
  917. } else {
  918. wcscat( SifFile, L"\\txtsetup.sif" );
  919. }
  920. SkuType = GetPrivateProfileInt(
  921. L"SetupData",
  922. L"ProductType",
  923. 0,
  924. SifFile );
  925. BinlFreeMemory( SifFile );
  926. return (SkuType);
  927. }
  928. BOOLEAN
  929. OscGetClosestNt(
  930. IN LPWSTR PathToKernel,
  931. IN DWORD SkuType,
  932. IN PCLIENT_STATE ClientState,
  933. OUT LPWSTR SetupPath,
  934. OUT PBOOLEAN ExactMatch
  935. )
  936. {
  937. DWORD Error = ERROR_SUCCESS;
  938. WIN32_FIND_DATA FindData;
  939. HANDLE hFind = INVALID_HANDLE_VALUE;
  940. BOOLEAN Impersonated = FALSE;
  941. WCHAR Path[MAX_PATH];
  942. ULONGLONG BestVersion = (ULONGLONG)0;
  943. ULONGLONG ThisVersion;
  944. ULONGLONG KernelVersion;
  945. DWORD dwPathLen;
  946. BOOLEAN ReturnValue = FALSE;
  947. TraceFunc("OscGetClosestNt( )\n");
  948. Error = ImpersonateSecurityContext(&ClientState->ServerContextHandle);
  949. if (Error != STATUS_SUCCESS) {
  950. BinlPrintDbg(( DEBUG_OSC_ERROR, "ImpersonateSecurityContext: 0x%08x\n", Error ));
  951. goto Cleanup;
  952. }
  953. Impersonated = TRUE;
  954. //
  955. // Get the version info of the kernel passed in
  956. //
  957. if (!OscGetNtVersionInfo(&KernelVersion, PathToKernel, ClientState)) {
  958. BinlPrintDbg(( DEBUG_OSC_ERROR, "OscGetNtVersionInfo failed\n" ));
  959. goto Cleanup;
  960. }
  961. //
  962. // Resulting string should be something like:
  963. // "D:\RemoteInstall\Setup\English\Images\*"
  964. if ( _snwprintf( Path,
  965. sizeof(Path) / sizeof(Path[0]),
  966. L"%ws\\Setup\\%ws\\%ws\\*",
  967. IntelliMirrorPathW,
  968. OscFindVariableW(ClientState, "LANGUAGE"),
  969. REMOTE_INSTALL_IMAGE_DIR_W
  970. ) == -1 ) {
  971. goto Cleanup;
  972. }
  973. hFind = FindFirstFile(Path, (LPVOID) &FindData);
  974. if (hFind == INVALID_HANDLE_VALUE) {
  975. goto Cleanup;
  976. }
  977. dwPathLen = wcslen(Path);
  978. //
  979. // Loop enumerating each subdirectory
  980. //
  981. do {
  982. //
  983. // Ignore directories "." and ".."
  984. //
  985. if (wcscmp(FindData.cFileName, L".") &&
  986. wcscmp(FindData.cFileName, L"..") &&
  987. (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  988. DWORD ThisSkuType;
  989. DWORD dwFileNameLen;
  990. //
  991. // Add the sub-directory to the path
  992. //
  993. dwFileNameLen = wcslen(FindData.cFileName);
  994. if (dwPathLen + dwFileNameLen + MAX_ARCHITECTURE_LENGTH + 1 > sizeof(Path)/sizeof(Path[0])) {
  995. continue; // path too long, skip it
  996. }
  997. wcscpy(&Path[dwPathLen - 1], FindData.cFileName );
  998. BinlPrintDbg(( DEBUG_OSC, "Found OS Directory: %ws\n", Path ));
  999. // Resulting string should be something like:
  1000. // "D:\RemoteInstall\Setup\English\Images\nt50.wks\i386"
  1001. wcscat(Path, L"\\");
  1002. wcscat(Path, OscFindVariableW(ClientState, "MACHINETYPE"));
  1003. ThisSkuType = OscGetSkuType( Path );
  1004. #if 0
  1005. //
  1006. // Now look for the kernel. We want to save the best version
  1007. // that is newer or equal to the kernel we are looking for,
  1008. // and older than the previous best version (note that
  1009. // BestVersion is initialized to 0 so we need to check for
  1010. // that also).
  1011. //
  1012. if (OscGetNtVersionInfo(&ThisVersion, Path, ClientState) &&
  1013. (ThisVersion >= KernelVersion) &&
  1014. (ThisSkuType == SkuType) &&
  1015. ((BestVersion == (ULONGLONG)0) || (ThisVersion < BestVersion))) {
  1016. BestVersion = ThisVersion;
  1017. wcscpy(SetupPath, Path);
  1018. }
  1019. #else
  1020. if (OscGetNtVersionInfo(&ThisVersion, Path, ClientState)) {
  1021. //
  1022. // if the sku we're looking for is ads and we've found srv,
  1023. // then lie and say it's really
  1024. // ads. This gets around a problem where txtsetup.sif didn't
  1025. // specify the SKU type correctly in 2195.
  1026. //
  1027. if (ThisSkuType == 1 && SkuType == 2) {
  1028. ThisSkuType = 2;
  1029. }
  1030. if ((ThisVersion >= KernelVersion) &&
  1031. (ThisSkuType == SkuType) &&
  1032. ((BestVersion == (ULONGLONG)0) || (ThisVersion < BestVersion))) {
  1033. BestVersion = ThisVersion;
  1034. wcscpy(SetupPath, Path);
  1035. }
  1036. }
  1037. #endif
  1038. }
  1039. } while (FindNextFile(hFind, (LPVOID) &FindData));
  1040. if (BestVersion != 0) {
  1041. ReturnValue = TRUE;
  1042. *ExactMatch = (BOOLEAN)(BestVersion == KernelVersion);
  1043. } else {
  1044. ReturnValue = FALSE;
  1045. }
  1046. Cleanup:
  1047. if (hFind != INVALID_HANDLE_VALUE) {
  1048. FindClose(hFind);
  1049. }
  1050. if (Impersonated) {
  1051. Error = RevertSecurityContext(&ClientState->ServerContextHandle);
  1052. if (Error != STATUS_SUCCESS) {
  1053. BinlPrintDbg(( DEBUG_OSC_ERROR, "RevertSecurityContext: 0x%08x\n", Error ));
  1054. return FALSE;
  1055. }
  1056. }
  1057. return ReturnValue;
  1058. }
  1059. BOOLEAN
  1060. OscGetNtVersionInfo(
  1061. PULONGLONG Version,
  1062. PWCHAR SearchDir,
  1063. PCLIENT_STATE ClientState
  1064. )
  1065. {
  1066. DWORD Error = ERROR_SUCCESS;
  1067. DWORD FileVersionInfoSize;
  1068. DWORD VersionHandle;
  1069. ULARGE_INTEGER TmpVersion;
  1070. PVOID VersionInfo;
  1071. VS_FIXEDFILEINFO * FixedFileInfo;
  1072. UINT FixedFileInfoLength;
  1073. WCHAR Path[MAX_PATH];
  1074. BOOLEAN fResult = FALSE;
  1075. TraceFunc("OscGetNtVersionInfo( )\n");
  1076. if (!SearchDir) {
  1077. goto e0;
  1078. }
  1079. // Resulting string should be something like:
  1080. // "D:\RemoteInstall\Setup\English\Images\nt50.wks\i386\ntoskrnl.exe"
  1081. if (wcslen(SearchDir) + sizeof("\\ntoskrnl.exe") + 1> sizeof(Path)/sizeof(Path[0])) {
  1082. goto e0; // path too long, skip it
  1083. }
  1084. wcscpy(Path, SearchDir);
  1085. wcscat(Path, L"\\ntoskrnl.exe");
  1086. BinlPrintDbg((DEBUG_OSC, "Checking version: %ws\n", Path));
  1087. FileVersionInfoSize = GetFileVersionInfoSize(Path, &VersionHandle);
  1088. if (FileVersionInfoSize == 0)
  1089. goto e0;
  1090. VersionInfo = BinlAllocateMemory(FileVersionInfoSize);
  1091. if (VersionInfo == NULL)
  1092. goto e0;
  1093. if (!GetFileVersionInfo(
  1094. Path,
  1095. VersionHandle,
  1096. FileVersionInfoSize,
  1097. VersionInfo))
  1098. goto e1;
  1099. if (!VerQueryValue(
  1100. VersionInfo,
  1101. L"\\",
  1102. &FixedFileInfo,
  1103. &FixedFileInfoLength))
  1104. goto e1;
  1105. TmpVersion.HighPart = FixedFileInfo->dwFileVersionMS;
  1106. TmpVersion.LowPart = FixedFileInfo->dwFileVersionLS;
  1107. *Version = TmpVersion.QuadPart;
  1108. fResult = TRUE;
  1109. e1:
  1110. BinlFreeMemory(VersionInfo);
  1111. e0:
  1112. return fResult;
  1113. }
  1114. //
  1115. // Send a message on our socket. If the message is too long, then it
  1116. // splits it into fragments of MAXIMUM_FRAGMENT_LENGTH bytes.
  1117. //
  1118. #define MAXIMUM_FRAGMENT_LENGTH 1400
  1119. DWORD
  1120. SendUdpMessage(
  1121. LPBINL_REQUEST_CONTEXT RequestContext,
  1122. PCLIENT_STATE clientState,
  1123. BOOL bFragment,
  1124. BOOL bResend
  1125. )
  1126. {
  1127. DWORD error;
  1128. FRAGMENT_PACKET FragmentHeader;
  1129. USHORT FragmentNumber;
  1130. USHORT FragmentTotal;
  1131. ULONG MessageLengthWithoutHeader;
  1132. ULONG BytesSent;
  1133. ULONG BytesThisSend;
  1134. UCHAR TempMessage[1500];
  1135. FRAGMENT_PACKET UNALIGNED * SendFragmentPacket =
  1136. (FRAGMENT_PACKET UNALIGNED *)TempMessage;
  1137. TraceFunc("SendUdpMessage( )\n");
  1138. //
  1139. // The message starts with a signature, a length, a sequence number (all
  1140. // four bytes), then two ushorts for fragment count and total. If
  1141. // we have to split it we preserve this header in each packet, with
  1142. // fragment count modified for each one.
  1143. //
  1144. MessageLengthWithoutHeader =
  1145. clientState->LastResponseLength - FRAGMENT_PACKET_DATA_OFFSET;
  1146. if (!bFragment ||
  1147. ((FragmentTotal = (USHORT)((MessageLengthWithoutHeader + MAXIMUM_FRAGMENT_LENGTH - 1) / MAXIMUM_FRAGMENT_LENGTH)) <= 1))
  1148. {
  1149. #ifdef _TRACE_FUNC_
  1150. SendFragmentPacket = (FRAGMENT_PACKET UNALIGNED *)clientState->LastResponse;
  1151. TraceFunc("Sending packet with ");
  1152. BinlPrintDbg(( DEBUG_OSC, " SequenceNumber = %u )\n", SendFragmentPacket->SequenceNumber ));
  1153. #endif
  1154. error = sendto(
  1155. RequestContext->ActiveEndpoint->Socket,
  1156. clientState->LastResponse,
  1157. clientState->LastResponseLength,
  1158. 0,
  1159. &RequestContext->SourceName,
  1160. RequestContext->SourceNameLength
  1161. );
  1162. } else {
  1163. FragmentHeader = *((FRAGMENT_PACKET UNALIGNED *)clientState->LastResponse); // struct copy -- save the header
  1164. BytesSent = 0;
  1165. for (FragmentNumber = 0; FragmentNumber < FragmentTotal; FragmentNumber++) {
  1166. if (FragmentNumber == (FragmentTotal - 1)) {
  1167. BytesThisSend = MessageLengthWithoutHeader - BytesSent;
  1168. } else {
  1169. BytesThisSend = MAXIMUM_FRAGMENT_LENGTH;
  1170. }
  1171. memcpy(
  1172. TempMessage + FRAGMENT_PACKET_DATA_OFFSET,
  1173. clientState->LastResponse + FRAGMENT_PACKET_DATA_OFFSET + (FragmentNumber * MAXIMUM_FRAGMENT_LENGTH),
  1174. BytesThisSend);
  1175. memcpy(SendFragmentPacket, &FragmentHeader, FRAGMENT_PACKET_DATA_OFFSET);
  1176. SendFragmentPacket->Length = BytesThisSend + FRAGMENT_PACKET_EMPTY_LENGTH;
  1177. SendFragmentPacket->FragmentNumber = FragmentNumber + 1;
  1178. SendFragmentPacket->FragmentTotal = FragmentTotal;
  1179. #ifdef TEST_FAILURE
  1180. if (FailFirstFragment) {
  1181. FailFirstFragment = FALSE;
  1182. BinlPrintDbg((DEBUG_OSC, "NOT sending first fragment, %ld bytes\n", BytesThisSend + FRAGMENT_PACKET_DATA_OFFSET));
  1183. error = ERROR_SUCCESS;
  1184. } else
  1185. #endif
  1186. //
  1187. // On resends, wait between fragments in case the resend is
  1188. // because the card can't handle quick bursts of packets.
  1189. //
  1190. if (bResend && (FragmentNumber != 0)) {
  1191. Sleep(10); // wait 10 milliseconds
  1192. }
  1193. error = sendto(
  1194. RequestContext->ActiveEndpoint->Socket,
  1195. TempMessage,
  1196. BytesThisSend + FRAGMENT_PACKET_DATA_OFFSET,
  1197. 0,
  1198. &RequestContext->SourceName,
  1199. RequestContext->SourceNameLength
  1200. );
  1201. if (error == SOCKET_ERROR) {
  1202. break;
  1203. }
  1204. BytesSent += BytesThisSend;
  1205. }
  1206. }
  1207. if ( error == SOCKET_ERROR ) {
  1208. error = WSAGetLastError();
  1209. BinlPrintDbg(( DEBUG_OSC_ERROR, "Sendto() failed, error = %ld\n", error ));
  1210. } else {
  1211. error = ERROR_SUCCESS;
  1212. }
  1213. return( error );
  1214. }
  1215. //
  1216. // Verifies the packets signature is authentic
  1217. //
  1218. DWORD
  1219. OscVerifySignature(
  1220. PCLIENT_STATE clientState,
  1221. SIGNED_PACKET UNALIGNED * signedMessage
  1222. )
  1223. {
  1224. SECURITY_STATUS SecStatus;
  1225. SecBuffer SigBuffers[2];
  1226. ULONG MessageLength, SignLength;
  1227. SecBufferDesc SignMessage;
  1228. TraceFunc("OscVerifySignature( )\n");
  1229. MessageLength = signedMessage->Length;
  1230. SignLength = signedMessage->SignLength;
  1231. //
  1232. // Verify the signature
  1233. //
  1234. SigBuffers[0].pvBuffer = signedMessage->Data;
  1235. SigBuffers[0].cbBuffer = MessageLength - SIGNED_PACKET_EMPTY_LENGTH;
  1236. SigBuffers[0].BufferType = SECBUFFER_DATA;
  1237. SigBuffers[1].pvBuffer = signedMessage->Sign;
  1238. SigBuffers[1].cbBuffer = SignLength;
  1239. SigBuffers[1].BufferType = SECBUFFER_TOKEN;
  1240. SignMessage.pBuffers = SigBuffers;
  1241. SignMessage.cBuffers = 2;
  1242. SignMessage.ulVersion = 0;
  1243. #ifndef ONLY_SIGN_MESSAGES
  1244. SecStatus = UnsealMessage(
  1245. &clientState->ServerContextHandle,
  1246. &SignMessage,
  1247. 0,
  1248. 0 );
  1249. #else
  1250. SecStatus = VerifySignature(
  1251. &clientState->ServerContextHandle,
  1252. &SignMessage,
  1253. 0,
  1254. 0 );
  1255. #endif
  1256. if (SecStatus != STATUS_SUCCESS)
  1257. {
  1258. DWORD Error;
  1259. SIGNED_PACKET UNALIGNED * SendSignedMessage;
  1260. BinlPrintDbg(( DEBUG_OSC_ERROR, "Sending ERR packet from Verify/Unseal!!\n"));
  1261. clientState->LastResponseLength = SIGNED_PACKET_ERROR_LENGTH;
  1262. Error = OscVerifyLastResponseSize(clientState);
  1263. if (Error != ERROR_SUCCESS)
  1264. return SecStatus; // we can't send anything back
  1265. SendSignedMessage = (SIGNED_PACKET UNALIGNED *)(clientState->LastResponse);
  1266. memcpy(SendSignedMessage->Signature, ErrorSignedSignature, 4);
  1267. SendSignedMessage->Length = 4;
  1268. SendSignedMessage->SequenceNumber = clientState->LastSequenceNumber;
  1269. }
  1270. return SecStatus;
  1271. }
  1272. //
  1273. //
  1274. //
  1275. DWORD
  1276. OscSendSignedMessage(
  1277. LPBINL_REQUEST_CONTEXT RequestContext,
  1278. PCLIENT_STATE clientState,
  1279. PCHAR Message,
  1280. ULONG MessageLength
  1281. )
  1282. {
  1283. DWORD Error = ERROR_SUCCESS;
  1284. SIGNED_PACKET UNALIGNED * SendSignedMessage;
  1285. SecBuffer SigBuffers[2];
  1286. SecBufferDesc SignMessage;
  1287. SECURITY_STATUS SecStatus;
  1288. #ifdef _TRACE_FUNC_
  1289. TraceFunc("OscSendSignedMessage( ");
  1290. BinlPrintDbg(( DEBUG_OSC, "SequenceNumber = %u )\n", clientState->LastSequenceNumber ));
  1291. #endif
  1292. //
  1293. // Make sure we have space for the message
  1294. //
  1295. clientState->LastResponseLength = MessageLength + SIGNED_PACKET_DATA_OFFSET;
  1296. Error = OscVerifyLastResponseSize(clientState);
  1297. if (Error != ERROR_SUCCESS)
  1298. return Error;
  1299. //
  1300. // copy the message
  1301. //
  1302. SendSignedMessage = (SIGNED_PACKET UNALIGNED *) clientState->LastResponse;
  1303. memcpy(SendSignedMessage->Data, Message, MessageLength);
  1304. //
  1305. // sign the message
  1306. //
  1307. memcpy(SendSignedMessage->Signature, ResponseSignedSignature, 4);
  1308. SendSignedMessage->Length = MessageLength + SIGNED_PACKET_EMPTY_LENGTH;
  1309. SendSignedMessage->SequenceNumber = clientState->LastSequenceNumber;
  1310. SendSignedMessage->FragmentNumber = 1; // fragment count
  1311. SendSignedMessage->FragmentTotal = 1; // fragment total
  1312. SendSignedMessage->SignLength = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  1313. #if 0
  1314. //
  1315. // Send out an unsealed copy to a different port.
  1316. //
  1317. {
  1318. USHORT TmpPort;
  1319. PCHAR TmpSignature[4];
  1320. TmpPort = ((struct sockaddr_in *)&RequestContext->SourceName)->sin_port;
  1321. memcpy(TmpSignature, SendSignedMessage->Signature, 4);
  1322. ((struct sockaddr_in *)&RequestContext->SourceName)->sin_port = 0xabcd;
  1323. memcpy(SendSignedMessage->Signature, "FAKE", 4);
  1324. Error = SendUdpMessage(RequestContext, clientState, TRUE, FALSE);
  1325. ((struct sockaddr_in *)&RequestContext->SourceName)->sin_port = TmpPort;
  1326. memcpy(SendSignedMessage->Signature, TmpSignature, 4);
  1327. }
  1328. #endif
  1329. SigBuffers[0].pvBuffer = SendSignedMessage->Data;
  1330. SigBuffers[0].cbBuffer = MessageLength;
  1331. SigBuffers[0].BufferType = SECBUFFER_DATA;
  1332. SigBuffers[1].pvBuffer = SendSignedMessage->Sign;
  1333. SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  1334. SigBuffers[1].BufferType = SECBUFFER_TOKEN;
  1335. SignMessage.pBuffers = SigBuffers;
  1336. SignMessage.cBuffers = 2;
  1337. SignMessage.ulVersion = 0;
  1338. #ifndef ONLY_SIGN_MESSAGES
  1339. SecStatus = SealMessage(
  1340. &clientState->ServerContextHandle,
  1341. 0,
  1342. &SignMessage,
  1343. 0 );
  1344. #else
  1345. SecStatus = MakeSignature(
  1346. &clientState->ServerContextHandle,
  1347. 0,
  1348. &SignMessage,
  1349. 0 );
  1350. #endif
  1351. //
  1352. // Make sure the signature worked. If not, send error packet.
  1353. //
  1354. if (SecStatus != STATUS_SUCCESS)
  1355. {
  1356. BinlPrintDbg(( DEBUG_OSC_ERROR, "Sending ERR packet from Make/Seal!!\n"));
  1357. clientState->LastResponseLength = SIGNED_PACKET_ERROR_LENGTH;
  1358. Error = OscVerifyLastResponseSize(clientState);
  1359. if (Error != ERROR_SUCCESS)
  1360. return Error;
  1361. memcpy(SendSignedMessage->Signature, ErrorSignedSignature, 4);
  1362. SendSignedMessage->Length = 4;
  1363. }
  1364. else
  1365. {
  1366. BinlPrintDbg(( DEBUG_OSC, "Sending RSPS, %d bytes\n", clientState->LastResponseLength));
  1367. }
  1368. #ifdef TEST_FAILURE
  1369. if (FailFirstResponse)
  1370. {
  1371. BinlPrintDbg(( DEBUG_OSC, "NOT Sending RSP, %d bytes\n", clientState->LastResponseLength));
  1372. FailFirstResponse = FALSE;
  1373. Error = ERROR_SUCCESS;
  1374. } else
  1375. #endif
  1376. Error = SendUdpMessage(RequestContext, clientState, TRUE, FALSE);
  1377. if (Error != ERROR_SUCCESS)
  1378. {
  1379. BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not send RSP message %d\n", Error ));
  1380. }
  1381. return Error;
  1382. }
  1383. //
  1384. //
  1385. //
  1386. DWORD
  1387. OscSendUnsignedMessage(
  1388. LPBINL_REQUEST_CONTEXT RequestContext,
  1389. PCLIENT_STATE clientState,
  1390. PCHAR Message,
  1391. ULONG MessageLength
  1392. )
  1393. {
  1394. DWORD Error = ERROR_SUCCESS;
  1395. SIGNED_PACKET UNALIGNED * SendSignedMessage;
  1396. SecBuffer SigBuffers[2];
  1397. SecBufferDesc SignMessage;
  1398. SECURITY_STATUS SecStatus;
  1399. #ifdef _TRACE_FUNC_
  1400. TraceFunc("OscSendUnsignedMessage( ");
  1401. BinlPrintDbg(( DEBUG_OSC, "SequenceNumber = %u )\n", clientState->LastSequenceNumber ));
  1402. #endif
  1403. //
  1404. // Make sure we have space for the message
  1405. //
  1406. clientState->LastResponseLength = MessageLength + SIGNED_PACKET_DATA_OFFSET;
  1407. Error = OscVerifyLastResponseSize(clientState);
  1408. if (Error != ERROR_SUCCESS)
  1409. return Error;
  1410. //
  1411. // copy the message
  1412. //
  1413. SendSignedMessage = (SIGNED_PACKET UNALIGNED *) clientState->LastResponse;
  1414. memcpy(SendSignedMessage->Data, Message, MessageLength);
  1415. //
  1416. // sign the message
  1417. //
  1418. memcpy(SendSignedMessage->Signature, ResponseUnsignedSignature, 4);
  1419. SendSignedMessage->Length = MessageLength + SIGNED_PACKET_EMPTY_LENGTH;
  1420. SendSignedMessage->SequenceNumber = clientState->LastSequenceNumber;
  1421. SendSignedMessage->FragmentNumber = 1; // fragment count
  1422. SendSignedMessage->FragmentTotal = 1; // fragment total
  1423. SendSignedMessage->SignLength = 0;
  1424. Error = SendUdpMessage(RequestContext, clientState, TRUE, FALSE);
  1425. if (Error != ERROR_SUCCESS)
  1426. {
  1427. BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not send RSU message %d\n", Error ));
  1428. }
  1429. return Error;
  1430. }
  1431. DWORD
  1432. OscSendSetupMessage(
  1433. LPBINL_REQUEST_CONTEXT RequestContext,
  1434. PCLIENT_STATE clientState,
  1435. ULONG RequestType,
  1436. PCHAR Message,
  1437. ULONG MessageLength
  1438. )
  1439. {
  1440. DWORD Error = ERROR_SUCCESS;
  1441. SPUDP_PACKET UNALIGNED * SendMessage;
  1442. #ifdef _TRACE_FUNC_
  1443. TraceFunc("OscSendSetupMessage( ");
  1444. BinlPrintDbg(( DEBUG_OSC, "SequenceNumber = %u )\n", clientState->LastSequenceNumber ));
  1445. #endif
  1446. //
  1447. // Make sure we have space for the message
  1448. //
  1449. clientState->LastResponseLength = MessageLength + SPUDP_PACKET_DATA_OFFSET;
  1450. Error = OscVerifyLastResponseSize(clientState);
  1451. if (Error != ERROR_SUCCESS) {
  1452. return Error;
  1453. }
  1454. //
  1455. // copy the message
  1456. //
  1457. SendMessage = (SPUDP_PACKET UNALIGNED *) clientState->LastResponse;
  1458. memcpy(SendMessage->Data, Message, MessageLength);
  1459. //
  1460. // fill in the message stuff
  1461. //
  1462. memcpy(SendMessage->Signature, SetupResponseSignature, 4);
  1463. SendMessage->Length = MessageLength + SPUDP_PACKET_EMPTY_LENGTH;
  1464. SendMessage->Status = STATUS_SUCCESS;
  1465. SendMessage->SequenceNumber = clientState->LastSequenceNumber;
  1466. SendMessage->RequestType = RequestType;
  1467. SendMessage->FragmentNumber = 1; // fragment count
  1468. SendMessage->FragmentTotal = 1; // fragment total
  1469. Error = SendUdpMessage(RequestContext, clientState, TRUE, FALSE);
  1470. if (Error != ERROR_SUCCESS) {
  1471. BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not send SPR message %d\n", Error ));
  1472. }
  1473. return Error;
  1474. }
  1475. #ifdef SET_ACLS_ON_CLIENT_DIRS
  1476. //
  1477. //
  1478. //
  1479. DWORD
  1480. OscSetClientDirectoryPermissions(
  1481. PCLIENT_STATE clientState )
  1482. {
  1483. DWORD Err = ERROR_SUCCESS;
  1484. WCHAR DirPath[ MAX_PATH ];
  1485. WCHAR Domain[ 80 ];
  1486. DWORD dwDomainSize = 80;
  1487. PSECURITY_DESCRIPTOR pSD;
  1488. PACL pDACL;
  1489. PSID pSID;
  1490. BOOL bOwnerDefault;
  1491. DWORD dwLengthRequired;
  1492. SID_NAME_USE snu;
  1493. PWCHAR pMachineName = OscFindVariableW( clientState, "MACHINENAME" );
  1494. if ( _snwprintf ( DirPath,
  1495. sizeof(DirPath) / sizeof(DirPath[0]),
  1496. L"%ws\\REMINST\\Clients\\%ws",
  1497. OscFindVariableW( clientState, "SERVERNAME" ),
  1498. pMachineName ) == -1 ) {
  1499. Err = ERROR_BAD_PATHNAME;
  1500. goto Cleanup;
  1501. }
  1502. //
  1503. // Figure out how big the machine account's SID is
  1504. //
  1505. LookupAccountName( NULL,
  1506. pMachineName,
  1507. pSID,
  1508. &dwLengthRequired,
  1509. Domain,
  1510. &dwDomainSize,
  1511. &snu );
  1512. //
  1513. // make space
  1514. //
  1515. pSID = (PSID) BinlAllocateMemory( dwLengthRequired );
  1516. if ( pSID == NULL )
  1517. goto OutOfMemory;
  1518. //
  1519. // get the machine account's SID
  1520. //
  1521. if (!LookupAccountName( NULL, pMachineName, pSID, &dwLengthRequired, Domain, &dwDomainSize, &snu ) )
  1522. goto Error;
  1523. dwLengthRequired += sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid ( pSID );
  1524. pDACL = (PACL) BinlAllocateMemory( dwLengthRequired );
  1525. if ( pDACL == NULL )
  1526. goto OutOfMemory;
  1527. pSD = ( PSECURITY_DESCRIPTOR) BinlAllocateMemory( SECURITY_DESCRIPTOR_MIN_LENGTH + dwLengthRequired );
  1528. if ( pSD == NULL )
  1529. goto OutOfMemory;
  1530. if ( !InitializeSecurityDescriptor ( pSD, SECURITY_DESCRIPTOR_REVISION) )
  1531. goto Error;
  1532. if ( !InitializeAcl( pDACL, dwLengthRequired, ACL_REVISION ) )
  1533. goto Error;
  1534. if ( !AddAccessAllowedAce( pDACL, ACL_REVISION, FILE_ALL_ACCESS, pSID ) )
  1535. goto Error;
  1536. if ( !IsValidAcl( pDACL ) )
  1537. goto Error;
  1538. if ( !SetSecurityDescriptorDacl( pSD, TRUE, pDACL, FALSE ) )
  1539. goto Error;
  1540. if ( !SetSecurityDescriptorOwner( pSD, pSID, FALSE ) )
  1541. goto Error;
  1542. if ( ! IsValidSecurityDescriptor ( pSD ) )
  1543. goto Error;
  1544. if ( !SetFileSecurity( DirPath,
  1545. OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
  1546. pSD ) )
  1547. goto Error;
  1548. goto Cleanup;
  1549. OutOfMemory:
  1550. Err = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1551. goto Cleanup;
  1552. Error:
  1553. Err = GetLastError( );
  1554. Cleanup:
  1555. if ( pSID )
  1556. BinlFreeMemory( pSID );
  1557. if ( pSD )
  1558. BinlFreeMemory( pSD );
  1559. return Err;
  1560. }
  1561. #endif // SET_ACLS_ON_CLIENT_DIRS
  1562. #if 0
  1563. VOID
  1564. OscGetFlipServerList(
  1565. PUCHAR FlipServerList,
  1566. PULONG FlipServerListLength
  1567. )
  1568. /*++
  1569. Routine Description:
  1570. This function gets the flip server list using the GPT of the
  1571. currently impersonated user.
  1572. Arguments:
  1573. FlipServerList - The location to store the flip server list, which
  1574. is a series of 4-byte IP addresses.
  1575. FlipServerListLength - Returns the length of the flip server list
  1576. if any are stored.
  1577. Return Value:
  1578. None.
  1579. --*/
  1580. {
  1581. LPWSTR GptPath;
  1582. WCHAR NetbootPath[MAX_PATH];
  1583. WCHAR TempServerList[128];
  1584. ULONG TempServerIp[4];
  1585. LPWSTR CurDirLoc, CurDirEnd;
  1586. LPWSTR CurSrvLoc, CurSrvEnd;
  1587. PUCHAR CurFlipLoc;
  1588. ULONG FlipServerCount;
  1589. TraceFunc("OscGetFlipServerList( )\n");
  1590. TempServerList[0] = L'\0';
  1591. //
  1592. // Read the GPT path.
  1593. //
  1594. GptPath = GetGPTPath(NULL, NULL);
  1595. //
  1596. // Scan the GPT path for a netboot.ini file.
  1597. //
  1598. CurDirLoc = GptPath;
  1599. while (*CurDirLoc != L'\0') {
  1600. CurDirEnd = wcschr(CurDirLoc, L';');
  1601. if (CurDirEnd == NULL) {
  1602. wsprintf(NetbootPath, L"%wsnetboot.ini", CurDirLoc);
  1603. CurDirLoc += wcslen(CurDirLoc); // points to final '\0'
  1604. } else {
  1605. *CurDirEnd = L'\0'; // HACK since %*ws does not seem to work
  1606. wsprintf(NetbootPath, L"%wsnetboot.ini", CurDirLoc);
  1607. *CurDirEnd = L';';
  1608. CurDirLoc = CurDirEnd + 1; // move past the ';'
  1609. }
  1610. //
  1611. // Check that the file exists.
  1612. //
  1613. if (GetFileAttributes(NetbootPath) == (DWORD)-1) {
  1614. continue;
  1615. }
  1616. //
  1617. // If the file exists, assume it is the right one -- if
  1618. // it doesn't have the right section and key, don't try to
  1619. // look in the next path location.
  1620. //
  1621. GetPrivateProfileString(
  1622. L"BINL Server",
  1623. L"NewAccountServers",
  1624. L"", // default value is empty string
  1625. TempServerList,
  1626. sizeof(TempServerList),
  1627. NetbootPath
  1628. );
  1629. break;
  1630. }
  1631. //
  1632. // At this point the server list is in TempServerList, which
  1633. // may be of length 0. Parse through it for IP addresses and
  1634. // put them in FlipServerList.
  1635. //
  1636. BinlPrintDbg(( DEBUG_OSC, "TempServerList is <%ws>\n", TempServerList ));
  1637. CurSrvLoc = TempServerList;
  1638. CurFlipLoc = FlipServerList;
  1639. while (*CurSrvLoc != L'\0') {
  1640. CurSrvEnd = wcschr(CurSrvLoc, L',');
  1641. if (CurSrvEnd != NULL) {
  1642. *CurSrvEnd = L'\0';
  1643. }
  1644. swscanf(CurSrvLoc, L"%ld.%ld.%ld.%ld", &TempServerIp[0], &TempServerIp[1], &TempServerIp[2], &TempServerIp[3]);
  1645. CurFlipLoc[0] = (UCHAR)TempServerIp[0];
  1646. CurFlipLoc[1] = (UCHAR)TempServerIp[1];
  1647. CurFlipLoc[2] = (UCHAR)TempServerIp[2];
  1648. CurFlipLoc[3] = (UCHAR)TempServerIp[3];
  1649. #if 0
  1650. BinlPrintDbg(( DEBUG_OSC, "FOUND IP address %d.%d.%d.%d\n",
  1651. CurFlipLoc[0],
  1652. CurFlipLoc[1],
  1653. CurFlipLoc[2],
  1654. CurFlipLoc[3]));
  1655. #endif
  1656. CurFlipLoc += 4;
  1657. *FlipServerListLength += 4;
  1658. //
  1659. // Only allow MAX_FLIP_SERVER_COUNT servers.
  1660. //
  1661. if (*FlipServerListLength == (MAX_FLIP_SERVER_COUNT*4)) {
  1662. break;
  1663. }
  1664. if (CurSrvEnd != NULL) {
  1665. CurSrvLoc = CurSrvEnd + 1;
  1666. } else {
  1667. break;
  1668. }
  1669. }
  1670. //
  1671. // Randomize the list in FlipServerList.
  1672. //
  1673. FlipServerCount = (*FlipServerListLength) / 4;
  1674. if (FlipServerCount > 1) {
  1675. ULONG RandomSeed;
  1676. ULONG i, j;
  1677. UCHAR TempBuffer[4];
  1678. //
  1679. // For each element except the last, swap it with a random
  1680. // element.
  1681. //
  1682. RandomSeed = GetTickCount();
  1683. for (i = 0; i < FlipServerCount-1; i++) {
  1684. //
  1685. // Pick a random element j between the ith and the end.
  1686. //
  1687. j = i + (RtlRandom(&RandomSeed) % (FlipServerCount - i));
  1688. //
  1689. // Swap ith and jth element, unless i == j.
  1690. //
  1691. if (i != j) {
  1692. memcpy(TempBuffer, &FlipServerList[i*4], 4);
  1693. memcpy(&FlipServerList[i*4], &FlipServerList[j*4], 4);
  1694. memcpy(&FlipServerList[j*4], TempBuffer, 4);
  1695. }
  1696. }
  1697. }
  1698. }
  1699. #endif // FlipServer
  1700. #ifdef REMOTE_BOOT
  1701. //
  1702. // Copy any initial files specified in SIF.
  1703. //
  1704. DWORD
  1705. OscCopyTemplateFiles(
  1706. LPWSTR SourcePath,
  1707. LPWSTR ImagePath,
  1708. LPWSTR TemplateFile
  1709. )
  1710. {
  1711. #define MAX_FILES_SIZE 2048
  1712. WCHAR Files[ MAX_FILES_SIZE ];
  1713. DWORD dwErr = ERROR_SUCCESS;
  1714. LPWSTR pFilename;
  1715. WCHAR SrcFilepath[ MAX_PATH ];
  1716. WCHAR DstFilepath[ MAX_PATH ];
  1717. TraceFunc("OscCopyTemplateFiles( )\n");
  1718. dwErr = GetPrivateProfileSection( L"OSChooserFiles",
  1719. Files,
  1720. MAX_FILES_SIZE,
  1721. TemplateFile );
  1722. BinlAssert( dwErr != MAX_FILES_SIZE - 2 );
  1723. #undef MAX_FILES_SIZE
  1724. pFilename = Files;
  1725. while ( *pFilename )
  1726. {
  1727. BOOL b;
  1728. LPWSTR psz = pFilename;
  1729. while ( *psz && *psz !=L',' )
  1730. psz++;
  1731. if ( *psz == L',' )
  1732. {
  1733. *psz = L'\0';
  1734. psz++;
  1735. }
  1736. else
  1737. {
  1738. psz = pFilename;
  1739. }
  1740. wsprintf( SrcFilepath, L"%ws\\%ws", SourcePath, psz );
  1741. wsprintf( DstFilepath, L"%ws\\%ws", ImagePath, pFilename );
  1742. BinlPrintDbg((DEBUG_OSC, "Copying %ws to %ws...\n", SrcFilepath, DstFilepath));
  1743. b = CopyFile( SrcFilepath, DstFilepath, TRUE );
  1744. if ( !b ) {
  1745. dwErr = GetLastError( );
  1746. goto Error;
  1747. }
  1748. // find the end of the string
  1749. while ( *psz )
  1750. psz++;
  1751. pFilename = ++psz; // skip null
  1752. }
  1753. Error:
  1754. return dwErr;
  1755. }
  1756. #endif // REMOTE_BOOT
  1757. #if DBG && defined(REMOTE_BOOT)
  1758. //
  1759. // Create MAC Address file -
  1760. // This might be turned into a DESKTOP.INI file(?). -gpease
  1761. //
  1762. DWORD
  1763. OscCreateNullFile(
  1764. LPWSTR Image,
  1765. LPWSTR MAC
  1766. )
  1767. {
  1768. DWORD dwErr = ERROR_SUCCESS;
  1769. WCHAR Path[ MAX_PATH ];
  1770. HANDLE hFile = INVALID_HANDLE_VALUE;
  1771. TraceFunc("OscCreateNullFile( )\n");
  1772. wsprintf( Path, L"%ws\\%ws", Image, MAC );
  1773. //
  1774. // Create NULL length file
  1775. //
  1776. hFile = CreateFile( Path,
  1777. GENERIC_WRITE,
  1778. FILE_SHARE_READ,
  1779. NULL, // security attribs
  1780. CREATE_ALWAYS,
  1781. FILE_ATTRIBUTE_NORMAL, // maybe FILE_ATTRIBUTE_HIDDEN
  1782. NULL ); // template
  1783. if (hFile != INVALID_HANDLE_VALUE) {
  1784. CloseHandle( hFile );
  1785. }
  1786. return dwErr;
  1787. }
  1788. #endif
  1789. DWORD
  1790. OscConstructSecret(
  1791. PCLIENT_STATE clientState,
  1792. PWCHAR UnicodePassword,
  1793. ULONG UnicodePasswordLength,
  1794. PCREATE_DATA CreateData
  1795. )
  1796. {
  1797. DWORD dwErr = ERROR_SUCCESS;
  1798. UINT i;
  1799. WCHAR DomainBuffer[64];
  1800. DWORD SidLength, DomainLength;
  1801. SID_NAME_USE NameUse;
  1802. BOOL b;
  1803. PCHAR pBootFile;
  1804. PCHAR pSifFile;
  1805. #if defined(REMOTE_BOOT)
  1806. PCHAR pNetBIOSName;
  1807. PCHAR pUserDomain;
  1808. #endif
  1809. TraceFunc( "OscConstructSecret( )\n" );
  1810. RtlZeroMemory(CreateData, sizeof(CREATE_DATA));
  1811. //
  1812. // Copy the machine data into the response packet
  1813. //
  1814. // The following fields aren't necessary unless we're supporting remote boot.
  1815. // UCHAR Sid[28];
  1816. // UCHAR Domain[32];
  1817. // UCHAR Name[32];
  1818. // UCHAR Password[32];
  1819. // ULONG UnicodePasswordLength; // in bytes
  1820. // WCHAR UnicodePassword[32];
  1821. // UCHAR Installation[32];
  1822. // UCHAR MachineType[6]; // 'i386\0' or 'Alpha\0'
  1823. //
  1824. pBootFile = OscFindVariableA( clientState, "BOOTFILE" );
  1825. if ( pBootFile[0] == L'\0' ) {
  1826. OscAddVariableA( clientState, "SUBERROR", "BOOTFILE" );
  1827. return ERROR_BINL_MISSING_VARIABLE;
  1828. }
  1829. pSifFile = OscFindVariableA( clientState, "SIFFILE" );
  1830. if ( pSifFile[0] == L'\0' ) {
  1831. OscAddVariableA( clientState, "SUBERROR", "SIFFILE" );
  1832. return ERROR_BINL_MISSING_VARIABLE;
  1833. }
  1834. memcpy( CreateData->Id, "ACCT", 4);
  1835. CreateData->VersionNumber = OSC_CREATE_DATA_VERSION;
  1836. strcpy( CreateData->NextBootfile, pBootFile );
  1837. strcpy( CreateData->SifFile, pSifFile );
  1838. #if defined(REMOTE_BOOT)
  1839. pNetBIOSName = OscFindVariableA( clientState, "NETBIOSNAME");
  1840. if ( pNetBIOSName[0] == L'\0' ) {
  1841. OscAddVariableA( clientState, "SUBERROR", "NETBIOSNAME" );
  1842. return ERROR_BINL_MISSING_VARIABLE;
  1843. }
  1844. pUserDomain = OscFindVariableA( clientState, "USERDOMAIN" );
  1845. if ( pUserDomain[0] == L'\0' ) {
  1846. OscAddVariableA( clientState, "SUBERROR", "USERDOMAIN" );
  1847. return ERROR_BINL_MISSING_VARIABLE;
  1848. }
  1849. strcpy( CreateData->Name, OscFindVariableA( clientState, pNetBIOSName ) );
  1850. CreateData->UnicodePasswordLength = UnicodePasswordLength;
  1851. memcpy( CreateData->UnicodePassword, UnicodePassword, CreateData->UnicodePasswordLength );
  1852. strcpy( CreateData->Domain, OscFindVariableA( clientState, pUserDomain ) );
  1853. //
  1854. // We send the password down in Unicode also which is
  1855. // just the machine name.
  1856. // NOTE: We probably need to worry about
  1857. // the code page of the client, for the moment just do
  1858. // the simplest conversion. We may also want to get
  1859. // the machine name/password in Unicode and only convert
  1860. // it to ANSI right here. We'll punt this for the moment,
  1861. // at least the on-the-wire format will be correct.
  1862. //
  1863. //
  1864. // This isn't used right now, we only care about the Unicode password.
  1865. //
  1866. memset( CreateData->Password, '\0', sizeof(CreateData->Password) );
  1867. //
  1868. // Get the SID from the system.
  1869. //
  1870. SidLength = sizeof(CreateData->Sid);
  1871. DomainLength = sizeof(DomainBuffer) / sizeof(WCHAR);
  1872. b = LookupAccountName(
  1873. NULL,
  1874. OscFindVariableW( clientState, "NETBIOSNAME" ),
  1875. CreateData->Sid,
  1876. &SidLength,
  1877. DomainBuffer,
  1878. &DomainLength,
  1879. &NameUse);
  1880. if (!b) {
  1881. DWORD dwErr = GetLastError( );
  1882. BinlPrintDbg(( DEBUG_OSC_ERROR, "!! Error 0x%08x - Account lookup failed.\n", dwErr ));
  1883. OscCreateWin32SubError( clientState, dwErr );
  1884. return ERROR_BINL_FAILED_TO_INITIALIZE_CLIENT;;
  1885. }
  1886. // This should be the NETBIOS domain name.
  1887. wcstombs( CreateData->Domain, DomainBuffer, DomainLength + 1 );
  1888. //
  1889. // Sanity check
  1890. //
  1891. BinlAssertMsg( CreateData->Name[0], "No machine name" );
  1892. // BinlAssertMsg( CreateData->Password[0], "No machine password" );
  1893. BinlAssertMsg( CreateData->UnicodePasswordLength, "Password length is ZERO" );
  1894. BinlAssertMsg( CreateData->UnicodePassword[0], "No UNICODE machine password" );
  1895. BinlAssertMsg( CreateData->Domain[0], "No machine domain" );
  1896. #endif
  1897. BinlAssertMsg( CreateData->NextBootfile[0], "No boot file" );
  1898. return dwErr;
  1899. }
  1900. DWORD
  1901. GetOurServerInfo (
  1902. VOID
  1903. )
  1904. //
  1905. // This routine gets several global names that we need to handle client
  1906. // requests. We store them in globals because they change very infrequently
  1907. // and they're relatively expense to retrieve.
  1908. //
  1909. {
  1910. PWCHAR fqdn = NULL;
  1911. DWORD uSize;
  1912. DWORD dnsError = ERROR_SUCCESS;
  1913. DWORD fqdnError = ERROR_SUCCESS;
  1914. DWORD netbiosServerError = ERROR_SUCCESS;
  1915. DWORD netbiosDomainError = ERROR_SUCCESS;
  1916. PWCHAR ourDNSName = NULL;
  1917. PWCHAR tmp;
  1918. PWCHAR pDomain;
  1919. WCHAR ServerName[32] = { 0 };
  1920. DWORD ServerSize = sizeof(ServerName) / sizeof(WCHAR);
  1921. ULONG Error;
  1922. // first grab the netbios name of our server
  1923. if ( !GetComputerNameEx( ComputerNameNetBIOS, ServerName, &ServerSize ) ) {
  1924. netbiosServerError = GetLastError();
  1925. BinlPrintDbg(( DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerNameEx failed.\n", netbiosServerError ));
  1926. } else {
  1927. tmp = BinlAllocateMemory( ( lstrlenW( ServerName ) + 1 ) * sizeof(WCHAR) );
  1928. if (tmp == NULL) {
  1929. netbiosServerError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1930. } else {
  1931. lstrcpyW( tmp, ServerName );
  1932. EnterCriticalSection( &gcsParameters );
  1933. if (BinlGlobalOurServerName) {
  1934. BinlFreeMemory( BinlGlobalOurServerName );
  1935. }
  1936. BinlGlobalOurServerName = tmp;
  1937. LeaveCriticalSection( &gcsParameters );
  1938. }
  1939. }
  1940. // Next grab the fully qualified domain name of our server
  1941. uSize = 0;
  1942. if ( !GetComputerObjectName( NameFullyQualifiedDN, NULL, &uSize ) ) {
  1943. fqdnError = GetLastError( );
  1944. if ( fqdnError != ERROR_MORE_DATA ) {
  1945. BinlPrint((DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerObjectName failed.\n", fqdnError ));
  1946. goto GetDNS;
  1947. }
  1948. fqdnError = ERROR_SUCCESS;
  1949. }
  1950. fqdn = BinlAllocateMemory( uSize * sizeof(WCHAR) );
  1951. if ( fqdn ) {
  1952. if ( !GetComputerObjectName( NameFullyQualifiedDN, fqdn, &uSize ) ) {
  1953. fqdnError = GetLastError( );
  1954. BinlPrint((DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerObjectName failed.\n", fqdnError ));
  1955. } else {
  1956. EnterCriticalSection( &gcsParameters );
  1957. tmp = BinlGlobalOurFQDNName;
  1958. BinlGlobalOurFQDNName = fqdn;
  1959. fqdn = tmp; // we'll free it below
  1960. // next setup the netbios domain name
  1961. pDomain = StrStrIW( BinlGlobalOurFQDNName, L"DC=" );
  1962. if ( pDomain ) {
  1963. PDS_NAME_RESULTW pResults;
  1964. BinlPrintDbg(( DEBUG_OSC, "Converting %ws to a NetBIOS domain name...\n", pDomain ));
  1965. netbiosDomainError = DsCrackNames( INVALID_HANDLE_VALUE,
  1966. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  1967. DS_FQDN_1779_NAME,
  1968. DS_CANONICAL_NAME,
  1969. 1,
  1970. &pDomain,
  1971. &pResults );
  1972. if (netbiosDomainError != ERROR_SUCCESS) {
  1973. BinlPrint(( DEBUG_ERRORS, "GetOurServerInfo error in DsCrackNames %u\n", netbiosDomainError ));
  1974. }
  1975. if ( netbiosDomainError == ERROR_SUCCESS ) {
  1976. if ( pResults->cItems == 1
  1977. && pResults->rItems[0].status == DS_NAME_NO_ERROR
  1978. && pResults->rItems[0].pName ) { // paranoid
  1979. pResults->rItems[0].pName[wcslen(pResults->rItems[0].pName)-1] = L'\0';
  1980. tmp = BinlAllocateMemory( ( lstrlenW( pResults->rItems[0].pName ) + 1 ) * sizeof(WCHAR) );
  1981. if (tmp == NULL) {
  1982. netbiosDomainError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1983. } else {
  1984. lstrcpyW( tmp, pResults->rItems[0].pName );
  1985. if (BinlGlobalOurDomainName) {
  1986. BinlFreeMemory( BinlGlobalOurDomainName );
  1987. }
  1988. BinlGlobalOurDomainName = tmp;
  1989. }
  1990. }
  1991. DsFreeNameResult( pResults );
  1992. }
  1993. }
  1994. LeaveCriticalSection( &gcsParameters );
  1995. }
  1996. } else {
  1997. fqdnError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1998. }
  1999. GetDNS:
  2000. // Retrieve the FQDNS name of the server
  2001. uSize = 0;
  2002. if ( !GetComputerNameEx( ComputerNameDnsFullyQualified, NULL, &uSize ) ) {
  2003. dnsError = GetLastError( );
  2004. if ( dnsError != ERROR_MORE_DATA ) {
  2005. BinlPrint((DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerNameEx failed.\n", dnsError ));
  2006. goto returnError;
  2007. }
  2008. dnsError = ERROR_SUCCESS;
  2009. }
  2010. ourDNSName = (PWCHAR) BinlAllocateMemory( uSize * sizeof(WCHAR) );
  2011. if ( ourDNSName ) {
  2012. if ( !GetComputerNameEx( ComputerNameDnsFullyQualified, ourDNSName, &uSize ) ) {
  2013. dnsError = GetLastError( );
  2014. BinlPrint((DEBUG_OSC_ERROR, "!! Error 0x%08x - GetComputerNameEx failed.\n", dnsError ));
  2015. } else {
  2016. EnterCriticalSection( &gcsParameters );
  2017. tmp = BinlGlobalOurDnsName;
  2018. BinlGlobalOurDnsName = ourDNSName;
  2019. LeaveCriticalSection( &gcsParameters );
  2020. ourDNSName = tmp; // we'll free it below
  2021. }
  2022. } else {
  2023. dnsError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2024. }
  2025. returnError:
  2026. if (ourDNSName) {
  2027. BinlFreeMemory( ourDNSName );
  2028. }
  2029. if (fqdn) {
  2030. BinlFreeMemory( fqdn );
  2031. }
  2032. if (fqdnError != ERROR_SUCCESS) {
  2033. Error = fqdnError;
  2034. } else if (dnsError != ERROR_SUCCESS) {
  2035. Error = dnsError;
  2036. } else if (netbiosServerError != ERROR_SUCCESS) {
  2037. Error = netbiosServerError;
  2038. } else {
  2039. Error = netbiosDomainError;
  2040. }
  2041. return Error;
  2042. }
  2043. DWORD
  2044. GetDomainNetBIOSName(
  2045. IN PCWSTR DomainNameInAnyFormat,
  2046. OUT PWSTR *NetBIOSName
  2047. )
  2048. /*++
  2049. Routine Description:
  2050. Retrieves the netbios name for a domain given an input name. The input
  2051. name may be in DNS form or netbios form, it doesn't really matter.
  2052. Arguments:
  2053. DomainNameInAnyFormat - string representing the name of the domain to query
  2054. NetBIOSName - receives string that represents the domain netbios name.
  2055. The string must be freed via BinlFreeMemory.
  2056. Return Value:
  2057. win32 error code indicating outcome.
  2058. --*/
  2059. {
  2060. PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
  2061. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC DomainInfo = NULL;
  2062. DWORD Error;
  2063. Error = DsGetDcName(
  2064. NULL,
  2065. DomainNameInAnyFormat,
  2066. NULL,
  2067. NULL,
  2068. DS_RETURN_FLAT_NAME,
  2069. &DomainControllerInfo );
  2070. if (Error != ERROR_SUCCESS) {
  2071. BinlPrintDbg((
  2072. DEBUG_ERRORS,
  2073. "DsGetDcName (%ws) failed, ec = %d.\r\n",
  2074. DomainNameInAnyFormat,
  2075. Error ));
  2076. goto exit;
  2077. }
  2078. Error = DsRoleGetPrimaryDomainInformation(
  2079. DomainControllerInfo->DomainControllerName,
  2080. DsRolePrimaryDomainInfoBasic,
  2081. (PBYTE *) &DomainInfo);
  2082. if (Error != ERROR_SUCCESS) {
  2083. BinlPrintDbg((
  2084. DEBUG_ERRORS,
  2085. "DsRoleGetPrimaryDomainInformation (%ws) failed, ec = %d.\r\n",
  2086. DomainControllerInfo->DomainControllerName,
  2087. Error ));
  2088. goto exit;
  2089. }
  2090. *NetBIOSName = BinlAllocateMemory(
  2091. (wcslen(DomainInfo->DomainNameFlat)+1) * sizeof(WCHAR) );
  2092. if (*NetBIOSName) {
  2093. wcscpy( *NetBIOSName, DomainInfo->DomainNameFlat );
  2094. } else {
  2095. BinlPrintDbg((
  2096. DEBUG_ERRORS,
  2097. "GetDomainNetBIOSName: failed to allocate memory (%d bytes) .\r\n",
  2098. (wcslen(DomainInfo->DomainNameFlat)+1) * sizeof(WCHAR) ));
  2099. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2100. }
  2101. exit:
  2102. if (DomainInfo) {
  2103. DsRoleFreeMemory( DomainInfo );
  2104. }
  2105. if (DomainControllerInfo) {
  2106. NetApiBufferFree( DomainControllerInfo );
  2107. }
  2108. return(Error);
  2109. }