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.

3138 lines
77 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. BOOL result = FALSE;
  521. pSD = (PSECURITY_DESCRIPTOR) Buf;
  522. //
  523. // Get Administrator's SID--they are the owner of the share
  524. //
  525. Sid = GetSidForUser (g_AdministratorsGroupStr);
  526. if (!Sid) {
  527. return FALSE;
  528. }
  529. //
  530. // Start building security descriptor
  531. //
  532. InitializeSecurityDescriptor (&desc, SECURITY_DESCRIPTOR_REVISION);
  533. if (!SetSecurityDescriptorOwner (&desc, Sid, FALSE)) {
  534. LOG ((LOG_ERROR, "Could not set %s as owner", g_AdministratorsGroupStr));
  535. return FALSE;
  536. }
  537. //
  538. // Set the defaulted group to Domain\Domain Users (if it exists),
  539. // otherwise get SID of none
  540. //
  541. Sid = GetSidForUser (g_DomainUsersGroupStr);
  542. if (!Sid) {
  543. Sid = GetSidForUser (g_NoneGroupStr);
  544. }
  545. if (Sid) {
  546. SetSecurityDescriptorGroup (&desc, Sid, FALSE);
  547. }
  548. //
  549. // Create access allowed ACL from member list
  550. //
  551. Acl = CreateAclFromMemberList (AclMemberList, MemberCount);
  552. if (!Acl) {
  553. DEBUGMSG ((DBG_WARNING, "SetShareAcl failed because CreateAclFromMemberList failed"));
  554. return FALSE;
  555. }
  556. __try {
  557. UnicodeShare = (PWSTR) CreateUnicode (Share);
  558. MYASSERT (UnicodeShare);
  559. if (!SetSecurityDescriptorDacl (&desc, TRUE, Acl, FALSE)) {
  560. DEBUGMSG ((DBG_WARNING, "SetShareAcl failed because SetSecurityDescriptorDacl failed"));
  561. __leave;
  562. }
  563. //
  564. // Set security descriptor on share
  565. //
  566. Size = sizeof (Buf);
  567. if (!MakeSelfRelativeSD (&desc, pSD, &Size)) {
  568. LOG ((LOG_ERROR, "MakeSelfRelativeSD failed"));
  569. __leave;
  570. }
  571. ZeroMemory (&shi1501, sizeof (shi1501));
  572. shi1501.shi1501_security_descriptor = pSD;
  573. rc = MigNetShareSetInfo (NULL, UnicodeShare, 1501, (PBYTE) &shi1501, NULL);
  574. if (rc != ERROR_SUCCESS) {
  575. SetLastError (rc);
  576. LOG ((LOG_ERROR, "NetShareSetInfo failed"));
  577. __leave;
  578. }
  579. result = TRUE;
  580. }
  581. __finally {
  582. if (Acl) {
  583. FreeMemberListAcl (Acl);
  584. }
  585. DestroyUnicode (UnicodeShare);
  586. }
  587. return TRUE;
  588. }
  589. VOID
  590. DoCreateShares (
  591. VOID
  592. )
  593. /*++
  594. Routine Description:
  595. DoCreateShares enumerates all the shares registered in memdb by WINNT32.
  596. For each enumeration, a share is created, and permissions or an ACL is
  597. applied.
  598. Arguments:
  599. None.
  600. Return Value:
  601. None.
  602. --*/
  603. {
  604. MEMDB_ENUM e, e2;
  605. TCHAR Path[MEMDB_MAX];
  606. TCHAR Remark[MEMDB_MAX];
  607. // we overlap the Remark stack buffer instead of making another
  608. #define flagKey Remark
  609. TCHAR Password[MEMDB_MAX];
  610. DWORD Flags;
  611. DWORD Members;
  612. DWORD shareType;
  613. GROWBUFFER NameList = GROWBUF_INIT;
  614. PCTSTR pathNT;
  615. //
  616. // Obtain shares from memdb
  617. //
  618. if (MemDbEnumItems (&e, MEMDB_CATEGORY_NETSHARES)) {
  619. do {
  620. //
  621. // Get share attributes
  622. //
  623. Flags = e.dwValue;
  624. if (!MemDbGetEndpointValueEx (
  625. MEMDB_CATEGORY_NETSHARES,
  626. e.szName,
  627. MEMDB_FIELD_PATH,
  628. Path
  629. )) {
  630. DEBUGMSG ((DBG_WARNING, "DoCreateShares: No path found for %s", e.szName));
  631. continue;
  632. }
  633. // IF YOU CHANGE CODE HERE: Note that flagKey is the same variable as Remark
  634. MemDbBuildKey (flagKey, MEMDB_CATEGORY_NETSHARES, e.szName, MEMDB_FIELD_TYPE, NULL);
  635. if (!MemDbGetValue (flagKey, &shareType)) {
  636. DEBUGMSG ((DBG_WARNING, "DoCreateShares: No type found for %s", e.szName));
  637. continue;
  638. }
  639. // IF YOU CHANGE CODE HERE: Note that flagKey is the same variable as Remark
  640. if (!MemDbGetEndpointValueEx (
  641. MEMDB_CATEGORY_NETSHARES,
  642. e.szName,
  643. MEMDB_FIELD_REMARK,
  644. Remark
  645. )) {
  646. Remark[0] = 0;
  647. }
  648. //
  649. // first check if the path changed
  650. //
  651. pathNT = GetPathStringOnNt (Path);
  652. //
  653. // Create the share and set appropriate security
  654. //
  655. if (Flags & SHI50F_ACLS) {
  656. //
  657. // Share has an ACL
  658. //
  659. if (pCreateNetShare (e.szName, pathNT, Remark, shareType, W95_GENERIC_NONE)) {
  660. //
  661. // For each user indexed, put them in an ACL member list
  662. //
  663. Members = 0;
  664. if (MemDbGetValueEx (
  665. &e2,
  666. MEMDB_CATEGORY_NETSHARES,
  667. e.szName,
  668. MEMDB_FIELD_ACCESS_LIST
  669. )) {
  670. do {
  671. //
  672. // On Win9x, per-user flags have a 8 flags that control access. We translate
  673. // them to one of four flavors on NT:
  674. //
  675. // 1. Deny All Access: (Flags == 0)
  676. // 2. Read-Only Access: (Flags & W95_GENERIC_READ) && !(Flags & W95_GENERIC_WRITE)
  677. // 3. Change-Only Access: !(Flags & W95_GENERIC_READ) && (Flags & W95_GENERIC_WRITE)
  678. // 4. Full Access: (Flags & W95_GENERIC_FULL) == W95_GENERIC_FULL
  679. //
  680. DEBUGMSG ((DBG_NETSHARES, "Share %s user %s flags %u", e.szName, e2.szName, e2.dwValue));
  681. if (AddAclMember (
  682. &NameList,
  683. e2.szName,
  684. Simplify9xAccessFlags (e2.dwValue)
  685. )) {
  686. Members++;
  687. }
  688. } while (MemDbEnumNextValue (&e2));
  689. }
  690. //
  691. // Convert member list into a real ACL and apply it to the share
  692. //
  693. if (NameList.Buf) {
  694. SetShareAcl (e.szName, pathNT, NameList.Buf, Members);
  695. LogUsersWhoFailed (NameList.Buf, Members, e.szName, pathNT);
  696. FreeGrowBuffer (&NameList);
  697. }
  698. }
  699. }
  700. else {
  701. //
  702. // Determine if a password is set
  703. //
  704. Password[0] = 0;
  705. if (Flags & SHI50F_RDONLY) {
  706. MemDbGetEndpointValueEx (
  707. MEMDB_CATEGORY_NETSHARES,
  708. e.szName,
  709. MEMDB_FIELD_RO_PASSWORD,
  710. Password
  711. );
  712. }
  713. if (!Password[0] && (Flags & SHI50F_FULL)) {
  714. MemDbGetEndpointValueEx (
  715. MEMDB_CATEGORY_NETSHARES,
  716. e.szName,
  717. MEMDB_FIELD_RW_PASSWORD,
  718. Password
  719. );
  720. }
  721. //
  722. // Enable all permissions for full access
  723. // Enable read-only permissions for read-only shares
  724. // Disable all permissions for no access
  725. //
  726. if (!Password[0]) {
  727. if (Flags & SHI50F_FULL) {
  728. Flags = W95_GENERIC_FULL;
  729. } else if (Flags & SHI50F_RDONLY) {
  730. Flags = W95_GENERIC_READ;
  731. } else if (Flags) {
  732. DEBUGMSG ((DBG_WHOOPS, "Flags (0x%X) is not 0, SHI50F_FULL or SHI50F_RDONLY", Flags));
  733. Flags = W95_GENERIC_NONE;
  734. }
  735. } else {
  736. DEBUGMSG ((DBG_VERBOSE, "Password on share %s is not supported", e.szName));
  737. Flags = W95_GENERIC_NONE;
  738. }
  739. //
  740. // We do not support share-level security with passwords. We
  741. // always create the share, but if a password exists, we
  742. // deny everyone access.
  743. //
  744. pCreateNetShare (e.szName, pathNT, Remark, shareType, Flags);
  745. Members = 0;
  746. if (AddAclMember (
  747. &NameList,
  748. g_EveryoneStr,
  749. Simplify9xAccessFlags (Flags)
  750. )) {
  751. Members++;
  752. }
  753. //
  754. // Convert member list into a real ACL and apply it to the share
  755. //
  756. if (NameList.Buf) {
  757. SetShareAcl (e.szName, pathNT, NameList.Buf, Members);
  758. FreeGrowBuffer (&NameList);
  759. }
  760. }
  761. FreePathString (pathNT);
  762. } while (MemDbEnumNextValue (&e));
  763. }
  764. }
  765. BOOL
  766. pUpdateRecycleBin (
  767. VOID
  768. )
  769. /*++
  770. Routine Description:
  771. Calls SHUpdateRecycleBinIcon to reset the status of the recycle bin. This
  772. operation takes a few seconds as all hard drives are scanned, the recycle
  773. bin database is read, and each entry in the database is verified.
  774. Arguments:
  775. None
  776. Return value:
  777. TRUE - the operation was successful
  778. FALSE - the operation failed (either LoadLibrary or GetProcAddress)
  779. --*/
  780. {
  781. SHUPDATERECYCLEBINICON_PROC Fn;
  782. HINSTANCE LibInst;
  783. BOOL b = TRUE;
  784. LibInst = LoadSystemLibrary (S_SHELL32_DLL);
  785. if (!LibInst) {
  786. return FALSE;
  787. }
  788. Fn = (SHUPDATERECYCLEBINICON_PROC) GetProcAddress (
  789. LibInst,
  790. S_ANSI_SHUPDATERECYCLEBINICON
  791. );
  792. if (Fn) {
  793. //
  794. // Scan all hard disks and validate the recycle bin status
  795. //
  796. Fn();
  797. } else {
  798. b = FALSE;
  799. }
  800. FreeLibrary (LibInst);
  801. return TRUE;
  802. }
  803. VOID
  804. pFixLogonDomainIfUserIsAdministrator (
  805. VOID
  806. )
  807. /*++
  808. Routine Description:
  809. pFixLogonDomainIfUserIsAdministrator handles a special error case where
  810. the logon domain is not equivalent to the computer name, but the user
  811. is named Administrator. In this case, we change the default logon domain
  812. to be the computer name.
  813. Arguments:
  814. None
  815. Return value:
  816. none
  817. --*/
  818. {
  819. PCTSTR AdministratorAcct;
  820. HKEY Key;
  821. PCTSTR Data;
  822. AdministratorAcct = GetStringResource (MSG_ADMINISTRATOR_ACCOUNT);
  823. if (AdministratorAcct) {
  824. Key = OpenRegKeyStr (S_WINLOGON_KEY);
  825. if (Key) {
  826. Data = GetRegValueString (Key, S_DEFAULT_USER_NAME);
  827. if (Data) {
  828. if (!StringCompare (Data, AdministratorAcct)) {
  829. //
  830. // Account name exactly matches our Administrator
  831. // string, so there is a good chance we wrote
  832. // this string. Therefore, we need to write the
  833. // computer name as the default domain.
  834. //
  835. if (g_ComputerName[0]) {
  836. RegSetValueEx (
  837. Key,
  838. S_DEFAULT_DOMAIN_NAME,
  839. 0,
  840. REG_SZ,
  841. (PBYTE) g_ComputerName,
  842. SizeOfString (g_ComputerName)
  843. );
  844. }
  845. }
  846. MemFree (g_hHeap, 0, Data);
  847. }
  848. CloseRegKey (Key);
  849. }
  850. FreeStringResource (AdministratorAcct);
  851. }
  852. }
  853. DWORD
  854. ProcessLocalMachine_First (
  855. DWORD Request
  856. )
  857. {
  858. if (Request == REQUEST_QUERYTICKS) {
  859. return TICKS_INI_ACTIONS_FIRST +
  860. TICKS_INI_MOVE +
  861. TICKS_INI_CONVERSION +
  862. TICKS_INI_MIGRATION;
  863. }
  864. //
  865. // We process the local machine in the following order:
  866. //
  867. // Initialization:
  868. // (1) Reload memdb
  869. //
  870. // Ini files conversion and mapping
  871. //
  872. DEBUGMSG ((DBG_INIFILES, "INI Files Actions.First - START"));
  873. DEBUGLOGTIME (("Starting function: DoIniActions"));
  874. if (!DoIniActions (INIACT_WKS_FIRST)) {
  875. LOG ((LOG_ERROR, "Process Local Machine: Could not perform one or more INI Files Actions.First"));
  876. }
  877. DEBUGLOGTIME (("Function complete: DoIniActions"));
  878. TickProgressBarDelta (TICKS_INI_ACTIONS_FIRST);
  879. DEBUGMSG ((DBG_INIFILES, "INI Files Actions.First - STOP"));
  880. DEBUGMSG ((DBG_INIFILES, "INI file moving - START"));
  881. DEBUGLOGTIME (("Starting function: MoveIniSettings"));
  882. if (!MoveIniSettings ()) {
  883. LOG ((LOG_ERROR, "Process Local Machine: Could not move one or more .INI files settings."));
  884. return GetLastError();
  885. }
  886. DEBUGLOGTIME (("Function complete: MoveIniSettings"));
  887. TickProgressBarDelta (TICKS_INI_MOVE);
  888. DEBUGMSG ((DBG_INIFILES, "INI file moving - STOP"));
  889. DEBUGMSG ((DBG_INIFILES, "INI file conversion - START"));
  890. DEBUGLOGTIME (("Starting function: ConvertIniFiles"));
  891. if (!ConvertIniFiles ()) {
  892. LOG ((LOG_ERROR, "Process Local Machine: Could not convert one or more .INI files."));
  893. return GetLastError();
  894. }
  895. DEBUGLOGTIME (("Function complete: ConvertIniFiles"));
  896. TickProgressBarDelta (TICKS_INI_CONVERSION);
  897. DEBUGMSG ((DBG_INIFILES, "INI file conversion - STOP"));
  898. DEBUGMSG ((DBG_INIFILES, "INI file migration - START"));
  899. DEBUGLOGTIME (("Starting function: ProcessIniFileMapping"));
  900. if (!ProcessIniFileMapping (FALSE)) {
  901. LOG ((LOG_ERROR, "Process Local Machine: Could not migrate one or more .INI files."));
  902. return GetLastError();
  903. }
  904. DEBUGLOGTIME (("Function complete: ProcessIniFileMapping"));
  905. TickProgressBarDelta (TICKS_INI_MIGRATION);
  906. DEBUGMSG ((DBG_INIFILES, "INI file migration - STOP"));
  907. return ERROR_SUCCESS;
  908. }
  909. VOID
  910. pTurnOffNetAccountWizard (
  911. VOID
  912. )
  913. /*++
  914. Routine Description:
  915. pTurnOffNetAccountWizard removes the RunNetAccessWizard key to keep the
  916. network account wizard from appearing before the first logon.
  917. Arguments:
  918. None.
  919. Return Value:
  920. None.
  921. --*/
  922. {
  923. HKEY Key;
  924. Key = OpenRegKeyStr (TEXT("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"));
  925. if (Key) {
  926. RegDeleteValue (Key, TEXT("RunNetAccessWizard"));
  927. CloseRegKey (Key);
  928. } else {
  929. DEBUGMSG ((DBG_WARNING, "Could not open key for RunNetAccessWizard value"));
  930. }
  931. }
  932. typedef struct _OLE_CONTROL_DATA {
  933. LPWSTR FullPath;
  934. LPCWSTR RegType;
  935. } OLE_CONTROL_DATA, *POLE_CONTROL_DATA;
  936. DWORD
  937. RegisterIndividualOleControl(
  938. POLE_CONTROL_DATA OleControlData
  939. )
  940. {
  941. PROCESS_INFORMATION processInfo;
  942. STARTUPINFO startupInfo;
  943. WCHAR cmdLine [MAX_PATH] = L"";
  944. WCHAR cmdOptions [MAX_PATH] = L"";
  945. DWORD WaitResult;
  946. BOOL b = TRUE;
  947. ZeroMemory (&startupInfo, sizeof (STARTUPINFO));
  948. startupInfo.cb = sizeof (STARTUPINFO);
  949. if (OleControlData->RegType && (*OleControlData->RegType == L'B')) {
  950. // install and register
  951. wcscpy (cmdOptions, L"/s /i");
  952. } else if (OleControlData->RegType && (*OleControlData->RegType == L'R')) {
  953. // register
  954. wcscpy (cmdOptions, L"/s");
  955. } else if (OleControlData->RegType && (*OleControlData->RegType == L'I')) {
  956. // install
  957. wcscpy (cmdOptions, L"/s /i /n");
  958. } else if ((OleControlData->RegType == NULL) || (*OleControlData->RegType == L'\0')) {
  959. // register
  960. wcscpy (cmdOptions, L"/s");
  961. }
  962. wsprintf (cmdLine, L"%s\\regsvr32.exe %s %s", g_System32Dir, cmdOptions, OleControlData->FullPath);
  963. if (CreateProcess (NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &processInfo)) {
  964. WaitResult = WaitForSingleObject (processInfo.hProcess, 1000 * 60 * 10 );
  965. if (WaitResult == WAIT_TIMEOUT) {
  966. DEBUGMSG ((DBG_ERROR, "Timeout installing and/or registering OLE control %s", OleControlData->FullPath));
  967. b = FALSE;
  968. }
  969. CloseHandle (processInfo.hProcess);
  970. CloseHandle (processInfo.hThread);
  971. }
  972. else {
  973. DEBUGMSG ((DBG_ERROR, "Create process failed: %s", cmdLine));
  974. b = FALSE;
  975. }
  976. return b;
  977. }
  978. typedef struct _KNOWN_DIRS {
  979. PCWSTR DirId;
  980. PCWSTR Translation;
  981. }
  982. KNOWN_DIRSW, *PKNOWN_DIRSW;
  983. KNOWN_DIRSW g_KnownDirsW [] = {
  984. {L"10" , g_WinDir},
  985. {L"11" , g_System32Dir},
  986. {L"24" , g_WinDrive},
  987. {L"16422" , g_ProgramFiles},
  988. {L"16427" , g_ProgramFilesCommon},
  989. {NULL, NULL}
  990. };
  991. BOOL
  992. pConvertDirName (
  993. PCWSTR OldDirName,
  994. PWSTR NewDirName
  995. )
  996. {
  997. PCWSTR OldDirCurr = OldDirName;
  998. PCWSTR OldDirNext;
  999. PKNOWN_DIRSW p;
  1000. NewDirName[0] = 0;
  1001. OldDirNext = wcschr (OldDirCurr, L'\\');
  1002. if (OldDirNext == NULL) {
  1003. OldDirNext = wcschr (OldDirCurr, 0);
  1004. }
  1005. StringCopyABW (NewDirName, OldDirCurr, OldDirNext);
  1006. p = g_KnownDirsW;
  1007. while (p->DirId!= NULL) {
  1008. if (StringIMatchW (NewDirName, p->DirId)) {
  1009. StringCopyW (NewDirName, p->Translation);
  1010. break;
  1011. }
  1012. p++;
  1013. }
  1014. StringCatW (NewDirName, OldDirNext);
  1015. return TRUE;
  1016. }
  1017. BOOL
  1018. RegisterOleControls(
  1019. VOID
  1020. )
  1021. {
  1022. INFCONTEXT InfLine;
  1023. WCHAR DirId [MAX_PATH];
  1024. WCHAR SubDir [MAX_PATH];
  1025. WCHAR Filename [MAX_PATH];
  1026. WCHAR RegType [MAX_PATH];
  1027. WCHAR FullPathTemp[MAX_PATH];
  1028. WCHAR FullPath[MAX_PATH];
  1029. BOOL b;
  1030. DWORD d;
  1031. UINT Line;
  1032. WCHAR OldCD[MAX_PATH];
  1033. OLE_CONTROL_DATA OleControlData;
  1034. b = TRUE;
  1035. Line = 0;
  1036. //
  1037. // Preserve current directory just in case
  1038. //
  1039. d = GetCurrentDirectory(MAX_PATH,OldCD);
  1040. if(!d || (d >= MAX_PATH)) {
  1041. OldCD[0] = 0;
  1042. }
  1043. if(SetupFindFirstLine(g_WkstaMigInf, L"Win9xUpg_OleControls", NULL, &InfLine)) {
  1044. do {
  1045. Line++;
  1046. if (!SetupGetStringField (&InfLine, 1, DirId, MAX_PATH, NULL) ||
  1047. !SetupGetStringField (&InfLine, 2, SubDir, MAX_PATH, NULL) ||
  1048. !SetupGetStringField (&InfLine, 3, Filename, MAX_PATH, NULL) ||
  1049. !SetupGetStringField (&InfLine, 4, RegType, MAX_PATH, NULL)
  1050. ) {
  1051. DEBUGMSGW ((DBG_ERROR, "Bad line while registering controls %d", Line));
  1052. } else {
  1053. DEBUGMSG ((DBG_VERBOSE, "SETUP: filename for file to register is %s", Filename));
  1054. //
  1055. // Get full path to dll
  1056. //
  1057. if (pConvertDirName (DirId, FullPathTemp)) {
  1058. wcscpy (FullPath, FullPathTemp);
  1059. if (*SubDir) {
  1060. wcscat (FullPath, L"\\");
  1061. wcscat (FullPath, SubDir);
  1062. }
  1063. SetCurrentDirectory(FullPath);
  1064. wcscat (FullPath, L"\\");
  1065. wcscat (FullPath, Filename);
  1066. OleControlData.FullPath = FullPath;
  1067. OleControlData.RegType = RegType;
  1068. RegisterIndividualOleControl (&OleControlData);
  1069. } else {
  1070. DEBUGMSG ((DBG_ERROR, "SETUP: dll skipped, bad dirid %s", DirId));
  1071. b = FALSE;
  1072. }
  1073. }
  1074. } while(SetupFindNextLine(&InfLine,&InfLine));
  1075. }
  1076. if(OldCD[0]) {
  1077. SetCurrentDirectory(OldCD);
  1078. }
  1079. return(b);
  1080. }
  1081. DWORD
  1082. ProcessLocalMachine_Last (
  1083. DWORD Request
  1084. )
  1085. {
  1086. DWORD rc;
  1087. #ifdef VAR_PROGRESS_BAR
  1088. CHAR SystemDatPath[MAX_MBCHAR_PATH];
  1089. WIN32_FIND_DATAA fd;
  1090. HANDLE h;
  1091. DWORD SizeKB;
  1092. #endif
  1093. static LONG g_TicksHklm;
  1094. if (Request == REQUEST_QUERYTICKS) {
  1095. #ifdef VAR_PROGRESS_BAR
  1096. //
  1097. // estimate g_TicksHklm function of size of file system.dat
  1098. //
  1099. StringCopyA (SystemDatPath, g_SystemHiveDir);
  1100. StringCatA (SystemDatPath, "system.dat");
  1101. h = FindFirstFileA (SystemDatPath, &fd);
  1102. if (h != INVALID_HANDLE_VALUE) {
  1103. FindClose (h);
  1104. MYASSERT (!fd.nFileSizeHigh);
  1105. SizeKB = (fd.nFileSizeLow + 511) / 1024;
  1106. DEBUGLOGTIME (("ProcessLocalMachine_Last: system.dat size = %lu KB", SizeKB));
  1107. //
  1108. // statistics show that average time is 243 * (filesize in KB) - 372000
  1109. // I'll use 256 instead just to make sure the progress bar will not stop
  1110. // at the end looking like it's hanged
  1111. // The checked build is much slower (about 1.5 times)
  1112. //
  1113. #ifdef DEBUG
  1114. g_TicksHklm = SizeKB * 400;
  1115. #else
  1116. g_TicksHklm = SizeKB * 256;
  1117. #endif
  1118. } else {
  1119. //
  1120. // what's wrong here?
  1121. //
  1122. MYASSERT (FALSE);
  1123. g_TicksHklm = TICKS_HKLM;
  1124. }
  1125. #else // !defined VAR_PROGRESS_BAR
  1126. g_TicksHklm = TICKS_HKLM;
  1127. #endif
  1128. return TICKS_INI_MERGE +
  1129. g_TicksHklm +
  1130. TICKS_SHARES +
  1131. TICKS_LINK_EDIT +
  1132. TICKS_DOSMIG_SYS +
  1133. TICKS_UPDATERECYCLEBIN +
  1134. TICKS_STF +
  1135. TICKS_RAS +
  1136. TICKS_TAPI +
  1137. TICKS_MULTIMEDIA +
  1138. TICKS_INI_ACTIONS_LAST;
  1139. }
  1140. //
  1141. // We process the local machine in the following order:
  1142. //
  1143. // Initialization:
  1144. // (1) Reload memdb
  1145. //
  1146. // Local machine registry preparation:
  1147. //
  1148. // (1) Process wkstamig.inf
  1149. // (2) Merge Win95 registry with NT hive
  1150. //
  1151. // Process instructions written to memdb:
  1152. //
  1153. // (1) Create Win95 shares
  1154. // (2) Process LinkEdit section
  1155. //
  1156. //
  1157. // Load in default MemDb state, or at least delete everything if
  1158. // memdb.dat does not exist.
  1159. //
  1160. MemDbLoad (GetMemDbDat());
  1161. DEBUGMSG ((DBG_INIFILES, "INI file merge - START"));
  1162. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: MergeIniSettings"));
  1163. if (!MergeIniSettings ()) {
  1164. LOG ((LOG_ERROR, "Process Local Machine: Could not merge one or more .INI files."));
  1165. return GetLastError();
  1166. }
  1167. TickProgressBarDelta (TICKS_INI_MERGE);
  1168. DEBUGMSG ((DBG_INIFILES, "INI file merge - STOP"));
  1169. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: MergeIniSettings"));
  1170. //
  1171. // Process local machine migration rules
  1172. //
  1173. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: MergeRegistry"));
  1174. if (!MergeRegistry (S_WKSTAMIG_INF, NULL)) {
  1175. LOG ((LOG_ERROR, "Process Local Machine: MergeRegistry failed for wkstamig.inf"));
  1176. return GetLastError();
  1177. }
  1178. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: MergeRegistry"));
  1179. TickProgressBarDelta (g_TicksHklm);
  1180. //
  1181. // Process memdb nodes
  1182. //
  1183. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: DoCreateShares"));
  1184. DoCreateShares(); // we ignore all errors
  1185. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: DoCreateShares"));
  1186. TickProgressBarDelta (TICKS_SHARES);
  1187. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: DoLinkEdit"));
  1188. if (!DoLinkEdit()) {
  1189. LOG ((LOG_ERROR, "Process Local Machine: DoLinkEdit failed."));
  1190. return GetLastError();
  1191. }
  1192. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: DoLinkEdit"));
  1193. TickProgressBarDelta (TICKS_LINK_EDIT);
  1194. //
  1195. // Handle DOS system migration.
  1196. //
  1197. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: DosMigNt_System"));
  1198. __try {
  1199. if (DosMigNt_System() != EXIT_SUCCESS) {
  1200. LOG((LOG_ERROR, "Process Local Machine: DosMigNt_System failed."));
  1201. }
  1202. }
  1203. __except(TRUE) {
  1204. DEBUGMSG ((DBG_WHOOPS, "Exception in DosMigNt_System"));
  1205. }
  1206. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: DosMigNt_System"));
  1207. TickProgressBarDelta (TICKS_DOSMIG_SYS);
  1208. //
  1209. // Make the recycled bin the correct status
  1210. //
  1211. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: pUpdateRecycleBin"));
  1212. if (!pUpdateRecycleBin ()) {
  1213. LOG ((LOG_ERROR, "Process Local Machine: Could not update recycle bin."));
  1214. }
  1215. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: pUpdateRecycleBin"));
  1216. TickProgressBarDelta (TICKS_UPDATERECYCLEBIN);
  1217. //
  1218. // Migrate all .STF files (ACME Setup)
  1219. //
  1220. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: ProcessStfFiles"));
  1221. if (!ProcessStfFiles()) {
  1222. LOG ((LOG_ERROR, "Process Local Machine: Could not migrate one or more .STF files."));
  1223. }
  1224. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: ProcessStfFiles"));
  1225. TickProgressBarDelta (TICKS_STF);
  1226. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: Ras_MigrateSystem"));
  1227. if (!Ras_MigrateSystem()) {
  1228. LOG ((LOG_ERROR, "Ras MigrateSystem: Error migrating system."));
  1229. }
  1230. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: Ras_MigrateSystem"));
  1231. TickProgressBarDelta (TICKS_RAS);
  1232. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: Tapi_MigrateSystem"));
  1233. if (!Tapi_MigrateSystem()) {
  1234. LOG ((LOG_ERROR, "Tapi MigrateSystem: Error migrating system TAPI settings."));
  1235. }
  1236. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: Tapi_MigrateSystem"));
  1237. TickProgressBarDelta (TICKS_TAPI);
  1238. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: RestoreMMSettings_System"));
  1239. if (!RestoreMMSettings_System ()) {
  1240. LOG ((LOG_ERROR, "Process Local Machine: Could not restore multimedia settings."));
  1241. return GetLastError();
  1242. }
  1243. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: RestoreMMSettings_System"));
  1244. TickProgressBarDelta (TICKS_MULTIMEDIA);
  1245. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: DoIniActions.Last"));
  1246. DEBUGMSG ((DBG_INIFILES, "INI Files Actions.Last - START"));
  1247. if (!DoIniActions (INIACT_WKS_LAST)) {
  1248. LOG ((LOG_ERROR, "Process Local Machine: Could not perform one or more INI Files Actions.Last"));
  1249. }
  1250. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: DoIniActions.Last"));
  1251. TickProgressBarDelta (TICKS_INI_ACTIONS_LAST);
  1252. DEBUGMSG ((DBG_INIFILES, "INI Files Actions.Last - STOP"));
  1253. DEBUGLOGTIME (("ProcessLocalMachine_Last: Starting function: RegisterOleControls"));
  1254. RegisterOleControls ();
  1255. DEBUGLOGTIME (("ProcessLocalMachine_Last: Function complete: RegisterOleControls"));
  1256. //
  1257. // Blow away the Network Account Wizard (so fast it doesn't need ticks)
  1258. //
  1259. pTurnOffNetAccountWizard();
  1260. //
  1261. // Update security for Crypto group
  1262. //
  1263. rc = SetRegKeySecurity (
  1264. TEXT("HKLM\\Software\\Microsoft\\Cryptography\\MachineKeys"),
  1265. SF_EVERYONE_FULL,
  1266. NULL,
  1267. NULL,
  1268. TRUE
  1269. );
  1270. return ERROR_SUCCESS;
  1271. }
  1272. BOOL
  1273. pEnumWin9xHiveFileWorker (
  1274. IN OUT PHIVEFILE_ENUM EnumPtr
  1275. )
  1276. /*++
  1277. Routine Description:
  1278. pEnumWin9xHiveFileWorker parses wkstamig.inf to get the source path to a
  1279. Win9x registry hive, and it gets the destination of where the hive should
  1280. be migrated to. The source is tested, and if it doesn't exist, the
  1281. function returns FALSE.
  1282. Environment variables in both the source or dest are expanded before
  1283. this function returns success.
  1284. Arguments:
  1285. EnumPtr - Specifies partially completed enumeration structure (the
  1286. EnumPtr->is member must be valid). Receives the source and
  1287. destination of the hive to be migrated.
  1288. Return Value:
  1289. Returns TRUE if a hive needs to be transfered from EnumPtr->Source to
  1290. EnumPtr->Dest, otherwise FALSE.
  1291. --*/
  1292. {
  1293. PCTSTR Source;
  1294. PCTSTR Dest;
  1295. //
  1296. // Get the source and dest from the INF
  1297. //
  1298. Source = InfGetStringField (&EnumPtr->is, 0);
  1299. Dest = InfGetStringField (&EnumPtr->is, 1);
  1300. if (!Source || !Dest) {
  1301. DEBUGMSG ((DBG_WHOOPS, "wkstamig.inf HiveFilesToConvert is not correct"));
  1302. return FALSE;
  1303. }
  1304. //
  1305. // Expand the source and dest
  1306. //
  1307. if (EnumPtr->Source) {
  1308. FreeText (EnumPtr->Source);
  1309. }
  1310. EnumPtr->Source = ExpandEnvironmentText (Source);
  1311. if (EnumPtr->Dest) {
  1312. FreeText (EnumPtr->Dest);
  1313. }
  1314. EnumPtr->Dest = ExpandEnvironmentText (Dest);
  1315. //
  1316. // The source must exist
  1317. //
  1318. if (!DoesFileExist (EnumPtr->Source)) {
  1319. return FALSE;
  1320. }
  1321. return TRUE;
  1322. }
  1323. VOID
  1324. pAbortHiveFileEnum (
  1325. IN OUT PHIVEFILE_ENUM EnumPtr
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. pAbortHiveFileEnum cleans up the allocations from an active enumeration of
  1330. Win9x hive files. This routine must be called by the enum first/next when
  1331. the enumeration completes, or it must be called by the code using the
  1332. enumeration. It is safe to call this routine in both places.
  1333. Arguments:
  1334. EnumPtr - Specifies the enumeration that needs to be aborted or that has
  1335. completed successfully. Receives a zero'd struct.
  1336. Return Value:
  1337. None.
  1338. --*/
  1339. {
  1340. if (EnumPtr->Pool) {
  1341. PoolMemDestroyPool (EnumPtr->Pool);
  1342. }
  1343. if (EnumPtr->Source) {
  1344. FreeText (EnumPtr->Source);
  1345. }
  1346. if (EnumPtr->Dest) {
  1347. FreeText (EnumPtr->Dest);
  1348. }
  1349. ZeroMemory (EnumPtr, sizeof (HIVEFILE_ENUM));
  1350. }
  1351. BOOL
  1352. pEnumNextWin9xHiveFile (
  1353. IN OUT PHIVEFILE_ENUM EnumPtr
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. pEnumNextWin9xHiveFile continues the enumeration wksatmig.inf until either
  1358. a hive needing migration is found, or no more INF entries are left.
  1359. Arguments:
  1360. EnumPtr - Specifies an enumeration structure that was initialized by
  1361. pEnumFirstWin9xHiveFile. Receives the next hive file source &
  1362. dest enumeration if one is available.
  1363. Return Value:
  1364. TRUE if a Win9x hive file needs to be migrated (its source and dest
  1365. specified in EnumPtr). FALSE if no more hive files are to be processed.
  1366. --*/
  1367. {
  1368. do {
  1369. if (!InfFindNextLine (&EnumPtr->is)) {
  1370. pAbortHiveFileEnum (EnumPtr);
  1371. return FALSE;
  1372. }
  1373. } while (!pEnumWin9xHiveFileWorker (EnumPtr));
  1374. return TRUE;
  1375. }
  1376. BOOL
  1377. pEnumFirstWin9xHiveFile (
  1378. OUT PHIVEFILE_ENUM EnumPtr
  1379. )
  1380. /*++
  1381. Routine Description:
  1382. pEnumFirstWin9xHiveFile begins an enumeration of Win9x registry files that
  1383. need to be migrated either to the NT registry, or to an NT registry hive
  1384. file.
  1385. Arguments:
  1386. EnumPtr - Receives the source Win9x hive file and the destination (either a
  1387. file or a registry path).
  1388. Return Value:
  1389. TRUE if a Win9x hive file was found and needs to be migrated, FALSE if no
  1390. hive file migration is needed.
  1391. --*/
  1392. {
  1393. ZeroMemory (EnumPtr, sizeof (HIVEFILE_ENUM));
  1394. //
  1395. // Begin the enumeration of the Hive Files section of wkstamig.inf
  1396. //
  1397. EnumPtr->Pool = PoolMemInitNamedPool ("Hive File Enum");
  1398. InitInfStruct (&EnumPtr->is, NULL, EnumPtr->Pool);
  1399. if (!InfFindFirstLine (g_WkstaMigInf, S_WKSTAMIG_HIVE_FILES, NULL, &EnumPtr->is)) {
  1400. pAbortHiveFileEnum (EnumPtr);
  1401. return FALSE;
  1402. }
  1403. //
  1404. // Attempt to return the first hive
  1405. //
  1406. if (pEnumWin9xHiveFileWorker (EnumPtr)) {
  1407. return TRUE;
  1408. }
  1409. //
  1410. // Hive does not exist, continue enumeration
  1411. //
  1412. return pEnumNextWin9xHiveFile (EnumPtr);
  1413. }
  1414. BOOL
  1415. pTransferWin9xHiveToRegKey (
  1416. IN PCTSTR Win9xHive,
  1417. IN PCTSTR NtRootKey
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. pTransferWin9xHiveToRegKey maps in a Win9x hive file, enumerates all the
  1422. keys and values, and transfers them to the NT registry.
  1423. Arguments:
  1424. Win9xHive - Specifies the registry hive file (a Win9x hive)
  1425. NtRootKey - Specifies the path to the NT registry destination, such as
  1426. HKLM\foo.
  1427. Return Value:
  1428. TRUE if the hive file was transferred without an error, FALSE otherwise.
  1429. Use GetLastError to get the error code.
  1430. --*/
  1431. {
  1432. LONG rc;
  1433. HKEY DestKey;
  1434. BOOL b = FALSE;
  1435. REGTREE_ENUM e;
  1436. REGVALUE_ENUM e2;
  1437. PCTSTR SubKey;
  1438. HKEY DestSubKey;
  1439. BOOL EnumAbort = FALSE;
  1440. PBYTE DataBuf;
  1441. GROWBUFFER Data = GROWBUF_INIT;
  1442. DWORD Type;
  1443. DWORD Size;
  1444. BOOL CloseDestSubKey = FALSE;
  1445. //
  1446. // Map the hive into a temporary key
  1447. //
  1448. rc = Win95RegLoadKey (
  1449. HKEY_LOCAL_MACHINE,
  1450. S_HIVE_TEMP,
  1451. Win9xHive
  1452. );
  1453. if (rc != ERROR_SUCCESS) {
  1454. DEBUGMSG ((DBG_ERROR, "Can't load %s for transfer", Win9xHive));
  1455. return FALSE;
  1456. }
  1457. __try {
  1458. DestKey = CreateRegKeyStr (NtRootKey);
  1459. if (!DestKey) {
  1460. DEBUGMSG ((DBG_ERROR, "Can't create %s", NtRootKey));
  1461. __leave;
  1462. }
  1463. if (EnumFirstRegKeyInTree95 (&e, TEXT("HKLM\\") S_HIVE_TEMP)) {
  1464. EnumAbort = TRUE;
  1465. do {
  1466. //
  1467. // Create the NT destination; if SubKey is empty, then
  1468. // use the root key for the destination.
  1469. //
  1470. SubKey = (PCTSTR) ((PBYTE) e.FullKeyName + e.EnumBaseBytes);
  1471. if (*SubKey) {
  1472. DestSubKey = CreateRegKey (DestKey, SubKey);
  1473. if (!DestSubKey) {
  1474. DEBUGMSG ((DBG_ERROR, "Can't create subkey %s", SubKey));
  1475. __leave;
  1476. }
  1477. CloseDestSubKey = TRUE;
  1478. } else {
  1479. DestSubKey = DestKey;
  1480. }
  1481. //
  1482. // Copy all values in 9x key to NT
  1483. //
  1484. if (EnumFirstRegValue95 (&e2, e.CurrentKey->KeyHandle)) {
  1485. do {
  1486. Data.End = 0;
  1487. DataBuf = GrowBuffer (&Data, e2.DataSize);
  1488. if (!DataBuf) {
  1489. DEBUGMSG ((DBG_ERROR, "Data size is too big: %s", e2.DataSize));
  1490. __leave;
  1491. }
  1492. Size = e2.DataSize;
  1493. rc = Win95RegQueryValueEx (
  1494. e2.KeyHandle,
  1495. e2.ValueName,
  1496. NULL,
  1497. &Type,
  1498. DataBuf,
  1499. &Size
  1500. );
  1501. if (rc != ERROR_SUCCESS) {
  1502. DEBUGMSG ((
  1503. DBG_ERROR,
  1504. "Can't read enumerated value:\n"
  1505. " %s\n"
  1506. " %s [%s]",
  1507. Win9xHive,
  1508. e.FullKeyName,
  1509. e2.ValueName
  1510. ));
  1511. __leave;
  1512. }
  1513. MYASSERT (Size == e2.DataSize);
  1514. rc = RegSetValueEx (
  1515. DestSubKey,
  1516. e2.ValueName,
  1517. 0,
  1518. e2.Type,
  1519. DataBuf,
  1520. Size
  1521. );
  1522. if (rc != ERROR_SUCCESS) {
  1523. DEBUGMSG ((
  1524. DBG_ERROR,
  1525. "Can't write enumerated value:\n"
  1526. " %s\n"
  1527. " %s\\%s [%s]",
  1528. Win9xHive,
  1529. NtRootKey,
  1530. SubKey,
  1531. e2.ValueName
  1532. ));
  1533. __leave;
  1534. }
  1535. } while (EnumNextRegValue95 (&e2));
  1536. }
  1537. if (CloseDestSubKey) {
  1538. CloseRegKey (DestSubKey);
  1539. CloseDestSubKey = FALSE;
  1540. }
  1541. } while (EnumNextRegKeyInTree95 (&e));
  1542. EnumAbort = FALSE;
  1543. }
  1544. ELSE_DEBUGMSG ((DBG_WARNING, "%s is empty", Win9xHive));
  1545. b = TRUE;
  1546. }
  1547. __finally {
  1548. PushError();
  1549. if (CloseDestSubKey) {
  1550. CloseRegKey (DestSubKey);
  1551. }
  1552. if (EnumAbort) {
  1553. AbortRegKeyTreeEnum95 (&e);
  1554. }
  1555. Win95RegUnLoadKey (HKEY_LOCAL_MACHINE, TEXT("$$$"));
  1556. if (DestKey) {
  1557. CloseRegKey (DestKey);
  1558. }
  1559. FreeGrowBuffer (&Data);
  1560. PopError();
  1561. }
  1562. return b;
  1563. }
  1564. BOOL
  1565. pTransferWin9xHive (
  1566. IN PCTSTR Win9xHive,
  1567. IN PCTSTR Destination
  1568. )
  1569. /*++
  1570. Routine Description:
  1571. pTransferWin9xHive transfers a Win9x registry hive file (foo.dat) to either
  1572. an NT registry file, or a key in the NT registry. The source and
  1573. destination can be the same file.
  1574. Arguments:
  1575. Win9xHive - Specifies the registry hive file path (a Win9x hive file).
  1576. Destination - Specifies either a path or NT registry location where the
  1577. Win9xHive should be transfered to.
  1578. Return Value:
  1579. TRUE if the hive was transfered, FALSE otherwise. Call GetLastError for an
  1580. error code.
  1581. --*/
  1582. {
  1583. PCTSTR DestHive;
  1584. BOOL ToHiveFile;
  1585. HKEY Key;
  1586. LONG rc;
  1587. //
  1588. // Determine if destination is a hive file or a reg location
  1589. //
  1590. if (_istalpha (Destination[0]) && Destination[1] == TEXT(':')) {
  1591. ToHiveFile = TRUE;
  1592. DestHive = TEXT("HKLM\\") S_TRANSFER_HIVE;
  1593. } else {
  1594. ToHiveFile = FALSE;
  1595. DestHive = Destination;
  1596. }
  1597. //
  1598. // Blast the Win9x hive data to the temp location
  1599. //
  1600. if (!pTransferWin9xHiveToRegKey (Win9xHive, DestHive)) {
  1601. RegDeleteKey (HKEY_LOCAL_MACHINE, S_TRANSFER_HIVE);
  1602. return FALSE;
  1603. }
  1604. //
  1605. // Save the key if the destination is a hive file
  1606. //
  1607. if (ToHiveFile) {
  1608. Key = OpenRegKeyStr (DestHive);
  1609. if (!Key) {
  1610. DEBUGMSG ((DBG_ERROR, "Transfer hive key %s does not exist", DestHive));
  1611. return FALSE;
  1612. }
  1613. rc = RegSaveKey (Key, Destination, NULL);
  1614. CloseRegKey (Key);
  1615. RegDeleteKey (HKEY_LOCAL_MACHINE, S_TRANSFER_HIVE);
  1616. if (rc != ERROR_SUCCESS) {
  1617. DEBUGMSG ((DBG_ERROR, "Win9x hive %s could not be saved to %s", Win9xHive, Destination));
  1618. return FALSE;
  1619. }
  1620. }
  1621. //
  1622. // Delete the source file if the destination is not the same
  1623. //
  1624. if (!ToHiveFile || !StringIMatch (Win9xHive, DestHive)) {
  1625. //
  1626. // By adding info to memdb, we must enforce a rule that
  1627. // memdb cannot be reloaded. Otherwise we lose our
  1628. // changes.
  1629. //
  1630. DeclareTemporaryFile (Win9xHive);
  1631. #ifdef DEBUG
  1632. g_NoReloadsAllowed = TRUE;
  1633. #endif
  1634. }
  1635. return TRUE;
  1636. }
  1637. DWORD
  1638. ConvertHiveFiles (
  1639. DWORD Request
  1640. )
  1641. /*++
  1642. Routine Description:
  1643. ConvertHiveFiles enumerates all the hive files on the system that need
  1644. conversion, and calls pTransferWin9xHive to migrate them to the destination
  1645. specified in wkstamig.inf.
  1646. Arguments:
  1647. Request - Specifies the progress bar-driven request.
  1648. Return Value:
  1649. If Request is REQUEST_QUERYTICKS, the return value is the number of ticks
  1650. this routine is expected to take. Otherwise, the return value is
  1651. ERROR_SUCCESS.
  1652. --*/
  1653. {
  1654. HIVEFILE_ENUM e;
  1655. switch (Request) {
  1656. case REQUEST_QUERYTICKS:
  1657. return TICKS_HIVE_CONVERSION;
  1658. case REQUEST_RUN:
  1659. //
  1660. // Enumerate all the hives that need to be processed
  1661. //
  1662. if (pEnumFirstWin9xHiveFile (&e)) {
  1663. do {
  1664. pTransferWin9xHive (e.Source, e.Dest);
  1665. } while (pEnumNextWin9xHiveFile (&e));
  1666. }
  1667. ELSE_DEBUGMSG ((DBG_NAUSEA, "ConvertHiveFiles: Nothing to do"));
  1668. break;
  1669. default:
  1670. break;
  1671. }
  1672. return ERROR_SUCCESS;
  1673. }
  1674. BOOL
  1675. pRegisterAtmFont (
  1676. IN PCTSTR PfmFile,
  1677. IN PCTSTR PfbFile,
  1678. IN PCTSTR MmmFile OPTIONAL
  1679. )
  1680. /*++
  1681. Routine Description:
  1682. pRegisterAtmFont calls the AtmFontExW API to register an Adobe PS font.
  1683. Arguments:
  1684. PfmFile - Specifies the path to the PFM file (the font metrics)
  1685. PfbFile - Specifies the path to the PFB file (the font bits)
  1686. MmmFile - Specifies the path to the MMM file (the new style metrics file)
  1687. Return Value:
  1688. TRUE if the font was registered, FALSE otherwise.
  1689. --*/
  1690. {
  1691. WORD StyleAndType = 0x2000;
  1692. INT Result;
  1693. if (AtmAddFontEx == NULL) {
  1694. return FALSE;
  1695. }
  1696. Result = AtmAddFontEx (
  1697. NULL,
  1698. &StyleAndType,
  1699. PfmFile,
  1700. PfbFile,
  1701. MmmFile
  1702. );
  1703. DEBUGMSG_IF ((
  1704. Result != ERROR_SUCCESS,
  1705. Result == - 1 ? DBG_WARNING : DBG_ERROR,
  1706. "Font not added, result = %i.\n"
  1707. " PFM: %s\n"
  1708. " PFB: %s\n"
  1709. " MMM: %s\n",
  1710. Result,
  1711. PfmFile,
  1712. PfbFile,
  1713. MmmFile
  1714. ));
  1715. return Result == ERROR_SUCCESS;
  1716. }
  1717. PCTSTR
  1718. pGetAtmMultiSz (
  1719. POOLHANDLE Pool,
  1720. PCTSTR InfName,
  1721. PCTSTR SectionName,
  1722. PCTSTR KeyName
  1723. )
  1724. /*++
  1725. Routine Description:
  1726. pGetAtmMultiSz returns a multi-sz of the ATM font file names in the order
  1727. of PFM, PFB and MMM. Profile APIs are used because the key names have
  1728. commas, and they are unquoted.
  1729. Arguments:
  1730. Pool - Specifies the pool where the multi-sz will allocate buffer
  1731. space from.
  1732. InfName - Specifies the full path to the INF, to be used with the
  1733. profile APIs.
  1734. SectionName - Specifies the section name in InfName that is being processed.
  1735. KeyName - Specifies the key name to process
  1736. Return Value:
  1737. A pointer to a multi-sz allocated in the specified pool.
  1738. --*/
  1739. {
  1740. PTSTR MultiSz;
  1741. PTSTR d;
  1742. TCHAR FileBuf[MAX_TCHAR_PATH * 2];
  1743. UINT Bytes;
  1744. GetPrivateProfileString (
  1745. SectionName,
  1746. KeyName,
  1747. TEXT(""),
  1748. FileBuf,
  1749. sizeof (FileBuf) / sizeof (FileBuf[0]),
  1750. InfName
  1751. );
  1752. //
  1753. // Turn all commas into nuls
  1754. //
  1755. d = FileBuf;
  1756. while (*d) {
  1757. if (_tcsnextc (d) == TEXT(',')) {
  1758. *d = 0;
  1759. }
  1760. d = _tcsinc (d);
  1761. }
  1762. //
  1763. // Terminate the multi-sz
  1764. //
  1765. d++;
  1766. *d = 0;
  1767. d++;
  1768. //
  1769. // Transfer to a pool-based allocation and return it
  1770. //
  1771. Bytes = (UINT) ((PBYTE) d - (PBYTE) FileBuf);
  1772. MultiSz = (PTSTR) PoolMemGetAlignedMemory (Pool, Bytes);
  1773. CopyMemory (MultiSz, FileBuf, Bytes);
  1774. return MultiSz;
  1775. }
  1776. BOOL
  1777. pEnumAtmFontWorker (
  1778. IN OUT PATM_FONT_ENUM EnumPtr
  1779. )
  1780. /*++
  1781. Routine Description:
  1782. pEnumAtmFontWorker implements the logic of parsing ATM.INI to get the Adobe
  1783. font names. This routine completes an enumeration started by
  1784. pEnumFirstAtmFont or pEnumNextAtmFont.
  1785. Arguments:
  1786. EnumPtr - Specifies a partially completed enumeration structure, receives a
  1787. fully completed structure.
  1788. Return Value:
  1789. TRUE if an ATM font was enumerated, FALSE otherwise.
  1790. --*/
  1791. {
  1792. PTSTR p;
  1793. PCTSTR MultiSz;
  1794. BOOL MetricFileExists;
  1795. //
  1796. // Get PFM, PFB and MMM files
  1797. //
  1798. MultiSz = pGetAtmMultiSz (
  1799. EnumPtr->Pool,
  1800. EnumPtr->InfName,
  1801. S_FONTS,
  1802. EnumPtr->KeyNames
  1803. );
  1804. if (!MultiSz) {
  1805. return FALSE;
  1806. }
  1807. if (*MultiSz) {
  1808. _tcssafecpy (EnumPtr->PfmFile, MultiSz, MAX_TCHAR_PATH);
  1809. MultiSz = GetEndOfString (MultiSz) + 1;
  1810. }
  1811. if (*MultiSz) {
  1812. _tcssafecpy (EnumPtr->PfbFile, MultiSz, MAX_TCHAR_PATH);
  1813. } else {
  1814. return FALSE;
  1815. }
  1816. MultiSz = pGetAtmMultiSz (
  1817. EnumPtr->Pool,
  1818. EnumPtr->InfName,
  1819. S_MMFONTS,
  1820. EnumPtr->KeyNames
  1821. );
  1822. if (MultiSz) {
  1823. _tcssafecpy (EnumPtr->MmmFile, MultiSz, MAX_TCHAR_PATH);
  1824. MultiSz = GetEndOfString (MultiSz) + 1;
  1825. if (*MultiSz) {
  1826. DEBUGMSG_IF ((
  1827. !StringIMatch (MultiSz, EnumPtr->PfbFile),
  1828. DBG_ERROR,
  1829. "ATM.INI: MMFonts and Fonts specify two different PFBs: %s and %s",
  1830. MultiSz,
  1831. EnumPtr->PfbFile
  1832. ));
  1833. }
  1834. } else {
  1835. EnumPtr->MmmFile[0] = 0;
  1836. }
  1837. //
  1838. // Special case: .MMM is listed in [Fonts]
  1839. //
  1840. p = _tcsrchr (EnumPtr->PfmFile, TEXT('.'));
  1841. if (p && p < _tcschr (p, TEXT('\\'))) {
  1842. p = NULL;
  1843. }
  1844. if (p && StringIMatch (p, TEXT(".mmm"))) {
  1845. EnumPtr->PfmFile[0] = 0;
  1846. }
  1847. //
  1848. // Special case: .MMM exists but is not listed in atm.ini
  1849. //
  1850. if (!EnumPtr->MmmFile[0]) {
  1851. StringCopy (EnumPtr->MmmFile, EnumPtr->PfmFile);
  1852. p = _tcsrchr (EnumPtr->MmmFile, TEXT('.'));
  1853. if (p && p < _tcschr (p, TEXT('\\'))) {
  1854. p = NULL;
  1855. }
  1856. if (p) {
  1857. StringCopy (p, TEXT(".mmm"));
  1858. if (!DoesFileExist (EnumPtr->MmmFile)) {
  1859. EnumPtr->MmmFile[0] = 0;
  1860. }
  1861. } else {
  1862. EnumPtr->MmmFile[0] = 0;
  1863. }
  1864. }
  1865. //
  1866. // Verify all files exist
  1867. //
  1868. MetricFileExists = FALSE;
  1869. if (EnumPtr->PfmFile[0] && DoesFileExist (EnumPtr->PfmFile)) {
  1870. MetricFileExists = TRUE;
  1871. }
  1872. if (EnumPtr->MmmFile[0] && DoesFileExist (EnumPtr->MmmFile)) {
  1873. MetricFileExists = TRUE;
  1874. }
  1875. if (!DoesFileExist (EnumPtr->PfbFile) || !MetricFileExists) {
  1876. DEBUGMSG ((
  1877. DBG_VERBOSE,
  1878. "At least one file is missing: %s, %s or %s",
  1879. EnumPtr->PfmFile[0] ? EnumPtr->PfmFile : TEXT("(no PFM specified)"),
  1880. EnumPtr->MmmFile[0] ? EnumPtr->MmmFile : TEXT("(no MMM specified)"),
  1881. EnumPtr->PfbFile
  1882. ));
  1883. return FALSE;
  1884. }
  1885. return TRUE;
  1886. }
  1887. VOID
  1888. pAbortAtmFontEnum (
  1889. IN OUT PATM_FONT_ENUM EnumPtr
  1890. )
  1891. /*++
  1892. Routine Description:
  1893. pAbortAtmFontEnum cleans up an enumeration structure after enumeration
  1894. completes or if enumeration needs to be aborted. This routine can safely be
  1895. called multiple times on the same structure.
  1896. Arguments:
  1897. EnumPtr - Specifies an initialized and possibly used enumeration structure.
  1898. Return Value:
  1899. None.
  1900. --*/
  1901. {
  1902. if (EnumPtr->Pool) {
  1903. PoolMemDestroyPool (EnumPtr->Pool);
  1904. }
  1905. ZeroMemory (EnumPtr, sizeof (ATM_FONT_ENUM));
  1906. }
  1907. BOOL
  1908. pEnumNextAtmFont (
  1909. IN OUT PATM_FONT_ENUM EnumPtr
  1910. )
  1911. /*++
  1912. Routine Description:
  1913. pEnumNextAtmFont continues enumeration, returning either another set of ATM
  1914. font paths, or FALSE.
  1915. Arguments:
  1916. EnumPtr - Specifies the enumeration structure started by pEnumNextAtmFont.
  1917. Return Value:
  1918. TRUE if another set of font paths is available, FALSE otherwise.
  1919. --*/
  1920. {
  1921. if (!EnumPtr->KeyNames || !(*EnumPtr->KeyNames)) {
  1922. pAbortAtmFontEnum (EnumPtr);
  1923. return FALSE;
  1924. }
  1925. //
  1926. // Continue enumeration, looping until a font path set was found,
  1927. // or there are no more atm.ini lines to enumerate.
  1928. //
  1929. do {
  1930. EnumPtr->KeyNames = GetEndOfString (EnumPtr->KeyNames) + 1;
  1931. if (!(*EnumPtr->KeyNames)) {
  1932. pAbortAtmFontEnum (EnumPtr);
  1933. return FALSE;
  1934. }
  1935. } while (!pEnumAtmFontWorker (EnumPtr));
  1936. return TRUE;
  1937. }
  1938. BOOL
  1939. pEnumFirstAtmFont (
  1940. OUT PATM_FONT_ENUM EnumPtr
  1941. )
  1942. /*++
  1943. Routine Description:
  1944. pEnumFirstAtmFont begins the enumeration of font path sets in ATM.INI.
  1945. Arguments:
  1946. EnumPtr - Receivies the first set of font paths found (if any).
  1947. Return Value:
  1948. TRUE if a font path set was found, FALSE otherwise.
  1949. --*/
  1950. {
  1951. TCHAR AtmIni[MAX_TCHAR_PATH];
  1952. PTSTR FilePart;
  1953. PTSTR KeyNames;
  1954. UINT Bytes;
  1955. //
  1956. // Init structure
  1957. //
  1958. ZeroMemory (EnumPtr, sizeof (ATM_FONT_ENUM));
  1959. //
  1960. // Find full path to atm.ini (usually in %windir%)
  1961. //
  1962. if (!SearchPath (NULL, TEXT("atm.ini"), NULL, MAX_TCHAR_PATH, AtmIni, &FilePart)) {
  1963. DEBUGMSG ((DBG_VERBOSE, "ATM.INI not found in search path"));
  1964. return FALSE;
  1965. }
  1966. StringCopy (EnumPtr->InfName, AtmIni);
  1967. //
  1968. // Establish processing pool and get all key names in [Fonts]
  1969. //
  1970. EnumPtr->Pool = PoolMemInitNamedPool ("ATM Font Enum");
  1971. MYASSERT (EnumPtr->Pool);
  1972. KeyNames = MemAlloc (g_hHeap, 0, MAX_KEY_NAME_LIST);
  1973. GetPrivateProfileString (
  1974. S_FONTS,
  1975. NULL,
  1976. TEXT(""),
  1977. KeyNames,
  1978. MAX_KEY_NAME_LIST,
  1979. AtmIni
  1980. );
  1981. Bytes = SizeOfMultiSz (KeyNames);
  1982. EnumPtr->KeyNames = (PTSTR) PoolMemGetAlignedMemory (EnumPtr->Pool, Bytes);
  1983. CopyMemory (EnumPtr->KeyNames, KeyNames, Bytes);
  1984. MemFree (g_hHeap, 0, KeyNames);
  1985. //
  1986. // Begin enumeration
  1987. //
  1988. if (!(*EnumPtr->KeyNames)) {
  1989. pAbortAtmFontEnum (EnumPtr);
  1990. return FALSE;
  1991. }
  1992. if (pEnumAtmFontWorker (EnumPtr)) {
  1993. return TRUE;
  1994. }
  1995. return pEnumNextAtmFont (EnumPtr);
  1996. }
  1997. DWORD
  1998. MigrateAtmFonts (
  1999. DWORD Request
  2000. )
  2001. /*++
  2002. Routine Description:
  2003. MigrateAtmFonts is called by the progress bar to query ticks or to migrate
  2004. ATM fonts.
  2005. Arguments:
  2006. Request - Specifies the reason the progress bar is calling the routine.
  2007. Return Value:
  2008. If Request is REQUEST_QUERYTICKS, then the return value is the number of
  2009. estimated ticks needed to complete processing. Otherwise the return value
  2010. is ERROR_SUCCESS.
  2011. --*/
  2012. {
  2013. ATM_FONT_ENUM e;
  2014. static HANDLE AtmLib;
  2015. TCHAR AtmIniPath[MAX_TCHAR_PATH];
  2016. if (Request == REQUEST_QUERYTICKS) {
  2017. //
  2018. // Dynamically load atmlib.dll
  2019. //
  2020. AtmAddFontEx = NULL;
  2021. AtmLib = LoadSystemLibrary (TEXT("atmlib.dll"));
  2022. if (!AtmLib) {
  2023. DEBUGMSG ((DBG_ERROR, "Cannot load entry point from atmlib.dll!"));
  2024. } else {
  2025. (FARPROC) AtmAddFontEx = GetProcAddress (AtmLib, "ATMAddFontExW");
  2026. DEBUGMSG_IF ((!AtmAddFontEx, DBG_ERROR, "Cannot get entry point ATMAddFontExW in atmlib.dll!"));
  2027. }
  2028. return AtmAddFontEx ? TICKS_ATM_MIGRATION : 0;
  2029. } else if (Request != REQUEST_RUN) {
  2030. return ERROR_SUCCESS;
  2031. }
  2032. if (AtmAddFontEx) {
  2033. //
  2034. // Do the ATM font migration
  2035. //
  2036. if (pEnumFirstAtmFont (&e)) {
  2037. StringCopy (AtmIniPath, e.InfName);
  2038. do {
  2039. if (pRegisterAtmFont (e.PfmFile, e.PfbFile, e.MmmFile)) {
  2040. DEBUGMSG ((DBG_VERBOSE, "ATM font registered %s", e.PfbFile));
  2041. }
  2042. } while (pEnumNextAtmFont (&e));
  2043. DeclareTemporaryFile (AtmIniPath);
  2044. #ifdef DEBUG
  2045. g_NoReloadsAllowed = TRUE;
  2046. #endif
  2047. }
  2048. //
  2049. // Clean up use of atmlib.dll - we're finished
  2050. //
  2051. FreeLibrary (AtmLib);
  2052. AtmLib = NULL;
  2053. AtmAddFontEx = NULL;
  2054. }
  2055. return ERROR_SUCCESS;
  2056. }
  2057. DWORD
  2058. RunSystemExternalProcesses (
  2059. IN DWORD Request
  2060. )
  2061. {
  2062. LONG Count;
  2063. if (Request == REQUEST_QUERYTICKS) {
  2064. //
  2065. // Count the number of entries and multiply by a constant
  2066. //
  2067. Count = SetupGetLineCount (g_WkstaMigInf, S_EXTERNAL_PROCESSES);
  2068. #ifdef PROGRESS_BAR
  2069. DEBUGLOGTIME (("RunSystemExternalProcesses: ExternalProcesses=%ld", Count));
  2070. #endif
  2071. if (Count < 1) {
  2072. return 0;
  2073. }
  2074. return Count * TICKS_SYSTEM_EXTERN_PROCESSES;
  2075. }
  2076. if (Request != REQUEST_RUN) {
  2077. return ERROR_SUCCESS;
  2078. }
  2079. //
  2080. // Loop through the processes and run each of them
  2081. //
  2082. RunExternalProcesses (g_WkstaMigInf, NULL);
  2083. return ERROR_SUCCESS;
  2084. }
  2085. BOOL
  2086. pEnumFirstWin9xBriefcase (
  2087. OUT PBRIEFCASE_ENUM e
  2088. )
  2089. {
  2090. if (!MemDbGetValueEx (&e->mde, MEMDB_CATEGORY_BRIEFCASES, NULL, NULL)) {
  2091. return FALSE;
  2092. }
  2093. e->BrfcaseDb = e->mde.szName;
  2094. return TRUE;
  2095. }
  2096. BOOL
  2097. pEnumNextWin9xBriefcase (
  2098. IN OUT PBRIEFCASE_ENUM e
  2099. )
  2100. {
  2101. if (!MemDbEnumNextValue (&e->mde)) {
  2102. return FALSE;
  2103. }
  2104. e->BrfcaseDb = e->mde.szName;
  2105. return TRUE;
  2106. }
  2107. BOOL
  2108. pMigrateBriefcase (
  2109. IN PCTSTR BriefcaseDatabase,
  2110. IN PCTSTR BriefcaseDir
  2111. )
  2112. {
  2113. HBRFCASE hbrfcase;
  2114. PTSTR NtPath;
  2115. BOOL Save, Success;
  2116. TWINRESULT tr;
  2117. BRFPATH_ENUM e;
  2118. BOOL Result = TRUE;
  2119. __try {
  2120. g_BrfcasePool = PoolMemInitNamedPool ("Briefcase");
  2121. if (!g_BrfcasePool) {
  2122. Result = FALSE;
  2123. __leave;
  2124. }
  2125. tr = OpenBriefcase (BriefcaseDatabase, OB_FL_OPEN_DATABASE, NULL, &hbrfcase);
  2126. if (tr == TR_SUCCESS) {
  2127. if (EnumFirstBrfcasePath (hbrfcase, &e)) {
  2128. Save = FALSE;
  2129. Success = TRUE;
  2130. do {
  2131. if (StringIMatch (BriefcaseDir, e.PathString)) {
  2132. //
  2133. // ignore this path
  2134. //
  2135. continue;
  2136. }
  2137. NtPath = GetPathStringOnNt (e.PathString);
  2138. MYASSERT (NtPath);
  2139. if (!StringIMatch (NtPath, e.PathString)) {
  2140. //
  2141. // try to replace Win9x path with NT path
  2142. //
  2143. if (!ReplaceBrfcasePath (&e, NtPath)) {
  2144. Success = FALSE;
  2145. break;
  2146. }
  2147. Save = TRUE;
  2148. }
  2149. FreePathString (NtPath);
  2150. } while (EnumNextBrfcasePath (&e));
  2151. if (!Success || Save && SaveBriefcase (hbrfcase) != TR_SUCCESS) {
  2152. Result = FALSE;
  2153. }
  2154. }
  2155. CloseBriefcase(hbrfcase);
  2156. }
  2157. }
  2158. __finally {
  2159. PoolMemDestroyPool (g_BrfcasePool);
  2160. g_BrfcasePool = NULL;
  2161. }
  2162. return Result;
  2163. }
  2164. DWORD
  2165. MigrateBriefcases (
  2166. DWORD Request
  2167. )
  2168. /*++
  2169. Routine Description:
  2170. MigrateBriefcases is called by the progress bar to query ticks or to migrate
  2171. briefcases.
  2172. Arguments:
  2173. Request - Specifies the reason the progress bar is calling the routine.
  2174. Return Value:
  2175. If Request is REQUEST_QUERYTICKS, then the return value is the number of
  2176. estimated ticks needed to complete processing. Otherwise the return value
  2177. is ERROR_SUCCESS.
  2178. --*/
  2179. {
  2180. BRIEFCASE_ENUM e;
  2181. TCHAR BrfcaseDir[MAX_PATH + 2];
  2182. PTSTR p;
  2183. PTSTR BrfcaseDbOnNt;
  2184. switch (Request) {
  2185. case REQUEST_QUERYTICKS:
  2186. return TICKS_MIGRATE_BRIEFCASES;
  2187. case REQUEST_RUN:
  2188. //
  2189. // Enumerate all the briefcases that need to be processed
  2190. //
  2191. if (pEnumFirstWin9xBriefcase (&e)) {
  2192. do {
  2193. BrfcaseDbOnNt = GetPathStringOnNt (e.BrfcaseDb);
  2194. MYASSERT (BrfcaseDbOnNt);
  2195. //
  2196. // get directory name first
  2197. //
  2198. if (TcharCount (BrfcaseDbOnNt) < MAX_PATH) {
  2199. StringCopy (BrfcaseDir, BrfcaseDbOnNt);
  2200. p = _tcsrchr (BrfcaseDir, TEXT('\\'));
  2201. if (p) {
  2202. *p = 0;
  2203. if (!pMigrateBriefcase (BrfcaseDbOnNt, BrfcaseDir)) {
  2204. LOG ((
  2205. LOG_WARNING,
  2206. (PCSTR)MSG_ERROR_MIGRATING_BRIEFCASE,
  2207. BrfcaseDir
  2208. ));
  2209. }
  2210. }
  2211. }
  2212. FreePathString (BrfcaseDbOnNt);
  2213. } while (pEnumNextWin9xBriefcase (&e));
  2214. }
  2215. ELSE_DEBUGMSG ((DBG_NAUSEA, "MigrateBriefcases: Nothing to do"));
  2216. break;
  2217. }
  2218. return ERROR_SUCCESS;
  2219. }
  2220. DWORD
  2221. RunSystemUninstallUserProfileCleanupPreparation (
  2222. IN DWORD Request
  2223. )
  2224. {
  2225. LONG Count;
  2226. if (Request == REQUEST_QUERYTICKS) {
  2227. //
  2228. // Count the number of entries and multiply by a constant
  2229. //
  2230. Count = SetupGetLineCount (g_WkstaMigInf, S_UNINSTALL_PROFILE_CLEAN_OUT);
  2231. #ifdef PROGRESS_BAR
  2232. DEBUGLOGTIME (("RunSystemUninstallUserProfileCleanupPreparation: FileNumber=%ld", Count));
  2233. #endif
  2234. if (Count < 1) {
  2235. return 1;
  2236. }
  2237. return Count * TICKS_SYSTEM_UNINSTALL_CLEANUP;
  2238. }
  2239. if (Request != REQUEST_RUN) {
  2240. return ERROR_SUCCESS;
  2241. }
  2242. //
  2243. // Loop through the files and mark them to be deleted during uninstall
  2244. //
  2245. UninstallUserProfileCleanupPreparation (g_WkstaMigInf, NULL, TRUE);
  2246. return ERROR_SUCCESS;
  2247. }
  2248. DWORD
  2249. AddOptionsDiskCleaner (
  2250. DWORD Request
  2251. )
  2252. {
  2253. HKEY key = NULL;
  2254. HKEY subKey = NULL;
  2255. PCTSTR optionsPath;
  2256. LONG rc;
  2257. PCTSTR descText = NULL;
  2258. DWORD d;
  2259. if (Request == REQUEST_QUERYTICKS) {
  2260. return 1;
  2261. }
  2262. if (Request != REQUEST_RUN) {
  2263. return ERROR_SUCCESS;
  2264. }
  2265. optionsPath = JoinPaths (g_WinDir, TEXT("OPTIONS"));
  2266. __try {
  2267. if (!DoesFileExist (optionsPath)) {
  2268. __leave;
  2269. }
  2270. key = OpenRegKeyStr (TEXT("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VolumeCaches"));
  2271. if (!key) {
  2272. DEBUGMSG ((DBG_ERROR, "Can't open VolumeCaches"));
  2273. __leave;
  2274. }
  2275. subKey = CreateRegKey (key, TEXT("Options Folder"));
  2276. if (!subKey) {
  2277. DEBUGMSG ((DBG_ERROR, "Can't create Options Folder"));
  2278. __leave;
  2279. }
  2280. rc = RegSetValueEx (
  2281. subKey,
  2282. TEXT(""),
  2283. 0,
  2284. REG_SZ,
  2285. (PBYTE) S_CLEANER_GUID,
  2286. sizeof (S_CLEANER_GUID)
  2287. );
  2288. if (rc != ERROR_SUCCESS) {
  2289. DEBUGMSG ((DBG_ERROR, "Can't write default value to Options Folder key"));
  2290. }
  2291. descText = GetStringResource (MSG_OPTIONS_CLEANER);
  2292. rc = RegSetValueEx (
  2293. subKey,
  2294. TEXT("Description"),
  2295. 0,
  2296. REG_SZ,
  2297. (PBYTE) descText,
  2298. SizeOfString (descText)
  2299. );
  2300. if (rc != ERROR_SUCCESS) {
  2301. DEBUGMSG ((DBG_ERROR, "Can't write Description value to Options Folder key"));
  2302. }
  2303. FreeStringResource (descText);
  2304. descText = GetStringResource (MSG_OPTIONS_CLEANER_TITLE);
  2305. rc = RegSetValueEx (
  2306. subKey,
  2307. TEXT("Display"),
  2308. 0,
  2309. REG_SZ,
  2310. (PBYTE) descText,
  2311. SizeOfString (descText)
  2312. );
  2313. if (rc != ERROR_SUCCESS) {
  2314. DEBUGMSG ((DBG_ERROR, "Can't write Display value to Options Folder key"));
  2315. }
  2316. rc = RegSetValueEx (
  2317. subKey,
  2318. TEXT("FileList"),
  2319. 0,
  2320. REG_SZ,
  2321. (PBYTE) S_CLEANER_ALL_FILES,
  2322. sizeof (S_CLEANER_ALL_FILES)
  2323. );
  2324. if (rc != ERROR_SUCCESS) {
  2325. DEBUGMSG ((DBG_ERROR, "Can't write FileList value to Options Folder key"));
  2326. }
  2327. rc = RegSetValueEx (
  2328. subKey,
  2329. TEXT("Folder"),
  2330. 0,
  2331. REG_SZ,
  2332. (PBYTE) optionsPath,
  2333. SizeOfString (optionsPath)
  2334. );
  2335. if (rc != ERROR_SUCCESS) {
  2336. DEBUGMSG ((DBG_ERROR, "Can't write Folder value to Options Folder key"));
  2337. }
  2338. d = 0x17F; // see shell\applets\cleaner\dataclen\common.h DDEVCF_* flags
  2339. rc = RegSetValueEx (
  2340. subKey,
  2341. TEXT("Flags"),
  2342. 0,
  2343. REG_DWORD,
  2344. (PBYTE) &d,
  2345. sizeof (d)
  2346. );
  2347. if (rc != ERROR_SUCCESS) {
  2348. DEBUGMSG ((DBG_ERROR, "Can't write flags to Options Folder key"));
  2349. }
  2350. }
  2351. __finally {
  2352. FreePathString (optionsPath);
  2353. if (key) {
  2354. CloseRegKey (key);
  2355. }
  2356. if (subKey) {
  2357. CloseRegKey (subKey);
  2358. }
  2359. FreeStringResource (descText);
  2360. }
  2361. return ERROR_SUCCESS;
  2362. }