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