LRESULT CALLBACK CookieWndProc(int nCode, WPARAM wParam, LPARAM lParam) { CWPSTRUCT* call_window_proc_struct = reinterpret_cast<CWPSTRUCT*>(lParam); if (WM_COPYDATA == call_window_proc_struct->message) { COPYDATASTRUCT* data = reinterpret_cast<COPYDATASTRUCT*>(call_window_proc_struct->lParam); webdriver::HookProcessor::CopyDataToBuffer(data->cbData, data->lpData); } else if (WD_GET_ALL_COOKIES == call_window_proc_struct->message) { std::wstring url = webdriver::HookProcessor::CopyWStringFromBuffer(); int driver_process_id = static_cast<int>(call_window_proc_struct->wParam); CComPtr<IUri> uri_pointer; HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer); DWORD scheme = 0; uri_pointer->GetScheme(&scheme); CComBSTR scheme_bstr; uri_pointer->GetSchemeName(&scheme_bstr); CComBSTR host_bstr; uri_pointer->GetHost(&host_bstr); CComBSTR path_bstr; uri_pointer->GetPath(&path_bstr); std::wstring parsed_uri = scheme_bstr; parsed_uri.append(L"://"); parsed_uri.append(host_bstr); parsed_uri.append(path_bstr); InternetGetCookieEx2Proc get_cookie_proc = NULL; InternetFreeCookiesProc free_cookies_proc = NULL; HMODULE wininet_handle = ::GetModuleHandle(L"wininet"); if (wininet_handle) { get_cookie_proc = reinterpret_cast<InternetGetCookieEx2Proc>(::GetProcAddress(wininet_handle, "InternetGetCookieEx2")); free_cookies_proc = reinterpret_cast<InternetFreeCookiesProc>(::GetProcAddress(wininet_handle, "InternetFreeCookies")); } DWORD cookie_count = 0; INTERNETCOOKIE2* cookie_pointer = NULL; DWORD success = 1; if (get_cookie_proc) { success = get_cookie_proc(parsed_uri.c_str(), NULL, INTERNET_COOKIE_NON_SCRIPT, &cookie_pointer, &cookie_count); } if (success == 0) { // Mimic the format of the old persistent cookie files for ease of // transmission back to the driver and parsing. std::wstring all_cookies = L""; for (DWORD cookie_index = 0; cookie_index < cookie_count; ++cookie_index) { if (all_cookies.size() > 0) { all_cookies.append(L"\n*\n"); } INTERNETCOOKIE2* current_cookie = cookie_pointer + cookie_index; std::wstring cookie_name = current_cookie->pwszName; std::wstring cookie_value = current_cookie->pwszValue; std::wstring cookie_domain = current_cookie->pwszDomain; std::wstring cookie_path = current_cookie->pwszPath; DWORD flags = current_cookie->dwFlags; FILETIME expires = current_cookie->ftExpires; all_cookies.append(cookie_name).append(L"\n"); all_cookies.append(cookie_value).append(L"\n"); all_cookies.append(cookie_domain).append(L"/").append(cookie_path).append(L"\n"); all_cookies.append(std::to_wstring(flags)).append(L"\n"); // If the expiration time is set, add it to the string for the cookie. // If not, append empty fields to the record so subsequent parsing // of the string will still work. if (current_cookie->fExpiresSet) { all_cookies.append(std::to_wstring(expires.dwLowDateTime)).append(L"\n"); all_cookies.append(std::to_wstring(expires.dwHighDateTime)).append(L"\n"); } else { all_cookies.append(L"\n\n"); } } free_cookies_proc(cookie_pointer, cookie_count); webdriver::HookProcessor::CopyWStringToBuffer(all_cookies); } else { webdriver::HookProcessor::SetDataBufferSize(sizeof(wchar_t)); } webdriver::HookProcessor::WriteBufferToPipe(driver_process_id); } else if (WD_GET_HTTPONLY_COOKIES == call_window_proc_struct->message || WD_GET_SCRIPTABLE_COOKIES == call_window_proc_struct->message || WD_GET_SECURE_COOKIES == call_window_proc_struct->message) { std::wstring url = webdriver::HookProcessor::CopyWStringFromBuffer(); int driver_process_id = static_cast<int>(call_window_proc_struct->wParam); DWORD get_cookie_flags = 0; if (WD_GET_HTTPONLY_COOKIES == call_window_proc_struct->message || WD_GET_SECURE_COOKIES == call_window_proc_struct->message) { get_cookie_flags = INTERNET_COOKIE_HTTPONLY; } CComPtr<IUri> uri_pointer; HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer); DWORD scheme = 0; uri_pointer->GetScheme(&scheme); CComBSTR scheme_bstr; uri_pointer->GetSchemeName(&scheme_bstr); CComBSTR host_bstr; uri_pointer->GetHost(&host_bstr); CComBSTR path_bstr; uri_pointer->GetPath(&path_bstr); // Get only the cookies for the base URL, omitting port, if there is one. // N.B., we only return cookies secure cookies when browsing a site using // SSL. The browser won't see cookies with the 'secure' flag for sites // visited using plain http. std::wstring parsed_uri = L"http"; if ((WD_GET_SECURE_COOKIES == call_window_proc_struct->message || WD_GET_SCRIPTABLE_COOKIES == call_window_proc_struct->message) && URL_SCHEME_HTTPS == scheme) { parsed_uri.append(L"s"); } parsed_uri.append(L"://"); parsed_uri.append(host_bstr); parsed_uri.append(path_bstr); // Call InternetGetCookieEx once to get the size of the buffer needed, // then call again with the appropriately sized buffer allocated. DWORD buffer_size = 0; BOOL success = ::InternetGetCookieEx(parsed_uri.c_str(), NULL, NULL, &buffer_size, get_cookie_flags, NULL); if (success) { webdriver::HookProcessor::SetDataBufferSize(buffer_size); ::InternetGetCookieEx(parsed_uri.c_str(), NULL, reinterpret_cast<LPTSTR>(webdriver::HookProcessor::GetDataBufferAddress()), &buffer_size, get_cookie_flags, NULL); webdriver::HookProcessor::WriteBufferToPipe(driver_process_id); } else { if (ERROR_NO_MORE_ITEMS == ::GetLastError()) { webdriver::HookProcessor::SetDataBufferSize(sizeof(wchar_t)); webdriver::HookProcessor::WriteBufferToPipe(driver_process_id); } } } else if (WD_GET_COOKIE_CACHE_FILES == call_window_proc_struct->message) { int driver_process_id = static_cast<int>(call_window_proc_struct->wParam); std::wstring file_list = L""; std::wstring url = webdriver::HookProcessor::CopyWStringFromBuffer(); // We need to remove the port to find the entry in the cache. CComPtr<IUri> uri_pointer; HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer); CComBSTR host_bstr; uri_pointer->GetHost(&host_bstr); CComBSTR path_bstr; uri_pointer->GetPath(&path_bstr); std::wstring parsed_uri = host_bstr; parsed_uri.append(path_bstr); // A 2048-byte buffer should be large enough to handle cookie // cache entries in all but the most extreme cases. HANDLE cache_enum_handle = NULL; DWORD entry_size = 2048; LPINTERNET_CACHE_ENTRY_INFO entry = NULL; std::vector<char> entry_buffer(entry_size); entry = reinterpret_cast<INTERNET_CACHE_ENTRY_INFO*>(&entry_buffer[0]); cache_enum_handle = ::FindFirstUrlCacheEntry(L"cookie:", entry, &entry_size); if (cache_enum_handle == NULL && ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) { entry_buffer.resize(entry_size); entry = reinterpret_cast<INTERNET_CACHE_ENTRY_INFO*>(&entry_buffer[0]); cache_enum_handle = ::FindFirstUrlCacheEntry(L"cookie:", entry, &entry_size); } while (cache_enum_handle != NULL) { if (COOKIE_CACHE_ENTRY == (entry->CacheEntryType & COOKIE_CACHE_ENTRY)) { std::wstring name = entry->lpszSourceUrlName; size_t name_separator_pos(name.find_first_of(L"@")); std::wstring domain = name.substr(name_separator_pos + 1); if (parsed_uri.find(domain) != std::wstring::npos) { if (file_list.size() > 0) { file_list.append(L"|"); } file_list.append(entry->lpszLocalFileName); } } BOOL success = ::FindNextUrlCacheEntry(cache_enum_handle, entry, &entry_size); if (!success) { DWORD error = ::GetLastError(); if (ERROR_INSUFFICIENT_BUFFER == error) { entry_buffer.resize(entry_size); BOOL other_success = ::FindNextUrlCacheEntry(cache_enum_handle, entry, &entry_size); } else if (ERROR_NO_MORE_ITEMS == error) { ::FindCloseUrlCache(cache_enum_handle); cache_enum_handle = NULL; } } } webdriver::HookProcessor::CopyWStringToBuffer(file_list); webdriver::HookProcessor::WriteBufferToPipe(driver_process_id); } else if (WD_SET_COOKIE == call_window_proc_struct->message) { DWORD set_cookie_flags = static_cast<DWORD>(call_window_proc_struct->wParam); std::wstring cookie_data = webdriver::HookProcessor::CopyWStringFromBuffer(); size_t url_separator_pos = cookie_data.find_first_of(L"|"); std::wstring url = cookie_data.substr(0, url_separator_pos); std::wstring cookie = cookie_data.substr(url_separator_pos + 1); CComPtr<IUri> uri_pointer; HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer); CComBSTR scheme_bstr; uri_pointer->GetSchemeName(&scheme_bstr); CComBSTR host_bstr; uri_pointer->GetHost(&host_bstr); std::wstring parsed_uri = scheme_bstr; parsed_uri.append(L"://"); parsed_uri.append(host_bstr); // Leverage the shared data buffer size to return the error code // back to the driver, if necessary. DWORD cookie_set = ::InternetSetCookieEx(parsed_uri.c_str(), NULL, cookie.c_str(), set_cookie_flags, NULL); if (cookie_set) { webdriver::HookProcessor::SetDataBufferSize(0); } else { DWORD error = ::GetLastError(); webdriver::HookProcessor::SetDataBufferSize(error); } } return ::CallNextHookEx(NULL, nCode, wParam, lParam); }
LRESULT CALLBACK CookieWndProc(int nCode, WPARAM wParam, LPARAM lParam) { CWPSTRUCT* call_window_proc_struct = reinterpret_cast<CWPSTRUCT*>(lParam); if (WM_COPYDATA == call_window_proc_struct->message) { COPYDATASTRUCT* data = reinterpret_cast<COPYDATASTRUCT*>(call_window_proc_struct->lParam); webdriver::HookProcessor::CopyDataToBuffer(data->cbData, data->lpData); } else if (WD_GET_HTTPONLY_COOKIES == call_window_proc_struct->message || WD_GET_SCRIPTABLE_COOKIES == call_window_proc_struct->message || WD_GET_SECURE_COOKIES == call_window_proc_struct->message) { std::wstring url = webdriver::HookProcessor::CopyWStringFromBuffer(); int driver_process_id = static_cast<int>(call_window_proc_struct->wParam); DWORD get_cookie_flags = 0; if (WD_GET_HTTPONLY_COOKIES == call_window_proc_struct->message || WD_GET_SECURE_COOKIES == call_window_proc_struct->message) { get_cookie_flags = INTERNET_COOKIE_HTTPONLY; } CComPtr<IUri> uri_pointer; HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer); DWORD scheme = 0; uri_pointer->GetScheme(&scheme); CComBSTR scheme_bstr; uri_pointer->GetSchemeName(&scheme_bstr); CComBSTR host_bstr; uri_pointer->GetHost(&host_bstr); CComBSTR path_bstr; uri_pointer->GetPath(&path_bstr); // Get only the cookies for the base URL, omitting port, if there is one. // N.B., we only return cookies secure cookies when browsing a site using // SSL. The browser won't see cookies with the 'secure' flag for sites // visited using plain http. std::wstring parsed_uri = L"http"; if ((WD_GET_SECURE_COOKIES == call_window_proc_struct->message || WD_GET_SCRIPTABLE_COOKIES == call_window_proc_struct->message) && URL_SCHEME_HTTPS == scheme) { parsed_uri.append(L"s"); } parsed_uri.append(L"://"); parsed_uri.append(host_bstr); parsed_uri.append(path_bstr); // Call InternetGetCookieEx once to get the size of the buffer needed, // then call again with the appropriately sized buffer allocated. DWORD buffer_size = 0; BOOL success = ::InternetGetCookieEx(parsed_uri.c_str(), NULL, NULL, &buffer_size, get_cookie_flags, NULL); if (success) { webdriver::HookProcessor::SetDataBufferSize(buffer_size); ::InternetGetCookieEx(parsed_uri.c_str(), NULL, reinterpret_cast<LPTSTR>(webdriver::HookProcessor::GetDataBufferAddress()), &buffer_size, get_cookie_flags, NULL); webdriver::HookProcessor::WriteBufferToPipe(driver_process_id); } else { if (ERROR_NO_MORE_ITEMS == ::GetLastError()) { webdriver::HookProcessor::SetDataBufferSize(sizeof(wchar_t)); webdriver::HookProcessor::WriteBufferToPipe(driver_process_id); } } } else if (WD_GET_COOKIE_CACHE_FILES == call_window_proc_struct->message) { int driver_process_id = static_cast<int>(call_window_proc_struct->wParam); std::wstring file_list = L""; std::wstring url = webdriver::HookProcessor::CopyWStringFromBuffer(); // We need to remove the port to find the entry in the cache. CComPtr<IUri> uri_pointer; HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer); CComBSTR host_bstr; uri_pointer->GetHost(&host_bstr); CComBSTR path_bstr; uri_pointer->GetPath(&path_bstr); std::wstring parsed_uri = host_bstr; parsed_uri.append(path_bstr); // A 2048-byte buffer should be large enough to handle cookie // cache entries in all but the most extreme cases. HANDLE cache_enum_handle = NULL; DWORD entry_size = 2048; LPINTERNET_CACHE_ENTRY_INFO entry = NULL; std::vector<char> entry_buffer(entry_size); entry = reinterpret_cast<INTERNET_CACHE_ENTRY_INFO*>(&entry_buffer[0]); cache_enum_handle = ::FindFirstUrlCacheEntry(L"cookie:", entry, &entry_size); if (cache_enum_handle == NULL && ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) { entry_buffer.resize(entry_size); entry = reinterpret_cast<INTERNET_CACHE_ENTRY_INFO*>(&entry_buffer[0]); cache_enum_handle = ::FindFirstUrlCacheEntry(L"cookie:", entry, &entry_size); } while (cache_enum_handle != NULL) { if (COOKIE_CACHE_ENTRY == (entry->CacheEntryType & COOKIE_CACHE_ENTRY)) { std::wstring name = entry->lpszSourceUrlName; size_t name_separator_pos(name.find_first_of(L"@")); std::wstring domain = name.substr(name_separator_pos + 1); if (parsed_uri.find(domain) != std::wstring::npos) { if (file_list.size() > 0) { file_list.append(L"|"); } file_list.append(entry->lpszLocalFileName); } } BOOL success = ::FindNextUrlCacheEntry(cache_enum_handle, entry, &entry_size); if (!success) { DWORD error = ::GetLastError(); if (ERROR_INSUFFICIENT_BUFFER == error) { entry_buffer.resize(entry_size); BOOL other_success = ::FindNextUrlCacheEntry(cache_enum_handle, entry, &entry_size); } else if (ERROR_NO_MORE_ITEMS == error) { ::FindCloseUrlCache(cache_enum_handle); cache_enum_handle = NULL; } } } webdriver::HookProcessor::CopyWStringToBuffer(file_list); webdriver::HookProcessor::WriteBufferToPipe(driver_process_id); } else if (WD_SET_COOKIE == call_window_proc_struct->message) { DWORD set_cookie_flags = static_cast<DWORD>(call_window_proc_struct->wParam); std::wstring cookie_data = webdriver::HookProcessor::CopyWStringFromBuffer(); size_t url_separator_pos = cookie_data.find_first_of(L"|"); std::wstring url = cookie_data.substr(0, url_separator_pos); std::wstring cookie = cookie_data.substr(url_separator_pos + 1); CComPtr<IUri> uri_pointer; HRESULT hr = ::CreateUri(url.c_str(), Uri_CREATE_ALLOW_RELATIVE, 0, &uri_pointer); CComBSTR scheme_bstr; uri_pointer->GetSchemeName(&scheme_bstr); CComBSTR host_bstr; uri_pointer->GetHost(&host_bstr); std::wstring parsed_uri = scheme_bstr; parsed_uri.append(L"://"); parsed_uri.append(host_bstr); // Leverage the shared data buffer size to return the error code // back to the driver, if necessary. DWORD cookie_set = ::InternetSetCookieEx(parsed_uri.c_str(), NULL, cookie.c_str(), set_cookie_flags, NULL); if (cookie_set) { webdriver::HookProcessor::SetDataBufferSize(0); } else { DWORD error = ::GetLastError(); webdriver::HookProcessor::SetDataBufferSize(error); } } return ::CallNextHookEx(NULL, nCode, wParam, lParam); }