5c4ace898ccaa5d134629f845808a613ffea700f
[reactos.git] / dll / win32 / winhttp / net.c
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 "winhttp_private.h"
21
22 #include <assert.h>
23 #include <schannel.h>
24
25 #ifdef HAVE_SYS_SOCKET_H
26 # include <sys/socket.h>
27 #endif
28 #ifdef HAVE_SYS_IOCTL_H
29 # include <sys/ioctl.h>
30 #endif
31 #ifdef HAVE_SYS_FILIO_H
32 # include <sys/filio.h>
33 #endif
34 #ifdef HAVE_POLL_H
35 # include <poll.h>
36 #endif
37
38 #ifndef HAVE_GETADDRINFO
39
40 /* critical section to protect non-reentrant gethostbyname() */
41 static CRITICAL_SECTION cs_gethostbyname;
42 static CRITICAL_SECTION_DEBUG critsect_debug =
43 {
44 0, 0, &cs_gethostbyname,
45 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
46 0, 0, { (DWORD_PTR)(__FILE__ ": cs_gethostbyname") }
47 };
48 static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 };
49
50 #endif
51
52 /* translate a unix error code into a winsock error code */
53 #ifndef __REACTOS__
54 static int sock_get_error( int err )
55 {
56 #if !defined(__MINGW32__) && !defined (_MSC_VER)
57 switch (err)
58 {
59 case EINTR: return WSAEINTR;
60 case EBADF: return WSAEBADF;
61 case EPERM:
62 case EACCES: return WSAEACCES;
63 case EFAULT: return WSAEFAULT;
64 case EINVAL: return WSAEINVAL;
65 case EMFILE: return WSAEMFILE;
66 case EWOULDBLOCK: return WSAEWOULDBLOCK;
67 case EINPROGRESS: return WSAEINPROGRESS;
68 case EALREADY: return WSAEALREADY;
69 case ENOTSOCK: return WSAENOTSOCK;
70 case EDESTADDRREQ: return WSAEDESTADDRREQ;
71 case EMSGSIZE: return WSAEMSGSIZE;
72 case EPROTOTYPE: return WSAEPROTOTYPE;
73 case ENOPROTOOPT: return WSAENOPROTOOPT;
74 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
75 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
76 case EOPNOTSUPP: return WSAEOPNOTSUPP;
77 case EPFNOSUPPORT: return WSAEPFNOSUPPORT;
78 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
79 case EADDRINUSE: return WSAEADDRINUSE;
80 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
81 case ENETDOWN: return WSAENETDOWN;
82 case ENETUNREACH: return WSAENETUNREACH;
83 case ENETRESET: return WSAENETRESET;
84 case ECONNABORTED: return WSAECONNABORTED;
85 case EPIPE:
86 case ECONNRESET: return WSAECONNRESET;
87 case ENOBUFS: return WSAENOBUFS;
88 case EISCONN: return WSAEISCONN;
89 case ENOTCONN: return WSAENOTCONN;
90 case ESHUTDOWN: return WSAESHUTDOWN;
91 case ETOOMANYREFS: return WSAETOOMANYREFS;
92 case ETIMEDOUT: return WSAETIMEDOUT;
93 case ECONNREFUSED: return WSAECONNREFUSED;
94 case ELOOP: return WSAELOOP;
95 case ENAMETOOLONG: return WSAENAMETOOLONG;
96 case EHOSTDOWN: return WSAEHOSTDOWN;
97 case EHOSTUNREACH: return WSAEHOSTUNREACH;
98 case ENOTEMPTY: return WSAENOTEMPTY;
99 #ifdef EPROCLIM
100 case EPROCLIM: return WSAEPROCLIM;
101 #endif
102 #ifdef EUSERS
103 case EUSERS: return WSAEUSERS;
104 #endif
105 #ifdef EDQUOT
106 case EDQUOT: return WSAEDQUOT;
107 #endif
108 #ifdef ESTALE
109 case ESTALE: return WSAESTALE;
110 #endif
111 #ifdef EREMOTE
112 case EREMOTE: return WSAEREMOTE;
113 #endif
114 default: errno = err; perror( "sock_set_error" ); return WSAEFAULT;
115 }
116 #endif
117 return err;
118 }
119 #else
120 #define sock_get_error(x) WSAGetLastError()
121
122 static inline int unix_ioctl(int filedes, long request, void *arg)
123 {
124 return ioctlsocket(filedes, request, arg);
125 }
126 #define ioctlsocket unix_ioctl
127 #endif
128
129 static int sock_send(int fd, const void *msg, size_t len, int flags)
130 {
131 int ret;
132 do
133 {
134 ret = send(fd, msg, len, flags);
135 }
136 while(ret == -1 && errno == EINTR);
137 return ret;
138 }
139
140 static int sock_recv(int fd, void *msg, size_t len, int flags)
141 {
142 int ret;
143 do
144 {
145 ret = recv(fd, msg, len, flags);
146 }
147 while(ret == -1 && errno == EINTR);
148 return ret;
149 }
150
151 static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, WCHAR *server, DWORD security_flags )
152 {
153 HCERTSTORE store = cert->hCertStore;
154 BOOL ret;
155 CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
156 PCCERT_CHAIN_CONTEXT chain;
157 char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH;
158 char *server_auth[] = { oid_server_auth };
159 DWORD err = ERROR_SUCCESS;
160
161 TRACE("verifying %s\n", debugstr_w( server ));
162 chainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
163 chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth;
164 if ((ret = CertGetCertificateChain( NULL, cert, NULL, store, &chainPara,
165 CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
166 NULL, &chain )))
167 {
168 if (chain->TrustStatus.dwErrorStatus)
169 {
170 static const DWORD supportedErrors =
171 CERT_TRUST_IS_NOT_TIME_VALID |
172 CERT_TRUST_IS_UNTRUSTED_ROOT |
173 CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
174
175 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
176 {
177 if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID))
178 err = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID;
179 }
180 else if (chain->TrustStatus.dwErrorStatus &
181 CERT_TRUST_IS_UNTRUSTED_ROOT)
182 {
183 if (!(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA))
184 err = ERROR_WINHTTP_SECURE_INVALID_CA;
185 }
186 else if ((chain->TrustStatus.dwErrorStatus &
187 CERT_TRUST_IS_OFFLINE_REVOCATION) ||
188 (chain->TrustStatus.dwErrorStatus &
189 CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
190 err = ERROR_WINHTTP_SECURE_CERT_REV_FAILED;
191 else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)
192 err = ERROR_WINHTTP_SECURE_CERT_REVOKED;
193 else if (chain->TrustStatus.dwErrorStatus &
194 CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
195 {
196 if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE))
197 err = ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE;
198 }
199 else if (chain->TrustStatus.dwErrorStatus & ~supportedErrors)
200 err = ERROR_WINHTTP_SECURE_INVALID_CERT;
201 }
202 if (!err)
203 {
204 CERT_CHAIN_POLICY_PARA policyPara;
205 SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara;
206 CERT_CHAIN_POLICY_STATUS policyStatus;
207 CERT_CHAIN_CONTEXT chainCopy;
208
209 /* Clear chain->TrustStatus.dwErrorStatus so
210 * CertVerifyCertificateChainPolicy will verify additional checks
211 * rather than stopping with an existing, ignored error.
212 */
213 memcpy(&chainCopy, chain, sizeof(chainCopy));
214 chainCopy.TrustStatus.dwErrorStatus = 0;
215 sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara);
216 sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER;
217 sslExtraPolicyPara.pwszServerName = server;
218 sslExtraPolicyPara.fdwChecks = security_flags;
219 policyPara.cbSize = sizeof(policyPara);
220 policyPara.dwFlags = 0;
221 policyPara.pvExtraPolicyPara = &sslExtraPolicyPara;
222 ret = CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL,
223 &chainCopy, &policyPara,
224 &policyStatus );
225 /* Any error in the policy status indicates that the
226 * policy couldn't be verified.
227 */
228 if (ret && policyStatus.dwError)
229 {
230 if (policyStatus.dwError == CERT_E_CN_NO_MATCH)
231 err = ERROR_WINHTTP_SECURE_CERT_CN_INVALID;
232 else
233 err = ERROR_WINHTTP_SECURE_INVALID_CERT;
234 }
235 }
236 CertFreeCertificateChain( chain );
237 }
238 else
239 err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
240 TRACE("returning %08x\n", err);
241 return err;
242 }
243
244 static SecHandle cred_handle;
245 static BOOL cred_handle_initialized;
246
247 static CRITICAL_SECTION init_sechandle_cs;
248 static CRITICAL_SECTION_DEBUG init_sechandle_cs_debug = {
249 0, 0, &init_sechandle_cs,
250 { &init_sechandle_cs_debug.ProcessLocksList,
251 &init_sechandle_cs_debug.ProcessLocksList },
252 0, 0, { (DWORD_PTR)(__FILE__ ": init_sechandle_cs") }
253 };
254 static CRITICAL_SECTION init_sechandle_cs = { &init_sechandle_cs_debug, -1, 0, 0, 0, 0 };
255
256 static BOOL ensure_cred_handle(void)
257 {
258 BOOL ret = TRUE;
259
260 EnterCriticalSection(&init_sechandle_cs);
261
262 if(!cred_handle_initialized) {
263 SECURITY_STATUS res;
264
265 res = AcquireCredentialsHandleW(NULL, (WCHAR*)UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, NULL,
266 NULL, NULL, &cred_handle, NULL);
267 if(res == SEC_E_OK) {
268 cred_handle_initialized = TRUE;
269 }else {
270 WARN("AcquireCredentialsHandleW failed: %u\n", res);
271 ret = FALSE;
272 }
273 }
274
275 LeaveCriticalSection(&init_sechandle_cs);
276 return ret;
277 }
278
279 #ifdef __REACTOS__
280 static BOOL winsock_initialized = FALSE;
281 BOOL netconn_init_winsock()
282 {
283 WSADATA wsaData;
284 int error;
285 if (!winsock_initialized)
286 {
287 error = WSAStartup(MAKEWORD(1, 1), &wsaData);
288 if (error)
289 {
290 ERR("WSAStartup failed: %d\n", error);
291 return FALSE;
292 }
293 else
294 winsock_initialized = TRUE;
295 }
296 return winsock_initialized;
297 }
298
299 #endif
300
301 void netconn_unload( void )
302 {
303 if(cred_handle_initialized)
304 FreeCredentialsHandle(&cred_handle);
305 DeleteCriticalSection(&init_sechandle_cs);
306 #ifndef HAVE_GETADDRINFO
307 DeleteCriticalSection(&cs_gethostbyname);
308 #endif
309 #ifdef __REACTOS__
310 if(winsock_initialized)
311 WSACleanup();
312 #endif
313 }
314
315 netconn_t *netconn_create( hostdata_t *host, const struct sockaddr_storage *sockaddr, int timeout )
316 {
317 netconn_t *conn;
318 unsigned int addr_len;
319 BOOL ret = FALSE;
320 int res;
321 ULONG state;
322
323 conn = heap_alloc_zero(sizeof(*conn));
324 if (!conn) return NULL;
325 conn->host = host;
326 conn->sockaddr = *sockaddr;
327 if ((conn->socket = socket( sockaddr->ss_family, SOCK_STREAM, 0 )) == -1)
328 {
329 WARN("unable to create socket (%s)\n", strerror(errno));
330 set_last_error( sock_get_error( errno ) );
331 heap_free(conn);
332 return NULL;
333 }
334
335 switch (conn->sockaddr.ss_family)
336 {
337 case AF_INET:
338 addr_len = sizeof(struct sockaddr_in);
339 break;
340 case AF_INET6:
341 addr_len = sizeof(struct sockaddr_in6);
342 break;
343 default:
344 assert(0);
345 }
346
347 if (timeout > 0)
348 {
349 state = 1;
350 ioctlsocket( conn->socket, FIONBIO, &state );
351 }
352
353 for (;;)
354 {
355 res = 0;
356 if (connect( conn->socket, (const struct sockaddr *)&conn->sockaddr, addr_len ) < 0)
357 {
358 res = sock_get_error( errno );
359 if (res == WSAEWOULDBLOCK || res == WSAEINPROGRESS)
360 {
361 #ifdef __REACTOS__
362 /* ReactOS: use select instead of poll */
363 fd_set outfd;
364 struct timeval tv;
365
366 FD_ZERO(&outfd);
367 FD_SET(conn->socket, &outfd);
368
369 tv.tv_sec = 0;
370 tv.tv_usec = timeout * 1000;
371 for (;;)
372 {
373 res = 0;
374
375 if (select( 0, NULL, &outfd, NULL, &tv ) > 0)
376 #else
377 struct pollfd pfd;
378
379 pfd.fd = conn->socket;
380 pfd.events = POLLOUT;
381 for (;;)
382 {
383 res = 0;
384 if (poll( &pfd, 1, timeout ) > 0)
385 #endif
386 {
387 ret = TRUE;
388 break;
389 }
390 else
391 {
392 res = sock_get_error( errno );
393 if (res != WSAEINTR) break;
394 }
395 }
396 }
397 if (res != WSAEINTR) break;
398 }
399 else
400 {
401 ret = TRUE;
402 break;
403 }
404 }
405 if (timeout > 0)
406 {
407 state = 0;
408 ioctlsocket( conn->socket, FIONBIO, &state );
409 }
410 if (!ret)
411 {
412 WARN("unable to connect to host (%d)\n", res);
413 set_last_error( res );
414 netconn_close( conn );
415 return NULL;
416 }
417 return conn;
418 }
419
420 BOOL netconn_close( netconn_t *conn )
421 {
422 int res;
423
424 if (conn->secure)
425 {
426 heap_free( conn->peek_msg_mem );
427 heap_free(conn->ssl_buf);
428 heap_free(conn->extra_buf);
429 DeleteSecurityContext(&conn->ssl_ctx);
430 }
431 res = closesocket( conn->socket );
432 release_host( conn->host );
433 heap_free(conn);
434 if (res == -1)
435 {
436 set_last_error( sock_get_error( errno ) );
437 return FALSE;
438 }
439 return TRUE;
440 }
441
442 BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname, DWORD security_flags )
443 {
444 SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}};
445 SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs};
446 BYTE *read_buf;
447 SIZE_T read_buf_size = 2048;
448 ULONG attrs = 0;
449 CtxtHandle ctx;
450 SSIZE_T size;
451 const CERT_CONTEXT *cert;
452 SECURITY_STATUS status;
453 DWORD res = ERROR_SUCCESS;
454
455 const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY
456 |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION;
457
458 if(!ensure_cred_handle())
459 return FALSE;
460
461 read_buf = heap_alloc(read_buf_size);
462 if(!read_buf)
463 return FALSE;
464
465 status = InitializeSecurityContextW(&cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0,
466 &ctx, &out_desc, &attrs, NULL);
467
468 assert(status != SEC_E_OK);
469
470 while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) {
471 if(out_buf.cbBuffer) {
472 assert(status == SEC_I_CONTINUE_NEEDED);
473
474 TRACE("sending %u bytes\n", out_buf.cbBuffer);
475
476 size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0);
477 if(size != out_buf.cbBuffer) {
478 ERR("send failed\n");
479 res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
480 break;
481 }
482
483 FreeContextBuffer(out_buf.pvBuffer);
484 out_buf.pvBuffer = NULL;
485 out_buf.cbBuffer = 0;
486 }
487
488 if(status == SEC_I_CONTINUE_NEEDED) {
489 assert(in_bufs[1].cbBuffer < read_buf_size);
490
491 memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer);
492 in_bufs[0].cbBuffer = in_bufs[1].cbBuffer;
493
494 in_bufs[1].BufferType = SECBUFFER_EMPTY;
495 in_bufs[1].cbBuffer = 0;
496 in_bufs[1].pvBuffer = NULL;
497 }
498
499 assert(in_bufs[0].BufferType == SECBUFFER_TOKEN);
500 assert(in_bufs[1].BufferType == SECBUFFER_EMPTY);
501
502 if(in_bufs[0].cbBuffer + 1024 > read_buf_size) {
503 BYTE *new_read_buf;
504
505 new_read_buf = heap_realloc(read_buf, read_buf_size + 1024);
506 if(!new_read_buf) {
507 status = E_OUTOFMEMORY;
508 break;
509 }
510
511 in_bufs[0].pvBuffer = read_buf = new_read_buf;
512 read_buf_size += 1024;
513 }
514
515 size = sock_recv(conn->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0);
516 if(size < 1) {
517 WARN("recv error\n");
518 status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
519 break;
520 }
521
522 TRACE("recv %lu bytes\n", size);
523
524 in_bufs[0].cbBuffer += size;
525 in_bufs[0].pvBuffer = read_buf;
526 status = InitializeSecurityContextW(&cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc,
527 0, NULL, &out_desc, &attrs, NULL);
528 TRACE("InitializeSecurityContext ret %08x\n", status);
529
530 if(status == SEC_E_OK) {
531 if(in_bufs[1].BufferType == SECBUFFER_EXTRA)
532 FIXME("SECBUFFER_EXTRA not supported\n");
533
534 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes);
535 if(status != SEC_E_OK) {
536 WARN("Could not get sizes\n");
537 break;
538 }
539
540 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert);
541 if(status == SEC_E_OK) {
542 res = netconn_verify_cert(cert, hostname, security_flags);
543 CertFreeCertificateContext(cert);
544 if(res != ERROR_SUCCESS) {
545 WARN("cert verify failed: %u\n", res);
546 break;
547 }
548 }else {
549 WARN("Could not get cert\n");
550 break;
551 }
552
553 conn->ssl_buf = heap_alloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer);
554 if(!conn->ssl_buf) {
555 res = GetLastError();
556 break;
557 }
558 }
559 }
560
561 heap_free(read_buf);
562
563 if(status != SEC_E_OK || res != ERROR_SUCCESS) {
564 WARN("Failed to initialize security context failed: %08x\n", status);
565 heap_free(conn->ssl_buf);
566 conn->ssl_buf = NULL;
567 DeleteSecurityContext(&ctx);
568 set_last_error(res ? res : ERROR_WINHTTP_SECURE_CHANNEL_ERROR);
569 return FALSE;
570 }
571
572
573 TRACE("established SSL connection\n");
574 conn->secure = TRUE;
575 conn->ssl_ctx = ctx;
576 return TRUE;
577 }
578
579 static BOOL send_ssl_chunk(netconn_t *conn, const void *msg, size_t size)
580 {
581 SecBuffer bufs[4] = {
582 {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_buf},
583 {size, SECBUFFER_DATA, conn->ssl_buf+conn->ssl_sizes.cbHeader},
584 {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_buf+conn->ssl_sizes.cbHeader+size},
585 {0, SECBUFFER_EMPTY, NULL}
586 };
587 SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs};
588 SECURITY_STATUS res;
589
590 memcpy(bufs[1].pvBuffer, msg, size);
591 res = EncryptMessage(&conn->ssl_ctx, 0, &buf_desc, 0);
592 if(res != SEC_E_OK) {
593 WARN("EncryptMessage failed\n");
594 return FALSE;
595 }
596
597 if(sock_send(conn->socket, conn->ssl_buf, bufs[0].cbBuffer+bufs[1].cbBuffer+bufs[2].cbBuffer, 0) < 1) {
598 WARN("send failed\n");
599 return FALSE;
600 }
601
602 return TRUE;
603 }
604
605 BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int *sent )
606 {
607 if (conn->secure)
608 {
609 const BYTE *ptr = msg;
610 size_t chunk_size;
611
612 *sent = 0;
613
614 while(len) {
615 chunk_size = min(len, conn->ssl_sizes.cbMaximumMessage);
616 if(!send_ssl_chunk(conn, ptr, chunk_size))
617 return FALSE;
618
619 *sent += chunk_size;
620 ptr += chunk_size;
621 len -= chunk_size;
622 }
623
624 return TRUE;
625 }
626 if ((*sent = sock_send( conn->socket, msg, len, 0 )) == -1)
627 {
628 set_last_error( sock_get_error( errno ) );
629 return FALSE;
630 }
631 return TRUE;
632 }
633
634 static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T *ret_size, BOOL *eof)
635 {
636 const SIZE_T ssl_buf_size = conn->ssl_sizes.cbHeader+conn->ssl_sizes.cbMaximumMessage+conn->ssl_sizes.cbTrailer;
637 SecBuffer bufs[4];
638 SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs};
639 SSIZE_T size, buf_len;
640 unsigned int i;
641 SECURITY_STATUS res;
642
643 assert(conn->extra_len < ssl_buf_size);
644
645 if(conn->extra_len) {
646 memcpy(conn->ssl_buf, conn->extra_buf, conn->extra_len);
647 buf_len = conn->extra_len;
648 conn->extra_len = 0;
649 heap_free(conn->extra_buf);
650 conn->extra_buf = NULL;
651 }else {
652 buf_len = sock_recv(conn->socket, conn->ssl_buf+conn->extra_len, ssl_buf_size-conn->extra_len, 0);
653 if(buf_len < 0) {
654 WARN("recv failed\n");
655 return FALSE;
656 }
657
658 if(!buf_len) {
659 *eof = TRUE;
660 return TRUE;
661 }
662 }
663
664 *ret_size = 0;
665 *eof = FALSE;
666
667 do {
668 memset(bufs, 0, sizeof(bufs));
669 bufs[0].BufferType = SECBUFFER_DATA;
670 bufs[0].cbBuffer = buf_len;
671 bufs[0].pvBuffer = conn->ssl_buf;
672
673 res = DecryptMessage(&conn->ssl_ctx, &buf_desc, 0, NULL);
674 switch(res) {
675 case SEC_E_OK:
676 break;
677 case SEC_I_CONTEXT_EXPIRED:
678 TRACE("context expired\n");
679 *eof = TRUE;
680 return TRUE;
681 case SEC_E_INCOMPLETE_MESSAGE:
682 assert(buf_len < ssl_buf_size);
683
684 size = sock_recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, 0);
685 if(size < 1)
686 return FALSE;
687
688 buf_len += size;
689 continue;
690 default:
691 WARN("failed: %08x\n", res);
692 return FALSE;
693 }
694 } while(res != SEC_E_OK);
695
696 for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) {
697 if(bufs[i].BufferType == SECBUFFER_DATA) {
698 size = min(buf_size, bufs[i].cbBuffer);
699 memcpy(buf, bufs[i].pvBuffer, size);
700 if(size < bufs[i].cbBuffer) {
701 assert(!conn->peek_len);
702 conn->peek_msg_mem = conn->peek_msg = heap_alloc(bufs[i].cbBuffer - size);
703 if(!conn->peek_msg)
704 return FALSE;
705 conn->peek_len = bufs[i].cbBuffer-size;
706 memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len);
707 }
708
709 *ret_size = size;
710 }
711 }
712
713 for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) {
714 if(bufs[i].BufferType == SECBUFFER_EXTRA) {
715 conn->extra_buf = heap_alloc(bufs[i].cbBuffer);
716 if(!conn->extra_buf)
717 return FALSE;
718
719 conn->extra_len = bufs[i].cbBuffer;
720 memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len);
721 }
722 }
723
724 return TRUE;
725 }
726
727 BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd )
728 {
729 *recvd = 0;
730 if (!len) return TRUE;
731
732 if (conn->secure)
733 {
734 SIZE_T size, cread;
735 BOOL res, eof;
736
737 if (conn->peek_msg)
738 {
739 *recvd = min( len, conn->peek_len );
740 memcpy( buf, conn->peek_msg, *recvd );
741 conn->peek_len -= *recvd;
742 conn->peek_msg += *recvd;
743
744 if (conn->peek_len == 0)
745 {
746 heap_free( conn->peek_msg_mem );
747 conn->peek_msg_mem = NULL;
748 conn->peek_msg = NULL;
749 }
750 /* check if we have enough data from the peek buffer */
751 if (!(flags & MSG_WAITALL) || *recvd == len) return TRUE;
752 }
753 size = *recvd;
754
755 do {
756 res = read_ssl_chunk(conn, (BYTE*)buf+size, len-size, &cread, &eof);
757 if(!res) {
758 WARN("read_ssl_chunk failed\n");
759 if(!size)
760 return FALSE;
761 break;
762 }
763
764 if(eof) {
765 TRACE("EOF\n");
766 break;
767 }
768
769 size += cread;
770 }while(!size || ((flags & MSG_WAITALL) && size < len));
771
772 TRACE("received %ld bytes\n", size);
773 *recvd = size;
774 return TRUE;
775 }
776 if ((*recvd = sock_recv( conn->socket, buf, len, flags )) == -1)
777 {
778 set_last_error( sock_get_error( errno ) );
779 return FALSE;
780 }
781 return TRUE;
782 }
783
784 ULONG netconn_query_data_available( netconn_t *conn )
785 {
786 return conn->secure ? conn->peek_len : 0;
787 }
788
789 DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value )
790 {
791 struct timeval tv;
792
793 /* value is in milliseconds, convert to struct timeval */
794 tv.tv_sec = value / 1000;
795 tv.tv_usec = (value % 1000) * 1000;
796
797 if (setsockopt( netconn->socket, SOL_SOCKET, send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv, sizeof(tv) ) == -1)
798 {
799 WARN("setsockopt failed (%s)\n", strerror( errno ));
800 return sock_get_error( errno );
801 }
802 return ERROR_SUCCESS;
803 }
804
805 BOOL netconn_is_alive( netconn_t *netconn )
806 {
807 #ifdef MSG_DONTWAIT
808 ssize_t len;
809 BYTE b;
810
811 len = recv( netconn->socket, &b, 1, MSG_PEEK | MSG_DONTWAIT );
812 return len == 1 || (len == -1 && errno == EWOULDBLOCK);
813 #elif defined(__MINGW32__) || defined(_MSC_VER)
814 ULONG mode;
815 int len;
816 char b;
817
818 mode = 1;
819 if(!ioctlsocket(netconn->socket, FIONBIO, &mode))
820 return FALSE;
821
822 len = recv(netconn->socket, &b, 1, MSG_PEEK);
823
824 mode = 0;
825 if(!ioctlsocket(netconn->socket, FIONBIO, &mode))
826 return FALSE;
827
828 return len == 1 || (len == -1 && WSAGetLastError() == WSAEWOULDBLOCK);
829 #else
830 FIXME("not supported on this platform\n");
831 return TRUE;
832 #endif
833 }
834
835 static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr_storage *sa )
836 {
837 char *hostname;
838 #ifdef HAVE_GETADDRINFO
839 struct addrinfo *res, hints;
840 int ret;
841 #else
842 struct hostent *he;
843 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
844 #endif
845
846 if (!(hostname = strdupWA( hostnameW ))) return ERROR_OUTOFMEMORY;
847
848 #ifdef HAVE_GETADDRINFO
849 memset( &hints, 0, sizeof(struct addrinfo) );
850 /* Prefer IPv4 to IPv6 addresses, since some web servers do not listen on
851 * their IPv6 addresses even though they have IPv6 addresses in the DNS.
852 */
853 hints.ai_family = AF_INET;
854
855 ret = getaddrinfo( hostname, NULL, &hints, &res );
856 if (ret != 0)
857 {
858 TRACE("failed to get IPv4 address of %s (%s), retrying with IPv6\n", debugstr_w(hostnameW), gai_strerror(ret));
859 hints.ai_family = AF_INET6;
860 ret = getaddrinfo( hostname, NULL, &hints, &res );
861 if (ret != 0)
862 {
863 TRACE("failed to get address of %s (%s)\n", debugstr_w(hostnameW), gai_strerror(ret));
864 heap_free( hostname );
865 return ERROR_WINHTTP_NAME_NOT_RESOLVED;
866 }
867 }
868 heap_free( hostname );
869 memcpy( sa, res->ai_addr, res->ai_addrlen );
870 /* Copy port */
871 switch (res->ai_family)
872 {
873 case AF_INET:
874 ((struct sockaddr_in *)sa)->sin_port = htons( port );
875 break;
876 case AF_INET6:
877 ((struct sockaddr_in6 *)sa)->sin6_port = htons( port );
878 break;
879 }
880
881 freeaddrinfo( res );
882 return ERROR_SUCCESS;
883 #else
884 EnterCriticalSection( &cs_gethostbyname );
885
886 he = gethostbyname( hostname );
887 heap_free( hostname );
888 if (!he)
889 {
890 TRACE("failed to get address of %s (%d)\n", debugstr_w(hostnameW), h_errno);
891 LeaveCriticalSection( &cs_gethostbyname );
892 return ERROR_WINHTTP_NAME_NOT_RESOLVED;
893 }
894 memset( sa, 0, sizeof(struct sockaddr_in) );
895 memcpy( &sin->sin_addr, he->h_addr, he->h_length );
896 sin->sin_family = he->h_addrtype;
897 sin->sin_port = htons( port );
898
899 LeaveCriticalSection( &cs_gethostbyname );
900 return ERROR_SUCCESS;
901 #endif
902 }
903
904 struct resolve_args
905 {
906 const WCHAR *hostname;
907 INTERNET_PORT port;
908 struct sockaddr_storage *sa;
909 };
910
911 static DWORD CALLBACK resolve_proc( LPVOID arg )
912 {
913 struct resolve_args *ra = arg;
914 return resolve_hostname( ra->hostname, ra->port, ra->sa );
915 }
916
917 BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_storage *sa, int timeout )
918 {
919 DWORD ret;
920
921 if (timeout)
922 {
923 DWORD status;
924 HANDLE thread;
925 struct resolve_args ra;
926
927 ra.hostname = hostname;
928 ra.port = port;
929 ra.sa = sa;
930
931 thread = CreateThread( NULL, 0, resolve_proc, &ra, 0, NULL );
932 if (!thread) return FALSE;
933
934 status = WaitForSingleObject( thread, timeout );
935 if (status == WAIT_OBJECT_0) GetExitCodeThread( thread, &ret );
936 else ret = ERROR_WINHTTP_TIMEOUT;
937 CloseHandle( thread );
938 }
939 else ret = resolve_hostname( hostname, port, sa );
940
941 if (ret)
942 {
943 set_last_error( ret );
944 return FALSE;
945 }
946 return TRUE;
947 }
948
949 const void *netconn_get_certificate( netconn_t *conn )
950 {
951 const CERT_CONTEXT *ret;
952 SECURITY_STATUS res;
953
954 if (!conn->secure) return NULL;
955 res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&ret);
956 return res == SEC_E_OK ? ret : NULL;
957 }
958
959 int netconn_get_cipher_strength( netconn_t *conn )
960 {
961 SecPkgContext_ConnectionInfo conn_info;
962 SECURITY_STATUS res;
963
964 if (!conn->secure) return 0;
965 res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_CONNECTION_INFO, (void*)&conn_info);
966 if(res != SEC_E_OK)
967 WARN("QueryContextAttributesW failed: %08x\n", res);
968 return res == SEC_E_OK ? conn_info.dwCipherStrength : 0;
969 }