windows-nt/Source/XPSP1/NT/shell/ext/msident/identmgr.cpp
2020-09-26 16:20:57 +08:00

1113 lines
29 KiB
C++

//
// ident.cpp - implementation of CIdentity class
//
#include "private.h"
#include "multiusr.h"
#include "multiui.h"
#include "strconst.h"
#include "resource.h"
#include "mluisup.h"
extern HINSTANCE g_hInst;
BOOL g_fReleasedMutex = true;
//
// Constructor / destructor
//
CUserIdentityManager::CUserIdentityManager()
{
m_cRef = 1;
m_fWndRegistered = FALSE;
m_hwnd = NULL;
m_pAdviseRegistry = NULL;
InitializeCriticalSection(&m_rCritSect);
DllAddRef();
}
CUserIdentityManager::~CUserIdentityManager()
{
if (m_pAdviseRegistry)
m_pAdviseRegistry->Release();
DeleteCriticalSection(&m_rCritSect);
DllRelease();
}
//
// IUnknown members
//
STDMETHODIMP CUserIdentityManager::QueryInterface(
REFIID riid, void **ppv)
{
if (NULL == ppv)
{
return E_INVALIDARG;
}
*ppv=NULL;
// Validate requested interface
if (IID_IUnknown == riid)
{
*ppv = (IUserIdentityManager *)this;
}
else if (IID_IUserIdentityManager == riid)
{
*ppv = (IUserIdentityManager *)this;
}
else if (IID_IConnectionPoint == riid)
{
*ppv = (IConnectionPoint *)this;
}
else if (IID_IPrivateIdentityManager == riid)
{
*ppv = (IPrivateIdentityManager *)this;
}
else if (IID_IPrivateIdentityManager2 == riid)
{
*ppv = (IPrivateIdentityManager2 *)this;
}
// Addref through the interface
if (NULL != *ppv) {
((LPUNKNOWN)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CUserIdentityManager::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CUserIdentityManager::Release()
{
if (0L != --m_cRef)
return m_cRef;
delete this;
return 0L;
}
STDMETHODIMP CUserIdentityManager::CreateIdentity(WCHAR *pszName, IUserIdentity **ppIdentity)
{
return CreateIdentity2(pszName, NULL, ppIdentity);
}
STDMETHODIMP CUserIdentityManager::CreateIdentity2(WCHAR *pszName, WCHAR *pszPassword, IUserIdentity **ppIdentity)
{
CUserIdentity *pIdentity;
HRESULT hr;
TCHAR szName[CCH_IDENTITY_NAME_MAX_LENGTH+1];
*ppIdentity = NULL;
if (MU_IdentitiesDisabled())
return E_IDENTITIES_DISABLED;
if (WideCharToMultiByte(CP_ACP, 0, pszName, -1, szName, CCH_IDENTITY_NAME_MAX_LENGTH, NULL, NULL) == 0)
return GetLastError();
if (MU_UsernameExists(szName))
return E_IDENTITY_EXISTS;
pIdentity = new CUserIdentity;
Assert(pIdentity);
if (!pIdentity)
return E_OUTOFMEMORY;
hr = pIdentity->SetName(pszName);
if (SUCCEEDED(hr))
{
if (pszPassword)
{
hr = pIdentity->SetPassword(pszPassword);
}
}
if (SUCCEEDED(hr))
{
*ppIdentity = pIdentity;
}
else
{
pIdentity->Release();
}
PostMessage(HWND_BROADCAST, WM_IDENTITY_INFO_CHANGED, 0, IIC_IDENTITY_ADDED);
return hr;
}
STDMETHODIMP CUserIdentityManager::ConfirmPassword(GUID *uidCookie, WCHAR *pszPassword)
{
TCHAR szPwd[CCH_USERPASSWORD_MAX_LENGTH+1];
HRESULT hr = E_FAIL;
USERINFO userInfo;
if (WideCharToMultiByte(CP_ACP, 0, pszPassword, -1, szPwd, CCH_USERPASSWORD_MAX_LENGTH, NULL, NULL) == 0)
return E_FAIL;
if (MU_GetUserInfo(uidCookie, &userInfo))
{
if (userInfo.fPasswordValid)
{
if (!userInfo.fUsePassword)
userInfo.szPassword[0] = 0;
if (lstrcmp(szPwd, userInfo.szPassword) == 0)
hr = S_OK;
else
hr = E_FAIL;
}
else
{
hr = E_FAIL;
}
}
return hr;
}
STDMETHODIMP CUserIdentityManager::DestroyIdentity(GUID *uidCookie)
{
if (MU_IdentitiesDisabled())
return E_IDENTITIES_DISABLED;
return MU_DeleteUser(uidCookie);
}
STDMETHODIMP CUserIdentityManager::EnumIdentities(IEnumUserIdentity **ppEnumIdentity)
{
CEnumUserIdentity *pEnumIdentity;
*ppEnumIdentity = NULL;
pEnumIdentity = new CEnumUserIdentity;
if (!pEnumIdentity)
return E_OUTOFMEMORY;
*ppEnumIdentity = pEnumIdentity;
return S_OK;
}
STDMETHODIMP CUserIdentityManager::SetDefaultIdentity(GUID *puidCookie)
{
if (MU_IdentitiesDisabled())
return E_IDENTITIES_DISABLED;
return MU_MakeDefaultUser(puidCookie);
}
STDMETHODIMP CUserIdentityManager::GetDefaultIdentity(GUID *puidCookie)
{
if (MU_IdentitiesDisabled())
return E_IDENTITIES_DISABLED;
return MU_GetDefaultUserID(puidCookie) ? S_OK : S_FALSE;
}
STDMETHODIMP CUserIdentityManager::ManageIdentities(HWND hwndParent, DWORD dwFlags)
{
TCHAR szUsername[CCH_USERNAME_MAX_LENGTH+1];
if (MU_IdentitiesDisabled())
return E_IDENTITIES_DISABLED;
*szUsername = 0;
MU_ManageUsers(hwndParent, szUsername, dwFlags);
// if the user created a new user and said they want to switch to them now,
// we should do so.
if (*szUsername)
{
BOOL fGotUser;
USERINFO rUser;
GUID uidUserID;
HRESULT hr;
fGotUser = MU_GetUserInfo(NULL, &rUser);
if (!fGotUser)
{
*rUser.szUsername = 0;
ZeroMemory(&rUser.uidUserID, sizeof(GUID));
}
MU_UsernameToUserId(szUsername, &uidUserID);
if (FAILED(hr = _SwitchToUser(&rUser.uidUserID, &uidUserID)))
{
SetForegroundWindow(hwndParent);
if (hr != E_USER_CANCELLED)
MU_ShowErrorMessage(hwndParent, idsSwitchCancelled, idsSwitchCancelCaption);
}
}
return S_OK;
}
STDMETHODIMP CUserIdentityManager::_PersistChangingIdentities()
{
HRESULT hr = E_FAIL;
HKEY hKeyIdentities = NULL;
if (ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER, c_szRegRoot, &hKeyIdentities))
{
goto exit;
}
if (ERROR_SUCCESS != RegSetValueEx(hKeyIdentities, c_szOutgoingID, 0, REG_BINARY, (LPBYTE)&g_uidOldUserId, sizeof(GUID)))
{
goto exit;
}
if (ERROR_SUCCESS != RegSetValueEx(hKeyIdentities, c_szIncomingID, 0, REG_BINARY, (LPBYTE)&g_uidNewUserId, sizeof(GUID)))
{
goto exit;
}
if (ERROR_SUCCESS != RegSetValueEx(hKeyIdentities, c_szChanging, 0, REG_BINARY, (LPBYTE)&g_fNotifyComplete, sizeof(g_fNotifyComplete)))
{
goto exit;
}
hr = S_OK;
exit:
if (hKeyIdentities)
{
RegCloseKey(hKeyIdentities);
}
return hr;
}
STDMETHODIMP CUserIdentityManager::_LoadChangingIdentities()
{
HRESULT hr = E_FAIL;
HKEY hKeyIdentities = NULL;
DWORD dwType, dwSize;
if (ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER, c_szRegRoot, &hKeyIdentities))
{
goto exit;
}
dwType = REG_BINARY;
dwSize = sizeof(GUID);
if (ERROR_SUCCESS != RegQueryValueEx(hKeyIdentities, c_szOutgoingID, 0, &dwType, (LPBYTE)&g_uidOldUserId, &dwSize))
{
goto exit;
}
dwSize = sizeof(GUID);
if (ERROR_SUCCESS != RegQueryValueEx(hKeyIdentities, c_szIncomingID, 0, &dwType, (LPBYTE)&g_uidNewUserId, &dwSize))
{
goto exit;
}
dwSize = sizeof(g_fNotifyComplete);
if (ERROR_SUCCESS != RegQueryValueEx(hKeyIdentities, c_szChanging, 0, &dwType, (LPBYTE)&g_fNotifyComplete, &dwSize))
{
goto exit;
}
hr = S_OK;
exit:
if (FAILED(hr))
{
g_uidOldUserId = GUID_NULL;
g_uidNewUserId = GUID_NULL;
g_fNotifyComplete = TRUE;
}
if (hKeyIdentities)
{
RegCloseKey(hKeyIdentities);
}
return hr;
}
STDMETHODIMP CUserIdentityManager::ClearChangingIdentities()
{
HRESULT hr = E_FAIL;
HKEY hKeyIdentities = NULL;
if (ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER, c_szRegRoot, &hKeyIdentities))
{
goto exit;
}
RegDeleteValue(hKeyIdentities, c_szChanging);
RegDeleteValue(hKeyIdentities, c_szIncomingID);
RegDeleteValue(hKeyIdentities, c_szOutgoingID);
hr = S_OK;
exit:
if (hKeyIdentities)
{
RegCloseKey(hKeyIdentities);
}
return hr;
}
STDMETHODIMP CUserIdentityManager::Logon(HWND hwndParent, DWORD dwFlags, IUserIdentity **ppIdentity)
{
CUserIdentity *pIdentity;
HRESULT hr = E_FAIL;
USERINFO rUser;
GUID uidUserID, uidNewUserID;
BOOL fGotUser;
TCHAR szOldUsername[CCH_USERNAME_MAX_LENGTH+1], szLogoffName[CCH_USERNAME_MAX_LENGTH+1];
TCHAR szRes[MAX_PATH];
// if identities are disabled, always return the default identity.
// if they are forcing the UI, return an error, otherwise succeed and
// send the message back that identities are disabled.
if (MU_IdentitiesDisabled())
{
if (!!(dwFlags & UIL_FORCE_UI))
return E_IDENTITIES_DISABLED;
hr = GetIdentityByCookie((GUID *)&UID_GIBC_DEFAULT_USER, ppIdentity);
return (SUCCEEDED(hr) ? S_IDENTITIES_DISABLED : hr);
}
if (!g_hMutex)
return E_UNEXPECTED;
_LoadChangingIdentities();
if (g_uidOldUserId != GUID_NULL || g_uidNewUserId != GUID_NULL)
{
// we are in the middle of a switch
if (!g_fNotifyComplete)
{
// and we are not done checking to see if a switch is ok.
if (!!(dwFlags & UIL_FORCE_UI)) //if its a force ui, then just fail.
return E_IDENTITY_CHANGING;
//otherwise, we need to do something here, but since they could be
//calling Login from the notifier proc, this could create a deadlock,
//but returning either the old or the new could be wrong. Return the
//same error here unless we can come up with a better solution.
return E_IDENTITY_CHANGING;
}
}
DWORD dwWaitResult;
dwWaitResult = WaitForSingleObject(g_hMutex, 5000);
g_fReleasedMutex = false;
if (dwWaitResult == WAIT_TIMEOUT)
{
char szMsg[255], szTitle[63];
// someone else seems to have a login dialog up. Notify the user
// about this problem and bail.
if (!!(dwFlags & UIL_FORCE_UI))
{
MLLoadStringA(idsSwitchInProgressSwitch, szMsg, ARRAYSIZE(szMsg));
MLLoadStringA(idsSwitchIdentities, szTitle, ARRAYSIZE(szTitle));
}
else
{
MLLoadStringA(idsSwitchInProgressLaunch, szMsg, ARRAYSIZE(szMsg));
MLLoadStringA(idsIdentityLogin, szTitle, ARRAYSIZE(szTitle));
}
MessageBox(hwndParent, szMsg, szTitle, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
return E_UNEXPECTED;
}
*ppIdentity = NULL;
fGotUser = MU_GetUserInfo(NULL, &rUser);
if (!fGotUser)
{
*rUser.szUsername = 0;
ZeroMemory(&rUser.uidUserID, sizeof(GUID));
}
lstrcpy(szOldUsername, rUser.szUsername);
// if we don't have to do the UI and there is a current
// user, then just return that identity
if (!(dwFlags & UIL_FORCE_UI) && fGotUser)
{
pIdentity = new CUserIdentity;
if (!pIdentity)
hr = E_OUTOFMEMORY;
if (pIdentity && SUCCEEDED(hr = pIdentity->InitFromUsername(rUser.szUsername)))
*ppIdentity = pIdentity;
}
else
{
if (0 == *rUser.szUsername)
{
GUID uidStart;
MU_GetLoginOption(&uidStart);
if (GUID_NULL != uidStart)
{
MU_GetUserInfo(&uidStart, &rUser);
rUser.uidUserID = GUID_NULL;
}
}
if (MU_Login(hwndParent, dwFlags, rUser.szUsername))
{
MLLoadStringA(idsLogoff, szLogoffName, sizeof(szLogoffName));
if (lstrcmp(szLogoffName, rUser.szUsername) == 0)
{
MLLoadStringA(idsConfirmLogoff, szRes, sizeof(szRes));
if (MessageBox(hwndParent, szRes, szLogoffName, MB_YESNO) == IDYES)
{
ReleaseMutex(g_hMutex);
g_fReleasedMutex = true;
Logoff(hwndParent);
}
}
else
{
pIdentity = new CUserIdentity;
if (pIdentity)
{
hr = pIdentity->InitFromUsername(rUser.szUsername);
if (SUCCEEDED(hr))
{
pIdentity->GetCookie(&uidNewUserID);
hr = _SwitchToUser(&rUser.uidUserID, &uidNewUserID);
*ppIdentity = pIdentity;
}
if (FAILED(hr))
{
UINT iMsgId = idsSwitchCancelled;
pIdentity->Release();
*ppIdentity = NULL;
SetForegroundWindow(hwndParent);
// could switch on some error codes to set iMsgId to
// other error messages. For now, skip showing the
// message if a user did the cancelling
if (hr != E_USER_CANCELLED)
MU_ShowErrorMessage(hwndParent, iMsgId, idsSwitchCancelCaption);
}
}
}
}
else
hr = E_USER_CANCELLED;
}
if (!g_fReleasedMutex)
ReleaseMutex(g_hMutex);
return hr;
}
STDMETHODIMP CUserIdentityManager::Logoff(HWND hwndParent)
{
GUID uidToID = GUID_NULL;
HRESULT hr;
USERINFO rUser;
BOOL fGotUser;
if (!g_hMutex)
return E_UNEXPECTED;
DWORD dwWaitResult;
dwWaitResult = WaitForSingleObject(g_hMutex, INFINITE);
if (dwWaitResult != WAIT_OBJECT_0)
return E_UNEXPECTED;
fGotUser = MU_GetUserInfo(NULL, &rUser);
if (!fGotUser)
rUser.uidUserID = GUID_NULL;
// switch to the null user
hr = _SwitchToUser(&rUser.uidUserID, &uidToID);
if (FAILED(hr))
{
UINT iMsgId = idsLogoutCancelled;
SetForegroundWindow(hwndParent);
// could switch on some error codes to set iMsgId to
// other error messages. For now, skip showing the
// message if a user did the cancelling
if (hr != E_USER_CANCELLED)
MU_ShowErrorMessage(hwndParent, iMsgId, idsSwitchCancelCaption);
}
ReleaseMutex(g_hMutex);
return hr;
}
STDMETHODIMP CUserIdentityManager::_SwitchToUser(GUID *puidFromUser, GUID *puidToUser)
{
TCHAR szUsername[CCH_USERNAME_MAX_LENGTH+1] = "";
HRESULT hr;
// switching to the same user is automatically OK.
if (*puidFromUser == *puidToUser)
return S_OK;
// Set up the from and to users
g_uidOldUserId = *puidFromUser;
g_uidNewUserId = *puidToUser;
g_fNotifyComplete = FALSE;
_PersistChangingIdentities();
if (*puidToUser != GUID_NULL)
MU_UserIdToUsername(puidToUser, szUsername, CCH_USERNAME_MAX_LENGTH);
// Notify window's that a switch is coming
if (SUCCEEDED(hr = _QueryProcessesCanSwitch()))
{
if (SUCCEEDED(hr = MU_SwitchToUser(szUsername)))
{
if (!g_fReleasedMutex)
{
g_fReleasedMutex = true;
g_fNotifyComplete = true;
ReleaseMutex(g_hMutex);
}
_NotifyIdentitiesSwitched();
}
}
g_fNotifyComplete = TRUE;
// clear these back out again
g_uidOldUserId = GUID_NULL;
g_uidNewUserId = GUID_NULL;
ClearChangingIdentities();
return hr;
}
STDMETHODIMP CUserIdentityManager::GetIdentityByCookie(GUID *uidCookie, IUserIdentity **ppIdentity)
{
CUserIdentity *pIdentity;
HRESULT hr = E_IDENTITY_NOT_FOUND;
GUID uidUserCookie = *uidCookie;
*ppIdentity = NULL;
if (MU_IdentitiesDisabled())
{
// if disabled, they can only get the default identity.
// if asking for the current, they will get the defalt.
// if asking for default by the constant or the default's guid, then succeed.
// otherwise return an error.
if (!MU_GetDefaultUserID(&uidUserCookie))
return E_IDENTITY_NOT_FOUND;
if (UID_GIBC_CURRENT_USER == uidUserCookie)
uidUserCookie = UID_GIBC_DEFAULT_USER;
if (!(uidUserCookie == uidUserCookie || UID_GIBC_DEFAULT_USER == uidUserCookie))
return E_IDENTITIES_DISABLED;
}
if (uidUserCookie == UID_GIBC_DEFAULT_USER)
{
if (!MU_GetDefaultUserID(&uidUserCookie))
return E_IDENTITY_NOT_FOUND;
}
else if (uidUserCookie == UID_GIBC_CURRENT_USER)
{
if (!MU_GetCurrentUserID(&uidUserCookie))
return E_NO_CURRENT_IDENTITY;
}
else if (uidUserCookie == UID_GIBC_OUTGOING_USER)
{
_LoadChangingIdentities();
if (g_uidOldUserId == GUID_NULL)
return E_IDENTITY_NOT_FOUND;
else
uidUserCookie = g_uidOldUserId;
}
else if (uidUserCookie == UID_GIBC_INCOMING_USER)
{
_LoadChangingIdentities();
if (g_uidNewUserId == GUID_NULL)
return E_IDENTITY_NOT_FOUND;
else
uidUserCookie = g_uidNewUserId;
}
pIdentity = new CUserIdentity;
if (pIdentity)
{
hr = pIdentity->InitFromCookie(&uidUserCookie);
if (SUCCEEDED(hr))
*ppIdentity = pIdentity;
else
{
// Cleanup
delete pIdentity;
}
}
return hr;
}
STDMETHODIMP CUserIdentityManager::GetConnectionInterface(IID *pIID)
{
return E_NOTIMPL;
}
STDMETHODIMP CUserIdentityManager::GetConnectionPointContainer(IConnectionPointContainer **ppCPC)
{
*ppCPC = NULL;
return E_NOTIMPL;
}
STDMETHODIMP CUserIdentityManager::Advise(IUnknown *pUnkSink, DWORD *pdwCookie)
{
HRESULT hr;
EnterCriticalSection(&m_rCritSect);
AddRef();
if (!m_pAdviseRegistry)
m_pAdviseRegistry = new CNotifierList;
Assert(m_pAdviseRegistry);
if (m_pAdviseRegistry)
{
if (!m_fWndRegistered)
_CreateWindowClass();
hr = m_pAdviseRegistry->Add(pUnkSink, pdwCookie);
}
else
hr = E_OUTOFMEMORY;
LeaveCriticalSection(&m_rCritSect);
return hr;
}
STDMETHODIMP CUserIdentityManager::Unadvise(DWORD dwCookie)
{
HRESULT hr;
EnterCriticalSection(&m_rCritSect);
if (m_pAdviseRegistry)
{
hr = m_pAdviseRegistry->RemoveCookie(dwCookie);
}
else
hr = E_FAIL;
LeaveCriticalSection(&m_rCritSect);
Release();
return hr;
}
STDMETHODIMP CUserIdentityManager::EnumConnections(IEnumConnections **ppEnum)
{
*ppEnum = NULL;
return E_NOTIMPL;
}
STDMETHODIMP CUserIdentityManager::QuerySwitchIdentities()
{
HRESULT hr = S_OK;
DWORD dwLength, dwIndex;
if (!m_pAdviseRegistry)
return S_OK;
TraceCall("Identity - CUserIdentityManager::QuerySwitchIdentities");
dwLength = m_pAdviseRegistry->GetLength();
for (dwIndex = 0; dwIndex < dwLength; dwIndex++)
{
IUnknown *punk;
IIdentityChangeNotify *pICNotify;
if (SUCCEEDED(m_pAdviseRegistry->GetAtIndex(dwIndex, &punk)) && punk)
{
if (SUCCEEDED(punk->QueryInterface(IID_IIdentityChangeNotify, (void **)&pICNotify)) && pICNotify)
{
if (FAILED(hr = pICNotify->QuerySwitchIdentities()))
{
punk->Release();
pICNotify->Release();
goto exit;
}
pICNotify->Release();
}
punk->Release();
}
}
exit:
return hr;
}
STDMETHODIMP CUserIdentityManager::NotifySwitchIdentities()
{
HRESULT hr = S_OK;
DWORD dwLength, dwIndex;
if (!m_pAdviseRegistry)
return S_OK;
TraceCall("Identity - CUserIdentityManager::NotifySwitchIdentities");
dwLength = m_pAdviseRegistry->GetLength();
for (dwIndex = 0; dwIndex < dwLength; dwIndex++)
{
IUnknown *punk;
IIdentityChangeNotify *pICNotify;
if (SUCCEEDED(m_pAdviseRegistry->GetAtIndex(dwIndex, &punk)) && punk)
{
if (SUCCEEDED(punk->QueryInterface(IID_IIdentityChangeNotify, (void **)&pICNotify)) && pICNotify)
{
if (FAILED(hr = pICNotify->SwitchIdentities()))
{
punk->Release();
pICNotify->Release();
goto exit;
}
pICNotify->Release();
}
punk->Release();
}
}
exit:
return hr;
}
STDMETHODIMP CUserIdentityManager::_QueryProcessesCanSwitch()
{
HWND hWnd, hNextWnd = NULL;
LRESULT lResult;
HWND *prghwnd = NULL;
DWORD chwnd = 0, cAllocHwnd = 0, dw;
HRESULT hr;
TraceCall("Identity - CUserIdentityManager::_QueryProcessesCanSwitch");
cAllocHwnd = 10;
if (!MemAlloc((LPVOID*)(&prghwnd), cAllocHwnd * sizeof(HWND)))
return E_OUTOFMEMORY;
hWnd = GetTopWindow(NULL);
while (hWnd)
{
hNextWnd = GetNextWindow(hWnd, GW_HWNDNEXT);
if (!IsWindowVisible(hWnd))
{
TCHAR szWndClassName[255];
GetClassName(hWnd, szWndClassName, sizeof(szWndClassName));
if (lstrcmp(szWndClassName, c_szNotifyWindowClass) == 0)
{
if (chwnd == cAllocHwnd)
{
cAllocHwnd += 10;
if (!MemRealloc((LPVOID*)(&prghwnd), cAllocHwnd * sizeof(HWND)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
}
prghwnd[chwnd++] = hWnd;
}
}
hWnd = hNextWnd;
}
hr = S_OK;
for (dw = 0; dw < chwnd; dw++)
{
if (IsWindow(prghwnd[dw]))
{
lResult = SendMessage(prghwnd[dw], WM_QUERY_IDENTITY_CHANGE, 0, 0);
if (FAILED((HRESULT)lResult))
{
hr = (HRESULT)lResult;
goto exit;
}
}
}
exit:
MemFree(prghwnd);
prghwnd = NULL;
return hr;
}
STDMETHODIMP CUserIdentityManager::_NotifyIdentitiesSwitched()
{
HWND hWnd, hNextWnd = NULL;
LRESULT lResult;
HWND *prghwnd = NULL;
DWORD chwnd = 0, cAllocHwnd = 0, dw;
TraceCall("Identity - CUserIdentityManager::_NotifyIdentitiesSwitched");
cAllocHwnd = 10;
if (!MemAlloc((LPVOID*)(&prghwnd), cAllocHwnd * sizeof(HWND)))
return E_OUTOFMEMORY;
hWnd = GetTopWindow(NULL);
while (hWnd)
{
hNextWnd = GetNextWindow(hWnd, GW_HWNDNEXT);
if (!IsWindowVisible(hWnd))
{
TCHAR szWndClassName[255];
GetClassName(hWnd, szWndClassName, sizeof(szWndClassName));
if (lstrcmp(szWndClassName, c_szNotifyWindowClass) == 0)
{
if (chwnd == cAllocHwnd)
{
cAllocHwnd += 10;
if (!MemRealloc((LPVOID*)(&prghwnd), cAllocHwnd * sizeof(HWND)))
goto exit;
}
prghwnd[chwnd++] = hWnd;
}
}
hWnd = hNextWnd;
}
for (dw = 0; dw < chwnd; dw++)
{
DWORD_PTR dwResult;
if (IsWindow(prghwnd[dw]))
// lResult = PostMessage(prghwnd[dw], WM_IDENTITY_CHANGED, 0, 0); //Raid 48054
SendMessageTimeout(prghwnd[dw], WM_IDENTITY_CHANGED, 0, 0, SMTO_ABORTIFHUNG | SMTO_NORMAL, 1500, &dwResult);
}
exit:
MemFree(prghwnd);
prghwnd = NULL;
return S_OK;
}
STDMETHODIMP CUserIdentityManager::_CreateWindowClass()
{
WNDCLASS wc;
if (!m_fWndRegistered) /*set up window class and register it */
{
wc.lpszClassName = c_szNotifyWindowClass;
wc.hInstance = g_hInst;
wc.lpfnWndProc = CUserIdentityManager::WndProc;
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.lpszMenuName = NULL;
wc.hbrBackground = NULL;
wc.style = CS_DBLCLKS;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
if (!RegisterClassA(&wc))
return E_FAIL;
m_fWndRegistered = TRUE;
}
return S_OK;
}
LRESULT CALLBACK CUserIdentityManager::WndProc(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
CNotifierList *pList = NULL;
HRESULT hr;
if (messg == WM_QUERY_IDENTITY_CHANGE ||
messg == WM_IDENTITY_CHANGED ||
messg == WM_IDENTITY_INFO_CHANGED)
{
#if defined(DEBUG)
DebugStrf("Identity - CUserIdentityManager::WndProc() called for notification.\r\n");
#endif
pList = (CNotifierList *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (pList)
{
hr = pList->SendNotification(messg, (DWORD)lParam);
return hr;
}
}
else
{
switch(messg)
{
case WM_CREATE:
LPCREATESTRUCT pcs;
pcs = (LPCREATESTRUCT)lParam;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LRESULT)pcs->lpCreateParams);
return(DefWindowProc(hWnd, messg, wParam, lParam));
break;
/*
case WM_QUERY_IDENTITY_CHANGE:
case WM_IDENTITY_CHANGED:
case WM_IDENTITY_INFO_CHANGED:
DebugStrf("Identity - CUserIdentityManager::WndProc() called for notification.\r\n");
pList = (CNotifierList *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (pList)
{
hr = pList->SendNotification(messg, (DWORD)lParam);
return hr;
}
break;
*/
case WM_CLOSE:
SetWindowLongPtr(hWnd, GWLP_USERDATA, 0);
return(DefWindowProc(hWnd, messg, wParam, lParam));
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam));
}
}
return 0;
}
//----------------------------------------------------------------------------
// Logon the specified user.
// - Checks password
//----------------------------------------------------------------------------
STDMETHODIMP CUserIdentityManager::LogonAs(WCHAR *pszName, WCHAR *pszPassword, IUserIdentity **ppIdentity)
{
CUserIdentity *pIdentity;
HRESULT hr = E_FAIL;
USERINFO rUser;
GUID uidNewUserID;
BOOL fGotUser;
TCHAR szName[CCH_USERNAME_MAX_LENGTH+1];
if (WideCharToMultiByte(CP_ACP, 0, pszName, -1, szName, CCH_USERNAME_MAX_LENGTH, NULL, NULL) == 0)
{
return E_FAIL;
}
// if identities are disabled, always return the default identity.
if (MU_IdentitiesDisabled())
{
hr = GetIdentityByCookie((GUID *)&UID_GIBC_DEFAULT_USER, ppIdentity);
return (SUCCEEDED(hr) ? S_IDENTITIES_DISABLED : hr);
}
if (!g_hMutex)
return E_UNEXPECTED;
if (g_uidOldUserId != GUID_NULL || g_uidOldUserId != GUID_NULL)
{
// we are in the middle of a switch
if (!g_fNotifyComplete)
{
return E_IDENTITY_CHANGING;
}
}
*ppIdentity = NULL;
//
// Grab info on the current user
//
fGotUser = MU_GetUserInfo(NULL, &rUser);
if (!fGotUser)
{
*rUser.szUsername = 0;
ZeroMemory(&rUser.uidUserID, sizeof(GUID));
}
if (0 == *rUser.szUsername)
{
GUID uidStart;
MU_GetLoginOption(&uidStart);
if (GUID_NULL != uidStart)
{
MU_GetUserInfo(&uidStart, &rUser);
rUser.uidUserID = GUID_NULL;
}
}
pIdentity = new CUserIdentity;
if (pIdentity)
{
hr = pIdentity->InitFromUsername(szName);
if (SUCCEEDED(hr))
{
pIdentity->GetCookie(&uidNewUserID);
hr= ConfirmPassword(&uidNewUserID, pszPassword);
if (SUCCEEDED(hr))
{
hr = _SwitchToUser(&rUser.uidUserID, &uidNewUserID);
if (SUCCEEDED(hr))
{
*ppIdentity = pIdentity;
}
else
{
UINT iMsgId = idsSwitchCancelled;
pIdentity->Release();
*ppIdentity = NULL;
// could switch on some error codes to set iMsgId to
// other error messages. For now, skip showing the
// message if a user did the cancelling
if (hr != E_USER_CANCELLED)
MU_ShowErrorMessage(NULL, iMsgId, idsSwitchCancelCaption);
}
} // ConfirmPassword()
} // InitFromUsername()
}
if (!g_fReleasedMutex)
ReleaseMutex(g_hMutex);
return hr;
}