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.
 
 
 
 
 
 

842 lines
25 KiB

//+---------------------------------------------------------------------------
//
// 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;
}