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.

695 lines
20 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: N C S F M . C P P
  7. //
  8. // Contents: Installation support for Services for Macintosh.
  9. //
  10. // Notes:
  11. //
  12. // Author: danielwe 5 May 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <ncxbase.h>
  18. #include "ncatlui.h"
  19. #include "ncmisc.h"
  20. #include "ncreg.h"
  21. #include "ncsfm.h"
  22. #include "ncui.h"
  23. #include "netoc.h"
  24. #include "resource.h"
  25. #include "sfmsec.h"
  26. #include "macfile.h"
  27. extern const WCHAR c_szBackslash[];
  28. static const WCHAR c_szNTFS[] = L"NTFS";
  29. static const WCHAR c_szColonBackslash[]= L":\\";
  30. // These will have %windir%\system32\ prepended to them
  31. static const WCHAR c_szSrcRSCFile[] = L"SFMUAM.RSC";
  32. static const WCHAR c_szSrcRSCFile5[] = L"SFMUAM5.RSC";
  33. static const WCHAR c_szSrcIFOFile[] = L"SFMUAM.IFO";
  34. static const WCHAR c_szSrcIFOFile5[] = L"SFMUAM5.IFO";
  35. static const WCHAR c_szSrcTXTFile[] = L"SFMUAM.TXT";
  36. static const WCHAR c_szSrcRSCUamInst[] = L"UAMINST.RSC";
  37. static const WCHAR c_szSrcIFOUamInst[] = L"UAMINST.IFO";
  38. // These will have UAM path prepended to them
  39. static const WCHAR c_szDstRSCFile[] = L"\\%s\\MS UAM:Afp_Resource";
  40. static const WCHAR c_szDstRSCFile5[] = L"\\%s\\MS UAM 5.0:Afp_Resource";
  41. static const WCHAR c_szDstIFOFile[] = L"\\%s\\MS UAM:Afp_AfpInfo";
  42. static const WCHAR c_szDstIFOFile5[] = L"\\%s\\MS UAM 5.0:Afp_AfpInfo";
  43. static const WCHAR c_szDstTXTFile[] = L"\\ReadMe.UAM";
  44. static const WCHAR c_szDstRSCUamInst[] = L"\\%s:Afp_Resource";
  45. static const WCHAR c_szDstIFOUamInst[] = L"\\%s:Afp_AfpInfo";
  46. // registry constants
  47. static const WCHAR c_szRegKeyVols[] = L"System\\CurrentControlSet\\Services\\MacFile\\Parameters\\Volumes";
  48. static const WCHAR c_szRegKeyParams[] = L"System\\CurrentControlSet\\Services\\MacFile\\Parameters";
  49. static const WCHAR c_szPath[] = L"PATH=";
  50. static const WCHAR c_szRegValServerOptions[] = L"ServerOptions";
  51. //+---------------------------------------------------------------------------
  52. //
  53. // Function: FContainsUAMVolume
  54. //
  55. // Purpose: Determines whether the given drive letter contains a UAM
  56. // volume.
  57. //
  58. // Arguments:
  59. // chDrive [in] Drive letter to search.
  60. //
  61. // Returns: TRUE if drive contains a UAM volume, FALSE if not.
  62. //
  63. // Author: danielwe 22 May 1997
  64. //
  65. // Notes:
  66. //
  67. BOOL FContainsUAMVolume(WCHAR chDrive)
  68. {
  69. tstring strUAMPath;
  70. WIN32_FIND_DATA w32Data;
  71. BOOL frt = FALSE;
  72. HANDLE hfind;
  73. strUAMPath = chDrive;
  74. strUAMPath += c_szColonBackslash;
  75. strUAMPath += SzLoadIds(IDS_OC_SFM_VOLNAME);
  76. hfind = FindFirstFile(strUAMPath.c_str(), &w32Data);
  77. if (hfind != INVALID_HANDLE_VALUE)
  78. {
  79. // Found a volume!
  80. frt = TRUE;
  81. FindClose(hfind);
  82. }
  83. return frt;
  84. }
  85. //+---------------------------------------------------------------------------
  86. //
  87. // Function: HrGetFirstPossibleUAMDrive
  88. //
  89. // Purpose: Obtains the first fixed or removable drive's drive letter
  90. // that has the NTFS file system installed on it and/or already
  91. // has a UAM volume on it.
  92. //
  93. // Arguments:
  94. // pchDriveLetter [out] Drive letter returned. If no drive is found,
  95. // this is the NUL character.
  96. //
  97. // Returns: S_OK if successfull, Win32 error otherwise.
  98. //
  99. // Author: danielwe 5 May 1997
  100. //
  101. // Notes:
  102. //
  103. HRESULT HrGetFirstPossibleUAMDrive(WCHAR *pchDriveLetter)
  104. {
  105. HRESULT hr = S_OK;
  106. WCHAR mszDrives[1024];
  107. Assert(pchDriveLetter);
  108. *pchDriveLetter = 0;
  109. if (GetLogicalDriveStrings(celems(mszDrives), mszDrives))
  110. {
  111. PCWSTR pchDrive;
  112. WCHAR szFileSystem[64];
  113. DWORD dwType;
  114. pchDrive = mszDrives;
  115. while (*pchDrive)
  116. {
  117. // pchDrive is something like "C:\" at this point
  118. dwType = GetDriveType(pchDrive);
  119. if ((dwType == DRIVE_REMOVABLE) || (dwType == DRIVE_FIXED))
  120. {
  121. // Only look at removable or fixed drives.
  122. if (GetVolumeInformation(pchDrive, NULL, 0, NULL, NULL, NULL,
  123. szFileSystem, celems(szFileSystem)))
  124. {
  125. if (!lstrcmpiW(szFileSystem, c_szNTFS))
  126. {
  127. // Drive letter gets first char of drive root path
  128. if (!*pchDriveLetter)
  129. {
  130. // If no drive was found yet, this becomes the
  131. // first
  132. *pchDriveLetter = *pchDrive;
  133. }
  134. // Found NTFS drive. Continue looking, though
  135. // in case there exists an NTFS drive that already has
  136. // a UAM volume on it.
  137. if (FContainsUAMVolume(*pchDrive))
  138. {
  139. // Override first drive letter and use this one
  140. // and break because it already has a UAM volume
  141. // on it.
  142. *pchDriveLetter = *pchDrive;
  143. break;
  144. }
  145. }
  146. }
  147. }
  148. pchDrive += lstrlenW(pchDrive) + 1;
  149. }
  150. }
  151. else
  152. {
  153. hr = HrFromLastWin32Error();
  154. }
  155. TraceError("HrGetFirstPossibleUAMDrive", hr);
  156. return hr;
  157. }
  158. //+---------------------------------------------------------------------------
  159. //
  160. // Function: HrDeleteOldFolders
  161. //
  162. // Purpose: Removes the old AppleShare Folder directory from an NT4 to
  163. // NT5 upgrade.
  164. //
  165. // Arguments:
  166. // pszUamPath [in] Path to UAM volume.
  167. //
  168. // Returns: S_OK if success, WIN32 error otherwise
  169. //
  170. // Author: danielwe 15 Dec 1998
  171. //
  172. // Notes:
  173. //
  174. HRESULT HrDeleteOldFolders(PCWSTR pszUamPath)
  175. {
  176. HRESULT hr = S_OK;
  177. WCHAR szOldFolder[MAX_PATH];
  178. lstrcpyW(szOldFolder, pszUamPath);
  179. lstrcatW(szOldFolder, c_szBackslash);
  180. lstrcatW(szOldFolder, SzLoadIds(IDS_OC_SFM_APPLESHARE_FOLDER));
  181. hr = HrDeleteDirectory(szOldFolder, TRUE);
  182. if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) ||
  183. (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr))
  184. {
  185. // ok if old directory was not there
  186. hr = S_OK;
  187. }
  188. TraceError("HrDeleteOldFolders", hr);
  189. return hr;
  190. }
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Function: HrInstallSFM
  194. //
  195. // Purpose: Called when SFM is being installed. Handles all of the
  196. // additional installation for SFM beyond that of the INF file.
  197. //
  198. // Arguments:
  199. // pnocd [in] Pointer to NETOC data.
  200. //
  201. // Returns: S_OK if successfull, Win32 error otherwise.
  202. //
  203. // Author: danielwe 5 May 1997
  204. //
  205. // Notes:
  206. //
  207. HRESULT HrInstallSFM(PNETOCDATA pnocd)
  208. {
  209. HRESULT hr = S_OK;
  210. WCHAR chNTFSDrive;
  211. hr = HrGetFirstPossibleUAMDrive(&chNTFSDrive);
  212. if (SUCCEEDED(hr))
  213. {
  214. if (chNTFSDrive != 0)
  215. {
  216. WCHAR szUAMPath[MAX_PATH];
  217. szUAMPath[0] = chNTFSDrive;
  218. szUAMPath[1] = 0;
  219. lstrcatW(szUAMPath, c_szColonBackslash);
  220. lstrcatW(szUAMPath, SzLoadIds(IDS_OC_SFM_VOLNAME));
  221. // UAM Path is now something like "D:\Microsoft UAM Volume".
  222. hr = HrDeleteOldFolders(szUAMPath);
  223. if (SUCCEEDED(hr))
  224. {
  225. hr = HrSetupUAM(szUAMPath);
  226. if (SUCCEEDED(hr))
  227. {
  228. WCHAR szValue[MAX_PATH];
  229. lstrcpyW(szValue, c_szPath);
  230. lstrcatW(szValue, szUAMPath);
  231. // Add the final multi_sz value to the registry
  232. hr = HrRegAddStringToMultiSz(szValue,
  233. HKEY_LOCAL_MACHINE,
  234. c_szRegKeyVols,
  235. SzLoadIds(IDS_OC_SFM_VOLNAME),
  236. STRING_FLAG_ENSURE_AT_END,
  237. 0);
  238. }
  239. }
  240. }
  241. else
  242. {
  243. // No NTFS drives present.
  244. //$ REVIEW (danielwe) 6 May 1997: For now we will fail,
  245. // but how can we do this in the future?
  246. // Not the best error code, but hopefully it's close to
  247. // what we want.
  248. hr = HRESULT_FROM_WIN32(ERROR_UNRECOGNIZED_MEDIA);
  249. }
  250. }
  251. TraceError("HrInstallSFM", hr);
  252. return hr;
  253. }
  254. //+---------------------------------------------------------------------------
  255. //
  256. // Function: HrRemoveSFM
  257. //
  258. // Purpose: Handles additional removal requirements for SFM component.
  259. //
  260. // pnocd [in] Pointer to NETOC data.
  261. //
  262. // Returns: S_OK if successfull, Win32 error otherwise.
  263. //
  264. // Author: danielwe 5 May 1997
  265. //
  266. // Notes:
  267. //
  268. HRESULT HrRemoveSFM(PNETOCDATA pnocd)
  269. {
  270. HRESULT hr = S_OK;
  271. static const WCHAR c_szRegKeyLsa[] = L"System\\CurrentControlSet\\Control\\Lsa";
  272. static const WCHAR c_szRegValueNotif[] = L"Notification Packages";
  273. static const WCHAR c_szRasSfm[] = L"RASSFM";
  274. hr = HrRegRemoveStringFromMultiSz(c_szRasSfm, HKEY_LOCAL_MACHINE,
  275. c_szRegKeyLsa, c_szRegValueNotif,
  276. STRING_FLAG_REMOVE_ALL);
  277. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  278. {
  279. // benign error
  280. hr = S_OK;
  281. }
  282. TraceError("HrRemoveSFM", hr);
  283. return hr;
  284. }
  285. //+---------------------------------------------------------------------------
  286. //
  287. // Function: HrOcExtSFM
  288. //
  289. // Purpose: NetOC external message handler
  290. //
  291. // Arguments:
  292. // pnocd []
  293. // uMsg []
  294. // wParam []
  295. // lParam []
  296. //
  297. // Returns:
  298. //
  299. // Author: danielwe 17 Sep 1998
  300. //
  301. // Notes:
  302. //
  303. HRESULT HrOcExtSFM(PNETOCDATA pnocd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  304. {
  305. HRESULT hr = S_OK;
  306. Assert(pnocd);
  307. switch (uMsg)
  308. {
  309. case NETOCM_POST_INSTALL:
  310. hr = HrOcSfmOnInstall(pnocd);
  311. break;
  312. case NETOCM_QUERY_CHANGE_SEL_STATE:
  313. hr = HrOcSfmOnQueryChangeSelState(pnocd, static_cast<BOOL>(wParam));
  314. break;
  315. }
  316. TraceError("HrOcExtSFM", hr);
  317. return hr;
  318. }
  319. //+---------------------------------------------------------------------------
  320. //
  321. // Function: HrOcSfmOnInstall
  322. //
  323. // Purpose: Called by optional components installer code to handle
  324. // additional installation requirements for SFM.
  325. //
  326. // Arguments:
  327. // pnocd [in] Pointer to NETOC data.
  328. //
  329. // Returns: S_OK if successfull, Win32 error otherwise.
  330. //
  331. // Author: danielwe 5 May 1997
  332. //
  333. // Notes:
  334. //
  335. HRESULT HrOcSfmOnInstall(PNETOCDATA pnocd)
  336. {
  337. HRESULT hr = S_OK;
  338. Assert(pnocd);
  339. if (pnocd->eit == IT_INSTALL || pnocd->eit == IT_UPGRADE)
  340. {
  341. hr = HrInstallSFM(pnocd);
  342. if (HRESULT_FROM_WIN32(ERROR_UNRECOGNIZED_MEDIA) == hr)
  343. {
  344. // This error code means no NTFS drives were present
  345. NcMsgBox(g_ocmData.hwnd, IDS_OC_CAPTION, IDS_OC_SFM_NO_NTFS,
  346. MB_ICONSTOP | MB_OK);
  347. g_ocmData.fErrorReported = TRUE;
  348. }
  349. else
  350. {
  351. if (SUCCEEDED(hr) && pnocd->eit == IT_UPGRADE)
  352. {
  353. HKEY hkeyParams;
  354. TraceTag(ttidNetOc, "Upgrading MacFile server options...");
  355. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyParams,
  356. KEY_ALL_ACCESS, &hkeyParams);
  357. if (S_OK == hr)
  358. {
  359. DWORD dwOptions;
  360. hr = HrRegQueryDword(hkeyParams, c_szRegValServerOptions,
  361. &dwOptions);
  362. if (S_OK == hr)
  363. {
  364. // 'or' in the UAM option
  365. //
  366. hr = HrRegSetDword(hkeyParams, c_szRegValServerOptions,
  367. dwOptions | AFP_SRVROPT_MICROSOFT_UAM);
  368. }
  369. RegCloseKey (hkeyParams);
  370. }
  371. }
  372. }
  373. }
  374. else
  375. {
  376. // Do not call HrRemoveSFM anymore.
  377. // It removes an entry in the notification packages list for LSA.
  378. // RASSFM entry should never be removed if LSA/SAM is to notify
  379. // SFM/IAS about changes in password/guest account changes etc.
  380. //hr = HrRemoveSFM(pnocd);
  381. }
  382. TraceError("HrOcSfmOnInstall", hr);
  383. return hr;
  384. }
  385. //+---------------------------------------------------------------------------
  386. //
  387. // Function: HrOcSfmOnQueryChangeSelState
  388. //
  389. // Purpose: Handles the request of the OC framework of whether or not
  390. // the user should be allowed to install this component.
  391. //
  392. // Arguments:
  393. // pnocd [in] NetOC Data
  394. // fShowUi [in] TRUE if UI should be shown, FALSE if not
  395. //
  396. // Returns: S_OK if install is allowed, S_FALSE if not, Win32 error
  397. // otherwise
  398. //
  399. // Author: danielwe 6 Feb 1998
  400. //
  401. // Notes:
  402. //
  403. HRESULT HrOcSfmOnQueryChangeSelState(PNETOCDATA pnocd, BOOL fShowUi)
  404. {
  405. HRESULT hr = S_OK;
  406. WCHAR chNTFSDrive;
  407. Assert(pnocd);
  408. Assert(g_ocmData.hwnd);
  409. // See if an NTFS volume exists
  410. hr = HrGetFirstPossibleUAMDrive(&chNTFSDrive);
  411. if (SUCCEEDED(hr))
  412. {
  413. if (chNTFSDrive == 0)
  414. {
  415. if (fShowUi)
  416. {
  417. NcMsgBox(g_ocmData.hwnd, IDS_OC_CAPTION, IDS_OC_SFM_NO_NTFS,
  418. MB_ICONSTOP | MB_OK);
  419. }
  420. hr = S_FALSE;
  421. }
  422. }
  423. TraceError("HrOcSfmOnQueryChangeSelState", (S_FALSE == hr) ? S_OK : hr);
  424. return hr;
  425. }
  426. //+---------------------------------------------------------------------------
  427. //
  428. // Function: HrCreateDirectory
  429. //
  430. // Purpose: Creates the given directory. If the directory already exists,
  431. // no error is returned.
  432. //
  433. // Arguments:
  434. // pszDir [in] Path to directory to create.
  435. //
  436. // Returns: S_OK if success, Win32 error otherwise.
  437. //
  438. // Author: danielwe 5 May 1997
  439. //
  440. // Notes:
  441. //
  442. HRESULT HrCreateDirectory(PCWSTR pszDir)
  443. {
  444. HRESULT hr = S_OK;
  445. if (!CreateDirectory(pszDir, NULL))
  446. {
  447. // Don't complain if directory already exists.
  448. if (GetLastError() != ERROR_ALREADY_EXISTS)
  449. {
  450. hr = HrFromLastWin32Error();
  451. }
  452. }
  453. TraceError("HrCreateDirectory" ,hr);
  454. return hr;
  455. }
  456. struct FOLDER
  457. {
  458. UINT idsFoldName;
  459. PCWSTR aszSrcFiles[2];
  460. PCWSTR aszDstFiles[2];
  461. };
  462. static const FOLDER c_afold[] =
  463. {
  464. {
  465. IDS_OC_SFM_FOLDNAMENT4,
  466. {
  467. c_szSrcRSCFile,
  468. c_szSrcIFOFile
  469. },
  470. {
  471. c_szDstRSCFile,
  472. c_szDstIFOFile,
  473. }
  474. },
  475. {
  476. IDS_OC_SFM_FOLDNAMENT5,
  477. {
  478. c_szSrcRSCFile5,
  479. c_szSrcIFOFile5
  480. },
  481. {
  482. c_szDstRSCFile5,
  483. c_szDstIFOFile5
  484. }
  485. }
  486. };
  487. static const INT c_cfold = celems(c_afold);
  488. static const PCWSTR c_aszRootFilesSrc[] =
  489. {
  490. c_szSrcTXTFile,
  491. c_szSrcIFOUamInst,
  492. c_szSrcRSCUamInst,
  493. };
  494. static const PCWSTR c_aszRootFilesDst[] =
  495. {
  496. c_szDstTXTFile,
  497. c_szDstIFOUamInst,
  498. c_szDstRSCUamInst,
  499. };
  500. static const INT c_cszFilesRoot = celems(c_aszRootFilesDst);
  501. //+---------------------------------------------------------------------------
  502. //
  503. // Function: HrSetupUAM
  504. //
  505. // Purpose: Copies the UAM files to the proper UAM path.
  506. //
  507. // Arguments:
  508. // pszPath [in] Path to UAM volume.
  509. //
  510. // Returns: S_OK if successfull, Win32 error otherwise.
  511. //
  512. // Author: danielwe 5 May 1997
  513. //
  514. // Notes:
  515. //
  516. HRESULT HrSetupUAM(PWSTR pszPath)
  517. {
  518. HRESULT hr = S_OK;
  519. WCHAR szWinDir[MAX_PATH];
  520. INT isz;
  521. // Create dir: "X:\Microsoft UAM Volume"
  522. hr = HrCreateDirectory(pszPath);
  523. if (SUCCEEDED(hr))
  524. {
  525. hr = HrSecureSfmDirectory(pszPath);
  526. if (SUCCEEDED(hr))
  527. {
  528. INT ifold;
  529. for (ifold = 0; ifold < c_cfold; ifold++)
  530. {
  531. WCHAR szNewDir[MAX_PATH];
  532. lstrcpyW(szNewDir, pszPath);
  533. lstrcatW(szNewDir, c_szBackslash);
  534. lstrcatW(szNewDir, SzLoadIds(c_afold[ifold].idsFoldName));
  535. lstrcatW(szNewDir, c_szBackslash);
  536. lstrcatW(szNewDir, SzLoadIds(IDS_OC_SFM_APPLESHARE_FOLDER));
  537. lstrcatW(szNewDir, c_szBackslash);
  538. // Create dir: "X:\Microsoft UAM Volume\<folder>\AppleShare Folder"
  539. hr = HrCreateDirectoryTree(szNewDir, NULL);
  540. if (SUCCEEDED(hr))
  541. {
  542. if (GetSystemDirectory(szWinDir, celems(szWinDir)))
  543. {
  544. WCHAR szSrcFile[MAX_PATH];
  545. WCHAR szDstFile[MAX_PATH];
  546. WCHAR szDstFilePath[MAX_PATH];
  547. INT isz;
  548. for (isz = 0; isz < celems(c_afold[ifold].aszSrcFiles);
  549. isz++)
  550. {
  551. lstrcpyW(szSrcFile, szWinDir);
  552. lstrcatW(szSrcFile, c_szBackslash);
  553. lstrcatW(szSrcFile, c_afold[ifold].aszSrcFiles[isz]);
  554. lstrcpyW(szDstFile, pszPath);
  555. lstrcatW(szDstFile, c_szBackslash);
  556. lstrcatW(szDstFile, SzLoadIds(c_afold[ifold].idsFoldName));
  557. wsprintf(szDstFilePath,
  558. c_afold[ifold].aszDstFiles[isz],
  559. SzLoadIds(IDS_OC_SFM_APPLESHARE_FOLDER));
  560. lstrcatW(szDstFile, szDstFilePath);
  561. TraceTag(ttidNetOc, "MacFile: Copying %S to %S...",
  562. szSrcFile, szDstFile);
  563. if (!CopyFile(szSrcFile, szDstFile, FALSE))
  564. {
  565. hr = HrFromLastWin32Error();
  566. goto err;
  567. }
  568. }
  569. }
  570. else
  571. {
  572. hr = HrFromLastWin32Error();
  573. }
  574. }
  575. }
  576. }
  577. }
  578. // Copy files to the root
  579. //
  580. if (SUCCEEDED(hr))
  581. {
  582. for (isz = 0; isz < c_cszFilesRoot; isz++)
  583. {
  584. WCHAR szSrcFile[MAX_PATH];
  585. WCHAR szDstFile[MAX_PATH];
  586. lstrcpyW(szSrcFile, szWinDir);
  587. lstrcatW(szSrcFile, c_szBackslash);
  588. lstrcatW(szSrcFile, c_aszRootFilesSrc[isz]);
  589. if ((c_aszRootFilesDst[isz] == c_szDstIFOUamInst) ||
  590. (c_aszRootFilesDst[isz] == c_szDstRSCUamInst))
  591. {
  592. WCHAR szTemp[MAX_PATH];
  593. lstrcpyW(szTemp, pszPath);
  594. lstrcatW(szTemp, c_aszRootFilesDst[isz]);
  595. wsprintfW(szDstFile, szTemp,
  596. SzLoadIds(IDS_OC_SFM_UAM_INSTALLER));
  597. }
  598. else
  599. {
  600. lstrcpyW(szDstFile, pszPath);
  601. lstrcatW(szDstFile, c_aszRootFilesDst[isz]);
  602. }
  603. TraceTag(ttidNetOc, "MacFile: Copying %S to %S", szSrcFile,
  604. szDstFile);
  605. if (!CopyFile(szSrcFile, szDstFile, FALSE))
  606. {
  607. hr = HrFromLastWin32Error();
  608. goto err;
  609. }
  610. }
  611. }
  612. err:
  613. TraceError("HrSetupUAM", hr);
  614. return hr;
  615. }