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