winamp/Src/auth/Loginbox/resultWinampAuth.cpp

575 lines
12 KiB
C++
Raw Normal View History

2024-09-24 12:54:57 +00:00
#include "./resultWinampAuth.h"
#include "./common.h"
#include "./commandWinampAuth.h"
#include "./loginData.h"
#include "./dataCredentials.h"
#include "./loginCredentials.h"
#include "./loginbox.h"
#include "../resource.h"
LoginResultWinampAuth::LoginResultWinampAuth(api_auth *auth, LoginDataCredentials *pInput, Callback fnCallback, void *pUser)
: ref(1), authApi(auth), input(pInput), callback(fnCallback), user(pUser),
thread(NULL), abort(NULL), completed(NULL), credentials(NULL), authCode(AUTH_NOT_AUTHORIZED), statusCookie(0)
{
InitializeCriticalSection(&lock);
authApi->AddRef();
input->AddRef();
}
LoginResultWinampAuth::~LoginResultWinampAuth()
{
if (NULL != abort)
CloseHandle(abort);
if (NULL != completed)
CloseHandle(completed);
if (NULL != thread)
CloseHandle(thread);
authApi->Release();
input->Release();
if (NULL != credentials)
credentials->Release();
DeleteCriticalSection(&lock);
}
HRESULT LoginResultWinampAuth::CreateInstance(LoginData *input, Callback callback, void *user, LoginResultWinampAuth **instance)
{
if (NULL == instance) return E_POINTER;
*instance = NULL;
LoginDataCredentials *credentialsInput;
if (NULL == input || FAILED(input->QueryInterface(IID_LoginDataCredentials, (void**)&credentialsInput)))
return E_INVALIDARG;
HRESULT hr;
api_auth *authApi;
HWND hLoginbox = credentialsInput->GetLoginbox();
if (NULL == hLoginbox || FALSE == LoginBox_GetAuthApi(hLoginbox, &authApi))
hr = E_FAIL;
else
{
LoginResultWinampAuth *result = new LoginResultWinampAuth(authApi, credentialsInput, callback, user);
if (NULL == result)
hr = E_OUTOFMEMORY;
else
{
hr = result->Start();
if (FAILED(hr))
{
result->Release();
result = NULL;
}
else
{
*instance = result;
}
}
authApi->Release();
}
credentialsInput->Release();
return hr;
}
STDMETHODIMP_(ULONG) LoginResultWinampAuth::AddRef(void)
{
return InterlockedIncrement((LONG*)&ref);
}
STDMETHODIMP_(ULONG) LoginResultWinampAuth::Release(void)
{
if (0 == ref)
return ref;
LONG r = InterlockedDecrement((LONG*)&ref);
if (0 == r)
delete(this);
return r;
}
STDMETHODIMP LoginResultWinampAuth::QueryInterface(REFIID riid, PVOID *ppvObject)
{
if (NULL == ppvObject)
return E_POINTER;
if (IsEqualIID(riid, LCUID_WINAMPAUTH))
*ppvObject = static_cast<LoginResultWinampAuth*>(this);
else if (IsEqualIID(riid, IID_IUnknown))
*ppvObject = static_cast<IUnknown*>(this);
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
if (NULL == *ppvObject)
return E_UNEXPECTED;
AddRef();
return S_OK;
}
size_t LoginResultWinampAuth::Wasabi_AddRef()
{
return AddRef();
}
size_t LoginResultWinampAuth::Wasabi_Release()
{
return Release();
}
int LoginResultWinampAuth::Wasabi_QueryInterface(GUID iid, void **object)
{
return QueryInterface(iid, object);
}
HRESULT LoginResultWinampAuth::Start()
{
//HRESULT hr;
HANDLE threadCopy = NULL;
input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_INITIALIZING));
EnterCriticalSection(&lock);
if (NULL != thread)
{
//hr = E_PENDING;
}
else
{
AddRef();
thread = CreateThread(NULL, 0, WinampAuth_ThreadProcCallback, this, CREATE_SUSPENDED, NULL);
if (NULL == thread)
{
Release();
}
else
{
if (0 == DuplicateHandle(GetCurrentProcess(), thread, GetCurrentProcess(), &threadCopy, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
ResumeThread(thread); // grr...
threadCopy = NULL;
}
}
}
LeaveCriticalSection(&lock);
if (NULL != threadCopy)
{
ResumeThread(threadCopy);
CloseHandle(threadCopy);
}
return S_OK;
}
DWORD LoginResultWinampAuth::ThreadProc()
{
Callback callbackCopy(NULL);
HANDLE completedCopy(NULL);
INT resultCode = AUTH_SUCCESS;
LPWSTR username(NULL), password(NULL);
api_auth::AuthResults authResults;
SecureZeroMemory(&authResults, sizeof(authResults));
EnterCriticalSection(&lock);
authCode = AUTH_NOT_AUTHORIZED;
if (NULL != credentials)
{
credentials->Release();
credentials = NULL;
}
LeaveCriticalSection(&lock);
username = GetUsername(input->GetUsername(), &resultCode);
if (AUTH_SUCCESS == resultCode)
password = GetPassword(input->GetPassword(), &resultCode);
if (AUTH_SUCCESS == resultCode)
{
if (NULL == input->GetContext())
{
resultCode = authApi->Login(username, password, &authResults, this);
}
else
{
LPWSTR passcode = GetPasscode(input->GetPasscode(), &resultCode);
if (AUTH_SUCCESS == resultCode)
{
resultCode = authApi->LoginSecurID(username, password, input->GetContext(), passcode, &authResults, this);
LoginBox_FreeStringSecure(passcode);
}
}
}
EnterCriticalSection(&lock);
authCode = resultCode;
switch(authCode)
{
case AUTH_SUCCESS:
{
GUID realm;
if (FAILED(input->GetRealm(&realm)) ||
FAILED(LoginCredentials::CreateInstance(&realm, username, authResults.session_key,
authResults.token, authResults.expire, &credentials)))
{
authCode = AUTH_UNEXPECTED;
}
}
break;
case AUTH_SECURID:
if(FAILED(input->SetContext(authResults.context)))
authCode = AUTH_NOT_AUTHORIZED;
break;
}
INT statusId;
switch(authCode)
{
case AUTH_SUCCESS: statusId = IDS_STATUS_SUCCEEDED; break;
case AUTH_SECURID: statusId = IDS_STATUS_PASSCODE_REQUIRED; break;
case AUTH_ABORT: statusId = IDS_STATUS_ABORTED; break;
default: statusId = IDS_STATUS_FAILED; break;
}
input->SetStatus(MAKEINTRESOURCE(statusId));
CloseHandle(thread);
thread = NULL;
callbackCopy = callback;
if (NULL == completed || FALSE == DuplicateHandle(GetCurrentProcess(), completed,
GetCurrentProcess(), &completedCopy, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
completedCopy = NULL;
}
LeaveCriticalSection(&lock);
SecureZeroMemory(&authResults, sizeof(authResults));
LoginBox_FreeStringSecure(username);
LoginBox_FreeStringSecure(password);
if (NULL != completedCopy)
{
SetEvent(completedCopy);
CloseHandle(completedCopy);
}
if (NULL != callbackCopy)
callbackCopy(this);
return 0;
}
HRESULT LoginResultWinampAuth::GetWaitHandle(HANDLE *handle)
{
if (NULL == handle)
return E_POINTER;
HRESULT hr = S_OK;
EnterCriticalSection(&lock);
if (NULL == completed)
{
completed = CreateEvent(NULL, TRUE, (S_OK == IsCompleted()), NULL);
if (NULL == completed)
{
*handle = NULL;
DWORD error = GetLastError();
hr = HRESULT_FROM_WIN32(error);
}
}
if (SUCCEEDED(hr) &&
FALSE == DuplicateHandle(GetCurrentProcess(), completed,
GetCurrentProcess(), handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
*handle = NULL;
DWORD error = GetLastError();
hr = HRESULT_FROM_WIN32(error);
}
LeaveCriticalSection(&lock);
return hr;
}
HRESULT LoginResultWinampAuth::GetUser(void **pUser)
{
if (NULL == pUser) return E_POINTER;
EnterCriticalSection(&lock);
*pUser = user;
LeaveCriticalSection(&lock);
return S_OK;
}
HRESULT LoginResultWinampAuth::RequestAbort(BOOL fDrop)
{
HRESULT hr;
EnterCriticalSection(&lock);
if (NULL == abort)
{
abort = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == abort)
{
DWORD error = GetLastError();
hr = HRESULT_FROM_WIN32(error);
}
}
if (NULL != abort && FALSE == SetEvent(abort))
{
DWORD error = GetLastError();
hr = HRESULT_FROM_WIN32(error);
}
else
{
input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_ABORTING));
}
if (FALSE != fDrop)
{
callback = NULL;
user = NULL;
}
LeaveCriticalSection(&lock);
return hr;
}
HRESULT LoginResultWinampAuth::IsCompleted()
{
return (NULL == thread) ? S_OK : S_FALSE;
}
HRESULT LoginResultWinampAuth::IsAborting()
{
return IsAbortingEx(0);
}
HRESULT LoginResultWinampAuth::IsAbortingEx(UINT waitMs)
{
return (NULL != abort && WAIT_OBJECT_0 == WaitForSingleObjectEx(abort, waitMs, TRUE))?
S_OK : S_FALSE;
}
HRESULT LoginResultWinampAuth::GetLoginData(LoginData **loginData)
{
if (NULL == loginData) return E_POINTER;
EnterCriticalSection(&lock);
*loginData = input;
if (NULL != input)
input->AddRef();
LeaveCriticalSection(&lock);
return S_OK;
}
HRESULT LoginResultWinampAuth::GetResult(INT *pAuthCode, LoginCredentials **ppCredentials)
{
if (S_OK != IsCompleted())
return E_PENDING;
EnterCriticalSection(&lock);
if (NULL != pAuthCode)
*pAuthCode = authCode;
if (NULL != ppCredentials)
{
*ppCredentials = credentials;
if (NULL != credentials)
credentials->AddRef();
}
LeaveCriticalSection(&lock);
return S_OK;
}
int LoginResultWinampAuth::Event_AuthConnecting()
{
if (S_OK == IsAbortingEx(0))
return 1;
input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_CONNECTING));
return 0;
}
int LoginResultWinampAuth::Event_AuthSending()
{
if (S_OK == IsAbortingEx(0))
return 1;
input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_SENDING));
return 0;
}
int LoginResultWinampAuth::Event_AuthReceiving()
{
if (S_OK == IsAbortingEx(0))
return 1;
input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_RECEIVING));
return 0;
}
int LoginResultWinampAuth::Event_AuthIdle()
{
if (S_OK == IsAbortingEx(50))
return 1;
return 0;
}
LPWSTR LoginResultWinampAuth::GetUsername(LPCWSTR pszInput, INT *authError)
{
return MakeAuthParam(pszInput, -1, 3, 48, TRUE, TRUE, (0xFFFF & ~C1_CNTRL), AUTH_USERNAME, authError);
}
LPWSTR LoginResultWinampAuth::GetPassword(LPCWSTR pszInput, INT *authError)
{
return MakeAuthParam(pszInput, -1, 6, 48, TRUE, FALSE, (0xFFFF & ~C1_CNTRL), AUTH_PASSWORD, authError);
}
LPWSTR LoginResultWinampAuth::GetPasscode(LPCWSTR pszInput, INT *authError)
{
return MakeAuthParam(pszInput, -1, 6, 6, FALSE, FALSE, C1_DIGIT, AUTH_PASSCODE, authError);
}
LPWSTR LoginResultWinampAuth::MakeAuthParam(LPCWSTR pszInput, INT cchInput, INT min, INT max, BOOL removeSpaces, BOOL firstLetter, WORD typeMask, INT errorBase, INT *authError)
{
if (cchInput < 0 || NULL == pszInput)
cchInput = (NULL != pszInput) ? lstrlen(pszInput) : 0;
if (cchInput < min || (FALSE == removeSpaces && cchInput > max))
{
if (NULL != authError)
*authError = errorBase + ((cchInput < min) ? AUTHPARAM_TOOSHORT : AUTHPARAM_TOOLONG);
return NULL;
}
WORD *info = (WORD*)calloc(cchInput, sizeof(WORD));
if (NULL == info)
{
if (NULL != authError) *authError = AUTH_UNEXPECTED;
return NULL;
}
if (FALSE == GetStringTypeW(CT_CTYPE1, pszInput, cchInput, info))
{
free(info);
if (NULL != authError) *authError = AUTH_UNEXPECTED;
return NULL;
}
INT error = AUTH_SUCCESS;
LPWSTR dest = NULL;
BOOL firstChecked = FALSE;
INT cchSpaces = 0;
for (INT i = 0; i < cchInput; i++)
{
if (FALSE != removeSpaces && 0 != (C1_SPACE & info[i]))
cchSpaces++;
else if (0 == (typeMask & info[i]))
{
error = errorBase + AUTHPARAM_BADFORMAT;
break;
}
else
{
if (FALSE != firstLetter && FALSE == firstChecked)
{
if (0 == (C1_ALPHA & info[i]))
{
error = errorBase + AUTHPARAM_BADFORMAT;
break;
}
firstChecked = TRUE;
}
}
}
if (AUTH_SUCCESS == error)
{
INT cchTotal = cchInput - cchSpaces;
if (cchTotal < min)
error = errorBase + AUTHPARAM_TOOSHORT;
else if (cchTotal > max)
error = errorBase + AUTHPARAM_TOOLONG;
else
{
dest = LoginBox_MallocString(cchTotal + 1);
if (NULL == dest)
error = AUTH_UNEXPECTED;
else
{
if (FALSE != removeSpaces)
{
LPCWSTR s = pszInput;
LPWSTR d = dest;
for (INT i = 0; i < cchInput; i++, s++)
{
if (0 == (C1_SPACE & info[i]))
{
*d = *s;
d++;
}
}
*d = L'\0';
}
else
{
CopyMemory(dest, pszInput, (cchInput * sizeof(WCHAR)));
dest[cchInput] = L'\0';
}
}
}
}
free(info);
if (NULL != authError)
*authError = error;
return dest;
}
static DWORD WINAPI WinampAuth_ThreadProcCallback(void *param)
{
LoginResultWinampAuth *result =(LoginResultWinampAuth*)param;
if (NULL == result) return 1;
INT exitCode = result->ThreadProc();
result->Release();
return exitCode;
}
#define CBCLASS LoginResultWinampAuth
START_DISPATCH;
CB(ADDREF, Wasabi_AddRef)
CB(RELEASE, Wasabi_Release)
CB(QUERYINTERFACE, Wasabi_QueryInterface)
CB(ONCONNECTING, Event_AuthConnecting)
CB(ONSENDING, Event_AuthSending)
CB(ONRECEIVING, Event_AuthReceiving)
CB(ONIDLE, Event_AuthIdle)
END_DISPATCH;
#undef CBCLASS