|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: N C S F M . C P P
//
// Contents: Installation support for Services for Macintosh.
//
// Notes:
//
// Author: danielwe 5 May 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include <ncxbase.h>
#include "ncatlui.h"
#include "ncmisc.h"
#include "ncreg.h"
#include "ncsfm.h"
#include "ncui.h"
#include "netoc.h"
#include "netocp.h"
#include "resource.h"
#include "sfmsec.h"
#include "macfile.h"
extern const WCHAR c_szBackslash[];
static const WCHAR c_szNTFS[] = L"NTFS"; static const WCHAR c_szColonBackslash[]= L":\\";
// These will have %windir%\system32\ prepended to them
static const WCHAR c_szSrcRSCFile[] = L"SFMUAM.RSC"; static const WCHAR c_szSrcRSCFile5[] = L"SFMUAM5.RSC"; static const WCHAR c_szSrcIFOFile[] = L"SFMUAM.IFO"; static const WCHAR c_szSrcIFOFile5[] = L"SFMUAM5.IFO"; static const WCHAR c_szSrcTXTFile[] = L"SFMUAM.TXT"; static const WCHAR c_szSrcRSCUamInst[] = L"UAMINST.RSC"; static const WCHAR c_szSrcIFOUamInst[] = L"UAMINST.IFO";
// These will have UAM path prepended to them
static const WCHAR c_szDstRSCFile[] = L"\\%s\\MS UAM:Afp_Resource"; static const WCHAR c_szDstRSCFile5[] = L"\\%s\\MS UAM 5.0:Afp_Resource"; static const WCHAR c_szDstIFOFile[] = L"\\%s\\MS UAM:Afp_AfpInfo"; static const WCHAR c_szDstIFOFile5[] = L"\\%s\\MS UAM 5.0:Afp_AfpInfo"; static const WCHAR c_szDstTXTFile[] = L"\\ReadMe.UAM"; static const WCHAR c_szDstRSCUamInst[] = L"\\%s:Afp_Resource"; static const WCHAR c_szDstIFOUamInst[] = L"\\%s:Afp_AfpInfo";
// registry constants
static const WCHAR c_szRegKeyVols[] = L"System\\CurrentControlSet\\Services\\MacFile\\Parameters\\Volumes"; static const WCHAR c_szRegKeyParams[] = L"System\\CurrentControlSet\\Services\\MacFile\\Parameters"; static const WCHAR c_szPath[] = L"PATH="; static const WCHAR c_szRegValServerOptions[] = L"ServerOptions";
inline BOOL IsValidHandle(HANDLE h) { return (h && INVALID_HANDLE_VALUE != h); }
//+---------------------------------------------------------------------------
//
// Function: FContainsUAMVolume
//
// Purpose: Determines whether the given drive letter contains a UAM
// volume.
//
// Arguments:
// chDrive [in] Drive letter to search.
//
// Returns: TRUE if drive contains a UAM volume, FALSE if not.
//
// Author: danielwe 22 May 1997
//
// Notes:
//
BOOL FContainsUAMVolume(WCHAR chDrive) { tstring strUAMPath; WIN32_FIND_DATA w32Data; BOOL frt = FALSE; HANDLE hfind;
try { strUAMPath = chDrive; strUAMPath += c_szColonBackslash; strUAMPath += SzLoadIds(IDS_OC_SFM_VOLNAME); } catch (bad_alloc) { return frt; }
hfind = FindFirstFile(strUAMPath.c_str(), &w32Data); if (hfind != INVALID_HANDLE_VALUE) { // Found a volume!
frt = TRUE; FindClose(hfind); }
return frt; }
//+---------------------------------------------------------------------------
//
// Function: HrGetFirstPossibleUAMDrive
//
// Purpose: Obtains the first fixed or removable drive's drive letter
// that has the NTFS file system installed on it and/or already
// has a UAM volume on it.
//
// Arguments:
// pchDriveLetter [out] Drive letter returned. If no drive is found,
// this is the NUL character.
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: danielwe 5 May 1997
//
// Notes:
//
HRESULT HrGetFirstPossibleUAMDrive(WCHAR *pchDriveLetter) { HRESULT hr = S_OK; WCHAR mszDrives[1024];
Assert(pchDriveLetter);
*pchDriveLetter = 0; ZeroMemory ((PVOID)mszDrives, 1024*sizeof(WCHAR));
if (GetLogicalDriveStrings(celems(mszDrives), mszDrives)) { PCWSTR pchDrive = NULL; WCHAR szFileSystem[64]; DWORD dwType;
pchDrive = mszDrives; while (*pchDrive) { // pchDrive is something like "C:\" at this point
dwType = GetDriveType(pchDrive);
if ((dwType == DRIVE_REMOVABLE) || (dwType == DRIVE_FIXED)) { // Only look at removable or fixed drives.
if (GetVolumeInformation(pchDrive, NULL, 0, NULL, NULL, NULL, szFileSystem, celems(szFileSystem))) { if (!lstrcmpiW(szFileSystem, c_szNTFS)) { // Drive letter gets first char of drive root path
if (!*pchDriveLetter) { // If no drive was found yet, this becomes the
// first
*pchDriveLetter = *pchDrive; }
// Found NTFS drive. Continue looking, though
// in case there exists an NTFS drive that already has
// a UAM volume on it.
if (FContainsUAMVolume(*pchDrive)) { // Override first drive letter and use this one
// and break because it already has a UAM volume
// on it.
*pchDriveLetter = *pchDrive; break; } } } } pchDrive += lstrlenW(pchDrive) + 1; } } else { hr = HrFromLastWin32Error(); }
TraceError("HrGetFirstPossibleUAMDrive", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrDeleteOldFolders
//
// Purpose: Removes the old AppleShare Folder directory from an NT4 to
// NT5 upgrade.
//
// Arguments:
// pszUamPath [in] Path to UAM volume.
//
// Returns: S_OK if success, WIN32 error otherwise
//
// Author: danielwe 15 Dec 1998
//
// Notes:
//
HRESULT HrDeleteOldFolders(PCWSTR pszUamPath) { HRESULT hr = S_OK;
WCHAR szOldFolder[MAX_PATH];
if (wcslen(pszUamPath) > (MAX_PATH - wcslen(c_szBackslash) - wcslen(SzLoadIds(IDS_OC_SFM_APPLESHARE_FOLDER)) - 1)) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); return hr; } lstrcpyW(szOldFolder, pszUamPath); lstrcatW(szOldFolder, c_szBackslash); lstrcatW(szOldFolder, SzLoadIds(IDS_OC_SFM_APPLESHARE_FOLDER));
hr = HrDeleteDirectory(szOldFolder, TRUE); if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) || (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)) { // ok if old directory was not there
hr = S_OK; }
TraceError("HrDeleteOldFolders", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrInstallSFM
//
// Purpose: Called when SFM is being installed. Handles all of the
// additional installation for SFM beyond that of the INF file.
//
// Arguments:
// pnocd [in] Pointer to NETOC data.
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: danielwe 5 May 1997
//
// Notes:
//
HRESULT HrInstallSFM(PNETOCDATA pnocd) { HRESULT hr = S_OK; WCHAR chNTFSDrive;
hr = HrGetFirstPossibleUAMDrive(&chNTFSDrive); if (SUCCEEDED(hr)) { if (chNTFSDrive != 0) { WCHAR szUAMPath[MAX_PATH];
szUAMPath[0] = chNTFSDrive; szUAMPath[1] = 0; lstrcatW(szUAMPath, c_szColonBackslash); lstrcatW(szUAMPath, SzLoadIds(IDS_OC_SFM_VOLNAME));
// UAM Path is now something like "D:\Microsoft UAM Volume".
hr = HrDeleteOldFolders(szUAMPath); if (SUCCEEDED(hr)) { hr = HrSetupUAM(szUAMPath); if (SUCCEEDED(hr)) { WCHAR szValue[MAX_PATH];
lstrcpyW(szValue, c_szPath); lstrcatW(szValue, szUAMPath);
// Add the final multi_sz value to the registry
hr = HrRegAddStringToMultiSz(szValue, HKEY_LOCAL_MACHINE, c_szRegKeyVols, SzLoadIds(IDS_OC_SFM_VOLNAME), STRING_FLAG_ENSURE_AT_END, 0); } } } else { // No NTFS drives present.
//$ REVIEW (danielwe) 6 May 1997: For now we will fail,
// but how can we do this in the future?
// Not the best error code, but hopefully it's close to
// what we want.
hr = HRESULT_FROM_WIN32(ERROR_UNRECOGNIZED_MEDIA); } }
TraceError("HrInstallSFM", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrRemoveSFM
//
// Purpose: Handles additional removal requirements for SFM component.
//
// pnocd [in] Pointer to NETOC data.
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: danielwe 5 May 1997
//
// Notes:
//
HRESULT HrRemoveSFM(PNETOCDATA pnocd) { HRESULT hr = S_OK;
static const WCHAR c_szRegKeyLsa[] = L"System\\CurrentControlSet\\Control\\Lsa"; static const WCHAR c_szRegValueNotif[] = L"Notification Packages"; static const WCHAR c_szRasSfm[] = L"RASSFM";
hr = HrRegRemoveStringFromMultiSz(c_szRasSfm, HKEY_LOCAL_MACHINE, c_szRegKeyLsa, c_szRegValueNotif, STRING_FLAG_REMOVE_ALL); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { // benign error
hr = S_OK; }
TraceError("HrRemoveSFM", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrOcExtSFM
//
// Purpose: NetOC external message handler
//
// Arguments:
// pnocd []
// uMsg []
// wParam []
// lParam []
//
// Returns:
//
// Author: danielwe 17 Sep 1998
//
// Notes:
//
HRESULT HrOcExtSFM(PNETOCDATA pnocd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr = S_OK;
Assert(pnocd);
switch (uMsg) { case NETOCM_POST_INSTALL: hr = HrOcSfmOnInstall(pnocd); break;
case NETOCM_QUERY_CHANGE_SEL_STATE: hr = HrOcSfmOnQueryChangeSelState(pnocd, static_cast<BOOL>(wParam)); break; }
TraceError("HrOcExtSFM", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrOcSfmOnInstall
//
// Purpose: Called by optional components installer code to handle
// additional installation requirements for SFM.
//
// Arguments:
// pnocd [in] Pointer to NETOC data.
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: danielwe 5 May 1997
//
// Notes:
//
HRESULT HrOcSfmOnInstall(PNETOCDATA pnocd) { HRESULT hr = S_OK;
Assert(pnocd);
if (pnocd->eit == IT_INSTALL || pnocd->eit == IT_UPGRADE) { hr = HrInstallSFM(pnocd); if (HRESULT_FROM_WIN32(ERROR_UNRECOGNIZED_MEDIA) == hr) { // This error code means no NTFS drives were present
ReportErrorHr(hr, IDS_OC_SFM_NO_NTFS, g_ocmData.hwnd, SzLoadIds(IDS_OC_GENERIC_COMP)); g_ocmData.fErrorReported = TRUE; } else { if (SUCCEEDED(hr) && pnocd->eit == IT_UPGRADE) { HKEY hkeyParams;
TraceTag(ttidNetOc, "Upgrading MacFile server options...");
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyParams, KEY_ALL_ACCESS, &hkeyParams); if (S_OK == hr) { DWORD dwOptions;
hr = HrRegQueryDword(hkeyParams, c_szRegValServerOptions, &dwOptions); if (S_OK == hr) { // 'or' in the UAM option
//
hr = HrRegSetDword(hkeyParams, c_szRegValServerOptions, dwOptions | AFP_SRVROPT_MICROSOFT_UAM); }
RegCloseKey (hkeyParams); } } } } else { // Do not call HrRemoveSFM anymore.
// It removes an entry in the notification packages list for LSA.
// RASSFM entry should never be removed if LSA/SAM is to notify
// SFM/IAS about changes in password/guest account changes etc.
//hr = HrRemoveSFM(pnocd);
}
TraceError("HrOcSfmOnInstall", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrOcSfmOnQueryChangeSelState
//
// Purpose: Handles the request of the OC framework of whether or not
// the user should be allowed to install this component.
//
// Arguments:
// pnocd [in] NetOC Data
// fShowUi [in] TRUE if UI should be shown, FALSE if not
//
// Returns: S_OK if install is allowed, S_FALSE if not, Win32 error
// otherwise
//
// Author: danielwe 6 Feb 1998
//
// Notes:
//
HRESULT HrOcSfmOnQueryChangeSelState(PNETOCDATA pnocd, BOOL fShowUi) { HRESULT hr = S_OK; WCHAR chNTFSDrive;
Assert(pnocd); Assert(g_ocmData.hwnd);
// See if an NTFS volume exists
hr = HrGetFirstPossibleUAMDrive(&chNTFSDrive); if (SUCCEEDED(hr)) { if (chNTFSDrive == 0) { if (fShowUi) { ReportErrorHr(hr, IDS_OC_SFM_NO_NTFS, g_ocmData.hwnd, SzLoadIds(IDS_OC_GENERIC_COMP)); }
hr = S_FALSE; } }
TraceError("HrOcSfmOnQueryChangeSelState", (S_FALSE == hr) ? S_OK : hr); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrCreateDirectory
//
// Purpose: Creates the given directory. If the directory already exists,
// no error is returned.
//
// Arguments:
// pszDir [in] Path to directory to create.
//
// Returns: S_OK if success, Win32 error otherwise.
//
// Author: danielwe 5 May 1997
//
// Notes:
//
HRESULT HrCreateDirectory(PCWSTR pszDir) { HRESULT hr = S_OK;
if (!CreateDirectory(pszDir, NULL)) { // Don't complain if directory already exists.
if (GetLastError() != ERROR_ALREADY_EXISTS) { hr = HrFromLastWin32Error(); } }
TraceError("HrCreateDirectory" ,hr); return hr; }
struct FOLDER { UINT idsFoldName; PCWSTR aszSrcFiles[2]; PCWSTR aszDstFiles[2]; };
static const FOLDER c_afold[] = { { IDS_OC_SFM_FOLDNAMENT4, { c_szSrcRSCFile, c_szSrcIFOFile }, { c_szDstRSCFile, c_szDstIFOFile, } }, { IDS_OC_SFM_FOLDNAMENT5, { c_szSrcRSCFile5, c_szSrcIFOFile5 }, { c_szDstRSCFile5, c_szDstIFOFile5 } } };
static const INT c_cfold = celems(c_afold);
static const PCWSTR c_aszRootFilesSrc[] = { c_szSrcTXTFile, c_szSrcIFOUamInst, c_szSrcRSCUamInst, };
static const PCWSTR c_aszRootFilesDst[] = { c_szDstTXTFile, c_szDstIFOUamInst, c_szDstRSCUamInst, };
static const INT c_cszFilesRoot = celems(c_aszRootFilesDst);
//+---------------------------------------------------------------------------
//
// Function: HrCopyFileAsStream
//
// Purpose: Copies a default data stream file as a named stream file
//
// Arguments: Same as CopyFile
//
// Returns: Same as CopyFile
//
// Author: roelfc 30 January 2002
//
// Notes: This function replaces the normal CopyFile API by manually
// reading the default data stream and writing it as a named
// stream to the new file name.
// This is because applications like eTrust can cause the normal
// CopyFile API to fail, since eTrust injects an additional stream
// into the file when the incremental scan option is used.
// (See RAID# 493890:
// SFM: File Services for Mac doesn't install with etrust installed.)
//
BOOL HrCopyFileAsStream(PWSTR pszSourceFileName, PWSTR pszDestFileName, BOOL bFailIfExists) { DWORD dwSize; DWORD dwResult = NO_ERROR; BOOL fResult = FALSE; PBYTE pBuffer = NULL; HANDLE hSourceFile = NULL; HANDLE hDestFile = NULL;
TraceTag(ttidNetOc, "HrCopyFileAsStream: Copying \"%s\" to \"%s\"...", pszSourceFileName, pszDestFileName);
// Open the unnamed stream source file first
hSourceFile = CreateFile(pszSourceFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hSourceFile) {
dwSize = GetFileSize(hSourceFile, NULL); if (0xFFFFFFFF != dwSize) { // Since we know we are working with small files,
// we can allocate the total file size.
pBuffer = (PBYTE)LocalAlloc(LPTR,dwSize); if (NULL != pBuffer) {
DWORD dwBytesRead; if (ReadFile(hSourceFile, pBuffer, dwSize, &dwBytesRead, NULL)) { // Sanity check
Assert(dwSize == dwBytesRead);
// Now try to open the named stream destination file
hDestFile = CreateFile(pszDestFileName, GENERIC_WRITE, 0, NULL, bFailIfExists ? CREATE_NEW : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hDestFile) { DWORD dwBytesWritten; if (WriteFile(hDestFile, pBuffer, dwSize, &dwBytesWritten, NULL)) { // Another sanity check
Assert(dwSize == dwBytesWritten); fResult = TRUE; } }
}
} } }
// Save the last error result code
if (!fResult) { dwResult = GetLastError(); }
if (IsValidHandle(hSourceFile)) { CloseHandle(hSourceFile); }
if (IsValidHandle(hDestFile)) { CloseHandle(hDestFile); }
if (NULL != pBuffer) { LocalFree(pBuffer); }
// Set the last result code again
SetLastError(dwResult);
TraceError("HrCopyFileAsStream", fResult ? S_OK : HrFromLastWin32Error());
return fResult;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupUAM
//
// Purpose: Copies the UAM files to the proper UAM path.
//
// Arguments:
// pszPath [in] Path to UAM volume.
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: danielwe 5 May 1997
//
// Notes:
//
HRESULT HrSetupUAM(PWSTR pszPath) { HRESULT hr = S_OK; WCHAR szWinDir[MAX_PATH]; INT isz;
// Create dir: "X:\Microsoft UAM Volume"
hr = HrCreateDirectory(pszPath); if (SUCCEEDED(hr)) { hr = HrSecureSfmDirectory(pszPath); if (SUCCEEDED(hr)) { INT ifold;
for (ifold = 0; ifold < c_cfold; ifold++) { WCHAR szNewDir[MAX_PATH];
lstrcpyW(szNewDir, pszPath); lstrcatW(szNewDir, c_szBackslash); lstrcatW(szNewDir, SzLoadIds(c_afold[ifold].idsFoldName)); lstrcatW(szNewDir, c_szBackslash); lstrcatW(szNewDir, SzLoadIds(IDS_OC_SFM_APPLESHARE_FOLDER)); lstrcatW(szNewDir, c_szBackslash);
// Create dir: "X:\Microsoft UAM Volume\<folder>\AppleShare Folder"
hr = HrCreateDirectoryTree(szNewDir, NULL); if (SUCCEEDED(hr)) { if (GetSystemDirectory(szWinDir, celems(szWinDir))) { WCHAR szSrcFile[MAX_PATH]; WCHAR szDstFile[MAX_PATH]; WCHAR szDstFilePath[MAX_PATH]; INT isz;
for (isz = 0; isz < celems(c_afold[ifold].aszSrcFiles); isz++) { lstrcpyW(szSrcFile, szWinDir); lstrcatW(szSrcFile, c_szBackslash); lstrcatW(szSrcFile, c_afold[ifold].aszSrcFiles[isz]);
lstrcpyW(szDstFile, pszPath); lstrcatW(szDstFile, c_szBackslash); lstrcatW(szDstFile, SzLoadIds(c_afold[ifold].idsFoldName));
wsprintf(szDstFilePath, c_afold[ifold].aszDstFiles[isz], SzLoadIds(IDS_OC_SFM_APPLESHARE_FOLDER));
lstrcatW(szDstFile, szDstFilePath);
TraceTag(ttidNetOc, "MacFile: Copying %S to %S...", szSrcFile, szDstFile);
if (!HrCopyFileAsStream(szSrcFile, szDstFile, FALSE)) { hr = HrFromLastWin32Error(); goto err; } } } else { hr = HrFromLastWin32Error(); } } } } }
// Copy files to the root
//
if (SUCCEEDED(hr)) { for (isz = 0; isz < c_cszFilesRoot; isz++) { WCHAR szSrcFile[MAX_PATH]; WCHAR szDstFile[MAX_PATH];
lstrcpyW(szSrcFile, szWinDir); lstrcatW(szSrcFile, c_szBackslash); lstrcatW(szSrcFile, c_aszRootFilesSrc[isz]);
if ((c_aszRootFilesDst[isz] == c_szDstIFOUamInst) || (c_aszRootFilesDst[isz] == c_szDstRSCUamInst)) { WCHAR szTemp[MAX_PATH];
lstrcpyW(szTemp, pszPath); lstrcatW(szTemp, c_aszRootFilesDst[isz]); wsprintfW(szDstFile, szTemp, SzLoadIds(IDS_OC_SFM_UAM_INSTALLER)); } else { lstrcpyW(szDstFile, pszPath); lstrcatW(szDstFile, c_aszRootFilesDst[isz]); }
TraceTag(ttidNetOc, "MacFile: Copying %S to %S", szSrcFile, szDstFile);
if (!HrCopyFileAsStream(szSrcFile, szDstFile, FALSE)) { hr = HrFromLastWin32Error(); goto err; } } }
err: TraceError("HrSetupUAM", hr); return hr; }
|