From 0c02e358418986c8139b787d098a1c41c8014254 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Thu, 27 Dec 2012 17:54:19 +0100 Subject: [PATCH] wininet: Properly handle output buffer size in InternetGetCookieW. --- dlls/wininet/cookie.c | 77 ++++++++++++++++++++++------------- dlls/wininet/http.c | 2 +- dlls/wininet/internet.h | 2 +- dlls/wininet/tests/internet.c | 7 ++++ 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/dlls/wininet/cookie.c b/dlls/wininet/cookie.c index 0dd93d97b1e..cd761b1f466 100644 --- a/dlls/wininet/cookie.c +++ b/dlls/wininet/cookie.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef HAVE_UNISTD_H # include #endif @@ -529,9 +530,10 @@ static void COOKIE_deleteDomain(cookie_domain *deadDomain) heap_free(deadDomain); } -BOOL get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD *size) +DWORD get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD *size) { - unsigned cnt = 0, len, domain_count = 0, cookie_count = 0; + unsigned cnt = 0, len, name_len, domain_count = 0, cookie_count = 0; + WCHAR *ptr = cookie_data; cookie_domain *domain; FILETIME tm; @@ -562,49 +564,62 @@ BOOL get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD continue; } - if(!cookie_data) { /* return the size of the buffer required to lpdwSize */ - if (cookie_count) - cnt += 2; /* '; ' */ - cnt += strlenW(cookie_iter->lpCookieName); - if ((len = strlenW(cookie_iter->lpCookieData))) { - cnt += 1; /* = */ - cnt += len; - } - }else { - static const WCHAR szsc[] = { ';',' ',0 }; - static const WCHAR szname[] = { '%','s',0 }; - static const WCHAR szdata[] = { '=','%','s',0 }; - - if (cookie_count) cnt += snprintfW(cookie_data + cnt, *size - cnt, szsc); - cnt += snprintfW(cookie_data + cnt, *size - cnt, szname, cookie_iter->lpCookieName); - - if (cookie_iter->lpCookieData[0]) - cnt += snprintfW(cookie_data + cnt, *size - cnt, szdata, cookie_iter->lpCookieData); - - TRACE("Cookie: %s\n", debugstr_w(cookie_data)); + if (cookie_count) + cnt += 2; /* '; ' */ + cnt += name_len = strlenW(cookie_iter->lpCookieName); + if ((len = strlenW(cookie_iter->lpCookieData))) { + cnt += 1; /* = */ + cnt += len; } + + if(ptr) { + if(*size > cnt) { + if(cookie_count) { + *ptr++ = ';'; + *ptr++ = ' '; + } + + memcpy(ptr, cookie_iter->lpCookieName, name_len*sizeof(WCHAR)); + ptr += name_len; + + if(len) { + *ptr++ = '='; + memcpy(ptr, cookie_iter->lpCookieData, len*sizeof(WCHAR)); + ptr += len; + } + + assert(cookie_data+cnt == ptr); + TRACE("Cookie: %s\n", debugstr_wn(cookie_data, cnt)); + }else { + /* Stop writing data, just compute the size */ + ptr = NULL; + } + } + cookie_count++; } } LeaveCriticalSection(&cookie_cs); - if (!domain_count) { + if(ptr) + *ptr = 0; + + if (!cnt) { TRACE("no cookies found for %s\n", debugstr_w(host)); - SetLastError(ERROR_NO_MORE_ITEMS); - return FALSE; + return ERROR_NO_MORE_ITEMS; } - if(!cookie_data) { + if(!cookie_data || !ptr) { *size = (cnt + 1) * sizeof(WCHAR); TRACE("returning %u\n", *size); - return TRUE; + return cookie_data ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS; } *size = cnt + 1; TRACE("Returning %u (from %u domains): %s\n", cnt, domain_count, debugstr_w(cookie_data)); - return cnt != 0; + return ERROR_SUCCESS; } /*********************************************************************** @@ -624,6 +639,7 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LPWSTR lpCookieData, LPDWORD lpdwSize) { WCHAR host[INTERNET_MAX_HOST_NAME_LENGTH], path[INTERNET_MAX_PATH_LENGTH]; + DWORD res; BOOL ret; TRACE("(%s, %s, %p, %p)\n", debugstr_w(lpszUrl),debugstr_w(lpszCookieName), lpCookieData, lpdwSize); @@ -641,7 +657,10 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, return FALSE; } - return get_cookie(host, path, lpCookieData, lpdwSize); + res = get_cookie(host, path, lpCookieData, lpdwSize); + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index f890363e2d0..9e3e8e4f7b1 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -4008,7 +4008,7 @@ static void HTTP_InsertCookies(http_request_t *request) if(!host) return; - if(!get_cookie(host->lpszValue, request->path, NULL, &cookie_size)) + if(get_cookie(host->lpszValue, request->path, NULL, &cookie_size) != ERROR_SUCCESS) return; size = sizeof(cookieW) + cookie_size * sizeof(WCHAR) + sizeof(szCrLf); diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index 10002d48b1d..3d2bd351058 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -517,7 +517,7 @@ DWORD HTTP_Connect(appinfo_t*,LPCWSTR, BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, struct sockaddr *psa, socklen_t *sa_len) DECLSPEC_HIDDEN; -BOOL get_cookie(const WCHAR*,const WCHAR*,WCHAR*,DWORD*) DECLSPEC_HIDDEN; +DWORD get_cookie(const WCHAR*,const WCHAR*,WCHAR*,DWORD*) DECLSPEC_HIDDEN; BOOL set_cookie(const WCHAR*,const WCHAR*,const WCHAR*,const WCHAR*) DECLSPEC_HIDDEN; void INTERNET_SetLastError(DWORD dwError) DECLSPEC_HIDDEN; diff --git a/dlls/wininet/tests/internet.c b/dlls/wininet/tests/internet.c index 1b4ee469384..8b0071c1033 100644 --- a/dlls/wininet/tests/internet.c +++ b/dlls/wininet/tests/internet.c @@ -426,6 +426,13 @@ static void test_complicated_cookie(void) ok(len == 19, "len = %u\n", len); ok(lstrlenW(wbuf) == 18, "strlenW(wbuf) = %u\n", lstrlenW(wbuf)); + len = 10; + memset(wbuf, 0xac, sizeof(wbuf)); + ret = InternetGetCookieW(testing_example_comW, NULL, wbuf, &len); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "InternetGetCookieW returned: %x(%u), expected ERROR_INSUFFICIENT_BUFFER\n", ret, GetLastError()); + ok(len == 38, "len = %u\n", len); + len = 1024; ret = InternetGetCookie("http://testing.example.com/foobar", NULL, buffer, &len); ok(ret == TRUE,"InternetGetCookie failed\n");