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.
 
 
 
 
 
 

1241 lines
36 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: util.cpp
//
// This file contains misc functions.
//
//--------------------------------------------------------------------------
#include "rshx32.h"
#include <shlobjp.h> // SHFree
#include <shlwapip.h> // IsOS
#include <safeboot.h> // SAFEBOOT_* flags
STDMETHODIMP
IDA_BindToFolder(LPIDA pIDA, LPSHELLFOLDER *ppsf)
{
HRESULT hr;
LPSHELLFOLDER psfDesktop;
TraceEnter(TRACE_UTIL, "IDA_BindToFolder");
TraceAssert(pIDA != NULL);
TraceAssert(ppsf != NULL);
*ppsf = NULL;
hr = SHGetDesktopFolder(&psfDesktop);
if (SUCCEEDED(hr))
{
LPCITEMIDLIST pidlFolder = (LPCITEMIDLIST)ByteOffset(pIDA, pIDA->aoffset[0]);
if (ILIsEmpty(pidlFolder))
{
// We're binding to the desktop
*ppsf = psfDesktop;
}
else
{
hr = psfDesktop->BindToObject(pidlFolder,
NULL,
IID_IShellFolder,
(PVOID*)ppsf);
psfDesktop->Release();
}
}
TraceLeaveResult(hr);
}
STDMETHODIMP
IDA_GetItemName(LPSHELLFOLDER psf,
LPCITEMIDLIST pidl,
LPTSTR pszName,
UINT cchName,
SHGNO uFlags)
{
STRRET str;
HRESULT hr;
hr = psf->GetDisplayNameOf(pidl, uFlags, &str);
if (SUCCEEDED(hr))
{
DWORD dwErr;
LPSTR psz;
switch (str.uType)
{
case STRRET_WSTR:
lstrcpyn(pszName, str.pOleStr, cchName);
//
// Since this string was alocated from the shell's IMalloc heap,
// we must free it to the same place.
//
SHFree(str.pOleStr);
break;
case STRRET_OFFSET:
psz = (LPSTR)ByteOffset(pidl, str.uOffset);
goto GetItemName_ANSI;
case STRRET_CSTR:
psz = str.cStr;
GetItemName_ANSI:
if (!MultiByteToWideChar(CP_ACP,
0,
psz,
-1,
pszName,
cchName))
{
dwErr = GetLastError();
hr = HRESULT_FROM_WIN32(dwErr);
}
break;
default:
hr = E_UNEXPECTED;
break;
}
}
return hr;
}
STDMETHODIMP
IDA_GetItemName(LPSHELLFOLDER psf,
LPCITEMIDLIST pidl,
LPTSTR *ppszName,
SHGNO uFlags)
{
TCHAR szName[MAX_PATH];
HRESULT hr = IDA_GetItemName(psf, pidl, szName, ARRAYSIZE(szName));
if (SUCCEEDED(hr))
hr = LocalAllocString(ppszName, szName);
else
*ppszName = NULL;
return hr;
}
//
// Helper functions used by DPA_CompareSecurityIntersection
//
BOOL
IsEqualSID(PSID pSid1, PSID pSid2)
{
//
// Are they both NULL?
//
if (pSid1 || pSid2)
{
//
// At least one is non-NULL, so if one is NULL then they can't
// be equal.
//
if (pSid1 == NULL || pSid2 == NULL)
return FALSE;
//
// Both are non-NULL. Check the SIDs.
//
if (!EqualSid(pSid1, pSid2))
return FALSE;
}
return TRUE;
}
BOOL
IsEqualACL(PACL pA1, PACL pA2)
{
//
// Are they both NULL?
//
if (pA1 || pA2)
{
//
// At least one is non-NULL, so if one is NULL then they can't
// be equal.
//
if (pA1 == NULL || pA2 == NULL)
return FALSE;
//
// At this point we know that both are non-NULL. Check the
// sizes and contents.
//
// could do a lot more here
if (pA1->AclSize != pA2->AclSize || memcmp(pA1, pA2, pA1->AclSize))
return FALSE;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: CompareSecurityDescriptors
//
// Synopsis: Determines if 2 security descriptors are identical. It does
// this by comparing control fields, owner/group, and acls.
//
// Arguments: [IN] pSD1 - 1st SD to compare
// [IN] pSD2 - 2nd SD to compare
// [OUT] pfOwnerConflict - (optional) Set to TRUE if the Owner SIDs are not equal
// [OUT] pfGroupConflict - (optional) Set to TRUE if the Group SIDs are not equal
// [OUT] pfDACLConflict - (optional) Set to TRUE if the DACLs are not equal
// [OUT] pfSACLConflict - (optional) Set to TRUE if the SACLs are not equal
//
// Returns: nothing
//
//
//----------------------------------------------------------------------------
#define DACL_CONTROL_MASK (SE_DACL_PRESENT | SE_DACL_DEFAULTED | SE_DACL_AUTO_INHERITED | SE_DACL_PROTECTED)
#define SACL_CONTROL_MASK (SE_SACL_PRESENT | SE_SACL_DEFAULTED | SE_SACL_AUTO_INHERITED | SE_SACL_PROTECTED)
void
CompareSecurityDescriptors(PSECURITY_DESCRIPTOR pSD1,
PSECURITY_DESCRIPTOR pSD2,
BOOL *pfOwnerConflict,
BOOL *pfGroupConflict,
BOOL *pfSACLConflict,
BOOL *pfDACLConflict)
{
PISECURITY_DESCRIPTOR pS1 = (PISECURITY_DESCRIPTOR)pSD1;
PISECURITY_DESCRIPTOR pS2 = (PISECURITY_DESCRIPTOR)pSD2;
//
// Are the pointers identical?
// This includes the case where both are NULL.
//
if (pS1 == pS2)
{
if (pfOwnerConflict)
*pfOwnerConflict = FALSE;
if (pfGroupConflict)
*pfGroupConflict = FALSE;
if (pfSACLConflict)
*pfSACLConflict = FALSE;
if (pfDACLConflict)
*pfDACLConflict = FALSE;
return;
}
//
// Is (only) one of them NULL? If so, then we can't compare so
// assume that nothing matches.
//
if (!pS1 || !pS2)
{
if (pfOwnerConflict)
*pfOwnerConflict = TRUE;
if (pfGroupConflict)
*pfGroupConflict = TRUE;
if (pfSACLConflict)
*pfSACLConflict = TRUE;
if (pfDACLConflict)
*pfDACLConflict = TRUE;
return;
}
//
// Owner
//
if (pfOwnerConflict)
{
if ((pS1->Control & SE_OWNER_DEFAULTED) != (pS2->Control & SE_OWNER_DEFAULTED))
{
*pfOwnerConflict = TRUE;
}
else
{
*pfOwnerConflict = !IsEqualSID(RtlpOwnerAddrSecurityDescriptor(pS1),
RtlpOwnerAddrSecurityDescriptor(pS2));
}
}
//
// Group
//
if (pfGroupConflict)
{
if ((pS1->Control & SE_GROUP_DEFAULTED) != (pS2->Control & SE_GROUP_DEFAULTED))
{
*pfGroupConflict = TRUE;
}
else
{
*pfGroupConflict = !IsEqualSID(RtlpGroupAddrSecurityDescriptor(pS1),
RtlpGroupAddrSecurityDescriptor(pS2));
}
}
//
// Sacl
//
if (pfSACLConflict)
{
if ((pS1->Control & SACL_CONTROL_MASK) != (pS2->Control & SACL_CONTROL_MASK))
{
*pfSACLConflict = TRUE;
}
else
{
*pfSACLConflict = !IsEqualACL(RtlpSaclAddrSecurityDescriptor(pS1),
RtlpSaclAddrSecurityDescriptor(pS2));
}
}
//
// Dacl
//
if (pfDACLConflict)
{
if ((pS1->Control & DACL_CONTROL_MASK) != (pS2->Control & DACL_CONTROL_MASK))
{
*pfDACLConflict = TRUE;
}
else
{
*pfDACLConflict = !IsEqualACL(RtlpDaclAddrSecurityDescriptor(pS1),
RtlpDaclAddrSecurityDescriptor(pS2));
}
}
}
/*******************************************************************
NAME: DPA_CompareSecurityIntersection
SYNOPSIS: Determines if the selected objects have
equivalent security descriptors
ENTRY: hItemList - DPA containing item names
pfnReadSD - callback function to read the Security Descriptor
for a single item.
pfOwnerConflict - (optional) Set to TRUE if not all Owner SIDs are equal
pfGroupConflict - (optional) Set to TRUE if not all Group SIDs are equal
pfDACLConflict - (optional) Set to TRUE if not all DACLs are equal
pfSACLConflict - (optional) Set to TRUE if not all SACLs are equal
ppszOwnerConflict - (optional) The name of the first item
with a different Owner is returned here.
Free with LocalFreeString.
ppszGroupConflict - (optional) similar to ppszOwnerConflict
ppszDaclConflict - (optional) similar to ppszOwnerConflict
ppszSaclConflict - (optional) similar to ppszOwnerConflict
ppszFailureMsg - Message to display in case of failure.
RETURNS: S_OK if successful, HRESULT error code otherwise
NOTES: The function may exit without checking all objects if all of
the requested flags become FALSE. All out parameters are
valid if the function succeeds, and undetermined otherwise.
HISTORY:
JeffreyS 18-Feb-1997 Created
********************************************************************/
STDMETHODIMP
DPA_CompareSecurityIntersection(HDPA hItemList,
PFN_READ_SD pfnReadSD,
BOOL *pfOwnerConflict,
BOOL *pfGroupConflict,
BOOL *pfSACLConflict,
BOOL *pfDACLConflict,
LPTSTR *ppszOwnerConflict,
LPTSTR *ppszGroupConflict,
LPTSTR *ppszSaclConflict,
LPTSTR *ppszDaclConflict,
LPTSTR *ppszFailureMsg,
LPBOOL pbCancel)
{
HRESULT hr = S_OK;
DWORD dwErr;
SECURITY_INFORMATION si = 0;
DWORD dwPriv = SE_SECURITY_PRIVILEGE;
HANDLE hToken = INVALID_HANDLE_VALUE;
LPTSTR pszItem;
LPTSTR pszFile;
PSECURITY_DESCRIPTOR pSD1 = NULL;
PSECURITY_DESCRIPTOR pSD2 = NULL;
int i;
#if DBG
DWORD dwTimeStart = GetTickCount();
#endif
TraceEnter(TRACE_UTIL, "DPA_CompareSecurityIntersection");
TraceAssert(hItemList != NULL);
TraceAssert(pfnReadSD != NULL);
if (pfOwnerConflict)
{
*pfOwnerConflict = FALSE;
si |= OWNER_SECURITY_INFORMATION;
}
if (pfGroupConflict)
{
*pfGroupConflict = FALSE;
si |= GROUP_SECURITY_INFORMATION;
}
if (pfSACLConflict)
{
*pfSACLConflict = FALSE;
// SeAuditPrivilege must be enabled to read the SACL.
hToken = EnablePrivileges(&dwPriv, 1);
if (INVALID_HANDLE_VALUE != hToken)
{
si |= SACL_SECURITY_INFORMATION;
}
else
{
// Leave *pfSACLConflict set to FALSE
pfSACLConflict = NULL;
TraceMsg("Security privilege not enabled -- not checking SACL");
}
}
if (pfDACLConflict)
{
*pfDACLConflict = FALSE;
si |= DACL_SECURITY_INFORMATION;
}
if (ppszOwnerConflict != NULL)
*ppszOwnerConflict = NULL;
if (ppszGroupConflict != NULL)
*ppszGroupConflict = NULL;
if (ppszSaclConflict != NULL)
*ppszSaclConflict = NULL;
if (ppszDaclConflict != NULL)
*ppszDaclConflict = NULL;
if (si == 0 || DPA_GetPtrCount(hItemList) < 2)
ExitGracefully(hr, S_OK, "Nothing requested or list contains only one item");
if (pbCancel && *pbCancel)
ExitGracefully(hr, S_OK, "DPA_CompareSecurityIntersection cancelled");
//
// Get the first item name and load its security descriptor.
//
pszItem = (LPTSTR)DPA_FastGetPtr(hItemList, 0);
if (NULL == pszItem)
ExitGracefully(hr, E_UNEXPECTED, "Item list is empty");
dwErr = (*pfnReadSD)(pszItem, si, &pSD1);
if (dwErr)
{
//Incase of multiple of selection, if we fail to read the security descriptor
//of single item, security page should be disabled.
LPTSTR pszSystemError = NULL;
LPTSTR pszFailureMsg = NULL;
if (GetSystemErrorText(&pszSystemError, dwErr))
{
//often last two chars are \r\n sequence which break our formatting.
DWORD dwLen = wcslen(pszSystemError);
if(dwLen >= 2 && pszSystemError[dwLen-2] == 0x0d && pszSystemError[dwLen-1] ==0x0a)
{
pszSystemError[dwLen-2] = 0;
}
FormatStringID(&pszFailureMsg, g_hInstance, IDS_MULTIPLE_SELECTION_READ_ERROR, pszItem, pszSystemError);
}
else
{
FormatStringID(&pszFailureMsg, g_hInstance, IDS_MULTIPLE_SELECTION_READ_ERROR_1, pszItem);
}
*ppszFailureMsg = pszFailureMsg;
ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "Unable to read Security Descriptor");
}
//
// Go through the rest of the list and compare their security
// descriptors to the first one.
//
for (i = 1; i < DPA_GetPtrCount(hItemList) && si != 0; i++)
{
if (pbCancel && *pbCancel)
ExitGracefully(hr, S_OK, "DPA_CompareSecurityIntersection cancelled");
pszItem = (LPTSTR)DPA_FastGetPtr(hItemList, i);
if (NULL == pszItem)
ExitGracefully(hr, E_UNEXPECTED, "Unable to retrieve item name from list");
dwErr = (*pfnReadSD)(pszItem, si, &pSD2);
if (dwErr)
{
//Incase of multiple of selection, if we fail to read the security descriptor
//of single item, security page should be disabled.
LPTSTR pszSystemError = NULL;
LPTSTR pszFailureMsg = NULL;
if (GetSystemErrorText(&pszSystemError, dwErr))
{
//often last two chars are \r\n sequence which break our formatting.
DWORD dwLen = wcslen(pszSystemError);
if(dwLen >= 2 && pszSystemError[dwLen-2] == 0x0d && pszSystemError[dwLen-1] ==0x0a)
{
pszSystemError[dwLen-2] = 0;
}
FormatStringID(&pszFailureMsg, g_hInstance, IDS_MULTIPLE_SELECTION_READ_ERROR, pszItem, pszSystemError);
}
else
{
FormatStringID(&pszFailureMsg, g_hInstance, IDS_MULTIPLE_SELECTION_READ_ERROR_1, pszItem);
}
*ppszFailureMsg = pszFailureMsg;
ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "Unable to read Security Descriptor");
}
CompareSecurityDescriptors(pSD1,
pSD2,
pfOwnerConflict,
pfGroupConflict,
pfSACLConflict,
pfDACLConflict);
if (pSD2 != NULL)
{
LocalFree(pSD2);
pSD2 = NULL;
}
//
// Get the leaf name of the item to return as the conflict name
//
pszFile = PathFindFileName(pszItem);
if (!pszFile)
pszFile = pszItem;
// If we find an owner that doesn't match, we can stop checking owners
if (pfOwnerConflict && *pfOwnerConflict)
{
pfOwnerConflict = NULL;
si &= ~OWNER_SECURITY_INFORMATION;
if (ppszOwnerConflict)
LocalAllocString(ppszOwnerConflict, pszFile);
}
// Ditto for the group
if (pfGroupConflict && *pfGroupConflict)
{
pfGroupConflict = NULL;
si &= ~GROUP_SECURITY_INFORMATION;
if (ppszGroupConflict)
LocalAllocString(ppszGroupConflict, pszFile);
}
// Same for SACLs
if (pfSACLConflict && *pfSACLConflict)
{
pfSACLConflict = NULL;
si &= ~SACL_SECURITY_INFORMATION;
if (ppszSaclConflict)
LocalAllocString(ppszSaclConflict, pszFile);
}
// Same for DACLs
if (pfDACLConflict && *pfDACLConflict)
{
pfDACLConflict = NULL;
si &= ~DACL_SECURITY_INFORMATION;
if (ppszDaclConflict)
LocalAllocString(ppszDaclConflict, pszFile);
}
}
exit_gracefully:
// Release any privileges we enabled
ReleasePrivileges(hToken);
if (FAILED(hr))
{
LocalFreeString(ppszOwnerConflict);
LocalFreeString(ppszGroupConflict);
LocalFreeString(ppszSaclConflict);
LocalFreeString(ppszDaclConflict);
}
if (pSD1 != NULL)
LocalFree(pSD1);
#if DBG
Trace((TEXT("DPA_CompareSecurityIntersection done: %d"), GetTickCount() - dwTimeStart));
#endif
TraceLeaveResult(hr);
}
//*************************************************************
//
// GetRemotePath
//
// Purpose: Return UNC version of a path
//
// Parameters: pszInName - initial path
// ppszOutName - UNC path returned here
//
//
// Return: HRESULT
// S_OK - UNC path returned
// S_FALSE - drive not connected (UNC not returned)
// or failure code
//
// Notes: The function fails is the path is not a valid
// network path. If the path is already UNC,
// a copy is made without validating the path.
// *ppszOutName must be LocalFree'd by the caller.
//
//*************************************************************
DWORD _WNetGetConnection(LPCTSTR pszLocal, LPTSTR pszRemote, LPDWORD pdwLen)
{
DWORD dwErr = ERROR_PROC_NOT_FOUND;
// This is the only function we call in mpr.dll, and it's delay-loaded
// so wrap it with SEH.
__try
{
dwErr = WNetGetConnection(pszLocal, pszRemote, pdwLen);
}
__finally
{
}
return dwErr;
}
STDMETHODIMP
GetRemotePath(LPCTSTR pszInName, LPTSTR *ppszOutName)
{
HRESULT hr = HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME);
TraceEnter(TRACE_UTIL, "GetRemotePath");
TraceAssert(pszInName);
TraceAssert(ppszOutName);
*ppszOutName = NULL;
if (pszInName[1] == TEXT(':'))
{
DWORD dwErr;
TCHAR szLocalName[3];
TCHAR szRemoteName[MAX_PATH];
DWORD dwLen = ARRAYSIZE(szRemoteName);
szLocalName[0] = pszInName[0];
szLocalName[1] = pszInName[1];
szLocalName[2] = TEXT('\0');
dwErr = _WNetGetConnection(szLocalName, szRemoteName, &dwLen);
if (NO_ERROR == dwErr)
{
hr = S_OK;
dwLen = lstrlen(szRemoteName);
}
else if (ERROR_NOT_CONNECTED == dwErr)
{
ExitGracefully(hr, S_FALSE, "Drive not connected");
}
else if (ERROR_MORE_DATA != dwErr)
ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "WNetGetConnection failed");
// if dwErr == ERROR_MORE_DATA, dwLen already has the correct value
// Skip the drive letter and add the length of the rest of the path
// (including NULL)
pszInName += 2;
DWORD dwOutputLen = dwLen + lstrlen(pszInName) + 1;
// We should never get incomplete paths, so we should always
// see a backslash after the "X:". If this isn't true, then
// we should call GetFullPathName above.
TraceAssert(TEXT('\\') == *pszInName);
// Allocate the return buffer
*ppszOutName = (LPTSTR)LocalAlloc(LPTR, dwOutputLen * SIZEOF(TCHAR));
if (!*ppszOutName)
ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
if (ERROR_MORE_DATA == dwErr)
{
// Try again with the bigger buffer
dwErr = _WNetGetConnection(szLocalName, *ppszOutName, &dwLen);
hr = HRESULT_FROM_WIN32(dwErr);
FailGracefully(hr, "WNetGetConnection failed");
}
else
{
// WNetGetConnection succeeded. Copy the result
lstrcpy(*ppszOutName, szRemoteName);
}
// Copy the rest of the path
hr = StringCchCat(*ppszOutName,dwOutputLen,pszInName);
}
else if (PathIsUNC(pszInName))
{
// Just copy the path without validating it
hr = LocalAllocString(ppszOutName, pszInName);
}
exit_gracefully:
if (FAILED(hr))
{
LocalFreeString(ppszOutName);
}
else
{
if(*ppszOutName)
{
//Trailing backshash causes IsShareRoot to fail.
//NTRAID#NTBUG9-533576-2002/05/06-hiteshr
PathRemoveBackslash(*ppszOutName);
}
}
TraceLeaveResult(hr);
}
/*******************************************************************
NAME: LocalFreeDPA
SYNOPSIS: LocalFree's all pointers in a Dynamic Pointer
Array and then frees the DPA.
ENTRY: hList - handle of list to destroy
RETURNS: nothing
********************************************************************/
int CALLBACK
_LocalFreeCB(LPVOID pVoid, LPVOID /*pData*/)
{
if (pVoid)
LocalFree(pVoid);
return 1;
}
void
LocalFreeDPA(HDPA hList)
{
if (hList != NULL)
DPA_DestroyCallback(hList, _LocalFreeCB, 0);
}
//+---------------------------------------------------------------------------
//
// Function: IsSafeMode
//
// Synopsis: Checks the registry to see if the system is in safe mode.
//
// History: 06-Oct-00 JeffreyS Created
//
//----------------------------------------------------------------------------
BOOL
IsSafeMode(void)
{
BOOL fIsSafeMode = FALSE;
LONG ec;
HKEY hkey;
ec = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option"),
0,
KEY_QUERY_VALUE,
&hkey
);
if (ec == NO_ERROR)
{
DWORD dwValue;
DWORD dwValueSize = sizeof(dwValue);
ec = RegQueryValueEx(hkey,
TEXT("OptionValue"),
NULL,
NULL,
(LPBYTE)&dwValue,
&dwValueSize);
if (ec == NO_ERROR)
{
fIsSafeMode = (dwValue == SAFEBOOT_MINIMAL || dwValue == SAFEBOOT_NETWORK);
}
RegCloseKey(hkey);
}
return fIsSafeMode;
}
//+---------------------------------------------------------------------------
//
// Function: IsGuestAccessMode
//
// Synopsis: Checks the registry to see if the system is using the
// Guest-only network access mode.
//
// History: 06-Oct-00 JeffreyS Created
// 19-Apr-00 GPease Modified and changed name
//
//----------------------------------------------------------------------------
BOOL
IsForcedGuestModeOn(void)
{
BOOL fIsForcedGuestModeOn = FALSE;
if (IsOS(OS_PERSONAL))
{
// Guest mode is always on for Personal
fIsForcedGuestModeOn = TRUE;
}
else if (IsOS(OS_PROFESSIONAL) && !IsOS(OS_DOMAINMEMBER))
{
LONG ec;
HKEY hkey;
// Professional, not in a domain. Check the ForceGuest value.
ec = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Control\\LSA"),
0,
KEY_QUERY_VALUE,
&hkey
);
if (ec == NO_ERROR)
{
DWORD dwValue;
DWORD dwValueSize = sizeof(dwValue);
ec = RegQueryValueEx(hkey,
TEXT("ForceGuest"),
NULL,
NULL,
(LPBYTE)&dwValue,
&dwValueSize);
if (ec == NO_ERROR && 1 == dwValue)
{
fIsForcedGuestModeOn = TRUE;
}
RegCloseKey(hkey);
}
}
return fIsForcedGuestModeOn;
}
//+---------------------------------------------------------------------------
//
// Function: IsSimpleUI
//
// Synopsis: Checks whether to show the simple version of the UI.
//
// History: 06-Oct-00 JeffreyS Created
// 19-Apr-00 GPease Removed CTRL key check
//
//----------------------------------------------------------------------------
BOOL
IsSimpleUI(void)
{
// Show old UI in safe mode and anytime network access involves
// true user identity (server, pro with GuestMode off).
// Show simple UI anytime network access is done using the Guest
// account (personal, pro with GuestMode on) except in safe mode.
return (!IsSafeMode() && IsForcedGuestModeOn());
}
HRESULT BindToObjectEx(IShellFolder *psf, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
{
HRESULT hr;
IShellFolder *psfRelease = NULL;
if (!psf)
{
hr = SHGetDesktopFolder(&psf);
if(SUCCEEDED(hr))
{
psfRelease = psf;
}
}
if (psf)
{
if (!pidl || ILIsEmpty(pidl))
{
hr = psf->QueryInterface(riid, ppv);
}
else
{
hr = psf->BindToObject(pidl, pbc, riid, ppv);
}
}
else
{
*ppv = NULL;
hr = E_FAIL;
}
if (psfRelease)
{
psfRelease->Release();
}
if (SUCCEEDED(hr) && (*ppv == NULL))
{
// Some shell extensions (eg WS_FTP) will return success and a null out pointer
hr = E_FAIL;
}
return hr;
}
LPITEMIDLIST ILCloneParent(LPCITEMIDLIST pidl)
{
LPITEMIDLIST pidlParent = ILClone(pidl);
if (pidlParent)
ILRemoveLastID(pidlParent);
return pidlParent;
}
// psfRoot is the base of the bind. If NULL, then we use the shell desktop.
// If you want to bind relative to the explorer root (e.g., CabView, MSN),
// then use SHBindToIDListParent.
HRESULT BindToFolderIDListParent(IShellFolder *psfRoot, LPCITEMIDLIST pidl, REFIID riid, void **ppv, LPCITEMIDLIST *ppidlLast)
{
HRESULT hr;
// Old shell32 code in some cases simply whacked the pidl,
// but this is unsafe. Do what shdocvw does and clone/remove:
//
LPITEMIDLIST pidlParent = ILCloneParent(pidl);
if (pidlParent)
{
hr = BindToObjectEx(psfRoot, pidlParent, NULL, riid, ppv);
ILFree(pidlParent);
}
else
hr = E_OUTOFMEMORY;
if (ppidlLast)
*ppidlLast = ILFindLastID(pidl);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: IsUIHiddenByPrivacyPolicy
//
// Synopsis: Checks if Security Tab is hidden by privacy policy
// NTRAID#NTBUG9-223899-2001/03/06-hiteshr
// History: 06-March-01 hiteshr Created
//
//----------------------------------------------------------------------------
BOOL
IsUIHiddenByPrivacyPolicy(void)
{
BOOL fIsUIHiddenByPrivacyPolicy = FALSE;
LONG ec;
HKEY hkey = NULL;
ec = RegOpenKeyEx(HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"),
0,
KEY_QUERY_VALUE,
&hkey
);
if (ec == NO_ERROR)
{
DWORD dwValue = 0;
DWORD dwValueSize = sizeof(dwValue);
ec = RegQueryValueEx(hkey,
TEXT("NoSecurityTab"),
NULL,
NULL,
(LPBYTE)&dwValue,
&dwValueSize);
if (ec == NO_ERROR && 1 == dwValue)
{
fIsUIHiddenByPrivacyPolicy = TRUE;
}
RegCloseKey(hkey);
}
return fIsUIHiddenByPrivacyPolicy;
}
//+----------------------------------------------------------------------------
// Function:SetAclOnRemoteNetworkDrive
// Synopsis: If Z: is a mapped drive( mapped to \\machineA\share), when
// we set DACL/SACL on Z:, Security API's cannot determine
// the parent of "share" on machineA and so we lose all the
// inherited aces. All UI can do is to detect such cases and
// show a warning. Thats what this function does.
// Arguments:hItemList List of items on which security is going to be set
// si: SECURITY_INFORMATION
// pSD: Security Descriptor to be set
// hWndPopupOwner: Owner window for message box
// Returns:
//-----------------------------------------------------------------------------
BOOL SetAclOnRemoteNetworkDrive(HDPA hItemList,
SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR pSD,
HWND hWndPopupOwner)
{
if(!hItemList || !pSD)
{
ASSERT(hItemList);
ASSERT(pSD);
return FALSE;
}
//We care only about DACL and SACL
if(!(si & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)))
{
return TRUE;
}
SECURITY_DESCRIPTOR_CONTROL Control = 0;
DWORD dwRevision = 0;
//Check if DACL or SACL is protected
if(!GetSecurityDescriptorControl(pSD,&Control,&dwRevision))
{
return FALSE;
}
//If inheritance is prevented for this object,there is no loss of inheritance
//so we are fine
if( ((si & DACL_SECURITY_INFORMATION) && (Control & SE_DACL_PROTECTED)) ||
((si & SACL_SECURITY_INFORMATION) && (Control & SE_SACL_PROTECTED)))
{
return TRUE;
}
LPTSTR pszPath = (LPTSTR)DPA_FastGetPtr(hItemList, 0);
int nMsgId = (si & DACL_SECURITY_INFORMATION) ? IDS_SET_PERM_ON_NETWORK_DRIVE : IDS_SET_SACL_ON_NETWORK_DRIVE;
//Ok, this is a remote network drive, display Warning.
//We display only one warning per list
if (IDNO == MsgPopup(hWndPopupOwner,
MAKEINTRESOURCE(nMsgId),
MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
MB_YESNO|MB_DEFBUTTON2| MB_ICONWARNING | MB_SETFOREGROUND,
g_hInstance,
pszPath))
{
return FALSE;
}
return TRUE;
}
//+----------------------------------------------------------------------------
// Function:GetSystemPaths
// Synopsis:Extract the value for environment variables SystemDrive
// and SystemRoot
//-----------------------------------------------------------------------------
void
GetSystemPaths(LPWSTR * ppszSystemDrive,
LPWSTR * ppszSystemRoot)
{
static WCHAR szSystemDrive[] = L"%SystemDrive%";
static WCHAR szSystemRoot[] = L"%SystemRoot%";
do
{
//Get SystemDrive
DWORD dwLen = ExpandEnvironmentStrings(szSystemDrive,
NULL,
0);
if(dwLen)
{
//dwLen contains space for NULL char. 1 is added for "\".
//SystemDrive is in format C:, while we want in the format C:"\"
DWORD dwArrayLen = dwLen + 1;
*ppszSystemDrive = (LPWSTR)LocalAlloc(LPTR,dwArrayLen*sizeof(WCHAR));
if(!*ppszSystemDrive)
break;
dwLen = ExpandEnvironmentStrings(szSystemDrive,
*ppszSystemDrive,
dwArrayLen);
if(!dwLen)
{
LocalFree(*ppszSystemDrive);
*ppszSystemDrive = NULL;
}
else
{
HRESULT hr = StringCchCat(*ppszSystemDrive,
dwArrayLen,
L"\\");
if(FAILED(hr))
{
ASSERT(SUCCEEDED(hr));
LocalFree(*ppszSystemDrive);
*ppszSystemDrive = NULL;
}
}
}
//Get SystemRoot
dwLen = ExpandEnvironmentStrings(szSystemRoot,
NULL,
0);
if(dwLen)
{
*ppszSystemRoot = (LPWSTR)LocalAlloc(LPTR,dwLen*sizeof(WCHAR));
if(!*ppszSystemRoot)
break;
dwLen = ExpandEnvironmentStrings(szSystemRoot,
*ppszSystemRoot,
dwLen);
if(!dwLen)
{
ASSERT(dwLen);
LocalFree(*ppszSystemRoot);
*ppszSystemRoot = NULL;
}
}
}while(0);
}
//+----------------------------------------------------------------------------
// Function:SetAclOnSystemPaths
// Synopsis:changing acl of SystemDrive or on or under SystemRoot results in
// problem. This function detects if user is changing acl on these
// system folder and shows appropriate warning.
// Returns: TRUE if its fine to set ACL , FALSE if not.
//-----------------------------------------------------------------------------
BOOL SetAclOnSystemPaths(HDPA hItemList,
LPCWSTR pszSystemDrive,
LPCWSTR pszSystemRoot,
SECURITY_INFORMATION si,
HWND hWndPopupOwner)
{
if(!hItemList)
{
ASSERT(hItemList);
return FALSE;
}
//We care only about DACL
if(!(si & DACL_SECURITY_INFORMATION))
{
return TRUE;
}
DWORD dwLenSystemRoot = 0;
if(pszSystemRoot)
{
dwLenSystemRoot = (DWORD)wcslen(pszSystemRoot);
}
//Now Check each item in hItemList
for (int i = 0; i < DPA_GetPtrCount(hItemList); i++)
{
LPTSTR pszPath = (LPTSTR)DPA_FastGetPtr(hItemList, i);
if(!pszPath)
continue;
//Check for system drive
if(pszSystemDrive &&
CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT,
0,
pszSystemDrive,
-1,
pszPath,
-1))
{
if (IDNO == MsgPopup(hWndPopupOwner,
MAKEINTRESOURCE(IDS_ACL_ON_SYSTEMROOT),
MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
MB_YESNO|MB_DEFBUTTON2| MB_ICONWARNING | MB_SETFOREGROUND,
g_hInstance))
{
return FALSE;
}
break;
}
//Check if its under systemroot
DWORD dwlenPath = wcslen(pszPath);
if(dwLenSystemRoot && (dwlenPath >= dwLenSystemRoot) &&
(CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT,
NORM_IGNORECASE,
pszSystemRoot,
dwLenSystemRoot,
pszPath,
dwLenSystemRoot)))
{
if (IDNO == MsgPopup(hWndPopupOwner,
MAKEINTRESOURCE(IDS_ACL_ON_UNDER_SYSTEM_DRIVE),
MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
MB_YESNO|MB_DEFBUTTON2| MB_ICONWARNING | MB_SETFOREGROUND,
g_hInstance))
{
return FALSE;
}
break;
}
}
return TRUE;
}