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