diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index d615011e833..2fee2c3f20e 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -1572,8 +1572,16 @@ static BOOL do_authorization( request_t *request, DWORD target, DWORD scheme_fla return FALSE; auth_ptr = &request->authinfo; auth_target = attr_authorization; - username = request->connect->username; - password = request->connect->password; + if (request->creds[TARGET_SERVER][scheme].username) + { + username = request->creds[TARGET_SERVER][scheme].username; + password = request->creds[TARGET_SERVER][scheme].password; + } + else + { + username = request->connect->username; + password = request->connect->password; + } break; case WINHTTP_AUTH_TARGET_PROXY: @@ -1581,8 +1589,16 @@ static BOOL do_authorization( request_t *request, DWORD target, DWORD scheme_fla return FALSE; auth_ptr = &request->proxy_authinfo; auth_target = attr_proxy_authorization; - username = request->connect->session->proxy_username; - password = request->connect->session->proxy_password; + if (request->creds[TARGET_PROXY][scheme].username) + { + username = request->creds[TARGET_PROXY][scheme].username; + password = request->creds[TARGET_PROXY][scheme].password; + } + else + { + username = request->connect->session->proxy_username; + password = request->connect->session->proxy_password; + } break; default: @@ -1766,11 +1782,12 @@ static BOOL do_authorization( request_t *request, DWORD target, DWORD scheme_fla return ret; } -static BOOL set_credentials( request_t *request, DWORD target, DWORD scheme, const WCHAR *username, +static BOOL set_credentials( request_t *request, DWORD target, DWORD scheme_flag, const WCHAR *username, const WCHAR *password ) { - if ((scheme == WINHTTP_AUTH_SCHEME_BASIC || scheme == WINHTTP_AUTH_SCHEME_DIGEST) && - (!username || !password)) + enum auth_scheme scheme = scheme_from_flag( scheme_flag ); + + if (scheme == SCHEME_INVALID || ((scheme == SCHEME_BASIC || scheme == SCHEME_DIGEST) && (!username || !password))) { set_last_error( ERROR_INVALID_PARAMETER ); return FALSE; @@ -1779,24 +1796,24 @@ static BOOL set_credentials( request_t *request, DWORD target, DWORD scheme, con { case WINHTTP_AUTH_TARGET_SERVER: { - heap_free( request->connect->username ); - if (!username) request->connect->username = NULL; - else if (!(request->connect->username = strdupW( username ))) return FALSE; + heap_free( request->creds[TARGET_SERVER][scheme].username ); + if (!username) request->creds[TARGET_SERVER][scheme].username = NULL; + else if (!(request->creds[TARGET_SERVER][scheme].username = strdupW( username ))) return FALSE; - heap_free( request->connect->password ); - if (!password) request->connect->password = NULL; - else if (!(request->connect->password = strdupW( password ))) return FALSE; + heap_free( request->creds[TARGET_SERVER][scheme].password ); + if (!password) request->creds[TARGET_SERVER][scheme].password = NULL; + else if (!(request->creds[TARGET_SERVER][scheme].password = strdupW( password ))) return FALSE; break; } case WINHTTP_AUTH_TARGET_PROXY: { - heap_free( request->connect->session->proxy_username ); - if (!username) request->connect->session->proxy_username = NULL; - else if (!(request->connect->session->proxy_username = strdupW( username ))) return FALSE; + heap_free( request->creds[TARGET_PROXY][scheme].username ); + if (!username) request->creds[TARGET_PROXY][scheme].username = NULL; + else if (!(request->creds[TARGET_PROXY][scheme].username = strdupW( username ))) return FALSE; - heap_free( request->connect->session->proxy_password ); - if (!password) request->connect->session->proxy_password = NULL; - else if (!(request->connect->session->proxy_password = strdupW( password ))) return FALSE; + heap_free( request->creds[TARGET_PROXY][scheme].password ); + if (!password) request->creds[TARGET_PROXY][scheme].password = NULL; + else if (!(request->creds[TARGET_PROXY][scheme].password = strdupW( password ))) return FALSE; break; } default: diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c index 9becdfe16d4..1b54288097b 100644 --- a/dlls/winhttp/session.c +++ b/dlls/winhttp/session.c @@ -555,7 +555,7 @@ end: static void request_destroy( object_header_t *hdr ) { request_t *request = (request_t *)hdr; - unsigned int i; + unsigned int i, j; TRACE("%p\n", request); @@ -587,6 +587,14 @@ static void request_destroy( object_header_t *hdr ) heap_free( request->headers ); for (i = 0; i < request->num_accept_types; i++) heap_free( request->accept_types[i] ); heap_free( request->accept_types ); + for (i = 0; i < TARGET_MAX; i++) + { + for (j = 0; j < SCHEME_MAX; j++) + { + heap_free( request->creds[i][j].username ); + heap_free( request->creds[i][j].password ); + } + } heap_free( request ); } diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index 705d65406cd..38604619431 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -1986,8 +1986,9 @@ static void test_basic_request(int port, const WCHAR *verb, const WCHAR *path) static void test_basic_authentication(int port) { static const WCHAR authW[] = {'/','a','u','t','h',0}; - static const WCHAR userW[] = {'u','s','e','r',0}; - static const WCHAR passW[] = {'p','w','d',0}; + static WCHAR userW[] = {'u','s','e','r',0}; + static WCHAR passW[] = {'p','w','d',0}; + static WCHAR pass2W[] = {'p','w','d','2',0}; HINTERNET ses, con, req; DWORD status, size, error, supported, first, target; BOOL ret; @@ -2120,6 +2121,76 @@ static void test_basic_authentication(int port) WinHttpCloseHandle(req); WinHttpCloseHandle(con); WinHttpCloseHandle(ses); + + /* credentials set with WinHttpSetCredentials take precedence over those set through options */ + + ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %u\n", GetLastError()); + + con = WinHttpConnect(ses, localhostW, port, 0); + ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + + req = WinHttpOpenRequest(con, NULL, authW, NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, passW, NULL); + ok(ret, "failed to set credentials %u\n", GetLastError()); + + ret = WinHttpSetOption(req, WINHTTP_OPTION_USERNAME, userW, lstrlenW(userW)); + ok(ret, "failed to set username %u\n", GetLastError()); + + ret = WinHttpSetOption(req, WINHTTP_OPTION_PASSWORD, pass2W, lstrlenW(pass2W)); + ok(ret, "failed to set password %u\n", GetLastError()); + + ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); + ok(ret, "failed to send request %u\n", GetLastError()); + + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %u\n", GetLastError()); + + status = 0xdeadbeef; + size = sizeof(status); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); + ok(ret, "failed to query status code %u\n", GetLastError()); + ok(status == 200, "request failed unexpectedly %u\n", status); + + WinHttpCloseHandle(req); + WinHttpCloseHandle(con); + WinHttpCloseHandle(ses); + + ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %u\n", GetLastError()); + + con = WinHttpConnect(ses, localhostW, port, 0); + ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + + req = WinHttpOpenRequest(con, NULL, authW, NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + ret = WinHttpSetOption(req, WINHTTP_OPTION_USERNAME, userW, lstrlenW(userW)); + ok(ret, "failed to set username %u\n", GetLastError()); + + ret = WinHttpSetOption(req, WINHTTP_OPTION_PASSWORD, pass2W, lstrlenW(passW)); + ok(ret, "failed to set password %u\n", GetLastError()); + + ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, pass2W, NULL); + ok(ret, "failed to set credentials %u\n", GetLastError()); + + ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); + ok(ret, "failed to send request %u\n", GetLastError()); + + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %u\n", GetLastError()); + + status = 0xdeadbeef; + size = sizeof(status); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); + ok(ret, "failed to query status code %u\n", GetLastError()); + ok(status == 401, "request failed unexpectedly %u\n", status); + + WinHttpCloseHandle(req); + WinHttpCloseHandle(con); + WinHttpCloseHandle(ses); } static void test_no_headers(int port) diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 4c567edb64a..6a7dd3e439a 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -148,6 +148,14 @@ typedef struct BOOL is_request; /* part of request headers? */ } header_t; +enum auth_target +{ + TARGET_INVALID = -1, + TARGET_SERVER, + TARGET_PROXY, + TARGET_MAX +}; + enum auth_scheme { SCHEME_INVALID = -1, @@ -155,7 +163,8 @@ enum auth_scheme SCHEME_NTLM, SCHEME_PASSPORT, SCHEME_DIGEST, - SCHEME_NEGOTIATE + SCHEME_NEGOTIATE, + SCHEME_MAX }; struct authinfo @@ -206,6 +215,11 @@ typedef struct HANDLE task_thread; struct list task_queue; CRITICAL_SECTION task_cs; + struct + { + WCHAR *username; + WCHAR *password; + } creds[TARGET_MAX][SCHEME_MAX]; } request_t; typedef struct _task_header_t task_header_t;