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.

6755 lines
200 KiB

  1. #ifdef DEBUG_LOGLOG
  2. #pragma message("*** Warning! This is a log-generating build.")
  3. #endif
  4. /*++
  5. File Description:
  6. This file contains all the functions required to add a registry entry
  7. to force execution of the system clone worker upon reboot.
  8. --*/
  9. #include <nt.h>
  10. #include <ntrtl.h>
  11. #include <nturtl.h>
  12. #include <ntsam.h>
  13. #include <ntlsa.h>
  14. #include <windows.h>
  15. #include <stdlib.h>
  16. #include <time.h>
  17. #include <lmcons.h>
  18. #include <lmerr.h>
  19. #include <lmjoin.h>
  20. #include <lmapibuf.h>
  21. #include <sddl.h>
  22. #include <setupapi.h>
  23. #include <spapip.h>
  24. #include <ntsetup.h>
  25. #include <imagehlp.h>
  26. #include <coguid.h>
  27. #include <cfg.h>
  28. #include <cfgmgr32.h>
  29. #include <devguid.h>
  30. #include <netcfgx.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <syssetup.h>
  34. #include <spsyslib.h>
  35. #include <sysprep_.h>
  36. #include <userenv.h>
  37. #include <userenvp.h>
  38. #include <shlwapi.h>
  39. #include <shlobj.h>
  40. #include <shellapi.h>
  41. #include <wininet.h>
  42. #include <winineti.h>
  43. #include "resource.h" // shared string resource from riprep/sysprep
  44. #include <strsafe.h>
  45. #include <shlguid.h> // Needed for CLSID_CUrlHistory
  46. #define COBJMACROS
  47. #include <urlhist.h> // Needed for IUrlHistoryStg2 and IID_IUrlHistoryStg2
  48. #if !(defined(AMD64) || defined(IA64))
  49. #include <cleandrm.h>
  50. #define CLEANDRM_LOGFILE TEXT("cleandrm.log")
  51. #endif // #if !(defined(AMD64) || defined(IA64))
  52. extern BOOL NoSidGen;
  53. extern BOOL PnP;
  54. extern BOOL bMiniSetup;
  55. extern HINSTANCE ghInstance;
  56. //
  57. // Internal Defines
  58. //
  59. #define STR_REG_USERASSIST TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{75048700-EF1F-11D0-9888-006097DEACF9}")
  60. #define STR_REG_USERASSIST_SHELL STR_REG_USERASSIST TEXT("\\Count")
  61. #define STR_REG_USERASSIST_IE TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{5E6AB780-7743-11CF-A12B-00AA004AE837}\\Count")
  62. #define STR_REG_USERASSIST_DEFSHELL TEXT(".DEFAULT\\") STR_REG_USERASSIST_SHELL
  63. #define STR_REG_VAL_VERSION TEXT("Version")
  64. #define VAL_UEM_VERSION 0x00000003
  65. #define VAL_MAX_DATA 16384
  66. #define SYSPREPMASSSTORAGE_SECTION TEXT("sysprepmassstorage")
  67. #define SYSPREP_SECTION TEXT("sysprep")
  68. #define SYSPREP_BUILDMASSSTORAGE_KEY TEXT("BuildMassStorageSection")
  69. #define STR_REG_VALUE_LASTALIVESTAMP TEXT("LastAliveStamp")
  70. #define STR_REG_KEY_RELIABILITY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Reliability")
  71. #ifdef NULLSTR
  72. #undef NULLSTR
  73. #endif // NULLSTR
  74. #define NULLSTR TEXT("\0")
  75. #ifdef NULLCHR
  76. #undef NULLCHR
  77. #endif // NULLCHR
  78. #define NULLCHR TEXT('\0')
  79. #ifdef CHR_BACKSLASH
  80. #undef CHR_BACKSLASH
  81. #endif // CHR_BACKSLASH
  82. #define CHR_BACKSLASH TEXT('\\')
  83. #ifdef CHR_SPACE
  84. #undef CHR_SPACE
  85. #endif // CHR_SPACE
  86. #define CHR_SPACE TEXT(' ')
  87. //
  88. // This is a string version of GUID_DEVCLASS_LEGACYDRIVER in devguid.h
  89. //
  90. #define LEGACYDRIVER_STRING L"{8ECC055D-047F-11D1-A537-0000F8753ED1}"
  91. //
  92. // Context for file queues in SysSetup
  93. //
  94. typedef struct _SYSSETUP_QUEUE_CONTEXT {
  95. PVOID DefaultContext;
  96. PWSTR DirectoryOnSourceDevice;
  97. PWSTR DiskDescription;
  98. PWSTR DiskTag;
  99. } SYSPREP_QUEUE_CONTEXT, *PSYSPREP_QUEUE_CONTEXT;
  100. typedef struct _CLEANUP_NODE
  101. {
  102. LPTSTR pszService;
  103. struct _CLEANUP_NODE* pNext;
  104. }CLEANUP_NODE, *PCLEANUP_NODE, **PPCLEANUP_NODE;
  105. PCLEANUP_NODE g_pCleanupListHead = NULL;
  106. // String macros.
  107. //
  108. #ifndef LSTRCMPI
  109. #define LSTRCMPI(x, y) ( ( CompareString( LOCALE_INVARIANT, NORM_IGNORECASE, x, -1, y, -1 ) - CSTR_EQUAL ) )
  110. #endif // LSTRCMPI
  111. #ifdef DEBUG_LOGLOG
  112. /*++
  113. ===============================================================================
  114. Debug logging for populating/depopulating the critical device
  115. database
  116. ===============================================================================
  117. --*/
  118. #define MAX_MSG_LEN 2048
  119. BOOL LOG_Init(LPCTSTR lpszLogFile);
  120. BOOL LOG_DeInit();
  121. BOOL LOG_Write(LPCTSTR lpszFormat,...);
  122. BOOL LOG_WriteLastError();
  123. int GetSystemErrorMessage(LPTSTR lpszMsg, int cbMsg);
  124. static HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
  125. BOOL LOG_Init(
  126. LPCTSTR lpszLogFile
  127. )
  128. {
  129. if (g_hLogFile != INVALID_HANDLE_VALUE)
  130. return FALSE;
  131. g_hLogFile = CreateFile(
  132. lpszLogFile,
  133. GENERIC_WRITE,
  134. FILE_SHARE_READ | FILE_SHARE_WRITE,
  135. NULL,
  136. OPEN_ALWAYS,
  137. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  138. NULL);
  139. if (g_hLogFile == INVALID_HANDLE_VALUE)
  140. return FALSE;
  141. return TRUE;
  142. }
  143. BOOL LOG_DeInit()
  144. {
  145. BOOL bRet = LOG_Write(TEXT("\r\n"));
  146. if (g_hLogFile != INVALID_HANDLE_VALUE) {
  147. bRet = CloseHandle(g_hLogFile) && bRet;
  148. g_hLogFile = INVALID_HANDLE_VALUE;
  149. }
  150. return bRet;
  151. }
  152. BOOL LOG_Write(
  153. LPCTSTR lpszFormat,
  154. ...
  155. )
  156. {
  157. DWORD dwTemp;
  158. TCHAR szBuf[MAX_MSG_LEN];
  159. char szMsg[MAX_MSG_LEN];
  160. va_list arglist;
  161. int len;
  162. if (g_hLogFile == INVALID_HANDLE_VALUE)
  163. return FALSE;
  164. va_start(arglist, lpszFormat);
  165. _vsnwprintf(szBuf, MAX_MSG_LEN, lpszFormat, arglist);
  166. va_end(arglist);
  167. StringCchCat (szBuf, AS ( szBuf ), TEXT("\r\n"));
  168. len = WideCharToMultiByte(
  169. CP_ACP,
  170. 0,
  171. szBuf,
  172. -1,
  173. szMsg,
  174. MAX_MSG_LEN,
  175. NULL,
  176. NULL
  177. );
  178. if (len == 0) {
  179. return FALSE;
  180. }
  181. SetFilePointer(g_hLogFile, 0L, 0L, FILE_END);
  182. return WriteFile(g_hLogFile, szMsg, len - 1, &dwTemp, NULL);
  183. }
  184. BOOL LOG_WriteLastError()
  185. {
  186. TCHAR szBuf[MAX_MSG_LEN];
  187. GetSystemErrorMessage(szBuf, MAX_MSG_LEN);
  188. return LOG_Write(TEXT("ERROR - %s"), szBuf);
  189. }
  190. int
  191. GetSystemErrorMessage(
  192. LPWSTR lpszMsg,
  193. int cbMsg
  194. )
  195. {
  196. LPVOID lpMsgBuf;
  197. DWORD dwError = GetLastError();
  198. int len;
  199. len = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  200. FORMAT_MESSAGE_FROM_SYSTEM |
  201. FORMAT_MESSAGE_IGNORE_INSERTS,
  202. NULL,
  203. dwError,
  204. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  205. (LPWSTR) &lpMsgBuf,
  206. 0,
  207. NULL );
  208. if( len == 0 ) {
  209. //
  210. // We failed to get a message. Just spew the error
  211. // code.
  212. //
  213. StringCchPrintf( lpszMsg, cbMsg, ( L"(0x%08X)", dwError);
  214. len = lstrlen((LPCWSTR) lpMsgBuf);
  215. } else {
  216. len = lstrlen((LPCWSTR) lpMsgBuf);
  217. StringCchPrintf( lpszMsg, cbMsg, L"(0x%08X) ", dwError);
  218. lpszMsg += lstrlen(lpszMsg);
  219. cbMsg -= lstrlen(lpszMsg);
  220. lstrcpyn(lpszMsg, (LPCWSTR) lpMsgBuf, cbMsg);
  221. if (len >= cbMsg)
  222. lpszMsg[cbMsg - 1] = L'\0';
  223. LocalFree(lpMsgBuf);
  224. }
  225. // Reset the last error incase someone after logging wants
  226. // to get last error again
  227. //
  228. SetLastError(dwError);
  229. return len;
  230. }
  231. #endif // DEBUG_LOGLOG
  232. #define PRO 0
  233. #define SRV 1
  234. #define ADS 2
  235. #define DAT 3
  236. #define PER 4
  237. #define BLA 5
  238. // Returns 0 - Professional, 1 - Server, 2 - ADS, 3 - Data, 4 - Personal, 5 - Blade
  239. //
  240. DWORD GetProductFlavor()
  241. {
  242. DWORD ProductFlavor = PRO; // Default Professional
  243. OSVERSIONINFOEX osvi;
  244. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  245. GetVersionEx((OSVERSIONINFO*)&osvi);
  246. if (osvi.wProductType == VER_NT_WORKSTATION)
  247. {
  248. if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
  249. {
  250. ProductFlavor = PER; // Personal
  251. }
  252. }
  253. else
  254. {
  255. ProductFlavor = SRV; // In the server case assume normal server
  256. if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
  257. {
  258. ProductFlavor = DAT; // Datacenter
  259. }
  260. else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
  261. {
  262. ProductFlavor = ADS; // Advanced server
  263. }
  264. else if (osvi.wSuiteMask & VER_SUITE_BLADE)
  265. {
  266. ProductFlavor = BLA; // Blade server
  267. }
  268. }
  269. return ProductFlavor;
  270. }
  271. // Check if Personal SKU
  272. //
  273. BOOL IsPersonalSKU()
  274. {
  275. if (PER == GetProductFlavor())
  276. return TRUE;
  277. return FALSE;
  278. }
  279. // Check if Professional SKU
  280. //
  281. BOOL IsProfessionalSKU()
  282. {
  283. if (PRO == GetProductFlavor())
  284. return TRUE;
  285. return FALSE;
  286. }
  287. // Check if Server SKU
  288. //
  289. BOOL IsServerSKU()
  290. {
  291. int OS = GetProductFlavor();
  292. if (SRV == OS ||
  293. BLA == OS ||
  294. DAT == OS ||
  295. ADS == OS)
  296. return TRUE;
  297. return FALSE;
  298. }
  299. BOOL
  300. IsDomainMember(
  301. VOID
  302. )
  303. /*++
  304. ===============================================================================
  305. Routine Description:
  306. Detect if we're a member of a domain or not.
  307. Arguments:
  308. Return Value:
  309. TRUE - We're in a domain.
  310. FALSE - We're not in a domain.
  311. ===============================================================================
  312. --*/
  313. {
  314. DWORD rc;
  315. PWSTR SpecifiedDomain = NULL;
  316. NETSETUP_JOIN_STATUS JoinStatus;
  317. rc = NetGetJoinInformation( NULL,
  318. &SpecifiedDomain,
  319. &JoinStatus );
  320. if( SpecifiedDomain ) {
  321. NetApiBufferFree( SpecifiedDomain );
  322. }
  323. if( rc == NO_ERROR ) {
  324. if( JoinStatus == NetSetupDomainName ) {
  325. return TRUE;
  326. }
  327. }
  328. return FALSE;
  329. }
  330. BOOL
  331. ResetRegistryKey(
  332. IN HKEY Rootkey,
  333. IN PCWSTR Subkey,
  334. IN PCWSTR Delkey
  335. )
  336. /*++
  337. ===============================================================================
  338. Routine Description:
  339. Reset a registry key by deleting the key and all subvalues
  340. then recreate the key
  341. Arguments:
  342. Return Value:
  343. ===============================================================================
  344. --*/
  345. {
  346. HKEY hkey;
  347. HKEY nkey;
  348. DWORD rc;
  349. BOOL AnyErrors;
  350. DWORD disp;
  351. AnyErrors = FALSE;
  352. rc = RegCreateKeyEx(Rootkey, Subkey, 0L, NULL,
  353. REG_OPTION_BACKUP_RESTORE,
  354. KEY_CREATE_SUB_KEY, NULL, &hkey, NULL);
  355. if ( rc == NO_ERROR )
  356. {
  357. rc = SHDeleteKey(hkey, Delkey);
  358. if( (rc != NO_ERROR) && (rc != ERROR_FILE_NOT_FOUND) )
  359. {
  360. AnyErrors = TRUE;
  361. }
  362. else
  363. {
  364. rc = RegCreateKeyEx(hkey, Delkey, 0L, NULL,
  365. REG_OPTION_NON_VOLATILE,
  366. KEY_ALL_ACCESS, NULL, &nkey, &disp);
  367. if ( rc != NO_ERROR )
  368. {
  369. AnyErrors = TRUE;
  370. }
  371. //
  372. // BUGUG - Tries to close key even if rc != NO_ERROR
  373. //
  374. RegCloseKey(nkey);
  375. }
  376. //
  377. // BUGUG - Tries to close key even if rc != NO_ERROR
  378. //
  379. RegCloseKey(hkey);
  380. }
  381. else
  382. {
  383. AnyErrors = TRUE;
  384. }
  385. return (!AnyErrors);
  386. }
  387. BOOL
  388. GetAdminAccountName(
  389. PWSTR AccountName
  390. )
  391. /*++
  392. ===============================================================================
  393. Routine Description:
  394. This routine retrieves the name of the Adminstrator account
  395. Arguments:
  396. AccountName This is a buffer that will recieve the name of the account.
  397. Return Value:
  398. TRUE - success.
  399. FALSE - failed.
  400. ===============================================================================
  401. --*/
  402. {
  403. BOOL b = TRUE;
  404. LSA_HANDLE hPolicy;
  405. NTSTATUS ntStatus;
  406. OBJECT_ATTRIBUTES ObjectAttributes;
  407. PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
  408. UCHAR SubAuthCount;
  409. DWORD sidlen;
  410. PSID psid = NULL;
  411. WCHAR domainname[MAX_PATH];
  412. DWORD adminlen= MAX_PATH;
  413. DWORD domlen=MAX_PATH;
  414. SID_NAME_USE sidtype;
  415. InitializeObjectAttributes( &ObjectAttributes,
  416. NULL,
  417. 0L,
  418. NULL,
  419. NULL );
  420. ntStatus = LsaOpenPolicy( NULL,
  421. &ObjectAttributes,
  422. POLICY_ALL_ACCESS,
  423. &hPolicy );
  424. if (!NT_SUCCESS(ntStatus)) {
  425. //
  426. // ISSUE-2002/02/26-brucegr: Do you close the handle if LsaOpenPolicy fails?
  427. //
  428. LsaClose(hPolicy);
  429. b = FALSE;
  430. }
  431. if( b ) {
  432. ntStatus = LsaQueryInformationPolicy( hPolicy,
  433. PolicyAccountDomainInformation,
  434. (PVOID *) &AccountDomainInfo );
  435. LsaClose( hPolicy );
  436. if (!NT_SUCCESS(ntStatus)) {
  437. if ( AccountDomainInfo != NULL ) {
  438. (VOID) LsaFreeMemory( AccountDomainInfo );
  439. }
  440. b = FALSE;
  441. }
  442. }
  443. if( b ) {
  444. //
  445. // calculate the size of a new sid with one more SubAuthority
  446. //
  447. SubAuthCount = *(GetSidSubAuthorityCount ( AccountDomainInfo->DomainSid ));
  448. SubAuthCount++; // for admin
  449. sidlen = GetSidLengthRequired ( SubAuthCount );
  450. //
  451. // allocate and copy the new new sid from the Domain SID
  452. //
  453. psid = (PSID)malloc(sidlen);
  454. if (psid) {
  455. memcpy(psid, AccountDomainInfo->DomainSid, GetLengthSid(AccountDomainInfo->DomainSid) );
  456. //
  457. // increment SubAuthority count and add Domain Admin RID
  458. //
  459. *(GetSidSubAuthorityCount( psid )) = SubAuthCount;
  460. *(GetSidSubAuthority( psid, SubAuthCount-1 )) = DOMAIN_USER_RID_ADMIN;
  461. if ( AccountDomainInfo != NULL ) {
  462. (VOID) LsaFreeMemory( AccountDomainInfo );
  463. }
  464. //
  465. // get the admin account name from the new SID
  466. //
  467. b = LookupAccountSid( NULL,
  468. psid,
  469. AccountName,
  470. &adminlen,
  471. domainname,
  472. &domlen,
  473. &sidtype );
  474. free(psid);
  475. }
  476. }
  477. return( b );
  478. }
  479. BOOL
  480. DeleteWinlogonDefaults(
  481. VOID
  482. )
  483. /*++
  484. ===============================================================================
  485. Routine Description:
  486. Delete the following registry values:
  487. HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\DefaultDomainName
  488. HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\DefaultUserName
  489. Arguments:
  490. Return Value:
  491. ===============================================================================
  492. --*/
  493. {
  494. HKEY hkey;
  495. DWORD rc;
  496. BOOL AnyErrors;
  497. WCHAR AccountName[MAX_PATH];
  498. AnyErrors = FALSE;
  499. rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  500. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  501. 0L, NULL,
  502. REG_OPTION_BACKUP_RESTORE,
  503. KEY_SET_VALUE, NULL, &hkey, NULL);
  504. if (rc == NO_ERROR)
  505. {
  506. //
  507. // If Personal then reset the values
  508. //
  509. if (IsPersonalSKU()) {
  510. DWORD dwSize = MAX_PATH * sizeof(TCHAR);
  511. StringCchCopy ( AccountName, AS ( AccountName ), TEXT("Owner"));
  512. rc = RegSetValueEx( hkey,
  513. TEXT("DefaultUserName"),
  514. 0,
  515. REG_SZ,
  516. (CONST BYTE *)AccountName,
  517. (lstrlen( AccountName ) + 1) * sizeof(TCHAR) );
  518. if((rc != NO_ERROR) && (rc != ERROR_FILE_NOT_FOUND)) {
  519. AnyErrors = TRUE;
  520. }
  521. }
  522. else {
  523. //
  524. // All others sku
  525. //
  526. if(rc == NO_ERROR) {
  527. rc = RegDeleteValue( hkey, TEXT("DefaultDomainName") );
  528. if((rc != NO_ERROR) && (rc != ERROR_FILE_NOT_FOUND)) {
  529. AnyErrors = TRUE;
  530. } else {
  531. //
  532. // Before we whack the DefaultUserName value, let's
  533. // make sure we can replace it with the name of the
  534. // administrator account. So first go retrieve that
  535. // name.
  536. //
  537. if( GetAdminAccountName( AccountName ) ) {
  538. //
  539. // Got it. Reset the value key.
  540. //
  541. rc = RegSetValueEx( hkey,
  542. TEXT("DefaultUserName"),
  543. 0,
  544. REG_SZ,
  545. (CONST BYTE *)AccountName,
  546. (lstrlen( AccountName ) + 1) * sizeof(TCHAR) );
  547. if((rc != NO_ERROR) && (rc != ERROR_FILE_NOT_FOUND)) {
  548. AnyErrors = TRUE;
  549. }
  550. } else {
  551. //
  552. // Sniff... We couldn't retrieve the name of the
  553. // administrator account. Very odd. Better
  554. // be safe and just leave the key as it is.
  555. //
  556. }
  557. }
  558. }
  559. }
  560. RegCloseKey(hkey);
  561. }
  562. else {
  563. AnyErrors = TRUE;
  564. }
  565. return (!AnyErrors);
  566. }
  567. VOID
  568. FixDevicePaths(
  569. VOID
  570. )
  571. /*++
  572. ===============================================================================
  573. Routine Description:
  574. This routine checks to see if the user specified an oempnpdriverspath in
  575. his unattend file. If so, we need to append it onto the DevicePath
  576. entry in the registry.
  577. If the user specified an InstallFilesPath in the unattend file, we
  578. will plug that value into the registry so that Lang files, ...
  579. can be obtained from this new directory.
  580. Arguments:
  581. None.
  582. Return Value:
  583. ===============================================================================
  584. --*/
  585. {
  586. LPTSTR lpNewPath = NULL,
  587. lpOldPath,
  588. lpSearch;
  589. DWORD dwChars = 512,
  590. dwReturn;
  591. TCHAR NewPath[2048];
  592. TCHAR FileName[2048];
  593. HKEY hKey;
  594. DWORD l;
  595. DWORD Size;
  596. DWORD Type;
  597. //
  598. // NOTE: This function should call UpdateDevicePath() and UpdateSourcePath()
  599. // from OPKLIB. Those fuctions do the exact thing that the following
  600. // code does. But for now because I don't want to deal the whole riprep
  601. // linking with OPKLIB, this duplicate code will just have to remain.
  602. //
  603. //
  604. // =================================
  605. // OemPnpDriversPath
  606. // =================================
  607. //
  608. //
  609. // First see if he's got the entry in the unattend file.
  610. //
  611. if (!GetWindowsDirectory( FileName, MAX_PATH ))
  612. return;
  613. StringCchCopy ( &FileName[3], AS ( FileName ) - 3, TEXT("sysprep\\sysprep.inf") );
  614. // Get the new string from the INF file.
  615. //
  616. do
  617. {
  618. // Start with 1k of characters, doubling each time.
  619. //
  620. dwChars *= 2;
  621. // Free the previous buffer, if there was one.
  622. //
  623. if ( lpNewPath )
  624. free(lpNewPath);
  625. // Allocate a new buffer.
  626. //
  627. if ( lpNewPath = (LPTSTR) malloc(dwChars * sizeof(TCHAR)) )
  628. {
  629. *lpNewPath = L'\0';
  630. dwReturn = GetPrivateProfileString(L"Unattended", L"OemPnPDriversPath", L"", lpNewPath, dwChars, FileName);
  631. }
  632. else
  633. dwReturn = 0;
  634. }
  635. while ( dwReturn >= (dwChars - 1) );
  636. if ( lpNewPath && *lpNewPath )
  637. {
  638. //
  639. // Got it. Open the registry and get the original value.
  640. //
  641. //
  642. // Open HKLM\Software\Microsoft\Windows\CurrentVersion
  643. //
  644. l = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  645. TEXT("Software\\Microsoft\\Windows\\CurrentVersion"),
  646. 0,
  647. KEY_ALL_ACCESS,
  648. &hKey );
  649. if( l == NO_ERROR ) {
  650. //
  651. // Query the value of the DevicePath Key.
  652. //
  653. Size = 0;
  654. l = RegQueryValueEx( hKey,
  655. TEXT("DevicePath"),
  656. NULL,
  657. &Type,
  658. NULL,
  659. &Size );
  660. if ( ERROR_SUCCESS != l )
  661. Size = 0;
  662. // Need to count the number of paths in the new path buffer.
  663. //
  664. for ( dwChars = 1, lpSearch = lpNewPath; *lpSearch; lpSearch++ )
  665. {
  666. if ( L';' == *lpSearch )
  667. dwChars++;
  668. }
  669. // The size of the old buffer needs to be the size of the registry key,
  670. // plus the size of the new buffer, plus room for the ";%systemdrive%\" we
  671. // are going to add to each path in the new buffer.
  672. //
  673. Size += (lstrlen(lpNewPath) + (dwChars * 16) + 1) * sizeof(TCHAR);
  674. if ( lpOldPath = (LPTSTR) malloc(Size) )
  675. {
  676. TCHAR *BeginStrPtr;
  677. TCHAR *EndStrPtr;
  678. BOOL Done = FALSE;
  679. LPTSTR lpAdd;
  680. DWORD dwBufSize = Size;
  681. l = RegQueryValueEx( hKey,
  682. TEXT("DevicePath"),
  683. NULL,
  684. &Type,
  685. (LPBYTE) lpOldPath,
  686. &dwBufSize );
  687. if ( ERROR_SUCCESS != l )
  688. *lpOldPath = L'\0';
  689. //
  690. // OemPnpDriversDirPath can have several entries, separated by
  691. // a semicolon. For each entry, we need to:
  692. // 1. append a semicolon.
  693. // 2. append %SystemDrive%
  694. // 3. concatenate the entry.
  695. //
  696. BeginStrPtr = lpNewPath;
  697. do {
  698. //
  699. // Mark the end of this entry.
  700. //
  701. EndStrPtr = BeginStrPtr;
  702. while( (*EndStrPtr) && (*EndStrPtr != L';') ) {
  703. EndStrPtr++;
  704. }
  705. //
  706. // Is this the last entry?
  707. //
  708. if( *EndStrPtr == 0 ) {
  709. Done = TRUE;
  710. }
  711. *EndStrPtr = 0;
  712. //
  713. // Make sure that if you change anything here that
  714. // has to do with the length of the extra data we add
  715. // to each path in the new buffer, that you change the
  716. // extra padding we give to the old path buffer (currenttly
  717. // 16 chars for every different path in the new buffer).
  718. //
  719. // Save a pointer to part we are adding
  720. // so it can be removed if already there.
  721. //
  722. lpAdd = lpOldPath + lstrlen(lpOldPath);
  723. if ( *lpOldPath )
  724. StringCchCat( lpAdd, ( Size / sizeof ( TCHAR ) ) - lstrlen( lpOldPath ), L";" );
  725. // Save a pointer to the part we are going to
  726. // search for in the old path (after the ;).
  727. //
  728. lpSearch = lpOldPath + lstrlen(lpOldPath);
  729. StringCchCat( lpSearch, ( Size / sizeof ( TCHAR ) ) - lstrlen( lpOldPath ), L"%SystemDrive%\\" );
  730. if ( L'\\' == *BeginStrPtr )
  731. BeginStrPtr++;
  732. lpSearch = lpOldPath + lstrlen(lpOldPath);
  733. StringCchCat( lpSearch, ( Size / sizeof ( TCHAR ) ) - lstrlen( lpOldPath ), BeginStrPtr);
  734. BeginStrPtr = EndStrPtr + 1;
  735. // Check to see if this new string is already
  736. // in the old path.
  737. //
  738. EndStrPtr = lpOldPath;
  739. do
  740. {
  741. // First check for our string we are adding.
  742. //
  743. if ( ( EndStrPtr = StrStrI(EndStrPtr, lpSearch) ) &&
  744. ( EndStrPtr < lpAdd ) )
  745. {
  746. // If found, make sure the next character
  747. // in our old path is a ; or null.
  748. //
  749. EndStrPtr += lstrlen(lpSearch);
  750. if ( ( TEXT('\0') == *EndStrPtr ) ||
  751. ( TEXT(';') == *EndStrPtr ) )
  752. {
  753. // If it is, it is already there and we
  754. // need to get rid of the string we added.
  755. //
  756. *lpAdd = TEXT('\0');
  757. }
  758. else
  759. {
  760. // If it isn't, move the end pointer to the next
  761. // ; so we can search the rest of the old path string.
  762. //
  763. while ( *EndStrPtr && ( TEXT(';') != *EndStrPtr ) )
  764. EndStrPtr++;
  765. }
  766. }
  767. }
  768. while ( EndStrPtr && ( EndStrPtr < lpAdd ) && *lpAdd );
  769. //
  770. // Take care of the case where the user ended the
  771. // OemPnpDriversPath entry with a semicolon.
  772. //
  773. if( *BeginStrPtr == 0 ) {
  774. Done = TRUE;
  775. }
  776. } while( !Done );
  777. //
  778. // Now set the key with our new value.
  779. //
  780. l = RegSetValueEx( hKey,
  781. TEXT("DevicePath"),
  782. 0,
  783. REG_EXPAND_SZ,
  784. (CONST BYTE *)lpOldPath,
  785. (lstrlen( lpOldPath ) + 1) * sizeof(TCHAR));
  786. free(lpOldPath);
  787. }
  788. RegCloseKey(hKey);
  789. }
  790. free(lpNewPath);
  791. }
  792. //
  793. // =================================
  794. // InstallFilesPath
  795. // =================================
  796. //
  797. //
  798. // First see if he's got the entry in the unattend file.
  799. //
  800. if (!GetWindowsDirectory( FileName, MAX_PATH ))
  801. return;
  802. StringCchCopy ( &FileName[3], AS ( FileName ) - 3, TEXT("sysprep\\sysprep.inf") );
  803. //
  804. // ISSUE-2002/02/26-brucegr: NewPath should be zero initialized for "if" check below
  805. //
  806. GetPrivateProfileString( TEXT( "Unattended" ),
  807. TEXT( "InstallFilesPath" ),
  808. L"",
  809. NewPath,
  810. sizeof(NewPath)/sizeof(NewPath[0]),
  811. FileName );
  812. if( NewPath[0] ) {
  813. //
  814. // Got it. Open the registry and get the original value.
  815. //
  816. //
  817. // Open HKLM\Software\Microsoft\Windows\CurrentVersion\\Setup
  818. //
  819. l = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  820. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Setup"),
  821. 0,
  822. KEY_ALL_ACCESS,
  823. &hKey );
  824. if( l == NO_ERROR ) {
  825. //
  826. // Now set the key with our new value.
  827. //
  828. l = RegSetValueEx( hKey,
  829. TEXT("SourcePath"),
  830. 0,
  831. REG_SZ,
  832. (CONST BYTE *)NewPath,
  833. (lstrlen( NewPath ) + 1) * sizeof(TCHAR));
  834. //
  835. // ISSUE-2002/02/26-brucegr: Do we care about the return value?
  836. //
  837. RegCloseKey(hKey);
  838. }
  839. }
  840. }
  841. void DeleteAllValues(HKEY hKey)
  842. {
  843. DWORD dwCount = 0;
  844. DWORD dwMaxNameLen = 0;
  845. // Enumerate all the existing values and delete them all.
  846. //Let's get the number of Entries already present and the max size of value name.
  847. if(RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwCount, &dwMaxNameLen, NULL, NULL, NULL) == ERROR_SUCCESS)
  848. {
  849. LPTSTR lpValueName = (LPTSTR) LocalAlloc(LPTR, (dwMaxNameLen + 1)*sizeof(TCHAR));
  850. if(lpValueName)
  851. {
  852. //Let's remove all the values already present in the UEM database.
  853. while(dwCount--)
  854. {
  855. DWORD dwNameLen = dwMaxNameLen + 1;
  856. if(RegEnumValue(hKey, dwCount, lpValueName, &dwNameLen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  857. {
  858. RegDeleteValue(hKey, lpValueName);
  859. }
  860. else
  861. {
  862. //If RegQueryInfoKey worked correct, this should never happen.
  863. ASSERT(0);
  864. }
  865. }
  866. LocalFree((HLOCAL)lpValueName);
  867. }
  868. }
  869. }
  870. void ClearRecentApps()
  871. {
  872. HKEY hKeyCurrentUser,
  873. hKeyDefault;
  874. DWORD dwDisposition;
  875. TCHAR szName[MAX_PATH] = TEXT("");
  876. LPTSTR lpszValue = NULL;
  877. DWORD dwNameSize = (sizeof(szName) / sizeof(TCHAR)),
  878. dwRegIndex = 0,
  879. dwUemVersion = VAL_UEM_VERSION,
  880. dwValueSize,
  881. dwType;
  882. // Open the key for the Shell MFU list
  883. //
  884. if ( RegCreateKeyEx(HKEY_CURRENT_USER, STR_REG_USERASSIST_SHELL, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKeyCurrentUser, &dwDisposition) == ERROR_SUCCESS )
  885. {
  886. // Check to see if we opened an existing key, if so delete all of the values
  887. //
  888. if(dwDisposition == REG_OPENED_EXISTING_KEY)
  889. {
  890. DeleteAllValues(hKeyCurrentUser);
  891. }
  892. // Write out the version value to the parent key
  893. //
  894. SHSetValue(HKEY_CURRENT_USER, STR_REG_USERASSIST, STR_REG_VAL_VERSION, REG_DWORD, &dwUemVersion, sizeof(dwUemVersion));
  895. // Copy all of the values from the .DEFAULT registry
  896. //
  897. if ( RegOpenKeyEx(HKEY_USERS, STR_REG_USERASSIST_DEFSHELL, 0, KEY_READ, &hKeyDefault) == ERROR_SUCCESS )
  898. {
  899. // Allocate the value buffer...
  900. //
  901. lpszValue = malloc(VAL_MAX_DATA * sizeof(TCHAR));
  902. if ( lpszValue )
  903. {
  904. dwValueSize = VAL_MAX_DATA * sizeof(TCHAR);
  905. // Enumerate each value
  906. //
  907. while (RegEnumValue(hKeyDefault, dwRegIndex, szName, &dwNameSize, NULL, &dwType, (LPBYTE)lpszValue, &dwValueSize ) == ERROR_SUCCESS)
  908. {
  909. // Set the value in the current user key
  910. //
  911. RegSetValueEx(hKeyCurrentUser, szName, 0, dwType, (LPBYTE) lpszValue, dwValueSize);
  912. // Reset the size of the name value
  913. //
  914. dwNameSize = sizeof(szName) / sizeof(TCHAR);
  915. dwValueSize = VAL_MAX_DATA * sizeof(TCHAR);
  916. // Increment to the next value
  917. //
  918. dwRegIndex++;
  919. }
  920. free( lpszValue );
  921. }
  922. // Clean up the registry keys
  923. //
  924. RegCloseKey(hKeyDefault);
  925. }
  926. // Clean up the registry keys
  927. //
  928. RegCloseKey(hKeyCurrentUser);
  929. }
  930. // Reset the disposition
  931. //
  932. dwDisposition = 0;
  933. // Open the second key containing information in the IE MFU list
  934. //
  935. if ( RegCreateKeyEx(HKEY_CURRENT_USER, STR_REG_USERASSIST_IE, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKeyCurrentUser, &dwDisposition) == ERROR_SUCCESS )
  936. {
  937. // Check to see if we opened an existing key, if so delete all of the values
  938. //
  939. if(dwDisposition == REG_OPENED_EXISTING_KEY)
  940. {
  941. DeleteAllValues(hKeyCurrentUser);
  942. }
  943. // Clean up the registry keys
  944. //
  945. RegCloseKey(hKeyCurrentUser);
  946. }
  947. }
  948. //
  949. // This function sets the registry key ACL to the specified SDDL string.
  950. //
  951. BOOL ApplySecurityStringToRegKey(HKEY hKey, SECURITY_INFORMATION SecurityInformation, LPTSTR lpszSecurityDescriptor )
  952. {
  953. BOOL bRet = FALSE;
  954. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  955. //
  956. // Make sure the caller actually gave us a string...
  957. //
  958. if ( lpszSecurityDescriptor && *lpszSecurityDescriptor )
  959. {
  960. //
  961. // Convert the passed in string into a usable security descriptor
  962. //
  963. if ( ( ConvertStringSecurityDescriptorToSecurityDescriptor(lpszSecurityDescriptor, // security descriptor string
  964. SDDL_REVISION_1, // revision level
  965. &pSecurityDescriptor, // SD
  966. NULL ) ) &&
  967. ( pSecurityDescriptor != NULL ) )
  968. {
  969. LONG lRes;
  970. //
  971. // Call RegSetKeySecurity with the new descriptor...
  972. //
  973. lRes = RegSetKeySecurity( hKey,
  974. SecurityInformation,
  975. pSecurityDescriptor );
  976. if ( lRes == ERROR_SUCCESS )
  977. {
  978. bRet = TRUE;
  979. }
  980. //
  981. // Free the security descriptor that was allocated for us...
  982. //
  983. LocalFree( pSecurityDescriptor );
  984. }
  985. }
  986. return bRet;
  987. }
  988. //
  989. // This function does a 3-step process
  990. // 1. Take ownership of the key
  991. // 2. Write the permissions into the key
  992. // 3. Open up the key with KEY_ALL_ACCESS and recurse into it.
  993. //
  994. // This function will always take ownership of the key for the owner specified in the SDDL string.
  995. //
  996. BOOL ReplaceSecurityInRegistry(HKEY hKeyRoot,
  997. LPTSTR lpszSubKey,
  998. LPTSTR lpszSecurityDescriptor,
  999. BOOL bRecurse)
  1000. {
  1001. HKEY hKey1 = NULL, // WRITE_OWNER
  1002. hKey2 = NULL, // WRITE_OWNER | WRITE_DAC
  1003. hKey3 = NULL; // KEY_ALL_ACCESS
  1004. BOOL bRoot = FALSE;
  1005. BOOL bRet = TRUE;
  1006. //
  1007. // If the caller didn't pass in a lpszSubKey value...
  1008. //
  1009. if ( !( lpszSubKey && *lpszSubKey ) )
  1010. {
  1011. hKey1 = hKeyRoot;
  1012. hKey2 = hKeyRoot;
  1013. hKey3 = hKeyRoot;
  1014. bRoot = TRUE;
  1015. }
  1016. //
  1017. // Open the currently requested subkey...
  1018. //
  1019. if ( ( hKey1 != NULL ) ||
  1020. ( RegOpenKeyEx(hKeyRoot,
  1021. lpszSubKey,
  1022. 0,
  1023. WRITE_OWNER,
  1024. &hKey1) == ERROR_SUCCESS ) )
  1025. {
  1026. //
  1027. // Apply the original specified descriptor to the current key...
  1028. //
  1029. if ( !( ( lpszSecurityDescriptor &&
  1030. ApplySecurityStringToRegKey(hKey1,
  1031. OWNER_SECURITY_INFORMATION,
  1032. lpszSecurityDescriptor ) ) &&
  1033. ( ( hKey2 != NULL ) ||
  1034. ( RegOpenKeyEx(hKeyRoot,
  1035. lpszSubKey,
  1036. 0,
  1037. WRITE_OWNER | WRITE_DAC,
  1038. &hKey2) == ERROR_SUCCESS ) ) &&
  1039. ( ApplySecurityStringToRegKey(hKey2,
  1040. OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
  1041. lpszSecurityDescriptor ) ) &&
  1042. ( ( hKey3 != NULL ) ||
  1043. ( RegOpenKeyEx(hKeyRoot,
  1044. lpszSubKey,
  1045. 0,
  1046. KEY_ALL_ACCESS,
  1047. &hKey3) == ERROR_SUCCESS ) ) ) )
  1048. {
  1049. bRet = FALSE;
  1050. }
  1051. //
  1052. // Check if we have to do any recursion...
  1053. //
  1054. if ( bRet && bRecurse )
  1055. {
  1056. LONG lRes;
  1057. DWORD dwSubKeyLen = 0;
  1058. LPTSTR lpszKeyName = NULL;
  1059. //
  1060. // Call RegQueryInfoKey to figure out how much memory we have to allocate...
  1061. //
  1062. lRes = RegQueryInfoKey( hKey3,
  1063. NULL,
  1064. NULL,
  1065. NULL,
  1066. NULL,
  1067. &dwSubKeyLen,
  1068. NULL,
  1069. NULL,
  1070. NULL,
  1071. NULL,
  1072. NULL,
  1073. NULL );
  1074. if ( lRes == ERROR_SUCCESS )
  1075. {
  1076. if ( dwSubKeyLen )
  1077. {
  1078. //
  1079. // Pad out the maximum key length by two just to be sure...
  1080. //
  1081. dwSubKeyLen += 2;
  1082. //
  1083. // Allocate a buffer from the heap so we don't run out of stack
  1084. //
  1085. lpszKeyName = malloc(dwSubKeyLen * sizeof(TCHAR));
  1086. }
  1087. }
  1088. else
  1089. {
  1090. bRet = FALSE;
  1091. }
  1092. //
  1093. // If we got a subkey buffer, do the recurse...
  1094. //
  1095. if (lpszKeyName)
  1096. {
  1097. DWORD dwIndex = 0;
  1098. DWORD cbName = 0;
  1099. BOOL bContinue = TRUE;
  1100. //
  1101. // Now enumerate the subkeys within this key...
  1102. //
  1103. while (bContinue)
  1104. {
  1105. *lpszKeyName = TEXT('\0');
  1106. cbName = dwSubKeyLen;
  1107. if ( RegEnumKeyEx(hKey3,
  1108. dwIndex++,
  1109. lpszKeyName,
  1110. &cbName,
  1111. NULL,
  1112. NULL,
  1113. NULL,
  1114. NULL) != ERROR_SUCCESS )
  1115. {
  1116. bContinue = FALSE;
  1117. }
  1118. if (bContinue && cbName && *lpszKeyName)
  1119. {
  1120. //
  1121. // Call ReplaceSecurityInRegistry to do the recursion...
  1122. //
  1123. ReplaceSecurityInRegistry(hKey3,
  1124. lpszKeyName,
  1125. lpszSecurityDescriptor,
  1126. bRecurse);
  1127. }
  1128. }
  1129. //
  1130. // Free the key buffer
  1131. //
  1132. free(lpszKeyName);
  1133. }
  1134. }
  1135. //
  1136. // Unless this was a root key, close the keys
  1137. //
  1138. if ( !bRoot )
  1139. {
  1140. if (hKey1) RegCloseKey(hKey1);
  1141. if (hKey2) RegCloseKey(hKey2);
  1142. if (hKey3) RegCloseKey(hKey3);
  1143. }
  1144. }
  1145. else
  1146. {
  1147. bRet = FALSE;
  1148. }
  1149. return bRet;
  1150. }
  1151. BOOL
  1152. NukeUserSettings(
  1153. VOID
  1154. )
  1155. /*++
  1156. ===============================================================================
  1157. Routine Description:
  1158. This routine clears user specific settings from all user profiles on system:
  1159. - clears unique settings that identify Media Player.
  1160. - resets the ICW Completed flag to force ICW to run again.
  1161. - deletes the MS Messenger Software\Microsoft\MessengerService\PassportBalloon value
  1162. Arguments:
  1163. None.
  1164. Return Value:
  1165. TRUE - on success
  1166. FALSE - if there were any errors
  1167. Remarks:
  1168. Media Player regenerates these settings when they don't exist, thus
  1169. each installation of an image will have unique Media Player IDs.
  1170. ===============================================================================
  1171. --*/
  1172. {
  1173. HKEY hKey;
  1174. HKEY oKey;
  1175. DWORD dwSt;
  1176. WCHAR szKeyname[1024];
  1177. BOOL AnyErrors = FALSE;
  1178. INT i = 0,
  1179. j = 0,
  1180. iElem = 0;
  1181. typedef struct _REGVALUES
  1182. {
  1183. LPTSTR szKey;
  1184. LPTSTR szValue;
  1185. } REGVALUES;
  1186. REGVALUES rvList[] =
  1187. {
  1188. { TEXT("Software\\Microsoft\\MediaPlayer\\Player\\Settings"), TEXT("Client ID") }, // Delete unique Media Player settings.
  1189. { TEXT("Software\\Microsoft\\Windows Media\\WMSDK\\General"), TEXT("UniqueID") }, // Delete unique Media Player settings.
  1190. { TEXT("Software\\Microsoft\\Internet Connection Wizard"), TEXT("Completed") }, // Delete this key to cause ICW to run again.
  1191. { TEXT("Software\\Microsoft\\MessengerService"), TEXT("PassportBalloon") }, // Cleanup for MS Messenger.
  1192. { TEXT("Software\\Microsoft\\MessengerService"), TEXT("FirstTimeUser") }, // Cleanup for MS Messenger.
  1193. { TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VisualEffects\\Fontsmoothing"), TEXT("DefaultApplied") }, // Makes it so clear type setting is applied again when user logs on.
  1194. { TEXT("Software\\Microsoft\\Protected Storage System Provider"), TEXT("*") }, // Delete any entry from the Protected System Provider. This is a special case..
  1195. };
  1196. TCHAR szSddl[] = TEXT("O:BAD:P(A;CI;GA;;;BA)");
  1197. // We need this privilege to make sure that we can take ownership of the key if somebody else owns it.
  1198. //
  1199. pSetupEnablePrivilege(SE_TAKE_OWNERSHIP_NAME, TRUE);
  1200. //
  1201. // Enumerate HKEY_USERS
  1202. // For each key under HKEY_USERS do the following.
  1203. //
  1204. while ( RegEnumKey( HKEY_USERS, i++, szKeyname, ARRAYSIZE(szKeyname)) == ERROR_SUCCESS )
  1205. {
  1206. // Open the key for this user.
  1207. //
  1208. if ( RegOpenKeyEx( HKEY_USERS, szKeyname, 0L, KEY_ALL_ACCESS, &hKey ) == ERROR_SUCCESS )
  1209. {
  1210. for ( iElem = 0; iElem < (sizeof( rvList ) / sizeof( rvList[0] )); iElem++ )
  1211. {
  1212. // Delete Values from each key.
  1213. //
  1214. if ( RegOpenKeyEx( hKey, rvList[iElem].szKey, 0L, KEY_ALL_ACCESS, &oKey ) == ERROR_SUCCESS )
  1215. {
  1216. if ( ( rvList[iElem].szValue[0] == TEXT('*') ) && ( rvList[iElem].szValue[1] == NULLCHR ) )
  1217. {
  1218. // If a wild card is specified, delete all the keys under under this key.
  1219. //
  1220. j = 0;
  1221. while ( RegEnumKey( oKey, j++, szKeyname, ARRAYSIZE(szKeyname)) == ERROR_SUCCESS )
  1222. {
  1223. if ( ReplaceSecurityInRegistry(oKey, szKeyname, szSddl, TRUE) )
  1224. {
  1225. AnyErrors = SHDeleteKey(oKey, szKeyname);
  1226. }
  1227. else
  1228. {
  1229. AnyErrors = TRUE;
  1230. }
  1231. }
  1232. }
  1233. else
  1234. {
  1235. RegDeleteValue( oKey, rvList[iElem].szValue );
  1236. RegCloseKey( oKey );
  1237. }
  1238. }
  1239. else
  1240. AnyErrors = TRUE;
  1241. }
  1242. RegCloseKey(hKey);
  1243. }
  1244. else
  1245. AnyErrors = TRUE;
  1246. }
  1247. return (!AnyErrors);
  1248. }
  1249. BOOL
  1250. NukeMruList(
  1251. VOID
  1252. )
  1253. /*++
  1254. ===============================================================================
  1255. Routine Description:
  1256. This routine clears the MRU lists on the machine.
  1257. Arguments:
  1258. None.
  1259. Return Value:
  1260. ===============================================================================
  1261. --*/
  1262. {
  1263. BOOL AnyErrors = FALSE;
  1264. BOOL b;
  1265. LONG rc;
  1266. WCHAR keyname[1024];
  1267. WCHAR netname[1024];
  1268. HKEY rkey;
  1269. HKEY ukey;
  1270. HKEY nkey;
  1271. HKEY hOpenKey;
  1272. INT i;
  1273. INT j;
  1274. AnyErrors = FALSE;
  1275. //
  1276. // Enumerate HKEY_USERS
  1277. // For each key under HKEY_USERS clean out MRU and Netconnections
  1278. //
  1279. i=0;
  1280. while ( (rc = RegEnumKey( HKEY_USERS, i, keyname, 1024)) == ERROR_SUCCESS ) {
  1281. //
  1282. // open this user key
  1283. //
  1284. rc = RegCreateKeyEx(HKEY_USERS, keyname, 0L, NULL,
  1285. REG_OPTION_BACKUP_RESTORE,
  1286. KEY_CREATE_SUB_KEY, NULL, &ukey, NULL);
  1287. if(rc == NO_ERROR) {
  1288. //
  1289. // special case Network because of subkeys
  1290. //
  1291. rc = RegCreateKeyEx(ukey, L"Network", 0L, NULL,
  1292. REG_OPTION_BACKUP_RESTORE,
  1293. KEY_CREATE_SUB_KEY, NULL, &nkey, NULL);
  1294. if (rc == NO_ERROR) {
  1295. j=0;
  1296. while ( (rc = RegEnumKey( nkey, j, netname, 1024)) == ERROR_SUCCESS ) {
  1297. // HKEY_CURRENT_USER\Network
  1298. rc = RegDeleteKey( nkey, netname );
  1299. if((rc != NO_ERROR) && (rc != ERROR_FILE_NOT_FOUND))
  1300. AnyErrors = TRUE;
  1301. j++; // increment network key
  1302. }
  1303. }
  1304. //
  1305. // HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Network\Persistent Connections
  1306. //
  1307. if (!ResetRegistryKey(
  1308. ukey,
  1309. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Network",
  1310. L"Persistent Connections") )
  1311. AnyErrors = TRUE;
  1312. //
  1313. // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs
  1314. //
  1315. if (!ResetRegistryKey(
  1316. ukey,
  1317. L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
  1318. L"RecentDocs") )
  1319. AnyErrors = TRUE;
  1320. //
  1321. // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced,StartMenuInit
  1322. //
  1323. if ( ERROR_SUCCESS == RegOpenKeyEx(ukey,
  1324. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"),
  1325. 0,
  1326. KEY_ALL_ACCESS,
  1327. &hOpenKey) )
  1328. {
  1329. // Set the value in the registry
  1330. //
  1331. RegDeleteValue(hOpenKey,
  1332. TEXT("StartMenuInit"));
  1333. // Close the key
  1334. //
  1335. RegCloseKey(hOpenKey);
  1336. }
  1337. //
  1338. // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU
  1339. //
  1340. if (!ResetRegistryKey(
  1341. ukey,
  1342. L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
  1343. L"RunMRU") )
  1344. AnyErrors = TRUE;
  1345. }
  1346. i++;
  1347. }
  1348. return (!AnyErrors);
  1349. }
  1350. VOID
  1351. NukeEventLogs(
  1352. VOID
  1353. )
  1354. /*++
  1355. ===============================================================================
  1356. Routine Description:
  1357. This routine clears the eventlogs. Ignore any errors here.
  1358. Arguments:
  1359. None.
  1360. Return Value:
  1361. ===============================================================================
  1362. --*/
  1363. {
  1364. HANDLE hEventLog;
  1365. hEventLog = OpenEventLog( NULL, TEXT("System") );
  1366. if (hEventLog) {
  1367. ClearEventLog( hEventLog, NULL );
  1368. CloseEventLog( hEventLog );
  1369. }
  1370. hEventLog = OpenEventLog( NULL, TEXT("Application") );
  1371. if (hEventLog) {
  1372. ClearEventLog( hEventLog, NULL );
  1373. CloseEventLog( hEventLog );
  1374. }
  1375. hEventLog = OpenEventLog( NULL, TEXT("Security") );
  1376. if (hEventLog) {
  1377. ClearEventLog( hEventLog, NULL );
  1378. CloseEventLog( hEventLog );
  1379. }
  1380. }
  1381. VOID
  1382. NukeSmsSettings(
  1383. VOID
  1384. )
  1385. /*++
  1386. ===============================================================================
  1387. Routine Description:
  1388. This routine clears the SMS client specific settings on system:
  1389. - clears unique settings for SMS from the registry and ini files.
  1390. Arguments:
  1391. None.
  1392. Return Value:
  1393. None.
  1394. Remarks:
  1395. Part of the clearing requires blanking out certain INI files.
  1396. ===============================================================================
  1397. --*/
  1398. {
  1399. HKEY hkSms = NULL;
  1400. TCHAR szWindowsDir[MAX_PATH] = TEXT("\0"),
  1401. szIniFile[MAX_PATH] = TEXT("\0"),
  1402. szDatFile[MAX_PATH] = TEXT("\0"),
  1403. szDefaultValue[] = TEXT("\0");
  1404. // Remove HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
  1405. //
  1406. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\SMS\\Client\\Configuration\\Client Properties"), &hkSms)) {
  1407. //
  1408. // ISSUE-2002/02/26-brucegr: Should be adding one character to length field for null-terminator
  1409. //
  1410. RegSetValueEx(hkSms, TEXT("SMS Unique Identifier"), 0, REG_SZ, (LPBYTE)szDefaultValue, (lstrlen(szDefaultValue)*sizeof(TCHAR)));
  1411. RegCloseKey(hkSms);
  1412. }
  1413. // Clear the SMS Unique ID from INI files
  1414. //
  1415. if ( GetWindowsDirectory(szWindowsDir, MAX_PATH) && *szWindowsDir )
  1416. {
  1417. StringCchCopy ( szIniFile, AS ( szIniFile ), szWindowsDir);
  1418. OPKAddPathN (szIniFile, TEXT("ms\\sms\\core\\data"), AS ( szIniFile ) );
  1419. if (PathIsDirectory(szIniFile)) {
  1420. OPKAddPathN(szIniFile, TEXT("sms1x.ini"), AS ( szIniFile ));
  1421. WritePrivateProfileString(TEXT("SMS"), TEXT("SMS Unique ID"), TEXT(""), szIniFile);
  1422. }
  1423. StringCchCopy ( szIniFile, AS ( szIniFile ), szWindowsDir);
  1424. if (PathIsDirectory(szIniFile)) {
  1425. OPKAddPathN(szIniFile, TEXT("smscfg.ini"), AS ( szIniFile ) );
  1426. WritePrivateProfileString(TEXT("Configuration - Client Properties"), TEXT("SMS Unique Identifier"), TEXT(""), szIniFile);
  1427. }
  1428. // Make sure we can delete the file SMS Unique ID file
  1429. //
  1430. StringCchCopy (szDatFile, AS ( szDatFile ), szWindowsDir);
  1431. OPKAddPathN(szDatFile, TEXT("ms\\sms\\core\\data"), AS ( szDatFile ) );
  1432. if (PathIsDirectory(szDatFile)) {
  1433. OPKAddPathN(szDatFile, TEXT("smsuid.dat"), AS ( szDatFile ) );
  1434. SetFileAttributes(szDatFile, FILE_ATTRIBUTE_NORMAL);
  1435. DeleteFile(szDatFile);
  1436. }
  1437. }
  1438. }
  1439. void RemoveDir(LPCTSTR lpDirectory, BOOL fDeleteDir)
  1440. {
  1441. WIN32_FIND_DATA FileFound;
  1442. HANDLE hFile;
  1443. // Validate the parameters.
  1444. //
  1445. if ( ( lpDirectory == NULL ) ||
  1446. ( *lpDirectory == TEXT('\0') ) ||
  1447. ( !SetCurrentDirectory(lpDirectory) ) )
  1448. {
  1449. return;
  1450. }
  1451. //
  1452. // ISSUE-2002/02/26-brucegr: We just called SetCurrentDirectory above!
  1453. //
  1454. // Process all the files and directories in the directory passed in.
  1455. //
  1456. SetCurrentDirectory(lpDirectory);
  1457. if ( (hFile = FindFirstFile(TEXT("*"), &FileFound)) != INVALID_HANDLE_VALUE )
  1458. {
  1459. do
  1460. {
  1461. // First check to see if this is a file (not a directory).
  1462. //
  1463. if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
  1464. {
  1465. // Make sure we clear the readonly flag
  1466. //
  1467. SetFileAttributes(FileFound.cFileName, FILE_ATTRIBUTE_NORMAL);
  1468. DeleteFile(FileFound.cFileName);
  1469. }
  1470. // Otherwise, make sure the directory is not "." or "..".
  1471. //
  1472. else if ( ( lstrcmp(FileFound.cFileName, TEXT(".")) ) &&
  1473. ( lstrcmp(FileFound.cFileName, TEXT("..")) ) )
  1474. {
  1475. RemoveDir(FileFound.cFileName, TRUE);
  1476. }
  1477. }
  1478. while ( FindNextFile(hFile, &FileFound) );
  1479. FindClose(hFile);
  1480. }
  1481. // Go to the parent directory and remove the current one.
  1482. // We have to make sure and reset the readonly attributes
  1483. // on the dir also.
  1484. //
  1485. SetCurrentDirectory(TEXT(".."));
  1486. if (fDeleteDir)
  1487. {
  1488. SetFileAttributes(lpDirectory, FILE_ATTRIBUTE_NORMAL);
  1489. RemoveDirectory(lpDirectory);
  1490. }
  1491. }
  1492. //
  1493. // DeleteCacheCookies was copy'n'pasted from Cachecpl.cpp
  1494. //
  1495. // Any changes to either version should probably be transfered to both.
  1496. // Minor difference from new/delete (.cpp) to LocalAlloc/LocalFree (.c).
  1497. //
  1498. BOOL DeleteCacheCookies()
  1499. {
  1500. BOOL bRetval = TRUE;
  1501. DWORD dwEntrySize, dwLastEntrySize;
  1502. LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntry;
  1503. HANDLE hCacheDir = NULL;
  1504. dwEntrySize = dwLastEntrySize = MAX_CACHE_ENTRY_INFO_SIZE;
  1505. lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA) LocalAlloc(LPTR, sizeof(BYTE) * dwEntrySize);
  1506. if( lpCacheEntry == NULL)
  1507. {
  1508. bRetval = FALSE;
  1509. goto Exit;
  1510. }
  1511. lpCacheEntry->dwStructSize = dwEntrySize;
  1512. Again:
  1513. if (!(hCacheDir = FindFirstUrlCacheEntryA("cookie:",lpCacheEntry,&dwEntrySize)))
  1514. {
  1515. LocalFree(lpCacheEntry);
  1516. switch(GetLastError())
  1517. {
  1518. case ERROR_NO_MORE_ITEMS:
  1519. goto Exit;
  1520. case ERROR_INSUFFICIENT_BUFFER:
  1521. lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA)
  1522. LocalAlloc(LPTR, sizeof(BYTE) * dwEntrySize );
  1523. if( lpCacheEntry == NULL)
  1524. {
  1525. bRetval = FALSE;
  1526. goto Exit;
  1527. }
  1528. lpCacheEntry->dwStructSize = dwLastEntrySize = dwEntrySize;
  1529. goto Again;
  1530. default:
  1531. bRetval = FALSE;
  1532. goto Exit;
  1533. }
  1534. }
  1535. do
  1536. {
  1537. if (lpCacheEntry->CacheEntryType & COOKIE_CACHE_ENTRY)
  1538. DeleteUrlCacheEntryA(lpCacheEntry->lpszSourceUrlName);
  1539. dwEntrySize = dwLastEntrySize;
  1540. Retry:
  1541. if (!FindNextUrlCacheEntryA(hCacheDir,lpCacheEntry, &dwEntrySize))
  1542. {
  1543. LocalFree(lpCacheEntry);
  1544. switch(GetLastError())
  1545. {
  1546. case ERROR_NO_MORE_ITEMS:
  1547. goto Exit;
  1548. case ERROR_INSUFFICIENT_BUFFER:
  1549. lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA)
  1550. LocalAlloc(LPTR, sizeof(BYTE) * dwEntrySize );
  1551. if( lpCacheEntry == NULL)
  1552. {
  1553. bRetval = FALSE;
  1554. goto Exit;
  1555. }
  1556. lpCacheEntry->dwStructSize = dwLastEntrySize = dwEntrySize;
  1557. goto Retry;
  1558. default:
  1559. bRetval = FALSE;
  1560. goto Exit;
  1561. }
  1562. }
  1563. }
  1564. while (TRUE);
  1565. Exit:
  1566. if (hCacheDir)
  1567. FindCloseUrlCache(hCacheDir);
  1568. return bRetval;
  1569. }
  1570. void ClearIEHistory (
  1571. VOID
  1572. )
  1573. /*++
  1574. ===============================================================================
  1575. Routine Description:
  1576. This routine clears the IE History.
  1577. Arguments:
  1578. None.
  1579. Return Value:
  1580. ===============================================================================
  1581. --*/
  1582. {
  1583. IUrlHistoryStg2* pHistory = NULL ; // We need this interface for clearing the history.
  1584. HRESULT hr;
  1585. HKEY hkeyInternational = NULL;
  1586. ULONG_PTR lres = 0;
  1587. // Remove all the entries here.
  1588. RegDeleteKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\TypedURLs"));
  1589. RegDeleteKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU"));
  1590. // this broadcast will nuke the address bars
  1591. SendMessageTimeoutW( HWND_BROADCAST,
  1592. WM_SETTINGCHANGE,
  1593. 0,
  1594. (LPARAM)TEXT("Software\\Microsoft\\Internet Explorer\\TypedURLs"),
  1595. SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG,
  1596. 30 * 1000,
  1597. &lres);
  1598. SendMessageTimeoutW( HWND_BROADCAST,
  1599. WM_SETTINGCHANGE,
  1600. 0,
  1601. (LPARAM)TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU"),
  1602. SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG,
  1603. 30 * 1000,
  1604. &lres);
  1605. // we remove these reg values when history is
  1606. // cleared. This will reset the encoding menu UI to the defaults.
  1607. if (ERROR_SUCCESS ==
  1608. RegOpenKeyEx(
  1609. HKEY_CURRENT_USER,
  1610. TEXT("Software\\Microsoft\\Internet Explorer\\International"),
  1611. 0,
  1612. KEY_WRITE,
  1613. &hkeyInternational))
  1614. {
  1615. ASSERT(hkeyInternational);
  1616. RegDeleteValue(hkeyInternational, TEXT("CpCache"));
  1617. RegDeleteValue(hkeyInternational, TEXT("CNum_CpCache"));
  1618. RegCloseKey(hkeyInternational);
  1619. }
  1620. //
  1621. // Init the Com Library
  1622. //
  1623. CoInitialize(NULL);
  1624. // Load the correct Class and request IUrlHistoryStg2
  1625. hr = CoCreateInstance( &CLSID_CUrlHistory,
  1626. NULL,
  1627. CLSCTX_INPROC_SERVER,
  1628. &IID_IUrlHistoryStg2,
  1629. &pHistory );
  1630. //
  1631. // If succeeded Clear the history
  1632. if (SUCCEEDED(hr))
  1633. {
  1634. // Clear the IE History
  1635. hr = IUrlHistoryStg2_ClearHistory(pHistory);
  1636. }
  1637. // Release our reference to the
  1638. if ( pHistory )
  1639. {
  1640. IUrlHistoryStg2_Release(pHistory);
  1641. }
  1642. // Un Init the Com Library
  1643. CoUninitialize();
  1644. }
  1645. void NukeTemporaryFiles(
  1646. VOID
  1647. )
  1648. /*++
  1649. ===============================================================================
  1650. Routine Description:
  1651. This routine clears the temporary folder and recycle bin for template user.
  1652. Arguments:
  1653. None.
  1654. Return Value:
  1655. ===============================================================================
  1656. --*/
  1657. {
  1658. TCHAR szTempDir[MAX_PATH] = TEXT(""),
  1659. szTempInetFilesDir[MAX_PATH] = TEXT(""),
  1660. szProfileDir[MAX_PATH] = TEXT(""),
  1661. szCurrentDir[MAX_PATH] = TEXT("");
  1662. DWORD dwSize;
  1663. HANDLE hFile;
  1664. WIN32_FIND_DATA FileFound;
  1665. //
  1666. // Save our current directory, so we can set it back later.
  1667. //
  1668. GetCurrentDirectory(MAX_PATH, szCurrentDir);
  1669. dwSize = sizeof(szProfileDir)/sizeof(szProfileDir[0]);
  1670. if ( !GetProfilesDirectory(szProfileDir, &dwSize) &&
  1671. !SetCurrentDirectory(szProfileDir) )
  1672. return;
  1673. //
  1674. // ISSUE-2002/02/26-brucegr: We just called SetCurrentDirectory above!
  1675. //
  1676. //
  1677. // Clear the I.E History folder.
  1678. //
  1679. ClearIEHistory ( ) ;
  1680. //
  1681. // Clear tmp files for all profile directories.
  1682. //
  1683. SetCurrentDirectory(szProfileDir);
  1684. if ( (hFile = FindFirstFile(TEXT("*"), &FileFound)) != INVALID_HANDLE_VALUE )
  1685. {
  1686. do
  1687. {
  1688. // Otherwise, make sure the directory is not "." or "..".
  1689. //
  1690. if ( (FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  1691. ( lstrcmp(FileFound.cFileName, TEXT(".")) ) &&
  1692. ( lstrcmp(FileFound.cFileName, TEXT("..")) ) )
  1693. {
  1694. TCHAR szTemp1[MAX_PATH] = TEXT("");
  1695. //
  1696. // Clear the Temp folder.
  1697. //
  1698. if ( LoadString(ghInstance, IDS_TEMP_DIR, szTemp1, MAX_PATH) )
  1699. {
  1700. StringCchCopy (szTempDir, AS ( szTempDir ), szProfileDir);
  1701. OPKAddPathN(szTempDir, FileFound.cFileName, AS ( szTempDir ) );
  1702. OPKAddPathN(szTempDir, szTemp1, AS ( szTempDir ) );
  1703. RemoveDir(szTempDir, FALSE);
  1704. }
  1705. //
  1706. // Clear the History.IE5 folder.
  1707. //
  1708. if ( LoadString(ghInstance, IDS_HISTORY_DIR_IE5, szTemp1, MAX_PATH) )
  1709. {
  1710. StringCchCopy (szTempDir, AS ( szTempDir ), szProfileDir);
  1711. OPKAddPathN(szTempDir, FileFound.cFileName, AS ( szTempDir ) );
  1712. OPKAddPathN(szTempDir, szTemp1, AS ( szTempDir ) );
  1713. RemoveDir(szTempDir, TRUE);
  1714. }
  1715. //
  1716. // Clear the History folder.
  1717. //
  1718. if ( LoadString(ghInstance, IDS_HISTORY_DIR, szTemp1, MAX_PATH) )
  1719. {
  1720. StringCchCopy (szTempDir, AS ( szTempDir ), szProfileDir);
  1721. OPKAddPathN(szTempDir, FileFound.cFileName, AS ( szTempDir ) );
  1722. OPKAddPathN(szTempDir, szTemp1, AS ( szTempDir ) );
  1723. RemoveDir(szTempDir, FALSE);
  1724. }
  1725. //
  1726. // Clear the Local Settings\Application Data\Microsoft\Credentials.
  1727. //
  1728. if ( !NoSidGen )
  1729. {
  1730. if ( LoadString(ghInstance, IDS_SID_DIR1, szTemp1, MAX_PATH) )
  1731. {
  1732. StringCchCopy (szTempDir, AS ( szTempDir ), szProfileDir);
  1733. OPKAddPathN(szTempDir, FileFound.cFileName, AS ( szTempDir ) );
  1734. OPKAddPathN(szTempDir, szTemp1, AS ( szTempDir ) );
  1735. RemoveDir(szTempDir, FALSE);
  1736. }
  1737. //
  1738. // Clear the Application Data\Microsoft\Credentials
  1739. //
  1740. if ( LoadString(ghInstance, IDS_SID_DIR2, szTemp1, MAX_PATH) )
  1741. {
  1742. StringCchCopy (szTempDir, AS ( szTempDir ), szProfileDir);
  1743. OPKAddPathN(szTempDir, FileFound.cFileName, AS ( szTempDir ) );
  1744. OPKAddPathN(szTempDir, szTemp1, AS ( szTempDir ) );
  1745. RemoveDir(szTempDir, FALSE);
  1746. }
  1747. //
  1748. // Clear the Application Data\Microsoft\Crypto\\RSA.
  1749. //
  1750. if ( LoadString(ghInstance, IDS_SID_DIR3, szTemp1, MAX_PATH) )
  1751. {
  1752. StringCchCopy (szTempDir, AS ( szTempDir ), szProfileDir);
  1753. OPKAddPathN(szTempDir, FileFound.cFileName, AS ( szTempDir ) );
  1754. OPKAddPathN(szTempDir, szTemp1, AS ( szTempDir ) );
  1755. RemoveDir(szTempDir, FALSE);
  1756. }
  1757. }
  1758. //
  1759. // Clear the Temporary Internet files and cookies.
  1760. //
  1761. if ( LoadString(ghInstance, IDS_TEMP_INTERNET_DIR, szTemp1, MAX_PATH) )
  1762. {
  1763. StringCchCopy ( szTempInetFilesDir, AS ( szTempInetFilesDir), szProfileDir);
  1764. OPKAddPathN(szTempInetFilesDir, FileFound.cFileName, AS ( szTempInetFilesDir ) );
  1765. OPKAddPathN(szTempInetFilesDir, szTemp1, AS ( szTempInetFilesDir ) );
  1766. FreeUrlCacheSpace(szTempInetFilesDir, 100, 0 /*remove all*/);
  1767. DeleteCacheCookies();
  1768. RemoveDir(szTempInetFilesDir, FALSE);
  1769. }
  1770. }
  1771. }
  1772. while ( FindNextFile(hFile, &FileFound) );
  1773. FindClose(hFile);
  1774. }
  1775. //
  1776. // Set back our current directory.
  1777. //
  1778. SetCurrentDirectory(szCurrentDir);
  1779. //
  1780. // Clear any recycle bin files.
  1781. //
  1782. SHEmptyRecycleBin(NULL, NULL, SHERB_NOSOUND|SHERB_NOCONFIRMATION|SHERB_NOPROGRESSUI);
  1783. }
  1784. DWORD NukeLKGControlSet(
  1785. VOID
  1786. )
  1787. /*++
  1788. ===============================================================================
  1789. Routine Description:
  1790. This routine will delete the last known good control set from the registry.
  1791. The reason is LKG doesn't make sense for the first boot. Also, if the BIOS
  1792. clock of a cloned machine is earlier than the creation time of a cloned
  1793. image, any change made to the CurrentControlSet before adjusting the clock
  1794. will not sync to LKG.
  1795. The code is adapted from base\screg\sc\server\bootcfg.cxx
  1796. Since we can't delete LKG directly because quite a few of the subkeys are
  1797. in use, this routine changes the system\select!LastKnownGood to a new Id
  1798. instead.
  1799. Arguments:
  1800. None.
  1801. Return Value:
  1802. NO_ERROR or other WIN32 error.
  1803. ===============================================================================
  1804. --*/
  1805. {
  1806. //
  1807. // ISSUE-2002/02/26-brucegr: Should rewrite to get highest DWORD value in Select key, then increment and write to LKG.
  1808. //
  1809. #define SELECT_KEY L"system\\select"
  1810. #define CURRENT_ID 0
  1811. #define DEFAULT_ID 1
  1812. #define LKG_ID 2
  1813. #define FAILED_ID 3
  1814. #define NUM_IDS 4
  1815. //
  1816. // ISSUE-2002/02/26-brucegr: Get rid of NUM_IDS and use ARRAYSIZE macro!
  1817. //
  1818. static const LPCWSTR SelectValueNames[NUM_IDS] =
  1819. {
  1820. L"Current",
  1821. L"Default",
  1822. L"LastKnownGood",
  1823. L"Failed"
  1824. };
  1825. DWORD idArray[NUM_IDS];
  1826. HKEY selectKey = 0;
  1827. DWORD status = NO_ERROR;
  1828. DWORD bufferSize = 0;
  1829. DWORD newId = 0;
  1830. DWORD i = 0;
  1831. //
  1832. // Get the Select Key
  1833. //
  1834. status = RegOpenKeyEx(
  1835. HKEY_LOCAL_MACHINE,
  1836. SELECT_KEY,
  1837. 0L,
  1838. KEY_QUERY_VALUE | KEY_SET_VALUE,
  1839. &selectKey);
  1840. if (status != NO_ERROR)
  1841. {
  1842. return status;
  1843. }
  1844. //
  1845. // Fill in the idArray
  1846. //
  1847. for (i = 0; i < NUM_IDS; i++)
  1848. {
  1849. bufferSize = sizeof(DWORD);
  1850. //
  1851. // ISSUE-2002/02/26-brucegr: Check data type matches REG_DWORD
  1852. //
  1853. status = RegQueryValueEx(
  1854. selectKey,
  1855. SelectValueNames[i],
  1856. NULL,
  1857. NULL,
  1858. (LPBYTE)&idArray[i],
  1859. &bufferSize);
  1860. if (status != NO_ERROR)
  1861. {
  1862. idArray[i] = 0;
  1863. }
  1864. }
  1865. status = ERROR_NO_MORE_ITEMS;
  1866. for(newId = 1; newId < 1000; newId++)
  1867. {
  1868. BOOL inArray = FALSE;
  1869. for(i = 0; i < NUM_IDS; i++)
  1870. {
  1871. if(idArray[i] == newId)
  1872. {
  1873. inArray = TRUE;
  1874. break;
  1875. }
  1876. }
  1877. if (!inArray)
  1878. {
  1879. status = RegSetValueEx(
  1880. selectKey,
  1881. SelectValueNames[LKG_ID],
  1882. 0,
  1883. REG_DWORD,
  1884. (LPBYTE)&newId,
  1885. sizeof(DWORD));
  1886. break;
  1887. }
  1888. }
  1889. RegCloseKey(selectKey);
  1890. return status;
  1891. }
  1892. BOOL
  1893. DeleteAdapterGuidsKeys(
  1894. VOID
  1895. )
  1896. {
  1897. HKEY hKey, hSubKey;
  1898. DWORD dwError = NO_ERROR;
  1899. int i = 0;
  1900. TCHAR SubKeyName[MAX_PATH * 2];
  1901. //
  1902. // Open HKLM\System\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}
  1903. //
  1904. dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1905. TEXT("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"),
  1906. 0,
  1907. KEY_ALL_ACCESS,
  1908. &hKey );
  1909. if(dwError != NO_ERROR)
  1910. {
  1911. SetLastError(dwError);
  1912. return FALSE;
  1913. }
  1914. //
  1915. // Now enumerate all subkeys. For each subkey delete the adapter GUID.
  1916. //
  1917. while( (dwError = RegEnumKey( hKey, i, SubKeyName, sizeof(SubKeyName)/sizeof(SubKeyName[0]))) == ERROR_SUCCESS)
  1918. {
  1919. //
  1920. // Check if the key is a probable GUID.
  1921. // If it's a GUID key, delete the adapter GUIDs only
  1922. //
  1923. if (SubKeyName[0] == TEXT('{'))
  1924. {
  1925. //
  1926. // If we were able to delete the key,then its okay, other wise
  1927. // increment the counter.
  1928. //
  1929. if ( ( dwError = SHDeleteKey(hKey, SubKeyName) ) != ERROR_SUCCESS )
  1930. i++;
  1931. }
  1932. else
  1933. {
  1934. //
  1935. // If we didn't find one go to next subkey.
  1936. //
  1937. i++;
  1938. }
  1939. }
  1940. RegCloseKey( hKey );
  1941. return TRUE;
  1942. }
  1943. BOOL
  1944. RemoveNetworkSettings(
  1945. LPTSTR lpszSysprepINFPath
  1946. )
  1947. /*++
  1948. ===============================================================================
  1949. Routine Description:
  1950. This routine will enumerate each physical NIC, call into the netsetup
  1951. code to save the settings, and then delete the network card.
  1952. When a new NIC is enumerated on the target machine, netsetup will apply the
  1953. settings that were saved away
  1954. If the LegacyNIC != 0 value exists in SYSPREP.INF in the [Unattended] section, then
  1955. the previous behavior will be preserved, since removing a legacy NIC card
  1956. will not work, because it will not be re-enumerated/detected on the next boot
  1957. Arguments:
  1958. lpszSysprepINFPath pointer to the SYSPREP.INF file. Can be NULL, in which case
  1959. a non-legacy NIC is assumed
  1960. Return Value:
  1961. TRUE if successful.
  1962. FALSE if any errors encountered
  1963. ===============================================================================
  1964. --*/
  1965. {
  1966. HDEVINFO DeviceInfoSet;
  1967. DWORD dwIdx;
  1968. SP_DEVINFO_DATA DevInfoData;
  1969. HKEY hDevRegKey;
  1970. DWORD dwChar;
  1971. DWORD dwSize;
  1972. FARPROC pNetSetupPrepareSysPrep = NULL;
  1973. BOOL DoLegacy = FALSE;
  1974. HMODULE hNetShell = LoadLibraryA( "netshell.dll" );
  1975. if (hNetShell) {
  1976. pNetSetupPrepareSysPrep = GetProcAddress( hNetShell, "NetSetupPrepareSysPrep" );
  1977. if (!pNetSetupPrepareSysPrep) {
  1978. DoLegacy = TRUE;
  1979. FreeLibrary( hNetShell );
  1980. }
  1981. }
  1982. else {
  1983. return FALSE;
  1984. }
  1985. // See if we are dealing with a legacy NIC
  1986. if ((lpszSysprepINFPath != NULL)
  1987. && GetPrivateProfileInt( TEXT( "Unattended" ),
  1988. TEXT( "LegacyNIC" ),
  1989. 0,
  1990. lpszSysprepINFPath)) {
  1991. //
  1992. // ISSUE-2002/02/26-brucegr: If we set DoLegacy to TRUE, then we don't free hNetShell!
  1993. //
  1994. DoLegacy = TRUE;
  1995. }
  1996. if (!DoLegacy)
  1997. {
  1998. // Call the netcfg function to save the networking settings
  1999. pNetSetupPrepareSysPrep();
  2000. FreeLibrary( hNetShell );
  2001. // Enumerate and delete all phyiscal NICs
  2002. DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_NET,
  2003. NULL,
  2004. NULL,
  2005. DIGCF_PRESENT);
  2006. if(DeviceInfoSet == INVALID_HANDLE_VALUE)
  2007. {
  2008. return FALSE;
  2009. }
  2010. dwIdx = 0;
  2011. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  2012. while (SetupDiEnumDeviceInfo(DeviceInfoSet, dwIdx, &DevInfoData))
  2013. {
  2014. hDevRegKey = SetupDiOpenDevRegKey(DeviceInfoSet,
  2015. &DevInfoData,
  2016. DICS_FLAG_GLOBAL,
  2017. 0,
  2018. DIREG_DRV,
  2019. KEY_READ);
  2020. if (hDevRegKey == INVALID_HANDLE_VALUE)
  2021. {
  2022. // Not sure why it would ever return INVALID_HANDLE_VALUE, but
  2023. // we don't care and should continue.
  2024. ++dwIdx;
  2025. continue;
  2026. }
  2027. dwChar = 0;
  2028. dwSize = sizeof(DWORD);
  2029. RegQueryValueEx(hDevRegKey,
  2030. L"Characteristics",
  2031. NULL,
  2032. NULL,
  2033. (LPBYTE) &dwChar,
  2034. &dwSize);
  2035. RegCloseKey(hDevRegKey);
  2036. if (dwChar & NCF_PHYSICAL)
  2037. {
  2038. // This is one to delete
  2039. SetupDiCallClassInstaller(DIF_REMOVE, DeviceInfoSet, &DevInfoData);
  2040. }
  2041. ++dwIdx;
  2042. }
  2043. // Cleanup
  2044. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  2045. }
  2046. //
  2047. // Delete the adapter GUIDs keys so we don't get multiple Local Area Connection # displays.
  2048. //
  2049. return DeleteAdapterGuidsKeys();
  2050. }
  2051. BOOL
  2052. ProcessUniquenessValue(
  2053. LPTSTR lpszDLLPath
  2054. )
  2055. {
  2056. BOOL bRet = FALSE;
  2057. //
  2058. // Make sure we were passed something valid...
  2059. //
  2060. if ( lpszDLLPath && *lpszDLLPath )
  2061. {
  2062. LPWSTR pSrch;
  2063. //
  2064. // Look for the comma that separates the DLL and the entrypoint...
  2065. //
  2066. if ( pSrch = wcschr( lpszDLLPath, L',' ) )
  2067. {
  2068. CHAR szEntryPointA[MAX_PATH] = {0};
  2069. // We found one, now NULL the string at the comma...
  2070. //
  2071. *(pSrch++) = L'\0';
  2072. //
  2073. // If there's still something after the comma, and we can convert it
  2074. // into ANSI for GetProcAddress, then let's proceed...
  2075. //
  2076. if ( *pSrch &&
  2077. ( 0 != WideCharToMultiByte( CP_ACP,
  2078. 0,
  2079. pSrch,
  2080. -1,
  2081. szEntryPointA,
  2082. ARRAYSIZE(szEntryPointA),
  2083. NULL,
  2084. NULL ) ) )
  2085. {
  2086. HMODULE hModule = NULL;
  2087. try
  2088. {
  2089. //
  2090. // Load and call the entry point.
  2091. //
  2092. if ( hModule = LoadLibrary( lpszDLLPath ) )
  2093. {
  2094. FARPROC fpEntryPoint;
  2095. if ( fpEntryPoint = GetProcAddress(hModule, szEntryPointA) )
  2096. {
  2097. //
  2098. // Do it, ignoring any return value/errors
  2099. //
  2100. fpEntryPoint();
  2101. //
  2102. // We made it this far, consider this a success...
  2103. //
  2104. bRet = TRUE;
  2105. }
  2106. }
  2107. }
  2108. except(EXCEPTION_EXECUTE_HANDLER)
  2109. {
  2110. //
  2111. // We don't do anything with the exception code...
  2112. //
  2113. }
  2114. //
  2115. // Free the library outside the try/except block in case the function faulted.
  2116. //
  2117. if ( hModule )
  2118. {
  2119. FreeLibrary( hModule );
  2120. }
  2121. }
  2122. }
  2123. }
  2124. return bRet;
  2125. }
  2126. VOID
  2127. ProcessUniquenessKey(
  2128. BOOL fBeforeReseal
  2129. )
  2130. {
  2131. HKEY hKey;
  2132. TCHAR szRegPath[MAX_PATH] = {0};
  2133. LPTSTR lpszBasePath = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\SysPrep\\");
  2134. //
  2135. // Build a path to the registry key we want to process...
  2136. //
  2137. lstrcpyn( szRegPath, lpszBasePath, ARRAYSIZE(szRegPath) );
  2138. lstrcpyn( szRegPath + lstrlen(szRegPath),
  2139. fBeforeReseal ? TEXT("SysprepBeforeExecute") : TEXT("SysprepAfterExecute"),
  2140. ARRAYSIZE(szRegPath) - lstrlen(szRegPath) );
  2141. //
  2142. // We want to make sure an Administrator is doing this, so get KEY_ALL_ACCESS
  2143. //
  2144. if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2145. szRegPath,
  2146. 0,
  2147. KEY_ALL_ACCESS,
  2148. &hKey ) )
  2149. {
  2150. DWORD dwValues = 0,
  2151. dwMaxValueLen = 0,
  2152. dwMaxValueNameLen = 0;
  2153. //
  2154. // Query the key to find out some information we care about...
  2155. //
  2156. if ( ( ERROR_SUCCESS == RegQueryInfoKey( hKey, // hKey
  2157. NULL, // lpClass
  2158. NULL, // lpcClass
  2159. NULL, // lpReserved
  2160. NULL, // lpcSubKeys
  2161. NULL, // lpcMaxSubKeyLen
  2162. NULL, // lpcMaxClassLen
  2163. &dwValues, // lpcValues
  2164. &dwMaxValueNameLen, // lpcMaxValueNameLen
  2165. &dwMaxValueLen, // lpcMaxValueLen
  2166. NULL, // lpcbSecurityDescriptor
  2167. NULL ) ) && // lpftLastWriteTime
  2168. ( dwValues > 0 ) &&
  2169. ( dwMaxValueNameLen > 0) &&
  2170. ( dwMaxValueLen > 0 ) )
  2171. {
  2172. //
  2173. // Allocate buffers large enough to hold the data we want...
  2174. //
  2175. LPBYTE lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMaxValueLen );
  2176. LPTSTR lpValueName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ( dwMaxValueNameLen + 1 ) * sizeof(TCHAR) );
  2177. //
  2178. // Make sure we could allocate our buffers... otherwise bail out
  2179. //
  2180. if ( lpData && lpValueName )
  2181. {
  2182. DWORD dwIndex = 0;
  2183. BOOL bContinue = TRUE;
  2184. //
  2185. // Enumerate through the key values and call the DLL entrypoints...
  2186. //
  2187. while ( bContinue )
  2188. {
  2189. DWORD dwType,
  2190. cbData = dwMaxValueLen,
  2191. dwValueNameLen = dwMaxValueNameLen + 1;
  2192. bContinue = ( ERROR_SUCCESS == RegEnumValue( hKey,
  2193. dwIndex++,
  2194. lpValueName,
  2195. &dwValueNameLen,
  2196. NULL,
  2197. &dwType,
  2198. lpData,
  2199. &cbData ) );
  2200. //
  2201. // Make sure we got some data of the correct format...
  2202. //
  2203. if ( bContinue && ( REG_SZ == dwType ) && ( cbData > 0 ) )
  2204. {
  2205. //
  2206. // Now split up the string and call the entrypoints...
  2207. //
  2208. ProcessUniquenessValue( (LPTSTR) lpData );
  2209. }
  2210. }
  2211. }
  2212. //
  2213. // Clean up any buffers we may have allocated...
  2214. //
  2215. if ( lpData )
  2216. {
  2217. HeapFree( GetProcessHeap(), 0, lpData );
  2218. }
  2219. if ( lpValueName )
  2220. {
  2221. HeapFree( GetProcessHeap(), 0, lpValueName );
  2222. }
  2223. }
  2224. //
  2225. // Close the key...
  2226. //
  2227. RegCloseKey( hKey );
  2228. }
  2229. }
  2230. VOID
  2231. RunExternalUniqueness(
  2232. VOID
  2233. )
  2234. /*++
  2235. ===============================================================================
  2236. Routine Description:
  2237. This routine will call out to any external dlls that will allow
  2238. 3rd party apps to make their stuff unique.
  2239. We'll look in 2 inf files:
  2240. %windir%\inf\minioc.inf
  2241. %systemroot%\sysprep\provider.inf
  2242. In each of these files, we'll look in the [SysprepBeforeExecute] section
  2243. for any entries. The entries must look like:
  2244. dllname,entrypoint
  2245. We'll load the dll and call into the entry point. Errors are ignored.
  2246. Arguments:
  2247. None.
  2248. Return Value:
  2249. TRUE if successful.
  2250. FALSE if any errors encountered
  2251. ===============================================================================
  2252. --*/
  2253. {
  2254. FARPROC MyProc;
  2255. WCHAR InfPath[MAX_PATH];
  2256. WCHAR DllName[MAX_PATH];
  2257. WCHAR EntryPointNameW[MAX_PATH];
  2258. CHAR EntryPointNameA[MAX_PATH];
  2259. HINF AnswerInf;
  2260. HMODULE DllHandle;
  2261. INFCONTEXT InfContext;
  2262. DWORD i;
  2263. PCWSTR SectionName = L"SysprepBeforeExecute";
  2264. BOOL LineExists;
  2265. //
  2266. // =================================
  2267. // Minioc.inf
  2268. // =================================
  2269. //
  2270. //
  2271. // Build the path.
  2272. //
  2273. if (!GetWindowsDirectory( InfPath, MAX_PATH ))
  2274. return;
  2275. StringCchCat( InfPath, AS ( InfPath ), TEXT("\\inf\\minioc.inf") );
  2276. //
  2277. // See if he's got an entry
  2278. // section.
  2279. //
  2280. // NTRAID#NTBUG9-551511-2002/02/26-brucegr: We should make sure that MINIOC.INF is digitally signed before opening!
  2281. // ISSUE-2002/02/26-brucegr: You can OR in both INF style bits!
  2282. //
  2283. AnswerInf = SetupOpenInfFile( InfPath, NULL, INF_STYLE_WIN4, NULL );
  2284. if( AnswerInf == INVALID_HANDLE_VALUE ) {
  2285. //
  2286. // Try an old-style.
  2287. //
  2288. AnswerInf = SetupOpenInfFile( InfPath, NULL, INF_STYLE_OLDNT, NULL );
  2289. }
  2290. if( AnswerInf != INVALID_HANDLE_VALUE ) {
  2291. //
  2292. // Process each line in our section
  2293. //
  2294. LineExists = SetupFindFirstLine( AnswerInf, SectionName, NULL, &InfContext );
  2295. while( LineExists ) {
  2296. //
  2297. // ISSUE-2002/02/26-brucegr: Why not use SetupGetStringFieldA with EntryPointNameA?
  2298. //
  2299. if( SetupGetStringField( &InfContext, 1, DllName, sizeof(DllName)/sizeof(TCHAR), NULL) ) {
  2300. if( SetupGetStringField( &InfContext, 2, EntryPointNameW, sizeof(EntryPointNameW)/sizeof(TCHAR), NULL )) {
  2301. DllHandle = NULL;
  2302. //
  2303. // Load and call the entry point.
  2304. //
  2305. try {
  2306. if( DllHandle = LoadLibrary(DllName) ) {
  2307. //
  2308. // No Unicode version of GetProcAddress(). Convert string to ANSI.
  2309. //
  2310. i = WideCharToMultiByte(CP_ACP,0,EntryPointNameW,-1,EntryPointNameA,MAX_PATH,NULL,NULL);
  2311. if( MyProc = GetProcAddress(DllHandle, EntryPointNameA) ) {
  2312. //
  2313. // Do it, ignoring any return value/errors
  2314. //
  2315. MyProc();
  2316. }
  2317. }
  2318. } except(EXCEPTION_EXECUTE_HANDLER) {
  2319. }
  2320. if( DllHandle ) {
  2321. FreeLibrary( DllHandle );
  2322. }
  2323. }
  2324. }
  2325. LineExists = SetupFindNextLine(&InfContext,&InfContext);
  2326. }
  2327. SetupCloseInfFile( AnswerInf );
  2328. }
  2329. //
  2330. // ISSUE-2002/02/26-brucegr: Why are we duplicating the same INF processing code from above?!!!!
  2331. //
  2332. //
  2333. // =================================
  2334. // Provider.inf
  2335. // =================================
  2336. //
  2337. ProcessUniquenessKey( TRUE );
  2338. }
  2339. BOOL PrepForSidGen
  2340. (
  2341. void
  2342. )
  2343. {
  2344. DWORD l;
  2345. HKEY hKey, hKeyNew;
  2346. DWORD d;
  2347. DWORD Size;
  2348. DWORD Type;
  2349. TCHAR SetupExecuteValue[1024];
  2350. //
  2351. // =================================
  2352. // Set the value of the SetupExecute subkey.
  2353. // =================================
  2354. //
  2355. //
  2356. // Open the Session Manager key.
  2357. //
  2358. l = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2359. TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager"),
  2360. 0,
  2361. KEY_ALL_ACCESS,
  2362. &hKey );
  2363. if(l != NO_ERROR)
  2364. {
  2365. SetLastError(l);
  2366. return FALSE;
  2367. }
  2368. //
  2369. // Set the Key.
  2370. //
  2371. StringCchCopy ( SetupExecuteValue, AS ( SetupExecuteValue ), TEXT(SYSCLONE_PART2) );
  2372. SetupExecuteValue[lstrlen(SetupExecuteValue) + 1] = L'\0';
  2373. //
  2374. // ISSUE-2002/02/26-brucegr: Are we stomping anything that is already in SetupExecute?
  2375. //
  2376. l = RegSetValueEx(hKey,
  2377. TEXT("SetupExecute"),
  2378. 0,
  2379. REG_MULTI_SZ,
  2380. (CONST BYTE *)SetupExecuteValue,
  2381. (lstrlen( SetupExecuteValue ) + 2) * sizeof(TCHAR));
  2382. RegCloseKey(hKey);
  2383. if(l != NO_ERROR)
  2384. {
  2385. SetLastError(l);
  2386. return FALSE;
  2387. }
  2388. //
  2389. // =================================
  2390. // Let's bump the size of the registry quota a bit so that
  2391. // setupcl.exe can run. He'll pop it back down.
  2392. // =================================
  2393. //
  2394. //
  2395. // Open HKLM\System\CurrentControlSet\Control
  2396. //
  2397. l = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2398. TEXT("SYSTEM\\CurrentControlSet\\Control"),
  2399. 0,
  2400. KEY_ALL_ACCESS,
  2401. &hKey );
  2402. if(l != NO_ERROR)
  2403. {
  2404. SetLastError(l);
  2405. return FALSE;
  2406. }
  2407. //
  2408. // Query the value of the RegistrySizeLimit Key.
  2409. //
  2410. l = RegQueryValueEx(hKey,
  2411. TEXT("RegistrySizeLimit"),
  2412. NULL,
  2413. &Type,
  2414. (LPBYTE)&d,
  2415. &Size);
  2416. if( l == ERROR_SUCCESS )
  2417. {
  2418. //
  2419. // Got it. Bump the value.
  2420. //
  2421. d += REGISTRY_QUOTA_BUMP; //Increase by some amount to load the repair hives
  2422. //
  2423. // Set the key.
  2424. //
  2425. l = RegSetValueEx(hKey,
  2426. TEXT("RegistrySizeLimit"),
  2427. 0,
  2428. REG_DWORD,
  2429. (CONST BYTE *)&d,
  2430. sizeof(DWORD) );
  2431. if(l != NO_ERROR)
  2432. {
  2433. SetLastError(l);
  2434. //
  2435. // ISSUE-2002/02/26-brucegr: Need to call RegCloseKey!
  2436. //
  2437. return FALSE;
  2438. }
  2439. }
  2440. else
  2441. {
  2442. //
  2443. // Darn! The value probably doesn't exist.
  2444. // Ignore it and expect stuff to work. Only repair hives cannot be fixed
  2445. //
  2446. }
  2447. RegCloseKey(hKey);
  2448. //
  2449. // =================================
  2450. // See if anyone wants to reset uniqueness
  2451. // in their component.
  2452. // =================================
  2453. //
  2454. RunExternalUniqueness();
  2455. return TRUE;
  2456. }
  2457. BOOL SetCloneTag
  2458. (
  2459. void
  2460. )
  2461. {
  2462. HKEY hKey;
  2463. DWORD l;
  2464. TCHAR DateString[1024];
  2465. time_t ltime;
  2466. LPTSTR lpszDate;
  2467. //
  2468. // =================================
  2469. // Put a unique identifier into the registry so we know this machine
  2470. // has been cloned.
  2471. // =================================
  2472. //
  2473. //
  2474. // Open HKLM\System\Setup
  2475. //
  2476. l = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2477. TEXT("SYSTEM\\Setup"),
  2478. 0,
  2479. KEY_ALL_ACCESS,
  2480. &hKey );
  2481. if(l != NO_ERROR)
  2482. {
  2483. SetLastError(l);
  2484. return FALSE;
  2485. }
  2486. //
  2487. // Set HKLM\System\Setup\CloneTag. We're going to
  2488. // pickup a date string and write it out.
  2489. //
  2490. time( &ltime );
  2491. ZeroMemory(DateString, sizeof(DateString));
  2492. //
  2493. // ISSUE-2002/02/26-brucegr: This function smells horrid!
  2494. //
  2495. lpszDate = _wctime( &ltime );
  2496. if ( lpszDate )
  2497. {
  2498. StringCchCopy( DateString, AS ( DateString ), lpszDate );
  2499. l = RegSetValueEx(hKey,
  2500. TEXT("CloneTag"),
  2501. 0,
  2502. REG_MULTI_SZ,
  2503. (CONST BYTE *)DateString,
  2504. (lstrlen( DateString ) + 2) * sizeof(TCHAR));
  2505. }
  2506. RegCloseKey(hKey);
  2507. if(l != NO_ERROR)
  2508. {
  2509. SetLastError(l);
  2510. return FALSE;
  2511. }
  2512. return (TRUE);
  2513. }
  2514. BOOL SetBigLbaSupport
  2515. (
  2516. LPTSTR lpszSysprepINFPath
  2517. )
  2518. {
  2519. HKEY hKey;
  2520. DWORD dwError, dwValue;
  2521. TCHAR szEnableBigLba[MAX_PATH] = TEXT("\0");
  2522. if ( ( lpszSysprepINFPath ) &&
  2523. ( *lpszSysprepINFPath ) &&
  2524. ( GetPrivateProfileString( TEXT( "Unattended" ), TEXT( "EnableBigLba" ), L"", szEnableBigLba, sizeof(szEnableBigLba)/sizeof(TCHAR), lpszSysprepINFPath ) ) )
  2525. {
  2526. // They would like to enable BigLba support. If the user does not specify "Yes" for this key, we do not
  2527. // touch the key (even if they specify "No"). This is By Design
  2528. //
  2529. if (LSTRCMPI(szEnableBigLba, TEXT("YES")) == 0)
  2530. {
  2531. // Open base key and subkey
  2532. //
  2533. dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2534. TEXT("System\\CurrentControlSet\\Services\\Atapi\\Parameters"),
  2535. 0,
  2536. KEY_ALL_ACCESS,
  2537. &hKey );
  2538. // Determine if opening the key was successful
  2539. //
  2540. if(dwError != NO_ERROR)
  2541. {
  2542. SetLastError(dwError);
  2543. return FALSE;
  2544. }
  2545. // Set the value in the registry
  2546. //
  2547. dwValue = 1;
  2548. dwError = RegSetValueEx(hKey,
  2549. TEXT("EnableBigLba"),
  2550. 0,
  2551. REG_DWORD,
  2552. (CONST BYTE *)&dwValue,
  2553. sizeof(DWORD));
  2554. // Close the key
  2555. //
  2556. RegCloseKey(hKey);
  2557. // Return the error if the SetValue failed
  2558. //
  2559. if(dwError != NO_ERROR)
  2560. {
  2561. SetLastError(dwError);
  2562. return FALSE;
  2563. }
  2564. }
  2565. }
  2566. return TRUE;
  2567. }
  2568. BOOL RemoveTapiSettings
  2569. (
  2570. LPTSTR lpszSysprepINFPath
  2571. )
  2572. {
  2573. HKEY hKey;
  2574. DWORD dwError, dwValue;
  2575. TCHAR szTapiConfigured[MAX_PATH] = TEXT("\0"),
  2576. szKeyPath[MAX_PATH] = TEXT("\0");
  2577. if ( ( lpszSysprepINFPath ) &&
  2578. ( *lpszSysprepINFPath ) &&
  2579. ( GetPrivateProfileString( TEXT( "Unattended" ), TEXT( "TapiConfigured" ), TEXT(""), szTapiConfigured, sizeof(szTapiConfigured)/sizeof(TCHAR), lpszSysprepINFPath ) ) )
  2580. {
  2581. // Only if the user specifies No will we remove the registry tapi settings
  2582. //
  2583. if (LSTRCMPI(szTapiConfigured, TEXT("NO")) == 0)
  2584. {
  2585. // Open base key and subkey
  2586. //
  2587. dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2588. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations"),
  2589. 0,
  2590. KEY_ALL_ACCESS,
  2591. &hKey );
  2592. // Determine if opening the key was successful
  2593. //
  2594. if(dwError != NO_ERROR)
  2595. {
  2596. SetLastError(dwError);
  2597. return FALSE;
  2598. }
  2599. // We enumerate the locations keys and delete any subkeys
  2600. //
  2601. while ( RegEnumKey(hKey, 0, szKeyPath, sizeof(szKeyPath)/sizeof(TCHAR)) == ERROR_SUCCESS )
  2602. {
  2603. // Delete the key and all subkeys
  2604. //
  2605. //
  2606. // NTRAID#NTBUG9-551815-2002/02/26-brucegr: If delete fails, should increment RegEnumKey index
  2607. //
  2608. SHDeleteKey(hKey, szKeyPath) ;
  2609. }
  2610. // Close the key
  2611. //
  2612. RegCloseKey(hKey);
  2613. }
  2614. }
  2615. return TRUE;
  2616. }
  2617. //
  2618. // =================================
  2619. // Modify the HKLM\System\Setup\DiskDuplicator Key appropriately.
  2620. // =================================
  2621. //
  2622. BOOL SetOEMDuplicatorString
  2623. (
  2624. LPTSTR lpszSysprepINFPath
  2625. )
  2626. {
  2627. TCHAR szOEMDuplicatorString[256];
  2628. DWORD l;
  2629. HKEY hKey;
  2630. ZeroMemory(szOEMDuplicatorString, sizeof(szOEMDuplicatorString));
  2631. // See if the DiskDuplicator string is present in the
  2632. // unattend file.
  2633. GetPrivateProfileString( TEXT( "GuiUnattended" ),
  2634. TEXT( "OEMDuplicatorString" ),
  2635. L"",
  2636. szOEMDuplicatorString,
  2637. sizeof(szOEMDuplicatorString)/sizeof(TCHAR),
  2638. lpszSysprepINFPath );
  2639. if( szOEMDuplicatorString[0] )
  2640. {
  2641. //
  2642. // ISSUE-2002/02/26-brucegr: This doesn't ensure double termination for REG_MULTI_SZ...
  2643. //
  2644. // Ensure it is not bigger than 255 chars
  2645. szOEMDuplicatorString[255] = TEXT('\0');
  2646. // Open HKLM\System\Setup
  2647. l = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2648. TEXT("SYSTEM\\Setup"),
  2649. 0,
  2650. KEY_ALL_ACCESS,
  2651. &hKey );
  2652. if(l != NO_ERROR)
  2653. {
  2654. SetLastError(l);
  2655. return FALSE;
  2656. }
  2657. l = RegSetValueEx(hKey,
  2658. TEXT( "OEMDuplicatorString" ),
  2659. 0,
  2660. REG_MULTI_SZ,
  2661. (CONST BYTE *)szOEMDuplicatorString,
  2662. (lstrlen( szOEMDuplicatorString ) + 2) * sizeof(TCHAR));
  2663. RegCloseKey(hKey);
  2664. if(l != NO_ERROR)
  2665. {
  2666. SetLastError(l);
  2667. return FALSE;
  2668. }
  2669. }
  2670. return (TRUE);
  2671. }
  2672. // Reset OOBE settings so it doesn't think it ran already
  2673. //
  2674. void ResetOobeSettings()
  2675. {
  2676. HKEY hkOobe;
  2677. TCHAR szOobeInfoFile[MAX_PATH];
  2678. // Remove HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\OOBE
  2679. //
  2680. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Setup"), &hkOobe)) {
  2681. //
  2682. // ISSUE-2002/02/26-brucegr: Why get lError? It's not used
  2683. //
  2684. LONG lError = SHDeleteKey(hkOobe, TEXT("OOBE"));
  2685. RegCloseKey(hkOobe);
  2686. }
  2687. // Build the path to oobeinfo.ini if oobe directory exists for personal
  2688. //
  2689. //
  2690. // NTRAID#NTBUG9-551815-2002/02/26-brucegr: No error checking for GetSystemDirectory
  2691. //
  2692. GetSystemDirectory(szOobeInfoFile, MAX_PATH);
  2693. OPKAddPathN (szOobeInfoFile, TEXT("oobe"), AS ( szOobeInfoFile ) );
  2694. if (PathIsDirectory(szOobeInfoFile)) {
  2695. OPKAddPathN(szOobeInfoFile, TEXT("oobeinfo.ini"), AS ( szOobeInfoFile ) );
  2696. // Remove the RetailOOBE key in oobeinfo.ini
  2697. //
  2698. WritePrivateProfileString(TEXT("StartupOptions"), TEXT("RetailOOBE"), NULL /*Remove it*/, szOobeInfoFile);
  2699. }
  2700. }
  2701. /*++
  2702. ===============================================================================
  2703. Routine Description:
  2704. This routine will setup the first application to run when the machine
  2705. with the image applied to it is run.
  2706. The first run application will either be setup, in MiniSetup mode, or MSOOBE
  2707. The decision for what it will be is based on the product type.
  2708. For Personal/Professional, MSOOBE
  2709. For Professional, default will be MSOOBE, but can be overriden by the OEM to be
  2710. MiniSetup
  2711. For Server, and DTC, MiniSetup
  2712. Arguments:
  2713. None.
  2714. Return Value:
  2715. TRUE if successful.
  2716. FALSE if any errors encountered
  2717. ===============================================================================
  2718. --*/
  2719. BOOL SetupFirstRunApp
  2720. (
  2721. void
  2722. )
  2723. {
  2724. DWORD dwError;
  2725. DWORD dwValue;
  2726. HKEY hKeySetup;
  2727. TCHAR Value[MAX_PATH + 1]; // +1 is for second NULL char at end of REG_MULTI_SZ reg type
  2728. OSVERSIONINFOEX verInfo;
  2729. BOOL bUseMSOOBE = FALSE, bPro = FALSE;
  2730. // Open HKLM\System\Setup
  2731. dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2732. TEXT("SYSTEM\\Setup"),
  2733. 0,
  2734. KEY_ALL_ACCESS,
  2735. &hKeySetup );
  2736. if(dwError != NO_ERROR)
  2737. {
  2738. SetLastError(dwError);
  2739. return FALSE;
  2740. }
  2741. // Check the product type, to determine what program we should run
  2742. if (IsPersonalSKU() || (bPro = IsProfessionalSKU())) {
  2743. bUseMSOOBE = TRUE;
  2744. if (bMiniSetup == TRUE && bPro)
  2745. bUseMSOOBE = FALSE;
  2746. }
  2747. else
  2748. bUseMSOOBE = FALSE;
  2749. // Start OOBE on next boot
  2750. //
  2751. if (bUseMSOOBE)
  2752. {
  2753. //
  2754. // ISSUE-2002/02/26-brucegr: If anything fails, machine is screwed. Should restore settings on failure?
  2755. //
  2756. // Set HKLM\System\Setup\SetupType Key to SETUPTYPE_NOREBOOT
  2757. dwValue = SETUPTYPE_NOREBOOT;
  2758. dwError = RegSetValueEx(hKeySetup,
  2759. TEXT("SetupType"),
  2760. 0,
  2761. REG_DWORD,
  2762. (CONST BYTE *)&dwValue,
  2763. sizeof(DWORD));
  2764. if(dwError != NO_ERROR)
  2765. {
  2766. RegCloseKey(hKeySetup);
  2767. SetLastError(dwError);
  2768. return FALSE;
  2769. }
  2770. // Set these keys for OEM
  2771. //
  2772. dwValue = 1;
  2773. dwError = RegSetValueEx(hKeySetup, TEXT("MiniSetupInProgress"), 0, REG_DWORD, (CONST BYTE *)&dwValue, sizeof(dwValue));
  2774. if(dwError != NO_ERROR)
  2775. {
  2776. RegCloseKey(hKeySetup);
  2777. SetLastError(dwError);
  2778. return FALSE;
  2779. }
  2780. dwError = RegSetValueEx(hKeySetup,
  2781. TEXT("SystemSetupInProgress"),
  2782. 0,
  2783. REG_DWORD,
  2784. (CONST BYTE *)&dwValue,
  2785. sizeof(dwValue));
  2786. if(dwError != NO_ERROR)
  2787. {
  2788. RegCloseKey(hKeySetup);
  2789. SetLastError(dwError);
  2790. return FALSE;
  2791. }
  2792. dwError = RegSetValueEx(hKeySetup, TEXT("OobeInProgress"), 0, REG_DWORD, (CONST BYTE *)&dwValue, sizeof(dwValue));
  2793. if(dwError != NO_ERROR)
  2794. {
  2795. RegCloseKey(hKeySetup);
  2796. SetLastError(dwError);
  2797. return FALSE;
  2798. }
  2799. // =================================
  2800. // Modify the HKLM\System\Setup\CmdLine key to run MSBOOBE
  2801. // =================================
  2802. ExpandEnvironmentStrings(TEXT("%SystemRoot%\\System32\\oobe\\msoobe.exe /f"), Value, sizeof(Value)/sizeof(Value[0]));
  2803. Value[lstrlen(Value) + 1] = L'\0';
  2804. dwError = RegSetValueEx(hKeySetup,
  2805. TEXT("CmdLine"),
  2806. 0,
  2807. REG_MULTI_SZ,
  2808. (CONST BYTE *)Value,
  2809. (lstrlen( Value ) + 2) * sizeof(TCHAR));
  2810. if(dwError != NO_ERROR)
  2811. {
  2812. RegCloseKey(hKeySetup);
  2813. SetLastError(dwError);
  2814. return FALSE;
  2815. }
  2816. }
  2817. else
  2818. {
  2819. //
  2820. // ISSUE-2002/02/26-brucegr: We are duplicating some of the above code again!
  2821. //
  2822. // Start MiniSetup on next boot
  2823. //
  2824. //
  2825. // =================================
  2826. // Modify the HKLM\System\Setup\SetupType Key appropriately (set it to 1 so we
  2827. // go into GUI-mode setup as if this were a full install.
  2828. // =================================
  2829. //
  2830. dwValue= SETUPTYPE;
  2831. dwError = RegSetValueEx(hKeySetup,
  2832. TEXT("SetupType"),
  2833. 0,
  2834. REG_DWORD,
  2835. (CONST BYTE *)&dwValue,
  2836. sizeof(dwValue));
  2837. if(dwError != NO_ERROR)
  2838. {
  2839. RegCloseKey(hKeySetup);
  2840. SetLastError(dwError);
  2841. return FALSE;
  2842. }
  2843. //
  2844. // =================================
  2845. // Modify the HKLM\System\Setup\SystemSetupInProgress.
  2846. // =================================
  2847. //
  2848. dwValue = 1;
  2849. dwError = RegSetValueEx(hKeySetup,
  2850. TEXT("SystemSetupInProgress"),
  2851. 0,
  2852. REG_DWORD,
  2853. (CONST BYTE *)&dwValue,
  2854. sizeof(dwValue));
  2855. if(dwError != NO_ERROR)
  2856. {
  2857. RegCloseKey(hKeySetup);
  2858. SetLastError(dwError);
  2859. return FALSE;
  2860. }
  2861. // Setup for PnP
  2862. if( PnP )
  2863. {
  2864. dwValue = 1;
  2865. dwError = RegSetValueEx(hKeySetup,
  2866. TEXT("MiniSetupDoPnP"),
  2867. 0,
  2868. REG_DWORD,
  2869. (CONST BYTE *)&dwValue,
  2870. sizeof(dwValue) );
  2871. if(dwError != NO_ERROR)
  2872. {
  2873. RegCloseKey(hKeySetup);
  2874. SetLastError(dwError);
  2875. return FALSE;
  2876. }
  2877. }
  2878. //
  2879. // =================================
  2880. // Create HKLM\System\Setup\MiniSetupInProgress key and set to 1. This tells LSA to
  2881. // skip generating a new SID. He wants to because he thinks we're
  2882. // setting up a machine for the first time. This also tells
  2883. // a few other people (networking, ...) that we're doing a
  2884. // boot into the mini wizard.
  2885. // =================================
  2886. //
  2887. dwValue = 1;
  2888. dwError = RegSetValueEx( hKeySetup,
  2889. TEXT("MiniSetupInProgress"),
  2890. 0,
  2891. REG_DWORD,
  2892. (CONST BYTE *)&dwValue,
  2893. sizeof(dwValue) );
  2894. if(dwError != NO_ERROR)
  2895. {
  2896. RegCloseKey(hKeySetup);
  2897. SetLastError(dwError);
  2898. return FALSE;
  2899. }
  2900. // =================================
  2901. // Modify the HKLM\System\Setup\CmdLine key appropriately so we do a mini
  2902. // version of gui-mode setup.
  2903. // =================================
  2904. StringCchCopy (Value, AS ( Value ), TEXT("setup.exe -newsetup -mini"));
  2905. Value[lstrlen(Value) + 1] = L'\0';
  2906. dwError = RegSetValueEx(hKeySetup,
  2907. TEXT("CmdLine"),
  2908. 0,
  2909. REG_MULTI_SZ,
  2910. (CONST BYTE *)Value,
  2911. (lstrlen( Value ) + 2) * sizeof(TCHAR));
  2912. if(dwError != NO_ERROR)
  2913. {
  2914. RegCloseKey(hKeySetup);
  2915. SetLastError(dwError);
  2916. return FALSE;
  2917. }
  2918. }
  2919. RegCloseKey(hKeySetup);
  2920. return (TRUE);
  2921. }
  2922. BOOL
  2923. IsSetupClPresent(
  2924. VOID
  2925. )
  2926. /*++
  2927. ===============================================================================
  2928. Routine Description:
  2929. This routine tests to see if the SID generator is present on the system.
  2930. The SID generator will be required to run on reboot, so if it's not here,
  2931. we need to know.
  2932. Arguments:
  2933. None.
  2934. Return Value:
  2935. TRUE - The SID generator is present.
  2936. FALSE - The SID generator is not present.
  2937. ===============================================================================
  2938. --*/
  2939. {
  2940. WCHAR NewFileName[MAX_PATH];
  2941. WCHAR OldFileName[MAX_PATH];
  2942. WIN32_FIND_DATA findData;
  2943. HANDLE FindHandle;
  2944. UINT OldMode;
  2945. DWORD Error;
  2946. WCHAR *wstr_ptr;
  2947. //
  2948. // First, try and copy a setupcl.exe into the system directory.
  2949. // If there's not one in our current directory, forget about it and
  2950. // keep going. The user may already have one installed.
  2951. //
  2952. //
  2953. // NTRAID#NTBUG9-551815-2002/02/26-brucegr: No checking for GetSystemDirectory failure
  2954. //
  2955. GetSystemDirectory( NewFileName, MAX_PATH );
  2956. StringCchCat( NewFileName, AS ( NewFileName ), TEXT( "\\" ) );
  2957. StringCchCat( NewFileName, AS ( NewFileName ), TEXT(SYSCLONE_PART2) );
  2958. //
  2959. // NTRAID#NTBUG9-551815-2002/02/26-brucegr: No checking for GetModuleFileName failure
  2960. //
  2961. GetModuleFileName(NULL,OldFileName,MAX_PATH);
  2962. //
  2963. // ISSUE-2002/02/26-brucegr: Use PathRemoveFileSpec instead of this horrid code
  2964. //
  2965. wstr_ptr = wcsrchr( OldFileName, TEXT( '\\' ) );
  2966. if (wstr_ptr)
  2967. *wstr_ptr = 0;
  2968. StringCchCat( OldFileName, AS ( OldFileName ), TEXT( "\\" ) );
  2969. StringCchCat( OldFileName, AS ( OldFileName ), TEXT(SYSCLONE_PART2) );
  2970. if( !CopyFile( OldFileName, NewFileName, FALSE ) ) {
  2971. Sleep( 500 );
  2972. if( !CopyFile( OldFileName, NewFileName, FALSE ) ) {
  2973. //
  2974. // ISSUE-2002/02/26-brucegr: Why get the error code if we overwrite it below?
  2975. //
  2976. Error = GetLastError();
  2977. }
  2978. }
  2979. //
  2980. // ISSUE-2002/02/26-brucegr: NewFileName should already be constructed... this seems redundant
  2981. //
  2982. //
  2983. // Generate path to the system32 directory, then tack on the
  2984. // name of the SID generator.
  2985. //
  2986. //
  2987. // NTRAID#NTBUG9-551815-2002/02/26-brucegr: No checking for GetSystemDirectory failure
  2988. //
  2989. GetSystemDirectory( NewFileName, MAX_PATH );
  2990. StringCchCat( NewFileName, AS ( NewFileName ), TEXT("\\") );
  2991. StringCchCat( NewFileName, AS ( NewFileName ), TEXT(SYSCLONE_PART2) );
  2992. //
  2993. // Now see if he exists...
  2994. //
  2995. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  2996. //
  2997. // ISSUE-2002/02/26-brucegr: Use GetFileAttributes instead of FindFirstFile
  2998. //
  2999. //
  3000. // See if he's there.
  3001. //
  3002. FindHandle = FindFirstFile( NewFileName, &findData );
  3003. if(FindHandle == INVALID_HANDLE_VALUE) {
  3004. //
  3005. // Nope...
  3006. //
  3007. Error = GetLastError();
  3008. } else {
  3009. //
  3010. // Yep. Close him.
  3011. //
  3012. FindClose(FindHandle);
  3013. Error = NO_ERROR;
  3014. }
  3015. //
  3016. // Restore error mode.
  3017. //
  3018. SetErrorMode(OldMode);
  3019. SetLastError(Error);
  3020. return (Error == NO_ERROR);
  3021. }
  3022. BOOL FCheckBuildMassStorageSectionFlag(TCHAR* pszSysprepInf)
  3023. {
  3024. TCHAR szValue[MAX_PATH];
  3025. DWORD dwReturn = 0;
  3026. BOOL fReturn = FALSE;
  3027. // If key is missing we default to no, we don't want to build the section
  3028. // but we still process the section if user manually added keys to this
  3029. // section.
  3030. //
  3031. //
  3032. // ISSUE-2002/02/26-brucegr: dwReturn isn't really used
  3033. //
  3034. if (dwReturn = GetPrivateProfileString(SYSPREP_SECTION, SYSPREP_BUILDMASSSTORAGE_KEY,
  3035. TEXT("NO"), szValue, MAX_PATH, pszSysprepInf))
  3036. {
  3037. if (LSTRCMPI(szValue, TEXT("YES")) == 0)
  3038. fReturn = TRUE;
  3039. else if (LSTRCMPI(szValue, TEXT("NO")) == 0)
  3040. fReturn = FALSE;
  3041. }
  3042. return fReturn;
  3043. }
  3044. VOID BuildMassStorageSection(BOOL fForceBuild)
  3045. {
  3046. LPDEVIDLIST lpDeviceIDList = NULL;
  3047. DWORD dwNumDevIDs = 0, dwGuids = 0, dwIdxDevIDs = 0;
  3048. TCHAR szSysPrepInf[MAX_PATH];
  3049. GUID rgGuids[3];
  3050. TCHAR *prgInfs[] = { TEXT("machine.inf"), TEXT("pnpscsi.inf"), TEXT("scsi.inf"), TEXT("mshdc.inf") };
  3051. /* Types of mass storage devices GUIDs */
  3052. rgGuids[0] = GUID_DEVCLASS_SYSTEM; /* machine.inf */
  3053. rgGuids[1] = GUID_DEVCLASS_SCSIADAPTER; /* scsi.inf */
  3054. rgGuids[2] = GUID_DEVCLASS_HDC; /* mshdc.inf */
  3055. /* Only from these inf */
  3056. //
  3057. // NTRAID#NTBUG9-551815-2002/02/26-brucegr: Need to check GetModuleFileName return value
  3058. //
  3059. GetModuleFileName(NULL, szSysPrepInf, MAX_PATH);
  3060. PathRemoveFileSpec(szSysPrepInf);
  3061. OPKAddPathN ( szSysPrepInf, TEXT("sysprep.inf"), AS ( szSysPrepInf ) );
  3062. // Only build if user requested it
  3063. //
  3064. if (!fForceBuild && !FCheckBuildMassStorageSectionFlag(szSysPrepInf))
  3065. return;
  3066. //
  3067. // =================================
  3068. // Remove [sysprepcleanup] which will be added during PopulateDeviceDatabase().
  3069. // =================================
  3070. //
  3071. WritePrivateProfileSection(L"sysprepcleanup", NULL, szSysPrepInf);
  3072. // Loop thru all the mass storage devices
  3073. //
  3074. for (dwGuids = 0; dwGuids < (sizeof(rgGuids) / sizeof(rgGuids[0])); dwGuids++) {
  3075. // Build a list of mass storage devices
  3076. //
  3077. if (BuildDeviceIDList(SYSPREPMASSSTORAGE_SECTION,
  3078. szSysPrepInf,
  3079. (LPGUID)&rgGuids[dwGuids],
  3080. &lpDeviceIDList,
  3081. &dwNumDevIDs,
  3082. TRUE,
  3083. FALSE))
  3084. {
  3085. // Write the mass storage info to sysprep.inf
  3086. //
  3087. for(dwIdxDevIDs = 0; dwIdxDevIDs < dwNumDevIDs; ++dwIdxDevIDs)
  3088. {
  3089. BOOL fInfFound = FALSE;
  3090. // Check if this inf if in our Infs table
  3091. //
  3092. int iCmp = 0;
  3093. for (iCmp = 0; iCmp < (sizeof(prgInfs)/sizeof(prgInfs[0])); iCmp++) {
  3094. //
  3095. // ISSUE-2002/02/26-brucegr: Can we use something better than StrStrI?
  3096. //
  3097. if (StrStrI(lpDeviceIDList[dwIdxDevIDs].szINFFileName, prgInfs[iCmp])) {
  3098. fInfFound = TRUE;
  3099. break;
  3100. }
  3101. }
  3102. if (fInfFound)
  3103. {
  3104. // Check HardwareID first then check the CompatID
  3105. //
  3106. if (lpDeviceIDList[dwIdxDevIDs].szHardwareID[0])
  3107. {
  3108. // Use only the infs we care about
  3109. //
  3110. WritePrivateProfileString(SYSPREPMASSSTORAGE_SECTION,
  3111. lpDeviceIDList[dwIdxDevIDs].szHardwareID,
  3112. lpDeviceIDList[dwIdxDevIDs].szINFFileName,
  3113. szSysPrepInf);
  3114. }
  3115. else if (lpDeviceIDList[dwIdxDevIDs].szCompatibleID[0])
  3116. {
  3117. // Use only the infs we care about
  3118. //
  3119. WritePrivateProfileString(SYSPREPMASSSTORAGE_SECTION,
  3120. lpDeviceIDList[dwIdxDevIDs].szCompatibleID,
  3121. lpDeviceIDList[dwIdxDevIDs].szINFFileName,
  3122. szSysPrepInf);
  3123. }
  3124. }
  3125. }
  3126. // Free the allocated list
  3127. //
  3128. LocalFree(lpDeviceIDList);
  3129. }
  3130. }
  3131. }
  3132. DWORD
  3133. ReArm(
  3134. VOID
  3135. )
  3136. /*++
  3137. ===============================================================================
  3138. Routine Description:
  3139. This routine returns either the error code or success.
  3140. Arguments:
  3141. None.
  3142. Return Value:
  3143. ERROR_SUCCESS - ReArm succeeded and shortcut restored.
  3144. Error code - ReArm failed.
  3145. ===============================================================================
  3146. --*/
  3147. {
  3148. DWORD dwError = ERROR_FILE_NOT_FOUND;
  3149. BYTE bDummy = 1;
  3150. typedef DWORD (WINAPI* MYPROC)(BYTE*);
  3151. // Use Loadlibrary/GetProcAddress because Riprep needs to support Windows 2000
  3152. //
  3153. HINSTANCE hInst = LoadLibrary(L"syssetup.dll");
  3154. if (hInst) {
  3155. MYPROC fnProc;
  3156. if ( fnProc = (MYPROC)GetProcAddress(hInst, "SetupOobeBnk") ) {
  3157. dwError = fnProc(&bDummy);
  3158. }
  3159. FreeLibrary(hInst);
  3160. }
  3161. // Return error code or success
  3162. //
  3163. return dwError;
  3164. }
  3165. BOOL FCommonReseal
  3166. (
  3167. VOID
  3168. )
  3169. /*++
  3170. ===============================================================================
  3171. Routine Description:
  3172. This routine is the common reseal code for both Riprep and Sysprep.
  3173. Arguments:
  3174. None.
  3175. Return Value:
  3176. TRUE - success
  3177. FALSE - failure
  3178. Remarks:
  3179. This routine should only cleanup registry keys as it is being called by
  3180. AdjustRegistry() which is the last step of Riprep after the network is
  3181. removed.
  3182. ===============================================================================
  3183. --*/
  3184. {
  3185. HKEY hKey = NULL;
  3186. SC_HANDLE schService;
  3187. SC_HANDLE schSystem;
  3188. TCHAR szUrllog[MAX_PATH];
  3189. DWORD dwLen;
  3190. //
  3191. // ISSUE-2002/02/26-brucegr: Make sure all intermediate return points are necessary!
  3192. //
  3193. //
  3194. // =================================
  3195. // Clear the MRU list on the machine.
  3196. // =================================
  3197. //
  3198. NukeMruList();
  3199. //
  3200. // =================================
  3201. // Clear recent apps
  3202. // =================================
  3203. //
  3204. ClearRecentApps();
  3205. //
  3206. // =================================
  3207. // Delete User Specific Settings from all user profiles.
  3208. // =================================
  3209. //
  3210. NukeUserSettings();
  3211. //
  3212. // =================================
  3213. // Remove HKLM\System\MountedDevices key.
  3214. // =================================
  3215. //
  3216. if ( NO_ERROR == (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3217. TEXT("System"),
  3218. 0,
  3219. KEY_ALL_ACCESS,
  3220. &hKey)) )
  3221. {
  3222. RegDeleteKey(hKey, TEXT("MountedDevices"));
  3223. RegCloseKey(hKey);
  3224. }
  3225. //
  3226. // =================================
  3227. // Remove Desktop Cleanup wizard registry key to reset cleanup timer
  3228. // =================================
  3229. //
  3230. if ( NO_ERROR == (RegOpenKeyEx(HKEY_CURRENT_USER,
  3231. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\CleanupWiz"),
  3232. 0,
  3233. KEY_ALL_ACCESS,
  3234. &hKey)) )
  3235. {
  3236. RegDeleteValue(hKey, TEXT("Last used time"));
  3237. RegCloseKey(hKey);
  3238. }
  3239. //
  3240. // =================================
  3241. // Windows Update Cleanup
  3242. //
  3243. // Do all of the following during SYSPREP -reseal before the system is rebooted:
  3244. //
  3245. // 1) stop the WUAUSERV service
  3246. // 2) delete %ProgramFiles%\WindowsUpdate\urllog.dat (note WindowsUpdate is a hiiden directory. I don't believe this will cause any issues).
  3247. // 3) remove the following registry entries under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate
  3248. // Delete value/data pair: PingID
  3249. // DO NOT DELETE key subtree: Auto Update
  3250. // Delete value/data pair: Auto Update\AUState
  3251. // Delete value/data pair: Auto Update\LastWaitTimeout
  3252. // Delete key subtree: IUControl
  3253. // Delete key subtree: OemInfo
  3254. // =================================
  3255. //
  3256. // 1) stop the WUAUSERV service
  3257. schSystem = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  3258. if (schSystem)
  3259. {
  3260. schService = OpenService( schSystem,
  3261. TEXT("WUAUSERV"),
  3262. SC_MANAGER_ALL_ACCESS);
  3263. if ( schService )
  3264. {
  3265. SERVICE_STATUS ss;
  3266. ControlService( schService, SERVICE_CONTROL_STOP, &ss );
  3267. CloseServiceHandle( schService );
  3268. }
  3269. CloseServiceHandle( schSystem );
  3270. }
  3271. // 2) delete %ProgramFiles%\WindowsUpdate\urllog.dat (note WindowsUpdate is a hiiden directory. I don't believe this will cause any issues).
  3272. dwLen=ExpandEnvironmentStrings(TEXT("%ProgramFiles%\\WindowsUpdate\\urllog.dat"),szUrllog,MAX_PATH);
  3273. if (dwLen && dwLen < MAX_PATH)
  3274. DeleteFile(szUrllog);
  3275. // 3) remove the following registry entries under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate
  3276. // Delete value/data pair: PingID
  3277. // DO NOT DELETE key subtree: Auto Update
  3278. // Delete value/data pair: Auto Update\AUState
  3279. // Delete value/data pair: Auto Update\LastWaitTimeout
  3280. // Delete key subtree: IUControl
  3281. // Delete key subtree: OemInfo
  3282. if ( NO_ERROR == (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3283. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate"),
  3284. 0,
  3285. KEY_ALL_ACCESS,
  3286. &hKey)) )
  3287. {
  3288. RegDeleteValue(hKey, TEXT("PingID"));
  3289. RegDeleteValue(hKey, TEXT("Auto Update\\AUState"));
  3290. RegDeleteValue(hKey, TEXT("Auto Update\\LastWaitTimeout"));
  3291. RegDeleteKey(hKey, TEXT("IUControl"));
  3292. RegDeleteKey(hKey, TEXT("OemInfo"));
  3293. RegCloseKey(hKey);
  3294. }
  3295. //
  3296. // =================================
  3297. // Modify any install paths that may be required
  3298. // for our reboot into gui-mode.
  3299. // =================================
  3300. //
  3301. FixDevicePaths();
  3302. //
  3303. // =================================
  3304. // Clear out winlogon's memory of the last user and domain.
  3305. // =================================
  3306. //
  3307. if( !DeleteWinlogonDefaults() ) {
  3308. return FALSE;
  3309. }
  3310. // Remove Cryptography key so it gets re-generated, only do this if the SIDS have been regenerated
  3311. //
  3312. if ( !NoSidGen )
  3313. {
  3314. if ( NO_ERROR == (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3315. TEXT("SOFTWARE\\Microsoft\\Cryptography"),
  3316. 0,
  3317. KEY_ALL_ACCESS,
  3318. &hKey)) )
  3319. {
  3320. RegDeleteValue(hKey, TEXT("MachineGuid"));
  3321. RegCloseKey(hKey);
  3322. }
  3323. }
  3324. // Set the cloned tag in the registry
  3325. if (!SetCloneTag())
  3326. return FALSE;
  3327. // Sets whether msoobe or mini-setup on first end user boot
  3328. //
  3329. if (!SetupFirstRunApp())
  3330. return FALSE;
  3331. //
  3332. // =================================
  3333. // Clear the LastKnownGood ControlSet.
  3334. // =================================
  3335. //
  3336. if (NO_ERROR != NukeLKGControlSet())
  3337. return FALSE;
  3338. //
  3339. // =================================
  3340. // Clear the eventlogs on the machine.
  3341. // This is the last thing that we should do.
  3342. // =================================
  3343. //
  3344. NukeEventLogs();
  3345. // Common reseal succeeded
  3346. //
  3347. return TRUE;
  3348. }
  3349. BOOL
  3350. AdjustFiles(
  3351. VOID
  3352. )
  3353. /*++
  3354. ===============================================================================
  3355. Routine Description:
  3356. This routine allows cleanup to happen before files are copied to the server
  3357. by Riprep.
  3358. Arguments:
  3359. None.
  3360. Return Value:
  3361. None.
  3362. Remarks:
  3363. This routine should be called before AdjustRegistry() for Riprep. Sysprep
  3364. needs to call this before FCommonReseal().
  3365. ===============================================================================
  3366. --*/
  3367. {
  3368. BOOL bUseMSOOBE = FALSE,
  3369. bPro = FALSE,
  3370. fReturn = TRUE;
  3371. TCHAR szSysprepFolder[MAX_PATH] = TEXT("\0");
  3372. //
  3373. // Make sure we've got the required privileges to update the registry.
  3374. //
  3375. pSetupEnablePrivilege(SE_RESTORE_NAME,TRUE);
  3376. pSetupEnablePrivilege(SE_BACKUP_NAME,TRUE);
  3377. //
  3378. // Check the product type.
  3379. //
  3380. if (IsPersonalSKU() || (bPro = IsProfessionalSKU())) {
  3381. bUseMSOOBE = TRUE;
  3382. if (bMiniSetup == TRUE && bPro)
  3383. bUseMSOOBE = FALSE;
  3384. }
  3385. else
  3386. bUseMSOOBE = FALSE;
  3387. if (bUseMSOOBE)
  3388. {
  3389. //
  3390. // Prepare for Oobe
  3391. //
  3392. }
  3393. else
  3394. {
  3395. //
  3396. // Prepare for MiniSetup
  3397. //
  3398. }
  3399. //
  3400. // =================================
  3401. // Clear the SMS settings and INI file.
  3402. // =================================
  3403. //
  3404. NukeSmsSettings();
  3405. //
  3406. // =================================
  3407. // Clean up Digital Rights Media information.
  3408. // =================================
  3409. //
  3410. #if !(defined(AMD64) || defined(IA64))
  3411. //
  3412. // This only works on x86. There is no 64-bit library available for us
  3413. // to call into right now.
  3414. //
  3415. if ( GetWindowsDirectory(szSysprepFolder, sizeof(szSysprepFolder)/sizeof(szSysprepFolder[0])) )
  3416. {
  3417. CHAR szLogFileA[MAX_PATH];
  3418. BOOL bLog = TRUE;
  3419. // This will look something like this: "c:\windows". Make the character after the '\' NULL, and
  3420. // append the name of the file to it.
  3421. //
  3422. szSysprepFolder[3] = UNICODE_NULL;
  3423. PathAppend(szSysprepFolder, TEXT("SYSPREP"));
  3424. // Create the folder if it does not exist
  3425. //
  3426. if ( !PathFileExists(szSysprepFolder) )
  3427. {
  3428. bLog = CreateDirectory(szSysprepFolder, NULL);
  3429. }
  3430. PathAppend(szSysprepFolder, CLEANDRM_LOGFILE);
  3431. // Convert UNICODE string to ANSI string.
  3432. //
  3433. if ( WideCharToMultiByte(CP_ACP, 0, szSysprepFolder, -1, szLogFileA, sizeof(szLogFileA), NULL, NULL) )
  3434. {
  3435. CleanDRM( bLog ? szLogFileA : NULL );
  3436. }
  3437. else
  3438. {
  3439. fReturn = FALSE;
  3440. }
  3441. }
  3442. else
  3443. {
  3444. fReturn = FALSE;
  3445. }
  3446. #endif // #if !(defined(AMD64) || defined(IA64))
  3447. //
  3448. // =================================
  3449. // Clear OOBE settings for both minisetup and oobe.
  3450. // =================================
  3451. //
  3452. ResetOobeSettings();
  3453. //
  3454. // =================================
  3455. // Clear the eventlogs on the machine.
  3456. // This is the last thing that we should do.
  3457. // =================================
  3458. //
  3459. NukeEventLogs();
  3460. //
  3461. // =================================
  3462. // Delete temporary files.
  3463. // =================================
  3464. //
  3465. NukeTemporaryFiles();
  3466. return fReturn;
  3467. }
  3468. BOOL
  3469. AdjustRegistry(
  3470. IN BOOL fRemoveNetworkSettings
  3471. )
  3472. /*++
  3473. ===============================================================================
  3474. Routine Description:
  3475. This routine actually adds in the registry entry to enable our second half
  3476. to execute.
  3477. Arguments:
  3478. fRemoveNetworkSettings - indicates if network settings should be removed
  3479. Return Value:
  3480. None
  3481. ===============================================================================
  3482. --*/
  3483. {
  3484. HKEY hKey;
  3485. TCHAR szSysprepINFPath[MAX_PATH];
  3486. BOOL fPopulated = FALSE;
  3487. // Formulate the path to SYSPRE.INF, since we will need it later to look up
  3488. // sysprep options
  3489. if (!GetWindowsDirectory( szSysprepINFPath, MAX_PATH ))
  3490. return FALSE;
  3491. StringCchCopy ( &szSysprepINFPath[3], AS ( szSysprepINFPath ) - 3, TEXT("sysprep\\sysprep.inf") );
  3492. //
  3493. // Make sure we've got the required privileges to update the registry.
  3494. //
  3495. pSetupEnablePrivilege(SE_RESTORE_NAME,TRUE);
  3496. pSetupEnablePrivilege(SE_BACKUP_NAME,TRUE);
  3497. // Set OEMDuplicatorString
  3498. if (!SetOEMDuplicatorString(szSysprepINFPath))
  3499. return (FALSE);
  3500. // Fill in the [sysprepMassStorage] section for PopulateDeviceDatabase()
  3501. //
  3502. BuildMassStorageSection(FALSE);
  3503. //
  3504. // =================================
  3505. // Fixup boot devices.
  3506. // =================================
  3507. //
  3508. if (!PopulateDeviceDatabase(&fPopulated))
  3509. return FALSE;
  3510. //
  3511. // Perform miscellaneous registry modifications
  3512. //
  3513. // Determine if we should set the BigLba support in registry
  3514. //
  3515. if ( !SetBigLbaSupport(szSysprepINFPath) )
  3516. {
  3517. return FALSE;
  3518. }
  3519. // Determine if we should remove the TAPI settings in registry
  3520. //
  3521. if ( !RemoveTapiSettings(szSysprepINFPath) )
  3522. {
  3523. return FALSE;
  3524. }
  3525. //
  3526. // Remove the LastAliveStamp value so that we don't get erroneous entries into the even log
  3527. // and avoid pop-ups on first boot saying that the machine has been shutdown improperly.
  3528. //
  3529. if ( ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, STR_REG_KEY_RELIABILITY, &hKey) )
  3530. {
  3531. RegDeleteValue(hKey, STR_REG_VALUE_LASTALIVESTAMP);
  3532. RegCloseKey(hKey);
  3533. }
  3534. //
  3535. // =================================
  3536. // Reset network settings last so if any errors happen before we still
  3537. // have network access.
  3538. // =================================
  3539. //
  3540. if (fRemoveNetworkSettings)
  3541. {
  3542. if (!RemoveNetworkSettings(szSysprepINFPath))
  3543. return FALSE;
  3544. }
  3545. //
  3546. // =================================
  3547. // Change our boot timeout to 1.
  3548. // =================================
  3549. //
  3550. ChangeBootTimeout( 1 );
  3551. // Do common reseal code for both Sysprep and Riprep
  3552. //
  3553. if (!FCommonReseal())
  3554. return FALSE;
  3555. return TRUE;
  3556. }
  3557. BOOL
  3558. CreateSysprepTemporaryDevnode(
  3559. HDEVINFO* phDevInfo,
  3560. SP_DEVINFO_DATA* pDeviceInfoData
  3561. )
  3562. /*++
  3563. ===============================================================================
  3564. Routine Description:
  3565. Arguments:
  3566. None.
  3567. Return Value:
  3568. TRUE if everything is OK, FALSE otherwise.
  3569. Assumptions:
  3570. 1. No HardwareID exceeds MAX_PATH characters.
  3571. ===============================================================================
  3572. --*/
  3573. {
  3574. if (phDevInfo) {
  3575. //
  3576. // Create a dummy devnode
  3577. //
  3578. *phDevInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
  3579. if (*phDevInfo == INVALID_HANDLE_VALUE) {
  3580. return FALSE;
  3581. }
  3582. //
  3583. // Initialize the DriverInfoData struct
  3584. //
  3585. pDeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
  3586. //
  3587. // Create the devnode
  3588. //
  3589. if (pDeviceInfoData && !SetupDiCreateDeviceInfo(*phDevInfo,
  3590. L"SYSPREP_TEMPORARY",
  3591. (LPGUID)&GUID_NULL,
  3592. NULL,
  3593. NULL,
  3594. DICD_GENERATE_ID,
  3595. pDeviceInfoData)) {
  3596. //
  3597. // ISSUE-2002/02/26-brucegr: Destroy the info list and set phDevInfo to INVALID_HANDLE_VALUE?
  3598. //
  3599. return FALSE;
  3600. }
  3601. }
  3602. return TRUE;
  3603. }
  3604. BOOL InsertCleanupNode(PPCLEANUP_NODE ppCleanupList, PCLEANUP_NODE pAddNode)
  3605. {
  3606. PPCLEANUP_NODE ppl = ppCleanupList;
  3607. while ( *ppl != NULL && (0 < lstrcmpi(pAddNode->pszService, (*ppl)->pszService))
  3608. )
  3609. {
  3610. ppl = &((*ppl)->pNext);
  3611. }
  3612. if (*ppl && (0 == lstrcmpi(pAddNode->pszService, (*ppl)->pszService)))
  3613. {
  3614. free(pAddNode);
  3615. return FALSE;
  3616. }
  3617. pAddNode->pNext = *ppl;
  3618. *ppl = pAddNode;
  3619. return TRUE;
  3620. }
  3621. PCLEANUP_NODE FindCleanupNode(PPCLEANUP_NODE ppCleanupList, LPTSTR pszServiceName)
  3622. {
  3623. PCLEANUP_NODE pTemp = *ppCleanupList;
  3624. while (pTemp)
  3625. {
  3626. if (0 == lstrcmpi(pTemp->pszService, pszServiceName))
  3627. return pTemp;
  3628. pTemp = pTemp->pNext;
  3629. }
  3630. return NULL;
  3631. }
  3632. void FreeCleanupList(PPCLEANUP_NODE ppCleanupList)
  3633. {
  3634. while (*ppCleanupList)
  3635. {
  3636. PCLEANUP_NODE pTemp = *ppCleanupList;
  3637. *ppCleanupList = (*ppCleanupList)->pNext;
  3638. free(pTemp->pszService);
  3639. free(pTemp);
  3640. }
  3641. *ppCleanupList = NULL;
  3642. }
  3643. BOOL AddCleanupNode(
  3644. LPTSTR pszServiceName
  3645. )
  3646. /*++
  3647. ===============================================================================
  3648. Routine Description:
  3649. When populating the [SysprepCleanup] section we need to check if the service
  3650. or filters already exists in the this section before we enter a duplicate
  3651. entry.
  3652. Arguments:
  3653. LPTSTR pszServiceName - Service/Filter name.
  3654. Return Value:
  3655. TRUE if a duplicate found, FALSE otherwise.
  3656. Assumptions:
  3657. 1. No duplicate entries in [SysprepCleanup] section.
  3658. ===============================================================================
  3659. --*/
  3660. {
  3661. BOOL fAdded = FALSE;
  3662. //
  3663. // Find the Service in our list.
  3664. //
  3665. if (pszServiceName && (NULL == FindCleanupNode(&g_pCleanupListHead, pszServiceName)))
  3666. {
  3667. PCLEANUP_NODE pNode = (PCLEANUP_NODE)malloc(sizeof(CLEANUP_NODE));
  3668. if (pNode)
  3669. {
  3670. int nLen = lstrlen ( pszServiceName ) + 1;
  3671. pNode->pszService = (LPTSTR)malloc( nLen * sizeof ( TCHAR ) );
  3672. if ( pNode->pszService )
  3673. {
  3674. StringCchCopy (pNode->pszService, nLen, pszServiceName);
  3675. }
  3676. pNode->pNext = NULL;
  3677. //
  3678. // We didn't find it so add it to our list.
  3679. // We will not add duplicates to our list.
  3680. //
  3681. fAdded = InsertCleanupNode(&g_pCleanupListHead, pNode);
  3682. }
  3683. }
  3684. return fAdded;
  3685. }
  3686. BOOL
  3687. PopulateDeviceDatabase(
  3688. IN BOOL* pfPopulated
  3689. )
  3690. /*++
  3691. ===============================================================================
  3692. Routine Description:
  3693. Parse the [SysprepMassStorage] section in the sysprep.inf file and
  3694. populate the critical device database with the specified devices to ensure
  3695. that we can boot into the miniwizard when moving the image to a target
  3696. system with different boot storage devices.
  3697. The installed services/upperfilters/lowerfilters will be recorded, so
  3698. that on the next boot into the mini-wizard those without an associated
  3699. device will be disabled (the cleanup stage) in order not to unnecessarily
  3700. degrade Windows start time.
  3701. Arguments:
  3702. None.
  3703. Return Value:
  3704. TRUE if everything is OK, FALSE otherwise.
  3705. Assumptions:
  3706. 1. No HardwareID exceeds MAX_PATH characters.
  3707. 2. No field on a line in the [SysprepMassStorage] section exceeds MAX_PATH
  3708. characters.
  3709. 3. No service's/upperfilter's/lowerfilter's name exceeds MAX_PATH characters.
  3710. 4. DirectoryOnSourceDevice, source DiskDescription, or source DiskTag
  3711. (applying to vendor-supplied drivers) cannot exceed MAX_PATH characters.
  3712. ===============================================================================
  3713. --*/
  3714. {
  3715. BOOL bAllOK = TRUE;
  3716. PCWSTR pszSectionName = L"SysprepMassStorage";
  3717. WCHAR szSysprepInfFile[] = L"?:\\sysprep\\sysprep.inf";
  3718. #ifdef DEBUG_LOGLOG
  3719. WCHAR szLogFile[] = L"?:\\sysprep.log";
  3720. #endif
  3721. WCHAR szBuffer[MAX_PATH], *pszFilter;
  3722. CHAR szOutBufferA[MAX_PATH];
  3723. HANDLE hInfFile = INVALID_HANDLE_VALUE;
  3724. HINF hAnswerInf = INVALID_HANDLE_VALUE;
  3725. BOOL bLineExists;
  3726. INFCONTEXT InfContext;
  3727. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  3728. SP_DEVINFO_DATA DeviceInfoData;
  3729. SP_DEVINSTALL_PARAMS DevInstallParams;
  3730. SP_DRVINFO_DATA DriverInfoData;
  3731. HSPFILEQ QueueHandle = INVALID_HANDLE_VALUE;
  3732. DWORD dwSize = 0;
  3733. BOOL bNodeCreated = FALSE;
  3734. WCHAR DirectoryOnSourceDevice[MAX_PATH];
  3735. WCHAR DiskDescription[MAX_PATH];
  3736. WCHAR DiskTag[MAX_PATH];
  3737. PSYSPREP_QUEUE_CONTEXT pSysprepContext;
  3738. if (!GetWindowsDirectory(szBuffer, MAX_PATH))
  3739. return FALSE;
  3740. szSysprepInfFile[0] = szBuffer[0];
  3741. #ifdef DEBUG_LOGLOG
  3742. szLogFile[0] = szBuffer[0];
  3743. DeleteFile(szLogFile);
  3744. LOG_Init(szLogFile);
  3745. LOG_Write(L">>\r\n>> PopulateDeviceDatabase\r\n>>\r\n");
  3746. LOG_Write(L"Sysprep.inf=%s", szSysprepInfFile);
  3747. #endif
  3748. //
  3749. // =================================
  3750. // Open the sysprep.inf file. Since we don't know what the user has in
  3751. // here, so try opening as both styles.
  3752. // =================================
  3753. //
  3754. //
  3755. // ISSUE-2002/02/26-brucegr: You can specify both bits in one call...
  3756. //
  3757. hAnswerInf = SetupOpenInfFile(szSysprepInfFile, NULL, INF_STYLE_WIN4, NULL);
  3758. if (hAnswerInf == INVALID_HANDLE_VALUE) {
  3759. hAnswerInf = SetupOpenInfFile(szSysprepInfFile, NULL, INF_STYLE_OLDNT, NULL);
  3760. if (hAnswerInf == INVALID_HANDLE_VALUE) {
  3761. //
  3762. // User didn't give us a sysprep.inf. Return as if nothing
  3763. // happened.
  3764. //
  3765. return TRUE;
  3766. }
  3767. }
  3768. //
  3769. // open the same inf file to record upper filters, lower filters, and
  3770. // services of the added devices
  3771. //
  3772. hInfFile = CreateFile(szSysprepInfFile,
  3773. GENERIC_WRITE,
  3774. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3775. NULL,
  3776. OPEN_ALWAYS,
  3777. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  3778. NULL);
  3779. if (hInfFile == INVALID_HANDLE_VALUE) {
  3780. goto PDD_Critical_Error_Handler;
  3781. }
  3782. //
  3783. // =================================
  3784. // Create/clear [sysprepcleanup] which should be at the bottom of the file.
  3785. // =================================
  3786. //
  3787. WritePrivateProfileSection(L"sysprepcleanup", L"", szSysprepInfFile);
  3788. //
  3789. // =================================
  3790. // Create a dummy devnode
  3791. // =================================
  3792. //
  3793. bNodeCreated = CreateSysprepTemporaryDevnode(&hDevInfo, &DeviceInfoData);
  3794. // Initialize the DriverInfoData struct
  3795. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  3796. if (!bNodeCreated)
  3797. goto PDD_Critical_Error_Handler;
  3798. //
  3799. // =================================
  3800. // Process each line in our section. Each line should look like:
  3801. // <hardware-id>=<inf pathname>
  3802. // or in the case of drivers that aren't on the product CD:
  3803. // <hardware-id>=<inf pathname>,<directory on recovery floppy>,<description of recovery floppy>,<disk tag of recovery floppy>
  3804. //
  3805. // If we see an entry like this, we'll know that in the case of system recovery, the
  3806. // file should be retrived from a floppy, and not the Windows CD.
  3807. // =================================
  3808. //
  3809. bLineExists = SetupFindFirstLine(hAnswerInf, pszSectionName, NULL, &InfContext);
  3810. //
  3811. // =================================
  3812. // Let caller know we've go entries to populate.
  3813. // =================================
  3814. //
  3815. if (pfPopulated)
  3816. *pfPopulated = bLineExists;
  3817. while (bLineExists) {
  3818. #ifdef DEBUG_LOGLOG
  3819. LOG_Write(L"");
  3820. #endif
  3821. //
  3822. // =================================
  3823. // Step 1: Set the hardwareID of the devnode.
  3824. // =================================
  3825. //
  3826. //
  3827. // retrieve the hardwareID from the line
  3828. //
  3829. ZeroMemory( szBuffer, sizeof(szBuffer) );
  3830. dwSize = MAX_PATH - 2;
  3831. if (!SetupGetStringField(&InfContext, 0, szBuffer, dwSize, &dwSize)) {
  3832. #ifdef DEBUG_LOGLOG
  3833. LOG_WriteLastError();
  3834. #endif
  3835. bAllOK = FALSE;
  3836. goto PDD_Next_Inf_Line;
  3837. }
  3838. #ifdef DEBUG_LOGLOG
  3839. LOG_Write(L"HardwareID=%s", szBuffer);
  3840. #endif
  3841. //
  3842. // and then set it to the devnode,
  3843. //
  3844. if ( !SetupDiSetDeviceRegistryProperty( hDevInfo,
  3845. &DeviceInfoData,
  3846. SPDRP_HARDWAREID,
  3847. (PBYTE)szBuffer,
  3848. (lstrlen(szBuffer) + 2) * sizeof(WCHAR) ) ) {
  3849. #ifdef DEBUG_LOGLOG
  3850. LOG_WriteLastError();
  3851. #endif
  3852. // If someone removed the devnode, we need to re-create it and repeat this pnp device
  3853. //
  3854. if (ERROR_NO_SUCH_DEVINST == GetLastError()) {
  3855. // Re-create the SYSPREP_TEMPORARY devnode again
  3856. //
  3857. bAllOK = CreateSysprepTemporaryDevnode(&hDevInfo, &DeviceInfoData);
  3858. bNodeCreated = bAllOK;
  3859. // Set the hardwareID again
  3860. //
  3861. //
  3862. // NTRAID#NTBUG9-551868-2002/02/26-brucegr: Need to increase size parameter by one WCHAR
  3863. //
  3864. if ( bNodeCreated &&
  3865. !SetupDiSetDeviceRegistryProperty( hDevInfo,
  3866. &DeviceInfoData,
  3867. SPDRP_HARDWAREID,
  3868. (PBYTE)szBuffer,
  3869. ( lstrlen(szBuffer) + 2 ) * sizeof(WCHAR) ) ) {
  3870. // We failed again, then quit
  3871. //
  3872. bAllOK = FALSE;
  3873. goto PDD_Critical_Error_Handler;
  3874. }
  3875. }
  3876. else {
  3877. bAllOK = FALSE;
  3878. goto PDD_Next_Inf_Line;
  3879. }
  3880. }
  3881. //
  3882. // make sure that there's no existing compatible list, since we're reusing
  3883. // the dummy devnode
  3884. //
  3885. if (!SetupDiDestroyDriverInfoList(hDevInfo, &DeviceInfoData, SPDIT_COMPATDRIVER)) {
  3886. #ifdef DEBUG_LOGLOG
  3887. LOG_WriteLastError();
  3888. #endif
  3889. bAllOK = FALSE;
  3890. goto PDD_Next_Inf_Line;
  3891. }
  3892. //
  3893. // Build the SP_DEVINSTALL_PARAMS for this node.
  3894. //
  3895. DevInstallParams.cbSize = sizeof(DevInstallParams);
  3896. if (!SetupDiGetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams)) {
  3897. #ifdef DEBUG_LOGLOG
  3898. LOG_WriteLastError();
  3899. #endif
  3900. bAllOK = FALSE;
  3901. goto PDD_Next_Inf_Line;
  3902. }
  3903. //
  3904. // set the Flags field: only search the INF file specified in DriverPath field;
  3905. // don't create a copy queue, use the provided one in FileQueue; don't call the
  3906. // Configuration Manager while populating the CriticalDeviceDatabase.
  3907. //
  3908. DevInstallParams.Flags |= DI_ENUMSINGLEINF;
  3909. DevInstallParams.Flags |= DI_NOVCP;
  3910. DevInstallParams.Flags |= DI_DONOTCALLCONFIGMG;
  3911. //
  3912. // set the file queue field
  3913. //
  3914. QueueHandle = SetupOpenFileQueue();
  3915. if (QueueHandle == INVALID_HANDLE_VALUE) {
  3916. #ifdef DEBUG_LOGLOG
  3917. LOG_WriteLastError();
  3918. #endif
  3919. bAllOK = FALSE;
  3920. goto PDD_Next_Inf_Line;
  3921. }
  3922. DevInstallParams.FileQueue = QueueHandle;
  3923. //
  3924. // set the device's inf pathname
  3925. //
  3926. dwSize = MAX_PATH;
  3927. if (!SetupGetStringField(&InfContext, 1, szBuffer, dwSize, &dwSize)) {
  3928. #ifdef DEBUG_LOGLOG
  3929. LOG_WriteLastError();
  3930. #endif
  3931. bAllOK = FALSE;
  3932. goto PDD_Next_Inf_Line;
  3933. }
  3934. ExpandEnvironmentStrings(szBuffer, DevInstallParams.DriverPath, MAX_PATH);
  3935. #ifdef DEBUG_LOGLOG
  3936. LOG_Write(L"DriverPath=%s", DevInstallParams.DriverPath);
  3937. #endif
  3938. if (!SetupDiSetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams)) {
  3939. #ifdef DEBUG_LOGLOG
  3940. LOG_WriteLastError();
  3941. #endif
  3942. bAllOK = FALSE;
  3943. goto PDD_Next_Inf_Line;
  3944. }
  3945. //
  3946. // Register the newly created device instance with the PnP Manager.
  3947. //
  3948. if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE,
  3949. hDevInfo,
  3950. &DeviceInfoData)) {
  3951. #ifdef DEBUG_LOGLOG
  3952. LOG_WriteLastError();
  3953. #endif
  3954. bAllOK = FALSE;
  3955. goto PDD_Next_Inf_Line;
  3956. }
  3957. //
  3958. // =================================
  3959. // Step 2: Perform a compatible driver search.
  3960. // =================================
  3961. //
  3962. if (!SetupDiBuildDriverInfoList(hDevInfo, &DeviceInfoData, SPDIT_COMPATDRIVER)) {
  3963. #ifdef DEBUG_LOGLOG
  3964. LOG_WriteLastError();
  3965. #endif
  3966. bAllOK = FALSE;
  3967. goto PDD_Next_Inf_Line;
  3968. }
  3969. // Make sure there is at least 1 compat driver for this device.
  3970. // If there is not, and then we just process the next one in the list
  3971. if (!SetupDiEnumDriverInfo(hDevInfo,
  3972. &DeviceInfoData,
  3973. SPDIT_COMPATDRIVER,
  3974. 0,
  3975. &DriverInfoData))
  3976. {
  3977. // Check to see what the error was. Any error other than ERROR_NO_MORE_ITEMS
  3978. // will be flaged, by setting the bAllOK return value to FALSE
  3979. if (ERROR_NO_MORE_ITEMS != GetLastError())
  3980. {
  3981. #ifdef DEBUG_LOGLOG
  3982. LOG_WriteLastError();
  3983. #endif
  3984. bAllOK = FALSE;
  3985. }
  3986. goto PDD_Next_Inf_Line;
  3987. }
  3988. //
  3989. // =================================
  3990. // Step 3: Select the best compatible driver.
  3991. // =================================
  3992. //
  3993. if (!SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV,
  3994. hDevInfo,
  3995. &DeviceInfoData)) {
  3996. #ifdef DEBUG_LOGLOG
  3997. LOG_WriteLastError();
  3998. #endif
  3999. bAllOK = FALSE;
  4000. goto PDD_Next_Inf_Line;
  4001. }
  4002. //
  4003. // =================================
  4004. // Step 4: Install the driver files.
  4005. // =================================
  4006. //
  4007. if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
  4008. hDevInfo,
  4009. &DeviceInfoData)) {
  4010. #ifdef DEBUG_LOGLOG
  4011. LOG_WriteLastError();
  4012. #endif
  4013. bAllOK = FALSE;
  4014. goto PDD_Next_Inf_Line;
  4015. }
  4016. //
  4017. // Need to commit the file queue here, so the later steps can properly
  4018. // be executed in case the device doesn't use the already existing
  4019. // coinstaller(s).
  4020. //
  4021. pSysprepContext = (PSYSPREP_QUEUE_CONTEXT) InitSysprepQueueCallback();
  4022. //
  4023. // Retrieve DirectoryOnSourceDevice from the inf line, if any
  4024. //
  4025. dwSize = MAX_PATH;
  4026. DirectoryOnSourceDevice[0] = L'\0';
  4027. if (!SetupGetStringField(&InfContext, 2, DirectoryOnSourceDevice, dwSize, &dwSize)) {
  4028. DirectoryOnSourceDevice[0] = L'\0';
  4029. }
  4030. if (DirectoryOnSourceDevice[0] != L'\0') {
  4031. pSysprepContext->DirectoryOnSourceDevice = DirectoryOnSourceDevice;
  4032. }
  4033. //
  4034. // Retrieve DiskDescription from the inf line, if any
  4035. //
  4036. dwSize = MAX_PATH;
  4037. DiskDescription[0] = L'\0';
  4038. if (!SetupGetStringField(&InfContext, 3, DiskDescription, dwSize, &dwSize)) {
  4039. DiskDescription[0] = L'\0';
  4040. }
  4041. if (DiskDescription[0] != L'\0') {
  4042. pSysprepContext->DiskDescription = DiskDescription;
  4043. }
  4044. //
  4045. // Retrieve DiskTag from the inf line, if any
  4046. //
  4047. dwSize = MAX_PATH;
  4048. DiskTag[0] = L'\0';
  4049. if (!SetupGetStringField(&InfContext, 4, DiskTag, dwSize, &dwSize)) {
  4050. DiskTag[0] = L'\0';
  4051. }
  4052. if (DiskTag[0] != L'\0') {
  4053. pSysprepContext->DiskTag = DiskTag;
  4054. }
  4055. //
  4056. // Commit the file queue
  4057. //
  4058. if (!SetupCommitFileQueue(NULL,
  4059. QueueHandle,
  4060. SysprepQueueCallback,
  4061. pSysprepContext)) {
  4062. #ifdef DEBUG_LOGLOG
  4063. LOG_WriteLastError();
  4064. #endif
  4065. }
  4066. FreeSysprepContext(pSysprepContext);
  4067. //
  4068. // =================================
  4069. // Step 4a: Dis-associate file copy queue before we close
  4070. // the queue.
  4071. // =================================
  4072. //
  4073. DevInstallParams.cbSize = sizeof(DevInstallParams);
  4074. if (!SetupDiGetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams)) {
  4075. #ifdef DEBUG_LOGLOG
  4076. LOG_WriteLastError();
  4077. #endif
  4078. bAllOK = FALSE;
  4079. goto PDD_Next_Inf_Line;
  4080. }
  4081. //
  4082. // Remove the DI_NOVCP flag and NULL out the FileQueue.
  4083. //
  4084. DevInstallParams.Flags &= ~DI_NOVCP;
  4085. DevInstallParams.FileQueue = NULL;
  4086. if (!SetupDiSetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams)) {
  4087. #ifdef DEBUG_LOGLOG
  4088. LOG_WriteLastError();
  4089. #endif
  4090. bAllOK = FALSE;
  4091. goto PDD_Next_Inf_Line;
  4092. }
  4093. SetupCloseFileQueue(QueueHandle);
  4094. QueueHandle = INVALID_HANDLE_VALUE;
  4095. //
  4096. // =================================
  4097. // Step 5: Register the device-specific coinstallers.
  4098. // =================================
  4099. //
  4100. if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
  4101. hDevInfo,
  4102. &DeviceInfoData)) {
  4103. #ifdef DEBUG_LOGLOG
  4104. LOG_WriteLastError();
  4105. #endif
  4106. bAllOK = FALSE;
  4107. goto PDD_Next_Inf_Line;
  4108. }
  4109. //
  4110. // =================================
  4111. // Step 6: Install the device.
  4112. // =================================
  4113. //
  4114. if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
  4115. hDevInfo,
  4116. &DeviceInfoData)) {
  4117. #ifdef DEBUG_LOGLOG
  4118. LOG_WriteLastError();
  4119. #endif
  4120. bAllOK = FALSE;
  4121. goto PDD_Next_Inf_Line;
  4122. }
  4123. //
  4124. // =================================
  4125. // Step 7: Retrieve upper filters, lower filters,
  4126. // and controlling service, save them back
  4127. // to the inf file.
  4128. // =================================
  4129. //
  4130. //
  4131. // retrieve device upperfilters (REG_MULTI_SZ)
  4132. //
  4133. if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
  4134. &DeviceInfoData,
  4135. SPDRP_UPPERFILTERS,
  4136. NULL,
  4137. (PBYTE)szBuffer,
  4138. sizeof(szBuffer),
  4139. NULL)) {
  4140. szBuffer[0] = L'\0';
  4141. }
  4142. for (pszFilter = szBuffer; *pszFilter; pszFilter += (lstrlen(pszFilter) + 1)) {
  4143. StringCchPrintfA(szOutBufferA, AS ( szOutBufferA ), "Upperfilter=%S\r\n", pszFilter);
  4144. if (AddCleanupNode(pszFilter)) {
  4145. SetFilePointer(hInfFile, 0L, 0L, FILE_END);
  4146. WriteFile(hInfFile, szOutBufferA, strlen(szOutBufferA), &dwSize, NULL);
  4147. }
  4148. #ifdef DEBUG_LOGLOG
  4149. LOG_Write(L"Upperfilter=%s", pszFilter);
  4150. #endif
  4151. }
  4152. //
  4153. // retrieve device lowerfilters (REG_MULTI_SZ)
  4154. //
  4155. if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
  4156. &DeviceInfoData,
  4157. SPDRP_LOWERFILTERS,
  4158. NULL,
  4159. (PBYTE)szBuffer,
  4160. sizeof(szBuffer),
  4161. NULL)) {
  4162. szBuffer[0] = L'\0';
  4163. }
  4164. for (pszFilter = szBuffer; *pszFilter; pszFilter += (lstrlen(pszFilter) + 1)) {
  4165. StringCchPrintfA(szOutBufferA, AS ( szOutBufferA ), "Lowerfilter=%S\r\n", pszFilter);
  4166. if (AddCleanupNode(pszFilter)) {
  4167. SetFilePointer(hInfFile, 0L, 0L, FILE_END);
  4168. WriteFile(hInfFile, szOutBufferA, strlen(szOutBufferA), &dwSize, NULL);
  4169. }
  4170. #ifdef DEBUG_LOGLOG
  4171. LOG_Write(L"Lowerfilter=%s", pszFilter);
  4172. #endif
  4173. }
  4174. //
  4175. // retrieve device its controlling service (REG_SZ)
  4176. //
  4177. if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
  4178. &DeviceInfoData,
  4179. SPDRP_SERVICE,
  4180. NULL,
  4181. (PBYTE)szBuffer,
  4182. sizeof(szBuffer),
  4183. NULL)) {
  4184. szBuffer[0] = L'\0';
  4185. }
  4186. if (szBuffer[0] != L'\0') {
  4187. StringCchPrintfA(szOutBufferA, AS ( szOutBufferA ), "Service=%S\r\n", szBuffer);
  4188. if (AddCleanupNode(szBuffer)) {
  4189. SetFilePointer(hInfFile, 0L, 0L, FILE_END);
  4190. WriteFile(hInfFile, szOutBufferA, strlen(szOutBufferA), &dwSize, NULL);
  4191. }
  4192. #ifdef DEBUG_LOGLOG
  4193. LOG_Write(L"Service=%s", szBuffer);
  4194. #endif
  4195. }
  4196. PDD_Next_Inf_Line:
  4197. if (QueueHandle != INVALID_HANDLE_VALUE) {
  4198. SetupCloseFileQueue(QueueHandle);
  4199. QueueHandle = INVALID_HANDLE_VALUE;
  4200. }
  4201. //
  4202. // Get the next line from the relevant section in the inf file.
  4203. //
  4204. bLineExists = SetupFindNextLine(&InfContext, &InfContext);
  4205. }
  4206. //
  4207. // =================================
  4208. // Cleanup for a successful run
  4209. // =================================
  4210. //
  4211. //
  4212. // remove the SYSPREP_TEMPORARY node under Root
  4213. //
  4214. SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, &DeviceInfoData);
  4215. SetupDiDestroyDeviceInfoList(hDevInfo);
  4216. CloseHandle(hInfFile);
  4217. SetupCloseInfFile(hAnswerInf);
  4218. //
  4219. // Backup the system hive to the Repair folder
  4220. //
  4221. if (!BackupHives()) {
  4222. #ifdef DEBUG_LOGLOG
  4223. LOG_Write(L"ERROR - Unable to backup the system hive.");
  4224. #endif
  4225. bAllOK = FALSE;
  4226. }
  4227. #ifdef DEBUG_LOGLOG
  4228. LOG_DeInit();
  4229. #endif
  4230. FreeCleanupList(&g_pCleanupListHead);
  4231. return bAllOK;
  4232. //
  4233. // =================================
  4234. PDD_Critical_Error_Handler:
  4235. // =================================
  4236. //
  4237. #ifdef DEBUG_LOGLOG
  4238. LOG_WriteLastError();
  4239. #endif
  4240. if (QueueHandle != INVALID_HANDLE_VALUE) {
  4241. SetupCloseFileQueue(QueueHandle);
  4242. }
  4243. //
  4244. // remove the SYSPREP_TEMPORARY node under Root
  4245. //
  4246. if (bNodeCreated) {
  4247. SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, &DeviceInfoData);
  4248. }
  4249. if (hDevInfo != INVALID_HANDLE_VALUE) {
  4250. SetupDiDestroyDeviceInfoList(hDevInfo);
  4251. }
  4252. if (hInfFile != INVALID_HANDLE_VALUE) {
  4253. CloseHandle(hInfFile);
  4254. }
  4255. if (hAnswerInf != INVALID_HANDLE_VALUE) {
  4256. SetupCloseInfFile(hAnswerInf);
  4257. }
  4258. #ifdef DEBUG_LOGLOG
  4259. LOG_DeInit();
  4260. #endif
  4261. FreeCleanupList(&g_pCleanupListHead);
  4262. return FALSE;
  4263. }
  4264. /*++
  4265. ===============================================================================
  4266. Routine Description:
  4267. Check to see if the service name passed in is in use by a PnP enumerated
  4268. device.
  4269. Arguments:
  4270. lpszServiceName
  4271. Return Value:
  4272. TRUE. The service is in use, or will be in use by a device (as evidenced by
  4273. the presence of the service name as a registry property for an enumerated
  4274. device)
  4275. FALSE. The service is not in use.
  4276. If LastError is set, then a bad thing happed, otherwise the service is
  4277. just not being used
  4278. Assumptions:
  4279. ===============================================================================
  4280. --*/
  4281. BOOL ServiceInUseByDevice
  4282. (
  4283. LPTSTR lpszServiceName
  4284. )
  4285. {
  4286. HDEVINFO DeviceInfoSet;
  4287. HDEVINFO NewDeviceInfoSet;
  4288. DWORD i;
  4289. SP_DEVINFO_DATA DevInfoData;
  4290. TCHAR szServiceName[MAX_PATH];
  4291. TCHAR szDeviceClass[MAX_PATH];
  4292. BOOL bRet = FALSE;
  4293. TCHAR szLegacyClass[MAX_CLASS_NAME_LEN];
  4294. // Clear the last error
  4295. SetLastError(0);
  4296. // Get the Class description for LegacyDriver
  4297. if (!SetupDiClassNameFromGuid(&GUID_DEVCLASS_LEGACYDRIVER,
  4298. szLegacyClass,
  4299. sizeof(szLegacyClass)/sizeof(TCHAR),
  4300. NULL))
  4301. {
  4302. #ifdef DEBUG_LOGLOG
  4303. LOG_Write(L"Unable to get LegacyDriver Class NAME");
  4304. #endif
  4305. // NOTE: LastError will be set to the appropriate error code by
  4306. // SetupDiGetClassDescription
  4307. return FALSE;
  4308. }
  4309. // Create a device information set that will be used to enumerate all
  4310. // present devices
  4311. DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);
  4312. if(DeviceInfoSet == INVALID_HANDLE_VALUE)
  4313. {
  4314. #ifdef DEBUG_LOGLOG
  4315. LOG_Write(L"Unable to Create a device info list");
  4316. #endif
  4317. SetLastError(E_FAIL);
  4318. return FALSE;
  4319. }
  4320. // Get a list of all present devices on the system
  4321. NewDeviceInfoSet = SetupDiGetClassDevsEx(NULL,
  4322. NULL,
  4323. NULL,
  4324. DIGCF_PRESENT | DIGCF_ALLCLASSES,
  4325. DeviceInfoSet,
  4326. NULL,
  4327. NULL);
  4328. if(NewDeviceInfoSet == INVALID_HANDLE_VALUE)
  4329. {
  4330. #ifdef DEBUG_LOGLOG
  4331. LOG_Write(L"Unable to enumerate present devices");
  4332. #endif
  4333. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  4334. SetLastError(E_FAIL);
  4335. return FALSE;
  4336. }
  4337. // Enumerate the list of devices, checking to see if the service listed in the
  4338. // registry matches the service we are interested in.
  4339. i = 0;
  4340. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  4341. while (SetupDiEnumDeviceInfo(NewDeviceInfoSet, i, &DevInfoData))
  4342. {
  4343. // See if this is devnode is using the service we care about.
  4344. // if so, then we will check to see if it is a legacy devnode. If it
  4345. // is NOT a legacy devnode, then we will not mess with it, because
  4346. // the service is in use by a real device.
  4347. if (SetupDiGetDeviceRegistryProperty(NewDeviceInfoSet,
  4348. &DevInfoData,
  4349. SPDRP_SERVICE,
  4350. NULL,
  4351. (PBYTE) szServiceName,
  4352. sizeof(szServiceName),
  4353. NULL))
  4354. {
  4355. // See if this is the service we are looking for
  4356. if (0 == lstrcmpiW(lpszServiceName, szServiceName))
  4357. {
  4358. // Check for a legacy class device
  4359. if (SetupDiGetDeviceRegistryProperty(NewDeviceInfoSet,
  4360. &DevInfoData,
  4361. SPDRP_CLASS,
  4362. NULL,
  4363. (PBYTE) szDeviceClass,
  4364. sizeof(szDeviceClass),
  4365. NULL))
  4366. {
  4367. // We have the class, lets see if it is a legacy device
  4368. if (0 != lstrcmpiW(szLegacyClass, szDeviceClass))
  4369. {
  4370. // it is NOT a legacy device, so this service is in use!
  4371. bRet = TRUE;
  4372. break;
  4373. }
  4374. }
  4375. else
  4376. {
  4377. // We don't know the class, but it is not legacy (otherwise we
  4378. // would have gotten the class returned above, so assume it is
  4379. // is use!
  4380. bRet = TRUE;
  4381. break;
  4382. }
  4383. }
  4384. }
  4385. ++i;
  4386. }
  4387. // Clean up the device info sets that were allocated
  4388. SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);
  4389. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  4390. return bRet;
  4391. }
  4392. BOOL
  4393. CleanDeviceDatabase(
  4394. VOID
  4395. )
  4396. /*++
  4397. ===============================================================================
  4398. Routine Description:
  4399. Parse the [SysprepCleanup] section in the sysprep.inf file, which was
  4400. created during the PopulateDeviceDatabase stage, and disable those
  4401. listed services/upperfilters/lowerfilters which don't have associated
  4402. physical devices.
  4403. The strategy here is that we try to stop each listed service/upperfilter/
  4404. lowerfilter. It will only be stopped if it's not currently running (so
  4405. not controlling a PnP devnode), or is associated with a legacy devnode
  4406. (Root\LEGACY_<SvcName>\0000). Once it can be stopped, we can safely
  4407. disable it.
  4408. Arguments:
  4409. None.
  4410. Return Value:
  4411. TRUE. No errors encountered
  4412. FALSE. Some error occurred. It's not likely that the call will be able
  4413. to do much though.
  4414. Assumptions:
  4415. 1. All listed services/upperfilters/lowerfilters have no dependencies.
  4416. 2. No service's/upperfilter's/lowerfilter's name exceeds MAX_PATH characters.
  4417. ===============================================================================
  4418. --*/
  4419. {
  4420. BOOL bAllOK = TRUE;
  4421. PCWSTR pszSectionName = L"SysprepCleanup";
  4422. WCHAR szSysprepInfFile[] = L"?:\\sysprep\\sysprep.inf";
  4423. #ifdef DEBUG_LOGLOG
  4424. WCHAR szLogFile[] = L"?:\\sysprep.log";
  4425. #endif
  4426. WCHAR szServiceName[MAX_PATH];
  4427. WCHAR szBuffer[MAX_PATH], *pszDevID;
  4428. HINF hAnswerInf = INVALID_HANDLE_VALUE;
  4429. BOOL bLineExists;
  4430. INFCONTEXT InfContext;
  4431. DWORD dwSize;
  4432. CONFIGRET cfgRetVal;
  4433. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  4434. SP_DEVINFO_DATA DeviceInfoData;
  4435. SC_HANDLE hSC = NULL;
  4436. SC_HANDLE hSvc = NULL;
  4437. LPQUERY_SERVICE_CONFIG psvcConfig = NULL;
  4438. DWORD Type, l;
  4439. HKEY hKey;
  4440. if (!GetWindowsDirectory(szBuffer, MAX_PATH)) {
  4441. //
  4442. // Unable to get Windows Directory
  4443. //
  4444. return FALSE;
  4445. }
  4446. szSysprepInfFile[0] = szBuffer[0];
  4447. #ifdef DEBUG_LOGLOG
  4448. szLogFile[0] = szBuffer[0];
  4449. LOG_Init(szLogFile);
  4450. LOG_Write(L">>\r\n>> CleanDeviceDatabase\r\n>>\r\n");
  4451. LOG_Write(L"Sysprep.inf=%s", szSysprepInfFile);
  4452. #endif
  4453. //
  4454. // =================================
  4455. // HACK. Winlogon may erroneously append a ',' onto
  4456. // the end of the path to explorer. This would normally
  4457. // get fixed up by ie.inf, but for the sysprep case,
  4458. // this inf isn't run, so we'll continue to have this
  4459. // bad path in the registry. Fix it here.
  4460. // =================================
  4461. //
  4462. //
  4463. // Open HKLM\Software\Microsoft\Windows NT\CurrentVersion\WinLogon
  4464. //
  4465. l = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  4466. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  4467. 0,
  4468. KEY_ALL_ACCESS,
  4469. &hKey );
  4470. if( l == NO_ERROR ) {
  4471. //
  4472. // Query the value of the Shell Key.
  4473. //
  4474. //
  4475. // ISSUE-2002/02/26-brucegr: dwSize = sizeof(szBuffer);
  4476. //
  4477. dwSize = sizeof(szBuffer)/sizeof(szBuffer[0]);
  4478. l = RegQueryValueEx( hKey,
  4479. TEXT("Shell"),
  4480. NULL,
  4481. &Type,
  4482. (LPBYTE)szBuffer,
  4483. &dwSize );
  4484. if( l == NO_ERROR ) {
  4485. pszDevID = wcschr( szBuffer, L',' );
  4486. if( pszDevID ) {
  4487. //
  4488. // We hit, so we should set it back to "Explorer.exe"
  4489. //
  4490. StringCchCopy ( szBuffer, AS ( szBuffer ), L"Explorer.exe" );
  4491. //
  4492. // Now set the key with our new value.
  4493. //
  4494. l = RegSetValueEx( hKey,
  4495. TEXT("Shell"),
  4496. 0,
  4497. REG_SZ,
  4498. (CONST BYTE *)szBuffer,
  4499. (lstrlen( szBuffer ) + 1) * sizeof(WCHAR));
  4500. }
  4501. }
  4502. RegCloseKey(hKey);
  4503. }
  4504. //
  4505. // =================================
  4506. // Open the sysprep.inf file. Since we don't know what the user has in
  4507. // here, so try opening as both styles.
  4508. // =================================
  4509. //
  4510. //
  4511. // ISSUE-2002/02/26-brucegr: You can pass in both bits in one call to SetupOpenInfFile
  4512. //
  4513. hAnswerInf = SetupOpenInfFile(szSysprepInfFile, NULL, INF_STYLE_WIN4, NULL);
  4514. if (hAnswerInf == INVALID_HANDLE_VALUE) {
  4515. hAnswerInf = SetupOpenInfFile(szSysprepInfFile, NULL, INF_STYLE_OLDNT, NULL);
  4516. if (hAnswerInf == INVALID_HANDLE_VALUE) {
  4517. //
  4518. // User didn't give us a sysprep.inf. Return as if nothing
  4519. // happened.
  4520. //
  4521. return TRUE;
  4522. }
  4523. }
  4524. //
  4525. // =================================
  4526. // Remove the buildmassstoragesection=yes if it exists.
  4527. // =================================
  4528. //
  4529. WritePrivateProfileString(SYSPREP_SECTION, SYSPREP_BUILDMASSSTORAGE_KEY, NULL, szSysprepInfFile);
  4530. //
  4531. // =================================
  4532. // Establish a connection to the service control manager on the local
  4533. // computer to retrieve status and reconfig services.
  4534. // =================================
  4535. //
  4536. hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  4537. if (hSC == NULL) {
  4538. goto CDD_Critical_Error_Handler;
  4539. }
  4540. //
  4541. // =================================
  4542. // Process each line in our section
  4543. // =================================
  4544. //
  4545. bLineExists = SetupFindFirstLine(hAnswerInf, pszSectionName, NULL, &InfContext);
  4546. while (bLineExists) {
  4547. #ifdef DEBUG_LOGLOG
  4548. LOG_Write(L"");
  4549. #endif
  4550. //
  4551. // We've got a line, and it should look like:
  4552. // <key>=<service name>
  4553. //
  4554. //
  4555. // =================================
  4556. // Retrieve the service name from the line
  4557. // =================================
  4558. //
  4559. dwSize = MAX_PATH;
  4560. if (!SetupGetStringField(&InfContext, 1, szServiceName, dwSize, &dwSize)) {
  4561. #ifdef DEBUG_LOGLOG
  4562. LOG_WriteLastError();
  4563. #endif
  4564. bAllOK = FALSE;
  4565. goto CDD_Next_Inf_Line;
  4566. }
  4567. #ifdef DEBUG_LOGLOG
  4568. LOG_Write(L"Service=%s", szServiceName);
  4569. #endif
  4570. //
  4571. // ISSUE-2002/02/26-brucegr: EXPENSIVE!!! Should build the in-use service list once and then loop through INF.
  4572. // Code is currently enumerating all devices for every INF entry. Bad times.
  4573. //
  4574. // Check to see if the service is in use by a currently present, enumerated
  4575. // device. If it is, then skip it, otherwise try to stop it, etc
  4576. if (ServiceInUseByDevice(szServiceName))
  4577. {
  4578. #ifdef DEBUG_LOGLOG
  4579. LOG_Write(L"Service is in use by a device. Skipping...");
  4580. #endif
  4581. goto CDD_Next_Inf_Line;
  4582. }
  4583. else
  4584. {
  4585. if (E_FAIL == GetLastError())
  4586. {
  4587. #ifdef DEBUG_LOGLOG
  4588. LOG_WriteLastError();
  4589. #endif
  4590. bAllOK = FALSE;
  4591. goto CDD_Next_Inf_Line;
  4592. }
  4593. #ifdef DEBUG_LOGLOG
  4594. LOG_Write(L"Service is not in use by a device. Attempting to disable...");
  4595. #endif
  4596. }
  4597. //
  4598. // =================================
  4599. // Open the service to query its status, start type, and disable
  4600. // it if it is not running and not yet disabled.
  4601. // =================================
  4602. //
  4603. hSvc = OpenService(
  4604. hSC,
  4605. szServiceName,
  4606. SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG
  4607. );
  4608. if (hSvc == NULL) {
  4609. #ifdef DEBUG_LOGLOG
  4610. LOG_WriteLastError();
  4611. #endif
  4612. bAllOK = FALSE;
  4613. goto CDD_Next_Inf_Line;
  4614. }
  4615. //
  4616. // =================================
  4617. // If PnP driver then don't disable the service and continue.
  4618. // =================================
  4619. //
  4620. if (IsPnPDriver(szServiceName)) {
  4621. #ifdef DEBUG_LOGLOG
  4622. LOG_Write(L"IsPnPDriver() returned TRUE. Continue to next entry.");
  4623. #endif
  4624. bAllOK = FALSE;
  4625. goto CDD_Next_Inf_Line;
  4626. }
  4627. //
  4628. // =================================
  4629. // Query the service start type.
  4630. // =================================
  4631. //
  4632. psvcConfig = (LPQUERY_SERVICE_CONFIG) malloc(sizeof(QUERY_SERVICE_CONFIG));
  4633. if (psvcConfig == NULL) {
  4634. #ifdef DEBUG_LOGLOG
  4635. LOG_Write(L"ERROR@malloc - Not enough memory.");
  4636. #endif
  4637. bAllOK = FALSE;
  4638. goto CDD_Next_Inf_Line;
  4639. }
  4640. if (!QueryServiceConfig(hSvc, psvcConfig, sizeof(QUERY_SERVICE_CONFIG), &dwSize)) {
  4641. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  4642. #ifdef DEBUG_LOGLOG
  4643. LOG_WriteLastError();
  4644. #endif
  4645. bAllOK = FALSE;
  4646. goto CDD_Next_Inf_Line;
  4647. }
  4648. else {
  4649. //
  4650. // Need to expand the service configuration buffer and call the API again.
  4651. //
  4652. void *pTemp = realloc(psvcConfig, dwSize);
  4653. if (pTemp == NULL) {
  4654. #ifdef DEBUG_LOGLOG
  4655. LOG_Write(L"ERROR@realloc - Not enough memory.");
  4656. #endif
  4657. bAllOK = FALSE;
  4658. goto CDD_Next_Inf_Line;
  4659. }
  4660. psvcConfig = (LPQUERY_SERVICE_CONFIG) pTemp;
  4661. if (!QueryServiceConfig(hSvc, psvcConfig, dwSize, &dwSize)) {
  4662. #ifdef DEBUG_LOGLOG
  4663. LOG_WriteLastError();
  4664. #endif
  4665. bAllOK = FALSE;
  4666. goto CDD_Next_Inf_Line;
  4667. }
  4668. }
  4669. }
  4670. #ifdef DEBUG_LOGLOG
  4671. switch(psvcConfig->dwStartType) {
  4672. case SERVICE_BOOT_START:
  4673. LOG_Write(L"StartType=SERVICE_BOOT_START");
  4674. break;
  4675. case SERVICE_SYSTEM_START:
  4676. LOG_Write(L"StartType=SERVICE_SYSTEM_START");
  4677. break;
  4678. case SERVICE_AUTO_START:
  4679. LOG_Write(L"StartType=SERVICE_AUTO_START");
  4680. break;
  4681. case SERVICE_DEMAND_START:
  4682. LOG_Write(L"StartType=SERVICE_DEMAND_START");
  4683. break;
  4684. case SERVICE_DISABLED:
  4685. LOG_Write(L"StartType=SERVICE_DISABLED");
  4686. break;
  4687. }
  4688. #endif
  4689. //
  4690. // =================================
  4691. // Retrieve device IDs for the device instances controlled by the service.
  4692. // ISSUE-2002/02/26-brucegr: Need to call CM_Get_Device_ID_List_Size to get
  4693. // the required buffer size. But we're OK here, since by reaching this point,
  4694. // we know we have a single device instance.
  4695. // =================================
  4696. //
  4697. cfgRetVal = CM_Get_Device_ID_List(
  4698. szServiceName,
  4699. szBuffer,
  4700. sizeof(szBuffer)/sizeof(WCHAR),
  4701. CM_GETIDLIST_FILTER_SERVICE | CM_GETIDLIST_DONOTGENERATE
  4702. );
  4703. if (cfgRetVal != CR_SUCCESS) {
  4704. #ifdef DEBUG_LOGLOG
  4705. LOG_Write(L"ERROR@CM_Get_Device_ID_List - (%08X)", cfgRetVal);
  4706. #endif
  4707. bAllOK = FALSE;
  4708. goto CDD_Next_Inf_Line;
  4709. }
  4710. //
  4711. // =================================
  4712. // Remove all "bogus" devnodes.
  4713. // =================================
  4714. //
  4715. //
  4716. // Create an empty device information set.
  4717. //
  4718. hDevInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
  4719. if (hDevInfo == INVALID_HANDLE_VALUE) {
  4720. #ifdef DEBUG_LOGLOG
  4721. LOG_WriteLastError();
  4722. #endif
  4723. bAllOK = FALSE;
  4724. goto CDD_Next_Inf_Line;
  4725. }
  4726. for (pszDevID = szBuffer; *pszDevID; pszDevID += (lstrlen(pszDevID) + 1)) {
  4727. #ifdef DEBUG_LOGLOG
  4728. LOG_Write(L"--> removing %s...", pszDevID);
  4729. #endif
  4730. //
  4731. // Open a device instance into the hDevInfo set
  4732. //
  4733. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  4734. if (!SetupDiOpenDeviceInfo(
  4735. hDevInfo,
  4736. pszDevID,
  4737. NULL,
  4738. 0,
  4739. &DeviceInfoData)
  4740. ) {
  4741. #ifdef DEBUG_LOGLOG
  4742. LOG_WriteLastError();
  4743. #endif
  4744. bAllOK = FALSE;
  4745. continue;
  4746. }
  4747. if (!SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, &DeviceInfoData)) {
  4748. #ifdef DEBUG_LOGLOG
  4749. LOG_WriteLastError();
  4750. #endif
  4751. bAllOK = FALSE;
  4752. }
  4753. #ifdef DEBUG_LOGLOG
  4754. LOG_Write(L"--> successfully done!");
  4755. #endif
  4756. }
  4757. SetupDiDestroyDeviceInfoList(hDevInfo);
  4758. hDevInfo = INVALID_HANDLE_VALUE;
  4759. //
  4760. // =================================
  4761. // Disable stopped and not-yet-disabled services
  4762. // =================================
  4763. //
  4764. #ifdef DEBUG_LOGLOG
  4765. LOG_Write(L"--> changing StartType to SERVICE_DISABLED...");
  4766. #endif
  4767. if (!ChangeServiceConfig(
  4768. hSvc,
  4769. SERVICE_NO_CHANGE,
  4770. SERVICE_DISABLED,
  4771. SERVICE_NO_CHANGE,
  4772. NULL,
  4773. NULL,
  4774. NULL,
  4775. NULL,
  4776. NULL,
  4777. NULL,
  4778. psvcConfig->lpDisplayName)) {
  4779. #ifdef DEBUG_LOGLOG
  4780. LOG_WriteLastError();
  4781. #endif
  4782. bAllOK = FALSE;
  4783. goto CDD_Next_Inf_Line;
  4784. }
  4785. #ifdef DEBUG_LOGLOG
  4786. LOG_Write(L"--> successfully done!");
  4787. #endif
  4788. CDD_Next_Inf_Line:
  4789. if (psvcConfig != NULL) {
  4790. free(psvcConfig);
  4791. psvcConfig = NULL;
  4792. }
  4793. if (hSvc != NULL) {
  4794. CloseServiceHandle(hSvc);
  4795. hSvc = NULL;
  4796. }
  4797. //
  4798. // Get the next line from the relevant section in the inf file
  4799. //
  4800. bLineExists = SetupFindNextLine(&InfContext, &InfContext);
  4801. }
  4802. //
  4803. // =================================
  4804. // Cleanup for a successful run
  4805. // =================================
  4806. //
  4807. CloseServiceHandle(hSC);
  4808. SetupCloseInfFile(hAnswerInf);
  4809. #ifdef DEBUG_LOGLOG
  4810. LOG_DeInit();
  4811. #endif
  4812. return bAllOK;
  4813. //
  4814. // =================================
  4815. CDD_Critical_Error_Handler:
  4816. //
  4817. // =================================
  4818. #ifdef DEBUG_LOGLOG
  4819. LOG_WriteLastError();
  4820. #endif
  4821. if (hSvc != NULL) {
  4822. CloseServiceHandle(hSvc);
  4823. }
  4824. if (hSC != NULL) {
  4825. CloseServiceHandle(hSC);
  4826. }
  4827. if (hAnswerInf != INVALID_HANDLE_VALUE) {
  4828. SetupCloseInfFile(hAnswerInf);
  4829. }
  4830. #ifdef DEBUG_LOGLOG
  4831. LOG_DeInit();
  4832. #endif
  4833. return FALSE;
  4834. }
  4835. BOOL
  4836. IsPnPDriver(
  4837. IN LPTSTR ServiceName
  4838. )
  4839. /*++
  4840. Routine Description:
  4841. This function checks whether a specified driver is a PnP driver
  4842. Arguments:
  4843. ServiceName - Specifies the driver of interest.
  4844. Return Value:
  4845. TRUE - if the driver is a PnP driver or if this cannot be determined.
  4846. FALSE - if the service is not a PnP driver.
  4847. --*/
  4848. {
  4849. CONFIGRET Status;
  4850. BOOL fRetStatus = TRUE;
  4851. WCHAR * pBuffer;
  4852. ULONG cchLen, ulRegDataType;
  4853. WCHAR szClassGuid[MAX_GUID_STRING_LEN];
  4854. DEVNODE DevNode;
  4855. //
  4856. // Allocate a buffer for the list of device instances associated with
  4857. // this service
  4858. //
  4859. Status = CM_Get_Device_ID_List_Size(
  4860. &cchLen, // list length in wchars
  4861. ServiceName, // pszFilter
  4862. CM_GETIDLIST_FILTER_SERVICE); // filter is a service name
  4863. if (Status != CR_SUCCESS)
  4864. {
  4865. #ifdef DEBUG_LOGLOG
  4866. LOG_Write(L"CM_Get_Device_ID_List_Size failed %#lx for service %ws\n",
  4867. Status, ServiceName);
  4868. #endif
  4869. return TRUE;
  4870. }
  4871. //
  4872. // If there are no devnodes, this is not a PnP driver
  4873. //
  4874. if (cchLen == 0)
  4875. {
  4876. #ifdef DEBUG_LOGLOG
  4877. LOG_Write(L"IsPnPDriver: %ws is not a PnP driver (no devnodes)\n",
  4878. ServiceName);
  4879. #endif
  4880. return FALSE;
  4881. }
  4882. pBuffer = (WCHAR *) LocalAlloc(0, cchLen * sizeof(WCHAR));
  4883. if (pBuffer == NULL)
  4884. {
  4885. #ifdef DEBUG_LOGLOG
  4886. LOG_Write(L"Couldn't allocate buffer for device list, error %lu\n",
  4887. GetLastError());
  4888. #endif
  4889. return TRUE;
  4890. }
  4891. //
  4892. // Initialize parameters for CM_Get_Device_ID_List, the same way as is
  4893. // normally done in the client side of the API
  4894. //
  4895. pBuffer[0] = L'\0';
  4896. //
  4897. // Get the list of device instances that are associated with this service
  4898. //
  4899. // (For legacy and PNP-aware services, we could get an empty device list.)
  4900. //
  4901. Status = CM_Get_Device_ID_List(
  4902. ServiceName, // pszFilter
  4903. pBuffer, // buffer for device list
  4904. cchLen, // buffer length in wchars
  4905. CM_GETIDLIST_FILTER_SERVICE | // filter is a service name
  4906. CM_GETIDLIST_DONOTGENERATE // do not generate an instance if none exists
  4907. );
  4908. if (Status != CR_SUCCESS)
  4909. {
  4910. #ifdef DEBUG_LOGLOG
  4911. LOG_Write(L"CM_Get_Device_ID_List failed %#lx for service %ws\n",
  4912. Status, ServiceName);
  4913. #endif
  4914. LocalFree(pBuffer);
  4915. return TRUE;
  4916. }
  4917. //
  4918. // If there's more than one devnode, this is a PnP driver
  4919. //
  4920. if (*(pBuffer + wcslen(pBuffer) + 1) != L'\0')
  4921. {
  4922. #ifdef DEBUG_LOGLOG
  4923. LOG_Write(L"IsPnPDriver: %ws is a PnP driver (more than 1 devnode)\n",
  4924. ServiceName);
  4925. #endif
  4926. LocalFree(pBuffer);
  4927. return TRUE;
  4928. }
  4929. //
  4930. // This has only one DevNode so lets check if it's legacy.
  4931. // Use CM_LOCATE_DEVNODE_PHANTOM because the DevNode may not be considered alive but
  4932. // exists in the registry.
  4933. //
  4934. if ( CR_SUCCESS == CM_Locate_DevNode(&DevNode, pBuffer, CM_LOCATE_DEVNODE_PHANTOM) )
  4935. {
  4936. //
  4937. // Get the class GUID of this driver
  4938. //
  4939. cchLen = sizeof(szClassGuid);
  4940. Status = CM_Get_DevNode_Registry_Property(
  4941. DevNode, // devnode
  4942. CM_DRP_CLASSGUID, // property to get
  4943. &ulRegDataType, // pointer to REG_* type
  4944. szClassGuid, // return buffer
  4945. &cchLen, // buffer length in bytes
  4946. 0 // flags
  4947. );
  4948. if (Status != CR_SUCCESS)
  4949. {
  4950. #ifdef DEBUG_LOGLOG
  4951. LOG_Write(L"CM_Get_DevNode_Registry_Property failed %#lx for service %ws\n",
  4952. Status, ServiceName);
  4953. #endif
  4954. LocalFree(pBuffer);
  4955. return TRUE;
  4956. }
  4957. //
  4958. // If the single devnode's class is LegacyDriver,
  4959. // this is not a PnP driver
  4960. //
  4961. fRetStatus = (_wcsicmp(szClassGuid, LEGACYDRIVER_STRING) != 0);
  4962. #ifdef DEBUG_LOGLOG
  4963. LOG_Write(L"IsPnPDriver: %ws %ws a PnP driver\n",
  4964. ServiceName, fRetStatus ? L"is" : L"is not");
  4965. #endif
  4966. }
  4967. LocalFree(pBuffer);
  4968. return fRetStatus;
  4969. }
  4970. BOOL
  4971. BackupHives(
  4972. VOID
  4973. )
  4974. /*++
  4975. ===============================================================================
  4976. Routine Description:
  4977. Copy the system hive over into the repair directory. This is required
  4978. if the user has asked us to fixup the critical device database (which
  4979. will change the contents of the system hive).
  4980. Arguments:
  4981. None.
  4982. Return Value:
  4983. TRUE if the operation succeeds, FALSE otherwise.
  4984. ===============================================================================
  4985. --*/
  4986. {
  4987. WCHAR szRepairSystemHive[MAX_PATH];
  4988. WCHAR szRepairSystemHiveBackup[MAX_PATH];
  4989. HKEY hkey;
  4990. LONG lStatus;
  4991. //
  4992. // Get the full pathname of the "system" file in the repair directory.
  4993. //
  4994. if (!GetWindowsDirectory(szRepairSystemHive, MAX_PATH))
  4995. return FALSE;
  4996. StringCchCat (szRepairSystemHive, AS ( szRepairSystemHive ), L"\\repair\\system");
  4997. //
  4998. // Generate the full pathname of the backup copy of the current "system" file.
  4999. StringCchCopy (szRepairSystemHiveBackup, AS ( szRepairSystemHiveBackup ), szRepairSystemHive);
  5000. //
  5001. // ISSUE-2002/02/26-brucegr: This should be szRepairSystemHiveBackup!!!!
  5002. //
  5003. StringCchCat(szRepairSystemHive, AS ( szRepairSystemHive ), L".bak");
  5004. //
  5005. // Open the root of the system hive.
  5006. //
  5007. lStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  5008. L"system",
  5009. REG_OPTION_RESERVED,
  5010. READ_CONTROL,
  5011. &hkey);
  5012. if (lStatus == ERROR_SUCCESS) {
  5013. //
  5014. // First, rename the current "system" file to "system.bak", so that
  5015. // we can restore it if RegSaveKey fails.
  5016. //
  5017. SetFileAttributes(szRepairSystemHiveBackup, FILE_ATTRIBUTE_NORMAL);
  5018. DeleteFile(szRepairSystemHiveBackup);
  5019. SetFileAttributes(szRepairSystemHive, FILE_ATTRIBUTE_NORMAL);
  5020. MoveFile(szRepairSystemHive, szRepairSystemHiveBackup);
  5021. //
  5022. // Save the registry system hive into the "system" file.
  5023. //
  5024. //
  5025. // ISSUE-2002/02/26-brucegr: We need to make sure we have SE_BACKUP_NAME privilege
  5026. //
  5027. lStatus = RegSaveKey(hkey, szRepairSystemHive, NULL);
  5028. if (lStatus == ERROR_SUCCESS) {
  5029. //
  5030. // Now we can safely delete the backup copy.
  5031. //
  5032. DeleteFile(szRepairSystemHiveBackup);
  5033. }
  5034. else {
  5035. //
  5036. // Otherwise we need to restore the system file from the backup.
  5037. //
  5038. MoveFile(szRepairSystemHiveBackup, szRepairSystemHive);
  5039. }
  5040. RegCloseKey(hkey);
  5041. }
  5042. return (lStatus == ERROR_SUCCESS);
  5043. }
  5044. VOID
  5045. FreeSysprepContext(
  5046. IN PVOID SysprepContext
  5047. )
  5048. {
  5049. PSYSPREP_QUEUE_CONTEXT Context = SysprepContext;
  5050. try {
  5051. if(Context->DefaultContext) {
  5052. SetupTermDefaultQueueCallback(Context->DefaultContext);
  5053. }
  5054. free(Context);
  5055. } except(EXCEPTION_EXECUTE_HANDLER) {
  5056. ;
  5057. }
  5058. }
  5059. PVOID
  5060. InitSysprepQueueCallback(
  5061. VOID
  5062. )
  5063. /*++
  5064. ===============================================================================
  5065. Routine Description:
  5066. Initialize the data structure used for the callback that fires when
  5067. we commit the file copy queue.
  5068. Arguments:
  5069. Return Value:
  5070. ===============================================================================
  5071. --*/
  5072. {
  5073. PSYSPREP_QUEUE_CONTEXT SysprepContext;
  5074. SysprepContext = malloc(sizeof(SYSPREP_QUEUE_CONTEXT));
  5075. if(SysprepContext) {
  5076. SysprepContext->DirectoryOnSourceDevice = NULL;
  5077. SysprepContext->DiskDescription = NULL;
  5078. SysprepContext->DiskTag = NULL;
  5079. SysprepContext->DefaultContext = SetupInitDefaultQueueCallbackEx( NULL,
  5080. INVALID_HANDLE_VALUE,
  5081. 0,
  5082. 0,
  5083. NULL );
  5084. }
  5085. return SysprepContext;
  5086. }
  5087. UINT
  5088. SysprepQueueCallback(
  5089. IN PVOID Context,
  5090. IN UINT Notification,
  5091. IN UINT_PTR Param1,
  5092. IN UINT_PTR Param2
  5093. )
  5094. /*++
  5095. ===============================================================================
  5096. Routine Description:
  5097. Callback function for setupapi to use as he's copying files.
  5098. We'll use this to ensure that the files we copy get appended to
  5099. setup.log, which in turn may get used when/if the user ever tries to
  5100. use Windows repair capabilities.
  5101. Arguments:
  5102. Return Value:
  5103. ===============================================================================
  5104. --*/
  5105. {
  5106. UINT Status;
  5107. PSYSPREP_QUEUE_CONTEXT SysprepContext = Context;
  5108. PFILEPATHS FilePaths = (PFILEPATHS)Param1;
  5109. //
  5110. // Make sure that if we get these notification to check Param1.
  5111. //
  5112. switch (Notification) {
  5113. case SPFILENOTIFY_COPYERROR:
  5114. {
  5115. //
  5116. // Copy error happened log and skip this file.
  5117. //
  5118. #ifdef DEBUG_LOGLOG
  5119. LOG_Write(L"SysprepQueueCallback: SPFILENOTIFY_COPYERROR - %s, %s, %s, %s, %s",
  5120. (PWSTR) FilePaths->Source,
  5121. (PWSTR) FilePaths->Target,
  5122. SysprepContext->DirectoryOnSourceDevice,
  5123. SysprepContext->DiskDescription,
  5124. SysprepContext->DiskTag);
  5125. #endif
  5126. return FILEOP_SKIP;
  5127. }
  5128. break;
  5129. case SPFILENOTIFY_NEEDMEDIA:
  5130. {
  5131. //
  5132. // If user specified an OEM driver file and path break and let
  5133. // the DefaultQueueCallback handle it.
  5134. //
  5135. PSOURCE_MEDIA pSourceMedia = (PSOURCE_MEDIA)Param1;
  5136. if (pSourceMedia) {
  5137. #ifdef DEBUG_LOGLOG
  5138. LOG_Write(L"SysprepQueueCallback: SPFILENOTIFY_NEEDMEDIA - %s, %s, %s, %s, %s",
  5139. (PWSTR) pSourceMedia->SourcePath,
  5140. (PWSTR) pSourceMedia->SourceFile,
  5141. (PWSTR) pSourceMedia->Tagfile,
  5142. (PWSTR) pSourceMedia->Description);
  5143. #endif
  5144. if (pSourceMedia->SourcePath && lstrlen(pSourceMedia->SourcePath) &&
  5145. pSourceMedia->SourceFile && lstrlen(pSourceMedia->SourceFile))
  5146. break; // continue if SourcePath and SourceFile is specified
  5147. else
  5148. return FILEOP_SKIP;
  5149. }
  5150. }
  5151. break;
  5152. default:
  5153. break;
  5154. }
  5155. //
  5156. // Use default processing, then check for errors.
  5157. //
  5158. Status = SetupDefaultQueueCallback( SysprepContext->DefaultContext,
  5159. Notification,
  5160. Param1,
  5161. Param2 );
  5162. switch(Notification) {
  5163. case SPFILENOTIFY_ENDCOPY:
  5164. //
  5165. // The copy just finished. Let's log the
  5166. // file.
  5167. //
  5168. LogRepairInfo( (PWSTR) FilePaths->Source,
  5169. (PWSTR) FilePaths->Target,
  5170. SysprepContext->DirectoryOnSourceDevice,
  5171. SysprepContext->DiskDescription,
  5172. SysprepContext->DiskTag );
  5173. break;
  5174. default:
  5175. break;
  5176. }
  5177. return Status;
  5178. }
  5179. BOOL
  5180. ValidateAndChecksumFile(
  5181. IN PCWSTR Filename,
  5182. OUT PBOOLEAN IsNtImage,
  5183. OUT PULONG Checksum,
  5184. OUT PBOOLEAN Valid
  5185. )
  5186. /*++
  5187. ===============================================================================
  5188. Routine Description:
  5189. Calculate a checksum value for a file using the standard
  5190. nt image checksum method. If the file is an nt image, validate
  5191. the image using the partial checksum in the image header. If the
  5192. file is not an nt image, it is simply defined as valid.
  5193. If we encounter an i/o error while checksumming, then the file
  5194. is declared invalid.
  5195. Arguments:
  5196. Filename - supplies full NT path of file to check.
  5197. IsNtImage - Receives flag indicating whether the file is an
  5198. NT image file.
  5199. Checksum - receives 32-bit checksum value.
  5200. Valid - receives flag indicating whether the file is a valid
  5201. image (for nt images) and that we can read the image.
  5202. Return Value:
  5203. BOOL - Returns TRUE if the flie was validated, and in this case,
  5204. IsNtImage, Checksum, and Valid will contain the result of
  5205. the validation.
  5206. This function will return FALSE, if the file could not be
  5207. validated, and in this case, the caller should call GetLastError()
  5208. to find out why this function failed.
  5209. ===============================================================================
  5210. --*/
  5211. {
  5212. DWORD Error;
  5213. PVOID BaseAddress;
  5214. ULONG FileSize;
  5215. HANDLE hFile;
  5216. HANDLE hSection;
  5217. PIMAGE_NT_HEADERS NtHeaders;
  5218. ULONG HeaderSum;
  5219. //
  5220. // Assume not an image and failure.
  5221. //
  5222. *IsNtImage = FALSE;
  5223. *Checksum = 0;
  5224. *Valid = FALSE;
  5225. //
  5226. // Open and map the file for read access.
  5227. //
  5228. Error = pSetupOpenAndMapFileForRead( Filename,
  5229. &FileSize,
  5230. &hFile,
  5231. &hSection,
  5232. &BaseAddress );
  5233. if( Error != ERROR_SUCCESS ) {
  5234. SetLastError( Error );
  5235. return(FALSE);
  5236. }
  5237. if( FileSize == 0 ) {
  5238. *IsNtImage = FALSE;
  5239. *Checksum = 0;
  5240. *Valid = TRUE;
  5241. CloseHandle( hFile );
  5242. return(TRUE);
  5243. }
  5244. try {
  5245. NtHeaders = CheckSumMappedFile(BaseAddress,FileSize,&HeaderSum,Checksum);
  5246. } except(EXCEPTION_EXECUTE_HANDLER) {
  5247. *Checksum = 0;
  5248. NtHeaders = NULL;
  5249. }
  5250. //
  5251. // If the file is not an image and we got this far (as opposed to encountering
  5252. // an i/o error) then the checksum is declared valid. If the file is an image,
  5253. // then its checksum may or may not be valid.
  5254. //
  5255. if(NtHeaders) {
  5256. *IsNtImage = TRUE;
  5257. *Valid = HeaderSum ? (*Checksum == HeaderSum) : TRUE;
  5258. } else {
  5259. *Valid = TRUE;
  5260. }
  5261. pSetupUnmapAndCloseFile( hFile, hSection, BaseAddress );
  5262. return( TRUE );
  5263. }
  5264. VOID
  5265. LogRepairInfo(
  5266. IN PWSTR Source,
  5267. IN PWSTR Target,
  5268. IN PWSTR DirectoryOnSourceDevice,
  5269. IN PWSTR DiskDescription,
  5270. IN PWSTR DiskTag
  5271. )
  5272. /*++
  5273. ===============================================================================
  5274. Routine Description:
  5275. This function will log the fact that a file was installed into the
  5276. machine. This will enable Windows repair functionality to be alerted
  5277. that in case of a repair, this file will need to be restored.
  5278. Arguments:
  5279. Return Value:
  5280. ===============================================================================
  5281. --*/
  5282. {
  5283. WCHAR RepairLog[MAX_PATH];
  5284. BOOLEAN IsNtImage;
  5285. ULONG Checksum;
  5286. BOOLEAN Valid;
  5287. WCHAR Filename[MAX_PATH];
  5288. WCHAR SourceName[MAX_PATH];
  5289. DWORD LastSourceChar, LastTargetChar;
  5290. DWORD LastSourcePeriod, LastTargetPeriod;
  5291. WCHAR Line[MAX_PATH];
  5292. WCHAR tmp[MAX_PATH];
  5293. if (!GetWindowsDirectory( RepairLog, MAX_PATH ))
  5294. return;
  5295. StringCchCat( RepairLog, AS ( RepairLog ), L"\\repair\\setup.log" );
  5296. if( ValidateAndChecksumFile( Target, &IsNtImage, &Checksum, &Valid )) {
  5297. //
  5298. // Strip off drive letter.
  5299. //
  5300. StringCchPrintf(
  5301. Filename,
  5302. AS ( Filename ),
  5303. L"\"%s\"",
  5304. Target+2
  5305. );
  5306. //
  5307. // Convert source name to uncompressed form.
  5308. //
  5309. StringCchCopy ( SourceName, AS ( SourceName ), wcsrchr( Source, (WCHAR)'\\' ) + 1 );
  5310. if(!SourceName [ 0 ] ) {
  5311. return;
  5312. }
  5313. LastSourceChar = wcslen (SourceName) - 1;
  5314. if(SourceName[LastSourceChar] == L'_') {
  5315. LastSourcePeriod = (DWORD)(wcsrchr( SourceName, (WCHAR)'.' ) - SourceName);
  5316. if(LastSourceChar - LastSourcePeriod == 1) {
  5317. //
  5318. // No extension - just truncate the "._"
  5319. //
  5320. SourceName[LastSourceChar-1] = L'\0';
  5321. } else {
  5322. //
  5323. // Make sure the extensions on source and target match.
  5324. // If this fails, we can't log the file copy
  5325. //
  5326. LastTargetChar = wcslen (Target) - 1;
  5327. LastTargetPeriod = (ULONG)(wcsrchr( Target, (WCHAR)'.' ) - Target);
  5328. if( _wcsnicmp(
  5329. SourceName + LastSourcePeriod,
  5330. Target + LastTargetPeriod,
  5331. LastSourceChar - LastSourcePeriod - 1 )) {
  5332. return;
  5333. }
  5334. if(LastTargetChar - LastTargetPeriod < 3) {
  5335. //
  5336. // Short extension - just truncate the "_"
  5337. //
  5338. SourceName[LastSourceChar] = L'\0';
  5339. } else {
  5340. //
  5341. // Need to replace "_" with last character from target
  5342. //
  5343. SourceName[LastSourceChar] = Target[LastTargetChar];
  5344. }
  5345. }
  5346. }
  5347. //
  5348. // Write the line.
  5349. //
  5350. if( (DirectoryOnSourceDevice) &&
  5351. (DiskDescription) &&
  5352. (DiskTag) ) {
  5353. //
  5354. // Treat this as an OEM file.
  5355. //
  5356. StringCchPrintf( Line,
  5357. AS ( Line ),
  5358. L"\"%s\",\"%x\",\"%s\",\"%s\",\"%s\"",
  5359. SourceName,
  5360. Checksum,
  5361. DirectoryOnSourceDevice,
  5362. DiskDescription,
  5363. DiskTag );
  5364. } else {
  5365. //
  5366. // Treat this as an "in the box" file.
  5367. //
  5368. StringCchPrintf( Line,
  5369. AS ( Line ),
  5370. L"\"%s\",\"%x\"",
  5371. SourceName,
  5372. Checksum );
  5373. }
  5374. if (GetPrivateProfileString(L"Files.WinNt",Filename,L"",tmp,sizeof(tmp)/sizeof(tmp[0]),RepairLog)) {
  5375. //
  5376. // there is already an entry for this file present (presumably
  5377. // from textmode phase of setup.) Favor this entry over what we
  5378. // are about to add
  5379. //
  5380. } else {
  5381. WritePrivateProfileString(
  5382. L"Files.WinNt",
  5383. Filename,
  5384. Line,
  5385. RepairLog);
  5386. }
  5387. }
  5388. }
  5389. #ifdef _X86_
  5390. BOOL
  5391. ChangeBootTimeout(
  5392. IN UINT Timeout
  5393. )
  5394. /*++
  5395. ===============================================================================
  5396. Routine Description:
  5397. Changes the boot countdown value in boot.ini.
  5398. Arguments:
  5399. Timeout - supplies new timeout value, in seconds.
  5400. Return Value:
  5401. None.
  5402. ===============================================================================
  5403. --*/
  5404. {
  5405. HFILE hfile;
  5406. ULONG FileSize;
  5407. PUCHAR buf = NULL,p1,p2;
  5408. BOOL b;
  5409. CHAR TimeoutLine[256];
  5410. CHAR szBootIni[] = "?:\\BOOT.INI";
  5411. UINT OldMode;
  5412. WIN32_FIND_DATA findData;
  5413. HANDLE FindHandle;
  5414. WCHAR DriveLetter;
  5415. WCHAR tmpBuffer[MAX_PATH];
  5416. //
  5417. // Generate path to the boot.ini file. This is actually more
  5418. // complicated than one might think. It will almost always
  5419. // be located on c:, but the user may have remapped his drive
  5420. // letters.
  5421. //
  5422. // We'll use a brute-force method here and look for the first
  5423. // instance of boot.ini. We've got two factors going for us
  5424. // here:
  5425. // 1. boot.ini be on the lower-drive letters, so look there
  5426. // first
  5427. // 2. I can't think of a scenario where he would have multiple
  5428. // boot.ini files, so the first one we find is going to be
  5429. // the right one.
  5430. //
  5431. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  5432. StringCchCopy ( tmpBuffer, AS ( tmpBuffer ), TEXT( "?:\\BOOT.INI" ) );
  5433. for( DriveLetter = 'c'; DriveLetter <= 'z'; DriveLetter++ ) {
  5434. tmpBuffer[0] = DriveLetter;
  5435. //
  5436. // See if he's there.
  5437. //
  5438. //
  5439. // ISSUE-2002/02/26-brucegr: Use GetFileAttributes/GetFileAttributesEx instead of FindFirstFile!
  5440. //
  5441. FindHandle = FindFirstFile( tmpBuffer, &findData );
  5442. if(FindHandle != INVALID_HANDLE_VALUE) {
  5443. //
  5444. // Yep. Close him and break the for-loop.
  5445. //
  5446. FindClose(FindHandle);
  5447. break;
  5448. }
  5449. }
  5450. SetErrorMode(OldMode);
  5451. if( DriveLetter > 'z' ) {
  5452. return FALSE;
  5453. }
  5454. szBootIni[0] = (CHAR)DriveLetter;
  5455. StringCchPrintfA (TimeoutLine,AS ( TimeoutLine ), "timeout=%u\r\n",Timeout);
  5456. //
  5457. // Open and read boot.ini.
  5458. //
  5459. //
  5460. // ISSUE-2002/02/26-brucegr: Why can't we use PrivateProfile APIs?
  5461. //
  5462. b = FALSE;
  5463. hfile = _lopen(szBootIni,OF_READ);
  5464. if(hfile != HFILE_ERROR) {
  5465. FileSize = _llseek(hfile,0,2);
  5466. if(FileSize != (ULONG)(-1)) {
  5467. if((_llseek(hfile,0,0) != -1)
  5468. && (buf = malloc(FileSize+1))
  5469. && (_lread(hfile,buf,FileSize) != (UINT)(-1)))
  5470. {
  5471. buf[FileSize] = 0;
  5472. b = TRUE;
  5473. }
  5474. }
  5475. _lclose(hfile);
  5476. }
  5477. if(!b) {
  5478. if(buf) {
  5479. free(buf);
  5480. }
  5481. return(FALSE);
  5482. }
  5483. if(!(p1 = strstr(buf,"timeout"))) {
  5484. free(buf);
  5485. return(FALSE);
  5486. }
  5487. if(p2 = strchr(p1,'\n')) {
  5488. p2++; // skip NL.
  5489. } else {
  5490. p2 = buf + FileSize;
  5491. }
  5492. SetFileAttributesA(szBootIni,FILE_ATTRIBUTE_NORMAL);
  5493. hfile = _lcreat(szBootIni,0);
  5494. if(hfile == HFILE_ERROR) {
  5495. free(buf);
  5496. return(FALSE);
  5497. }
  5498. //
  5499. // Write:
  5500. //
  5501. // 1) the first part, start=buf, len=p1-buf
  5502. // 2) the timeout line
  5503. // 3) the last part, start=p2, len=buf+FileSize-p2
  5504. //
  5505. b = ((_lwrite(hfile,buf ,p1-buf ) != (UINT)(-1))
  5506. && (_lwrite(hfile,TimeoutLine,strlen(TimeoutLine)) != (UINT)(-1))
  5507. && (_lwrite(hfile,p2 ,buf+FileSize-p2 ) != (UINT)(-1)));
  5508. _lclose(hfile);
  5509. free(buf);
  5510. //
  5511. // Make boot.ini archive, read only, and system.
  5512. //
  5513. SetFileAttributesA(
  5514. szBootIni,
  5515. FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN
  5516. );
  5517. return(b);
  5518. }
  5519. #else
  5520. BOOL
  5521. ChangeBootTimeout(
  5522. IN UINT Timeout
  5523. )
  5524. /*++
  5525. ===============================================================================
  5526. Routine Description:
  5527. Changes the boot timeout value in NVRAM.
  5528. Arguments:
  5529. Timeout - supplies new timeout value, in seconds.
  5530. Return Value:
  5531. None.
  5532. ===============================================================================
  5533. --*/
  5534. {
  5535. NTSTATUS Status;
  5536. BOOT_OPTIONS BootOptions;
  5537. BootOptions.Version = BOOT_OPTIONS_VERSION;
  5538. BootOptions.Length = sizeof(BootOptions);
  5539. BootOptions.Timeout = Timeout;
  5540. pSetupEnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE);
  5541. Status = NtSetBootOptions(&BootOptions, BOOT_OPTIONS_FIELD_TIMEOUT);
  5542. return (NT_SUCCESS(Status));
  5543. }
  5544. #endif
  5545. // Disable System Restore
  5546. //
  5547. void DisableSR()
  5548. {
  5549. HINSTANCE hInst = LoadLibrary(FILE_SRCLIENT_DLL);
  5550. if (hInst) {
  5551. FARPROC fnProc;
  5552. if ( fnProc = GetProcAddress(hInst, "DisableSR") ) {
  5553. fnProc(NULL);
  5554. }
  5555. FreeLibrary(hInst);
  5556. }
  5557. }
  5558. // Enable System Restore
  5559. //
  5560. void EnableSR()
  5561. {
  5562. HINSTANCE hInst = LoadLibrary(FILE_SRCLIENT_DLL);
  5563. if (hInst) {
  5564. FARPROC fnProc;
  5565. if ( fnProc = GetProcAddress(hInst, "EnableSR") ) {
  5566. fnProc(NULL);
  5567. }
  5568. FreeLibrary(hInst);
  5569. }
  5570. }
  5571. LPTSTR OPKAddPathN(LPTSTR lpPath, LPCTSTR lpName, DWORD cbPath)
  5572. {
  5573. LPTSTR lpTemp = lpPath;
  5574. // Validate the parameters passed in.
  5575. //
  5576. if ( ( lpPath == NULL ) ||
  5577. ( lpName == NULL ) )
  5578. {
  5579. return NULL;
  5580. }
  5581. // Find the end of the path.
  5582. //
  5583. while ( *lpTemp )
  5584. {
  5585. lpTemp = CharNext(lpTemp);
  5586. if ( cbPath )
  5587. {
  5588. cbPath--;
  5589. }
  5590. }
  5591. // If no trailing backslash on the path then add one.
  5592. //
  5593. if ( ( lpTemp > lpPath ) &&
  5594. ( *CharPrev(lpPath, lpTemp) != CHR_BACKSLASH ) )
  5595. {
  5596. // Make sure there is room in the path buffer to
  5597. // add the backslash and the null terminator.
  5598. //
  5599. if ( cbPath < 2 )
  5600. {
  5601. return NULL;
  5602. }
  5603. *lpTemp = CHR_BACKSLASH;
  5604. lpTemp = CharNext(lpTemp);
  5605. cbPath--;
  5606. }
  5607. else
  5608. {
  5609. // Make sure there is at least room for the null
  5610. // terminator.
  5611. //
  5612. if ( cbPath < 1 )
  5613. {
  5614. return NULL;
  5615. }
  5616. }
  5617. // Make sure there is no preceeding spaces or backslashes
  5618. // on the name to add.
  5619. //
  5620. while ( ( *lpName == CHR_SPACE ) ||
  5621. ( *lpName == CHR_BACKSLASH ) )
  5622. {
  5623. lpName = CharNext(lpName);
  5624. }
  5625. // Add the new name to existing path.
  5626. //
  5627. lstrcpyn(lpTemp, lpName, cbPath);
  5628. // Trim trailing spaces from result.
  5629. //
  5630. while ( ( lpTemp > lpPath ) &&
  5631. ( *(lpTemp = CharPrev(lpPath, lpTemp)) == CHR_SPACE ) )
  5632. {
  5633. *lpTemp = NULLCHR;
  5634. }
  5635. return lpPath;
  5636. }