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