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.
531 lines
15 KiB
531 lines
15 KiB
/*++
|
|
|
|
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 <cache.hxx>
|
|
#include <hlink.h>
|
|
#include <urlmon.h>
|
|
#include <shlobj.h>
|
|
#define HMONITOR_DECLARED 1
|
|
#include <shlobjp.h>
|
|
|
|
|
|
|
|
// -- whatever -----------------------------------------------------------------------------------------------
|
|
#undef SHGetFolderPath
|
|
HRESULT SHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath);
|
|
|
|
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 };
|
|
|
|
|
|
// -- 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
|
|
|
|
|
|
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_INTERNET_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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|