//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: util.cpp // // This file contains misc functions. // //-------------------------------------------------------------------------- #include "rshx32.h" #include // SHFree #include // IsOS #include // 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; }