|
|
//
// N W C L I O B J . C P P
//
// Implementation of the CNWClient notify object model
//
#include "pch.h"
#pragma hdrstop
#include "ncerror.h"
#include "ncperms.h"
#include "ncreg.h"
#include "ncsetup.h"
#include "ncsvc.h"
#include "nwcliobj.h"
#include <ncshell.h>
extern const WCHAR c_szAfNWCWorkstationParameters[]; extern const WCHAR c_szAfNWCWorkstationShares[]; extern const WCHAR c_szAfNWCWorkstationDrives[]; extern const WCHAR c_szInfId_MS_NWIPX[]; extern const WCHAR c_szInfId_MS_Server[];
//---[ Constants ]-------------------------------------------------------------
static const WCHAR c_szNWClientParamPath[] = L"System\\CurrentControlSet\\Services\\NWCWorkstation\\Parameters"; static const WCHAR c_szNWClientSharesPath[] = L"System\\CurrentControlSet\\Services\\NWCWorkstation\\Shares"; static const WCHAR c_szNWClientDrivesPath[] = L"System\\CurrentControlSet\\Services\\NWCWorkstation\\Drives"; static const WCHAR c_szLMServerParamPath[] = L"System\\CurrentControlSet\\Services\\LanmanServer\\Parameters"; static const WCHAR c_szLMServerLinkagePath[] = L"System\\CurrentControlSet\\Services\\LanmanServer\\Linkage"; static const WCHAR c_szEnableSharedNetDrives[] = L"EnableSharedNetDrives"; static const WCHAR c_szOtherDependencies[] = L"OtherDependencies"; static const WCHAR c_szGWEnabledValue[] = L"GatewayEnabled";
extern const WCHAR c_szSvcLmServer[]; // L"LanmanServer";
extern const WCHAR c_szSvcNWCWorkstation[]; // L"NWCWorkstation";
HRESULT HrRefreshEntireNetwork(); HRESULT HrGetEntireNetworkPidl(LPITEMIDLIST *ppidlFolder);
//
// Constructor
//
CNWClient::CNWClient() { // Initialize member variables.
m_pnc = NULL; m_pncc = NULL; m_eInstallAction = eActUnknown; m_hlibConfig = NULL; m_fUpgrade = FALSE;
// Get the product flavor (PF_WORKSTATION or PF_SERVER). Use this
// to decide whether or not we need to install the "server" component.
//
GetProductFlavor(NULL, &m_pf); }
CNWClient::~CNWClient() { ReleaseObj(m_pncc); ReleaseObj(m_pnc);
// Release KEY handles here.
}
//
// INetCfgNotify
//
STDMETHODIMP CNWClient::Initialize( INetCfgComponent * pnccItem, INetCfg* pnc, BOOL fInstalling) { Validate_INetCfgNotify_Initialize(pnccItem, pnc, fInstalling);
TraceTag(ttidNWClientCfg, "CNWClient::Initialize");
m_pncc = pnccItem; m_pnc = pnc;
AssertSz(m_pncc, "m_pncc NULL in CNWClient::Initialize"); AssertSz(m_pnc, "m_pnc NULL in CNWClient::Initialize");
// Addref the config objects
//
AddRefObj(m_pncc); AddRefObj(m_pnc);
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CNWClient::HrRestoreRegistry
//
// Purpose: Restores the contents of the registry for this component
//
// Arguments:
// (none)
//
// Returns: Win32 error if failed, otherwise S_OK
//
// Author: jeffspr 13 Aug 1997
//
// Notes:
//
HRESULT CNWClient::HrRestoreRegistry() { HRESULT hr = S_OK; HKEY hkey = NULL; TOKEN_PRIVILEGES * ptpRestore = NULL; DWORD dwDisp = 0; static const WCHAR c_szSvcDLLName[] = L"%SystemRoot%\\System32\\nwwks.dll"; static const WCHAR c_szServiceDll[] = L"ServiceDll";
TraceTag(ttidNWClientCfg, "CNWClient::HrRestoreRegistry");
if (!m_strParamsRestoreFile.empty() || !m_strDrivesRestoreFile.empty() || !m_strSharesRestoreFile.empty()) { hr = HrEnableAllPrivileges(&ptpRestore); }
if (SUCCEEDED(hr) && !m_strParamsRestoreFile.empty()) { // Ensure key is there by creating it
hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szNWClientParamPath, 0, KEY_ALL_ACCESS, NULL, &hkey, &dwDisp); if (SUCCEEDED(hr)) { hr = HrRegRestoreKey(hkey, m_strParamsRestoreFile.c_str(), 0); if (FAILED(hr)) { TraceError("CNWClient::HrRestoreRegistry - HrRestoreRegistry for " "Parameters", hr); hr = S_OK; }
//
// Bug 182442. HrRegRestoreKey above overwrites the ServiceDll value added
// from the inf file. So, we manually save it.
//
hr = HrRegSetValueEx(hkey, c_szServiceDll, REG_EXPAND_SZ, (const BYTE *)c_szSvcDLLName, (wcslen(c_szSvcDLLName) + 1) * sizeof(WCHAR)); if (FAILED(hr)) { TraceError("CNWClient::HrRestoreRegistry - HrRestoreRegistry for " "ServiceDll", hr); hr = S_OK; }
RegCloseKey(hkey); hkey = NULL; } }
if (!m_strSharesRestoreFile.empty()) { // Ensure key is there by creating it
hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szNWClientSharesPath, 0, KEY_ALL_ACCESS, NULL, &hkey, &dwDisp); if (SUCCEEDED(hr)) { hr = HrRegRestoreKey(hkey, m_strSharesRestoreFile.c_str(), 0); if (FAILED(hr)) { TraceError("CNWClient::HrRestoreRegistry - HrRestoreRegistry for " "Shares", hr); hr = S_OK; }
RegCloseKey(hkey); hkey = NULL; } }
if (!m_strDrivesRestoreFile.empty()) { // Ensure key is there by creating it
hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szNWClientDrivesPath, 0, KEY_ALL_ACCESS, NULL, &hkey, &dwDisp); if (SUCCEEDED(hr)) { hr = HrRegRestoreKey(hkey, m_strDrivesRestoreFile.c_str(), 0); if (FAILED(hr)) { TraceError("CNWClient::HrRestoreRegistry - HrRestoreRegistry for " "Drives", hr); hr = S_OK; }
RegCloseKey(hkey); hkey = NULL; } }
if (ptpRestore) { hr = HrRestorePrivileges(ptpRestore);
delete [] reinterpret_cast<BYTE *>(ptpRestore); }
TraceError("CNWClient::HrRestoreRegistry", hr); return hr; }
static const WCHAR c_szDefaultLocation[] = L"DefaultLocation"; static const WCHAR c_szDefaultScriptOptions[] = L"DefaultScriptOptions";
HRESULT CNWClient::HrWriteAnswerFileParams() { HRESULT hr = S_OK;
TraceTag(ttidNWClientCfg, "CNWClient::HrWriteAnswerFileParams");
// Don't do anything if we don't have anything to write to the
// registry
if (!m_strDefaultLocation.empty() || (m_dwLogonScript != 0xFFFFFFFF)) { HKEY hkey; DWORD dwDisp;
// Ensure key is there by creating it
hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szNWClientParamPath, 0, KEY_ALL_ACCESS, NULL, &hkey, &dwDisp); if (SUCCEEDED(hr)) { if (!m_strDefaultLocation.empty()) { hr = HrRegSetString(hkey, c_szDefaultLocation, m_strDefaultLocation); if (FAILED(hr)) { TraceError("CNWClient::HrWriteAnswerFileParams - Couldn't" " set DefaultLocation", hr); hr = S_OK; } }
if (m_dwLogonScript != 0xFFFFFFFF) { // 0x3 is combination of the following:
//
// #define NW_LOGONSCRIPT_DISABLED 0x00000000
// #define NW_LOGONSCRIPT_ENABLED 0x00000001
// #define NW_LOGONSCRIPT_4X_ENABLED 0x00000002
//
hr = HrRegSetDword(hkey, c_szDefaultScriptOptions, m_dwLogonScript ? 0x3 : 0x0); if (FAILED(hr)) { TraceError("CNWClient::HrWriteAnswerFileParams - Couldn't" " set DefaultLocation", hr); hr = S_OK; } }
RegCloseKey(hkey); } }
TraceError("CNWClient::HrWriteAnswerFileParams", hr); return hr; }
static const WCHAR c_szPreferredServer[] = L"PreferredServer"; static const WCHAR c_szDefaultTree[] = L"DefaultTree"; static const WCHAR c_szDefaultContext[] = L"DefaultContext"; static const WCHAR c_szLogonScript[] = L"LogonScript";
//+---------------------------------------------------------------------------
//
// Member: CNWClient::HrProcessAnswerFile
//
// Purpose: Handles necessary processing of contents of the answer file.
//
// Arguments:
// pszAnswerFile [in] Filename of answer file for upgrade.
// pszAnswerSection [in] Comma-separated list of sections in the
// file appropriate to this component.
//
// Returns: S_OK if successful, setup API error otherwise.
//
// Author: jeffspr 8 May 1997
//
// Notes:
//
HRESULT CNWClient::HrProcessAnswerFile( PCWSTR pszAnswerFile, PCWSTR pszAnswerSection) { HRESULT hr; CSetupInfFile csif;
TraceTag(ttidNWClientCfg, "CNWClient::HrProcessAnswerFile");
// Open the answer file.
hr = csif.HrOpen(pszAnswerFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL); if (FAILED(hr)) { hr = S_OK; goto Exit; }
// Restore portions of the registry based on file names from the answer
// file
// Get restore file for "Parameters" key
hr = csif.HrGetString(pszAnswerSection, c_szAfNWCWorkstationParameters, &m_strParamsRestoreFile); if (FAILED(hr)) { TraceError("CNWClient::HrProcessAnswerFile - Error restoring " "Parameters key", hr);
// oh well, just continue
hr = S_OK; }
// Get restore file for "Shares" key
hr = csif.HrGetString(pszAnswerSection, c_szAfNWCWorkstationShares, &m_strSharesRestoreFile); if (FAILED(hr)) { TraceError("CNWClient::HrProcessAnswerFile - Error restoring " "Shares key", hr);
// oh well, just continue
hr = S_OK; }
// Get restore file for "Drives" key
hr = csif.HrGetString(pszAnswerSection, c_szAfNWCWorkstationDrives, &m_strDrivesRestoreFile); if (FAILED(hr)) { TraceError("CNWClient::HrProcessAnswerFile - Error restoring " "Drives key", hr);
// oh well, just continue
hr = S_OK; }
//
// Read answer file parameters (these are all optional so no errors are
// saved)
//
TraceTag(ttidNWClientCfg, "Reading PreferredServer from answer file");
// Read contents of PreferredServer key.
if (FAILED(csif.HrGetString(pszAnswerSection, c_szPreferredServer, &m_strDefaultLocation))) { // Couldn't read PreferredServer key, so we must assume that the other
// two values are present
tstring strDefaultTree; tstring strDefaultContext;
TraceTag(ttidNWClientCfg, "PreferredServer not found so trying " "DefaultTree and DefaultContext instead");
// Read contents of DefaultTree key.
if (SUCCEEDED(csif.HrGetString(pszAnswerSection, c_szDefaultTree, &strDefaultTree))) { TraceTag(ttidNWClientCfg, "Got DefaultTree ok: %S", strDefaultTree.c_str());
// Read contents of DefaultContext key.
hr = csif.HrGetString(pszAnswerSection, c_szDefaultContext, &strDefaultContext); if (SUCCEEDED(hr)) { TraceTag(ttidNWClientCfg, "Got DefaultContext ok: %S", strDefaultContext.c_str());
// Munge the DefaultLocation value with the DefaultTree and
// DefaultContext values read from the answer file
m_strDefaultLocation = L"*"; m_strDefaultLocation += strDefaultTree; m_strDefaultLocation += L"\\"; m_strDefaultLocation += strDefaultContext;
TraceTag(ttidNWClientCfg, "DefaultLocation is: %S", m_strDefaultLocation.c_str()); } else { TraceError("CNWClient::HrProcessAnswerFile - error reading " "DefaultContext", hr); hr = S_OK; } } } else { TraceTag(ttidNWClientCfg, "DefaultLocation is: %S", m_strDefaultLocation.c_str()); }
// Init to impossible value so we know whether we read it or not
m_dwLogonScript = 0xFFFFFFFF;
// Read contents of LogonScript key.
(VOID) csif.HrGetStringAsBool(pszAnswerSection, c_szLogonScript, reinterpret_cast<BOOL *>(&m_dwLogonScript));
TraceTag(ttidNWClientCfg, "LogonScript is: %ld", m_dwLogonScript);
Exit: TraceError("CNWClient::HrProcessAnswerFile", hr); return hr; }
STDMETHODIMP CNWClient::Upgrade(DWORD dwSetupFlags, DWORD dwUpgradeFromBuildNo) { return S_FALSE; }
STDMETHODIMP CNWClient::ReadAnswerFile(PCWSTR pszAnswerFile, PCWSTR pszAnswerSection) { Validate_INetCfgNotify_ReadAnswerFile(pszAnswerFile, pszAnswerSection);
TraceTag(ttidNWClientCfg, "CNWClient::ReadAnswerFile");
m_eInstallAction = eActInstall;
// If we're not already installed, do the work.
//
if (pszAnswerFile && pszAnswerSection) { HRESULT hr = HrProcessAnswerFile(pszAnswerFile, pszAnswerSection); if (FAILED(hr)) { TraceError("CNWClient::NetworkInstall - Answer file has errors. Defaulting " "all information as if answer file did not exist.", hr); } }
return S_OK; }
STDMETHODIMP CNWClient::Install(DWORD dw) { Validate_INetCfgNotify_Install(dw);
TraceTag(ttidNWClientCfg, "CNWClient::Install");
m_eInstallAction = eActInstall;
// Install the NWLink sub-component
HRESULT hr = HrInstallComponentOboComponent(m_pnc, NULL, GUID_DEVCLASS_NETTRANS, c_szInfId_MS_NWIPX, m_pncc, NULL); if (SUCCEEDED(hr)) { // If we're NT Server, we DO need to install it, as what we're
// installing is GSNW, not CSNW (and therefore, since we're sharing
// resources, we need to use the server service)
//
if (PF_SERVER == m_pf) { NETWORK_INSTALL_PARAMS nip;
nip.dwSetupFlags = dw; nip.dwUpgradeFromBuildNo = -1; nip.pszAnswerFile = NULL; nip.pszAnswerSection = NULL;
// Install Server
hr = HrInstallComponentOboComponent(m_pnc, &nip, GUID_DEVCLASS_NETSERVICE, c_szInfId_MS_Server, m_pncc, NULL); } }
TraceError("CNWClient::Install", hr); return hr; }
STDMETHODIMP CNWClient::Removing() { TraceTag(ttidNWClientCfg, "CNWClient::Removing");
m_eInstallAction = eActRemove;
// Remove the NWLink service
//
HRESULT hr = HrRemoveComponentOboComponent(m_pnc, GUID_DEVCLASS_NETTRANS, c_szInfId_MS_NWIPX, m_pncc);
if (SUCCEEDED(hr)) { if (PF_SERVER == m_pf) { // Remove our reference of the Server service
//
hr = HrRemoveComponentOboComponent(m_pnc, GUID_DEVCLASS_NETSERVICE, c_szInfId_MS_Server, m_pncc); } }
if (hr == NETCFG_S_STILL_REFERENCED) { // If services are still in use, that's OK, I just needed to make
// sure that I released my reference.
//
hr = S_OK; }
Validate_INetCfgNotify_Removing_Return(hr);
TraceError("CNWClient::Removing()", hr); return hr; }
STDMETHODIMP CNWClient::Validate() { return S_OK; }
STDMETHODIMP CNWClient::CancelChanges() { return S_OK; }
STDMETHODIMP CNWClient::ApplyRegistryChanges() { HRESULT hr = S_OK;
TraceTag(ttidNWClientCfg, "CNWClient::ApplyRegistryChanges");
if (m_eInstallAction == eActRemove) { hr = HrRemoveCodeFromOldINF(); } else if (m_eInstallAction == eActInstall) { hr = HrRestoreRegistry(); if (FAILED(hr)) { TraceError("CNWClient::ApplyRegistryChanges - HrRestoreRegistry non-fatal error", hr); hr = S_OK; }
hr = HrWriteAnswerFileParams(); if (FAILED(hr)) { TraceError("CNWClient::ApplyRegistryChanges - HrWriteAnswerFileParams " "non-fatal error", hr); hr = S_OK; }
// If gateway is enabled, modify lanmanserver appropriately
// Ignore the return code other than to trace it.
//
hr = HrEnableGatewayIfNeeded(); if (FAILED(hr)) { TraceError("CNWClient::ApplyRegistryChanges - HrEnableGatewayIfNeeded non-fatal error", hr); }
hr = HrInstallCodeFromOldINF(); }
Validate_INetCfgNotify_Apply_Return(hr);
TraceError("CNWClient::ApplyRegistryChanges", (hr == S_FALSE) ? S_OK : hr); return hr; }
STDMETHODIMP CNWClient::ApplyPnpChanges ( INetCfgPnpReconfigCallback* pICallback) { HRESULT hr;
hr = HrRefreshEntireNetwork();
if (FAILED(hr)) { TraceError("CNWClient::ApplyPnpChanges - HrRefreshEntireNetwork" "non-fatal error", hr); hr = S_OK; }
// GlennC can't do the work to make NW Client PnP so we're forced to
// prompt for a reboot for any change.
//
return NETCFG_S_REBOOT; }
// Note -- Don't convert this to a constant. We need copies of it within the
// functions because ParseDisplayName actually mangles the string.
//
#define ENTIRE_NETWORK_PATH L"::{208D2C60-3AEA-1069-A2D7-08002B30309D}\\EntireNetwork"
//+---------------------------------------------------------------------------
//
// Function: HrGetEntireNetworkPidl
//
// Purpose: Get the pidl for "Entire Network". Used in places where we're
// not folder specific, but we still need to update folder
// entries.
//
// Arguments:
// ppidlFolder [out] Return parameter for the folder pidl
//
// Returns:
//
// Author: anbrad 08 Jun 1999
// jeffspr 13 Jun 1998
//
// Notes:
//
HRESULT HrGetEntireNetworkPidl(LPITEMIDLIST *ppidlFolder) { HRESULT hr = S_OK; LPSHELLFOLDER pshf = NULL; LPITEMIDLIST pidlFolder = NULL;
Assert(ppidlFolder);
WCHAR szEntireNetworkPath[] = ENTIRE_NETWORK_PATH;
// Get the desktop folder, so we can parse the display name and get
// the UI object of the connections folder
//
hr = SHGetDesktopFolder(&pshf); if (SUCCEEDED(hr)) { ULONG chEaten;
hr = pshf->ParseDisplayName(NULL, 0, (WCHAR *) szEntireNetworkPath, &chEaten, &pidlFolder, NULL);
ReleaseObj(pshf); }
// If succeeded, fill in the return param.
//
if (SUCCEEDED(hr)) { *ppidlFolder = pidlFolder; } else { // If we failed, then delete the pidl if we already got it.
//
if (pidlFolder) SHFree(pidlFolder); }
TraceHr(ttidNWClientCfg, FAL, hr, FALSE, "HrGetEntireNetworkPidl"); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrRefreshEntireNetwork
//
// Purpose: Update the "Entire Network" portion of the shell due to
// the addition of a new networking client (NWClient)
//
// Arguments:
// (none)
//
// Returns:
//
// Author: anbrad 08 Jun 1999
//
// Notes:
//
HRESULT HrRefreshEntireNetwork() { HRESULT hr = S_OK; HCURSOR hcWait = SetCursor(LoadCursor(NULL, IDC_WAIT)); LPITEMIDLIST pidlFolder = NULL;;
hr = HrGetEntireNetworkPidl(&pidlFolder);
// If we now have a pidl, send the GenerateEvent to update the item
//
if (SUCCEEDED(hr)) { Assert(pidlFolder); // SHCNE_UPDATEDIR?ITEM
GenerateEvent(SHCNE_UPDATEDIR, pidlFolder, NULL, NULL); }
if (hcWait) { SetCursor(hcWait); }
if (pidlFolder) { SHFree(pidlFolder); }
TraceHr(ttidError, FAL, hr, FALSE, "HrRefreshEntireNetwork"); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrEnableGatewayIfNeeded
//
// Purpose: Update the Lanman dependencies, if appropriate (meaning if
// gateway is enabled).
//
// Arguments:
// (none)
//
// Returns:
//
// Author: jeffspr 19 Aug 1999
//
// Notes:
//
HRESULT CNWClient::HrEnableGatewayIfNeeded() { HRESULT hr = S_OK; HKEY hKey = NULL; DWORD dwValue = 0; CServiceManager sm; CService svc;
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szNWClientParamPath, KEY_READ, &hKey); if (FAILED(hr)) { TraceError("Couldn't open NWClient param key", hr); goto Exit; }
hr = HrRegQueryDword(hKey, c_szGWEnabledValue, &dwValue); if (FAILED(hr)) { if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { TraceError("Couldn't query the GWEnabled Value", hr); goto Exit; } else { dwValue = 0; } } else { // Normalize to bool
//
dwValue = !!dwValue; }
RegSafeCloseKey(hKey); hKey = NULL;
// If there are gateway services present, then add the dependencies
// to LanmanServer
//
if (dwValue > 0) { // Set the value in the registry for the server paramaters.
//
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szLMServerParamPath, KEY_WRITE, &hKey); if (SUCCEEDED(hr)) { hr = HrRegSetDword(hKey, c_szEnableSharedNetDrives, dwValue);
RegSafeCloseKey(hKey); hKey = NULL; }
hr = sm.HrOpen(); if (SUCCEEDED(hr)) { hr = sm.HrOpenService(&svc, c_szSvcLmServer, NO_LOCK); if (SUCCEEDED(hr)) { // Add dependency of NWC Workstation to Server
//
hr = sm.HrAddServiceDependency(c_szSvcLmServer, c_szSvcNWCWorkstation);
if (SUCCEEDED(hr)) { hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szLMServerLinkagePath, KEY_READ | KEY_WRITE, &hKey); if (SUCCEEDED(hr)) { // Add the "OtherDependencies" to LanmanServer for legacy reasons
//
hr = HrRegAddStringToMultiSz(c_szSvcNWCWorkstation, hKey, NULL, c_szOtherDependencies, STRING_FLAG_ENSURE_AT_END | STRING_FLAG_DONT_MODIFY_IF_PRESENT, 0);
RegSafeCloseKey(hKey); hKey = NULL; } } } else { TraceError("Failed to open LanmanServer service for dependency mods", hr); } } else { TraceError("Failed to open service control manager", hr); } }
Exit: TraceHr(ttidNWClientCfg, FAL, hr, FALSE, "HrEnableGatewayIfNeeded"); return hr; }
|