1019 lines
27 KiB
C++
1019 lines
27 KiB
C++
#include "private.h"
|
|
#include "multiutl.h"
|
|
#include <wtypes.h>
|
|
#include "strconst.h"
|
|
#include <platform.h>
|
|
|
|
extern HINSTANCE g_hInst;
|
|
|
|
// Pstore related variables.
|
|
static PST_KEY s_Key = PST_KEY_CURRENT_USER;
|
|
|
|
// {89C39569-6841-11d2-9F59-0000F8085266}
|
|
static const GUID GUID_PStoreType = { 0x89c39569, 0x6841, 0x11d2, { 0x9f, 0x59, 0x0, 0x0, 0xf8, 0x8, 0x52, 0x66 } };
|
|
static WCHAR c_szIdentityMgr[] = L"IdentityMgr";
|
|
static WCHAR c_szIdentities[] = L"Identities";
|
|
static WCHAR c_szIdentityPass[] = L"IdentitiesPass";
|
|
|
|
//Need these private implementations
|
|
//OE has dependency on the particular allocator used
|
|
|
|
void * __cdecl operator new(size_t nSize)
|
|
{
|
|
// Zero init just to save some headaches
|
|
return CoTaskMemAlloc(nSize);
|
|
}
|
|
|
|
void __cdecl operator delete(void *pv)
|
|
{
|
|
//If changed to GlobalFree or HeapFree - must check for NULL here
|
|
CoTaskMemFree(pv);
|
|
}
|
|
|
|
extern "C" int __cdecl _purecall(void)
|
|
{
|
|
DebugBreak();
|
|
return 0;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// FIsSpaceA
|
|
// --------------------------------------------------------------------------
|
|
BOOL FIsSpaceA(LPSTR psz)
|
|
{
|
|
#ifdef MAC
|
|
return (isspace(*psz));
|
|
#else // !MAC
|
|
WORD wType;
|
|
|
|
if (IsDBCSLeadByte(*psz))
|
|
GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 2, &wType);
|
|
else
|
|
GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 1, &wType);
|
|
return (wType & C1_SPACE);
|
|
#endif // MAC
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// FIsSpaceW
|
|
// --------------------------------------------------------------------------
|
|
BOOL FIsSpaceW(LPWSTR psz)
|
|
{
|
|
#ifdef MAC
|
|
// Maybe we should convert to ANSI before checking??
|
|
return (isspace(*( ( (TCHAR *) psz ) + 1 ) ));
|
|
#else // !MAC
|
|
WORD wType;
|
|
GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 1, &wType);
|
|
return (wType & C1_SPACE);
|
|
#endif // !MAC
|
|
}
|
|
|
|
|
|
ULONG UlStripWhitespace(LPTSTR lpsz, BOOL fLeading, BOOL fTrailing, ULONG *pcb)
|
|
{
|
|
// Locals
|
|
ULONG cb;
|
|
LPTSTR psz;
|
|
|
|
Assert(lpsz != NULL);
|
|
Assert(fLeading || fTrailing);
|
|
|
|
// Did the user pass in the length
|
|
if (pcb)
|
|
cb = *pcb;
|
|
else
|
|
cb = lstrlen (lpsz);
|
|
|
|
if (cb == 0)
|
|
return cb;
|
|
|
|
if (fLeading)
|
|
{
|
|
psz = lpsz;
|
|
|
|
while (FIsSpace(psz))
|
|
{
|
|
psz++;
|
|
cb--;
|
|
}
|
|
|
|
if (psz != lpsz)
|
|
// get the NULL at the end too
|
|
MoveMemory(lpsz, psz, (cb + 1) * sizeof(TCHAR));
|
|
}
|
|
|
|
if (fTrailing)
|
|
{
|
|
psz = lpsz + cb;
|
|
|
|
while (cb > 0)
|
|
{
|
|
if (!FIsSpace(psz-1))
|
|
break;
|
|
psz--;
|
|
cb--;
|
|
}
|
|
|
|
// NULL Term
|
|
*psz = '\0';
|
|
}
|
|
|
|
// Set String Size
|
|
if (pcb)
|
|
*pcb = cb;
|
|
|
|
// Done
|
|
return cb;
|
|
}
|
|
|
|
BOOL OnContextHelp(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, HELPMAP const * rgCtxMap)
|
|
{
|
|
if (uMsg == WM_HELP)
|
|
{
|
|
LPHELPINFO lphi = (LPHELPINFO) lParam;
|
|
if (lphi->iContextType == HELPINFO_WINDOW) // must be for a control
|
|
{
|
|
WinHelp ((HWND)lphi->hItemHandle,
|
|
c_szCtxHelpFile,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)(void*)rgCtxMap);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
else if (uMsg == WM_CONTEXTMENU)
|
|
{
|
|
WinHelp ((HWND) wParam,
|
|
c_szCtxHelpFile,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)(void*)rgCtxMap);
|
|
return (TRUE);
|
|
}
|
|
|
|
Assert(0);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
#define OBFUSCATOR 0x14151875;
|
|
|
|
#define PROT_SIZEOF_HEADER 0x02 // 2 bytes in the header
|
|
#define PROT_SIZEOF_XORHEADER (PROT_SIZEOF_HEADER+sizeof(DWORD))
|
|
|
|
#define PROT_VERSION_1 0x01
|
|
|
|
#define PROT_PASS_XOR 0x01
|
|
#define PROT_PASS_PST 0x02
|
|
|
|
static BOOL FDataIsValidV1(BYTE *pb)
|
|
{ return pb && pb[0] == PROT_VERSION_1 && (pb[1] == PROT_PASS_XOR || pb[1] == PROT_PASS_PST); }
|
|
|
|
static BOOL FDataIsPST(BYTE *pb)
|
|
{ return pb && pb[1] == PROT_PASS_PST; }
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NOTE - The functions for encoding the user passwords really should not
|
|
// be here. Unfortunately, they are not anywhere else so for now,
|
|
// this is where they will stay. They are defined as static since
|
|
// other code should not rely on them staying here, particularly the
|
|
// XOR stuff.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// XOR functions
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
static HRESULT _XOREncodeProp(const BLOB *const pClear, BLOB *const pEncoded)
|
|
{
|
|
DWORD dwSize;
|
|
DWORD last, last2;
|
|
DWORD UNALIGNED *pdwCypher;
|
|
DWORD dex;
|
|
|
|
pEncoded->cbSize = pClear->cbSize+PROT_SIZEOF_XORHEADER;
|
|
if (!MemAlloc((void* *)&pEncoded->pBlobData, pEncoded->cbSize + 6))
|
|
return E_OUTOFMEMORY;
|
|
|
|
// set up header data
|
|
Assert(2 == PROT_SIZEOF_HEADER);
|
|
pEncoded->pBlobData[0] = PROT_VERSION_1;
|
|
pEncoded->pBlobData[1] = PROT_PASS_XOR;
|
|
*((DWORD UNALIGNED *)&(pEncoded->pBlobData[2])) = pClear->cbSize;
|
|
|
|
// nevermind that the pointer is offset by the header size, this is
|
|
// where we start to write out the modified password
|
|
pdwCypher = (DWORD UNALIGNED *)&(pEncoded->pBlobData[PROT_SIZEOF_XORHEADER]);
|
|
|
|
dex = 0;
|
|
last = OBFUSCATOR; // 0' = 0 ^ ob
|
|
if (dwSize = pClear->cbSize / sizeof(DWORD))
|
|
{
|
|
// case where data is >= 4 bytes
|
|
for (; dex < dwSize; dex++)
|
|
{
|
|
last2 = ((DWORD UNALIGNED *)pClear->pBlobData)[dex]; // 1
|
|
pdwCypher[dex] = last2 ^ last; // 1' = 1 ^ 0
|
|
last = last2; // save 1 for the 2 round
|
|
}
|
|
}
|
|
|
|
// if we have bits left over
|
|
// note that dwSize is computed now in bits
|
|
if (dwSize = (pClear->cbSize % sizeof(DWORD))*8)
|
|
{
|
|
// need to not munge memory that isn't ours
|
|
last >>= sizeof(DWORD)*8-dwSize;
|
|
pdwCypher[dex] &= ((DWORD)-1) << dwSize;
|
|
pdwCypher[dex] |=
|
|
((((DWORD UNALIGNED *)pClear->pBlobData)[dex] & (((DWORD)-1) >> (sizeof(DWORD)*8-dwSize))) ^ last);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT _XORDecodeProp(const BLOB *const pEncoded, BLOB *const pClear)
|
|
{
|
|
DWORD dwSize;
|
|
DWORD last;
|
|
DWORD UNALIGNED *pdwCypher;
|
|
DWORD dex;
|
|
|
|
// we use CoTaskMemAlloc to be in line with the PST implementation
|
|
pClear->cbSize = *(DWORD UNALIGNED *)(&pEncoded->pBlobData[2]);
|
|
MemAlloc((void **)&pClear->pBlobData, pClear->cbSize);
|
|
if (!pClear->pBlobData)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// should have been tested by now
|
|
Assert(FDataIsValidV1(pEncoded->pBlobData));
|
|
Assert(!FDataIsPST(pEncoded->pBlobData));
|
|
|
|
// nevermind that the pointer is offset by the header size, this is
|
|
// where the password starts
|
|
pdwCypher = (DWORD UNALIGNED *)&(pEncoded->pBlobData[PROT_SIZEOF_XORHEADER]);
|
|
|
|
dex = 0;
|
|
last = OBFUSCATOR;
|
|
if (dwSize = pClear->cbSize / sizeof(DWORD))
|
|
{
|
|
// case where data is >= 4 bytes
|
|
for (; dex < dwSize; dex++)
|
|
last = ((DWORD UNALIGNED *)pClear->pBlobData)[dex] = pdwCypher[dex] ^ last;
|
|
}
|
|
|
|
// if we have bits left over
|
|
if (dwSize = (pClear->cbSize % sizeof(DWORD))*8)
|
|
{
|
|
// need to not munge memory that isn't ours
|
|
last >>= sizeof(DWORD)*8-dwSize;
|
|
((DWORD UNALIGNED *)pClear->pBlobData)[dex] &= ((DWORD)-1) << dwSize;
|
|
((DWORD UNALIGNED *)pClear->pBlobData)[dex] |=
|
|
((pdwCypher[dex] & (((DWORD)-1) >> (sizeof(DWORD)*8-dwSize))) ^ last);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
EncodeUserPassword
|
|
|
|
Encrypt the passed in password. This encryption seems to
|
|
add an extra 6 bytes on to the beginning of the data
|
|
that it passes back, so we need to make sure that the
|
|
lpszPwd is large enough to hold a few extra characters.
|
|
*cb should be different on return than it was when it
|
|
was passed in.
|
|
|
|
Parameters:
|
|
lpszPwd - on entry, a c string containing the password.
|
|
on exit, it is the encrypted data, plus some header info.
|
|
|
|
cb - the size of lpszPwd on entry and exit. Note that it should
|
|
include the trailing null, so "foo" would enter with *cb == 4.
|
|
*/
|
|
void EncodeUserPassword(TCHAR *lpszPwd, ULONG *cb)
|
|
{
|
|
BLOB blobClient;
|
|
BLOB blobProp;
|
|
|
|
blobClient.pBlobData= (BYTE *)lpszPwd;
|
|
blobClient.cbSize = *cb;
|
|
blobProp.pBlobData = NULL;
|
|
blobProp.cbSize = 0;
|
|
|
|
_XOREncodeProp(&blobClient, &blobProp);
|
|
|
|
if (blobProp.pBlobData)
|
|
{
|
|
memcpy(lpszPwd, blobProp.pBlobData, blobProp.cbSize);
|
|
*cb = blobProp.cbSize;
|
|
MemFree(blobProp.pBlobData);
|
|
}
|
|
}
|
|
|
|
/*
|
|
DecodeUserPassword
|
|
|
|
Decrypt the passed in data and return a password. This
|
|
encryption seems to add an extra 6 bytes on to the beginning
|
|
so decrupting will result in a using less of lpszPwd.
|
|
.
|
|
*cb should be different on return than it was when it
|
|
was passed in.
|
|
|
|
Parameters:
|
|
lpszPwd - on entry, the encrypted password plus some
|
|
header info.
|
|
on exit, a c string containing the password.
|
|
|
|
cb - the size of lpszPwd on entry and exit. Note that it should
|
|
include the trailing null, so "foo" would leave with *cb == 4.
|
|
*/
|
|
void DecodeUserPassword(TCHAR *lpszPwd, ULONG *cb)
|
|
{
|
|
BLOB blobClient;
|
|
BLOB blobProp;
|
|
|
|
blobClient.pBlobData= (BYTE *)lpszPwd;
|
|
blobClient.cbSize = *cb;
|
|
blobProp.pBlobData = NULL;
|
|
blobProp.cbSize = 0;
|
|
|
|
_XORDecodeProp(&blobClient, &blobProp);
|
|
|
|
if (blobProp.pBlobData)
|
|
{
|
|
memcpy(lpszPwd, blobProp.pBlobData, blobProp.cbSize);
|
|
lpszPwd[blobProp.cbSize] = 0;
|
|
*cb = blobProp.cbSize;
|
|
MemFree(blobProp.pBlobData);
|
|
}
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// MemInit
|
|
// --------------------------------------------------------------------------------
|
|
void MemInit()
|
|
{
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// MemUnInit
|
|
// --------------------------------------------------------------------------------
|
|
void MemUnInit()
|
|
{
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// MemFree
|
|
// --------------------------------------------------------------------------------
|
|
void MemFree(void* pv)
|
|
{
|
|
CoTaskMemFree(pv);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// MemAlloc
|
|
// --------------------------------------------------------------------------------
|
|
BOOL MemAlloc(void** ppv, ULONG cb)
|
|
{
|
|
assert(ppv && cb);
|
|
*ppv = CoTaskMemAlloc(cb);
|
|
if (NULL == *ppv)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// MemRealloc
|
|
// --------------------------------------------------------------------------------
|
|
BOOL MemRealloc(void* *ppv, ULONG cbNew)
|
|
{
|
|
assert(ppv && cbNew);
|
|
void* pv = CoTaskMemRealloc(*ppv, cbNew);
|
|
if (NULL == pv)
|
|
return FALSE;
|
|
*ppv = pv;
|
|
return TRUE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Functions to convert GUIDs to ascii strings
|
|
// --------------------------------------------------------------------------------
|
|
|
|
int AStringFromGUID(GUID *puid, TCHAR *lpsz, int cch)
|
|
{
|
|
WCHAR wsz[255];
|
|
int i;
|
|
|
|
i = StringFromGUID2(*puid, wsz, 255);
|
|
|
|
if (WideCharToMultiByte(CP_ACP, 0, wsz, -1, lpsz, cch, NULL, NULL) == 0)
|
|
return 0;
|
|
|
|
return (lstrlen(lpsz) + 1);
|
|
}
|
|
|
|
|
|
HRESULT GUIDFromAString(TCHAR *lpsz, GUID *puid)
|
|
{
|
|
WCHAR wsz[255];
|
|
HRESULT hr;
|
|
|
|
if (MultiByteToWideChar(CP_ACP, 0, lpsz, -1, wsz, 255) == 0)
|
|
return GetLastError();
|
|
|
|
hr = CLSIDFromString(wsz, puid);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// ****************************************************************************************************
|
|
// CNotifierList Class
|
|
//
|
|
// A really basic IUnknown list class. Actually, its a IUnknown array class, but you don't need to know
|
|
// that.
|
|
//
|
|
|
|
|
|
CNotifierList::CNotifierList()
|
|
{
|
|
m_count = 0;
|
|
m_ptrCount = 0;
|
|
m_entries = NULL;
|
|
m_nextCookie = 1;
|
|
m_cRef = 1;
|
|
InitializeCriticalSection(&m_rCritSect);
|
|
}
|
|
|
|
/*
|
|
CNotifierList::~CNotifierList
|
|
|
|
Clean up any memory that was allocated in the CNotifierList object
|
|
*/
|
|
CNotifierList::~CNotifierList()
|
|
{
|
|
if (m_entries)
|
|
{
|
|
for (int i = 0; i < m_count; i++)
|
|
{
|
|
if (m_entries[i].punk)
|
|
{
|
|
m_entries[i].punk->Release();
|
|
m_entries[i].punk = NULL;
|
|
m_entries[i].dwCookie = 0;
|
|
}
|
|
}
|
|
MemFree(m_entries);
|
|
m_entries = NULL;
|
|
m_count = 0;
|
|
}
|
|
DeleteCriticalSection(&m_rCritSect);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CNotifierList::AddRef()
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNotifierList::Release()
|
|
{
|
|
if( 0L != --m_cRef )
|
|
return m_cRef;
|
|
|
|
delete this;
|
|
return 0L;
|
|
}
|
|
|
|
/*
|
|
CNotifierList::Add
|
|
|
|
Add a IUnknown to the end of the IUnknown list.
|
|
*/
|
|
HRESULT CNotifierList::Add(IUnknown *punk, DWORD *pdwCookie)
|
|
{
|
|
TraceCall("Identity - CNotifierList::Add");
|
|
|
|
EnterCriticalSection(&m_rCritSect);
|
|
// make more room for pointers, if necessary
|
|
if (m_ptrCount == m_count)
|
|
{
|
|
m_ptrCount += 5;
|
|
if (!MemRealloc((void **)&m_entries, sizeof(UNKLIST_ENTRY) * m_ptrCount))
|
|
{
|
|
m_ptrCount -= 5;
|
|
Assert(false);
|
|
LeaveCriticalSection(&m_rCritSect);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// initialize the new IUnknowns to nil
|
|
for (int i = m_count; i < m_ptrCount; i++)
|
|
{
|
|
ZeroMemory(&m_entries[i], sizeof(UNKLIST_ENTRY));
|
|
}
|
|
}
|
|
|
|
//now put the IUnknown in the next location
|
|
int iNewIndex = m_count++;
|
|
|
|
punk->AddRef();
|
|
m_entries[iNewIndex].punk = punk;
|
|
m_entries[iNewIndex].bState = NS_NONE;
|
|
m_entries[iNewIndex].dwCookie = ++m_nextCookie;
|
|
m_entries[iNewIndex].dwThreadId = GetCurrentThreadId();
|
|
*pdwCookie = m_entries[iNewIndex].dwCookie;
|
|
LeaveCriticalSection(&m_rCritSect);
|
|
CreateNotifyWindow();
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
CNotifierList::Remove
|
|
|
|
Remove a IUnknown at zero based index iIndex
|
|
*/
|
|
|
|
HRESULT CNotifierList::Remove(int iIndex)
|
|
{
|
|
int iCopySize;
|
|
|
|
TraceCall("Identity - CNotifierList::Remove");
|
|
|
|
EnterCriticalSection(&m_rCritSect);
|
|
iCopySize = ((m_count - iIndex) - 1) * sizeof(UNKLIST_ENTRY);
|
|
|
|
// free the memory for the IUnknown
|
|
if (m_entries[iIndex].punk)
|
|
{
|
|
ReleaseWindow();
|
|
m_entries[iIndex].punk->Release();
|
|
ZeroMemory(&m_entries[iIndex], sizeof(UNKLIST_ENTRY));
|
|
}
|
|
|
|
// move the other IUnknowns down
|
|
if (iCopySize)
|
|
{
|
|
memmove(&(m_entries[iIndex]), &(m_entries[iIndex+1]), iCopySize);
|
|
}
|
|
|
|
// null out the last item in the list and decrement the counter.
|
|
m_entries[--m_count].punk = NULL;
|
|
LeaveCriticalSection(&m_rCritSect);
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
CNotifierList::RemoveCookie
|
|
|
|
Remove an IUnknown by its cookie
|
|
*/
|
|
|
|
HRESULT CNotifierList::RemoveCookie(DWORD dwCookie)
|
|
{
|
|
int iIndex;
|
|
|
|
for (iIndex = 0; iIndex < m_count; iIndex++)
|
|
{
|
|
if (m_entries[iIndex].dwCookie == dwCookie)
|
|
{
|
|
return Remove(iIndex);
|
|
}
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
/*
|
|
CNotifierList::GetAtIndex
|
|
|
|
Return the pointer to the IUnknown at zero based index iIndex.
|
|
|
|
Return the IUnknown at the given index. Note that the object pointer
|
|
is still owned by the IUnknown list and should not be deleted.
|
|
*/
|
|
|
|
HRESULT CNotifierList::GetAtIndex(int iIndex, IUnknown **ppunk)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
EnterCriticalSection(&m_rCritSect);
|
|
if (iIndex < m_count && iIndex >= 0 && m_entries[iIndex].punk)
|
|
{
|
|
*ppunk = m_entries[iIndex].punk;
|
|
(*ppunk)->AddRef();
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
*ppunk = NULL;
|
|
|
|
LeaveCriticalSection(&m_rCritSect);
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CNotifierList::CreateNotifyWindow()
|
|
{
|
|
DWORD dwThreadCount = 0;
|
|
DWORD dwThreadId = GetCurrentThreadId();
|
|
int iIndex;
|
|
int iFound = -1;
|
|
HWND hwnd = NULL;
|
|
|
|
for (iIndex = 0; iIndex < m_count; iIndex++)
|
|
{
|
|
if (m_entries[iIndex].dwThreadId == dwThreadId)
|
|
{
|
|
iFound = iIndex;
|
|
if (!hwnd)
|
|
hwnd = m_entries[iIndex].hwnd;
|
|
else
|
|
{
|
|
Assert(NULL == m_entries[iIndex].hwnd || hwnd == m_entries[iIndex].hwnd);
|
|
m_entries[iIndex].hwnd = hwnd;
|
|
}
|
|
dwThreadCount++;
|
|
}
|
|
}
|
|
|
|
if (dwThreadCount == 1 && iFound >= 0)
|
|
{
|
|
hwnd = m_entries[iFound].hwnd = CreateWindowA(c_szNotifyWindowClass, c_szNotifyWindowClass, WS_POPUP,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
|
|
NULL, g_hInst, this);
|
|
|
|
if (m_entries[iFound].hwnd)
|
|
SetWindowLongPtr(m_entries[iFound].hwnd, GWLP_USERDATA, (LRESULT)this);
|
|
}
|
|
return (hwnd ? S_OK : E_FAIL);
|
|
}
|
|
|
|
|
|
HRESULT CNotifierList::ReleaseWindow()
|
|
{
|
|
DWORD dwThreadCount = 0;
|
|
DWORD dwThreadId = GetCurrentThreadId();
|
|
int iIndex;
|
|
HWND hwnd = NULL;
|
|
|
|
for (iIndex = 0; iIndex < m_count; iIndex++)
|
|
{
|
|
if (m_entries[iIndex].dwThreadId == dwThreadId)
|
|
{
|
|
if (dwThreadCount == 0)
|
|
hwnd = m_entries[iIndex].hwnd;
|
|
dwThreadCount++;
|
|
}
|
|
}
|
|
|
|
if (dwThreadCount == 1 && hwnd)
|
|
{
|
|
SendMessage(hwnd, WM_CLOSE, 0, 0);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CNotifierList::PreNotify()
|
|
{
|
|
DWORD dwThreadId = GetCurrentThreadId();
|
|
int iIndex;
|
|
|
|
for (iIndex = m_count -1; iIndex >= 0; iIndex--)
|
|
{
|
|
if (m_entries[iIndex].dwThreadId == dwThreadId && NULL != m_entries[iIndex].punk)
|
|
m_entries[iIndex].bState = NS_PRE_NOTIFY;
|
|
// else //BUG 47472, this could cause problems during re-entrant calls to SendNotification
|
|
// m_entries[iIndex].bState = NS_NONE;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
int CNotifierList::GetNextNotify()
|
|
{
|
|
DWORD dwThreadId = GetCurrentThreadId();
|
|
int iIndex;
|
|
for (iIndex = m_count -1; iIndex >= 0; iIndex--)
|
|
{
|
|
if (m_entries[iIndex].dwThreadId == dwThreadId && NULL != m_entries[iIndex].punk && NS_PRE_NOTIFY == m_entries[iIndex].bState)
|
|
return iIndex;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
HRESULT CNotifierList::SendNotification(UINT msg, DWORD dwType)
|
|
{
|
|
DWORD dwThreadCount = 0, dwOldCount;
|
|
DWORD dwThreadId = GetCurrentThreadId();
|
|
int iIndex;
|
|
HWND hwnd = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
#if defined(DEBUG)
|
|
DebugStrf("Identity - CNotifierList::SendNotification %ld\r\n", msg);
|
|
#endif
|
|
|
|
AddRef();
|
|
|
|
PreNotify();
|
|
|
|
while ((iIndex = GetNextNotify()) != -1)
|
|
{
|
|
IUnknown *punk;
|
|
IIdentityChangeNotify *pICNotify;
|
|
|
|
punk = m_entries[iIndex].punk;
|
|
m_entries[iIndex].bState = NS_NOTIFIED;
|
|
|
|
punk->AddRef();
|
|
if (SUCCEEDED(punk->QueryInterface(IID_IIdentityChangeNotify, (void **)&pICNotify)) && pICNotify)
|
|
{
|
|
if( msg == WM_QUERY_IDENTITY_CHANGE )
|
|
{
|
|
if (FAILED(hr = pICNotify->QuerySwitchIdentities()))
|
|
{
|
|
punk->Release();
|
|
pICNotify->Release();
|
|
goto exit;
|
|
}
|
|
}
|
|
else if( msg == WM_IDENTITY_CHANGED )
|
|
{
|
|
pICNotify->SwitchIdentities();
|
|
}
|
|
else if( msg == WM_IDENTITY_INFO_CHANGED )
|
|
{
|
|
pICNotify->IdentityInformationChanged(dwType);
|
|
}
|
|
|
|
pICNotify->Release();
|
|
}
|
|
punk->Release();
|
|
}
|
|
|
|
exit:
|
|
Release();
|
|
return hr;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DebugStrf
|
|
// --------------------------------------------------------------------------------
|
|
void DebugStrf(LPTSTR lpszFormat, ...)
|
|
{
|
|
static TCHAR szDebugBuff[500];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, lpszFormat);
|
|
wvsprintf(szDebugBuff, lpszFormat, arglist);
|
|
va_end(arglist);
|
|
|
|
OutputDebugString(szDebugBuff);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
// Pstore code for storing passwords
|
|
// ---------------------------------------------------------------------------------
|
|
// Functions related to saving and restoring user passwords from the pstore.
|
|
|
|
|
|
// We have wrappers around Create and Release to allow for future caching of the pstore
|
|
// instance within webcheck.
|
|
|
|
STDAPI CreatePStore(IPStore **ppIPStore)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = PStoreCreateInstance ( ppIPStore,
|
|
NULL,
|
|
NULL,
|
|
0);
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDAPI ReleasePStore(IPStore *pIPStore)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (pIPStore)
|
|
{
|
|
pIPStore->Release();
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDAPI ReadIdentityPassword(GUID *puidIdentity, PASSWORD_STORE *pPwdStore)
|
|
{
|
|
GUID itemType = GUID_NULL;
|
|
GUID itemSubtype = GUID_NULL;
|
|
PST_PROMPTINFO promptInfo = {0};
|
|
IPStore* pStore = NULL;
|
|
HRESULT hr ;
|
|
|
|
if (pPwdStore == NULL)
|
|
return E_POINTER;
|
|
|
|
promptInfo.cbSize = sizeof(promptInfo);
|
|
promptInfo.szPrompt = NULL;
|
|
promptInfo.dwPromptFlags = 0;
|
|
promptInfo.hwndApp = NULL;
|
|
|
|
hr = CreatePStore(&pStore);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
Assert(pStore != NULL);
|
|
|
|
itemType = GUID_PStoreType;
|
|
itemSubtype = *puidIdentity;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD cbData;
|
|
BYTE *pbData = NULL;
|
|
|
|
|
|
hr = pStore->ReadItem(
|
|
s_Key,
|
|
&itemType,
|
|
&itemSubtype,
|
|
c_szIdentityPass,
|
|
&cbData,
|
|
&pbData,
|
|
&promptInfo,
|
|
0);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CopyMemory(pPwdStore, pbData, (cbData <= sizeof(PASSWORD_STORE) ? cbData : sizeof(PASSWORD_STORE)));
|
|
MemFree(pbData);
|
|
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
ReleasePStore(pStore);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDAPI WriteIdentityPassword(GUID *puidIdentity, PASSWORD_STORE *pPwdStore)
|
|
{
|
|
HRESULT hr;
|
|
PST_TYPEINFO typeInfo;
|
|
PST_PROMPTINFO promptInfo;
|
|
IPStore * pStore;
|
|
|
|
typeInfo.cbSize = sizeof(typeInfo);
|
|
|
|
typeInfo.szDisplayName = c_szIdentityMgr;
|
|
|
|
promptInfo.cbSize = sizeof(promptInfo);
|
|
promptInfo.dwPromptFlags = 0;
|
|
promptInfo.hwndApp = NULL;
|
|
promptInfo.szPrompt = NULL;
|
|
|
|
hr = CreatePStore(&pStore);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
GUID itemType = GUID_NULL;
|
|
GUID itemSubtype = GUID_NULL;
|
|
|
|
Assert(pStore != NULL);
|
|
|
|
itemType = GUID_PStoreType;
|
|
itemSubtype = *puidIdentity;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStore->CreateType(s_Key, &itemType, &typeInfo, 0);
|
|
|
|
// PST_E_TYPE_EXISTS implies type already exists which is just fine
|
|
// by us.
|
|
if (SUCCEEDED(hr) || hr == PST_E_TYPE_EXISTS)
|
|
{
|
|
typeInfo.szDisplayName = c_szIdentities;
|
|
|
|
hr = pStore->CreateSubtype(
|
|
s_Key,
|
|
&itemType,
|
|
&itemSubtype,
|
|
&typeInfo,
|
|
NULL,
|
|
0);
|
|
|
|
if (SUCCEEDED(hr) || hr == PST_E_TYPE_EXISTS)
|
|
{
|
|
if (pPwdStore != NULL)
|
|
{
|
|
hr = pStore->WriteItem(
|
|
s_Key,
|
|
&itemType,
|
|
&itemSubtype,
|
|
c_szIdentityPass,
|
|
(sizeof(PASSWORD_STORE)),
|
|
(BYTE *)pPwdStore,
|
|
&promptInfo,
|
|
PST_CF_NONE,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
hr = pStore->DeleteItem(
|
|
s_Key,
|
|
&itemType,
|
|
&itemSubtype,
|
|
c_szIdentityPass,
|
|
&promptInfo,
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ReleasePStore(pStore);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
#define CH_WHACK TEXT(FILENAME_SEPARATOR)
|
|
|
|
// rips the last part of the path off including the backslash
|
|
// C:\foo -> C:\ ;
|
|
// C:\foo\bar -> C:\foo
|
|
// C:\foo\ -> C:\foo
|
|
// \\x\y\x -> \\x\y
|
|
// \\x\y -> \\x
|
|
// \\x -> ?? (test this)
|
|
// \foo -> \ (Just the slash!)
|
|
//
|
|
// in/out:
|
|
// pFile fully qualified path name
|
|
// returns:
|
|
// TRUE we stripped something
|
|
// FALSE didn't strip anything (root directory case)
|
|
//
|
|
// Stolen from shlwapi\path.c
|
|
|
|
STDAPI_(BOOL) _PathRemoveFileSpec(LPTSTR pFile)
|
|
{
|
|
LPTSTR pT;
|
|
LPTSTR pT2 = pFile;
|
|
|
|
for (pT = pT2; *pT2; pT2 = CharNext(pT2)) {
|
|
if (*pT2 == CH_WHACK)
|
|
pT = pT2; // last "\" found, (we will strip here)
|
|
else if (*pT2 == TEXT(':')) { // skip ":\" so we don't
|
|
if (pT2[1] ==TEXT('\\')) // strip the "\" from "C:\"
|
|
pT2++;
|
|
pT = pT2 + 1;
|
|
}
|
|
}
|
|
if (*pT == 0)
|
|
return FALSE; // didn't strip anything
|
|
|
|
//
|
|
// handle the \foo case
|
|
//
|
|
else if ((pT == pFile) && (*pT == CH_WHACK)) {
|
|
// Is it just a '\'?
|
|
if (*(pT+1) != TEXT('\0')) {
|
|
// Nope.
|
|
*(pT+1) = TEXT('\0');
|
|
return TRUE; // stripped something
|
|
}
|
|
else {
|
|
// Yep.
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
*pT = 0;
|
|
return TRUE; // stripped something
|
|
}
|
|
}
|