|
|
/*++
Copyright (c) 1994-2000 Microsoft Corporation
Module Name:
ids.cxx
Abstract:
Contains functions responsible for managing identities in wininet Contents:
Author:
July - September 1999. akabir
Environment:
Win32 user-mode DLL
Revision History:
--*/
#include <wininetp.h>
#include <cache.hxx>
#undef SHGetFolderPath
HRESULT SHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath);
#if 0
#include <hlink.h>
#include <urlmon.h>
#include <shlobj.h>
#define HMONITOR_DECLARED 1
#include <shlobjp.h>
typedef HRESULT (*PFNSHGETDESKTOPFOLDER)(IShellFolder**);
HRESULT _SHGetDesktopFolder(IShellFolder **psfDesktop) { HMODULE h = LoadLibrary("shell32.dll"); HRESULT hr = E_POINTER; if (h) { PFNSHGETDESKTOPFOLDER pfn = (PFNSHGETDESKTOPFOLDER)GetProcAddress(h, "SHGetDesktopFolder"); if (pfn) { hr = pfn(psfDesktop); } FreeLibrary(h); } return hr; }
typedef VOID (*PFNILFREE)(LPITEMIDLIST);
VOID _ILFree(LPITEMIDLIST pidl) { HMODULE h = LoadLibrary("shell32.dll"); if (h) { PFNILFREE pfn = (PFNILFREE)GetProcAddress(h, "ILFree"); if (pfn) { pfn(pidl); } FreeLibrary(h); } }
const GUID DefaultGuid = { 0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const GUID IID_IHistSFPrivate = { 0x62e1261L, 0xa60e, 0x11d0, 0x82, 0xc2, 0x0, 0xc0, 0x4f, 0xd5, 0xae, 0x38 }; #endif // 0
// -- Utility functions --------------------------------------------------------------------------------------
// Create an ansi representation of a guid.
VOID GuidToAnsiStr(GUID* pGuid, PSTR psz, DWORD dwSize) { WCHAR wszUid[MAX_PATH]; StringFromGUID2(*pGuid, wszUid, ARRAY_ELEMENTS(wszUid)); SHUnicodeToAnsi(wszUid, psz, dwSize); }
REGISTRY_OBJ* CreateExtensiRegObjFor(HKEY hKey, GUID* pguid) { REGISTRY_OBJ *pro = NULL;
CHAR sz[MAX_PATH]; GuidToAnsiStr(pguid, sz, ARRAY_ELEMENTS(sz));
CHAR szBranches[MAX_PATH]; if (wnsprintf(szBranches, ARRAY_ELEMENTS(szBranches), "%s\\%s\\%s", IDENTITIES_KEY, sz, EXTENSIBLE_CACHE_PATH_KEY) >= 0) { pro = new REGISTRY_OBJ(hKey, szBranches, CREATE_KEY_IF_NOT_EXISTS); }
return pro; }
#ifdef WININET6
DWORD IDRegDwordCore(LPCTSTR psz, PDWORD pdw, BOOL fSet) { INET_ASSERT(GlobalIdentity); CHAR sz[MAX_PATH]; GuidToAnsiStr(&GlobalIdentityGuid, sz, ARRAY_ELEMENTS(sz));
CHAR szBranches[MAX_PATH]; DWORD dwError = ERROR_INVALID_PARAMETER; if (wnsprintf(szBranches, ARRAY_ELEMENTS(szBranches), "%s\\%s", IDENTITIES_KEY, sz) >= 0) { REGISTRY_OBJ ro(GlobalCacheHKey, szBranches); dwError = ro.GetStatus(); if (dwError==ERROR_SUCCESS) { dwError = fSet ? ro.SetValue((LPTSTR)psz, pdw) : ro.GetValue((LPTSTR)psz, pdw); } } return dwError; }
DWORD ReadIDRegDword(LPCTSTR psz, PDWORD pdw) { return IDRegDwordCore(psz, pdw, FALSE); }
DWORD WriteIDRegDword(LPCTSTR psz, DWORD dw) { return IDRegDwordCore(psz, &dw, TRUE); } #endif
// Disable the funny business of altering identities for now. It can be
// enabled once we have a better understanding of how this can fit
// into WinHttp
#if 0
VOID CreateCurrentHistory() { INTERNET_CACHE_CONFIG_INFO icci; icci.dwStructSize = sizeof(icci); if (GlobalUrlContainers->GetUrlCacheConfigInfo(&icci, NULL, CACHE_CONFIG_HISTORY_PATHS_FC) && SUCCEEDED(CoInitialize(NULL))) { // We want to ensure that the history is valid for this user.
IShellFolder *psfDesktop; if (SUCCEEDED(_SHGetDesktopFolder(&psfDesktop))) { WCHAR wszPath[MAX_PATH]; LPITEMIDLIST pidlHistory; IShellFolder *psfHistory; MultiByteToWideChar(CP_ACP, 0, icci.CachePath, -1, wszPath, ARRAY_ELEMENTS(wszPath)); PathRemoveFileSpecW(wszPath); // get the trailing slash
PathRemoveFileSpecW(wszPath); // get the trailing slash
PathRemoveFileSpecW(wszPath); // trim the "content.ie5" junk
if (SUCCEEDED(psfDesktop->ParseDisplayName(NULL, NULL, wszPath, NULL, &pidlHistory, NULL))) { if (SUCCEEDED(psfDesktop->BindToObject(pidlHistory, NULL, IID_IShellFolder, (VOID**)&psfHistory))) { IHistSFPrivate *phsf; if (SUCCEEDED(psfHistory->QueryInterface(IID_IHistSFPrivate, (void**)&phsf))) { FILETIME ftBogus = { 0 }; // This forces the validation in shdocvw
phsf->WriteHistory(L"", ftBogus, ftBogus, NULL); phsf->Release(); } psfHistory->Release(); } _ILFree(pidlHistory); } psfDesktop->Release(); } CoUninitialize(); } }
CONST TCHAR c_szIdentityOrdinal[] = "Identity Ordinal";
DWORD MapGuidToOrdinal(GUID* lpGUID) { DWORD dwOrdinal = 0; HKEY hSourceSubKey;
if (!memcmp(lpGUID, &DefaultGuid, sizeof(DefaultGuid))) { return 0; }
if (RegCreateKey(HKEY_CURRENT_USER, IDENTITIES_KEY, &hSourceSubKey) == ERROR_SUCCESS) { CHAR szUid[MAX_PATH]; GuidToAnsiStr(lpGUID, szUid, ARRAY_ELEMENTS(szUid));
DWORD dwSize, dwType; DWORD dwIdentityOrdinal = 1;
dwSize = sizeof(dwIdentityOrdinal); RegQueryValueEx(hSourceSubKey, c_szIdentityOrdinal, NULL, &dwType, (LPBYTE)&dwIdentityOrdinal, &dwSize);
HKEY hkUserKey; if (RegCreateKey(hSourceSubKey, szUid, &hkUserKey) == ERROR_SUCCESS) { if (RegQueryValueEx(hkUserKey, c_szIdentityOrdinal, NULL, &dwType, (LPBYTE)&dwOrdinal, &dwSize)!=ERROR_SUCCESS) { if (RegSetValueEx(hkUserKey, c_szIdentityOrdinal, NULL, REG_DWORD, (LPBYTE)&dwIdentityOrdinal, dwSize)==ERROR_SUCCESS) { dwOrdinal = dwIdentityOrdinal++; RegSetValueEx(hSourceSubKey, c_szIdentityOrdinal, 0, REG_DWORD, (LPBYTE)&dwIdentityOrdinal, dwSize); } } RegCloseKey(hkUserKey); } RegCloseKey(hSourceSubKey); }
INET_ASSERT(dwOrdinal); return dwOrdinal; }
DWORD AlterIdentity(DWORD dwFlags) { if (!GlobalIdentity) { return ERROR_INVALID_PARAMETER; } switch (dwFlags) { case INTERNET_IDENTITY_FLAG_PRIVATE_CACHE: case INTERNET_IDENTITY_FLAG_SHARED_CACHE: case INTERNET_IDENTITY_FLAG_CLEAR_DATA: case INTERNET_IDENTITY_FLAG_CLEAR_COOKIES: case INTERNET_IDENTITY_FLAG_CLEAR_HISTORY: case INTERNET_IDENTITY_FLAG_CLEAR_CONTENT: break; } return ERROR_CALL_NOT_IMPLEMENTED; }
DWORD RemoveIdentity(GUID* pguidIdentity) { if (!pguidIdentity || !memcmp(pguidIdentity, &DefaultGuid, sizeof(DefaultGuid))) { return ERROR_INVALID_PARAMETER; }
CHAR szUid[MAX_PATH]; GuidToAnsiStr(pguidIdentity, szUid, ARRAY_ELEMENTS(szUid)); DWORD dwIdentity = MapGuidToOrdinal(pguidIdentity); if (dwIdentity==GlobalIdentity) { DWORD dwErr = SwitchIdentity(NULL); if (dwErr!=ERROR_SUCCESS) return dwErr; }
DWORD dwErr = ERROR_INVALID_PARAMETER; REGISTRY_OBJ roIds(HKEY_CURRENT_USER, IDENTITIES_KEY); if (roIds.GetStatus()==ERROR_SUCCESS) { // We want to delete the containers before we delete the reg keys.
// First the extensible containers
REGISTRY_OBJ* pro = CreateExtensiRegObjFor(HKEY_CURRENT_USER, pguidIdentity); if (pro && (pro->GetStatus()==ERROR_SUCCESS)) { CHAR szVendorKey[MAX_PATH]; while (pro->FindNextKey(szVendorKey, MAX_PATH) == ERROR_SUCCESS) { REGISTRY_OBJ roVendor(pro, szVendorKey); if (roVendor.GetStatus()==ERROR_SUCCESS) { TCHAR szPath[MAX_PATH]; DWORD ccKeyLen = ARRAY_ELEMENTS(szPath); if (roVendor.GetValue(CACHE_PATH_VALUE, (LPBYTE) szPath, &ccKeyLen)==ERROR_SUCCESS) { TCHAR szScratch[MAX_PATH+1]; ExpandEnvironmentStrings(szPath, szScratch, ARRAY_ELEMENTS(szScratch)-1); // don't count the NULL
DeleteCachedFilesInDir(szScratch); RemoveDirectory(szScratch); } } } } if (pro) { delete pro; } TCHAR szPath[MAX_PATH]; if ((S_OK==SHGetFolderPath(NULL, CSIDL_COOKIES | CSIDL_FLAG_CREATE, NULL, 0, szPath)) && (*szPath!='\0')) { if (GenerateStringWithOrdinal(NULL, dwIdentity, szPath, ARRAY_ELEMENTS(szPath))) { DeleteCachedFilesInDir(szPath); RemoveDirectory(szPath); } } if ((S_OK==SHGetFolderPath(NULL, CSIDL_HISTORY | CSIDL_FLAG_CREATE, NULL, 0, szPath)) && (*szPath!='\0')) { StrCatBuff(szPath, "\\History.IE5", ARRAY_ELEMENTS(szPath)); if (GenerateStringWithOrdinal(NULL, dwIdentity, szPath, ARRAY_ELEMENTS(szPath))) { DeleteCachedFilesInDir(szPath); RemoveDirectory(szPath); } }
// We'll leave the content; it'll be scavenged anyway.
if (roIds.DeleteKey(szUid)==ERROR_SUCCESS) { dwErr = ERROR_SUCCESS; } } return dwErr; }
DWORD SwitchIdentity(GUID* pguidIdentity) { DWORD dwIdentity = pguidIdentity ? MapGuidToOrdinal(pguidIdentity) : 0; if (dwIdentity==GlobalIdentity) return ERROR_SUCCESS;
DWORD dwErr = ERROR_SUCCESS; LOCK_CACHE(); INET_ASSERT(dwIdentity!=GlobalIdentity);
CloseTheCookieJar();
DWORD dwTemp = GlobalIdentity; GUID guidTemp; GlobalIdentity = dwIdentity; GlobalCacheInitialized = FALSE; memcpy(&guidTemp, &GlobalIdentityGuid, sizeof(GlobalIdentityGuid)); if (dwIdentity==0) { memset(&GlobalIdentityGuid, 0, sizeof(GlobalIdentityGuid)); } else { memcpy(&GlobalIdentityGuid, pguidIdentity, sizeof(*pguidIdentity)); }
CConMgr* NewGUC = new CConMgr();
if (!NewGUC || (NewGUC->GetStatus()!=ERROR_SUCCESS) || (!InternetSetOption(NULL, INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0))) { INET_ASSERT(FALSE); if (NewGUC) delete NewGUC; dwErr = ERROR_WINHTTP_INTERNAL_ERROR; GlobalCacheInitialized = TRUE; GlobalIdentity = dwTemp; memcpy(&GlobalIdentityGuid, &guidTemp, sizeof(GlobalIdentityGuid)); goto exit; }
// We need to stop the scavenger
GlobalPleaseQuitWhatYouAreDoing = TRUE; while (GlobalScavengerRunning!=-1) { Sleep(0); } delete GlobalUrlContainers; GlobalUrlContainers = NewGUC; GlobalCacheInitialized = TRUE;
// It's safe now, you can scavenge
GlobalPleaseQuitWhatYouAreDoing = FALSE;
if (AnyFindsInProgress(0)) { HandleMgr.InvalidateAll(); }
CreateCurrentHistory(); // Note to ASK: check what this call does, if it affects identities
if ((dwErr = GlobalUrlContainers->CreateDefaultGroups())!=ERROR_SUCCESS) goto exit; if (!OpenTheCookieJar()) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto exit; }
#ifdef WININET6
// Set warnings appropriately.
GlobalWarnOnPost = FALSE; GlobalWarnAlways = FALSE; GlobalWarnOnZoneCrossing = TRUE; GlobalWarnOnBadCertSending = FALSE; GlobalWarnOnBadCertRecving = TRUE; GlobalWarnOnPostRedirect = TRUE; GlobalDataReadWarningUIFlags(); #endif
exit: UNLOCK_CACHE(); INET_ASSERT((dwErr==ERROR_SUCCESS)); return dwErr; }
#endif
// CreateExtensiRegObj ----------------
// Create an identity-appropriate registry object
// for extensible cache containers.
REGISTRY_OBJ* CreateExtensiRegObj(HKEY hKey) { REGISTRY_OBJ *pro = NULL; if (GlobalIdentity) { pro = CreateExtensiRegObjFor(hKey, &GlobalIdentityGuid); } else { REGISTRY_OBJ roCache(hKey, CACHE5_KEY); if (roCache.GetStatus()==ERROR_SUCCESS) { pro = new REGISTRY_OBJ(&roCache, EXTENSIBLE_CACHE_PATH_KEY, CREATE_KEY_IF_NOT_EXISTS); } }
if (pro && pro->GetStatus()!=ERROR_SUCCESS) { delete pro; pro = NULL; }
return pro; }
// GenerateStringWithOrdinal ------------
// We want to append the identity ordinal to a string
// If psz is null, then pszBuffer better contain a 0-terminated string that we can
// append the ordinal to.
// Otherwise, we copy psz to pszBuffer and append to that.
BOOL GenerateStringWithOrdinal(PCTSTR psz, DWORD dwOrdinal, PTSTR pszBuffer, DWORD dwMax) { DWORD cc = psz ? lstrlen(psz) : lstrlen(pszBuffer);
if (cc>dwMax) return FALSE;
if (psz) { memcpy(pszBuffer, psz, cc*sizeof(*pszBuffer)); } if (dwOrdinal) { if (!AppendSlashIfNecessary(pszBuffer, &cc)) return FALSE;
if (wnsprintf(pszBuffer+cc, dwMax-cc, "%d", dwOrdinal) < 0) return FALSE; } else { pszBuffer[cc] = TEXT('\0'); } return TRUE; }
// IsPerUserEntry
// Examine the headers of a cache entry to determine whether or
// not it is user-specific
BOOL IsPerUserEntry(LPURL_FILEMAP_ENTRY pfe) { INET_ASSERT(pfe); BOOL fRet = FALSE; PTSTR lpszHeaderInfo = (PTSTR)pfe + pfe->HeaderInfoOffset; DWORD dwHeaderSize = pfe->HeaderInfoSize;
if (!lpszHeaderInfo || !dwHeaderSize) { return FALSE; } LPSTR lpTemp = lpszHeaderInfo+dwHeaderSize-1; LPSTR lpTemp2;
// start searching backwards
while (lpTemp >= lpszHeaderInfo) { if (*lpTemp ==':') { // compare with "~U:"
fRet = (!strnicmp(lpTemp-2, vszUserNameHeader, sizeof(vszUserNameHeader)-1)) // guarantee that this is the beginning of a header
&& (((lpTemp-2)==lpszHeaderInfo) || isspace(*(lpTemp-3))); break; } --lpTemp; } return fRet; }
|