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

3133 lines
74 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. wkstamig.c
  5. Abstract:
  6. The functions in this module are called to perform migration of
  7. system-wide settings.
  8. Author:
  9. Jim Schmidt (jimschm) 04-Feb-1997
  10. Revision History:
  11. ovidiut 10-May-1999 Added DoIniActions
  12. jimschm 16-Dec-1998 Changed ATM font migration to use Adobe's
  13. APIs.
  14. jimschm 25-Nov-1998 ATM.INI migration; Win9x hive migration
  15. jimschm 23-Sep-1998 Consolidated memdb saves into usermig.c
  16. jimschm 19-Feb-1998 Added "none" group support, fixed
  17. share problems.
  18. calinn 12-Dec-1997 Added RestoreMMSettings_System
  19. --*/
  20. #include "pch.h"
  21. #include "migmainp.h"
  22. #include "brfcasep.h"
  23. #include <lm.h>
  24. //
  25. // Constants, types, declarations
  26. //
  27. #define W95_ACCESS_READ 0x1
  28. #define W95_ACCESS_WRITE 0x2
  29. #define W95_ACCESS_CREATE 0x4
  30. #define W95_ACCESS_EXEC 0x8
  31. #define W95_ACCESS_DELETE 0x10
  32. #define W95_ACCESS_ATRIB 0x20
  33. #define W95_ACCESS_PERM 0x40
  34. #define W95_ACCESS_FINDFIRST 0x80
  35. #define W95_ACCESS_FULL 0xff
  36. #define W95_ACCESS_GROUP 0x8000
  37. #define W95_GENERIC_READ (W95_ACCESS_READ|W95_ACCESS_FINDFIRST)
  38. #define W95_GENERIC_WRITE (W95_ACCESS_WRITE|W95_ACCESS_CREATE|W95_ACCESS_DELETE|W95_ACCESS_ATRIB)
  39. #define W95_GENERIC_FULL (W95_GENERIC_READ|W95_GENERIC_WRITE|W95_ACCESS_PERM)
  40. #define W95_GENERIC_NONE 0
  41. #define S_DEFAULT_USER_NAME TEXT("DefaultUserName")
  42. #define S_DEFAULT_DOMAIN_NAME TEXT("DefaultDomainName")
  43. // from private\net\svcdlls\srvsvc\server
  44. #define SHARES_REGISTRY_PATH L"LanmanServer\\Shares"
  45. #define SHARES_SECURITY_REGISTRY_PATH L"LanmanServer\\Shares\\Security"
  46. #define CSCFLAGS_VARIABLE_NAME L"CSCFlags"
  47. #define MAXUSES_VARIABLE_NAME L"MaxUses"
  48. #define PATH_VARIABLE_NAME L"Path"
  49. #define PERMISSIONS_VARIABLE_NAME L"Permissions"
  50. #define REMARK_VARIABLE_NAME L"Remark"
  51. #define TYPE_VARIABLE_NAME L"Type"
  52. // Win9x-specific flags for NetShareEnum
  53. #define SHI50F_RDONLY 0x0001
  54. #define SHI50F_FULL 0x0002
  55. #define SHI50F_DEPENDSON (SHI50F_RDONLY|SHI50F_FULL)
  56. #define SHI50F_ACCESSMASK (SHI50F_RDONLY|SHI50F_FULL)
  57. #ifndef UNICODE
  58. #error UNICODE required
  59. #endif
  60. #define DBG_NETSHARES "NetShares"
  61. #define DBG_INIFILES "IniFiles"
  62. #define S_CLEANER_GUID TEXT("{C0E13E61-0CC6-11d1-BBB6-0060978B2AE6}")
  63. #define S_CLEANER_ALL_FILES TEXT("*")
  64. typedef struct {
  65. // Enumeration return data
  66. TCHAR PfmFile[MAX_TCHAR_PATH];
  67. TCHAR PfbFile[MAX_TCHAR_PATH];
  68. TCHAR MmmFile[MAX_TCHAR_PATH];
  69. TCHAR InfName[MAX_TCHAR_PATH];
  70. // Internal state
  71. PTSTR KeyNames;
  72. POOLHANDLE Pool;
  73. } ATM_FONT_ENUM, *PATM_FONT_ENUM;
  74. typedef INT (WINAPI ATMADDFONTEXW) (
  75. IN OUT PWSTR MenuName,
  76. IN OUT PWORD StyleAndType,
  77. IN PCWSTR MetricsFile,
  78. IN PCWSTR FontFile,
  79. IN PCWSTR MMMFile
  80. );
  81. typedef ATMADDFONTEXW * PATMADDFONTEXW;
  82. PATMADDFONTEXW AtmAddFontEx;
  83. typedef VOID (SHUPDATERECYCLEBINICON_PROTOTYPE)(VOID);
  84. typedef SHUPDATERECYCLEBINICON_PROTOTYPE * SHUPDATERECYCLEBINICON_PROC;
  85. typedef struct {
  86. // enumeration output
  87. PCTSTR Source;
  88. PCTSTR Dest;
  89. // private members
  90. POOLHANDLE Pool;
  91. INFSTRUCT is;
  92. } HIVEFILE_ENUM, *PHIVEFILE_ENUM;
  93. #define MAX_KEY_NAME_LIST 32768
  94. typedef struct {
  95. // enumeration output
  96. PCTSTR BrfcaseDb;
  97. // private
  98. MEMDB_ENUM mde;
  99. } BRIEFCASE_ENUM, *PBRIEFCASE_ENUM;
  100. //
  101. // Implementation
  102. //
  103. DWORD
  104. Simplify9xAccessFlags (
  105. IN DWORD Win9xFlags
  106. )
  107. /*++
  108. Routine Description:
  109. Translates the Win9x LanMan flags into NT LanMan flags (for use with Net* APIs).
  110. Full permission requires:
  111. W95_ACCESS_READ
  112. W95_ACCESS_WRITE
  113. W95_ACCESS_CREATE
  114. W95_ACCESS_DELETE
  115. W95_ACCESS_ATRIB
  116. W95_ACCESS_FINDFIRST
  117. Read-only permission requires:
  118. W95_ACCESS_READ
  119. W95_ACCESS_FINDFIRST
  120. Change-only permission requires:
  121. W95_ACCESS_WRITE
  122. W95_ACCESS_CREATE
  123. W95_ACCESS_DELETE
  124. W95_ACCESS_ATRIB
  125. Any other combination results in
  126. The returned flags are currently converted to security flags based on the
  127. following mapping:
  128. 0 - Deny All Rights
  129. ACCESS_READ - Read-Only Rights
  130. ACCESS_WRITE - Change-Only Rights
  131. ACCESS_READ|ACCESS_WRITE - Full Rights
  132. See AddAclMember for details.
  133. Arguments:
  134. Flags - The set of Win9x flags as returned by an API on Win9x
  135. Return value:
  136. The NT equivalent of the flags.
  137. --*/
  138. {
  139. DWORD NtFlags = 0;
  140. if (BITSARESET (Win9xFlags, W95_GENERIC_WRITE)) {
  141. NtFlags |= ACCESS_WRITE;
  142. }
  143. if (BITSARESET (Win9xFlags, W95_GENERIC_READ)) {
  144. NtFlags |= ACCESS_READ;
  145. }
  146. DEBUGMSG_IF ((
  147. !NtFlags,
  148. DBG_VERBOSE,
  149. "Unsupported permission %u was translated to disable permission",
  150. Win9xFlags
  151. ));
  152. return NtFlags;
  153. }
  154. NET_API_STATUS
  155. MigNetShareAdd (
  156. IN PTSTR ServerName,
  157. IN DWORD Level,
  158. IN PBYTE Buf,
  159. OUT PDWORD ErrParam
  160. )
  161. /*++
  162. Routine Description:
  163. Our private version of NetShareAdd. The real NetShareAdd does not work
  164. in GUI mode. We emulate the real thing carefully because maybe some day
  165. it WILL work and we should use it.
  166. For now, we write directly to the registry. (This function is a reverse-
  167. engineer of the NetShareAdd function.)
  168. Arguments:
  169. ServerName - Always NULL
  170. Level - Always 2
  171. Buf - A pointer to a caller-allocated SHARE_INFO_2 buffer cast
  172. as an PBYTE
  173. ErrParam - Not supported
  174. Return value:
  175. The Win32 result
  176. --*/
  177. {
  178. SHARE_INFO_2 *psi;
  179. DWORD rc;
  180. HKEY hKey = NULL, hKeyShares = NULL;
  181. DWORD DontCare;
  182. GROWBUFFER GrowBuf = GROWBUF_INIT;
  183. //
  184. // This function is for compatibility with NetShareAdd, because one day
  185. // the real NetShareAdd might be improved to work in GUI mode setup.
  186. //
  187. if (Level != 2) {
  188. return ERROR_INVALID_LEVEL;
  189. }
  190. psi = (SHARE_INFO_2 *) Buf;
  191. rc = TrackedRegOpenKeyEx (
  192. HKEY_LOCAL_MACHINE,
  193. L"SYSTEM\\CurrentControlSet\\Services",
  194. 0,
  195. KEY_WRITE,
  196. &hKey
  197. );
  198. if (rc != ERROR_SUCCESS) {
  199. goto cleanup;
  200. }
  201. rc = TrackedRegCreateKeyEx (
  202. hKey,
  203. SHARES_REGISTRY_PATH,
  204. 0,
  205. S_EMPTY,
  206. REG_OPTION_NON_VOLATILE,
  207. KEY_ALL_ACCESS,
  208. NULL,
  209. &hKeyShares,
  210. &DontCare
  211. );
  212. if (rc != ERROR_SUCCESS) {
  213. goto cleanup;
  214. }
  215. //
  216. // Prepare multisz
  217. //
  218. if (!MultiSzAppendVal (&GrowBuf, CSCFLAGS_VARIABLE_NAME, 0)) {
  219. rc = GetLastError();
  220. goto cleanup;
  221. }
  222. if (!MultiSzAppendVal (&GrowBuf, MAXUSES_VARIABLE_NAME, psi->shi2_max_uses)) {
  223. rc = GetLastError();
  224. goto cleanup;
  225. }
  226. if (!psi->shi2_path || !(*psi->shi2_path)) {
  227. rc = ERROR_INVALID_PARAMETER;
  228. goto cleanup;
  229. }
  230. if (!MultiSzAppendString (&GrowBuf, PATH_VARIABLE_NAME, psi->shi2_path)) {
  231. rc = GetLastError();
  232. goto cleanup;
  233. }
  234. if (!MultiSzAppendVal (&GrowBuf, PERMISSIONS_VARIABLE_NAME, psi->shi2_permissions)) {
  235. rc = GetLastError();
  236. goto cleanup;
  237. }
  238. if (psi->shi2_remark && *psi->shi2_remark) {
  239. // Safety
  240. if (TcharCount (psi->shi2_remark) >= MAXCOMMENTSZ) {
  241. psi->shi2_remark[MAXCOMMENTSZ-1] = 0;
  242. }
  243. if (!MultiSzAppendString (&GrowBuf, REMARK_VARIABLE_NAME, psi->shi2_remark)) {
  244. rc = GetLastError();
  245. goto cleanup;
  246. }
  247. }
  248. if (!MultiSzAppendVal (&GrowBuf, TYPE_VARIABLE_NAME, psi->shi2_type)) {
  249. rc = GetLastError();
  250. goto cleanup;
  251. }
  252. // terminate multi-sz string chain
  253. if (!MultiSzAppend (&GrowBuf, S_EMPTY)) {
  254. rc = GetLastError();
  255. goto cleanup;
  256. }
  257. //
  258. // Save to registry
  259. //
  260. rc = RegSetValueEx (hKeyShares, psi->shi2_netname, 0, REG_MULTI_SZ,
  261. GrowBuf.Buf, GrowBuf.End);
  262. cleanup:
  263. if (hKeyShares) {
  264. CloseRegKey (hKeyShares);
  265. }
  266. if (hKey) {
  267. CloseRegKey (hKey);
  268. }
  269. FreeGrowBuffer (&GrowBuf);
  270. return rc;
  271. }
  272. NET_API_STATUS
  273. MigNetShareSetInfo (
  274. IN PTSTR Server, // ignored
  275. IN PTSTR NetName,
  276. IN DWORD Level,
  277. IN PBYTE Buf,
  278. OUT PDWORD ErrParam // ignored
  279. )
  280. /*++
  281. Routine Description:
  282. MigNetShareSetInfo implements a NetShareSetInfo emulation routine, because
  283. the real routine does not work properly in GUI mode setup. See SDK
  284. documentation for details.
  285. Arguments:
  286. Server - Unused
  287. NetName - Specifies the share name to create.
  288. Level - Specifies the API level (must be 1501)
  289. Buf - Specifies a filled SHARE_INFO_1501 structure.
  290. ErrParam - Unused
  291. Return Value:
  292. The Win32 status code.
  293. --*/
  294. {
  295. SHARE_INFO_1501 *psi;
  296. DWORD rc;
  297. HKEY hKey;
  298. DWORD DontCare;
  299. TCHAR KeyName[MAX_TCHAR_PATH];
  300. DWORD Len;
  301. if (Level != 1501) {
  302. return ERROR_INVALID_LEVEL;
  303. }
  304. psi = (SHARE_INFO_1501 *) Buf;
  305. //
  306. // Verify share exists
  307. //
  308. StringCopyW (
  309. KeyName,
  310. L"SYSTEM\\CurrentControlSet\\Services\\" SHARES_REGISTRY_PATH
  311. );
  312. rc = TrackedRegOpenKeyEx (
  313. HKEY_LOCAL_MACHINE,
  314. KeyName,
  315. 0,
  316. KEY_READ,
  317. &hKey
  318. );
  319. if (rc != ERROR_SUCCESS) {
  320. return rc;
  321. }
  322. rc = RegQueryValueEx (hKey, NetName, NULL, NULL, NULL, NULL);
  323. CloseRegKey (hKey);
  324. if (rc != ERROR_SUCCESS) {
  325. if (rc == ERROR_FILE_NOT_FOUND) {
  326. rc = ERROR_INVALID_SHARENAME;
  327. }
  328. return rc;
  329. }
  330. //
  331. // Save security descriptor as binary type in registry
  332. //
  333. StringCopy (
  334. KeyName,
  335. L"SYSTEM\\CurrentControlSet\\Services\\" SHARES_SECURITY_REGISTRY_PATH
  336. );
  337. rc = TrackedRegCreateKeyEx (
  338. HKEY_LOCAL_MACHINE,
  339. KeyName,
  340. 0,
  341. S_EMPTY,
  342. REG_OPTION_NON_VOLATILE,
  343. KEY_ALL_ACCESS,
  344. NULL,
  345. &hKey,
  346. &DontCare
  347. );
  348. if (rc != ERROR_SUCCESS) {
  349. return rc;
  350. }
  351. Len = GetSecurityDescriptorLength (psi->shi1501_security_descriptor);
  352. rc = RegSetValueEx (
  353. hKey,
  354. NetName,
  355. 0,
  356. REG_BINARY,
  357. (PBYTE) psi->shi1501_security_descriptor,
  358. Len
  359. );
  360. CloseRegKey (hKey);
  361. return rc;
  362. }
  363. BOOL
  364. pCreateNetShare (
  365. IN PCTSTR NetName,
  366. IN PCTSTR Path,
  367. IN PCTSTR Remark,
  368. IN DWORD Type,
  369. IN DWORD Permissions
  370. )
  371. /*++
  372. Routine Description:
  373. pCreateNetShare is a wrapper to the Net APIs.
  374. Arguments:
  375. NetName - Specifies the share name
  376. Path - Specifies the local path to be shared
  377. Remark - Specifies the remark to register with the share
  378. Type - Specifies the share type
  379. Permissions - Specifies the Win9x share permissions, used only for logging
  380. errors.
  381. Return Value:
  382. TRUE if the share was created, FALSE otherwise.
  383. --*/
  384. {
  385. SHARE_INFO_2 si2;
  386. DWORD rc;
  387. PWSTR UnicodePath;
  388. BOOL b = FALSE;
  389. UnicodePath = (PWSTR) CreateUnicode (Path);
  390. MYASSERT (UnicodePath);
  391. __try {
  392. //
  393. // Make NetShareAdd call
  394. //
  395. ZeroMemory (&si2, sizeof (si2));
  396. si2.shi2_netname = (PTSTR) NetName;
  397. si2.shi2_type = (WORD) Type;
  398. si2.shi2_remark = (PTSTR) Remark;
  399. si2.shi2_permissions = 0;
  400. si2.shi2_max_uses = 0xffffffff;
  401. si2.shi2_path = UnicodePath;
  402. si2.shi2_passwd = NULL;
  403. rc = MigNetShareAdd (NULL, 2, (PBYTE) (&si2), NULL);
  404. if (rc != ERROR_SUCCESS) {
  405. SetLastError (rc);
  406. DEBUGMSG ((
  407. DBG_ERROR,
  408. "CreateShares: NetShareAdd failed for %s ('%s'), permissions=%x",
  409. NetName,
  410. Path,
  411. Permissions
  412. ));
  413. if (Permissions == W95_GENERIC_NONE) {
  414. LOG ((LOG_ERROR, (PCSTR)MSG_UNABLE_TO_CREATE_ACL_SHARE, NetName, Path));
  415. } else if (Permissions != W95_GENERIC_READ) {
  416. LOG ((LOG_ERROR, (PCSTR)MSG_UNABLE_TO_CREATE_RO_SHARE, NetName, Path));
  417. } else {
  418. LOG ((LOG_ERROR, (PCSTR)MSG_UNABLE_TO_CREATE_SHARE, NetName, Path));
  419. }
  420. __leave;
  421. }
  422. b = TRUE;
  423. }
  424. __finally {
  425. DestroyUnicode (UnicodePath);
  426. }
  427. return b;
  428. }
  429. VOID
  430. LogUsersWhoFailed (
  431. PBYTE AclMemberList,
  432. DWORD Members,
  433. PCTSTR Share,
  434. PCTSTR Path
  435. )
  436. /*++
  437. Routine Description:
  438. LogUsersWhoFailed implements logic to log the users who could not be added
  439. to a share. If there are a small number of users, a popup is given with
  440. each name. Otherwise, the share users are logged, and a popup tells the
  441. installer to look in the log for the list.
  442. Arguments:
  443. AclMemberList - Specifies the ACL data structure containing all the user
  444. names that need to be logged.
  445. Members - Specifies the number of members in AclMemberList.
  446. Share - Specifies the share name that could not be added.
  447. Path - Specifies the share path that could not be added.
  448. Return Value:
  449. None.
  450. --*/
  451. {
  452. PACLMEMBER AclMember;
  453. DWORD d;
  454. DWORD GoodCount;
  455. DWORD BadCount;
  456. HWND Parent;
  457. GoodCount = 0;
  458. BadCount = 0;
  459. AclMember = (PACLMEMBER) AclMemberList;
  460. for (d = 0 ; d < Members ; d++) {
  461. if (AclMember->Failed) {
  462. BadCount++;
  463. } else {
  464. GoodCount++;
  465. }
  466. GetNextAclMember (&AclMember);
  467. }
  468. if (!BadCount) {
  469. return;
  470. }
  471. if (BadCount < 5) {
  472. Parent = g_ParentWnd;
  473. } else {
  474. if (!GoodCount) {
  475. LOG ((LOG_ERROR, (PCSTR)MSG_ALL_SIDS_BAD, Share, Path));
  476. } else {
  477. LOG ((LOG_ERROR, (PCSTR)MSG_MANY_SIDS_BAD,
  478. BadCount, BadCount + GoodCount, Share, Path));
  479. }
  480. Parent = NULL;
  481. }
  482. AclMember = (PACLMEMBER) AclMemberList;
  483. for (d = 0 ; d < Members ; d++) {
  484. if (AclMember->Failed) {
  485. LOG ((LOG_ERROR, (PCSTR)MSG_NO_USER_SID, AclMember->UserOrGroup, Share, Path));
  486. }
  487. GetNextAclMember (&AclMember);
  488. }
  489. }
  490. BOOL
  491. SetShareAcl (
  492. IN PCTSTR Share,
  493. IN PCTSTR Path,
  494. IN PBYTE AclMemberList,
  495. IN DWORD MemberCount
  496. )
  497. /*++
  498. Routine Description:
  499. SetShareAcl applies the access control list to a share that was previously
  500. created.
  501. Arguments:
  502. Share - Specifies the share name
  503. Path - Specifies the share path
  504. AclMemberList - Specifies the ACL data structure giving the user(s) with
  505. rights to the share
  506. MemberCount - Specifies the number of members in AclMemberList.
  507. Return Value:
  508. TRUE if the ACL was successfully applied to the share, FALSE otherwise.
  509. --*/
  510. {
  511. BYTE Buf[8192];
  512. PSECURITY_DESCRIPTOR pSD;
  513. SECURITY_DESCRIPTOR desc;
  514. PSID Sid;
  515. PACL Acl;
  516. SHARE_INFO_1501 shi1501;
  517. DWORD rc;
  518. DWORD Size;
  519. PWSTR UnicodeShare;
  520. pSD = (PSECURITY_DESCRIPTOR) Buf;
  521. //
  522. // Get Administrator's SID--they are the owner of the share
  523. //
  524. Sid = GetSidForUser (g_AdministratorsGroupStr);
  525. if (!Sid) {
  526. return FALSE;
  527. }
  528. //
  529. // Start building security descriptor
  530. //
  531. InitializeSecurityDescriptor (&desc, SECURITY_DESCRIPTOR_REVISION);
  532. if (!SetSecurityDescriptorOwner (&desc, Sid, FALSE)) {
  533. LOG ((LOG_ERROR, "Could not set %s as owner", g_AdministratorsGroupStr));
  534. return FALSE;
  535. }
  536. //
  537. // Set the defaulted group to Domain\Domain Users (if it exists),
  538. // otherwise get SID of none
  539. //
  540. Sid = GetSidForUser (g_DomainUsersGroupStr);
  541. if (!Sid) {
  542. Sid = GetSidForUser (g_NoneGroupStr);
  543. }
  544. if (Sid) {
  545. SetSecurityDescriptorGroup (&desc, Sid, FALSE);
  546. }
  547. //
  548. // Create access allowed ACL from member list
  549. //
  550. Acl = CreateAclFromMemberList (AclMemberList, MemberCount);
  551. if (!Acl) {
  552. DEBUGMSG ((DBG_WARNING, "SetShareAcl failed because CreateAclFromMemberList failed"));
  553. return FALSE;
  554. }
  555. __try {
  556. UnicodeShare = (PWSTR) CreateUnicode (Share);
  557. MYASSERT (UnicodeShare);
  558. if (!SetSecurityDescriptorDacl (&desc, TRUE, Acl, FALSE)) {
  559. DEBUGMSG ((DBG_WARNING, "SetShareAcl failed because SetSecurityDescriptorDacl failed"));
  560. return FALSE;
  561. }
  562. //
  563. // Set security descriptor on share
  564. //
  565. Size = sizeof (Buf);
  566. if (!MakeSelfRelativeSD (&desc, pSD, &Size)) {
  567. LOG ((LOG_ERROR, "MakeSelfRelativeSD failed"));
  568. return FALSE;
  569. }
  570. ZeroMemory (&shi1501, sizeof (shi1501));
  571. shi1501.shi1501_security_descriptor = pSD;
  572. rc = MigNetShareSetInfo (NULL, UnicodeShare, 1501, (PBYTE) &shi1501, NULL);
  573. if (rc != ERROR_SUCCESS) {
  574. SetLastError (rc);
  575. LOG ((LOG_ERROR, "NetShareSetInfo failed"));
  576. return FALSE;
  577. }
  578. }
  579. __finally {
  580. if (Acl) {
  581. FreeMemberListAcl (Acl);
  582. }
  583. DestroyUnicode (UnicodeShare);
  584. }
  585. return TRUE;
  586. }
  587. VOID
  588. DoCreateShares (
  589. VOID
  590. )
  591. /*++
  592. Routine Description:
  593. DoCreateShares enumerates all the shares registered in memdb by WINNT32.
  594. For each enumeration, a share is created, and permissions or an ACL is
  595. applied.
  596. Arguments:
  597. None.
  598. Return Value:
  599. None.
  600. --*/
  601. {
  602. MEMDB_ENUM e, e2;
  603. TCHAR Path[MEMDB_MAX];
  604. TCHAR Remark[MEMDB_MAX];
  605. // we overlap the Remark stack buffer instead of making another
  606. #define flagKey Remark
  607. TCHAR Password[MEMDB_MAX];
  608. DWORD Flags;
  609. DWORD Members;
  610. DWORD shareType;
  611. GROWBUFFER NameList = GROWBUF_INIT;
  612. PCTSTR pathNT;
  613. //
  614. // Obtain shares from memdb
  615. //
  616. if (MemDbEnumItems (&e, MEMDB_CATEGORY_NETSHARES)) {
  617. do {
  618. //
  619. // Get share attributes
  620. //
  621. Flags = e.dwValue;
  622. if (!MemDbGetEndpointValueEx (
  623. MEMDB_CATEGORY_NETSHARES,
  624. e.szName,
  625. MEMDB_FIELD_PATH,
  626. Path
  627. )) {
  628. DEBUGMSG ((DBG_WARNING, "DoCreateShares: No path found for %s", e.szName));
  629. continue;
  630. }
  631. // IF YOU CHANGE CODE HERE: Note that flagKey is the same variable as Remark
  632. MemDbBuildKey (flagKey, MEMDB_CATEGORY_NETSHARES, e.szName, MEMDB_FIELD_TYPE, NULL);
  633. if (!MemDbGetValue (flagKey, &shareType)) {
  634. DEBUGMSG ((DBG_WARNING, "DoCreateShares: No type found for %s", e.szName));
  635. continue;
  636. }
  637. // IF YOU CHANGE CODE HERE: Note that flagKey is the same variable as Remark
  638. if (!MemDbGetEndpointValueEx (
  639. MEMDB_CATEGORY_NETSHARES,
  640. e.szName,
  641. MEMDB_FIELD_REMARK,
  642. Remark
  643. )) {
  644. Remark[0] = 0;
  645. }
  646. //
  647. // first check if the path changed
  648. //
  649. pathNT = GetPathStringOnNt (Path);
  650. //
  651. // Create the share and set appropriate security
  652. //
  653. if (Flags & SHI50F_ACLS) {
  654. //
  655. // Share has an ACL
  656. //
  657. if (pCreateNetShare (e.szName, pathNT, Remark, shareType, W95_GENERIC_NONE)) {
  658. //
  659. // For each user indexed, put them in an ACL member list
  660. //
  661. Members = 0;
  662. if (MemDbGetValueEx (
  663. &e2,
  664. MEMDB_CATEGORY_NETSHARES,
  665. e.szName,
  666. MEMDB_FIELD_ACCESS_LIST
  667. )) {
  668. do {
  669. //
  670. // On Win9x, per-user flags have a 8 flags that control access. We translate
  671. // them to one of four flavors on NT:
  672. //
  673. // 1. Deny All Access: (Flags == 0)
  674. // 2. Read-Only Access: (Flags & W95_GENERIC_READ) && !(Flags & W95_GENERIC_WRITE)
  675. // 3. Change-Only Access: !(Flags & W95_GENERIC_READ) && (Flags & W95_GENERIC_WRITE)
  676. // 4. Full Access: (Flags & W95_GENERIC_FULL) == W95_GENERIC_FULL
  677. //
  678. DEBUGMSG ((DBG_NETSHARES, "Share %s user %s flags %u", e.szName, e2.szName, e2.dwValue));
  679. if (AddAclMember (
  680. &NameList,
  681. e2.szName,
  682. Simplify9xAccessFlags (e2.dwValue)
  683. )) {
  684. Members++;
  685. }
  686. } while (MemDbEnumNextValue (&e2));
  687. }
  688. //
  689. // Convert member list into a real ACL and apply it to the share
  690. //
  691. if (NameList.Buf) {
  692. SetShareAcl (e.szName, pathNT, NameList.Buf, Members);
  693. LogUsersWhoFailed (NameList.Buf, Members, e.szName, pathNT);
  694. FreeGrowBuffer (&NameList);
  695. }
  696. }
  697. }
  698. else {
  699. //
  700. // Determine if a password is set
  701. //
  702. Password[0] = 0;
  703. if (Flags & SHI50F_RDONLY) {
  704. MemDbGetEndpointValueEx (
  705. MEMDB_CATEGORY_NETSHARES,
  706. e.szName,
  707. MEMDB_FIELD_RO_PASSWORD,
  708. Password
  709. );
  710. }
  711. if (!Password[0] && (Flags & SHI50F_FULL)) {
  712. MemDbGetEndpointValueEx (
  713. MEMDB_CATEGORY_NETSHARES,
  714. e.szName,
  715. MEMDB_FIELD_RW_PASSWORD,
  716. Password
  717. );
  718. }
  719. //
  720. // Enable all permissions for full access
  721. // Enable read-only permissions for read-only shares
  722. // Disable all permissions for no access
  723. //
  724. if (!Password[0]) {
  725. if (Flags & SHI50F_FULL) {
  726. Flags = W95_GENERIC_FULL;
  727. } else if (Flags & SHI50F_RDONLY) {
  728. Flags = W95_GENERIC_READ;
  729. } else if (Flags) {
  730. DEBUGMSG ((DBG_WHOOPS, "Flags (0x%X) is not 0, SHI50F_FULL or SHI50F_RDONLY", Flags));
  731. Flags = W95_GENERIC_NONE;
  732. }
  733. } else {
  734. DEBUGMSG ((DBG_VERBOSE, "Password on share %s is not supported", e.szName));
  735. Flags = W95_GENERIC_NONE;
  736. }
  737. //
  738. // We do not support share-level security with passwords. We
  739. // always create the share, but if a password exists, we
  740. // deny everyone access.
  741. //
  742. pCreateNetShare (e.szName, pathNT, Remark, shareType, Flags);
  743. Members = 0;
  744. if (AddAclMember (
  745. &NameList,
  746. g_EveryoneStr,
  747. Simplify9xAccessFlags (Flags)
  748. )) {
  749. Members++;
  750. }
  751. //
  752. // Convert member list into a real ACL and apply it to the share
  753. //
  754. if (NameList.Buf) {
  755. SetShareAcl (e.szName, pathNT, NameList.Buf, Members);
  756. FreeGrowBuffer (&NameList);
  757. }
  758. }
  759. FreePathString (pathNT);
  760. } while (MemDbEnumNextValue (&e));
  761. }
  762. }
  763. BOOL
  764. pUpdateRecycleBin (
  765. VOID
  766. )
  767. /*++
  768. Routine Description:
  769. Calls SHUpdateRecycleBinIcon to reset the status of the recycle bin. This
  770. operation takes a few seconds as all hard drives are scanned, the recycle
  771. bin database is read, and each entry in the database is verified.
  772. Arguments:
  773. None
  774. Return value:
  775. TRUE - the operation was successful
  776. FALSE - the operation failed (either LoadLibrary or GetProcAddress)
  777. --*/
  778. {
  779. SHUPDATERECYCLEBINICON_PROC Fn;
  780. HINSTANCE LibInst;
  781. BOOL b = TRUE;
  782. LibInst = LoadLibrary (S_SHELL32_DLL);
  783. if (!LibInst) {
  784. return FALSE;
  785. }
  786. Fn = (SHUPDATERECYCLEBINICON_PROC) GetProcAddress (
  787. LibInst,
  788. S_ANSI_SHUPDATERECYCLEBINICON
  789. );
  790. if (Fn) {
  791. //
  792. // Scan all hard disks and validate the recycle bin status
  793. //
  794. Fn();
  795. } else {
  796. b = FALSE;
  797. }
  798. FreeLibrary (LibInst);
  799. return TRUE;
  800. }
  801. VOID
  802. pFixLogonDomainIfUserIsAdministrator (
  803. VOID
  804. )
  805. /*++
  806. Routine Description:
  807. pFixLogonDomainIfUserIsAdministrator handles a special error case where
  808. the logon domain is not equivalent to the computer name, but the user
  809. is named Administrator. In this case, we change the default logon domain
  810. to be the computer name.
  811. Arguments:
  812. None
  813. Return value:
  814. none
  815. --*/
  816. {
  817. PCTSTR AdministratorAcct;
  818. HKEY Key;
  819. PCTSTR Data;
  820. AdministratorAcct = GetStringResource (MSG_ADMINISTRATOR_ACCOUNT);
  821. if (AdministratorAcct) {
  822. Key = OpenRegKeyStr (S_WINLOGON_KEY);
  823. if (Key) {
  824. Data = GetRegValueString (Key, S_DEFAULT_USER_NAME);
  825. if (Data) {
  826. if (!StringCompare (Data, AdministratorAcct)) {
  827. //
  828. // Account name exactly matches our Administrator
  829. // string, so there is a good chance we wrote
  830. // this string. Therefore, we need to write the
  831. // computer name as the default domain.
  832. //
  833. if (g_ComputerName[0]) {
  834. RegSetValueEx (
  835. Key,
  836. S_DEFAULT_DOMAIN_NAME,
  837. 0,
  838. REG_SZ,
  839. (PBYTE) g_ComputerName,
  840. SizeOfString (g_ComputerName)
  841. );
  842. }
  843. }
  844. MemFree (g_hHeap, 0, Data);
  845. }
  846. CloseRegKey (Key);
  847. }
  848. FreeStringResource (AdministratorAcct);
  849. }
  850. }
  851. DWORD
  852. ProcessLocalMachine_First (
  853. DWORD Request
  854. )
  855. {
  856. if (Request == REQUEST_QUERYTICKS) {
  857. return TICKS_INI_ACTIONS_FIRST +
  858. TICKS_INI_MOVE +
  859. TICKS_INI_CONVERSION +
  860. TICKS_INI_MIGRATION;
  861. }
  862. //
  863. // We process the local machine in the following order:
  864. //
  865. // Initialization:
  866. // (1) Reload memdb
  867. //
  868. // Ini files conversion and mapping
  869. //
  870. DEBUGMSG ((DBG_INIFILES, "INI Files Actions.First - START"));
  871. DEBUGLOGTIME (("Starting function: DoIniActions"));
  872. if (!DoIniActions (INIACT_WKS_FIRST)) {
  873. LOG ((LOG_ERROR, "Process Local Machine: Could not perform one or more INI Files Actions.First"));
  874. }
  875. DEBUGLOGTIME (("Function complete: DoIniActions"));
  876. TickProgressBarDelta (TICKS_INI_ACTIONS_FIRST);
  877. DEBUGMSG ((DBG_INIFILES, "INI Files Actions.First - STOP"));
  878. DEBUGMSG ((DBG_INIFILES, "INI file moving - START"));
  879. DEBUGLOGTIME (("Starting function: MoveIniSettings"));
  880. if (!MoveIniSettings ()) {
  881. LOG ((LOG_ERROR, "Process Local Machine: Could not move one or more .INI files settings."));
  882. return GetLastError();
  883. }
  884. DEBUGLOGTIME (("Function complete: MoveIniSettings"));
  885. TickProgressBarDelta (TICKS_INI_MOVE);
  886. DEBUGMSG ((DBG_INIFILES, "INI file moving - STOP"));
  887. DEBUGMSG ((DBG_INIFILES, "INI file conversion - START"));
  888. DEBUGLOGTIME (("Starting function: ConvertIniFiles"));
  889. if (!ConvertIniFiles ()) {
  890. LOG ((LOG_ERROR, "Process Local Machine: Could not convert one or more .INI files."));
  891. return GetLastError();
  892. }
  893. DEBUGLOGTIME (("Function complete: ConvertIniFiles"));
  894. TickProgressBarDelta (TICKS_INI_CONVERSION);
  895. DEBUGMSG ((DBG_INIFILES, "INI file conversion - STOP"));
  896. DEBUGMSG ((DBG_INIFILES, "INI file migration - START"));
  897. DEBUGLOGTIME (("Starting function: ProcessIniFileMapping"));
  898. if (!ProcessIniFileMapping (FALSE)) {
  899. LOG ((LOG_ERROR, "Process Local Machine: Could not migrate one or more .INI files."));
  900. return GetLastError();
  901. }
  902. DEBUGLOGTIME (("Function complete: ProcessIniFileMapping"));
  903. TickProgressBarDelta (TICKS_INI_MIGRATION);
  904. DEBUGMSG ((DBG_INIFILES, "INI file migration - STOP"));
  905. return ERROR_SUCCESS;
  906. }
  907. VOID
  908. pTurnOffNetAccountWizard (
  909. VOID
  910. )
  911. /*++
  912. Routine Description:
  913. pTurnOffNetAccountWizard removes the RunNetAccessWizard key to keep the
  914. network account wizard from appearing before the first logon.
  915. Arguments:
  916. None.
  917. Return Value:
  918. None.
  919. --*/
  920. {
  921. HKEY Key;
  922. Key = OpenRegKeyStr (TEXT("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"));
  923. if (Key) {
  924. RegDeleteValue (Key, TEXT("RunNetAccessWizard"));
  925. CloseRegKey (Key);
  926. } else {
  927. DEBUGMSG ((DBG_WARNING, "Could not open key for RunNetAccessWizard value"));
  928. }
  929. }
  930. typedef struct _OLE_CONTROL_DATA {
  931. LPWSTR FullPath;
  932. LPCWSTR RegType;
  933. } OLE_CONTROL_DATA, *POLE_CONTROL_DATA;
  934. DWORD
  935. RegisterIndividualOleControl(
  936. POLE_CONTROL_DATA OleControlData
  937. )
  938. {
  939. PROCESS_INFORMATION processInfo;
  940. STARTUPINFO startupInfo;
  941. WCHAR cmdLine [MAX_PATH] = L"";
  942. WCHAR cmdOptions [MAX_PATH] = L"";
  943. DWORD WaitResult;
  944. BOOL b = TRUE;
  945. ZeroMemory (&startupInfo, sizeof (STARTUPINFO));
  946. startupInfo.cb = sizeof (STARTUPINFO);
  947. if (OleControlData->RegType && (*OleControlData->RegType == L'B')) {
  948. // install and register
  949. wcscpy (cmdOptions, L"/s /i");
  950. } else if (OleControlData->RegType && (*OleControlData->RegType == L'R')) {
  951. // register
  952. wcscpy (cmdOptions, L"/s");
  953. } else if (OleControlData->RegType && (*OleControlData->RegType == L'I')) {
  954. // install
  955. wcscpy (cmdOptions, L"/s /i /n");
  956. } else if ((OleControlData->RegType == NULL) || (*OleControlData->RegType == L'\0')) {
  957. // register
  958. wcscpy (cmdOptions, L"/s");
  959. }
  960. wsprintf (cmdLine, L"%s\\regsvr32.exe %s %s", g_System32Dir, cmdOptions, OleControlData->FullPath);
  961. if (CreateProcess (NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &processInfo)) {
  962. WaitResult = WaitForSingleObject (processInfo.hProcess, 1000 * 60 * 10 );
  963. if (WaitResult == WAIT_TIMEOUT) {
  964. DEBUGMSG ((DBG_ERROR, "Timeout installing and/or registering OLE control %s", OleControlData->FullPath));
  965. b = FALSE;
  966. }
  967. CloseHandle (processInfo.hProcess);
  968. CloseHandle (processInfo.hThread);
  969. }
  970. else {
  971. DEBUGMSG ((DBG_ERROR, "Create process failed: %s", cmdLine));
  972. b = FALSE;
  973. }
  974. return b;
  975. }
  976. typedef struct _KNOWN_DIRS {
  977. PCWSTR DirId;
  978. PCWSTR Translation;
  979. }
  980. KNOWN_DIRSW, *PKNOWN_DIRSW;
  981. KNOWN_DIRSW g_KnownDirsW [] = {
  982. {L"10" , g_WinDir},
  983. {L"11" , g_System32Dir},
  984. {L"24" , g_WinDrive},
  985. {L"16422" , g_ProgramFiles},
  986. {L"16427" , g_ProgramFilesCommon},
  987. {NULL, NULL}
  988. };
  989. BOOL
  990. pConvertDirName (
  991. PCWSTR OldDirName,
  992. PWSTR NewDirName
  993. )
  994. {
  995. PCWSTR OldDirCurr = OldDirName;
  996. PCWSTR OldDirNext;
  997. PKNOWN_DIRSW p;
  998. NewDirName[0] = 0;
  999. OldDirNext = wcschr (OldDirCurr, L'\\');
  1000. if (OldDirNext == NULL) {
  1001. OldDirNext = wcschr (OldDirCurr, 0);
  1002. }
  1003. StringCopyABW (NewDirName, OldDirCurr, OldDirNext);
  1004. p = g_KnownDirsW;
  1005. while (p->DirId!= NULL) {
  1006. if (StringIMatchW (NewDirName, p->DirId)) {
  1007. StringCopyW (NewDirName, p->Translation);
  1008. break;
  1009. }
  1010. p++;
  1011. }
  1012. StringCatW (NewDirName, OldDirNext);
  1013. return TRUE;
  1014. }
  1015. BOOL
  1016. RegisterOleControls(
  1017. VOID
  1018. )
  1019. {
  1020. INFCONTEXT InfLine;
  1021. WCHAR DirId [MAX_PATH];
  1022. WCHAR SubDir [MAX_PATH];
  1023. WCHAR Filename [MAX_PATH];
  1024. WCHAR RegType [MAX_PATH];
  1025. WCHAR FullPathTemp[MAX_PATH];
  1026. WCHAR FullPath[MAX_PATH];
  1027. BOOL b;
  1028. DWORD d;
  1029. UINT Line;
  1030. WCHAR OldCD[MAX_PATH];
  1031. OLE_CONTROL_DATA OleControlData;
  1032. b = TRUE;
  1033. Line = 0;
  1034. //
  1035. // Preserve current directory just in case
  1036. //
  1037. d = GetCurrentDirectory(MAX_PATH,OldCD);
  1038. if(!d || (d >= MAX_PATH)) {
  1039. OldCD[0] = 0;
  1040. }
  1041. if(SetupFindFirstLine(g_WkstaMigInf, L"Win9xUpg_OleControls", NULL, &InfLine)) {
  1042. do {
  1043. Line++;
  1044. if (!SetupGetStringField (&InfLine, 1, DirId, MAX_PATH, NULL) ||
  1045. !SetupGetStringField (&InfLine, 2, SubDir, MAX_PATH, NULL) ||
  1046. !SetupGetStringField (&InfLine, 3, Filename, MAX_PATH, NULL) ||
  1047. !SetupGetStringField (&InfLine, 4, RegType, MAX_PATH, NULL)
  1048. ) {
  1049. DEBUGMSGW ((DBG_ERROR, "Bad line while registering controls %d", Line));
  1050. } else {
  1051. DEBUGMSG ((DBG_VERBOSE, "SETUP: filename for file to register is %s", Filename));
  1052. //
  1053. // Get full path to dll
  1054. //
  1055. if (pConvertDirName (DirId, FullPathTemp)) {
  1056. wcscpy (FullPath, FullPathTemp);
  1057. if (*SubDir) {
  1058. wcscat (FullPath, L"\\");
  1059. wcscat (FullPath, SubDir);
  1060. }
  1061. SetCurrentDirectory(FullPath);
  1062. wcscat (FullPath, L"\\");
  1063. wcscat (FullPath, Filename);
  1064. OleControlData.FullPath = FullPath;
  1065. OleControlData.RegType = RegType;
  1066. RegisterIndividualOleControl (&OleControlData);
  1067. } else {
  1068. DEBUGMSG ((DBG_ERROR, "SETUP: dll skipped, bad dirid %s", DirId));
  1069. b = FALSE;
  1070. }
  1071. }
  1072. } while(SetupFindNextLine(&InfLine,&InfLine));
  1073. }
  1074. if(OldCD[0]) {
  1075. SetCurrentDirectory(OldCD);
  1076. }
  1077. return(b);
  1078. }
  1079. DWORD
  1080. ProcessLocalMachine_Last (
  1081. DWORD Request
  1082. )
  1083. {
  1084. DWORD rc;
  1085. #ifdef VAR_PROGRESS_BAR
  1086. CHAR SystemDatPath[MAX_MBCHAR_PATH];
  1087. WIN32_FIND_DATAA fd;
  1088. HANDLE h;
  1089. DWORD SizeKB;
  1090. #endif
  1091. static LONG g_TicksHklm;
  1092. if (Request == REQUEST_QUERYTICKS) {
  1093. #ifdef VAR_PROGRESS_BAR
  1094. //
  1095. // estimate g_TicksHklm function of size of file system.dat
  1096. //
  1097. StringCopyA (SystemDatPath, g_SystemHiveDir);
  1098. StringCatA (SystemDatPath, "system.dat");
  1099. h = FindFirstFileA (SystemDatPath, &fd);
  1100. if (h != INVALID_HANDLE_VALUE) {
  1101. FindClose (h);
  1102. MYASSERT (!fd.nFileSizeHigh);
  1103. SizeKB = (fd.nFileSizeLow + 511) / 1024;
  1104. DEBUGLOGTIME (("ProcessLocalMachine_Last: system.dat size = %lu KB", SizeKB));
  1105. //
  1106. // statistics show that average time is 243 * (filesize in KB) - 372000
  1107. // I'll use 256 instead just to make sure the progress bar will not stop
  1108. // at the end looking like it's hanged
  1109. // The checked build is much slower (about 1.5 times)
  1110. //
  1111. #ifdef DEBUG
  1112. g_TicksHklm = SizeKB * 400;
  1113. #else
  1114. g_TicksHklm = SizeKB * 256;
  1115. #endif
  1116. } else {
  1117. //
  1118. // what's wrong here?
  1119. //
  1120. MYASSERT (FALSE);
  1121. g_TicksHklm = TICKS_HKLM;
  1122. }
  1123. #else // !defined VAR_PROGRESS_BAR
  1124. g_TicksHklm = TICKS_HKLM;
  1125. #endif
  1126. return TICKS_INI_MERGE +
  1127. g_TicksHklm +
  1128. TICKS_SHARES +
  1129. TICKS_LINK_EDIT +
  1130. TICKS_DOSMIG_SYS +
  1131. TICKS_UPDATERECYCLEBIN +
  1132. TICKS_STF +
  1133. TICKS_RAS +
  1134. TICKS_TAPI +
  1135. TICKS_MULTIMEDIA +
  1136. TICKS_INI_ACTIONS_LAST;
  1137. }
  1138. //
  1139. // We process the local machine in the following order:
  1140. //
  1141. // Initialization:
  1142. // (1) Reload memdb
  1143. //
  1144. // Local machine registry preparation:
  1145. //
  1146. // (1) Process wkstamig.inf
  1147. // (2) Merge Win95 registry with NT hive
  1148. //
  1149. // Process instructions written to memdb:
  1150. //
  1151. // (1) Create Win95 shares
  1152. // (2) Process LinkEdit section
  1153. //
  1154. //
  1155. // Load in default MemDb state, or at least delete everything if
  1156. // memdb.dat does not exist.
  1157. //
  1158. MemDbLoad (GetMemDbDat());
  1159. DEBUGMSG ((DBG_INIFILES, "INI file merge - START"));
  1160. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: MergeIniSettings"));
  1161. if (!MergeIniSettings ()) {
  1162. LOG ((LOG_ERROR, "Process Local Machine: Could not merge one or more .INI files."));
  1163. return GetLastError();
  1164. }
  1165. TickProgressBarDelta (TICKS_INI_MERGE);
  1166. DEBUGMSG ((DBG_INIFILES, "INI file merge - STOP"));
  1167. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: MergeIniSettings"));
  1168. //
  1169. // Process local machine migration rules
  1170. //
  1171. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: MergeRegistry"));
  1172. if (!MergeRegistry (S_WKSTAMIG_INF, NULL)) {
  1173. LOG ((LOG_ERROR, "Process Local Machine: MergeRegistry failed for wkstamig.inf"));
  1174. return GetLastError();
  1175. }
  1176. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: MergeRegistry"));
  1177. TickProgressBarDelta (g_TicksHklm);
  1178. //
  1179. // Process memdb nodes
  1180. //
  1181. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: DoCreateShares"));
  1182. DoCreateShares(); // we ignore all errors
  1183. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: DoCreateShares"));
  1184. TickProgressBarDelta (TICKS_SHARES);
  1185. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: DoLinkEdit"));
  1186. if (!DoLinkEdit()) {
  1187. LOG ((LOG_ERROR, "Process Local Machine: DoLinkEdit failed."));
  1188. return GetLastError();
  1189. }
  1190. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: DoLinkEdit"));
  1191. TickProgressBarDelta (TICKS_LINK_EDIT);
  1192. //
  1193. // Handle DOS system migration.
  1194. //
  1195. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: DosMigNt_System"));
  1196. __try {
  1197. if (DosMigNt_System() != EXIT_SUCCESS) {
  1198. LOG((LOG_ERROR, "Process Local Machine: DosMigNt_System failed."));
  1199. }
  1200. }
  1201. __except(TRUE) {
  1202. DEBUGMSG ((DBG_WHOOPS, "Exception in DosMigNt_System"));
  1203. }
  1204. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: DosMigNt_System"));
  1205. TickProgressBarDelta (TICKS_DOSMIG_SYS);
  1206. //
  1207. // Make the recycled bin the correct status
  1208. //
  1209. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: pUpdateRecycleBin"));
  1210. if (!pUpdateRecycleBin ()) {
  1211. LOG ((LOG_ERROR, "Process Local Machine: Could not update recycle bin."));
  1212. }
  1213. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: pUpdateRecycleBin"));
  1214. TickProgressBarDelta (TICKS_UPDATERECYCLEBIN);
  1215. //
  1216. // Migrate all .STF files (ACME Setup)
  1217. //
  1218. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: ProcessStfFiles"));
  1219. if (!ProcessStfFiles()) {
  1220. LOG ((LOG_ERROR, "Process Local Machine: Could not migrate one or more .STF files."));
  1221. }
  1222. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: ProcessStfFiles"));
  1223. TickProgressBarDelta (TICKS_STF);
  1224. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: Ras_MigrateSystem"));
  1225. if (!Ras_MigrateSystem()) {
  1226. LOG ((LOG_ERROR, "Ras MigrateSystem: Error migrating system."));
  1227. }
  1228. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: Ras_MigrateSystem"));
  1229. TickProgressBarDelta (TICKS_RAS);
  1230. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: Tapi_MigrateSystem"));
  1231. if (!Tapi_MigrateSystem()) {
  1232. LOG ((LOG_ERROR, "Tapi MigrateSystem: Error migrating system TAPI settings."));
  1233. }
  1234. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: Tapi_MigrateSystem"));
  1235. TickProgressBarDelta (TICKS_TAPI);
  1236. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: RestoreMMSettings_System"));
  1237. if (!RestoreMMSettings_System ()) {
  1238. LOG ((LOG_ERROR, "Process Local Machine: Could not restore multimedia settings."));
  1239. return GetLastError();
  1240. }
  1241. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: RestoreMMSettings_System"));
  1242. TickProgressBarDelta (TICKS_MULTIMEDIA);
  1243. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: DoIniActions.Last"));
  1244. DEBUGMSG ((DBG_INIFILES, "INI Files Actions.Last - START"));
  1245. if (!DoIniActions (INIACT_WKS_LAST)) {
  1246. LOG ((LOG_ERROR, "Process Local Machine: Could not perform one or more INI Files Actions.Last"));
  1247. }
  1248. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: DoIniActions.Last"));
  1249. TickProgressBarDelta (TICKS_INI_ACTIONS_LAST);
  1250. DEBUGMSG ((DBG_INIFILES, "INI Files Actions.Last - STOP"));
  1251. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: RegisterOleControls"));
  1252. RegisterOleControls ();
  1253. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: RegisterOleControls"));
  1254. //
  1255. // Blow away the Network Account Wizard (so fast it doesn't need ticks)
  1256. //
  1257. pTurnOffNetAccountWizard();
  1258. //
  1259. // Update security for Crypto group
  1260. //
  1261. rc = SetRegKeySecurity (
  1262. TEXT("HKLM\\Software\\Microsoft\\Cryptography\\MachineKeys"),
  1263. SF_EVERYONE_FULL,
  1264. NULL,
  1265. NULL,
  1266. TRUE
  1267. );
  1268. return ERROR_SUCCESS;
  1269. }
  1270. BOOL
  1271. pEnumWin9xHiveFileWorker (
  1272. IN OUT PHIVEFILE_ENUM EnumPtr
  1273. )
  1274. /*++
  1275. Routine Description:
  1276. pEnumWin9xHiveFileWorker parses wkstamig.inf to get the source path to a
  1277. Win9x registry hive, and it gets the destination of where the hive should
  1278. be migrated to. The source is tested, and if it doesn't exist, the
  1279. function returns FALSE.
  1280. Environment variables in both the source or dest are expanded before
  1281. this function returns success.
  1282. Arguments:
  1283. EnumPtr - Specifies partially completed enumeration structure (the
  1284. EnumPtr->is member must be valid). Receives the source and
  1285. destination of the hive to be migrated.
  1286. Return Value:
  1287. Returns TRUE if a hive needs to be transfered from EnumPtr->Source to
  1288. EnumPtr->Dest, otherwise FALSE.
  1289. --*/
  1290. {
  1291. PCTSTR Source;
  1292. PCTSTR Dest;
  1293. //
  1294. // Get the source and dest from the INF
  1295. //
  1296. Source = InfGetStringField (&EnumPtr->is, 0);
  1297. Dest = InfGetStringField (&EnumPtr->is, 1);
  1298. if (!Source || !Dest) {
  1299. DEBUGMSG ((DBG_WHOOPS, "wkstamig.inf HiveFilesToConvert is not correct"));
  1300. return FALSE;
  1301. }
  1302. //
  1303. // Expand the source and dest
  1304. //
  1305. if (EnumPtr->Source) {
  1306. FreeText (EnumPtr->Source);
  1307. }
  1308. EnumPtr->Source = ExpandEnvironmentText (Source);
  1309. if (EnumPtr->Dest) {
  1310. FreeText (EnumPtr->Dest);
  1311. }
  1312. EnumPtr->Dest = ExpandEnvironmentText (Dest);
  1313. //
  1314. // The source must exist
  1315. //
  1316. if (!DoesFileExist (EnumPtr->Source)) {
  1317. return FALSE;
  1318. }
  1319. return TRUE;
  1320. }
  1321. VOID
  1322. pAbortHiveFileEnum (
  1323. IN OUT PHIVEFILE_ENUM EnumPtr
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. pAbortHiveFileEnum cleans up the allocations from an active enumeration of
  1328. Win9x hive files. This routine must be called by the enum first/next when
  1329. the enumeration completes, or it must be called by the code using the
  1330. enumeration. It is safe to call this routine in both places.
  1331. Arguments:
  1332. EnumPtr - Specifies the enumeration that needs to be aborted or that has
  1333. completed successfully. Receives a zero'd struct.
  1334. Return Value:
  1335. None.
  1336. --*/
  1337. {
  1338. if (EnumPtr->Pool) {
  1339. PoolMemDestroyPool (EnumPtr->Pool);
  1340. }
  1341. if (EnumPtr->Source) {
  1342. FreeText (EnumPtr->Source);
  1343. }
  1344. if (EnumPtr->Dest) {
  1345. FreeText (EnumPtr->Dest);
  1346. }
  1347. ZeroMemory (EnumPtr, sizeof (HIVEFILE_ENUM));
  1348. }
  1349. BOOL
  1350. pEnumNextWin9xHiveFile (
  1351. IN OUT PHIVEFILE_ENUM EnumPtr
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. pEnumNextWin9xHiveFile continues the enumeration wksatmig.inf until either
  1356. a hive needing migration is found, or no more INF entries are left.
  1357. Arguments:
  1358. EnumPtr - Specifies an enumeration structure that was initialized by
  1359. pEnumFirstWin9xHiveFile. Receives the next hive file source &
  1360. dest enumeration if one is available.
  1361. Return Value:
  1362. TRUE if a Win9x hive file needs to be migrated (its source and dest
  1363. specified in EnumPtr). FALSE if no more hive files are to be processed.
  1364. --*/
  1365. {
  1366. do {
  1367. if (!InfFindNextLine (&EnumPtr->is)) {
  1368. pAbortHiveFileEnum (EnumPtr);
  1369. return FALSE;
  1370. }
  1371. } while (!pEnumWin9xHiveFileWorker (EnumPtr));
  1372. return TRUE;
  1373. }
  1374. BOOL
  1375. pEnumFirstWin9xHiveFile (
  1376. OUT PHIVEFILE_ENUM EnumPtr
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. pEnumFirstWin9xHiveFile begins an enumeration of Win9x registry files that
  1381. need to be migrated either to the NT registry, or to an NT registry hive
  1382. file.
  1383. Arguments:
  1384. EnumPtr - Receives the source Win9x hive file and the destination (either a
  1385. file or a registry path).
  1386. Return Value:
  1387. TRUE if a Win9x hive file was found and needs to be migrated, FALSE if no
  1388. hive file migration is needed.
  1389. --*/
  1390. {
  1391. ZeroMemory (EnumPtr, sizeof (HIVEFILE_ENUM));
  1392. //
  1393. // Begin the enumeration of the Hive Files section of wkstamig.inf
  1394. //
  1395. EnumPtr->Pool = PoolMemInitNamedPool ("Hive File Enum");
  1396. InitInfStruct (&EnumPtr->is, NULL, EnumPtr->Pool);
  1397. if (!InfFindFirstLine (g_WkstaMigInf, S_WKSTAMIG_HIVE_FILES, NULL, &EnumPtr->is)) {
  1398. pAbortHiveFileEnum (EnumPtr);
  1399. return FALSE;
  1400. }
  1401. //
  1402. // Attempt to return the first hive
  1403. //
  1404. if (pEnumWin9xHiveFileWorker (EnumPtr)) {
  1405. return TRUE;
  1406. }
  1407. //
  1408. // Hive does not exist, continue enumeration
  1409. //
  1410. return pEnumNextWin9xHiveFile (EnumPtr);
  1411. }
  1412. BOOL
  1413. pTransferWin9xHiveToRegKey (
  1414. IN PCTSTR Win9xHive,
  1415. IN PCTSTR NtRootKey
  1416. )
  1417. /*++
  1418. Routine Description:
  1419. pTransferWin9xHiveToRegKey maps in a Win9x hive file, enumerates all the
  1420. keys and values, and transfers them to the NT registry.
  1421. Arguments:
  1422. Win9xHive - Specifies the registry hive file (a Win9x hive)
  1423. NtRootKey - Specifies the path to the NT registry destination, such as
  1424. HKLM\foo.
  1425. Return Value:
  1426. TRUE if the hive file was transferred without an error, FALSE otherwise.
  1427. Use GetLastError to get the error code.
  1428. --*/
  1429. {
  1430. LONG rc;
  1431. HKEY DestKey;
  1432. BOOL b = FALSE;
  1433. REGTREE_ENUM e;
  1434. REGVALUE_ENUM e2;
  1435. PCTSTR SubKey;
  1436. HKEY DestSubKey;
  1437. BOOL EnumAbort = FALSE;
  1438. PBYTE DataBuf;
  1439. GROWBUFFER Data = GROWBUF_INIT;
  1440. DWORD Type;
  1441. DWORD Size;
  1442. BOOL CloseDestSubKey = FALSE;
  1443. //
  1444. // Map the hive into a temporary key
  1445. //
  1446. rc = Win95RegLoadKey (
  1447. HKEY_LOCAL_MACHINE,
  1448. S_HIVE_TEMP,
  1449. Win9xHive
  1450. );
  1451. if (rc != ERROR_SUCCESS) {
  1452. DEBUGMSG ((DBG_ERROR, "Can't load %s for transfer", Win9xHive));
  1453. return FALSE;
  1454. }
  1455. __try {
  1456. DestKey = CreateRegKeyStr (NtRootKey);
  1457. if (!DestKey) {
  1458. DEBUGMSG ((DBG_ERROR, "Can't create %s", NtRootKey));
  1459. __leave;
  1460. }
  1461. if (EnumFirstRegKeyInTree95 (&e, TEXT("HKLM\\") S_HIVE_TEMP)) {
  1462. EnumAbort = TRUE;
  1463. do {
  1464. //
  1465. // Create the NT destination; if SubKey is empty, then
  1466. // use the root key for the destination.
  1467. //
  1468. SubKey = (PCTSTR) ((PBYTE) e.FullKeyName + e.EnumBaseBytes);
  1469. if (*SubKey) {
  1470. DestSubKey = CreateRegKey (DestKey, SubKey);
  1471. if (!DestSubKey) {
  1472. DEBUGMSG ((DBG_ERROR, "Can't create subkey %s", SubKey));
  1473. __leave;
  1474. }
  1475. CloseDestSubKey = TRUE;
  1476. } else {
  1477. DestSubKey = DestKey;
  1478. }
  1479. //
  1480. // Copy all values in 9x key to NT
  1481. //
  1482. if (EnumFirstRegValue95 (&e2, e.CurrentKey->KeyHandle)) {
  1483. do {
  1484. Data.End = 0;
  1485. DataBuf = GrowBuffer (&Data, e2.DataSize);
  1486. if (!DataBuf) {
  1487. DEBUGMSG ((DBG_ERROR, "Data size is too big: %s", e2.DataSize));
  1488. __leave;
  1489. }
  1490. Size = e2.DataSize;
  1491. rc = Win95RegQueryValueEx (
  1492. e2.KeyHandle,
  1493. e2.ValueName,
  1494. NULL,
  1495. &Type,
  1496. DataBuf,
  1497. &Size
  1498. );
  1499. if (rc != ERROR_SUCCESS) {
  1500. DEBUGMSG ((
  1501. DBG_ERROR,
  1502. "Can't read enumerated value:\n"
  1503. " %s\n"
  1504. " %s [%s]",
  1505. Win9xHive,
  1506. e.FullKeyName,
  1507. e2.ValueName
  1508. ));
  1509. __leave;
  1510. }
  1511. MYASSERT (Size == e2.DataSize);
  1512. rc = RegSetValueEx (
  1513. DestSubKey,
  1514. e2.ValueName,
  1515. 0,
  1516. e2.Type,
  1517. DataBuf,
  1518. Size
  1519. );
  1520. if (rc != ERROR_SUCCESS) {
  1521. DEBUGMSG ((
  1522. DBG_ERROR,
  1523. "Can't write enumerated value:\n"
  1524. " %s\n"
  1525. " %s\\%s [%s]",
  1526. Win9xHive,
  1527. NtRootKey,
  1528. SubKey,
  1529. e2.ValueName
  1530. ));
  1531. __leave;
  1532. }
  1533. } while (EnumNextRegValue95 (&e2));
  1534. }
  1535. if (CloseDestSubKey) {
  1536. CloseRegKey (DestSubKey);
  1537. CloseDestSubKey = FALSE;
  1538. }
  1539. } while (EnumNextRegKeyInTree95 (&e));
  1540. EnumAbort = FALSE;
  1541. }
  1542. ELSE_DEBUGMSG ((DBG_WARNING, "%s is empty", Win9xHive));
  1543. b = TRUE;
  1544. }
  1545. __finally {
  1546. PushError();
  1547. if (CloseDestSubKey) {
  1548. CloseRegKey (DestSubKey);
  1549. }
  1550. if (EnumAbort) {
  1551. AbortRegKeyTreeEnum95 (&e);
  1552. }
  1553. Win95RegUnLoadKey (HKEY_LOCAL_MACHINE, TEXT("$$$"));
  1554. if (DestKey) {
  1555. CloseRegKey (DestKey);
  1556. }
  1557. FreeGrowBuffer (&Data);
  1558. PopError();
  1559. }
  1560. return b;
  1561. }
  1562. BOOL
  1563. pTransferWin9xHive (
  1564. IN PCTSTR Win9xHive,
  1565. IN PCTSTR Destination
  1566. )
  1567. /*++
  1568. Routine Description:
  1569. pTransferWin9xHive transfers a Win9x registry hive file (foo.dat) to either
  1570. an NT registry file, or a key in the NT registry. The source and
  1571. destination can be the same file.
  1572. Arguments:
  1573. Win9xHive - Specifies the registry hive file path (a Win9x hive file).
  1574. Destination - Specifies either a path or NT registry location where the
  1575. Win9xHive should be transfered to.
  1576. Return Value:
  1577. TRUE if the hive was transfered, FALSE otherwise. Call GetLastError for an
  1578. error code.
  1579. --*/
  1580. {
  1581. PCTSTR DestHive;
  1582. BOOL ToHiveFile;
  1583. HKEY Key;
  1584. LONG rc;
  1585. //
  1586. // Determine if destination is a hive file or a reg location
  1587. //
  1588. if (_istalpha (Destination[0]) && Destination[1] == TEXT(':')) {
  1589. ToHiveFile = TRUE;
  1590. DestHive = TEXT("HKLM\\") S_TRANSFER_HIVE;
  1591. } else {
  1592. ToHiveFile = FALSE;
  1593. DestHive = Destination;
  1594. }
  1595. //
  1596. // Blast the Win9x hive data to the temp location
  1597. //
  1598. if (!pTransferWin9xHiveToRegKey (Win9xHive, DestHive)) {
  1599. RegDeleteKey (HKEY_LOCAL_MACHINE, S_TRANSFER_HIVE);
  1600. return FALSE;
  1601. }
  1602. //
  1603. // Save the key if the destination is a hive file
  1604. //
  1605. if (ToHiveFile) {
  1606. Key = OpenRegKeyStr (DestHive);
  1607. if (!Key) {
  1608. DEBUGMSG ((DBG_ERROR, "Transfer hive key %s does not exist", DestHive));
  1609. return FALSE;
  1610. }
  1611. rc = RegSaveKey (Key, Destination, NULL);
  1612. CloseRegKey (Key);
  1613. RegDeleteKey (HKEY_LOCAL_MACHINE, S_TRANSFER_HIVE);
  1614. if (rc != ERROR_SUCCESS) {
  1615. DEBUGMSG ((DBG_ERROR, "Win9x hive %s could not be saved to %s", Win9xHive, Destination));
  1616. return FALSE;
  1617. }
  1618. }
  1619. //
  1620. // Delete the source file if the destination is not the same
  1621. //
  1622. if (!ToHiveFile || !StringIMatch (Win9xHive, DestHive)) {
  1623. //
  1624. // By adding info to memdb, we must enforce a rule that
  1625. // memdb cannot be reloaded. Otherwise we lose our
  1626. // changes.
  1627. //
  1628. DeclareTemporaryFile (Win9xHive);
  1629. #ifdef DEBUG
  1630. g_NoReloadsAllowed = TRUE;
  1631. #endif
  1632. }
  1633. return TRUE;
  1634. }
  1635. DWORD
  1636. ConvertHiveFiles (
  1637. DWORD Request
  1638. )
  1639. /*++
  1640. Routine Description:
  1641. ConvertHiveFiles enumerates all the hive files on the system that need
  1642. conversion, and calls pTransferWin9xHive to migrate them to the destination
  1643. specified in wkstamig.inf.
  1644. Arguments:
  1645. Request - Specifies the progress bar-driven request.
  1646. Return Value:
  1647. If Request is REQUEST_QUERYTICKS, the return value is the number of ticks
  1648. this routine is expected to take. Otherwise, the return value is
  1649. ERROR_SUCCESS.
  1650. --*/
  1651. {
  1652. HIVEFILE_ENUM e;
  1653. switch (Request) {
  1654. case REQUEST_QUERYTICKS:
  1655. return TICKS_HIVE_CONVERSION;
  1656. case REQUEST_RUN:
  1657. //
  1658. // Enumerate all the hives that need to be processed
  1659. //
  1660. if (pEnumFirstWin9xHiveFile (&e)) {
  1661. do {
  1662. pTransferWin9xHive (e.Source, e.Dest);
  1663. } while (pEnumNextWin9xHiveFile (&e));
  1664. }
  1665. ELSE_DEBUGMSG ((DBG_NAUSEA, "ConvertHiveFiles: Nothing to do"));
  1666. break;
  1667. default:
  1668. break;
  1669. }
  1670. return ERROR_SUCCESS;
  1671. }
  1672. BOOL
  1673. pRegisterAtmFont (
  1674. IN PCTSTR PfmFile,
  1675. IN PCTSTR PfbFile,
  1676. IN PCTSTR MmmFile OPTIONAL
  1677. )
  1678. /*++
  1679. Routine Description:
  1680. pRegisterAtmFont calls the AtmFontExW API to register an Adobe PS font.
  1681. Arguments:
  1682. PfmFile - Specifies the path to the PFM file (the font metrics)
  1683. PfbFile - Specifies the path to the PFB file (the font bits)
  1684. MmmFile - Specifies the path to the MMM file (the new style metrics file)
  1685. Return Value:
  1686. TRUE if the font was registered, FALSE otherwise.
  1687. --*/
  1688. {
  1689. WORD StyleAndType = 0x2000;
  1690. INT Result;
  1691. if (AtmAddFontEx == NULL) {
  1692. return FALSE;
  1693. }
  1694. Result = AtmAddFontEx (
  1695. NULL,
  1696. &StyleAndType,
  1697. PfmFile,
  1698. PfbFile,
  1699. MmmFile
  1700. );
  1701. DEBUGMSG_IF ((
  1702. Result != ERROR_SUCCESS,
  1703. Result == - 1 ? DBG_WARNING : DBG_ERROR,
  1704. "Font not added, result = %i.\n"
  1705. " PFM: %s\n"
  1706. " PFB: %s\n"
  1707. " MMM: %s\n",
  1708. Result,
  1709. PfmFile,
  1710. PfbFile,
  1711. MmmFile
  1712. ));
  1713. return Result == ERROR_SUCCESS;
  1714. }
  1715. PCTSTR
  1716. pGetAtmMultiSz (
  1717. POOLHANDLE Pool,
  1718. PCTSTR InfName,
  1719. PCTSTR SectionName,
  1720. PCTSTR KeyName
  1721. )
  1722. /*++
  1723. Routine Description:
  1724. pGetAtmMultiSz returns a multi-sz of the ATM font file names in the order
  1725. of PFM, PFB and MMM. Profile APIs are used because the key names have
  1726. commas, and they are unquoted.
  1727. Arguments:
  1728. Pool - Specifies the pool where the multi-sz will allocate buffer
  1729. space from.
  1730. InfName - Specifies the full path to the INF, to be used with the
  1731. profile APIs.
  1732. SectionName - Specifies the section name in InfName that is being processed.
  1733. KeyName - Specifies the key name to process
  1734. Return Value:
  1735. A pointer to a multi-sz allocated in the specified pool.
  1736. --*/
  1737. {
  1738. PTSTR MultiSz;
  1739. PTSTR d;
  1740. TCHAR FileBuf[MAX_TCHAR_PATH * 2];
  1741. UINT Bytes;
  1742. GetPrivateProfileString (
  1743. SectionName,
  1744. KeyName,
  1745. TEXT(""),
  1746. FileBuf,
  1747. sizeof (FileBuf) / sizeof (FileBuf[0]),
  1748. InfName
  1749. );
  1750. //
  1751. // Turn all commas into nuls
  1752. //
  1753. d = FileBuf;
  1754. while (*d) {
  1755. if (_tcsnextc (d) == TEXT(',')) {
  1756. *d = 0;
  1757. }
  1758. d = _tcsinc (d);
  1759. }
  1760. //
  1761. // Terminate the multi-sz
  1762. //
  1763. d++;
  1764. *d = 0;
  1765. d++;
  1766. //
  1767. // Transfer to a pool-based allocation and return it
  1768. //
  1769. Bytes = (UINT) ((PBYTE) d - (PBYTE) FileBuf);
  1770. MultiSz = (PTSTR) PoolMemGetAlignedMemory (Pool, Bytes);
  1771. CopyMemory (MultiSz, FileBuf, Bytes);
  1772. return MultiSz;
  1773. }
  1774. BOOL
  1775. pEnumAtmFontWorker (
  1776. IN OUT PATM_FONT_ENUM EnumPtr
  1777. )
  1778. /*++
  1779. Routine Description:
  1780. pEnumAtmFontWorker implements the logic of parsing ATM.INI to get the Adobe
  1781. font names. This routine completes an enumeration started by
  1782. pEnumFirstAtmFont or pEnumNextAtmFont.
  1783. Arguments:
  1784. EnumPtr - Specifies a partially completed enumeration structure, receives a
  1785. fully completed structure.
  1786. Return Value:
  1787. TRUE if an ATM font was enumerated, FALSE otherwise.
  1788. --*/
  1789. {
  1790. PTSTR p;
  1791. PCTSTR MultiSz;
  1792. BOOL MetricFileExists;
  1793. //
  1794. // Get PFM, PFB and MMM files
  1795. //
  1796. MultiSz = pGetAtmMultiSz (
  1797. EnumPtr->Pool,
  1798. EnumPtr->InfName,
  1799. S_FONTS,
  1800. EnumPtr->KeyNames
  1801. );
  1802. if (!MultiSz) {
  1803. return FALSE;
  1804. }
  1805. if (*MultiSz) {
  1806. _tcssafecpy (EnumPtr->PfmFile, MultiSz, MAX_TCHAR_PATH);
  1807. MultiSz = GetEndOfString (MultiSz) + 1;
  1808. }
  1809. if (*MultiSz) {
  1810. _tcssafecpy (EnumPtr->PfbFile, MultiSz, MAX_TCHAR_PATH);
  1811. } else {
  1812. return FALSE;
  1813. }
  1814. MultiSz = pGetAtmMultiSz (
  1815. EnumPtr->Pool,
  1816. EnumPtr->InfName,
  1817. S_MMFONTS,
  1818. EnumPtr->KeyNames
  1819. );
  1820. if (MultiSz) {
  1821. _tcssafecpy (EnumPtr->MmmFile, MultiSz, MAX_TCHAR_PATH);
  1822. MultiSz = GetEndOfString (MultiSz) + 1;
  1823. if (*MultiSz) {
  1824. DEBUGMSG_IF ((
  1825. !StringIMatch (MultiSz, EnumPtr->PfbFile),
  1826. DBG_ERROR,
  1827. "ATM.INI: MMFonts and Fonts specify two different PFBs: %s and %s",
  1828. MultiSz,
  1829. EnumPtr->PfbFile
  1830. ));
  1831. }
  1832. } else {
  1833. EnumPtr->MmmFile[0] = 0;
  1834. }
  1835. //
  1836. // Special case: .MMM is listed in [Fonts]
  1837. //
  1838. p = _tcsrchr (EnumPtr->PfmFile, TEXT('.'));
  1839. if (p && p < _tcschr (p, TEXT('\\'))) {
  1840. p = NULL;
  1841. }
  1842. if (p && StringIMatch (p, TEXT(".mmm"))) {
  1843. EnumPtr->PfmFile[0] = 0;
  1844. }
  1845. //
  1846. // Special case: .MMM exists but is not listed in atm.ini
  1847. //
  1848. if (!EnumPtr->MmmFile[0]) {
  1849. StringCopy (EnumPtr->MmmFile, EnumPtr->PfmFile);
  1850. p = _tcsrchr (EnumPtr->MmmFile, TEXT('.'));
  1851. if (p && p < _tcschr (p, TEXT('\\'))) {
  1852. p = NULL;
  1853. }
  1854. if (p) {
  1855. StringCopy (p, TEXT(".mmm"));
  1856. if (!DoesFileExist (EnumPtr->MmmFile)) {
  1857. EnumPtr->MmmFile[0] = 0;
  1858. }
  1859. } else {
  1860. EnumPtr->MmmFile[0] = 0;
  1861. }
  1862. }
  1863. //
  1864. // Verify all files exist
  1865. //
  1866. MetricFileExists = FALSE;
  1867. if (EnumPtr->PfmFile[0] && DoesFileExist (EnumPtr->PfmFile)) {
  1868. MetricFileExists = TRUE;
  1869. }
  1870. if (EnumPtr->MmmFile[0] && DoesFileExist (EnumPtr->MmmFile)) {
  1871. MetricFileExists = TRUE;
  1872. }
  1873. if (!DoesFileExist (EnumPtr->PfbFile) || !MetricFileExists) {
  1874. DEBUGMSG ((
  1875. DBG_VERBOSE,
  1876. "At least one file is missing: %s, %s or %s",
  1877. EnumPtr->PfmFile[0] ? EnumPtr->PfmFile : TEXT("(no PFM specified)"),
  1878. EnumPtr->MmmFile[0] ? EnumPtr->MmmFile : TEXT("(no MMM specified)"),
  1879. EnumPtr->PfbFile
  1880. ));
  1881. return FALSE;
  1882. }
  1883. return TRUE;
  1884. }
  1885. VOID
  1886. pAbortAtmFontEnum (
  1887. IN OUT PATM_FONT_ENUM EnumPtr
  1888. )
  1889. /*++
  1890. Routine Description:
  1891. pAbortAtmFontEnum cleans up an enumeration structure after enumeration
  1892. completes or if enumeration needs to be aborted. This routine can safely be
  1893. called multiple times on the same structure.
  1894. Arguments:
  1895. EnumPtr - Specifies an initialized and possibly used enumeration structure.
  1896. Return Value:
  1897. None.
  1898. --*/
  1899. {
  1900. if (EnumPtr->Pool) {
  1901. PoolMemDestroyPool (EnumPtr->Pool);
  1902. }
  1903. ZeroMemory (EnumPtr, sizeof (ATM_FONT_ENUM));
  1904. }
  1905. BOOL
  1906. pEnumNextAtmFont (
  1907. IN OUT PATM_FONT_ENUM EnumPtr
  1908. )
  1909. /*++
  1910. Routine Description:
  1911. pEnumNextAtmFont continues enumeration, returning either another set of ATM
  1912. font paths, or FALSE.
  1913. Arguments:
  1914. EnumPtr - Specifies the enumeration structure started by pEnumNextAtmFont.
  1915. Return Value:
  1916. TRUE if another set of font paths is available, FALSE otherwise.
  1917. --*/
  1918. {
  1919. if (!EnumPtr->KeyNames || !(*EnumPtr->KeyNames)) {
  1920. pAbortAtmFontEnum (EnumPtr);
  1921. return FALSE;
  1922. }
  1923. //
  1924. // Continue enumeration, looping until a font path set was found,
  1925. // or there are no more atm.ini lines to enumerate.
  1926. //
  1927. do {
  1928. EnumPtr->KeyNames = GetEndOfString (EnumPtr->KeyNames) + 1;
  1929. if (!(*EnumPtr->KeyNames)) {
  1930. pAbortAtmFontEnum (EnumPtr);
  1931. return FALSE;
  1932. }
  1933. } while (!pEnumAtmFontWorker (EnumPtr));
  1934. return TRUE;
  1935. }
  1936. BOOL
  1937. pEnumFirstAtmFont (
  1938. OUT PATM_FONT_ENUM EnumPtr
  1939. )
  1940. /*++
  1941. Routine Description:
  1942. pEnumFirstAtmFont begins the enumeration of font path sets in ATM.INI.
  1943. Arguments:
  1944. EnumPtr - Receivies the first set of font paths found (if any).
  1945. Return Value:
  1946. TRUE if a font path set was found, FALSE otherwise.
  1947. --*/
  1948. {
  1949. TCHAR AtmIni[MAX_TCHAR_PATH];
  1950. PTSTR FilePart;
  1951. PTSTR KeyNames;
  1952. UINT Bytes;
  1953. //
  1954. // Init structure
  1955. //
  1956. ZeroMemory (EnumPtr, sizeof (ATM_FONT_ENUM));
  1957. //
  1958. // Find full path to atm.ini (usually in %windir%)
  1959. //
  1960. if (!SearchPath (NULL, TEXT("atm.ini"), NULL, MAX_TCHAR_PATH, AtmIni, &FilePart)) {
  1961. DEBUGMSG ((DBG_VERBOSE, "ATM.INI not found in search path"));
  1962. return FALSE;
  1963. }
  1964. StringCopy (EnumPtr->InfName, AtmIni);
  1965. //
  1966. // Establish processing pool and get all key names in [Fonts]
  1967. //
  1968. EnumPtr->Pool = PoolMemInitNamedPool ("ATM Font Enum");
  1969. MYASSERT (EnumPtr->Pool);
  1970. KeyNames = MemAlloc (g_hHeap, 0, MAX_KEY_NAME_LIST);
  1971. GetPrivateProfileString (
  1972. S_FONTS,
  1973. NULL,
  1974. TEXT(""),
  1975. KeyNames,
  1976. MAX_KEY_NAME_LIST,
  1977. AtmIni
  1978. );
  1979. Bytes = SizeOfMultiSz (KeyNames);
  1980. EnumPtr->KeyNames = (PTSTR) PoolMemGetAlignedMemory (EnumPtr->Pool, Bytes);
  1981. CopyMemory (EnumPtr->KeyNames, KeyNames, Bytes);
  1982. MemFree (g_hHeap, 0, KeyNames);
  1983. //
  1984. // Begin enumeration
  1985. //
  1986. if (!(*EnumPtr->KeyNames)) {
  1987. pAbortAtmFontEnum (EnumPtr);
  1988. return FALSE;
  1989. }
  1990. if (pEnumAtmFontWorker (EnumPtr)) {
  1991. return TRUE;
  1992. }
  1993. return pEnumNextAtmFont (EnumPtr);
  1994. }
  1995. DWORD
  1996. MigrateAtmFonts (
  1997. DWORD Request
  1998. )
  1999. /*++
  2000. Routine Description:
  2001. MigrateAtmFonts is called by the progress bar to query ticks or to migrate
  2002. ATM fonts.
  2003. Arguments:
  2004. Request - Specifies the reason the progress bar is calling the routine.
  2005. Return Value:
  2006. If Request is REQUEST_QUERYTICKS, then the return value is the number of
  2007. estimated ticks needed to complete processing. Otherwise the return value
  2008. is ERROR_SUCCESS.
  2009. --*/
  2010. {
  2011. ATM_FONT_ENUM e;
  2012. static HANDLE AtmLib;
  2013. TCHAR AtmIniPath[MAX_TCHAR_PATH];
  2014. if (Request == REQUEST_QUERYTICKS) {
  2015. //
  2016. // Dynamically load atmlib.dll
  2017. //
  2018. AtmAddFontEx = NULL;
  2019. AtmLib = LoadLibrary (TEXT("atmlib.dll"));
  2020. if (!AtmLib) {
  2021. DEBUGMSG ((DBG_ERROR, "Cannot load entry point from atmlib.dll!"));
  2022. } else {
  2023. (FARPROC) AtmAddFontEx = GetProcAddress (AtmLib, "ATMAddFontExW");
  2024. DEBUGMSG_IF ((!AtmAddFontEx, DBG_ERROR, "Cannot get entry point ATMAddFontExW in atmlib.dll!"));
  2025. }
  2026. return AtmAddFontEx ? TICKS_ATM_MIGRATION : 0;
  2027. } else if (Request != REQUEST_RUN) {
  2028. return ERROR_SUCCESS;
  2029. }
  2030. if (AtmAddFontEx) {
  2031. //
  2032. // Do the ATM font migration
  2033. //
  2034. if (pEnumFirstAtmFont (&e)) {
  2035. StringCopy (AtmIniPath, e.InfName);
  2036. do {
  2037. if (pRegisterAtmFont (e.PfmFile, e.PfbFile, e.MmmFile)) {
  2038. DEBUGMSG ((DBG_VERBOSE, "ATM font registered %s", e.PfbFile));
  2039. }
  2040. } while (pEnumNextAtmFont (&e));
  2041. DeclareTemporaryFile (AtmIniPath);
  2042. #ifdef DEBUG
  2043. g_NoReloadsAllowed = TRUE;
  2044. #endif
  2045. }
  2046. //
  2047. // Clean up use of atmlib.dll - we're finished
  2048. //
  2049. FreeLibrary (AtmLib);
  2050. AtmLib = NULL;
  2051. AtmAddFontEx = NULL;
  2052. }
  2053. return ERROR_SUCCESS;
  2054. }
  2055. DWORD
  2056. RunSystemExternalProcesses (
  2057. IN DWORD Request
  2058. )
  2059. {
  2060. LONG Count;
  2061. if (Request == REQUEST_QUERYTICKS) {
  2062. //
  2063. // Count the number of entries and multiply by a constant
  2064. //
  2065. Count = SetupGetLineCount (g_WkstaMigInf, S_EXTERNAL_PROCESSES);
  2066. #ifdef PROGRESS_BAR
  2067. DEBUGLOGTIME (("RunSystemExternalProcesses: ExternalProcesses=%ld", Count));
  2068. #endif
  2069. if (Count < 1) {
  2070. return 0;
  2071. }
  2072. return Count * TICKS_SYSTEM_EXTERN_PROCESSES;
  2073. }
  2074. if (Request != REQUEST_RUN) {
  2075. return ERROR_SUCCESS;
  2076. }
  2077. //
  2078. // Loop through the processes and run each of them
  2079. //
  2080. RunExternalProcesses (g_WkstaMigInf, NULL);
  2081. return ERROR_SUCCESS;
  2082. }
  2083. BOOL
  2084. pEnumFirstWin9xBriefcase (
  2085. OUT PBRIEFCASE_ENUM e
  2086. )
  2087. {
  2088. if (!MemDbGetValueEx (&e->mde, MEMDB_CATEGORY_BRIEFCASES, NULL, NULL)) {
  2089. return FALSE;
  2090. }
  2091. e->BrfcaseDb = e->mde.szName;
  2092. return TRUE;
  2093. }
  2094. BOOL
  2095. pEnumNextWin9xBriefcase (
  2096. IN OUT PBRIEFCASE_ENUM e
  2097. )
  2098. {
  2099. if (!MemDbEnumNextValue (&e->mde)) {
  2100. return FALSE;
  2101. }
  2102. e->BrfcaseDb = e->mde.szName;
  2103. return TRUE;
  2104. }
  2105. BOOL
  2106. pMigrateBriefcase (
  2107. IN PCTSTR BriefcaseDatabase,
  2108. IN PCTSTR BriefcaseDir
  2109. )
  2110. {
  2111. HBRFCASE hbrfcase;
  2112. PTSTR NtPath;
  2113. BOOL Save, Success;
  2114. TWINRESULT tr;
  2115. BRFPATH_ENUM e;
  2116. BOOL Result = TRUE;
  2117. __try {
  2118. g_BrfcasePool = PoolMemInitNamedPool ("Briefcase");
  2119. if (!g_BrfcasePool) {
  2120. return FALSE;
  2121. }
  2122. tr = OpenBriefcase (BriefcaseDatabase, OB_FL_OPEN_DATABASE, NULL, &hbrfcase);
  2123. if (tr == TR_SUCCESS) {
  2124. if (EnumFirstBrfcasePath (hbrfcase, &e)) {
  2125. Save = FALSE;
  2126. Success = TRUE;
  2127. do {
  2128. if (StringIMatch (BriefcaseDir, e.PathString)) {
  2129. //
  2130. // ignore this path
  2131. //
  2132. continue;
  2133. }
  2134. NtPath = GetPathStringOnNt (e.PathString);
  2135. MYASSERT (NtPath);
  2136. if (!StringIMatch (NtPath, e.PathString)) {
  2137. //
  2138. // try to replace Win9x path with NT path
  2139. //
  2140. if (!ReplaceBrfcasePath (&e, NtPath)) {
  2141. Success = FALSE;
  2142. break;
  2143. }
  2144. Save = TRUE;
  2145. }
  2146. FreePathString (NtPath);
  2147. } while (EnumNextBrfcasePath (&e));
  2148. if (!Success || Save && SaveBriefcase (hbrfcase) != TR_SUCCESS) {
  2149. Result = FALSE;
  2150. }
  2151. }
  2152. CloseBriefcase(hbrfcase);
  2153. }
  2154. }
  2155. __finally {
  2156. PoolMemDestroyPool (g_BrfcasePool);
  2157. g_BrfcasePool = NULL;
  2158. }
  2159. return Result;
  2160. }
  2161. DWORD
  2162. MigrateBriefcases (
  2163. DWORD Request
  2164. )
  2165. /*++
  2166. Routine Description:
  2167. MigrateBriefcases is called by the progress bar to query ticks or to migrate
  2168. briefcases.
  2169. Arguments:
  2170. Request - Specifies the reason the progress bar is calling the routine.
  2171. Return Value:
  2172. If Request is REQUEST_QUERYTICKS, then the return value is the number of
  2173. estimated ticks needed to complete processing. Otherwise the return value
  2174. is ERROR_SUCCESS.
  2175. --*/
  2176. {
  2177. BRIEFCASE_ENUM e;
  2178. TCHAR BrfcaseDir[MAX_PATH + 2];
  2179. PTSTR p;
  2180. PTSTR BrfcaseDbOnNt;
  2181. switch (Request) {
  2182. case REQUEST_QUERYTICKS:
  2183. return TICKS_MIGRATE_BRIEFCASES;
  2184. case REQUEST_RUN:
  2185. //
  2186. // Enumerate all the briefcases that need to be processed
  2187. //
  2188. if (pEnumFirstWin9xBriefcase (&e)) {
  2189. do {
  2190. BrfcaseDbOnNt = GetPathStringOnNt (e.BrfcaseDb);
  2191. MYASSERT (BrfcaseDbOnNt);
  2192. //
  2193. // get directory name first
  2194. //
  2195. if (CharCount (BrfcaseDbOnNt) <= MAX_PATH) {
  2196. StringCopy (BrfcaseDir, BrfcaseDbOnNt);
  2197. p = _tcsrchr (BrfcaseDir, TEXT('\\'));
  2198. if (p) {
  2199. *p = 0;
  2200. if (!pMigrateBriefcase (BrfcaseDbOnNt, BrfcaseDir)) {
  2201. LOG ((
  2202. LOG_WARNING,
  2203. (PCSTR)MSG_ERROR_MIGRATING_BRIEFCASE,
  2204. BrfcaseDir
  2205. ));
  2206. }
  2207. }
  2208. }
  2209. FreePathString (BrfcaseDbOnNt);
  2210. } while (pEnumNextWin9xBriefcase (&e));
  2211. }
  2212. ELSE_DEBUGMSG ((DBG_NAUSEA, "MigrateBriefcases: Nothing to do"));
  2213. break;
  2214. }
  2215. return ERROR_SUCCESS;
  2216. }
  2217. DWORD
  2218. RunSystemUninstallUserProfileCleanupPreparation (
  2219. IN DWORD Request
  2220. )
  2221. {
  2222. LONG Count;
  2223. if (Request == REQUEST_QUERYTICKS) {
  2224. //
  2225. // Count the number of entries and multiply by a constant
  2226. //
  2227. Count = SetupGetLineCount (g_WkstaMigInf, S_UNINSTALL_PROFILE_CLEAN_OUT);
  2228. #ifdef PROGRESS_BAR
  2229. DEBUGLOGTIME (("RunSystemUninstallUserProfileCleanupPreparation: FileNumber=%ld", Count));
  2230. #endif
  2231. if (Count < 1) {
  2232. return 1;
  2233. }
  2234. return Count * TICKS_SYSTEM_UNINSTALL_CLEANUP;
  2235. }
  2236. if (Request != REQUEST_RUN) {
  2237. return ERROR_SUCCESS;
  2238. }
  2239. //
  2240. // Loop through the files and mark them to be deleted during uninstall
  2241. //
  2242. UninstallUserProfileCleanupPreparation (g_WkstaMigInf, NULL, TRUE);
  2243. return ERROR_SUCCESS;
  2244. }
  2245. DWORD
  2246. AddOptionsDiskCleaner (
  2247. DWORD Request
  2248. )
  2249. {
  2250. HKEY key = NULL;
  2251. HKEY subKey = NULL;
  2252. PCTSTR optionsPath;
  2253. LONG rc;
  2254. PCTSTR descText = NULL;
  2255. DWORD d;
  2256. if (Request == REQUEST_QUERYTICKS) {
  2257. return 1;
  2258. }
  2259. if (Request != REQUEST_RUN) {
  2260. return ERROR_SUCCESS;
  2261. }
  2262. optionsPath = JoinPaths (g_WinDir, TEXT("OPTIONS"));
  2263. __try {
  2264. if (!DoesFileExist (optionsPath)) {
  2265. __leave;
  2266. }
  2267. key = OpenRegKeyStr (TEXT("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VolumeCaches"));
  2268. if (!key) {
  2269. DEBUGMSG ((DBG_ERROR, "Can't open VolumeCaches"));
  2270. __leave;
  2271. }
  2272. subKey = CreateRegKey (key, TEXT("Options Folder"));
  2273. if (!subKey) {
  2274. DEBUGMSG ((DBG_ERROR, "Can't create Options Folder"));
  2275. __leave;
  2276. }
  2277. rc = RegSetValueEx (
  2278. subKey,
  2279. TEXT(""),
  2280. 0,
  2281. REG_SZ,
  2282. (PBYTE) S_CLEANER_GUID,
  2283. sizeof (S_CLEANER_GUID)
  2284. );
  2285. if (rc != ERROR_SUCCESS) {
  2286. DEBUGMSG ((DBG_ERROR, "Can't write default value to Options Folder key"));
  2287. }
  2288. descText = GetStringResource (MSG_OPTIONS_CLEANER);
  2289. rc = RegSetValueEx (
  2290. subKey,
  2291. TEXT("Description"),
  2292. 0,
  2293. REG_SZ,
  2294. (PBYTE) descText,
  2295. SizeOfString (descText)
  2296. );
  2297. if (rc != ERROR_SUCCESS) {
  2298. DEBUGMSG ((DBG_ERROR, "Can't write Description value to Options Folder key"));
  2299. }
  2300. FreeStringResource (descText);
  2301. descText = GetStringResource (MSG_OPTIONS_CLEANER_TITLE);
  2302. rc = RegSetValueEx (
  2303. subKey,
  2304. TEXT("Display"),
  2305. 0,
  2306. REG_SZ,
  2307. (PBYTE) descText,
  2308. SizeOfString (descText)
  2309. );
  2310. if (rc != ERROR_SUCCESS) {
  2311. DEBUGMSG ((DBG_ERROR, "Can't write Display value to Options Folder key"));
  2312. }
  2313. rc = RegSetValueEx (
  2314. subKey,
  2315. TEXT("FileList"),
  2316. 0,
  2317. REG_SZ,
  2318. (PBYTE) S_CLEANER_ALL_FILES,
  2319. sizeof (S_CLEANER_ALL_FILES)
  2320. );
  2321. if (rc != ERROR_SUCCESS) {
  2322. DEBUGMSG ((DBG_ERROR, "Can't write FileList value to Options Folder key"));
  2323. }
  2324. rc = RegSetValueEx (
  2325. subKey,
  2326. TEXT("Folder"),
  2327. 0,
  2328. REG_SZ,
  2329. (PBYTE) optionsPath,
  2330. SizeOfString (optionsPath)
  2331. );
  2332. if (rc != ERROR_SUCCESS) {
  2333. DEBUGMSG ((DBG_ERROR, "Can't write Folder value to Options Folder key"));
  2334. }
  2335. d = 0x17F; // see shell\applets\cleaner\dataclen\common.h DDEVCF_* flags
  2336. rc = RegSetValueEx (
  2337. subKey,
  2338. TEXT("Flags"),
  2339. 0,
  2340. REG_DWORD,
  2341. (PBYTE) &d,
  2342. sizeof (d)
  2343. );
  2344. if (rc != ERROR_SUCCESS) {
  2345. DEBUGMSG ((DBG_ERROR, "Can't write flags to Options Folder key"));
  2346. }
  2347. }
  2348. __finally {
  2349. FreePathString (optionsPath);
  2350. if (key) {
  2351. CloseRegKey (key);
  2352. }
  2353. if (subKey) {
  2354. CloseRegKey (subKey);
  2355. }
  2356. FreeStringResource (descText);
  2357. }
  2358. return ERROR_SUCCESS;
  2359. }