[WINHTTP] Sync with Wine Staging 2.2. CORE-12823
[reactos.git] / reactos / 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 BOOL netconn_init( netconn_t *conn )
302 {
303 memset(conn, 0, sizeof(*conn));
304 conn->socket = -1;
305 return TRUE;
306 }
307
308 void netconn_unload( void )
309 {
310 if(cred_handle_initialized)
311 FreeCredentialsHandle(&cred_handle);
312 DeleteCriticalSection(&init_sechandle_cs);
313 #ifndef HAVE_GETADDRINFO
314 DeleteCriticalSection(&cs_gethostbyname);
315 #endif
316 #ifdef __REACTOS__
317 if(winsock_initialized)
318 WSACleanup();
319 #endif
320 }
321
322 BOOL netconn_connected( netconn_t *conn )
323 {
324 return (conn->socket != -1);
325 }
326
327 BOOL netconn_create( netconn_t *conn, int domain, int type, int protocol )
328 {
329 if ((conn->socket = socket( domain, type, protocol )) == -1)
330 {
331 WARN("unable to create socket (%s)\n", strerror(errno));
332 set_last_error( sock_get_error( errno ) );
333 return FALSE;
334 }
335 return TRUE;
336 }
337
338 BOOL netconn_close( netconn_t *conn )
339 {
340 int res;
341
342 if (conn->secure)
343 {
344 heap_free( conn->peek_msg_mem );
345 conn->peek_msg_mem = NULL;
346 conn->peek_msg = NULL;
347 conn->peek_len = 0;
348 heap_free(conn->ssl_buf);
349 conn->ssl_buf = NULL;
350 heap_free(conn->extra_buf);
351 conn->extra_buf = NULL;
352 conn->extra_len = 0;
353 DeleteSecurityContext(&conn->ssl_ctx);
354 conn->secure = FALSE;
355 }
356 res = closesocket( conn->socket );
357 conn->socket = -1;
358 if (res == -1)
359 {
360 set_last_error( sock_get_error( errno ) );
361 return FALSE;
362 }
363 return TRUE;
364 }
365
366 BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned int addr_len, int timeout )
367 {
368 BOOL ret = FALSE;
369 int res;
370 ULONG state;
371
372 if (timeout > 0)
373 {
374 state = 1;
375 ioctlsocket( conn->socket, FIONBIO, &state );
376 }
377
378 for (;;)
379 {
380 res = 0;
381 if (connect( conn->socket, sockaddr, addr_len ) < 0)
382 {
383 res = sock_get_error( errno );
384 if (res == WSAEWOULDBLOCK || res == WSAEINPROGRESS)
385 {
386 #ifdef __REACTOS__
387 /* ReactOS: use select instead of poll */
388 fd_set outfd;
389 struct timeval tv;
390
391 FD_ZERO(&outfd);
392 FD_SET(conn->socket, &outfd);
393
394 tv.tv_sec = 0;
395 tv.tv_usec = timeout * 1000;
396 for (;;)
397 {
398 res = 0;
399
400 if (select( 0, NULL, &outfd, NULL, &tv ) > 0)
401 #else
402 struct pollfd pfd;
403
404 pfd.fd = conn->socket;
405 pfd.events = POLLOUT;
406 for (;;)
407 {
408 res = 0;
409 if (poll( &pfd, 1, timeout ) > 0)
410 #endif
411 {
412 ret = TRUE;
413 break;
414 }
415 else
416 {
417 res = sock_get_error( errno );
418 if (res != WSAEINTR) break;
419 }
420 }
421 }
422 if (res != WSAEINTR) break;
423 }
424 else
425 {
426 ret = TRUE;
427 break;
428 }
429 }
430 if (timeout > 0)
431 {
432 state = 0;
433 ioctlsocket( conn->socket, FIONBIO, &state );
434 }
435 if (!ret)
436 {
437 WARN("unable to connect to host (%d)\n", res);
438 set_last_error( res );
439 }
440 return ret;
441 }
442
443 BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname )
444 {
445 SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}};
446 SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs};
447 BYTE *read_buf;
448 SIZE_T read_buf_size = 2048;
449 ULONG attrs = 0;
450 CtxtHandle ctx;
451 SSIZE_T size;
452 const CERT_CONTEXT *cert;
453 SECURITY_STATUS status;
454 DWORD res = ERROR_SUCCESS;
455
456 const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY
457 |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION;
458
459 if(!ensure_cred_handle())
460 return FALSE;
461
462 read_buf = heap_alloc(read_buf_size);
463 if(!read_buf)
464 return FALSE;
465
466 status = InitializeSecurityContextW(&cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0,
467 &ctx, &out_desc, &attrs, NULL);
468
469 assert(status != SEC_E_OK);
470
471 while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) {
472 if(out_buf.cbBuffer) {
473 assert(status == SEC_I_CONTINUE_NEEDED);
474
475 TRACE("sending %u bytes\n", out_buf.cbBuffer);
476
477 size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0);
478 if(size != out_buf.cbBuffer) {
479 ERR("send failed\n");
480 res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
481 break;
482 }
483
484 FreeContextBuffer(out_buf.pvBuffer);
485 out_buf.pvBuffer = NULL;
486 out_buf.cbBuffer = 0;
487 }
488
489 if(status == SEC_I_CONTINUE_NEEDED) {
490 assert(in_bufs[1].cbBuffer < read_buf_size);
491
492 memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer);
493 in_bufs[0].cbBuffer = in_bufs[1].cbBuffer;
494
495 in_bufs[1].BufferType = SECBUFFER_EMPTY;
496 in_bufs[1].cbBuffer = 0;
497 in_bufs[1].pvBuffer = NULL;
498 }
499
500 assert(in_bufs[0].BufferType == SECBUFFER_TOKEN);
501 assert(in_bufs[1].BufferType == SECBUFFER_EMPTY);
502
503 if(in_bufs[0].cbBuffer + 1024 > read_buf_size) {
504 BYTE *new_read_buf;
505
506 new_read_buf = heap_realloc(read_buf, read_buf_size + 1024);
507 if(!new_read_buf) {
508 status = E_OUTOFMEMORY;
509 break;
510 }
511
512 in_bufs[0].pvBuffer = read_buf = new_read_buf;
513 read_buf_size += 1024;
514 }
515
516 size = sock_recv(conn->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0);
517 if(size < 1) {
518 WARN("recv error\n");
519 status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
520 break;
521 }
522
523 TRACE("recv %lu bytes\n", size);
524
525 in_bufs[0].cbBuffer += size;
526 in_bufs[0].pvBuffer = read_buf;
527 status = InitializeSecurityContextW(&cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc,
528 0, NULL, &out_desc, &attrs, NULL);
529 TRACE("InitializeSecurityContext ret %08x\n", status);
530
531 if(status == SEC_E_OK) {
532 if(in_bufs[1].BufferType == SECBUFFER_EXTRA)
533 FIXME("SECBUFFER_EXTRA not supported\n");
534
535 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes);
536 if(status != SEC_E_OK) {
537 WARN("Could not get sizes\n");
538 break;
539 }
540
541 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert);
542 if(status == SEC_E_OK) {
543 res = netconn_verify_cert(cert, hostname, conn->security_flags);
544 CertFreeCertificateContext(cert);
545 if(res != ERROR_SUCCESS) {
546 WARN("cert verify failed: %u\n", res);
547 break;
548 }
549 }else {
550 WARN("Could not get cert\n");
551 break;
552 }
553
554 conn->ssl_buf = heap_alloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer);
555 if(!conn->ssl_buf) {
556 res = GetLastError();
557 break;
558 }
559 }
560 }
561
562 heap_free(read_buf);
563
564 if(status != SEC_E_OK || res != ERROR_SUCCESS) {
565 WARN("Failed to initialize security context failed: %08x\n", status);
566 heap_free(conn->ssl_buf);
567 conn->ssl_buf = NULL;
568 DeleteSecurityContext(&ctx);
569 set_last_error(res ? res : ERROR_WINHTTP_SECURE_CHANNEL_ERROR);
570 return FALSE;
571 }
572
573
574 TRACE("established SSL connection\n");
575 conn->secure = TRUE;
576 conn->ssl_ctx = ctx;
577 return TRUE;
578 }
579
580 static BOOL send_ssl_chunk(netconn_t *conn, const void *msg, size_t size)
581 {
582 SecBuffer bufs[4] = {
583 {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_buf},
584 {size, SECBUFFER_DATA, conn->ssl_buf+conn->ssl_sizes.cbHeader},
585 {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_buf+conn->ssl_sizes.cbHeader+size},
586 {0, SECBUFFER_EMPTY, NULL}
587 };
588 SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs};
589 SECURITY_STATUS res;
590
591 memcpy(bufs[1].pvBuffer, msg, size);
592 res = EncryptMessage(&conn->ssl_ctx, 0, &buf_desc, 0);
593 if(res != SEC_E_OK) {
594 WARN("EncryptMessage failed\n");
595 return FALSE;
596 }
597
598 if(sock_send(conn->socket, conn->ssl_buf, bufs[0].cbBuffer+bufs[1].cbBuffer+bufs[2].cbBuffer, 0) < 1) {
599 WARN("send failed\n");
600 return FALSE;
601 }
602
603 return TRUE;
604 }
605
606 BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int *sent )
607 {
608 if (!netconn_connected( conn )) return FALSE;
609 if (conn->secure)
610 {
611 const BYTE *ptr = msg;
612 size_t chunk_size;
613
614 *sent = 0;
615
616 while(len) {
617 chunk_size = min(len, conn->ssl_sizes.cbMaximumMessage);
618 if(!send_ssl_chunk(conn, ptr, chunk_size))
619 return FALSE;
620
621 *sent += chunk_size;
622 ptr += chunk_size;
623 len -= chunk_size;
624 }
625
626 return TRUE;
627 }
628 if ((*sent = sock_send( conn->socket, msg, len, 0 )) == -1)
629 {
630 set_last_error( sock_get_error( errno ) );
631 return FALSE;
632 }
633 return TRUE;
634 }
635
636 static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T *ret_size, BOOL *eof)
637 {
638 const SIZE_T ssl_buf_size = conn->ssl_sizes.cbHeader+conn->ssl_sizes.cbMaximumMessage+conn->ssl_sizes.cbTrailer;
639 SecBuffer bufs[4];
640 SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs};
641 SSIZE_T size, buf_len;
642 unsigned int i;
643 SECURITY_STATUS res;
644
645 assert(conn->extra_len < ssl_buf_size);
646
647 if(conn->extra_len) {
648 memcpy(conn->ssl_buf, conn->extra_buf, conn->extra_len);
649 buf_len = conn->extra_len;
650 conn->extra_len = 0;
651 heap_free(conn->extra_buf);
652 conn->extra_buf = NULL;
653 }else {
654 buf_len = sock_recv(conn->socket, conn->ssl_buf+conn->extra_len, ssl_buf_size-conn->extra_len, 0);
655 if(buf_len < 0) {
656 WARN("recv failed\n");
657 return FALSE;
658 }
659
660 if(!buf_len) {
661 *eof = TRUE;
662 return TRUE;
663 }
664 }
665
666 *ret_size = 0;
667 *eof = FALSE;
668
669 do {
670 memset(bufs, 0, sizeof(bufs));
671 bufs[0].BufferType = SECBUFFER_DATA;
672 bufs[0].cbBuffer = buf_len;
673 bufs[0].pvBuffer = conn->ssl_buf;
674
675 res = DecryptMessage(&conn->ssl_ctx, &buf_desc, 0, NULL);
676 switch(res) {
677 case SEC_E_OK:
678 break;
679 case SEC_I_CONTEXT_EXPIRED:
680 TRACE("context expired\n");
681 *eof = TRUE;
682 return TRUE;
683 case SEC_E_INCOMPLETE_MESSAGE:
684 assert(buf_len < ssl_buf_size);
685
686 size = sock_recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, 0);
687 if(size < 1)
688 return FALSE;
689
690 buf_len += size;
691 continue;
692 default:
693 WARN("failed: %08x\n", res);
694 return FALSE;
695 }
696 } while(res != SEC_E_OK);
697
698 for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) {
699 if(bufs[i].BufferType == SECBUFFER_DATA) {
700 size = min(buf_size, bufs[i].cbBuffer);
701 memcpy(buf, bufs[i].pvBuffer, size);
702 if(size < bufs[i].cbBuffer) {
703 assert(!conn->peek_len);
704 conn->peek_msg_mem = conn->peek_msg = heap_alloc(bufs[i].cbBuffer - size);
705 if(!conn->peek_msg)
706 return FALSE;
707 conn->peek_len = bufs[i].cbBuffer-size;
708 memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len);
709 }
710
711 *ret_size = size;
712 }
713 }
714
715 for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) {
716 if(bufs[i].BufferType == SECBUFFER_EXTRA) {
717 conn->extra_buf = heap_alloc(bufs[i].cbBuffer);
718 if(!conn->extra_buf)
719 return FALSE;
720
721 conn->extra_len = bufs[i].cbBuffer;
722 memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len);
723 }
724 }
725
726 return TRUE;
727 }
728
729 BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd )
730 {
731 *recvd = 0;
732 if (!netconn_connected( conn )) return FALSE;
733 if (!len) return TRUE;
734
735 if (conn->secure)
736 {
737 SIZE_T size, cread;
738 BOOL res, eof;
739
740 if (conn->peek_msg)
741 {
742 *recvd = min( len, conn->peek_len );
743 memcpy( buf, conn->peek_msg, *recvd );
744 conn->peek_len -= *recvd;
745 conn->peek_msg += *recvd;
746
747 if (conn->peek_len == 0)
748 {
749 heap_free( conn->peek_msg_mem );
750 conn->peek_msg_mem = NULL;
751 conn->peek_msg = NULL;
752 }
753 /* check if we have enough data from the peek buffer */
754 if (!(flags & MSG_WAITALL) || *recvd == len) return TRUE;
755 }
756 size = *recvd;
757
758 do {
759 res = read_ssl_chunk(conn, (BYTE*)buf+size, len-size, &cread, &eof);
760 if(!res) {
761 WARN("read_ssl_chunk failed\n");
762 if(!size)
763 return FALSE;
764 break;
765 }
766
767 if(eof) {
768 TRACE("EOF\n");
769 break;
770 }
771
772 size += cread;
773 }while(!size || ((flags & MSG_WAITALL) && size < len));
774
775 TRACE("received %ld bytes\n", size);
776 *recvd = size;
777 return TRUE;
778 }
779 if ((*recvd = sock_recv( conn->socket, buf, len, flags )) == -1)
780 {
781 set_last_error( sock_get_error( errno ) );
782 return FALSE;
783 }
784 return TRUE;
785 }
786
787 ULONG netconn_query_data_available( netconn_t *conn )
788 {
789 if(!netconn_connected(conn))
790 return 0;
791
792 if(conn->secure)
793 return conn->peek_len;
794
795 return 0;
796 }
797
798 DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value )
799 {
800 struct timeval tv;
801
802 /* value is in milliseconds, convert to struct timeval */
803 tv.tv_sec = value / 1000;
804 tv.tv_usec = (value % 1000) * 1000;
805
806 if (setsockopt( netconn->socket, SOL_SOCKET, send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv, sizeof(tv) ) == -1)
807 {
808 WARN("setsockopt failed (%s)\n", strerror( errno ));
809 return sock_get_error( errno );
810 }
811 return ERROR_SUCCESS;
812 }
813
814 static DWORD resolve_hostname( const WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len )
815 {
816 char *hostname;
817 #ifdef HAVE_GETADDRINFO
818 struct addrinfo *res, hints;
819 int ret;
820 #else
821 struct hostent *he;
822 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
823 #endif
824
825 if (!(hostname = strdupWA( hostnameW ))) return ERROR_OUTOFMEMORY;
826
827 #ifdef HAVE_GETADDRINFO
828 memset( &hints, 0, sizeof(struct addrinfo) );
829 /* Prefer IPv4 to IPv6 addresses, since some web servers do not listen on
830 * their IPv6 addresses even though they have IPv6 addresses in the DNS.
831 */
832 hints.ai_family = AF_INET;
833
834 ret = getaddrinfo( hostname, NULL, &hints, &res );
835 if (ret != 0)
836 {
837 TRACE("failed to get IPv4 address of %s (%s), retrying with IPv6\n", debugstr_w(hostnameW), gai_strerror(ret));
838 hints.ai_family = AF_INET6;
839 ret = getaddrinfo( hostname, NULL, &hints, &res );
840 if (ret != 0)
841 {
842 TRACE("failed to get address of %s (%s)\n", debugstr_w(hostnameW), gai_strerror(ret));
843 heap_free( hostname );
844 return ERROR_WINHTTP_NAME_NOT_RESOLVED;
845 }
846 }
847 heap_free( hostname );
848 if (*sa_len < res->ai_addrlen)
849 {
850 WARN("address too small\n");
851 freeaddrinfo( res );
852 return ERROR_WINHTTP_NAME_NOT_RESOLVED;
853 }
854 *sa_len = res->ai_addrlen;
855 memcpy( sa, res->ai_addr, res->ai_addrlen );
856 /* Copy port */
857 switch (res->ai_family)
858 {
859 case AF_INET:
860 ((struct sockaddr_in *)sa)->sin_port = htons( port );
861 break;
862 case AF_INET6:
863 ((struct sockaddr_in6 *)sa)->sin6_port = htons( port );
864 break;
865 }
866
867 freeaddrinfo( res );
868 return ERROR_SUCCESS;
869 #else
870 EnterCriticalSection( &cs_gethostbyname );
871
872 he = gethostbyname( hostname );
873 heap_free( hostname );
874 if (!he)
875 {
876 TRACE("failed to get address of %s (%d)\n", debugstr_w(hostnameW), h_errno);
877 LeaveCriticalSection( &cs_gethostbyname );
878 return ERROR_WINHTTP_NAME_NOT_RESOLVED;
879 }
880 if (*sa_len < sizeof(struct sockaddr_in))
881 {
882 WARN("address too small\n");
883 LeaveCriticalSection( &cs_gethostbyname );
884 return ERROR_WINHTTP_NAME_NOT_RESOLVED;
885 }
886 *sa_len = sizeof(struct sockaddr_in);
887 memset( sa, 0, sizeof(struct sockaddr_in) );
888 memcpy( &sin->sin_addr, he->h_addr, he->h_length );
889 sin->sin_family = he->h_addrtype;
890 sin->sin_port = htons( port );
891
892 LeaveCriticalSection( &cs_gethostbyname );
893 return ERROR_SUCCESS;
894 #endif
895 }
896
897 struct resolve_args
898 {
899 const WCHAR *hostname;
900 INTERNET_PORT port;
901 struct sockaddr *sa;
902 socklen_t *sa_len;
903 };
904
905 static DWORD CALLBACK resolve_proc( LPVOID arg )
906 {
907 struct resolve_args *ra = arg;
908 return resolve_hostname( ra->hostname, ra->port, ra->sa, ra->sa_len );
909 }
910
911 BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len, int timeout )
912 {
913 DWORD ret;
914
915 if (timeout)
916 {
917 DWORD status;
918 HANDLE thread;
919 struct resolve_args ra;
920
921 ra.hostname = hostname;
922 ra.port = port;
923 ra.sa = sa;
924 ra.sa_len = sa_len;
925
926 thread = CreateThread( NULL, 0, resolve_proc, &ra, 0, NULL );
927 if (!thread) return FALSE;
928
929 status = WaitForSingleObject( thread, timeout );
930 if (status == WAIT_OBJECT_0) GetExitCodeThread( thread, &ret );
931 else ret = ERROR_WINHTTP_TIMEOUT;
932 CloseHandle( thread );
933 }
934 else ret = resolve_hostname( hostname, port, sa, sa_len );
935
936 if (ret)
937 {
938 set_last_error( ret );
939 return FALSE;
940 }
941 return TRUE;
942 }
943
944 const void *netconn_get_certificate( netconn_t *conn )
945 {
946 const CERT_CONTEXT *ret;
947 SECURITY_STATUS res;
948
949 if (!conn->secure) return NULL;
950 res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&ret);
951 return res == SEC_E_OK ? ret : NULL;
952 }
953
954 int netconn_get_cipher_strength( netconn_t *conn )
955 {
956 SecPkgContext_ConnectionInfo conn_info;
957 SECURITY_STATUS res;
958
959 if (!conn->secure) return 0;
960 res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_CONNECTION_INFO, (void*)&conn_info);
961 if(res != SEC_E_OK)
962 WARN("QueryContextAttributesW failed: %08x\n", res);
963 return res == SEC_E_OK ? conn_info.dwCipherStrength : 0;
964 }