1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2008 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
17
18
19 #if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_)
20 #include "boinc_win.h"
21 #endif
22
23 #ifdef _WIN32
24 #include "win_util.h"
25
26 #ifndef InternetGetCookie
27
28 #if defined(__cplusplus)
29 extern "C" {
30 #endif
31
32 BOOL WINAPI InternetGetCookieA( LPCSTR lpszUrl, LPCSTR lpszCookieName, LPSTR lpszCookieData, LPDWORD lpdwSize );
33
34 #if defined(__cplusplus)
35 }
36 #endif
37
38 #endif
39 #else
40 #include <string>
41 #include <vector>
42 #include <time.h>
43 #endif
44
45 #include <sqlite3.h>
46 #include "error_numbers.h"
47 #include "str_replace.h"
48 #include "mfile.h"
49 #include "miofile.h"
50 #include "str_util.h"
51 #include "filesys.h"
52 #include "browser.h"
53
54
55 //
56 // Utility Functions
57 //
58
59 // retrieve the user's application data directory.
60 // Win : C:\Documents and Settings\<username>\Application Data
61 // Unix: ~/
62 //
63 // Google Chrome decided to put its application data in the 'local' application data
64 // store on Windows. 'local' only has meaning for Windows.
65 //
get_home_dir_path(std::string & path,bool local=false)66 void get_home_dir_path( std::string& path, bool local = false ) {
67 #ifdef _WIN32
68 CHAR szBuffer[MAX_PATH];
69 int iCSIDLFlags = CSIDL_FLAG_CREATE;
70
71 if (local) {
72 iCSIDLFlags |= CSIDL_LOCAL_APPDATA;
73 } else {
74 iCSIDLFlags |= CSIDL_APPDATA;
75 }
76
77 if (SUCCEEDED(SHGetFolderPathA(NULL, iCSIDLFlags, NULL, SHGFP_TYPE_CURRENT, szBuffer))) {
78 path = std::string(szBuffer);
79 path += std::string("\\");
80 }
81 #elif defined(__APPLE__)
82 path = std::string(getenv("HOME")) + std::string("/");
83 #else
84 path = std::string("~/");
85 #endif
86 }
87
88 // retrieve the user's cookie directory.
89 // WinXP
90 // C:\Documents and Settings\<username>\Cookies
91 // WinVista/Win7
92 // C:\Documents and Settings\<username>\Application Data\Roaming\Microsoft\Windows\Cookies
93 // C:\Documents and Settings\<username>\Application Data\Roaming\Microsoft\Windows\Cookies\Low
94 //
get_internet_explorer_cookie_path(bool low_rights,std::string & path)95 void get_internet_explorer_cookie_path( bool low_rights, std::string& path ) {
96 #ifdef _WIN32
97 CHAR szBuffer[MAX_PATH];
98 if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COOKIES|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szBuffer))) {
99 path = std::string(szBuffer);
100 path += std::string("\\");
101 if (low_rights) {
102 path += std::string("Low\\");
103 }
104 }
105 #endif
106 }
107
108
109 // retrieve the user's name.
110 //
get_user_name(std::string & name)111 void get_user_name( std::string& name ) {
112 #ifdef _WIN32
113 CHAR szBuffer[256];
114 DWORD dwSize = sizeof(szBuffer);
115
116 if (GetUserNameA((LPSTR)&szBuffer, &dwSize)) {
117 name = szBuffer;
118 }
119 #endif
120 }
121
122
123 // is the authenticator valid?
124 //
is_authenticator_valid(const std::string authenticator)125 bool is_authenticator_valid(const std::string authenticator) {
126 std::string tmp = authenticator;
127
128 // Perform some basic validation of the suspect authenticator
129 //
130
131 // If the string is null then it is invalid.
132 if (0 == tmp.length()) {
133 return false;
134 }
135
136 // If the string contains non alpha numeric characters it is invalid.
137 std::string::iterator it = tmp.begin();
138 while (it != tmp.end()) {
139 if (!isalpha(*it) && !isdigit(*it)) {
140 return false;
141 }
142 ++it;
143 }
144
145 return true;
146 }
147
148
149 // parse name value pairs based on INI file rules.
150 //
parse_name_value_pair(char * buf,std::string & name,std::string & value)151 bool parse_name_value_pair(char* buf, std::string& name, std::string& value) {
152 std::basic_string<char>::size_type i;
153 std::string s;
154
155 s = std::string(buf);
156 i = s.find("=", 0);
157 if ( i < s.npos ) {
158 name = s.substr(0, i);
159 value = s.substr(i + 1);
160 strip_whitespace(name);
161 strip_whitespace(value);
162 return true;
163 }
164 return false;
165 }
166
167
168 // parse host name from url for Mozilla compatible browsers.
169 //
parse_hostname_mozilla_compatible(std::string & project_url,std::string & hostname)170 bool parse_hostname_mozilla_compatible(std::string& project_url, std::string& hostname) {
171 std::basic_string<char>::size_type start;
172 std::basic_string<char>::size_type end;
173
174 start = project_url.find("//", 0) + 2;
175 end = project_url.find("/", start);
176
177 hostname = project_url.substr(start, end - start);
178
179 if (starts_with(hostname.c_str(), "www"))
180 hostname.erase(0, 3);
181
182 if (!hostname.empty())
183 return true;
184
185 return false;
186 }
187
188
189 // parse host name from url for Chrome compatible browsers.
190 //
parse_hostname_chrome_compatible(std::string & project_url,std::string & hostname)191 bool parse_hostname_chrome_compatible(std::string& project_url, std::string& hostname) {
192 std::basic_string<char>::size_type start;
193 std::basic_string<char>::size_type end;
194
195 start = project_url.find("//", 0) + 2;
196 end = project_url.find("/", start);
197
198 hostname = project_url.substr(start, end - start);
199
200 if (starts_with(hostname.c_str(), "www"))
201 hostname.erase(0, 3);
202
203 if (!hostname.empty())
204 return true;
205
206 return false;
207 }
208
209
210 // parse host name from url for Internet Explorer compatible browsers.
211 //
parse_hostname_ie_compatible(std::string & project_url,std::string & hostname,std::string & domainname)212 bool parse_hostname_ie_compatible(
213 std::string& project_url, std::string& hostname, std::string& domainname
214 ) {
215 std::basic_string<char>::size_type start;
216 std::basic_string<char>::size_type end;
217
218 // Remove the protocol identifier
219 start = project_url.find("//", 0) + 2;
220 end = project_url.find("/", start);
221
222 hostname = project_url.substr(start, end - start);
223
224 // Remove the hostname to extract the domain name
225 start = 0;
226 end = hostname.find(".") + 1;
227
228 domainname = hostname;
229 domainname.erase(start, end);
230
231 if (!hostname.empty() && !domainname.empty())
232 return true;
233
234 return false;
235 }
236
237
238 //
239 // Generic Browser Support
240 //
241
242 class COOKIE_SQL {
243 public:
244 std::string host;
245 std::string name;
246 std::string value;
247
248 COOKIE_SQL();
249
250 void clear();
251 };
252
253
COOKIE_SQL()254 COOKIE_SQL::COOKIE_SQL() {
255 clear();
256 }
257
258
clear()259 void COOKIE_SQL::clear() {
260 host.clear();
261 name.clear();
262 value.clear();
263 }
264
265
266 //
267 // Mozilla-Based Browser Support
268 //
269
270 class MOZILLA_PROFILE {
271 public:
272 std::string name;
273 std::string path;
274 bool is_relative;
275 bool is_default;
276
277 MOZILLA_PROFILE();
278
279 void clear();
280 int parse(MIOFILE& in);
281 };
282
283
284 class MOZILLA_PROFILES {
285 public:
286 std::vector<MOZILLA_PROFILE*> profiles;
287
288 MOZILLA_PROFILES();
289
290 void clear();
291 int parse(MIOFILE& in);
292 };
293
294
MOZILLA_PROFILE()295 MOZILLA_PROFILE::MOZILLA_PROFILE() {
296 clear();
297 }
298
299
clear()300 void MOZILLA_PROFILE::clear() {
301 name.clear();
302 path.clear();
303 is_relative = false;
304 is_default = false;
305 }
306
307
parse(MIOFILE & in)308 int MOZILLA_PROFILE::parse(MIOFILE& in) {
309 char buf[512];
310 std::string sn;
311 std::string sv;
312
313 while (in.fgets(buf, 512)) {
314 if (starts_with(buf, "\n")) return 0;
315 if (starts_with(buf, "\r\n")) return 0;
316 if (!parse_name_value_pair(buf, sn, sv)) continue;
317
318 if ("Name" == sn) name = sv;
319 if ("Path" == sn) path = sv;
320 if (("IsRelative" == sn) && ("1" == sv)) is_relative = true;
321 if (("Default" == sn) && ("1" == sv)) is_default = true;
322 }
323 return ERR_FREAD;
324 }
325
326
MOZILLA_PROFILES()327 MOZILLA_PROFILES::MOZILLA_PROFILES() {
328 clear();
329 }
330
331
clear()332 void MOZILLA_PROFILES::clear() {
333 unsigned int i;
334 for (i=0; i<profiles.size(); i++) {
335 delete profiles[i];
336 }
337 profiles.clear();
338 }
339
340
parse(MIOFILE & in)341 int MOZILLA_PROFILES::parse(MIOFILE& in) {
342 char buf[512];
343 MOZILLA_PROFILE* p = NULL;
344
345 while (in.fgets(buf, 512)) {
346 if (starts_with(buf, "[Profile")) {
347 p = new MOZILLA_PROFILE;
348 if (!p->parse( in )) {
349 profiles.push_back( p );
350 } else {
351 delete p;
352 }
353 }
354 }
355
356 return 0;
357 }
358
359
360 // search for the project specific cookie for mozilla based browsers.
361 // SELECT host, name, value, expiry from moz_cookies WHERE name = '%s' AND host LIKE '%s'
362 //
find_site_cookie_mozilla_v3(void * cookie,int,char ** argv,char **)363 static int find_site_cookie_mozilla_v3(
364 void* cookie, int /* argc */, char **argv, char ** /* szColumnName */
365 ) {
366 COOKIE_SQL* _cookie = (COOKIE_SQL*)cookie;
367 char host[256], cookie_name[256], cookie_value[4096];
368 long long expires;
369
370
371 safe_strcpy(host, "");
372 safe_strcpy(cookie_name, "");
373 safe_strcpy(cookie_value, "");
374 expires = 0;
375
376 sscanf( argv[0], "%255s", host );
377 sscanf( argv[1], "%255s", cookie_name );
378 sscanf( argv[2], "%4095s", cookie_value );
379 sscanf( argv[3],
380 #ifdef _WIN32
381 "%I64d",
382 #elif defined(__APPLE__)
383 "%lld",
384 #else
385 "%Ld",
386 #endif
387 &expires
388 );
389
390 // is this a real cookie?
391 // temporary cookie? these cookies do not trickle back up
392 // to the jscript interface, so ignore them.
393 if (starts_with(host, "#HttpOnly")) return 0;
394
395 // is this the right host?
396 if (!strstr(host, _cookie->host.c_str())) return 0;
397
398 // has the cookie expired?
399 if (time(0) > expires) return 0;
400
401 // is this the right cookie?
402 if (starts_with(cookie_name, _cookie->name)) {
403 _cookie->value = cookie_value;
404 }
405
406 return 0;
407 }
408
409
410 // traverse the profiles and determine which profile to use.
411 // this should be compatible with firefox2, firefox3, firefox4, seamonkey, and netscape.
412 //
get_firefox_profile_root(std::string & profile_root)413 bool get_firefox_profile_root( std::string& profile_root ) {
414 bool retval = false;
415 FILE* pf = NULL;
416 MIOFILE pmf;
417 MOZILLA_PROFILES mps;
418 MOZILLA_PROFILE* mp = NULL;
419 std::string cookies_root;
420 std::string tmp;
421 unsigned int i = 0;
422 unsigned int default_index = 0;
423
424 get_home_dir_path( profile_root );
425 #ifdef _WIN32
426 profile_root += std::string("Mozilla\\Firefox\\");
427 #elif defined(__APPLE__)
428 profile_root += std::string("Library/Application Support/Firefox/");
429 #else
430 profile_root += std::string(".mozilla/firefox/");
431 #endif
432
433 // lets see if we can open the profiles configuration file
434 tmp = profile_root + "profiles.ini";
435 pf = fopen(tmp.c_str(), "r");
436
437 // if profiles configuration file exists, parse it.
438 if (pf) {
439 pmf.init_file(pf);
440 mps.parse(pmf);
441 }
442
443 // we need to know which cookie file to look at, so if only
444 // one profile exists, use it.
445 //
446 // if more than one profile exists, look through all the
447 // profiles until we find the default profile. even when the
448 // user selects a different profile at startup the default
449 // profile flag is changed at startup to the new profile.
450 if (mps.profiles.size() == 0) {
451 if (pf) fclose(pf);
452 return retval; // something is very wrong, don't
453 // risk a crash
454 }
455
456 if (mps.profiles.size() == 1) {
457 default_index = 0;
458 } else {
459 for (i=0; i < mps.profiles.size(); i++) {
460 if (mps.profiles[i]->is_default) {
461 default_index = i;
462 break;
463 }
464 }
465 }
466
467 // should the path be treated as an absolute path or a relative
468 // path?
469 mp = mps.profiles[default_index];
470 if (mp->is_relative) {
471 cookies_root = profile_root + mp->path + "/";
472 } else {
473 cookies_root = mp->path + "/";
474 }
475
476 profile_root = cookies_root;
477 retval = true;
478
479 // cleanup
480 if (pf) fclose(pf);
481
482 return retval;
483 }
484
485
detect_cookie_mozilla_v3(std::string profile_root,std::string & project_url,std::string & name,std::string & value)486 bool detect_cookie_mozilla_v3(
487 std::string profile_root, std::string& project_url, std::string& name, std::string& value
488 ) {
489 bool retval = false;
490 std::string tmp;
491 std::string hostname;
492 char query[1024];
493 sqlite3* db;
494 char* lpszSQLErrorMessage = NULL;
495 int rc;
496 COOKIE_SQL cookie;
497
498
499 // determine the project hostname using the project url
500 parse_hostname_mozilla_compatible(project_url, hostname);
501
502
503 // now we should open up the cookie database.
504 tmp = profile_root + "cookies.sqlite";
505 rc = sqlite3_open(tmp.c_str(), &db);
506 if ( rc ) {
507 sqlite3_close(db);
508 return false;
509 }
510
511 // construct SQL query to extract the desired cookie
512 // SELECT host, name, value, expiry from moz_cookies WHERE name = '%s' AND host LIKE '%%%s'
513 sqlite3_snprintf(sizeof(query), query,
514 "SELECT host, name, value, expiry from moz_cookies WHERE name = '%q' AND host LIKE '%%%q'",
515 name.c_str(),
516 hostname.c_str()
517 );
518
519 // execute query
520 rc = sqlite3_exec(db, query, find_site_cookie_mozilla_v3, &cookie, &lpszSQLErrorMessage);
521 if ( rc != SQLITE_OK ){
522 sqlite3_free(lpszSQLErrorMessage);
523 }
524
525 // cleanup
526 sqlite3_close(db);
527
528 if ( !cookie.value.empty() ) {
529 value = cookie.value;
530 retval = true;
531 }
532
533 return retval;
534 }
535
536
537 //
538 // Firefox Browser Support
539 //
540
detect_cookie_firefox_3(std::string & project_url,std::string & name,std::string & value)541 bool detect_cookie_firefox_3(
542 std::string& project_url, std::string& name, std::string& value
543 ) {
544 std::string profile_root;
545 get_firefox_profile_root(profile_root);
546
547 return detect_cookie_mozilla_v3(
548 profile_root,
549 project_url,
550 name,
551 value
552 );
553 }
554
555
556 //
557 // Chrome-Based Browser Support
558 //
559
560 // search for the project specific cookie for chrome based browsers.
561 // SELECT host_key, name, value, expires_utc, httponly from cookies WHERE name = '%s' AND host_key LIKE '%s'
562 //
find_site_cookie_chrome(void * cookie,int,char ** argv,char **)563 static int find_site_cookie_chrome(
564 void* cookie, int /* argc */, char **argv, char ** /* szColumnName */
565 ) {
566 COOKIE_SQL* _cookie = (COOKIE_SQL*)cookie;
567 char host[256], cookie_name[256], cookie_value[4096];
568 long long expires;
569 long httponly;
570
571 safe_strcpy(host, "");
572 safe_strcpy(cookie_name, "");
573 safe_strcpy(cookie_value, "");
574 expires = 0;
575
576 sscanf( argv[0], "%255s", host );
577 sscanf( argv[1], "%255s", cookie_name );
578 sscanf( argv[2], "%4095s", cookie_value );
579 sscanf( argv[3],
580 #ifdef _WIN32
581 "%I64d",
582 #elif defined(__APPLE__)
583 "%lld",
584 #else
585 "%Ld",
586 #endif
587 &expires
588 );
589 sscanf( argv[4],
590 "%ld",
591 &httponly
592 );
593
594 // Convert Google Chrome time (microseconds since January 1, 1601)
595 // to UNIX time (seconds since January 1, 1970)
596 expires = (expires / 1000000) - 11644473600LL;
597
598 // is this a real cookie?
599 // temporary cookie? these cookies do not trickle back up
600 // to the jscript interface, so ignore them.
601 if (httponly) return 0;
602
603 // is this the right host?
604 if (!strstr(host, _cookie->host.c_str())) return 0;
605
606 // has the cookie expired?
607 if (time(0) > expires) return 0;
608
609 // is this the right cookie?
610 if (starts_with(cookie_name, _cookie->name)) {
611 _cookie->value = cookie_value;
612 }
613
614 return 0;
615 }
616
617
618 // traverse the profiles and determine which profile to use.
619 // this should be compatible with chrome.
620 //
get_chrome_profile_root(std::string & profile_root)621 bool get_chrome_profile_root( std::string& profile_root ) {
622 get_home_dir_path( profile_root, true );
623
624 #ifdef _WIN32
625 profile_root += std::string("Google\\Chrome\\User Data\\Default\\");
626 #elif defined(__APPLE__)
627 profile_root += std::string("Library/Application Support/Google/Chrome/Default/");
628 #else
629 profile_root += std::string(".google/chrome/");
630 #endif
631
632 return true;
633 }
634
635
detect_cookie_chrome(std::string profile_root,std::string & project_url,std::string & name,std::string & value)636 bool detect_cookie_chrome(
637 std::string profile_root, std::string& project_url, std::string& name, std::string& value
638 ) {
639 bool retval = false;
640 std::string tmp;
641 std::string hostname;
642 char query[1024];
643 sqlite3* db;
644 char* lpszSQLErrorMessage = NULL;
645 int rc;
646 COOKIE_SQL cookie;
647
648
649 // determine the project hostname using the project url
650 parse_hostname_chrome_compatible(project_url, hostname);
651
652
653 // now we should open up the cookie database.
654 tmp = profile_root + "Cookies";
655 rc = sqlite3_open(tmp.c_str(), &db);
656 if ( rc ) {
657 sqlite3_close(db);
658 tmp = profile_root + "Safe Browsing Cookies";
659 rc = sqlite3_open(tmp.c_str(), &db);
660 if ( rc ) {
661 sqlite3_close(db);
662 return false;
663 }
664 }
665
666 // construct SQL query to extract the desired cookie
667 // SELECT host_key, name, value, expires_utc, httponly from cookies WHERE name = '%s' AND host_key LIKE '%%%s'
668 sqlite3_snprintf(sizeof(query), query,
669 "SELECT host_key, name, value, expires_utc, httponly from cookies WHERE name = '%q' AND host_key LIKE '%%%q'",
670 name.c_str(),
671 hostname.c_str()
672 );
673
674 // execute query
675 rc = sqlite3_exec(db, query, find_site_cookie_chrome, &cookie, &lpszSQLErrorMessage);
676 if ( rc != SQLITE_OK ){
677 sqlite3_free(lpszSQLErrorMessage);
678 }
679
680 // cleanup
681 sqlite3_close(db);
682
683 if ( !cookie.value.empty() ) {
684 value = cookie.value;
685 retval = true;
686 }
687
688 return retval;
689 }
690
691
detect_cookie_chrome(std::string & project_url,std::string & name,std::string & value)692 bool detect_cookie_chrome(
693 std::string& project_url, std::string& name, std::string& value
694 ) {
695 std::string profile_root;
696 get_chrome_profile_root(profile_root);
697
698 return detect_cookie_chrome(
699 profile_root,
700 project_url,
701 name,
702 value
703 );
704 }
705
706
707 #ifdef _WIN32
708 //
709 // Internet Explorer Browser Support
710 //
711
712 //
713 // Detect a cookie in Internet Explorer by using the InternetGetCookie API.
714 // Supports: 3.x, 4.x, 5.x, 6.x, 7.x (UAC Turned Off), 8.x (UAC Turned Off), 9.x (UAC Turned Off), and
715 // 10.x (UAC Turned Off).
716 //
detect_cookie_ie_supported(std::string & project_url,std::string & name,std::string & value)717 bool detect_cookie_ie_supported(std::string& project_url, std::string& name, std::string& value)
718 {
719 bool bReturnValue = false;
720 bool bCheckDomainName = false;
721 char szCookieBuffer[4096];
722 char* pszCookieFragment = NULL;
723 DWORD dwSize = sizeof(szCookieBuffer)/sizeof(char);
724 std::string strCookieFragment;
725 std::string strCookieName;
726 std::string strCookieValue;
727 std::string hostname;
728 std::string domainname;
729 size_t uiDelimeterLocation;
730
731
732 // if we don't find the cookie at the exact project dns name, check one higher
733 // (i.e. www.worldcommunitygrid.org becomes worldcommunitygrid.org
734 parse_hostname_ie_compatible(project_url, hostname, domainname);
735
736 // InternetGetCookie expects them in URL format
737 hostname = std::string("http://") + hostname + std::string("/");
738 domainname = std::string("http://") + domainname + std::string("/");
739
740 // First check to see if the desired cookie is assigned to the hostname.
741 bReturnValue = InternetGetCookieA(hostname.c_str(), NULL, szCookieBuffer, &dwSize) == TRUE;
742 if (!bReturnValue || (!strstr(szCookieBuffer, name.c_str()))) {
743 bCheckDomainName = true;
744 }
745
746 // Next check if it was assigned to the domainname.
747 if (bCheckDomainName) {
748 bReturnValue = InternetGetCookieA(domainname.c_str(), NULL, szCookieBuffer, &dwSize) == TRUE;
749 if (!bReturnValue || (!strstr(szCookieBuffer, name.c_str()))) {
750 return false;
751 }
752 }
753
754 // Format of cookie buffer:
755 // 'cookie1=value1; cookie2=value2; cookie3=value3;
756 //
757 pszCookieFragment = strtok(szCookieBuffer, "; ");
758 while(pszCookieFragment) {
759 // Convert to a std::string so we can go to town
760 strCookieFragment = pszCookieFragment;
761
762 // Extract the name & value
763 uiDelimeterLocation = strCookieFragment.find("=", 0);
764 strCookieName = strCookieFragment.substr(0, uiDelimeterLocation);
765 strCookieValue = strCookieFragment.substr(uiDelimeterLocation + 1);
766
767 if (0 == strcmp(name.c_str(), strCookieName.c_str())) {
768 // Now we found it! Yea - auto attach!
769 value = strCookieValue;
770 bReturnValue = true;
771 }
772
773 pszCookieFragment = strtok(NULL, "; ");
774 }
775
776 return bReturnValue;
777 }
778
779 //
780 // Detect a cookie in Internet Explorer by using the InternetGetCookie API.
781 // Supports: 8.x (UAC Turned On), 9.x (UAC Turned On), 10.x (UAC Turned On).
782 //
783 typedef HRESULT (__stdcall *tIEGPMC)( IN LPCWSTR, IN LPCWSTR, OUT LPWSTR, OUT DWORD*, IN DWORD );
784
detect_cookie_ie_supported_uac(std::string & project_url,std::string & name,std::string & value)785 bool detect_cookie_ie_supported_uac(std::string& project_url, std::string& name, std::string& value)
786 {
787 static HMODULE ieframelib = NULL;
788 static tIEGPMC pIEGPMC = NULL;
789 bool bReturnValue = false;
790 bool bCheckDomainName = false;
791 HRESULT rc;
792 WCHAR szCookieBuffer[4096];
793 WCHAR* pszCookieFragment = NULL;
794 DWORD dwSize = sizeof(szCookieBuffer)/sizeof(WCHAR);
795 std::wstring strCookieFragment;
796 std::wstring strCookieName;
797 std::wstring strCookieValue;
798 std::string hostname;
799 std::wstring hostname_w;
800 std::string domainname;
801 std::wstring domainname_w;
802 std::wstring name_w;
803 size_t uiDelimeterLocation;
804
805 if (!ieframelib) {
806 ieframelib = LoadLibraryA("ieframe.dll");
807 if (ieframelib) {
808 pIEGPMC = (tIEGPMC)GetProcAddress(ieframelib, "IEGetProtectedModeCookie");
809 }
810 }
811
812 if (!pIEGPMC) {
813 return false;
814 }
815
816 // Convert name into wide character string
817 name_w = boinc_ascii_to_wide(name);
818
819 // if we don't find the cookie at the exact project dns name, check one higher
820 // (i.e. www.worldcommunitygrid.org becomes worldcommunitygrid.org
821 parse_hostname_ie_compatible(project_url, hostname, domainname);
822
823 // InternetGetCookie expects them in URL format
824 hostname_w = std::wstring(_T("http://")) + boinc_ascii_to_wide(hostname) + std::wstring(_T("/"));
825 domainname_w = std::wstring(_T("http://")) + boinc_ascii_to_wide(domainname) + std::wstring(_T("/"));
826
827 // First check to see if the desired cookie is assigned to the hostname.
828 rc = pIEGPMC(hostname_w.c_str(), NULL, szCookieBuffer, &dwSize, NULL) == TRUE;
829 if (!SUCCEEDED(rc) || (!wcsstr(szCookieBuffer, name_w.c_str()))) {
830 bCheckDomainName = true;
831 }
832
833 // Next check if it was assigned to the domainname.
834 if (bCheckDomainName) {
835 rc = pIEGPMC(domainname_w.c_str(), NULL, szCookieBuffer, &dwSize, NULL) == TRUE;
836 if (!SUCCEEDED(rc) || (!wcsstr(szCookieBuffer, name_w.c_str()))) {
837 return false;
838 }
839 }
840
841 // Format of cookie buffer:
842 // 'cookie1=value1; cookie2=value2; cookie3=value3;
843 //
844 pszCookieFragment = wcstok(szCookieBuffer, _T("; "));
845 while(pszCookieFragment) {
846 // Convert to a std::string so we can go to town
847 strCookieFragment = pszCookieFragment;
848
849 // Extract the name & value
850 uiDelimeterLocation = strCookieFragment.find(_T("="), 0);
851 strCookieName = strCookieFragment.substr(0, uiDelimeterLocation);
852 strCookieValue = strCookieFragment.substr(uiDelimeterLocation + 1);
853
854 if (0 == wcscmp(name_w.c_str(), strCookieName.c_str())) {
855 // Now we found it! Yea - auto attach!
856 value = boinc_wide_to_ascii(strCookieValue);
857 bReturnValue = true;
858 }
859
860 pszCookieFragment = wcstok(NULL, _T("; "));
861 }
862
863 return bReturnValue;
864 }
865
866
867 //
868 // Detect a cookie in Internet Explorer.
869 //
detect_cookie_ie(std::string & project_url,std::string & name,std::string & value)870 bool detect_cookie_ie(std::string& project_url, std::string& name, std::string& value)
871 {
872 // Check using the supported methods first
873 if (detect_cookie_ie_supported( project_url, name, value )) return true;
874 if (detect_cookie_ie_supported_uac( project_url, name, value )) return true;
875 return false;
876 }
877
878 #endif
879
880
881 //
882 // walk through the various browsers looking up the
883 // project cookies until the projects 'Setup' cookie is found.
884 //
885 // give preference to the default platform specific browers first before going
886 // to the platform independant browsers since most people don't switch from
887 // the default.
888 //
detect_setup_authenticator(std::string & project_url,std::string & authenticator)889 bool detect_setup_authenticator(
890 std::string& project_url, std::string& authenticator
891 ) {
892 bool retval = false;
893 std::string strCookieSetup("Setup");
894
895 #ifdef _WIN32
896 if (detect_cookie_ie(project_url, strCookieSetup, authenticator)) goto END;
897 #endif
898 #ifdef __APPLE__
899 if (detect_cookie_safari(project_url, strCookieSetup, authenticator)) goto END;
900 #endif
901 if (detect_cookie_chrome(project_url, strCookieSetup, authenticator)) goto END;
902 if (detect_cookie_firefox_3(project_url, strCookieSetup, authenticator)) goto END;
903
904 END:
905 if (is_authenticator_valid(authenticator)) {
906 retval = true;
907 }
908
909 return retval;
910 }
911
912
913 //
914 // walk through the various browsers looking up the
915 // various cookies that make up the simple account creation scheme.
916 //
917 // give preference to the default platform specific browers first before going
918 // to the platform independant browsers since most people don't switch from
919 // the default.
920 //
detect_simple_account_credentials(std::string & project_name,std::string & project_url,std::string & authenticator,std::string & project_institution,std::string & project_description,std::string & known)921 bool detect_simple_account_credentials(
922 std::string& project_name, std::string& project_url, std::string& authenticator,
923 std::string& project_institution, std::string& project_description, std::string& known
924 ) {
925 bool retval = false;
926 std::string strCookieServer("http://boinc.berkeley.edu");
927 std::string strCookieProjectName("attach_project_name");
928 std::string strCookieProjectURL("attach_master_url");
929 std::string strCookieAuthenticator("attach_auth");
930 std::string strCookieProjectInstitution("attach_project_inst");
931 std::string strCookieProjectDescription("attach_project_desc");
932 std::string strCookieKnown("attach_known");
933
934 #ifdef _WIN32
935 if ( detect_cookie_ie(strCookieServer, strCookieProjectName, project_name) &&
936 detect_cookie_ie(strCookieServer, strCookieProjectURL, project_url)
937 ){
938 detect_cookie_ie(strCookieServer, strCookieAuthenticator, authenticator);
939 detect_cookie_ie(strCookieServer, strCookieProjectInstitution, project_institution);
940 detect_cookie_ie(strCookieServer, strCookieProjectDescription, project_description);
941 detect_cookie_ie(strCookieServer, strCookieKnown, known);
942 goto END;
943 }
944 #endif
945 #ifdef __APPLE__
946 if ( detect_cookie_safari(strCookieServer, strCookieProjectName, project_name) &&
947 detect_cookie_safari(strCookieServer, strCookieProjectURL, project_url)
948 ){
949 detect_cookie_safari(strCookieServer, strCookieAuthenticator, authenticator);
950 detect_cookie_safari(strCookieServer, strCookieProjectInstitution, project_institution);
951 detect_cookie_safari(strCookieServer, strCookieProjectDescription, project_description);
952 detect_cookie_safari(strCookieServer, strCookieKnown, known);
953 goto END;
954 }
955 #endif
956 if ( detect_cookie_chrome(strCookieServer, strCookieProjectName, project_name) &&
957 detect_cookie_chrome(strCookieServer, strCookieProjectURL, project_url)
958 ){
959 detect_cookie_chrome(strCookieServer, strCookieAuthenticator, authenticator);
960 detect_cookie_chrome(strCookieServer, strCookieProjectInstitution, project_institution);
961 detect_cookie_chrome(strCookieServer, strCookieProjectDescription, project_description);
962 detect_cookie_chrome(strCookieServer, strCookieKnown, known);
963 goto END;
964 }
965 if ( detect_cookie_firefox_3(strCookieServer, strCookieProjectName, project_name) &&
966 detect_cookie_firefox_3(strCookieServer, strCookieProjectURL, project_url)
967 ){
968 detect_cookie_firefox_3(strCookieServer, strCookieAuthenticator, authenticator);
969 detect_cookie_firefox_3(strCookieServer, strCookieProjectInstitution, project_institution);
970 detect_cookie_firefox_3(strCookieServer, strCookieProjectDescription, project_description);
971 detect_cookie_firefox_3(strCookieServer, strCookieKnown, known);
972 goto END;
973 }
974 END:
975 if (!project_name.empty() && !project_url.empty()) {
976 retval = true;
977 }
978
979 return retval;
980 }
981
982
983 //
984 // walk through the various browsers looking up the
985 // account manager cookies until the account manager's 'Login' and 'Password_Hash'
986 // cookies are found.
987 //
988 // give preference to the default platform specific browers first before going
989 // to the platform independant browsers since most people don't switch from
990 // the default.
991 //
detect_account_manager_credentials(std::string & project_url,std::string & login,std::string & password_hash,std::string & return_url)992 bool detect_account_manager_credentials(
993 std::string& project_url, std::string& login, std::string& password_hash, std::string& return_url
994 ) {
995 bool retval = false;
996 std::string strCookieLogon("Logon");
997 std::string strCookiePasswordHash("PasswordHash");
998 std::string strCookieReturnURL("ReturnURL");
999
1000 #ifdef _WIN32
1001 if ( detect_cookie_ie(project_url, strCookieLogon, login) &&
1002 detect_cookie_ie(project_url, strCookiePasswordHash, password_hash)
1003 ){
1004 detect_cookie_ie(project_url, strCookieReturnURL, return_url);
1005 goto END;
1006 }
1007 #endif
1008 #ifdef __APPLE__
1009 if ( detect_cookie_safari(project_url, strCookieLogon, login) &&
1010 detect_cookie_safari(project_url, strCookiePasswordHash, password_hash)
1011 ){
1012 detect_cookie_safari(project_url, strCookieReturnURL, return_url);
1013 goto END;
1014 }
1015 #endif
1016 if ( detect_cookie_chrome(project_url, strCookieLogon, login) &&
1017 detect_cookie_chrome(project_url, strCookiePasswordHash, password_hash)
1018 ){
1019 detect_cookie_chrome(project_url, strCookieReturnURL, return_url);
1020 goto END;
1021 }
1022
1023 if ( detect_cookie_firefox_3(project_url, strCookieLogon, login) &&
1024 detect_cookie_firefox_3(project_url, strCookiePasswordHash, password_hash)
1025 ){
1026 detect_cookie_firefox_3(project_url, strCookieReturnURL, return_url);
1027 goto END;
1028 }
1029
1030 END:
1031 if (!login.empty() && !password_hash.empty()) {
1032 retval = true;
1033 }
1034
1035 return retval;
1036 }
1037
1038