auth.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. #include "api.h"
  2. #include "../nu/ns_wc.h"
  3. #include <api/service/waservicefactory.h>
  4. #include "OAuthKey.h"
  5. #include "../nu/AutoCharFn.h"
  6. #include "../nu/AutoChar.h"
  7. #include "auth.h"
  8. #include "./loginbox/loginbox.h"
  9. #include "ifc_authcallback.h"
  10. #include "main.h"
  11. #include "../nu/AutoUrl.h"
  12. #include <api/syscb/callbacks/authcb.h>
  13. #include "../Winamp/buildType.h"
  14. #include <strsafe.h>
  15. //#ifdef INTERNAL
  16. //// QA
  17. ////const char *openauth_url ="https://authapi.qa.aol.com:8439/auth/clientLogin";
  18. //// QH
  19. //const char *openauth_url ="https://authapi.qh.aol.com:6443/auth/clientLogin";
  20. //#else
  21. const char *openauth_url ="https://api.screenname.aol.com:443/auth/clientLogin";
  22. //#endif
  23. static void CleanPassword(char *password)
  24. {
  25. char *src = password;
  26. char *dest = password;
  27. while (src && *src)
  28. {
  29. char c = *src++;
  30. if (c >= 'a' && c <= 'z')
  31. *dest++ = c;
  32. else if (c >= 'A' && c <= 'Z')
  33. *dest++ = c;
  34. else if (c >= '0' && c <= '9')
  35. *dest++ = c;
  36. }
  37. *dest=0;
  38. }
  39. static void ParsePassword(const wchar_t *password, char **password_url, char **securid=0)
  40. {
  41. const wchar_t *find_slash = wcschr(password, L'/');
  42. if (find_slash)
  43. {
  44. *password_url = AutoUrlDupN(password, find_slash-password);
  45. if (securid)
  46. *securid = AutoUrlDup(find_slash+1);
  47. }
  48. else
  49. {
  50. *password_url = AutoUrlDup(password);
  51. if (securid)
  52. *securid=0;
  53. }
  54. }
  55. // TODO: benski> use &forceRateLimit=true to force captcha request
  56. int PostXML(const char *url, const char *post_data, obj_xml *parser, ifc_authcallback *callback);
  57. static int Authorize(obj_xml *parser, const wchar_t *username, const wchar_t *password, ifc_authcallback *callback)
  58. {
  59. char *password_url, *securid;
  60. ParsePassword(password, &password_url, &securid);
  61. char post_data[2048] = {0};
  62. StringCbPrintfA(post_data, sizeof(post_data),
  63. "devId=%s"
  64. "&f=xml"
  65. "&pwd=%s"
  66. "&s=%s"
  67. "%s%s"
  68. "&tokenType=longterm",
  69. OPENAUTH_DEVID,
  70. password_url,
  71. AutoUrl(username),
  72. (securid?"&securid=":""),
  73. (securid?securid:"")
  74. );
  75. free(password_url);
  76. free(securid);
  77. return PostXML(openauth_url, post_data, parser, callback);
  78. }
  79. static int AuthorizeSecurID(obj_xml *parser, const wchar_t *username, const char *context, const wchar_t *securid, ifc_authcallback *callback)
  80. {
  81. char post_data[2048] = {0};
  82. StringCbPrintfA(post_data, sizeof(post_data),
  83. "devId=%s"
  84. "&f=xml"
  85. "&s=%s"
  86. "&context=%s"
  87. "&securid=%s"
  88. "&tokenType=longterm",
  89. OPENAUTH_DEVID,
  90. AutoUrl(username),
  91. AutoUrl(context),
  92. AutoUrl(securid)
  93. );
  94. return PostXML(openauth_url, post_data, parser, callback);
  95. }
  96. void OpenAuthParser::RegisterCallbacks(obj_xml *parser)
  97. {
  98. parser->xmlreader_registerCallback(L"response\fstatusCode", &statusCode);
  99. parser->xmlreader_registerCallback(L"response\fstatusText", &statusText);
  100. parser->xmlreader_registerCallback(L"response\fstatusDetailCode", &statusDetailCode);
  101. parser->xmlreader_registerCallback(L"response\fdata\ftoken\fa", &token);
  102. parser->xmlreader_registerCallback(L"response\fdata\ftoken\fexpiresIn", &expire);
  103. parser->xmlreader_registerCallback(L"response\fdata\fsessionSecret", &session_secret);
  104. parser->xmlreader_registerCallback(L"response\fdata\fchallenge\fcontext", &context);
  105. }
  106. void OpenAuthParser::UnregisterCallbacks(obj_xml *parser)
  107. {
  108. parser->xmlreader_unregisterCallback(&statusCode);
  109. parser->xmlreader_unregisterCallback(&statusText);
  110. parser->xmlreader_unregisterCallback(&statusDetailCode);
  111. parser->xmlreader_unregisterCallback(&token);
  112. parser->xmlreader_unregisterCallback(&expire);
  113. parser->xmlreader_unregisterCallback(&session_secret);
  114. parser->xmlreader_unregisterCallback(&context);
  115. }
  116. int Auth::SetupLogin(OpenAuthParser &authParser, waServiceFactory *&parserFactory, obj_xml *&parser)
  117. {
  118. parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID);
  119. if (parserFactory)
  120. parser = (obj_xml *)parserFactory->getInterface();
  121. if (parser)
  122. {
  123. parser->xmlreader_setCaseSensitive();
  124. authParser.RegisterCallbacks(parser);
  125. parser->xmlreader_open();
  126. return AUTH_SUCCESS;
  127. }
  128. else
  129. return AUTH_NOPARSER;
  130. }
  131. int Auth::ParseAuth(const wchar_t *password, OpenAuthParser &authParser, AuthResults *results)
  132. {
  133. switch(authParser.statusCode.GetUInt32())
  134. {
  135. case 200:
  136. {
  137. char *password_url;
  138. ParsePassword(password, &password_url);
  139. UrlDecode(password_url);
  140. OAuthKey key(password_url, strlen(password_url));
  141. AutoChar session_utf8(authParser.session_secret.GetString(), CP_UTF8);
  142. key.FeedMessage((char *)session_utf8, strlen(session_utf8));
  143. key.EndMessage();
  144. key.GetBase64(results->session_key, sizeof(results->session_key));
  145. WideCharToMultiByteSZ(CP_UTF8, 0, authParser.token.GetString(), -1, results->token, sizeof(results->token), 0, 0);
  146. results->expire = authParser.expire.GetUInt32() + _time64(0);
  147. free(password_url);
  148. return AUTH_SUCCESS;
  149. }
  150. case 330:
  151. switch(authParser.statusDetailCode.GetUInt32())
  152. {
  153. case 3011: // Password-LoginId Required/Invalid
  154. return AUTH_INVALIDCRED;
  155. case 3012: // SecurId Required/Invalid
  156. case 3013: // SecurId Next Token Required
  157. WideCharToMultiByteSZ(CP_UTF8, 0, authParser.context.GetString(), -1, results->context, sizeof(results->context), 0, 0);
  158. return AUTH_SECURID;
  159. }
  160. break;
  161. case 401:
  162. switch(authParser.statusDetailCode.GetUInt32())
  163. {
  164. case 3020:
  165. return AUTH_UNCONFIRMED;
  166. }
  167. break;
  168. }
  169. return AUTH_NOT_AUTHORIZED;
  170. }
  171. int Auth::Login(const wchar_t *username, const wchar_t *password, AuthResults *results, ifc_authcallback *callback)
  172. {
  173. SecureZeroMemory(results, sizeof(AuthResults));
  174. OpenAuthParser authParser;
  175. obj_xml *parser = 0;
  176. waServiceFactory *parserFactory = 0;
  177. int err = SetupLogin(authParser, parserFactory, parser);
  178. if (err == AUTH_SUCCESS)
  179. {
  180. err = Authorize(parser, username, password, callback);
  181. authParser.UnregisterCallbacks(parser);
  182. parser->xmlreader_close();
  183. parserFactory->releaseInterface(parser);
  184. if (err != AUTH_SUCCESS)
  185. return err;
  186. return ParseAuth(password, authParser, results);
  187. }
  188. else
  189. return err;
  190. return AUTH_NOT_AUTHORIZED;
  191. }
  192. int Auth::LoginSecurID(const wchar_t *username, const wchar_t *password, const char *context, const wchar_t *securid, AuthResults *results, ifc_authcallback *callback)
  193. {
  194. SecureZeroMemory(results, sizeof(AuthResults));
  195. OpenAuthParser authParser;
  196. obj_xml *parser = 0;
  197. waServiceFactory *parserFactory = 0;
  198. int err = SetupLogin(authParser, parserFactory, parser);
  199. if (err == AUTH_SUCCESS)
  200. {
  201. err = AuthorizeSecurID(parser, username, context, securid, callback);
  202. authParser.UnregisterCallbacks(parser);
  203. parser->xmlreader_close();
  204. parserFactory->releaseInterface(parser);
  205. if (err != AUTH_SUCCESS)
  206. return err;
  207. return ParseAuth(password, authParser, results);
  208. }
  209. else
  210. return err;
  211. return AUTH_NOT_AUTHORIZED;
  212. }
  213. const char *Auth::GetDevID()
  214. {
  215. return OPENAUTH_DEVID;
  216. }
  217. int Auth::SetCredentials(GUID realm, const char *session_key, const char *token, const wchar_t *username, __time64_t expire)
  218. {
  219. if (NULL != WASABI_API_SYSCB)
  220. WASABI_API_SYSCB->syscb_issueCallback(SysCallback::AUTH, AuthCallback::CREDENTIALS_ABOUTTOCHANGE, (intptr_t)this, (intptr_t)&realm);
  221. char guid_str[40] = {0};
  222. if (realm != GUID_NULL)
  223. {
  224. StringCbPrintfA( guid_str, sizeof(guid_str), "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
  225. (int)realm.Data1, (int)realm.Data2, (int)realm.Data3,
  226. (int)realm.Data4[0], (int)realm.Data4[1],
  227. (int)realm.Data4[2], (int)realm.Data4[3],
  228. (int)realm.Data4[4], (int)realm.Data4[5],
  229. (int)realm.Data4[6], (int)realm.Data4[7] );
  230. }
  231. else
  232. {
  233. StringCbCopyA(guid_str, sizeof(guid_str), "default");
  234. }
  235. if (session_key && session_key[0])
  236. {
  237. WritePrivateProfileStringA(guid_str, "session_key", session_key, inifile);
  238. WritePrivateProfileStringA(guid_str, "token", token, inifile);
  239. WritePrivateProfileStringA(guid_str, "username", AutoChar(username, CP_UTF8), inifile);
  240. char temp[128] = {0};
  241. StringCbPrintfA(temp, sizeof(temp), "%I64d", expire);
  242. WritePrivateProfileStringA(guid_str, "expiration", temp, inifile);
  243. }
  244. else
  245. {
  246. char empty[2] = {0,0};
  247. WritePrivateProfileSectionA(guid_str, empty, inifile);
  248. if (username && username[0]) // they might want to save their username tho
  249. WritePrivateProfileStringA(guid_str, "username", AutoChar(username, CP_UTF8), inifile);
  250. }
  251. if (NULL != WASABI_API_SYSCB)
  252. WASABI_API_SYSCB->syscb_issueCallback(SysCallback::AUTH, AuthCallback::CREDENTIALS_CHANGED, (intptr_t)this, (intptr_t)&realm);
  253. return AUTH_SUCCESS;
  254. }
  255. int Auth::GetCredentials(GUID realm, char *session_key, size_t session_key_len, char *token, size_t token_len, wchar_t *username, size_t username_len, __time64_t *expire)
  256. {
  257. char guid_str[40] = {0};
  258. if (realm != GUID_NULL)
  259. {
  260. StringCbPrintfA( guid_str, sizeof(guid_str), "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
  261. (int)realm.Data1, (int)realm.Data2, (int)realm.Data3,
  262. (int)realm.Data4[0], (int)realm.Data4[1],
  263. (int)realm.Data4[2], (int)realm.Data4[3],
  264. (int)realm.Data4[4], (int)realm.Data4[5],
  265. (int)realm.Data4[6], (int)realm.Data4[7] );
  266. }
  267. else
  268. {
  269. StringCbCopyA(guid_str, sizeof(guid_str), "default");
  270. }
  271. GetPrivateProfileStringA(guid_str, "session_key", "", session_key, (DWORD)session_key_len, inifile);
  272. GetPrivateProfileStringA(guid_str, "token", "", token, (DWORD)token_len, inifile);
  273. char temp[1024] = {0};
  274. GetPrivateProfileStringA(guid_str, "username", "", temp, sizeof(temp), inifile);
  275. MultiByteToWideCharSZ(CP_UTF8, 0, temp, -1, username, (DWORD)username_len);
  276. GetPrivateProfileStringA(guid_str, "expiration", "", temp, sizeof(temp), inifile);
  277. *expire = _atoi64(temp);
  278. return AUTH_SUCCESS;
  279. }
  280. int Auth::GetUserName(GUID realm, wchar_t *username, size_t username_len)
  281. {
  282. char guid_str[40] = {0};
  283. if (realm != GUID_NULL)
  284. {
  285. StringCbPrintfA( guid_str, sizeof(guid_str), "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
  286. (int)realm.Data1, (int)realm.Data2, (int)realm.Data3,
  287. (int)realm.Data4[0], (int)realm.Data4[1],
  288. (int)realm.Data4[2], (int)realm.Data4[3],
  289. (int)realm.Data4[4], (int)realm.Data4[5],
  290. (int)realm.Data4[6], (int)realm.Data4[7] );
  291. }
  292. else
  293. {
  294. StringCbCopyA(guid_str, sizeof(guid_str), "default");
  295. }
  296. char temp[1024] = {0};
  297. GetPrivateProfileStringA(guid_str, "username", "", temp, sizeof(temp), inifile);
  298. MultiByteToWideCharSZ(CP_UTF8, 0, temp, -1, username, (DWORD)username_len);
  299. return AUTH_SUCCESS;
  300. }
  301. Auth::Auth()
  302. {
  303. inifile=0;
  304. }
  305. void Auth::Init()
  306. {
  307. wchar_t inifileW[MAX_PATH] = {0};
  308. const wchar_t *settings_path = WASABI_API_APP->path_getUserSettingsPath();
  309. PathCombineW(inifileW, settings_path, L"auth.ini");
  310. inifile = _strdup(AutoCharFn(inifileW));
  311. }
  312. void Auth::Quit()
  313. {
  314. free(inifile);
  315. }
  316. static void AddParameter(char *&position, size_t &len, const char *param, const wchar_t *val)
  317. {
  318. AutoUrl encoded_val(val);
  319. StringCchPrintfExA(position, len, &position, &len, 0, "&%s=%s", param, encoded_val);
  320. }
  321. static void AddParameter(char *&position, size_t &len, const char *param, const char *val)
  322. {
  323. AutoUrl encoded_val(val);
  324. StringCchPrintfExA(position, len, &position, &len, 0, "&%s=%s", param, encoded_val);
  325. }
  326. static void AddParameter(char *&position, size_t &len, const char *param, int64_t val)
  327. {
  328. char temp[64] = {0};
  329. StringCchPrintfA(temp, 64, "%I64d", val);
  330. StringCchPrintfExA(position, len, &position, &len, 0, "&%s=%s", param, temp);
  331. }
  332. //#ifdef INTERNAL
  333. // QA
  334. //static const char *c2w_server="my.screenname.qa.aol.com";
  335. //static const char *c2w_path="/_cqr/login/login.psp";
  336. //static const char *c2w_path_encoded="%2F_cqr%2Flogin%2Flogin.psp";
  337. // QH
  338. //static const char *c2w_server="my.screenname.qh.aol.com";
  339. //static const char *c2w_path="/_cqr/login/login.psp";
  340. //static const char *c2w_path_encoded="%2F_cqr%2Flogin%2Flogin.psp";
  341. //#else
  342. static const char *c2w_server="my.screenname.aol.com";
  343. static const char *c2w_path="/_cqr/login/login.psp";
  344. static const char *c2w_path_encoded="%2F_cqr%2Flogin%2Flogin.psp";
  345. //#endif
  346. int Auth::ClientToWeb(GUID realm, const wchar_t *destination_url, wchar_t *url, size_t urlcch)
  347. {
  348. char session_key[1024], token[1024] = {0};
  349. wchar_t username[1024] = {0};
  350. __time64_t expire;
  351. int ret = GetCredentials(realm, session_key, 1024, token, 1024, username, 1024, &expire);
  352. if (ret)
  353. return ret;
  354. if (!session_key[0] || !token[0] || !username[0])
  355. return 1;
  356. char post_data[2048]="";
  357. char *post_itr=post_data;
  358. size_t post_cch=sizeof(post_data)/sizeof(*post_data);
  359. OAuthKey key(session_key, strlen(session_key));
  360. key.FeedMessage("GET&", 4);
  361. key.FeedMessage("http%3A%2F%2F", 13);
  362. key.FeedMessage(c2w_server, strlen(c2w_server));
  363. key.FeedMessage(c2w_path_encoded, strlen(c2w_path_encoded));
  364. key.FeedMessage("&", 1);
  365. // parameters
  366. StringCbPrintfExA(post_itr, post_cch, &post_itr, &post_cch, 0, "a=%s", AutoUrl(token));
  367. char *start = post_itr;
  368. key.FeedMessage("a%3D", 4);
  369. AutoUrl token_a_url1(token);
  370. AutoUrl token_a_url((char *)token_a_url1);
  371. key.FeedMessage(token_a_url, strlen((char *)token_a_url));
  372. AddParameter(post_itr, post_cch, "destUrl", destination_url);
  373. AddParameter(post_itr, post_cch, "devId", GetDevID());
  374. AddParameter(post_itr, post_cch, "entryType", L"client2Web");
  375. __time64_t t = _time64(0);
  376. AddParameter(post_itr, post_cch, "ts", t);
  377. AutoUrl encoded_post(start);
  378. key.FeedMessage((char *)encoded_post, strlen(encoded_post));
  379. key.EndMessage();
  380. char hash[512] = {0};
  381. key.GetBase64(hash, 512);
  382. StringCchPrintfA(post_itr, post_cch, "&sig_sha256=%s", AutoUrl(hash));
  383. char urla[2048] = {0};
  384. StringCbPrintfA(urla, sizeof(urla), "http://%s%s?%s", c2w_server, c2w_path, post_data);
  385. MultiByteToWideCharSZ(CP_UTF8, 0, urla, -1, url, (int)urlcch);
  386. return 0;
  387. }
  388. HWND Auth::CreateLoginWindow(GUID realm, HWND owner, UINT style)
  389. {
  390. #ifndef USE_LOGINBOX
  391. return NULL;
  392. #else
  393. return LoginBox_CreateWindow(this, &realm, owner, style);
  394. #endif
  395. }
  396. INT_PTR Auth::LoginBox(GUID realm, HWND owner, UINT style)
  397. {
  398. #ifndef USE_LOGINBOX
  399. return -1;
  400. #else
  401. return LoginBox_Show(this, &realm, owner, style);
  402. #endif
  403. }
  404. #define CBCLASS Auth
  405. START_DISPATCH;
  406. CB(API_AUTH_LOGIN, Login)
  407. CB(API_AUTH_GETDEVID, GetDevID)
  408. CB(API_AUTH_LOGIN_SECURID, LoginSecurID)
  409. CB(API_AUTH_SETCREDENTIALS, SetCredentials)
  410. CB(API_AUTH_GETCREDENTIALS, GetCredentials)
  411. CB(API_AUTH_CLIENT_TO_WEB, ClientToWeb)
  412. CB(API_AUTH_CREATELOGINWINDOW, CreateLoginWindow)
  413. CB(API_AUTH_LOGINBOX, LoginBox)
  414. CB(API_AUTH_GETUSERNAME, GetUserName)
  415. END_DISPATCH;
  416. #undef CBCLASS