1 /* 2 * Copyright 2008 Hans Leidekker for CodeWeavers 3 * Copyright 2013 Jacek Caban for CodeWeavers 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library 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. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include "config.h" 21 #define NONAMELESSUNION 22 #include "ws2tcpip.h" 23 #include <stdarg.h> 24 #include <stdio.h> 25 #include <assert.h> 26 27 #include "windef.h" 28 #include "winbase.h" 29 #include "winhttp.h" 30 #include "schannel.h" 31 32 #include "wine/debug.h" 33 #include "wine/library.h" 34 #include "winhttp_private.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(winhttp); 37 38 static int sock_send(int fd, const void *msg, size_t len, int flags) 39 { 40 int ret; 41 do 42 { 43 if ((ret = send(fd, msg, len, flags)) == -1) WARN("send error %u\n", WSAGetLastError()); 44 } 45 while(ret == -1 && WSAGetLastError() == WSAEINTR); 46 return ret; 47 } 48 49 static int sock_recv(int fd, void *msg, size_t len, int flags) 50 { 51 int ret; 52 do 53 { 54 if ((ret = recv(fd, msg, len, flags)) == -1) WARN("recv error %u\n", WSAGetLastError()); 55 } 56 while(ret == -1 && WSAGetLastError() == WSAEINTR); 57 return ret; 58 } 59 60 static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, WCHAR *server, DWORD security_flags, BOOL check_revocation ) 61 { 62 HCERTSTORE store = cert->hCertStore; 63 BOOL ret; 64 CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; 65 PCCERT_CHAIN_CONTEXT chain; 66 char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; 67 char *server_auth[] = { oid_server_auth }; 68 DWORD err = ERROR_SUCCESS; 69 70 TRACE("verifying %s\n", debugstr_w( server )); 71 chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; 72 chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth; 73 ret = CertGetCertificateChain( NULL, cert, NULL, store, &chainPara, 74 check_revocation ? CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT : 0, 75 NULL, &chain ); 76 if (ret) 77 { 78 if (chain->TrustStatus.dwErrorStatus) 79 { 80 static const DWORD supportedErrors = 81 CERT_TRUST_IS_NOT_TIME_VALID | 82 CERT_TRUST_IS_UNTRUSTED_ROOT | 83 CERT_TRUST_IS_NOT_VALID_FOR_USAGE; 84 85 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) 86 { 87 if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)) 88 err = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID; 89 } 90 else if (chain->TrustStatus.dwErrorStatus & 91 CERT_TRUST_IS_UNTRUSTED_ROOT) 92 { 93 if (!(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) 94 err = ERROR_WINHTTP_SECURE_INVALID_CA; 95 } 96 else if ((chain->TrustStatus.dwErrorStatus & 97 CERT_TRUST_IS_OFFLINE_REVOCATION) || 98 (chain->TrustStatus.dwErrorStatus & 99 CERT_TRUST_REVOCATION_STATUS_UNKNOWN)) 100 err = ERROR_WINHTTP_SECURE_CERT_REV_FAILED; 101 else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) 102 err = ERROR_WINHTTP_SECURE_CERT_REVOKED; 103 else if (chain->TrustStatus.dwErrorStatus & 104 CERT_TRUST_IS_NOT_VALID_FOR_USAGE) 105 { 106 if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)) 107 err = ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE; 108 } 109 else if (chain->TrustStatus.dwErrorStatus & ~supportedErrors) 110 err = ERROR_WINHTTP_SECURE_INVALID_CERT; 111 } 112 if (!err) 113 { 114 CERT_CHAIN_POLICY_PARA policyPara; 115 SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; 116 CERT_CHAIN_POLICY_STATUS policyStatus; 117 CERT_CHAIN_CONTEXT chainCopy; 118 119 /* Clear chain->TrustStatus.dwErrorStatus so 120 * CertVerifyCertificateChainPolicy will verify additional checks 121 * rather than stopping with an existing, ignored error. 122 */ 123 memcpy(&chainCopy, chain, sizeof(chainCopy)); 124 chainCopy.TrustStatus.dwErrorStatus = 0; 125 sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); 126 sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; 127 sslExtraPolicyPara.pwszServerName = server; 128 sslExtraPolicyPara.fdwChecks = security_flags; 129 policyPara.cbSize = sizeof(policyPara); 130 policyPara.dwFlags = 0; 131 policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; 132 ret = CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, 133 &chainCopy, &policyPara, 134 &policyStatus ); 135 /* Any error in the policy status indicates that the 136 * policy couldn't be verified. 137 */ 138 if (ret && policyStatus.dwError) 139 { 140 if (policyStatus.dwError == CERT_E_CN_NO_MATCH) 141 err = ERROR_WINHTTP_SECURE_CERT_CN_INVALID; 142 else 143 err = ERROR_WINHTTP_SECURE_INVALID_CERT; 144 } 145 } 146 CertFreeCertificateChain( chain ); 147 } 148 else 149 err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; 150 TRACE("returning %08x\n", err); 151 return err; 152 } 153 154 static BOOL winsock_loaded; 155 156 void netconn_unload( void ) 157 { 158 if (winsock_loaded) WSACleanup(); 159 } 160 161 static BOOL WINAPI winsock_startup( INIT_ONCE *once, void *param, void **ctx ) 162 { 163 int ret; 164 WSADATA data; 165 if (!(ret = WSAStartup( MAKEWORD(1,1), &data ))) winsock_loaded = TRUE; 166 else ERR( "WSAStartup failed: %d\n", ret ); 167 return TRUE; 168 } 169 170 #ifdef __REACTOS__ 171 void winsock_init(void) 172 #else 173 static void winsock_init(void) 174 #endif 175 { 176 static INIT_ONCE once = INIT_ONCE_STATIC_INIT; 177 InitOnceExecuteOnce( &once, winsock_startup, NULL, NULL ); 178 } 179 180 static void set_blocking( struct netconn *conn, BOOL blocking ) 181 { 182 ULONG state = !blocking; 183 ioctlsocket( conn->socket, FIONBIO, &state ); 184 } 185 186 struct netconn *netconn_create( struct hostdata *host, const struct sockaddr_storage *sockaddr, int timeout ) 187 { 188 struct netconn *conn; 189 unsigned int addr_len; 190 BOOL ret = FALSE; 191 192 #ifndef __REACTOS__ 193 winsock_init(); 194 #endif 195 196 conn = heap_alloc_zero(sizeof(*conn)); 197 if (!conn) return NULL; 198 conn->host = host; 199 conn->sockaddr = *sockaddr; 200 if ((conn->socket = socket( sockaddr->ss_family, SOCK_STREAM, 0 )) == -1) 201 { 202 WARN("unable to create socket (%u)\n", WSAGetLastError()); 203 heap_free(conn); 204 return NULL; 205 } 206 207 switch (conn->sockaddr.ss_family) 208 { 209 case AF_INET: 210 addr_len = sizeof(struct sockaddr_in); 211 break; 212 case AF_INET6: 213 addr_len = sizeof(struct sockaddr_in6); 214 break; 215 default: 216 assert(0); 217 } 218 219 if (timeout > 0) set_blocking( conn, FALSE ); 220 221 if (!connect( conn->socket, (const struct sockaddr *)&conn->sockaddr, addr_len )) ret = TRUE; 222 else 223 { 224 DWORD err = WSAGetLastError(); 225 if (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS) 226 { 227 FD_SET set; 228 TIMEVAL timeval = { 0, timeout * 1000 }; 229 int res; 230 231 FD_ZERO( &set ); 232 FD_SET( conn->socket, &set ); 233 if ((res = select( conn->socket + 1, NULL, &set, NULL, &timeval )) > 0) ret = TRUE; 234 else if (!res) SetLastError( ERROR_WINHTTP_TIMEOUT ); 235 } 236 } 237 238 if (timeout > 0) set_blocking( conn, TRUE ); 239 240 if (!ret) 241 { 242 WARN("unable to connect to host (%u)\n", GetLastError()); 243 closesocket( conn->socket ); 244 heap_free( conn ); 245 return NULL; 246 } 247 return conn; 248 } 249 250 void netconn_close( struct netconn *conn ) 251 { 252 if (conn->secure) 253 { 254 heap_free( conn->peek_msg_mem ); 255 heap_free(conn->ssl_buf); 256 heap_free(conn->extra_buf); 257 DeleteSecurityContext(&conn->ssl_ctx); 258 } 259 closesocket( conn->socket ); 260 release_host( conn->host ); 261 heap_free(conn); 262 } 263 264 BOOL netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD security_flags, CredHandle *cred_handle, 265 BOOL check_revocation) 266 { 267 SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; 268 SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; 269 BYTE *read_buf; 270 SIZE_T read_buf_size = 2048; 271 ULONG attrs = 0; 272 CtxtHandle ctx; 273 SSIZE_T size; 274 const CERT_CONTEXT *cert; 275 SECURITY_STATUS status; 276 DWORD res = ERROR_SUCCESS; 277 278 const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY 279 |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION; 280 281 read_buf = heap_alloc(read_buf_size); 282 if(!read_buf) 283 return FALSE; 284 285 status = InitializeSecurityContextW(cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0, 286 &ctx, &out_desc, &attrs, NULL); 287 288 assert(status != SEC_E_OK); 289 290 while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) { 291 if(out_buf.cbBuffer) { 292 assert(status == SEC_I_CONTINUE_NEEDED); 293 294 TRACE("sending %u bytes\n", out_buf.cbBuffer); 295 296 size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0); 297 if(size != out_buf.cbBuffer) { 298 ERR("send failed\n"); 299 res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; 300 break; 301 } 302 303 FreeContextBuffer(out_buf.pvBuffer); 304 out_buf.pvBuffer = NULL; 305 out_buf.cbBuffer = 0; 306 } 307 308 if(status == SEC_I_CONTINUE_NEEDED) { 309 assert(in_bufs[1].cbBuffer < read_buf_size); 310 311 memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer); 312 in_bufs[0].cbBuffer = in_bufs[1].cbBuffer; 313 314 in_bufs[1].BufferType = SECBUFFER_EMPTY; 315 in_bufs[1].cbBuffer = 0; 316 in_bufs[1].pvBuffer = NULL; 317 } 318 319 assert(in_bufs[0].BufferType == SECBUFFER_TOKEN); 320 assert(in_bufs[1].BufferType == SECBUFFER_EMPTY); 321 322 if(in_bufs[0].cbBuffer + 1024 > read_buf_size) { 323 BYTE *new_read_buf; 324 325 new_read_buf = heap_realloc(read_buf, read_buf_size + 1024); 326 if(!new_read_buf) { 327 status = E_OUTOFMEMORY; 328 break; 329 } 330 331 in_bufs[0].pvBuffer = read_buf = new_read_buf; 332 read_buf_size += 1024; 333 } 334 335 size = sock_recv(conn->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0); 336 if(size < 1) { 337 status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; 338 break; 339 } 340 341 TRACE("recv %lu bytes\n", size); 342 343 in_bufs[0].cbBuffer += size; 344 in_bufs[0].pvBuffer = read_buf; 345 status = InitializeSecurityContextW(cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc, 346 0, NULL, &out_desc, &attrs, NULL); 347 TRACE("InitializeSecurityContext ret %08x\n", status); 348 349 if(status == SEC_E_OK) { 350 if(in_bufs[1].BufferType == SECBUFFER_EXTRA) 351 FIXME("SECBUFFER_EXTRA not supported\n"); 352 353 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes); 354 if(status != SEC_E_OK) { 355 WARN("Could not get sizes\n"); 356 break; 357 } 358 359 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); 360 if(status == SEC_E_OK) { 361 res = netconn_verify_cert(cert, hostname, security_flags, check_revocation); 362 CertFreeCertificateContext(cert); 363 if(res != ERROR_SUCCESS) { 364 WARN("cert verify failed: %u\n", res); 365 break; 366 } 367 }else { 368 WARN("Could not get cert\n"); 369 break; 370 } 371 372 conn->ssl_buf = heap_alloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); 373 if(!conn->ssl_buf) { 374 res = GetLastError(); 375 break; 376 } 377 } 378 } 379 380 heap_free(read_buf); 381 382 if(status != SEC_E_OK || res != ERROR_SUCCESS) { 383 WARN("Failed to initialize security context failed: %08x\n", status); 384 heap_free(conn->ssl_buf); 385 conn->ssl_buf = NULL; 386 DeleteSecurityContext(&ctx); 387 SetLastError(res ? res : ERROR_WINHTTP_SECURE_CHANNEL_ERROR); 388 return FALSE; 389 } 390 391 392 TRACE("established SSL connection\n"); 393 conn->secure = TRUE; 394 conn->ssl_ctx = ctx; 395 return TRUE; 396 } 397 398 static BOOL send_ssl_chunk(struct netconn *conn, const void *msg, size_t size) 399 { 400 SecBuffer bufs[4] = { 401 {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_buf}, 402 {size, SECBUFFER_DATA, conn->ssl_buf+conn->ssl_sizes.cbHeader}, 403 {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_buf+conn->ssl_sizes.cbHeader+size}, 404 {0, SECBUFFER_EMPTY, NULL} 405 }; 406 SecBufferDesc buf_desc = {SECBUFFER_VERSION, ARRAY_SIZE(bufs), bufs}; 407 SECURITY_STATUS res; 408 409 memcpy(bufs[1].pvBuffer, msg, size); 410 res = EncryptMessage(&conn->ssl_ctx, 0, &buf_desc, 0); 411 if(res != SEC_E_OK) { 412 WARN("EncryptMessage failed\n"); 413 return FALSE; 414 } 415 416 if(sock_send(conn->socket, conn->ssl_buf, bufs[0].cbBuffer+bufs[1].cbBuffer+bufs[2].cbBuffer, 0) < 1) { 417 WARN("send failed\n"); 418 return FALSE; 419 } 420 421 return TRUE; 422 } 423 424 BOOL netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent ) 425 { 426 if (conn->secure) 427 { 428 const BYTE *ptr = msg; 429 size_t chunk_size; 430 431 *sent = 0; 432 433 while(len) { 434 chunk_size = min(len, conn->ssl_sizes.cbMaximumMessage); 435 if(!send_ssl_chunk(conn, ptr, chunk_size)) 436 return FALSE; 437 438 *sent += chunk_size; 439 ptr += chunk_size; 440 len -= chunk_size; 441 } 442 443 return TRUE; 444 } 445 return ((*sent = sock_send( conn->socket, msg, len, 0 )) != -1); 446 } 447 448 static BOOL read_ssl_chunk(struct netconn *conn, void *buf, SIZE_T buf_size, SIZE_T *ret_size, BOOL *eof) 449 { 450 const SIZE_T ssl_buf_size = conn->ssl_sizes.cbHeader+conn->ssl_sizes.cbMaximumMessage+conn->ssl_sizes.cbTrailer; 451 SecBuffer bufs[4]; 452 SecBufferDesc buf_desc = {SECBUFFER_VERSION, ARRAY_SIZE(bufs), bufs}; 453 SSIZE_T size, buf_len; 454 unsigned int i; 455 SECURITY_STATUS res; 456 457 assert(conn->extra_len < ssl_buf_size); 458 459 if(conn->extra_len) { 460 memcpy(conn->ssl_buf, conn->extra_buf, conn->extra_len); 461 buf_len = conn->extra_len; 462 conn->extra_len = 0; 463 heap_free(conn->extra_buf); 464 conn->extra_buf = NULL; 465 }else { 466 buf_len = sock_recv(conn->socket, conn->ssl_buf+conn->extra_len, ssl_buf_size-conn->extra_len, 0); 467 if(buf_len < 0) 468 return FALSE; 469 470 if(!buf_len) { 471 *eof = TRUE; 472 return TRUE; 473 } 474 } 475 476 *ret_size = 0; 477 *eof = FALSE; 478 479 do { 480 memset(bufs, 0, sizeof(bufs)); 481 bufs[0].BufferType = SECBUFFER_DATA; 482 bufs[0].cbBuffer = buf_len; 483 bufs[0].pvBuffer = conn->ssl_buf; 484 485 res = DecryptMessage(&conn->ssl_ctx, &buf_desc, 0, NULL); 486 switch(res) { 487 case SEC_E_OK: 488 break; 489 case SEC_I_CONTEXT_EXPIRED: 490 TRACE("context expired\n"); 491 *eof = TRUE; 492 return TRUE; 493 case SEC_E_INCOMPLETE_MESSAGE: 494 assert(buf_len < ssl_buf_size); 495 496 size = sock_recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, 0); 497 if(size < 1) 498 return FALSE; 499 500 buf_len += size; 501 continue; 502 default: 503 WARN("failed: %08x\n", res); 504 return FALSE; 505 } 506 } while(res != SEC_E_OK); 507 508 for(i = 0; i < ARRAY_SIZE(bufs); i++) { 509 if(bufs[i].BufferType == SECBUFFER_DATA) { 510 size = min(buf_size, bufs[i].cbBuffer); 511 memcpy(buf, bufs[i].pvBuffer, size); 512 if(size < bufs[i].cbBuffer) { 513 assert(!conn->peek_len); 514 conn->peek_msg_mem = conn->peek_msg = heap_alloc(bufs[i].cbBuffer - size); 515 if(!conn->peek_msg) 516 return FALSE; 517 conn->peek_len = bufs[i].cbBuffer-size; 518 memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len); 519 } 520 521 *ret_size = size; 522 } 523 } 524 525 for(i = 0; i < ARRAY_SIZE(bufs); i++) { 526 if(bufs[i].BufferType == SECBUFFER_EXTRA) { 527 conn->extra_buf = heap_alloc(bufs[i].cbBuffer); 528 if(!conn->extra_buf) 529 return FALSE; 530 531 conn->extra_len = bufs[i].cbBuffer; 532 memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len); 533 } 534 } 535 536 return TRUE; 537 } 538 539 BOOL netconn_recv( struct netconn *conn, void *buf, size_t len, int flags, int *recvd ) 540 { 541 *recvd = 0; 542 if (!len) return TRUE; 543 544 if (conn->secure) 545 { 546 SIZE_T size, cread; 547 BOOL res, eof; 548 549 if (conn->peek_msg) 550 { 551 *recvd = min( len, conn->peek_len ); 552 memcpy( buf, conn->peek_msg, *recvd ); 553 conn->peek_len -= *recvd; 554 conn->peek_msg += *recvd; 555 556 if (conn->peek_len == 0) 557 { 558 heap_free( conn->peek_msg_mem ); 559 conn->peek_msg_mem = NULL; 560 conn->peek_msg = NULL; 561 } 562 /* check if we have enough data from the peek buffer */ 563 if (!(flags & MSG_WAITALL) || *recvd == len) return TRUE; 564 } 565 size = *recvd; 566 567 do { 568 res = read_ssl_chunk(conn, (BYTE*)buf+size, len-size, &cread, &eof); 569 if(!res) { 570 WARN("read_ssl_chunk failed\n"); 571 if(!size) 572 return FALSE; 573 break; 574 } 575 576 if(eof) { 577 TRACE("EOF\n"); 578 break; 579 } 580 581 size += cread; 582 }while(!size || ((flags & MSG_WAITALL) && size < len)); 583 584 TRACE("received %ld bytes\n", size); 585 *recvd = size; 586 return TRUE; 587 } 588 return ((*recvd = sock_recv( conn->socket, buf, len, flags )) != -1); 589 } 590 591 ULONG netconn_query_data_available( struct netconn *conn ) 592 { 593 return conn->secure ? conn->peek_len : 0; 594 } 595 596 DWORD netconn_set_timeout( struct netconn *netconn, BOOL send, int value ) 597 { 598 int opt = send ? SO_SNDTIMEO : SO_RCVTIMEO; 599 if (setsockopt( netconn->socket, SOL_SOCKET, opt, (void *)&value, sizeof(value) ) == -1) 600 { 601 DWORD err = WSAGetLastError(); 602 WARN("setsockopt failed (%u)\n", err ); 603 return err; 604 } 605 return ERROR_SUCCESS; 606 } 607 608 BOOL netconn_is_alive( struct netconn *netconn ) 609 { 610 int len; 611 char b; 612 DWORD err; 613 614 set_blocking( netconn, FALSE ); 615 len = sock_recv( netconn->socket, &b, 1, MSG_PEEK ); 616 err = WSAGetLastError(); 617 set_blocking( netconn, TRUE ); 618 619 return len == 1 || (len == -1 && err == WSAEWOULDBLOCK); 620 } 621 622 static DWORD resolve_hostname( const WCHAR *name, INTERNET_PORT port, struct sockaddr_storage *sa ) 623 { 624 ADDRINFOW *res, hints; 625 int ret; 626 627 memset( &hints, 0, sizeof(hints) ); 628 /* Prefer IPv4 to IPv6 addresses, since some web servers do not listen on 629 * their IPv6 addresses even though they have IPv6 addresses in the DNS. 630 */ 631 hints.ai_family = AF_INET; 632 633 ret = GetAddrInfoW( name, NULL, &hints, &res ); 634 if (ret != 0) 635 { 636 TRACE("failed to get IPv4 address of %s, retrying with IPv6\n", debugstr_w(name)); 637 hints.ai_family = AF_INET6; 638 ret = GetAddrInfoW( name, NULL, &hints, &res ); 639 if (ret != 0) 640 { 641 TRACE("failed to get address of %s\n", debugstr_w(name)); 642 return ERROR_WINHTTP_NAME_NOT_RESOLVED; 643 } 644 } 645 memcpy( sa, res->ai_addr, res->ai_addrlen ); 646 switch (res->ai_family) 647 { 648 case AF_INET: 649 ((struct sockaddr_in *)sa)->sin_port = htons( port ); 650 break; 651 case AF_INET6: 652 ((struct sockaddr_in6 *)sa)->sin6_port = htons( port ); 653 break; 654 } 655 656 FreeAddrInfoW( res ); 657 return ERROR_SUCCESS; 658 } 659 660 #ifdef __REACTOS__ 661 662 struct resolve_args 663 { 664 const WCHAR *hostname; 665 INTERNET_PORT port; 666 struct sockaddr_storage *sa; 667 }; 668 669 static DWORD CALLBACK resolve_proc( LPVOID arg ) 670 { 671 struct resolve_args *ra = arg; 672 return resolve_hostname( ra->hostname, ra->port, ra->sa ); 673 } 674 675 BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_storage *sa, int timeout ) 676 { 677 DWORD ret; 678 679 if (timeout) 680 { 681 DWORD status; 682 HANDLE thread; 683 struct resolve_args ra; 684 685 ra.hostname = hostname; 686 ra.port = port; 687 ra.sa = sa; 688 689 thread = CreateThread( NULL, 0, resolve_proc, &ra, 0, NULL ); 690 if (!thread) return FALSE; 691 692 status = WaitForSingleObject( thread, timeout ); 693 if (status == WAIT_OBJECT_0) GetExitCodeThread( thread, &ret ); 694 else ret = ERROR_WINHTTP_TIMEOUT; 695 CloseHandle( thread ); 696 } 697 else ret = resolve_hostname( hostname, port, sa ); 698 699 if (ret) 700 { 701 SetLastError( ret ); 702 return FALSE; 703 } 704 return TRUE; 705 } 706 707 #else /* __REACTOS__ */ 708 709 struct async_resolve 710 { 711 const WCHAR *hostname; 712 INTERNET_PORT port; 713 struct sockaddr_storage *addr; 714 DWORD result; 715 HANDLE done; 716 }; 717 718 static void CALLBACK resolve_proc( TP_CALLBACK_INSTANCE *instance, void *ctx ) 719 { 720 struct async_resolve *async = ctx; 721 async->result = resolve_hostname( async->hostname, async->port, async->addr ); 722 SetEvent( async->done ); 723 } 724 725 BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_storage *addr, int timeout ) 726 { 727 DWORD ret; 728 729 if (!timeout) ret = resolve_hostname( hostname, port, addr ); 730 else 731 { 732 struct async_resolve async; 733 734 async.hostname = hostname; 735 async.port = port; 736 async.addr = addr; 737 if (!(async.done = CreateEventW( NULL, FALSE, FALSE, NULL ))) return FALSE; 738 if (!TrySubmitThreadpoolCallback( resolve_proc, &async, NULL )) 739 { 740 CloseHandle( async.done ); 741 return FALSE; 742 } 743 if (WaitForSingleObject( async.done, timeout ) != WAIT_OBJECT_0) ret = ERROR_WINHTTP_TIMEOUT; 744 else ret = async.result; 745 CloseHandle( async.done ); 746 } 747 748 if (ret) 749 { 750 SetLastError( ret ); 751 return FALSE; 752 } 753 return TRUE; 754 } 755 756 #endif /* __REACTOS__ */ 757 758 const void *netconn_get_certificate( struct netconn *conn ) 759 { 760 const CERT_CONTEXT *ret; 761 SECURITY_STATUS res; 762 763 if (!conn->secure) return NULL; 764 res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&ret); 765 return res == SEC_E_OK ? ret : NULL; 766 } 767 768 int netconn_get_cipher_strength( struct netconn *conn ) 769 { 770 SecPkgContext_ConnectionInfo conn_info; 771 SECURITY_STATUS res; 772 773 if (!conn->secure) return 0; 774 res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_CONNECTION_INFO, (void*)&conn_info); 775 if(res != SEC_E_OK) 776 WARN("QueryContextAttributesW failed: %08x\n", res); 777 return res == SEC_E_OK ? conn_info.dwCipherStrength : 0; 778 } 779