resultWinampAuth.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. #include "./resultWinampAuth.h"
  2. #include "./common.h"
  3. #include "./commandWinampAuth.h"
  4. #include "./loginData.h"
  5. #include "./dataCredentials.h"
  6. #include "./loginCredentials.h"
  7. #include "./loginbox.h"
  8. #include "../resource.h"
  9. LoginResultWinampAuth::LoginResultWinampAuth(api_auth *auth, LoginDataCredentials *pInput, Callback fnCallback, void *pUser)
  10. : ref(1), authApi(auth), input(pInput), callback(fnCallback), user(pUser),
  11. thread(NULL), abort(NULL), completed(NULL), credentials(NULL), authCode(AUTH_NOT_AUTHORIZED), statusCookie(0)
  12. {
  13. InitializeCriticalSection(&lock);
  14. authApi->AddRef();
  15. input->AddRef();
  16. }
  17. LoginResultWinampAuth::~LoginResultWinampAuth()
  18. {
  19. if (NULL != abort)
  20. CloseHandle(abort);
  21. if (NULL != completed)
  22. CloseHandle(completed);
  23. if (NULL != thread)
  24. CloseHandle(thread);
  25. authApi->Release();
  26. input->Release();
  27. if (NULL != credentials)
  28. credentials->Release();
  29. DeleteCriticalSection(&lock);
  30. }
  31. HRESULT LoginResultWinampAuth::CreateInstance(LoginData *input, Callback callback, void *user, LoginResultWinampAuth **instance)
  32. {
  33. if (NULL == instance) return E_POINTER;
  34. *instance = NULL;
  35. LoginDataCredentials *credentialsInput;
  36. if (NULL == input || FAILED(input->QueryInterface(IID_LoginDataCredentials, (void**)&credentialsInput)))
  37. return E_INVALIDARG;
  38. HRESULT hr;
  39. api_auth *authApi;
  40. HWND hLoginbox = credentialsInput->GetLoginbox();
  41. if (NULL == hLoginbox || FALSE == LoginBox_GetAuthApi(hLoginbox, &authApi))
  42. hr = E_FAIL;
  43. else
  44. {
  45. LoginResultWinampAuth *result = new LoginResultWinampAuth(authApi, credentialsInput, callback, user);
  46. if (NULL == result)
  47. hr = E_OUTOFMEMORY;
  48. else
  49. {
  50. hr = result->Start();
  51. if (FAILED(hr))
  52. {
  53. result->Release();
  54. result = NULL;
  55. }
  56. else
  57. {
  58. *instance = result;
  59. }
  60. }
  61. authApi->Release();
  62. }
  63. credentialsInput->Release();
  64. return hr;
  65. }
  66. STDMETHODIMP_(ULONG) LoginResultWinampAuth::AddRef(void)
  67. {
  68. return InterlockedIncrement((LONG*)&ref);
  69. }
  70. STDMETHODIMP_(ULONG) LoginResultWinampAuth::Release(void)
  71. {
  72. if (0 == ref)
  73. return ref;
  74. LONG r = InterlockedDecrement((LONG*)&ref);
  75. if (0 == r)
  76. delete(this);
  77. return r;
  78. }
  79. STDMETHODIMP LoginResultWinampAuth::QueryInterface(REFIID riid, PVOID *ppvObject)
  80. {
  81. if (NULL == ppvObject)
  82. return E_POINTER;
  83. if (IsEqualIID(riid, LCUID_WINAMPAUTH))
  84. *ppvObject = static_cast<LoginResultWinampAuth*>(this);
  85. else if (IsEqualIID(riid, IID_IUnknown))
  86. *ppvObject = static_cast<IUnknown*>(this);
  87. else
  88. {
  89. *ppvObject = NULL;
  90. return E_NOINTERFACE;
  91. }
  92. if (NULL == *ppvObject)
  93. return E_UNEXPECTED;
  94. AddRef();
  95. return S_OK;
  96. }
  97. size_t LoginResultWinampAuth::Wasabi_AddRef()
  98. {
  99. return AddRef();
  100. }
  101. size_t LoginResultWinampAuth::Wasabi_Release()
  102. {
  103. return Release();
  104. }
  105. int LoginResultWinampAuth::Wasabi_QueryInterface(GUID iid, void **object)
  106. {
  107. return QueryInterface(iid, object);
  108. }
  109. HRESULT LoginResultWinampAuth::Start()
  110. {
  111. //HRESULT hr;
  112. HANDLE threadCopy = NULL;
  113. input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_INITIALIZING));
  114. EnterCriticalSection(&lock);
  115. if (NULL != thread)
  116. {
  117. //hr = E_PENDING;
  118. }
  119. else
  120. {
  121. AddRef();
  122. thread = CreateThread(NULL, 0, WinampAuth_ThreadProcCallback, this, CREATE_SUSPENDED, NULL);
  123. if (NULL == thread)
  124. {
  125. Release();
  126. }
  127. else
  128. {
  129. if (0 == DuplicateHandle(GetCurrentProcess(), thread, GetCurrentProcess(), &threadCopy, 0, FALSE, DUPLICATE_SAME_ACCESS))
  130. {
  131. ResumeThread(thread); // grr...
  132. threadCopy = NULL;
  133. }
  134. }
  135. }
  136. LeaveCriticalSection(&lock);
  137. if (NULL != threadCopy)
  138. {
  139. ResumeThread(threadCopy);
  140. CloseHandle(threadCopy);
  141. }
  142. return S_OK;
  143. }
  144. DWORD LoginResultWinampAuth::ThreadProc()
  145. {
  146. Callback callbackCopy(NULL);
  147. HANDLE completedCopy(NULL);
  148. INT resultCode = AUTH_SUCCESS;
  149. LPWSTR username(NULL), password(NULL);
  150. api_auth::AuthResults authResults;
  151. SecureZeroMemory(&authResults, sizeof(authResults));
  152. EnterCriticalSection(&lock);
  153. authCode = AUTH_NOT_AUTHORIZED;
  154. if (NULL != credentials)
  155. {
  156. credentials->Release();
  157. credentials = NULL;
  158. }
  159. LeaveCriticalSection(&lock);
  160. username = GetUsername(input->GetUsername(), &resultCode);
  161. if (AUTH_SUCCESS == resultCode)
  162. password = GetPassword(input->GetPassword(), &resultCode);
  163. if (AUTH_SUCCESS == resultCode)
  164. {
  165. if (NULL == input->GetContext())
  166. {
  167. resultCode = authApi->Login(username, password, &authResults, this);
  168. }
  169. else
  170. {
  171. LPWSTR passcode = GetPasscode(input->GetPasscode(), &resultCode);
  172. if (AUTH_SUCCESS == resultCode)
  173. {
  174. resultCode = authApi->LoginSecurID(username, password, input->GetContext(), passcode, &authResults, this);
  175. LoginBox_FreeStringSecure(passcode);
  176. }
  177. }
  178. }
  179. EnterCriticalSection(&lock);
  180. authCode = resultCode;
  181. switch(authCode)
  182. {
  183. case AUTH_SUCCESS:
  184. {
  185. GUID realm;
  186. if (FAILED(input->GetRealm(&realm)) ||
  187. FAILED(LoginCredentials::CreateInstance(&realm, username, authResults.session_key,
  188. authResults.token, authResults.expire, &credentials)))
  189. {
  190. authCode = AUTH_UNEXPECTED;
  191. }
  192. }
  193. break;
  194. case AUTH_SECURID:
  195. if(FAILED(input->SetContext(authResults.context)))
  196. authCode = AUTH_NOT_AUTHORIZED;
  197. break;
  198. }
  199. INT statusId;
  200. switch(authCode)
  201. {
  202. case AUTH_SUCCESS: statusId = IDS_STATUS_SUCCEEDED; break;
  203. case AUTH_SECURID: statusId = IDS_STATUS_PASSCODE_REQUIRED; break;
  204. case AUTH_ABORT: statusId = IDS_STATUS_ABORTED; break;
  205. default: statusId = IDS_STATUS_FAILED; break;
  206. }
  207. input->SetStatus(MAKEINTRESOURCE(statusId));
  208. CloseHandle(thread);
  209. thread = NULL;
  210. callbackCopy = callback;
  211. if (NULL == completed || FALSE == DuplicateHandle(GetCurrentProcess(), completed,
  212. GetCurrentProcess(), &completedCopy, 0, FALSE, DUPLICATE_SAME_ACCESS))
  213. {
  214. completedCopy = NULL;
  215. }
  216. LeaveCriticalSection(&lock);
  217. SecureZeroMemory(&authResults, sizeof(authResults));
  218. LoginBox_FreeStringSecure(username);
  219. LoginBox_FreeStringSecure(password);
  220. if (NULL != completedCopy)
  221. {
  222. SetEvent(completedCopy);
  223. CloseHandle(completedCopy);
  224. }
  225. if (NULL != callbackCopy)
  226. callbackCopy(this);
  227. return 0;
  228. }
  229. HRESULT LoginResultWinampAuth::GetWaitHandle(HANDLE *handle)
  230. {
  231. if (NULL == handle)
  232. return E_POINTER;
  233. HRESULT hr = S_OK;
  234. EnterCriticalSection(&lock);
  235. if (NULL == completed)
  236. {
  237. completed = CreateEvent(NULL, TRUE, (S_OK == IsCompleted()), NULL);
  238. if (NULL == completed)
  239. {
  240. *handle = NULL;
  241. DWORD error = GetLastError();
  242. hr = HRESULT_FROM_WIN32(error);
  243. }
  244. }
  245. if (SUCCEEDED(hr) &&
  246. FALSE == DuplicateHandle(GetCurrentProcess(), completed,
  247. GetCurrentProcess(), handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
  248. {
  249. *handle = NULL;
  250. DWORD error = GetLastError();
  251. hr = HRESULT_FROM_WIN32(error);
  252. }
  253. LeaveCriticalSection(&lock);
  254. return hr;
  255. }
  256. HRESULT LoginResultWinampAuth::GetUser(void **pUser)
  257. {
  258. if (NULL == pUser) return E_POINTER;
  259. EnterCriticalSection(&lock);
  260. *pUser = user;
  261. LeaveCriticalSection(&lock);
  262. return S_OK;
  263. }
  264. HRESULT LoginResultWinampAuth::RequestAbort(BOOL fDrop)
  265. {
  266. HRESULT hr;
  267. EnterCriticalSection(&lock);
  268. if (NULL == abort)
  269. {
  270. abort = CreateEvent(NULL, TRUE, FALSE, NULL);
  271. if (NULL == abort)
  272. {
  273. DWORD error = GetLastError();
  274. hr = HRESULT_FROM_WIN32(error);
  275. }
  276. }
  277. if (NULL != abort && FALSE == SetEvent(abort))
  278. {
  279. DWORD error = GetLastError();
  280. hr = HRESULT_FROM_WIN32(error);
  281. }
  282. else
  283. {
  284. input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_ABORTING));
  285. }
  286. if (FALSE != fDrop)
  287. {
  288. callback = NULL;
  289. user = NULL;
  290. }
  291. LeaveCriticalSection(&lock);
  292. return hr;
  293. }
  294. HRESULT LoginResultWinampAuth::IsCompleted()
  295. {
  296. return (NULL == thread) ? S_OK : S_FALSE;
  297. }
  298. HRESULT LoginResultWinampAuth::IsAborting()
  299. {
  300. return IsAbortingEx(0);
  301. }
  302. HRESULT LoginResultWinampAuth::IsAbortingEx(UINT waitMs)
  303. {
  304. return (NULL != abort && WAIT_OBJECT_0 == WaitForSingleObjectEx(abort, waitMs, TRUE))?
  305. S_OK : S_FALSE;
  306. }
  307. HRESULT LoginResultWinampAuth::GetLoginData(LoginData **loginData)
  308. {
  309. if (NULL == loginData) return E_POINTER;
  310. EnterCriticalSection(&lock);
  311. *loginData = input;
  312. if (NULL != input)
  313. input->AddRef();
  314. LeaveCriticalSection(&lock);
  315. return S_OK;
  316. }
  317. HRESULT LoginResultWinampAuth::GetResult(INT *pAuthCode, LoginCredentials **ppCredentials)
  318. {
  319. if (S_OK != IsCompleted())
  320. return E_PENDING;
  321. EnterCriticalSection(&lock);
  322. if (NULL != pAuthCode)
  323. *pAuthCode = authCode;
  324. if (NULL != ppCredentials)
  325. {
  326. *ppCredentials = credentials;
  327. if (NULL != credentials)
  328. credentials->AddRef();
  329. }
  330. LeaveCriticalSection(&lock);
  331. return S_OK;
  332. }
  333. int LoginResultWinampAuth::Event_AuthConnecting()
  334. {
  335. if (S_OK == IsAbortingEx(0))
  336. return 1;
  337. input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_CONNECTING));
  338. return 0;
  339. }
  340. int LoginResultWinampAuth::Event_AuthSending()
  341. {
  342. if (S_OK == IsAbortingEx(0))
  343. return 1;
  344. input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_SENDING));
  345. return 0;
  346. }
  347. int LoginResultWinampAuth::Event_AuthReceiving()
  348. {
  349. if (S_OK == IsAbortingEx(0))
  350. return 1;
  351. input->SetStatus(MAKEINTRESOURCE(IDS_STATUS_RECEIVING));
  352. return 0;
  353. }
  354. int LoginResultWinampAuth::Event_AuthIdle()
  355. {
  356. if (S_OK == IsAbortingEx(50))
  357. return 1;
  358. return 0;
  359. }
  360. LPWSTR LoginResultWinampAuth::GetUsername(LPCWSTR pszInput, INT *authError)
  361. {
  362. return MakeAuthParam(pszInput, -1, 3, 48, TRUE, TRUE, (0xFFFF & ~C1_CNTRL), AUTH_USERNAME, authError);
  363. }
  364. LPWSTR LoginResultWinampAuth::GetPassword(LPCWSTR pszInput, INT *authError)
  365. {
  366. return MakeAuthParam(pszInput, -1, 6, 48, TRUE, FALSE, (0xFFFF & ~C1_CNTRL), AUTH_PASSWORD, authError);
  367. }
  368. LPWSTR LoginResultWinampAuth::GetPasscode(LPCWSTR pszInput, INT *authError)
  369. {
  370. return MakeAuthParam(pszInput, -1, 6, 6, FALSE, FALSE, C1_DIGIT, AUTH_PASSCODE, authError);
  371. }
  372. LPWSTR LoginResultWinampAuth::MakeAuthParam(LPCWSTR pszInput, INT cchInput, INT min, INT max, BOOL removeSpaces, BOOL firstLetter, WORD typeMask, INT errorBase, INT *authError)
  373. {
  374. if (cchInput < 0 || NULL == pszInput)
  375. cchInput = (NULL != pszInput) ? lstrlen(pszInput) : 0;
  376. if (cchInput < min || (FALSE == removeSpaces && cchInput > max))
  377. {
  378. if (NULL != authError)
  379. *authError = errorBase + ((cchInput < min) ? AUTHPARAM_TOOSHORT : AUTHPARAM_TOOLONG);
  380. return NULL;
  381. }
  382. WORD *info = (WORD*)calloc(cchInput, sizeof(WORD));
  383. if (NULL == info)
  384. {
  385. if (NULL != authError) *authError = AUTH_UNEXPECTED;
  386. return NULL;
  387. }
  388. if (FALSE == GetStringTypeW(CT_CTYPE1, pszInput, cchInput, info))
  389. {
  390. free(info);
  391. if (NULL != authError) *authError = AUTH_UNEXPECTED;
  392. return NULL;
  393. }
  394. INT error = AUTH_SUCCESS;
  395. LPWSTR dest = NULL;
  396. BOOL firstChecked = FALSE;
  397. INT cchSpaces = 0;
  398. for (INT i = 0; i < cchInput; i++)
  399. {
  400. if (FALSE != removeSpaces && 0 != (C1_SPACE & info[i]))
  401. cchSpaces++;
  402. else if (0 == (typeMask & info[i]))
  403. {
  404. error = errorBase + AUTHPARAM_BADFORMAT;
  405. break;
  406. }
  407. else
  408. {
  409. if (FALSE != firstLetter && FALSE == firstChecked)
  410. {
  411. if (0 == (C1_ALPHA & info[i]))
  412. {
  413. error = errorBase + AUTHPARAM_BADFORMAT;
  414. break;
  415. }
  416. firstChecked = TRUE;
  417. }
  418. }
  419. }
  420. if (AUTH_SUCCESS == error)
  421. {
  422. INT cchTotal = cchInput - cchSpaces;
  423. if (cchTotal < min)
  424. error = errorBase + AUTHPARAM_TOOSHORT;
  425. else if (cchTotal > max)
  426. error = errorBase + AUTHPARAM_TOOLONG;
  427. else
  428. {
  429. dest = LoginBox_MallocString(cchTotal + 1);
  430. if (NULL == dest)
  431. error = AUTH_UNEXPECTED;
  432. else
  433. {
  434. if (FALSE != removeSpaces)
  435. {
  436. LPCWSTR s = pszInput;
  437. LPWSTR d = dest;
  438. for (INT i = 0; i < cchInput; i++, s++)
  439. {
  440. if (0 == (C1_SPACE & info[i]))
  441. {
  442. *d = *s;
  443. d++;
  444. }
  445. }
  446. *d = L'\0';
  447. }
  448. else
  449. {
  450. CopyMemory(dest, pszInput, (cchInput * sizeof(WCHAR)));
  451. dest[cchInput] = L'\0';
  452. }
  453. }
  454. }
  455. }
  456. free(info);
  457. if (NULL != authError)
  458. *authError = error;
  459. return dest;
  460. }
  461. static DWORD WINAPI WinampAuth_ThreadProcCallback(void *param)
  462. {
  463. LoginResultWinampAuth *result =(LoginResultWinampAuth*)param;
  464. if (NULL == result) return 1;
  465. INT exitCode = result->ThreadProc();
  466. result->Release();
  467. return exitCode;
  468. }
  469. #define CBCLASS LoginResultWinampAuth
  470. START_DISPATCH;
  471. CB(ADDREF, Wasabi_AddRef)
  472. CB(RELEASE, Wasabi_Release)
  473. CB(QUERYINTERFACE, Wasabi_QueryInterface)
  474. CB(ONCONNECTING, Event_AuthConnecting)
  475. CB(ONSENDING, Event_AuthSending)
  476. CB(ONRECEIVING, Event_AuthReceiving)
  477. CB(ONIDLE, Event_AuthIdle)
  478. END_DISPATCH;
  479. #undef CBCLASS