//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: D H C P S O B J . C P P // // Contents: Implementation of the CDHCPServer notify object // // Notes: // // Author: jeffspr 31 May 1997 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "dhcpsobj.h" #include "ncerror.h" #include "ncperms.h" #include "ncreg.h" #include "ncsetup.h" #include "ncnetcfg.h" #include "ncipaddr.h" #include extern const WCHAR c_szInfId_MS_DHCPServer[]; extern const WCHAR c_szAfDhcpServerConfiguration[]; extern const WCHAR c_szAfDhcpServerParameters[]; //---[ Constants ]------------------------------------------------------------ static const WCHAR c_szDHCPServerServicePath[] = L"System\\CurrentControlSet\\Services\\DHCPServer"; static const WCHAR c_szDHCPServerParamPath[] = L"System\\CurrentControlSet\\Services\\DHCPServer\\Parameters"; static const WCHAR c_szDHCPServerConfigPath[] = L"System\\CurrentControlSet\\Services\\DHCPServer\\Configuration"; static const WCHAR c_szOptionInfo[] = L"OptionInfo"; static const WCHAR c_szSubnets[] = L"Subnets"; static const WCHAR c_szIpRanges[] = L"IpRanges"; static const WCHAR c_szSubnetOptions[] = L"SubnetOptions"; static const WCHAR c_szDHCPServerUnattendRegSection[] = L"DHCPServer_Unattend"; const WCHAR c_szStartIp[] = L"StartIp"; const WCHAR c_szEndIp[] = L"EndIp"; const WCHAR c_szSubnetMask[] = L"SubnetMask"; const WCHAR c_szLeaseDuration[] = L"LeaseDuration"; const WCHAR c_szDnsServer[] = L"DnsServer"; const WCHAR c_szDomainName[] = L"DomainName"; // Destructor // CDHCPServer::CDHCPServer() { // Initialize member variables. m_pnc = NULL; m_pncc = NULL; m_eInstallAction = eActUnknown; m_fUpgrade = FALSE; m_fUnattend = FALSE; } CDHCPServer::~CDHCPServer() { ReleaseObj(m_pncc); ReleaseObj(m_pnc); // Release KEY handles here. } // // INetCfgNotify // STDMETHODIMP CDHCPServer::Initialize( INetCfgComponent * pnccItem, INetCfg * pnc, BOOL fInstalling) { Validate_INetCfgNotify_Initialize(pnccItem, pnc, fInstalling); m_pncc = pnccItem; m_pnc = pnc; AssertSz(m_pncc, "m_pncc NULL in CDHCPServer::Initialize"); AssertSz(m_pnc, "m_pnc NULL in CDHCPServer::Initialize"); // Addref the config objects // AddRefObj(m_pncc); AddRefObj(m_pnc); return S_OK; } //+--------------------------------------------------------------------------- // // Function: HrRestoreRegistrySz // // Purpose: Restore a subkey from the specified file // // Arguments: // hkeyBase [in] handle of basekey // pszSubKey [in] subkey to restore // pszRegFile [in] name of file to restore from // // Returns: S_OK on success, otherwise an error code // // Author: kumarp 16-September-98 // // Notes: This should be moved to common code // HRESULT HrRestoreRegistrySz ( IN HKEY hkeyBase, IN PCWSTR pszSubKey, IN PCWSTR pszRegFile) { Assert(hkeyBase); AssertValidReadPtr(pszSubKey); AssertValidReadPtr(pszRegFile); HRESULT hr; HKEY hkey = NULL; DWORD dwDisp; TraceTag(ttidDHCPServer, "restoring subkey '%S' from file '%S'", pszSubKey, pszRegFile); hr = HrEnablePrivilege (SE_RESTORE_NAME); if (S_OK == hr) { // Ensure key is there by creating it // hr = HrRegCreateKeyEx (hkeyBase, pszSubKey, REG_OPTION_NON_VOLATILE, KEY_READ_WRITE_DELETE, NULL, &hkey, &dwDisp); if (S_OK == hr) { // Restore the old settings // hr = HrRegRestoreKey (hkey, pszRegFile, 0); RegCloseKey (hkey); } } TraceError ("HrRestoreRegistrySz", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CDHCPServer::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 CDHCPServer::HrRestoreRegistry() { HRESULT hr = S_OK; TraceTag(ttidDHCPServer, "CDHCPServer::HrRestoreRegistry()"); // If we have a "configuration" key restore file // if (!m_strConfigRestoreFile.empty()) { // We always want to continue, so ignore the return code // (void) HrRestoreRegistrySz(HKEY_LOCAL_MACHINE, c_szDHCPServerConfigPath, m_strConfigRestoreFile.c_str()); } else { TraceTag(ttidDHCPServer, "DHCP Server Params restore file doesn't exist"); } // If we have a params restore file // if (!m_strParamsRestoreFile.empty()) { // We always want to continue, so ignore the return code // (void) HrRestoreRegistrySz(HKEY_LOCAL_MACHINE, c_szDHCPServerParamPath, m_strParamsRestoreFile.c_str()); } else { TraceTag(ttidDHCPServer, "DHCP Server Params restore file doesn't exist"); } TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::HrRestoreRegistry"); return hr; } HRESULT CDHCPServer::HrWriteUnattendedKeys() { HRESULT hr = S_OK; HKEY hkeyService = NULL; const COMPONENT_INFO * pci = NULL; Assert(m_fUnattend); hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szDHCPServerServicePath, KEY_READ_WRITE_DELETE, &hkeyService); if (SUCCEEDED(hr)) { Assert(hkeyService); pci = PComponentInfoFromComponentId(c_szInfId_MS_DHCPServer); if (pci) { CSetupInfFile csif; // Open the answer file. hr = csif.HrOpen(pci->pszInfFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL); if (SUCCEEDED(hr)) { // Install the unattend params // hr = HrSetupInstallFromInfSection ( NULL, csif.Hinf(), c_szDHCPServerUnattendRegSection, SPINST_REGISTRY, hkeyService, NULL, NULL, NULL, NULL, NULL, NULL); } } RegCloseKey(hkeyService); } TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::HrWriteUnattendedKeys"); return hr; } //+--------------------------------------------------------------------------- // // Member: CDHCPServer::HrWriteDhcpOptionInfo // // Purpose: Write to the registry the Dhcp OptionInfo data. // // Arguments: // hkeyConfig // // Returns: S_OK if successful, Reg API error otherwise. // // Notes: // HRESULT CDHCPServer::HrWriteDhcpOptionInfo(HKEY hkeyConfig) { HRESULT hr; DWORD dwDisposition; HKEY hkeyOptionInfo = NULL; typedef struct { const WCHAR * pcszOptionKeyName; const WCHAR * pcszOptionName; const WCHAR * pcszOptionComment; DWORD dwOptionType; DWORD dwOptionId; DWORD cbBinData; DWORD * pdwBinData; } OIDATA; OIDATA OiData[2]; DWORD BinData006[] = {0x14, 0x4, 0x1, 0x0, 0x0}; DWORD BinData015[] = {0x18, 0x5, 0x1, 0x0, 0x2, 0x0}; OiData[0].pcszOptionKeyName = L"006"; OiData[0].pcszOptionName = SzLoadIds(IDS_DHCP_OPTION_006_NAME); // DNS Servers OiData[0].pcszOptionComment = SzLoadIds(IDS_DHCP_OPTION_006_COMMENT); // Array of DNS Servers, by preference OiData[0].dwOptionType = 0x1; OiData[0].dwOptionId = 0x6; OiData[0].cbBinData = celems(BinData006) * sizeof(BinData006[0]); OiData[0].pdwBinData = BinData006; OiData[1].pcszOptionKeyName = L"015"; OiData[1].pcszOptionName = SzLoadIds(IDS_DHCP_OPTION_015_NAME); // DNS Domain Name OiData[1].pcszOptionComment = SzLoadIds(IDS_DHCP_OPTION_015_COMMENT); // Domainname for client resolutions OiData[1].dwOptionType = 0x0; OiData[1].dwOptionId = 0xf; OiData[1].cbBinData = celems(BinData015) * sizeof(BinData015[0]); OiData[1].pdwBinData = BinData015; hr = ::HrRegCreateKeyEx(hkeyConfig, c_szOptionInfo, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hkeyOptionInfo, &dwDisposition); if (SUCCEEDED(hr)) { for (UINT idx=0; (idxHrGetString(pszAnswerSection, c_szSubnets, &strSubnet); if (SUCCEEDED(hr)) { hr = pcsif->HrGetString(pszAnswerSection, c_szStartIp, &strStartIp); if (SUCCEEDED(hr)) { hr = pcsif->HrGetString(pszAnswerSection, c_szEndIp, &str); if (SUCCEEDED(hr)) { DWORD dwEndIp = IpPszToHostAddr(str.c_str()); hr = pcsif->HrGetString(pszAnswerSection, c_szSubnetMask, &str); if (SUCCEEDED(hr)) { DWORD dwSubnetMask = IpPszToHostAddr(str.c_str()); hr = pcsif->HrGetString(pszAnswerSection, c_szDnsServer, &str); if (SUCCEEDED(hr)) { DWORD dwLeaseDuration; DWORD dwDnsServer = IpPszToHostAddr(str.c_str()); hr = pcsif->HrGetDword(pszAnswerSection, c_szLeaseDuration, &dwLeaseDuration); if (SUCCEEDED(hr)) { hr = pcsif->HrGetString(pszAnswerSection, c_szDomainName, &str); if (SUCCEEDED(hr) && lstrlenW(str.c_str())) { HKEY hkeyDhcpCfg = NULL; DWORD dwDisposition; // Write the registry data // hr = ::HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szDHCPServerConfigPath, REG_OPTION_NON_VOLATILE, KEY_READ_WRITE, NULL, &hkeyDhcpCfg, &dwDisposition); if (SUCCEEDED(hr)) { hr = HrWriteDhcpOptionInfo(hkeyDhcpCfg); if (SUCCEEDED(hr)) { hr = HrWriteDhcpSubnets(hkeyDhcpCfg, strSubnet.c_str(), strStartIp.c_str(), dwEndIp, dwSubnetMask, dwLeaseDuration, dwDnsServer, str.c_str()); } RegCloseKey(hkeyDhcpCfg); } } } } } } } } // If there are any params missing, so be it // if ((SPAPI_E_SECTION_NOT_FOUND == hr) || (SPAPI_E_LINE_NOT_FOUND == hr) || (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)) { hr = S_OK; } TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::HrProcessDhcpServerSolutionsParams"); return hr; } //+--------------------------------------------------------------------------- // // Member: CDHCPServer::HrProcessAnswerFile // // Purpose: Handles necessary processing of contents of the answer file. // // Arguments: // pszAnswerFile [in] Filename of answer file for upgrade. // pszAnswerSection [in] Answer file section in the // file appropriate to this component. // // Returns: S_OK if successful, setup API error otherwise. // // Author: jeffspr 8 May 1997 // // Notes: // HRESULT CDHCPServer::HrProcessAnswerFile ( IN PCWSTR pszAnswerFile, IN PCWSTR pszAnswerSection) { HRESULT hr = S_OK; CSetupInfFile csif; TraceTag(ttidDHCPServer, "CDHCPServer::HrProcessAnswerFile()"); // Open the answer file. hr = csif.HrOpen(pszAnswerFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL); if (FAILED(hr)) { TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::HrProcessAnswerFile -- HrOpen failed()"); 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_szAfDhcpServerParameters, &m_strParamsRestoreFile); if (FAILED(hr)) { TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::HrProcessAnswerFile - Error restoring " "Parameters key"); // oh well, just continue hr = S_OK; } // Get restore file for "Configuration" key hr = csif.HrGetString(pszAnswerSection, c_szAfDhcpServerConfiguration, &m_strConfigRestoreFile); if (FAILED(hr)) { TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::HrProcessAnswerFile - Error restoring " "Config key"); // oh well, just continue hr = S_OK; } // Server Solutions has some parameters that need to be plumbed into the registry // for their unattended install scenarios // hr = HrProcessDhcpServerSolutionsParams(&csif, pszAnswerSection); Exit: TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::HrProcessAnswerFile"); return hr; } STDMETHODIMP CDHCPServer::ReadAnswerFile( IN PCWSTR pszAnswerFile, IN PCWSTR pszAnswerSection) { HRESULT hr = S_OK; TraceTag(ttidDHCPServer, "CDHCPServer::ReadAnswerFile()"); // don't call Validate_INetCfgNotify_ReadAnswerFile here, as the netoc // installer for this will intentionally call it with NULL params. The // Validate macro actually causes a return E_INVALIDARG in this case. // We're being installed unattended // m_fUnattend = TRUE; TraceTag(ttidDHCPServer, "Answerfile: %S", pszAnswerFile ? pszAnswerFile : L""); TraceTag(ttidDHCPServer, "Answersection: %S", pszAnswerSection ? pszAnswerSection : L""); // If we're not already installed, do the work. // if (pszAnswerFile && pszAnswerSection) { // Process the actual answer file (read our sections) // hr = HrProcessAnswerFile(pszAnswerFile, pszAnswerSection); if (FAILED(hr)) { TraceHr(ttidDHCPServer, FAL, NETSETUP_E_ANS_FILE_ERROR, FALSE, "CDHCPServer::ReadAnswerFile - Answer file has errors. Defaulting " "all information as if answer file did not exist."); hr = S_OK; } } Validate_INetCfgNotify_ReadAnswerFile_Return(hr); TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::ReadAnswerFile"); return hr; } STDMETHODIMP CDHCPServer::Install(DWORD dwSetupFlags) { TraceTag(ttidDHCPServer, "CDHCPServer::Install()"); Validate_INetCfgNotify_Install(dwSetupFlags); m_eInstallAction = eActInstall; TraceTag(ttidDHCPServer, "dwSetupFlags = %d", dwSetupFlags); TraceTag(ttidDHCPServer, "NSF_WINNT_WKS_UPGRADE = %x", NSF_WINNT_WKS_UPGRADE); TraceTag(ttidDHCPServer, "NSF_WINNT_SVR_UPGRADE = %x", NSF_WINNT_SVR_UPGRADE); if ((NSF_WINNT_WKS_UPGRADE & dwSetupFlags) || (NSF_WINNT_SBS_UPGRADE & dwSetupFlags) || (NSF_WINNT_SVR_UPGRADE & dwSetupFlags)) { TraceTag(ttidDHCPServer, "This is indeed an upgrade"); m_fUpgrade = TRUE; } else { TraceTag(ttidDHCPServer, "This is NOT an upgrade"); } return S_OK; } STDMETHODIMP CDHCPServer::Removing() { m_eInstallAction = eActRemove; return S_OK; } STDMETHODIMP CDHCPServer::Validate() { return S_OK; } STDMETHODIMP CDHCPServer::CancelChanges() { return S_OK; } STDMETHODIMP CDHCPServer::ApplyRegistryChanges() { HRESULT hr = S_OK; TraceTag(ttidDHCPServer, "CDHCPServer::ApplyRegistryChanges()"); TraceTag(ttidDHCPServer, "ApplyRegistryChanges -- Unattend: %d", m_fUnattend); TraceTag(ttidDHCPServer, "ApplyRegistryChanges -- Upgrade: %d", m_fUpgrade); if (m_eInstallAction == eActInstall) { TraceTag(ttidDHCPServer, "ApplyRegistryChanges -- Installing"); // We used to only do this on upgrade, now we'll do it all the time. // If there's no answerfile info for the restore files, then we // won't do anything, and life will still be fine. // hr = HrRestoreRegistry(); if (FAILED(hr)) { TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::ApplyRegistryChanges - HrRestoreRegistry non-fatal error"); hr = S_OK; } if (m_fUnattend && !m_fUpgrade) { // I'm if 0'ing this out for now. All of this work was done to appease Ram Cherala // and whoever asked him to do the same for SP4. Now we're hearing from Ye Gu that // we don't even want this code on normal NT4/NT5. Who knows what the desire will // be in the future. // #if 0 hr = HrWriteUnattendedKeys(); if (FAILED(hr)) { TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::ApplyRegistryChanges - HrWriteUnattendedKeys non-fatal error"); hr = S_OK; } #endif } // Bug #153298: Mark as upgrade so DS info is upgraded if (m_fUpgrade) { DHCP_MARKUPG_ROUTINE pfnDhcpMarkUpgrade; HMODULE hmod; hr = HrLoadLibAndGetProc(L"dhcpssvc.dll", "DhcpMarkUpgrade", &hmod, (FARPROC *)&pfnDhcpMarkUpgrade); if (SUCCEEDED(hr)) { TraceTag(ttidDHCPServer, "Upgrading DS info..."); pfnDhcpMarkUpgrade(); FreeLibrary(hmod); } else { TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::ApplyRegistryChanges - Failed to upgrade DS info. Non-fatal"); hr = S_OK; } } } else if (m_eInstallAction == eActRemove) { TraceTag(ttidDHCPServer, "ApplyRegistryChanges -- removing"); // RAID #154380: Clean up DS before uninstalling { DHCP_CLEAR_DS_ROUTINE pfnDhcpDsClearHostServerEntries; HMODULE hmod; hr = HrLoadLibAndGetProc(L"dhcpsapi.dll", "DhcpDsClearHostServerEntries", &hmod, (FARPROC *)&pfnDhcpDsClearHostServerEntries); if (SUCCEEDED(hr)) { TraceTag(ttidDHCPServer, "Removing DS info..."); pfnDhcpDsClearHostServerEntries(); FreeLibrary(hmod); } else { TraceHr(ttidDHCPServer, FAL, hr, FALSE, "CDHCPServer::ApplyRegistryChanges - Failed to remove DS info. Non-fatal"); hr = S_OK; } } } Validate_INetCfgNotify_Apply_Return(hr); TraceHr(ttidDHCPServer, FAL, hr, (hr == S_FALSE), "CDHCPServer::ApplyRegistryChanges"); return hr; }