|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 2001
//
// File: admin.cpp
//
// Authors;
// Jeff Saathoff (jeffreys)
//
// Notes;
// Support for Administratively pinned folders
//--------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "strings.h"
DWORD WINAPI _PinAdminFoldersThread(LPVOID);
//*************************************************************
//
// ApplyAdminFolderPolicy
//
// Purpose: Pin the admin folder list
//
// Parameters: none
//
// Return: none
//
// Notes:
//
//*************************************************************
void ApplyAdminFolderPolicy(void) { BOOL bNoNet = FALSE; CSCIsServerOffline(NULL, &bNoNet); if (!bNoNet) { SHCreateThread(_PinAdminFoldersThread, NULL, CTF_COINIT | CTF_FREELIBANDEXIT, NULL); } }
//
// Does a particular path exist in the DPA of path strings?
//
BOOL ExistsAPF( HDPA hdpa, LPCTSTR pszPath ) { const int cItems = DPA_GetPtrCount(hdpa); for (int i = 0; i < cItems; i++) { LPCTSTR pszItem = (LPCTSTR)DPA_GetPtr(hdpa, i); if (pszItem && (0 == lstrcmpi(pszItem, pszPath))) return TRUE; } return FALSE; }
BOOL ReadAPFFromRegistry(HDPA hdpaFiles) { const HKEY rghkeyRoots[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
for (int i = 0; i < ARRAYSIZE(rghkeyRoots); i++) { HKEY hKey;
// Read in the Administratively pinned folder list.
if (ERROR_SUCCESS == RegOpenKeyEx(rghkeyRoots[i], c_szRegKeyAPF, 0, KEY_QUERY_VALUE, &hKey)) { TCHAR szName[MAX_PATH]; DWORD dwIndex = 0, dwSize = ARRAYSIZE(szName);
while (ERROR_SUCCESS == _RegEnumValueExp(hKey, dwIndex, szName, &dwSize, NULL, NULL, NULL, NULL)) { if (!ExistsAPF(hdpaFiles, szName)) { LPTSTR pszDup; if (LocalAllocString(&pszDup, szName)) { if (-1 == DPA_AppendPtr(hdpaFiles, pszDup)) { LocalFreeString(&pszDup); } } }
dwSize = ARRAYSIZE(szName); dwIndex++; } RegCloseKey(hKey); } }
return TRUE; }
BOOL BuildFRList(HDPA hdpaFiles) { HKEY hKey;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), 0, KEY_QUERY_VALUE, &hKey)) { TCHAR szName[MAX_PATH]; DWORD cchName = ARRAYSIZE(szName); TCHAR szValue[MAX_PATH]; DWORD cbValue = sizeof(szValue); DWORD dwIndex = 0;
while (ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szName, &cchName, NULL, NULL, (LPBYTE)szValue, &cbValue)) { LPTSTR pszUNC = NULL;
GetRemotePath(szValue, &pszUNC);
if (pszUNC) { if (-1 == DPA_AppendPtr(hdpaFiles, pszUNC)) { LocalFreeString(&pszUNC); } }
cchName = ARRAYSIZE(szName); cbValue = sizeof(szValue); dwIndex++; } RegCloseKey(hKey); }
return TRUE; }
BOOL ReconcileAPF(HDPA hdpaPin, HDPA hdpaUnpin) { HKEY hKey; int cItems; int i;
//
// First, try to convert everything to UNC
//
cItems = DPA_GetPtrCount(hdpaPin); for (i = 0; i < cItems; i++) { LPTSTR pszItem = (LPTSTR)DPA_GetPtr(hdpaPin, i); if (!PathIsUNC(pszItem)) { LPTSTR pszUNC = NULL;
GetRemotePath(pszItem, &pszUNC); if (pszUNC) { DPA_SetPtr(hdpaPin, i, pszUNC); LocalFree(pszItem); } } }
// Read in the previous Administratively pinned folder list for this user.
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegKeyAPFResult, 0, KEY_QUERY_VALUE, &hKey)) { TCHAR szName[MAX_PATH]; DWORD dwIndex = 0, dwSize = ARRAYSIZE(szName);
while (ERROR_SUCCESS == _RegEnumValueExp(hKey, dwIndex, szName, &dwSize, NULL, NULL, NULL, NULL)) { if (!ExistsAPF(hdpaPin, szName)) { LPTSTR pszDup = NULL;
// This one is not in the new list, save it in the Unpin list
if (LocalAllocString(&pszDup, szName)) { if (-1 == DPA_AppendPtr(hdpaUnpin, pszDup)) { LocalFreeString(&pszDup); } } }
dwSize = ARRAYSIZE(szName); dwIndex++; }
RegCloseKey(hKey); }
// Save out the new admin pin list for this user
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, c_szRegKeyAPFResult, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL)) { // Add reg entries from the Pin list
cItems = DPA_GetPtrCount(hdpaPin); for (i = 0; i < cItems; i++) { DWORD dwValue = 0; RegSetValueEx(hKey, (LPCTSTR)DPA_GetPtr(hdpaPin, i), 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue)); }
// Remove reg entries from the Unpin list
cItems = DPA_GetPtrCount(hdpaUnpin); for (i = 0; i < cItems; i++) { RegDeleteValue(hKey, (LPCTSTR)DPA_GetPtr(hdpaUnpin, i)); }
RegCloseKey(hKey); }
return TRUE; }
DWORD WINAPI _AdminFillCallback(LPCTSTR /*pszName*/, DWORD /*dwStatus*/, DWORD /*dwHintFlags*/, DWORD /*dwPinCount*/, LPWIN32_FIND_DATA /*pFind32*/, DWORD /*dwReason*/, DWORD /*dwParam1*/, DWORD /*dwParam2*/, DWORD_PTR /*dwContext*/) { if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0)) return CSCPROC_RETURN_ABORT;
return CSCPROC_RETURN_CONTINUE; }
void _DoAdminPin(LPCTSTR pszItem, LPWIN32_FIND_DATA pFind32) { DWORD dwHintFlags = 0;
TraceEnter(TRACE_ADMINPIN, "_DoAdminPin");
if (!pszItem || !*pszItem) TraceLeaveVoid();
TraceAssert(PathIsUNC(pszItem));
// This may fail, for example if the file is not in the cache
CSCQueryFileStatus(pszItem, NULL, NULL, &dwHintFlags);
// Is the admin flag already turned on?
if (!(dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN)) { //
// Pin the item
//
if (CSCPinFile(pszItem, dwHintFlags | FLAG_CSC_HINT_PIN_ADMIN, NULL, NULL, &dwHintFlags)) { ShellChangeNotify(pszItem, pFind32, FALSE); } }
//
// Make sure files are filled.
//
// Yes, this takes longer, and isn't necessary if you stay logged
// on, since the CSC agent fills everything in the background.
//
// However, JDP's are using this with laptop pools, and for
// people who logon just to get the latest stuff, then immediately
// disconnect their laptop and hit the road. They need to have
// everything filled right away.
//
if (!pFind32 || !(pFind32->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { CSCFillSparseFiles(pszItem, FALSE, _AdminFillCallback, 0); }
Trace((TEXT("AdminPin %s"), pszItem));
TraceLeaveVoid(); }
void _PinLinkTarget(LPCTSTR pszLink) { LPTSTR pszTarget = NULL;
TraceEnter(TRACE_ADMINPIN, "_PinLinkTarget"); TraceAssert(pszLink);
// We only want to pin a link target if it's a file (not a directory).
// GetLinkTarget does this check and only returns files.
GetLinkTarget(pszLink, &pszTarget, NULL);
if (pszTarget) { WIN32_FIND_DATA fd = {0}; fd.dwFileAttributes = 0; StringCchCopy(fd.cFileName, ARRAYSIZE(fd.cFileName), PathFindFileName(pszTarget));
// Pin the target
_DoAdminPin(pszTarget, &fd);
LocalFree(pszTarget); }
TraceLeaveVoid(); }
// export this from shell32.dll
BOOL PathIsShortcut(LPCTSTR pszItem, DWORD dwAttributes) { BOOL bIsShortcut = FALSE;
SHFILEINFO sfi; sfi.dwAttributes = SFGAO_LINK;
if (SHGetFileInfo(pszItem, dwAttributes, &sfi, sizeof(sfi), SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED | SHGFI_USEFILEATTRIBUTES)) { bIsShortcut = (sfi.dwAttributes & SFGAO_LINK); } return bIsShortcut; }
DWORD WINAPI _PinAdminFolderCallback(LPCTSTR pszItem, ENUM_REASON eReason, LPWIN32_FIND_DATA pFind32, LPARAM /*lpContext*/) { TraceEnter(TRACE_ADMINPIN, "_PinAdminFolderCallback"); TraceAssert(pszItem);
if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0)) TraceLeaveValue(CSCPROC_RETURN_ABORT);
if (!pszItem || !*pszItem) TraceLeaveValue(CSCPROC_RETURN_SKIP);
if (eReason == ENUM_REASON_FILE || eReason == ENUM_REASON_FOLDER_BEGIN) { // If it's a link, pin the target
if (PathIsShortcut(pszItem, pFind32 ? pFind32->dwFileAttributes : 0)) _PinLinkTarget(pszItem);
// Pin the item
if (PathIsUNC(pszItem)) _DoAdminPin(pszItem, pFind32); }
TraceLeaveValue(CSCPROC_RETURN_CONTINUE); }
void _UnpinLinkTarget(LPCTSTR pszLink) { LPTSTR pszTarget = NULL;
TraceEnter(TRACE_ADMINPIN, "_UnpinLinkTarget"); TraceAssert(pszLink);
// We only want to unpin a link target if it's a file (not a directory).
// GetLinkTarget does this check and only returns files.
GetLinkTarget(pszLink, &pszTarget, NULL);
if (pszTarget) { DWORD dwStatus = 0; DWORD dwPinCount = 0; DWORD dwHintFlags = 0;
if (CSCQueryFileStatus(pszTarget, &dwStatus, &dwPinCount, &dwHintFlags) && (dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN)) { // Unpin the target
CSCUnpinFile(pszTarget, FLAG_CSC_HINT_PIN_ADMIN, &dwStatus, &dwPinCount, &dwHintFlags);
if (0 == dwPinCount && 0 == dwHintFlags && !(dwStatus & FLAG_CSCUI_COPY_STATUS_LOCALLY_DIRTY)) { WIN32_FIND_DATA fd = {0}; fd.dwFileAttributes = 0; StringCchCopy(fd.cFileName, ARRAYSIZE(fd.cFileName), PathFindFileName(pszTarget));
CscDelete(pszTarget); ShellChangeNotify(pszTarget, &fd, FALSE); } }
LocalFree(pszTarget); }
TraceLeaveVoid(); }
DWORD WINAPI _UnpinAdminFolderCallback(LPCTSTR pszItem, ENUM_REASON eReason, DWORD dwStatus, DWORD dwHintFlags, DWORD dwPinCount, LPWIN32_FIND_DATA pFind32, LPARAM /*dwContext*/) { BOOL bDeleteItem = FALSE; TraceEnter(TRACE_ADMINPIN, "_UnpinAdminFolderCallback");
if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0)) TraceLeaveValue(CSCPROC_RETURN_ABORT);
if (!pszItem || !*pszItem) TraceLeaveValue(CSCPROC_RETURN_SKIP);
TraceAssert(PathIsUNC(pszItem));
if (eReason == ENUM_REASON_FILE) { if (PathIsShortcut(pszItem, pFind32 ? pFind32->dwFileAttributes : 0)) { _UnpinLinkTarget(pszItem); } }
if ((eReason == ENUM_REASON_FILE || eReason == ENUM_REASON_FOLDER_BEGIN) && (dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN)) { // Unpin the item
CSCUnpinFile(pszItem, FLAG_CSC_HINT_PIN_ADMIN, &dwStatus, &dwPinCount, &dwHintFlags); //
// If it's a file, delete it below on this pass
//
bDeleteItem = (ENUM_REASON_FILE == eReason);
Trace((TEXT("AdminUnpin %s"), pszItem)); } else if (ENUM_REASON_FOLDER_END == eReason) { //
// Delete any unused folders in the post-order part of the traversal.
//
// Note that dwPinCount and dwHintFlags are always 0 in the
// post-order part of the traversal, so fetch them here.
//
bDeleteItem = CSCQueryFileStatus(pszItem, &dwStatus, &dwPinCount, &dwHintFlags); }
//
// Delete items that are no longer pinned and have no offline changes
//
if (bDeleteItem && 0 == dwPinCount && 0 == dwHintFlags && !(dwStatus & FLAG_CSCUI_COPY_STATUS_LOCALLY_DIRTY)) { CscDelete(pszItem); ShellChangeNotify(pszItem, pFind32, FALSE); }
TraceLeaveValue(CSCPROC_RETURN_CONTINUE); }
//
// Determines if a path is a "special" file pinned by the folder
// redirection code.
//
BOOL _IsSpecialRedirectedFile( LPCTSTR pszPath, HDPA hdpaFRList ) { TraceAssert(NULL != pszPath);
if (hdpaFRList) { const int cchPath = lstrlen(pszPath); int i;
for (i = 0; i < DPA_GetPtrCount(hdpaFRList); i++) { LPCTSTR pszThis = (LPCTSTR)DPA_GetPtr(hdpaFRList, i); int cchThis = lstrlen(pszThis);
if (cchPath >= cchThis) { //
// Path being examined is the same length or longer than
// current path from the table. Possible match.
//
if (0 == StrCmpNI(pszPath, pszThis, cchThis)) { //
// Path being examined is either the same as,
// or a child of, the current path from the table.
//
if (TEXT('\0') == *(pszPath + cchThis)) { //
// Path is same as this path from the table.
//
return TRUE; } else if (0 == lstrcmpi(pszPath + cchThis + 1, L"desktop.ini")) { //
// Path is for a desktop.ini file that exists in the
// root of one of our special folders.
//
return TRUE; } } } } }
return FALSE; }
DWORD WINAPI _ResetPinCountsCallback(LPCTSTR pszItem, ENUM_REASON eReason, DWORD dwStatus, DWORD dwHintFlags, DWORD dwPinCount, LPWIN32_FIND_DATA /*pFind32*/, LPARAM dwContext) { TraceEnter(TRACE_ADMINPIN, "_ResetPinCountsCallback");
if (WAIT_OBJECT_0 == WaitForSingleObject(g_heventTerminate, 0)) TraceLeaveValue(CSCPROC_RETURN_ABORT);
if (!pszItem || !*pszItem) TraceLeaveValue(CSCPROC_RETURN_SKIP);
TraceAssert(PathIsUNC(pszItem));
if (eReason == ENUM_REASON_FILE || eReason == ENUM_REASON_FOLDER_BEGIN) { DWORD dwCurrentPinCount = dwPinCount; DWORD dwDesiredPinCount = _IsSpecialRedirectedFile(pszItem, (HDPA)dwContext) ? 1 : 0;
while (dwCurrentPinCount-- > dwDesiredPinCount) { CSCUnpinFile(pszItem, FLAG_CSC_HINT_COMMAND_ALTER_PIN_COUNT, &dwStatus, &dwPinCount, &dwHintFlags); } }
TraceLeaveValue(CSCPROC_RETURN_CONTINUE); }
int CALLBACK _LocalFreeCallback(LPVOID p, LPVOID) { // OK to pass NULL to LocalFree
LocalFree(p); return 1; }
DWORD WINAPI _PinAdminFoldersThread(LPVOID) { TraceEnter(TRACE_ADMINPIN, "_PinAdminFoldersThread"); TraceAssert(IsCSCEnabled());
HANDLE rghSyncObj[] = { g_heventTerminate, g_hmutexAdminPin };
UINT wmAdminPin = RegisterWindowMessage(c_szAPFMessage);
//
// Wait until we either own the "admin pin" mutex OR the
// "terminate" event is set.
//
// If the wait fails for some reason, e.g. we failed to
// allocate one of these handles, we will abort immediately.
// Is that OK?
//
TraceMsg("Waiting for 'admin-pin' mutex or 'terminate' event..."); DWORD dwWait = WaitForMultipleObjects(ARRAYSIZE(rghSyncObj), rghSyncObj, FALSE, INFINITE); if (1 == (dwWait - WAIT_OBJECT_0)) { HKEY hkCSC = NULL; FILETIME ft = {0};
RegCreateKeyEx(HKEY_CURRENT_USER, c_szCSCKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hkCSC, NULL);
if (hkCSC) { GetSystemTimeAsFileTime(&ft); RegSetValueEx(hkCSC, c_szAPFStart, 0, REG_BINARY, (LPBYTE)&ft, sizeof(ft)); RegDeleteValue(hkCSC, c_szAPFEnd); } if (wmAdminPin) SendNotifyMessage(HWND_BROADCAST, wmAdminPin, 0, 0);
TraceMsg("Thread now owns 'admin-pin' mutex."); //
// We own the "admin pin" mutex. OK to perform admin pin.
//
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
//
// Get the Admin Folders list from the registry
//
HDPA hdpaFiles = DPA_Create(10); HDPA hdpaUnpin = DPA_Create(4);
if (NULL != hdpaFiles && NULL != hdpaUnpin) { DWORD dwResult = CSCPROC_RETURN_CONTINUE; int cFiles; int i;
//
// NTRAID#NTBUG9-376185-2001/04/24-jeffreys
// NTRAID#NTBUG9-379736-2001/04/24-jeffreys
//
// Unless directed by policy, pin all redirected special folders.
//
if (!CConfig::GetSingleton().NoAdminPinSpecialFolders()) { BuildFRList(hdpaFiles); } ReadAPFFromRegistry(hdpaFiles); ReconcileAPF(hdpaFiles, hdpaUnpin);
//
// Iterate through the unpin list and unpin the items
//
//
cFiles = DPA_GetPtrCount(hdpaUnpin); for (i = 0; i < cFiles; i++) { LPTSTR pszItem = (LPTSTR)DPA_GetPtr(hdpaUnpin, i);
DWORD dwStatus = 0; DWORD dwPinCount = 0; DWORD dwHintFlags = 0;
// If this fails, then it's not cached and there's nothing to do
if (CSCPROC_RETURN_CONTINUE == dwResult && CSCQueryFileStatus(pszItem, &dwStatus, &dwPinCount, &dwHintFlags)) { // Unpin this item
dwResult = _UnpinAdminFolderCallback(pszItem, ENUM_REASON_FILE, dwStatus, dwHintFlags, dwPinCount, NULL, 0);
if (CSCPROC_RETURN_CONTINUE == dwResult && PathIsUNC(pszItem)) { // Unpin everything under this folder (if it's a folder)
dwResult = _CSCEnumDatabase(pszItem, TRUE, _UnpinAdminFolderCallback, 0);
// Delete this item if it's no longer used (won't cause any
// harm if it's not a folder).
_UnpinAdminFolderCallback(pszItem, ENUM_REASON_FOLDER_END, 0, 0, 0, NULL, 0); } }
if (CSCPROC_RETURN_ABORT == dwResult) { // We failed to clean this one up completely, so remember it for next time
SHSetValue(HKEY_CURRENT_USER, c_szRegKeyAPFResult, pszItem, REG_DWORD, &dwResult, sizeof(dwResult)); } }
//
// Iterate through the list and pin the items
//
cFiles = DPA_GetPtrCount(hdpaFiles); for (i = 0; i < cFiles && CSCPROC_RETURN_CONTINUE == dwResult; i++) { LPTSTR pszItem = (LPTSTR)DPA_GetPtr(hdpaFiles, i);
// Pin this item
dwResult = _PinAdminFolderCallback(pszItem, ENUM_REASON_FILE, NULL, 0);
// Pin everything under this folder (if it's a folder)
if (CSCPROC_RETURN_CONTINUE == dwResult && PathIsUNC(pszItem)) { dwResult = _Win32EnumFolder(pszItem, TRUE, _PinAdminFolderCallback, 0); } } }
if (NULL != hdpaFiles) { DPA_DestroyCallback(hdpaFiles, _LocalFreeCallback, 0); } if (NULL != hdpaUnpin) { DPA_DestroyCallback(hdpaUnpin, _LocalFreeCallback, 0); }
//
// Reduce pin counts on everything since we don't use them anymore.
// This is a one time (per user) cleanup.
//
DWORD dwCleanupDone = 0; DWORD dwSize = sizeof(dwCleanupDone); if (hkCSC) { RegQueryValueEx(hkCSC, c_szPinCountsReset, 0, NULL, (LPBYTE)&dwCleanupDone, &dwSize); } if (0 == dwCleanupDone) { HDPA hdpaFRList = DPA_Create(4); if (hdpaFRList) { BuildFRList(hdpaFRList); }
TraceMsg("Doing pin count cleanup."); if (CSCPROC_RETURN_ABORT != _CSCEnumDatabase(NULL, TRUE, _ResetPinCountsCallback, (LPARAM)hdpaFRList) && hkCSC) { dwCleanupDone = 1; RegSetValueEx(hkCSC, c_szPinCountsReset, 0, REG_DWORD, (LPBYTE)&dwCleanupDone, sizeof(dwCleanupDone)); }
if (hdpaFRList) { DPA_DestroyCallback(hdpaFRList, _LocalFreeCallback, 0); } }
if (hkCSC) { GetSystemTimeAsFileTime(&ft); RegSetValueEx(hkCSC, c_szAPFEnd, 0, REG_BINARY, (LPBYTE)&ft, sizeof(ft)); RegCloseKey(hkCSC); } if (wmAdminPin) SendNotifyMessage(HWND_BROADCAST, wmAdminPin, 1, 0);
TraceMsg("Thread releasing 'admin-pin' mutex."); ReleaseMutex(g_hmutexAdminPin); }
TraceMsg("_PinAdminFoldersThread exiting"); TraceLeaveValue(0); }
|