WindowsXP-SP1/shell/ext/shgina/dllreg.cpp
2020-09-30 16:53:49 +02:00

511 lines
16 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1999.
//
// File: DllReg.cpp
//
// Contents: automatic registration and unregistration
//
//----------------------------------------------------------------------------
#include "priv.h"
#include "resource.h"
#include <advpub.h> // for REGINSTALL
#include <sddl.h> // for string security descriptor stuff
#include <shfusion.h>
#include <MSGinaExports.h>
#include <ntlsa.h>
// prototypes
STDAPI DllRegisterServer(void);
STDAPI DllUnregisterServer(void);
STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine);
//
// Calls the ADVPACK entry-point which executes an inf
// file section.
//
HRESULT CallRegInstall(HINSTANCE hinstFTP, LPSTR szSection)
{
UNREFERENCED_PARAMETER(hinstFTP);
HRESULT hr = E_FAIL;
HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
if (hinstAdvPack)
{
REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall");
if (pfnri)
{
char szThisDLL[MAX_PATH];
// Get the location of this DLL from the HINSTANCE
if (GetModuleFileNameA(HINST_THISDLL, szThisDLL, ARRAYSIZE(szThisDLL)))
{
STRENTRY seReg[] = {
{"THISDLL", szThisDLL },
{ "25", "%SystemRoot%" }, // These two NT-specific entries
{ "11", "%SystemRoot%\\system32" }, // must be at the end of the table
};
STRTABLE stReg = {ARRAYSIZE(seReg) - 2, seReg};
hr = pfnri(HINST_THISDLL, szSection, &stReg);
}
}
FreeLibrary(hinstAdvPack);
}
return hr;
}
HRESULT UnregisterTypeLibrary(const CLSID* piidLibrary)
{
HRESULT hr = E_FAIL;
TCHAR szGuid[GUIDSTR_MAX];
HKEY hk;
// convert the libid into a string.
//
SHStringFromGUID(*piidLibrary, szGuid, ARRAYSIZE(szGuid));
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("TypeLib"), 0, MAXIMUM_ALLOWED, &hk) == ERROR_SUCCESS)
{
if (SHDeleteKey(hk, szGuid))
{
// success
hr = S_OK;
}
RegCloseKey(hk);
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
HRESULT RegisterTypeLibrary(const CLSID* piidLibrary)
{
HRESULT hr = E_FAIL;
ITypeLib* pTypeLib;
WCHAR wszModuleName[MAX_PATH];
// Load and register our type library.
if (GetModuleFileNameW(HINST_THISDLL, wszModuleName, ARRAYSIZE(wszModuleName)))
{
hr = LoadTypeLib(wszModuleName, &pTypeLib);
if (SUCCEEDED(hr))
{
// call the unregister type library in case we had some old junk in the registry
UnregisterTypeLibrary(piidLibrary);
hr = RegisterTypeLib(pTypeLib, wszModuleName, NULL);
if (FAILED(hr))
{
TraceMsg(TF_WARNING, "RegisterTypeLibrary: RegisterTypeLib failed (%x)", hr);
}
pTypeLib->Release();
}
else
{
TraceMsg(TF_WARNING, "RegisterTypeLibrary: LoadTypeLib failed (%x) on", hr);
}
}
return hr;
}
BOOL SetDacl(LPTSTR pszTarget, SE_OBJECT_TYPE seType, LPCTSTR pszStringSD)
{
BOOL bResult;
PSECURITY_DESCRIPTOR pSD;
bResult = ConvertStringSecurityDescriptorToSecurityDescriptor(pszStringSD,
SDDL_REVISION_1,
&pSD,
NULL);
if (bResult)
{
PACL pDacl;
BOOL bPresent;
BOOL bDefault;
bResult = GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefault);
if (bResult)
{
DWORD dwErr;
dwErr = SetNamedSecurityInfo(pszTarget,
seType,
DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION,
NULL,
NULL,
pDacl,
NULL);
if (ERROR_SUCCESS != dwErr)
{
SetLastError(dwErr);
bResult = FALSE;
}
}
LocalFree(pSD);
}
return bResult;
}
STDAPI DllRegisterServer(void)
{
HRESULT hr;
HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL")); // keep advpack loaded across multiple calls to RegInstall
hr = CallRegInstall(HINST_THISDLL, "ShellUserOMInstall");
ASSERT(SUCCEEDED(hr));
// Grant Authenticated Users the right to create subkeys under the Hints key.
// This is so non-admins can change their own hint.
SetDacl(TEXT("MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Hints"),
SE_REGISTRY_KEY,
TEXT("D:(A;;0x4;;;AU)")); // 0x4 = KEY_CREATE_SUB_KEY
hr = RegisterTypeLibrary(&LIBID_SHGINALib);
ASSERT(SUCCEEDED(hr));
if (hinstAdvPack)
{
FreeLibrary(hinstAdvPack);
}
return hr;
}
STDAPI DllUnregisterServer(void)
{
return S_OK;
}
//
// This will be going away when we have resource based manifests
//
STDAPI SHSquirtManifest(HINSTANCE hInst, UINT uIdManifest, LPTSTR pszPath)
{
HRESULT hr = E_FAIL;
char szManifest[2048];
if (LoadStringA(hInst, uIdManifest, szManifest, ARRAYSIZE(szManifest)))
{
HANDLE hFile;
SetFileAttributes(pszPath, FILE_ATTRIBUTE_NORMAL);
hFile = CreateFile(pszPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD dw = lstrlenA(szManifest) * sizeof(char);
if (WriteFile(hFile, szManifest, dw, &dw, NULL))
{
hr = S_OK;
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
CloseHandle(hFile);
}
}
return hr;
}
void DoFusion()
{
// First, get the path to explorer.exe.
TCHAR szManifest[MAX_PATH];
GetSystemDirectory(szManifest, ARRAYSIZE(szManifest)); // e.g. c:\winnt\system32
// Tack on logonui.exe.maniest
StrCat(szManifest, TEXT("\\logonui.exe.manifest"));
// Extract the fusion manifest from the resource.
SHSquirtManifest(HINST_THISDLL, IDS_LOGONUIMANIFEST, szManifest);
GetSystemDirectory(szManifest, ARRAYSIZE(szManifest)); // e.g. c:\winnt\system32
// Tack on WindowsLogon.maniest
StrCat(szManifest, TEXT("\\WindowsLogon.manifest"));
// Extract the fusion manifest from the resource.
SHSquirtManifest(HINST_THISDLL, IDS_WINLOGONMANIFEST, szManifest);
}
//
// End going away....
//
// --------------------------------------------------------------------------
// IsLogonTypePresent
//
// Arguments: hKey = HKEY to HKLM\SW\MS\WINNT\CV\Winlogon.
//
// Returns: bool
//
// Purpose: Returns whether the value "LogonType" is present. This helps
// determines upgrade cases.
//
// History: 2000-09-04 vtan created
// --------------------------------------------------------------------------
bool IsLogonTypePresent (HKEY hKey)
{
DWORD dwType, dwLogonType, dwLogonTypeSize;
dwLogonTypeSize = sizeof(dwLogonType);
return((ERROR_SUCCESS == RegQueryValueEx(hKey,
TEXT("LogonType"),
NULL,
&dwType,
reinterpret_cast<LPBYTE>(&dwLogonType),
&dwLogonTypeSize)) &&
(REG_DWORD == dwType));
}
// --------------------------------------------------------------------------
// IsDomainMember
//
// Arguments: <none>
//
// Returns: bool
//
// Purpose: Is this machine a member of a domain? Use the LSA to get this
// information.
//
// History: 1999-09-14 vtan created
// 2000-09-04 vtan copied from msgina
// --------------------------------------------------------------------------
bool IsDomainMember (void)
{
bool fResult;
int iCounter;
NTSTATUS status;
OBJECT_ATTRIBUTES objectAttributes;
LSA_HANDLE lsaHandle;
SECURITY_QUALITY_OF_SERVICE securityQualityOfService;
PPOLICY_DNS_DOMAIN_INFO pDNSDomainInfo;
fResult = false;
securityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
securityQualityOfService.ImpersonationLevel = SecurityImpersonation;
securityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
securityQualityOfService.EffectiveOnly = FALSE;
InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);
objectAttributes.SecurityQualityOfService = &securityQualityOfService;
iCounter = 0;
do
{
status = LsaOpenPolicy(NULL, &objectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &lsaHandle);
if (RPC_NT_SERVER_TOO_BUSY == status)
{
Sleep(10);
}
} while ((RPC_NT_SERVER_TOO_BUSY == status) && (++iCounter < 10));
ASSERTMSG(iCounter < 10, "Abandoned advapi32!LsaOpenPolicy call - counter limit exceeded\r\n");
if (NT_SUCCESS(status))
{
status = LsaQueryInformationPolicy(lsaHandle, PolicyDnsDomainInformation, reinterpret_cast<void**>(&pDNSDomainInfo));
if (NT_SUCCESS(status) && (pDNSDomainInfo != NULL))
{
fResult = ((pDNSDomainInfo->DnsDomainName.Length != 0) ||
(pDNSDomainInfo->DnsForestName.Length != 0) ||
(pDNSDomainInfo->Sid != NULL));
(NTSTATUS)LsaFreeMemory(pDNSDomainInfo);
}
(NTSTATUS)LsaClose(lsaHandle);
}
return(fResult);
}
// --------------------------------------------------------------------------
// IsDomainMembershipAttempted
//
// Arguments: hKey = HKEY to HKLM\SW\MS\WINNT\CV\Winlogon.
//
// Returns: bool
//
// Purpose: Returns whether a domain join was attempt (success or failure)
// during network install.
//
// History: 2000-09-04 vtan created
// --------------------------------------------------------------------------
bool IsDomainMembershipAttempted (HKEY hKey)
{
DWORD dwType, dwRunNetAccessWizardType, dwRunNetAccessWizardTypeSize;
dwRunNetAccessWizardTypeSize = sizeof(dwRunNetAccessWizardType);
return((ERROR_SUCCESS == RegQueryValueEx(hKey,
TEXT("RunNetAccessWizard"),
NULL,
&dwType,
reinterpret_cast<LPBYTE>(&dwRunNetAccessWizardType),
&dwRunNetAccessWizardTypeSize)) &&
(REG_DWORD == dwType) &&
((NAW_PSDOMAINJOINED == dwRunNetAccessWizardType) || (NAW_PSDOMAINJOINFAILED == dwRunNetAccessWizardType)));
}
// --------------------------------------------------------------------------
// IsPersonal
//
// Arguments: <none>
//
// Returns: bool
//
// Purpose: Returns whether this product is personal.
//
// History: 2000-09-04 vtan created
// --------------------------------------------------------------------------
bool IsPersonal (void)
{
return(IsOS(OS_PERSONAL) != FALSE);
}
// --------------------------------------------------------------------------
// IsProfessional
//
// Arguments: <none>
//
// Returns: bool
//
// Purpose: Returns whether this product is professional.
//
// History: 2000-09-04 vtan created
// --------------------------------------------------------------------------
bool IsProfessional (void)
{
return(IsOS(OS_PROFESSIONAL) != FALSE);
}
// --------------------------------------------------------------------------
// IsServer
//
// Arguments: <none>
//
// Returns: bool
//
// Purpose: Returns whether this product is server.
//
// History: 2000-09-04 vtan created
// --------------------------------------------------------------------------
bool IsServer (void)
{
return(!IsPersonal() && !IsProfessional());
}
// --------------------------------------------------------------------------
// SetDefaultLogonType
//
// Arguments: ulWizardType = Type of network access configured during setup.
//
// Returns: <none>
//
// Purpose: Sets the default logon type based on network settings. In this case the
// machine is still on a workgroup and therefore will have all
// consumer UI enabled by default. Because join domain was
// requested the logon type is set to classic GINA.
//
// History: 2000-03-14 vtan created
// 2000-07-24 vtan turn on FUS by default
// 2000-09-04 vtan moved from winlogon to shgina
// --------------------------------------------------------------------------
void SetDefaultLogonType (void)
{
HKEY hKeyWinlogon;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
0,
KEY_QUERY_VALUE,
&hKeyWinlogon))
{
// Any of the following cause the logon type to be defaulted
// which means that the value is NOT written to the registry:
//
// 1. Value already present (this is an upgrade).
// 2. Machine is a domain member (this is not supported).
// 3. Machine attempted to join a domain (this indicates security).
// 4. The product is a server
//
// Otherwise the product is either personal or professional and
// the machine was joined to a workgroup or is a member of a workgroup
// and therefore requires the friendly UI.
if (!IsLogonTypePresent(hKeyWinlogon) &&
!IsDomainMember() &&
!IsDomainMembershipAttempted(hKeyWinlogon) &&
!IsServer())
{
MEMORYSTATUSEX memoryStatusEx;
TBOOL(ShellEnableFriendlyUI(TRUE));
// Multiple users used to be enabled when the friendly UI was
// enabled. However, on 64Mb machines the experience is
// unsatisfactory. Disable it on 64Mb or lower machines.
memoryStatusEx.dwLength = sizeof(memoryStatusEx);
GlobalMemoryStatusEx(&memoryStatusEx);
TBOOL(ShellEnableMultipleUsers((memoryStatusEx.ullTotalPhys / (1024 * 1024) > 64)));
}
TW32(RegCloseKey(hKeyWinlogon));
}
}
STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
{
HRESULT hr = S_OK;
if (bInstall)
{
DoFusion();
ShellInstallAccountFilterData();
#ifdef _X86_
SetDefaultLogonType();
#endif
}
return(hr);
}