usp10: Handle Ligature Substitution Subtable from GSUB.
[wine] / dlls / wininet / netconnection.c
1 /*
2  * Wininet - networking layer. Uses unix sockets or OpenSSL.
3  *
4  * Copyright 2002 TransGaming Technologies Inc.
5  *
6  * David Hammerton
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #define NONAMELESSUNION
27
28 #if defined(__MINGW32__) || defined (_MSC_VER)
29 #include <ws2tcpip.h>
30 #endif
31
32 #include <sys/types.h>
33 #ifdef HAVE_POLL_H
34 #include <poll.h>
35 #endif
36 #ifdef HAVE_SYS_POLL_H
37 # include <sys/poll.h>
38 #endif
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
41 #endif
42 #ifdef HAVE_SYS_SOCKET_H
43 # include <sys/socket.h>
44 #endif
45 #ifdef HAVE_SYS_FILIO_H
46 # include <sys/filio.h>
47 #endif
48 #ifdef HAVE_UNISTD_H
49 # include <unistd.h>
50 #endif
51 #ifdef HAVE_SYS_IOCTL_H
52 # include <sys/ioctl.h>
53 #endif
54 #include <time.h>
55 #ifdef HAVE_NETDB_H
56 # include <netdb.h>
57 #endif
58 #ifdef HAVE_NETINET_IN_H
59 # include <netinet/in.h>
60 #endif
61 #ifdef HAVE_OPENSSL_SSL_H
62 # include <openssl/ssl.h>
63 #undef FAR
64 #undef DSA
65 #endif
66
67 #include <stdarg.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <stdio.h>
71 #include <errno.h>
72
73 #include "wine/library.h"
74 #include "windef.h"
75 #include "winbase.h"
76 #include "wininet.h"
77 #include "winerror.h"
78 #include "wincrypt.h"
79
80 #include "wine/debug.h"
81 #include "internet.h"
82
83 /* To avoid conflicts with the Unix socket headers. we only need it for
84  * the error codes anyway. */
85 #define USE_WS_PREFIX
86 #include "winsock2.h"
87
88 #define RESPONSE_TIMEOUT        30            /* FROM internet.c */
89
90
91 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
92
93 /* FIXME!!!!!!
94  *    This should use winsock - To use winsock the functions will have to change a bit
95  *        as they are designed for unix sockets.
96  *    SSL stuff should use crypt32.dll
97  */
98
99 #ifdef SONAME_LIBSSL
100
101 #include <openssl/err.h>
102
103 static CRITICAL_SECTION init_ssl_cs;
104 static CRITICAL_SECTION_DEBUG init_ssl_cs_debug =
105 {
106     0, 0, &init_ssl_cs,
107     { &init_ssl_cs_debug.ProcessLocksList,
108       &init_ssl_cs_debug.ProcessLocksList },
109     0, 0, { (DWORD_PTR)(__FILE__ ": init_ssl_cs") }
110 };
111 static CRITICAL_SECTION init_ssl_cs = { &init_ssl_cs_debug, -1, 0, 0, 0, 0 };
112
113 static void *OpenSSL_ssl_handle;
114 static void *OpenSSL_crypto_handle;
115
116 static SSL_METHOD *meth;
117 static SSL_CTX *ctx;
118 static int hostname_idx;
119 static int error_idx;
120
121 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
122
123 /* OpenSSL functions that we use */
124 MAKE_FUNCPTR(SSL_library_init);
125 MAKE_FUNCPTR(SSL_load_error_strings);
126 MAKE_FUNCPTR(SSLv23_method);
127 MAKE_FUNCPTR(SSL_CTX_free);
128 MAKE_FUNCPTR(SSL_CTX_new);
129 MAKE_FUNCPTR(SSL_new);
130 MAKE_FUNCPTR(SSL_free);
131 MAKE_FUNCPTR(SSL_set_fd);
132 MAKE_FUNCPTR(SSL_connect);
133 MAKE_FUNCPTR(SSL_shutdown);
134 MAKE_FUNCPTR(SSL_write);
135 MAKE_FUNCPTR(SSL_read);
136 MAKE_FUNCPTR(SSL_pending);
137 MAKE_FUNCPTR(SSL_get_error);
138 MAKE_FUNCPTR(SSL_get_ex_new_index);
139 MAKE_FUNCPTR(SSL_get_ex_data);
140 MAKE_FUNCPTR(SSL_set_ex_data);
141 MAKE_FUNCPTR(SSL_get_ex_data_X509_STORE_CTX_idx);
142 MAKE_FUNCPTR(SSL_get_verify_result);
143 MAKE_FUNCPTR(SSL_get_peer_certificate);
144 MAKE_FUNCPTR(SSL_CTX_get_timeout);
145 MAKE_FUNCPTR(SSL_CTX_set_timeout);
146 MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths);
147 MAKE_FUNCPTR(SSL_CTX_set_verify);
148 MAKE_FUNCPTR(X509_STORE_CTX_get_ex_data);
149
150 /* OpenSSL's libcrypto functions that we use */
151 MAKE_FUNCPTR(BIO_new_fp);
152 MAKE_FUNCPTR(CRYPTO_num_locks);
153 MAKE_FUNCPTR(CRYPTO_set_id_callback);
154 MAKE_FUNCPTR(CRYPTO_set_locking_callback);
155 MAKE_FUNCPTR(ERR_free_strings);
156 MAKE_FUNCPTR(ERR_get_error);
157 MAKE_FUNCPTR(ERR_error_string);
158 MAKE_FUNCPTR(i2d_X509);
159 MAKE_FUNCPTR(sk_num);
160 MAKE_FUNCPTR(sk_value);
161 #undef MAKE_FUNCPTR
162
163 static CRITICAL_SECTION *ssl_locks;
164 static unsigned int num_ssl_locks;
165
166 static unsigned long ssl_thread_id(void)
167 {
168     return GetCurrentThreadId();
169 }
170
171 static void ssl_lock_callback(int mode, int type, const char *file, int line)
172 {
173     if (mode & CRYPTO_LOCK)
174         EnterCriticalSection(&ssl_locks[type]);
175     else
176         LeaveCriticalSection(&ssl_locks[type]);
177 }
178
179 static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
180 {
181     unsigned char* buffer,*p;
182     INT len;
183     BOOL malloced = FALSE;
184     PCCERT_CONTEXT ret;
185
186     p = NULL;
187     len = pi2d_X509(cert,&p);
188     /*
189      * SSL 0.9.7 and above malloc the buffer if it is null.
190      * however earlier version do not and so we would need to alloc the buffer.
191      *
192      * see the i2d_X509 man page for more details.
193      */
194     if (!p)
195     {
196         buffer = HeapAlloc(GetProcessHeap(),0,len);
197         p = buffer;
198         len = pi2d_X509(cert,&p);
199     }
200     else
201     {
202         buffer = p;
203         malloced = TRUE;
204     }
205
206     ret = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len);
207
208     if (malloced)
209         free(buffer);
210     else
211         HeapFree(GetProcessHeap(),0,buffer);
212
213     return ret;
214 }
215
216 static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store,
217     WCHAR *server)
218 {
219     BOOL ret;
220     CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
221     PCCERT_CHAIN_CONTEXT chain;
222     char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH;
223     char *server_auth[] = { oid_server_auth };
224     DWORD err = ERROR_SUCCESS;
225
226     TRACE("verifying %s\n", debugstr_w(server));
227     chainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
228     chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth;
229     if ((ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara, 0,
230         NULL, &chain)))
231     {
232         if (chain->TrustStatus.dwErrorStatus)
233         {
234             if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
235                 err = ERROR_INTERNET_SEC_CERT_DATE_INVALID;
236             else if (chain->TrustStatus.dwErrorStatus &
237                      CERT_TRUST_IS_UNTRUSTED_ROOT)
238                 err = ERROR_INTERNET_INVALID_CA;
239             else if ((chain->TrustStatus.dwErrorStatus &
240                       CERT_TRUST_IS_OFFLINE_REVOCATION) ||
241                      (chain->TrustStatus.dwErrorStatus &
242                       CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
243                 err = ERROR_INTERNET_SEC_CERT_NO_REV;
244             else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)
245                 err = ERROR_INTERNET_SEC_CERT_REVOKED;
246             else if (chain->TrustStatus.dwErrorStatus &
247                 CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
248                 err = ERROR_INTERNET_SEC_INVALID_CERT;
249             else
250                 err = ERROR_INTERNET_SEC_INVALID_CERT;
251         }
252         else
253         {
254             CERT_CHAIN_POLICY_PARA policyPara;
255             SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara;
256             CERT_CHAIN_POLICY_STATUS policyStatus;
257
258             sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara);
259             sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER;
260             sslExtraPolicyPara.pwszServerName = server;
261             policyPara.cbSize = sizeof(policyPara);
262             policyPara.dwFlags = 0;
263             policyPara.pvExtraPolicyPara = &sslExtraPolicyPara;
264             ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
265                 chain, &policyPara, &policyStatus);
266             /* Any error in the policy status indicates that the
267              * policy couldn't be verified.
268              */
269             if (ret && policyStatus.dwError)
270             {
271                 if (policyStatus.dwError == CERT_E_CN_NO_MATCH)
272                     err = ERROR_INTERNET_SEC_CERT_CN_INVALID;
273                 else
274                     err = ERROR_INTERNET_SEC_INVALID_CERT;
275             }
276         }
277         CertFreeCertificateChain(chain);
278     }
279     TRACE("returning %08x\n", err);
280     return err;
281 }
282
283 static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx)
284 {
285     SSL *ssl;
286     WCHAR *server;
287     BOOL ret = FALSE;
288
289     ssl = pX509_STORE_CTX_get_ex_data(ctx,
290         pSSL_get_ex_data_X509_STORE_CTX_idx());
291     server = pSSL_get_ex_data(ssl, hostname_idx);
292     if (preverify_ok)
293     {
294         HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
295             CERT_STORE_CREATE_NEW_FLAG, NULL);
296
297         if (store)
298         {
299             X509 *cert;
300             int i;
301             PCCERT_CONTEXT endCert = NULL;
302
303             ret = TRUE;
304             for (i = 0; ret && i < psk_num((struct stack_st *)ctx->chain); i++)
305             {
306                 PCCERT_CONTEXT context;
307
308                 cert = (X509 *)psk_value((struct stack_st *)ctx->chain, i);
309                 if ((context = X509_to_cert_context(cert)))
310                 {
311                     if (i == 0)
312                         ret = CertAddCertificateContextToStore(store, context,
313                             CERT_STORE_ADD_ALWAYS, &endCert);
314                     else
315                         ret = CertAddCertificateContextToStore(store, context,
316                             CERT_STORE_ADD_ALWAYS, NULL);
317                     CertFreeCertificateContext(context);
318                 }
319             }
320             if (!endCert) ret = FALSE;
321             if (ret)
322             {
323                 DWORD_PTR err = netconn_verify_cert(endCert, store, server);
324
325                 if (err)
326                 {
327                     pSSL_set_ex_data(ssl, error_idx, (void *)err);
328                     ret = FALSE;
329                 }
330             }
331             CertFreeCertificateContext(endCert);
332             CertCloseStore(store, 0);
333         }
334     } else
335         pSSL_set_ex_data(ssl, error_idx, (void *)ERROR_INTERNET_SEC_CERT_ERRORS);
336
337     return ret;
338 }
339
340 #endif
341
342 DWORD NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
343 {
344     connection->useSSL = FALSE;
345     connection->socketFD = -1;
346     if (useSSL)
347     {
348 #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
349         int i;
350
351         TRACE("using SSL connection\n");
352         EnterCriticalSection(&init_ssl_cs);
353         if (OpenSSL_ssl_handle) /* already initialized everything */
354         {
355             LeaveCriticalSection(&init_ssl_cs);
356             return ERROR_SUCCESS;
357         }
358         OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0);
359         if (!OpenSSL_ssl_handle)
360         {
361             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
362                 SONAME_LIBSSL);
363             LeaveCriticalSection(&init_ssl_cs);
364             return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
365         }
366         OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0);
367         if (!OpenSSL_crypto_handle)
368         {
369             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
370                 SONAME_LIBCRYPTO);
371             LeaveCriticalSection(&init_ssl_cs);
372             return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
373         }
374
375         /* mmm nice ugly macroness */
376 #define DYNSSL(x) \
377     p##x = wine_dlsym(OpenSSL_ssl_handle, #x, NULL, 0); \
378     if (!p##x) \
379     { \
380         ERR("failed to load symbol %s\n", #x); \
381         LeaveCriticalSection(&init_ssl_cs); \
382         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \
383     }
384
385         DYNSSL(SSL_library_init);
386         DYNSSL(SSL_load_error_strings);
387         DYNSSL(SSLv23_method);
388         DYNSSL(SSL_CTX_free);
389         DYNSSL(SSL_CTX_new);
390         DYNSSL(SSL_new);
391         DYNSSL(SSL_free);
392         DYNSSL(SSL_set_fd);
393         DYNSSL(SSL_connect);
394         DYNSSL(SSL_shutdown);
395         DYNSSL(SSL_write);
396         DYNSSL(SSL_read);
397         DYNSSL(SSL_pending);
398         DYNSSL(SSL_get_error);
399         DYNSSL(SSL_get_ex_new_index);
400         DYNSSL(SSL_get_ex_data);
401         DYNSSL(SSL_set_ex_data);
402         DYNSSL(SSL_get_ex_data_X509_STORE_CTX_idx);
403         DYNSSL(SSL_get_verify_result);
404         DYNSSL(SSL_get_peer_certificate);
405         DYNSSL(SSL_CTX_get_timeout);
406         DYNSSL(SSL_CTX_set_timeout);
407         DYNSSL(SSL_CTX_set_default_verify_paths);
408         DYNSSL(SSL_CTX_set_verify);
409         DYNSSL(X509_STORE_CTX_get_ex_data);
410 #undef DYNSSL
411
412 #define DYNCRYPTO(x) \
413     p##x = wine_dlsym(OpenSSL_crypto_handle, #x, NULL, 0); \
414     if (!p##x) \
415     { \
416         ERR("failed to load symbol %s\n", #x); \
417         LeaveCriticalSection(&init_ssl_cs); \
418         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \
419     }
420         DYNCRYPTO(BIO_new_fp);
421         DYNCRYPTO(CRYPTO_num_locks);
422         DYNCRYPTO(CRYPTO_set_id_callback);
423         DYNCRYPTO(CRYPTO_set_locking_callback);
424         DYNCRYPTO(ERR_free_strings);
425         DYNCRYPTO(ERR_get_error);
426         DYNCRYPTO(ERR_error_string);
427         DYNCRYPTO(i2d_X509);
428         DYNCRYPTO(sk_num);
429         DYNCRYPTO(sk_value);
430 #undef DYNCRYPTO
431
432         pSSL_library_init();
433         pSSL_load_error_strings();
434         pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */
435
436         meth = pSSLv23_method();
437         ctx = pSSL_CTX_new(meth);
438         if (!pSSL_CTX_set_default_verify_paths(ctx))
439         {
440             ERR("SSL_CTX_set_default_verify_paths failed: %s\n",
441                 pERR_error_string(pERR_get_error(), 0));
442             LeaveCriticalSection(&init_ssl_cs);
443             return ERROR_OUTOFMEMORY;
444         }
445         hostname_idx = pSSL_get_ex_new_index(0, (void *)"hostname index",
446                 NULL, NULL, NULL);
447         if (hostname_idx == -1)
448         {
449             ERR("SSL_get_ex_new_index failed; %s\n",
450                 pERR_error_string(pERR_get_error(), 0));
451             LeaveCriticalSection(&init_ssl_cs);
452             return ERROR_OUTOFMEMORY;
453         }
454         error_idx = pSSL_get_ex_new_index(0, (void *)"error index",
455                 NULL, NULL, NULL);
456         if (error_idx == -1)
457         {
458             ERR("SSL_get_ex_new_index failed; %s\n",
459                 pERR_error_string(pERR_get_error(), 0));
460             LeaveCriticalSection(&init_ssl_cs);
461             return ERROR_OUTOFMEMORY;
462         }
463         pSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, netconn_secure_verify);
464
465         pCRYPTO_set_id_callback(ssl_thread_id);
466         num_ssl_locks = pCRYPTO_num_locks();
467         ssl_locks = HeapAlloc(GetProcessHeap(), 0, num_ssl_locks * sizeof(CRITICAL_SECTION));
468         if (!ssl_locks)
469         {
470             LeaveCriticalSection(&init_ssl_cs);
471             return ERROR_OUTOFMEMORY;
472         }
473         for (i = 0; i < num_ssl_locks; i++)
474             InitializeCriticalSection(&ssl_locks[i]);
475         pCRYPTO_set_locking_callback(ssl_lock_callback);
476         LeaveCriticalSection(&init_ssl_cs);
477 #else
478         FIXME("can't use SSL, not compiled in.\n");
479         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
480 #endif
481     }
482     return ERROR_SUCCESS;
483 }
484
485 void NETCON_unload(void)
486 {
487 #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
488     if (OpenSSL_crypto_handle)
489     {
490         pERR_free_strings();
491         wine_dlclose(OpenSSL_crypto_handle, NULL, 0);
492     }
493     if (OpenSSL_ssl_handle)
494     {
495         if (ctx)
496             pSSL_CTX_free(ctx);
497         wine_dlclose(OpenSSL_ssl_handle, NULL, 0);
498     }
499     if (ssl_locks)
500     {
501         int i;
502         for (i = 0; i < num_ssl_locks; i++) DeleteCriticalSection(&ssl_locks[i]);
503         HeapFree(GetProcessHeap(), 0, ssl_locks);
504     }
505 #endif
506 }
507
508 BOOL NETCON_connected(WININET_NETCONNECTION *connection)
509 {
510     if (connection->socketFD == -1)
511         return FALSE;
512     else
513         return TRUE;
514 }
515
516 /* translate a unix error code into a winsock one */
517 int sock_get_error( int err )
518 {
519 #if !defined(__MINGW32__) && !defined (_MSC_VER)
520     switch (err)
521     {
522         case EINTR:             return WSAEINTR;
523         case EBADF:             return WSAEBADF;
524         case EPERM:
525         case EACCES:            return WSAEACCES;
526         case EFAULT:            return WSAEFAULT;
527         case EINVAL:            return WSAEINVAL;
528         case EMFILE:            return WSAEMFILE;
529         case EWOULDBLOCK:       return WSAEWOULDBLOCK;
530         case EINPROGRESS:       return WSAEINPROGRESS;
531         case EALREADY:          return WSAEALREADY;
532         case ENOTSOCK:          return WSAENOTSOCK;
533         case EDESTADDRREQ:      return WSAEDESTADDRREQ;
534         case EMSGSIZE:          return WSAEMSGSIZE;
535         case EPROTOTYPE:        return WSAEPROTOTYPE;
536         case ENOPROTOOPT:       return WSAENOPROTOOPT;
537         case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
538         case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
539         case EOPNOTSUPP:        return WSAEOPNOTSUPP;
540         case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
541         case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
542         case EADDRINUSE:        return WSAEADDRINUSE;
543         case EADDRNOTAVAIL:     return WSAEADDRNOTAVAIL;
544         case ENETDOWN:          return WSAENETDOWN;
545         case ENETUNREACH:       return WSAENETUNREACH;
546         case ENETRESET:         return WSAENETRESET;
547         case ECONNABORTED:      return WSAECONNABORTED;
548         case EPIPE:
549         case ECONNRESET:        return WSAECONNRESET;
550         case ENOBUFS:           return WSAENOBUFS;
551         case EISCONN:           return WSAEISCONN;
552         case ENOTCONN:          return WSAENOTCONN;
553         case ESHUTDOWN:         return WSAESHUTDOWN;
554         case ETOOMANYREFS:      return WSAETOOMANYREFS;
555         case ETIMEDOUT:         return WSAETIMEDOUT;
556         case ECONNREFUSED:      return WSAECONNREFUSED;
557         case ELOOP:             return WSAELOOP;
558         case ENAMETOOLONG:      return WSAENAMETOOLONG;
559         case EHOSTDOWN:         return WSAEHOSTDOWN;
560         case EHOSTUNREACH:      return WSAEHOSTUNREACH;
561         case ENOTEMPTY:         return WSAENOTEMPTY;
562 #ifdef EPROCLIM
563         case EPROCLIM:          return WSAEPROCLIM;
564 #endif
565 #ifdef EUSERS
566         case EUSERS:            return WSAEUSERS;
567 #endif
568 #ifdef EDQUOT
569         case EDQUOT:            return WSAEDQUOT;
570 #endif
571 #ifdef ESTALE
572         case ESTALE:            return WSAESTALE;
573 #endif
574 #ifdef EREMOTE
575         case EREMOTE:           return WSAEREMOTE;
576 #endif
577     default: errno=err; perror("sock_set_error"); return WSAEFAULT;
578     }
579 #endif
580     return err;
581 }
582
583 /******************************************************************************
584  * NETCON_create
585  * Basically calls 'socket()'
586  */
587 DWORD NETCON_create(WININET_NETCONNECTION *connection, int domain,
588               int type, int protocol)
589 {
590 #ifdef SONAME_LIBSSL
591     if (connection->useSSL)
592         return ERROR_NOT_SUPPORTED;
593 #endif
594
595     connection->socketFD = socket(domain, type, protocol);
596     if (connection->socketFD == -1)
597         return sock_get_error(errno);
598
599     return ERROR_SUCCESS;
600 }
601
602 /******************************************************************************
603  * NETCON_close
604  * Basically calls 'close()' unless we should use SSL
605  */
606 DWORD NETCON_close(WININET_NETCONNECTION *connection)
607 {
608     int result;
609
610     if (!NETCON_connected(connection)) return ERROR_SUCCESS;
611
612 #ifdef SONAME_LIBSSL
613     if (connection->useSSL)
614     {
615         pSSL_shutdown(connection->ssl_s);
616         pSSL_free(connection->ssl_s);
617         connection->ssl_s = NULL;
618
619         connection->useSSL = FALSE;
620     }
621 #endif
622
623     result = closesocket(connection->socketFD);
624     connection->socketFD = -1;
625
626     if (result == -1)
627         return sock_get_error(errno);
628     return ERROR_SUCCESS;
629 }
630
631 /******************************************************************************
632  * NETCON_secure_connect
633  * Initiates a secure connection over an existing plaintext connection.
634  */
635 DWORD NETCON_secure_connect(WININET_NETCONNECTION *connection, LPWSTR hostname)
636 {
637     DWORD res = ERROR_NOT_SUPPORTED;
638 #ifdef SONAME_LIBSSL
639     long verify_res;
640     X509 *cert;
641
642     /* can't connect if we are already connected */
643     if (connection->useSSL)
644     {
645         ERR("already connected\n");
646         return ERROR_INTERNET_CANNOT_CONNECT;
647     }
648
649     connection->ssl_s = pSSL_new(ctx);
650     if (!connection->ssl_s)
651     {
652         ERR("SSL_new failed: %s\n",
653             pERR_error_string(pERR_get_error(), 0));
654         res = ERROR_OUTOFMEMORY;
655         goto fail;
656     }
657
658     if (!pSSL_set_fd(connection->ssl_s, connection->socketFD))
659     {
660         ERR("SSL_set_fd failed: %s\n",
661             pERR_error_string(pERR_get_error(), 0));
662         res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
663         goto fail;
664     }
665
666     if (pSSL_connect(connection->ssl_s) <= 0)
667     {
668         res = (DWORD_PTR)pSSL_get_ex_data(connection->ssl_s, error_idx);
669         if (!res)
670             res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
671         ERR("SSL_connect failed: %d\n", res);
672         goto fail;
673     }
674     pSSL_set_ex_data(connection->ssl_s, hostname_idx, hostname);
675     cert = pSSL_get_peer_certificate(connection->ssl_s);
676     if (!cert)
677     {
678         ERR("no certificate for server %s\n", debugstr_w(hostname));
679         /* FIXME: is this the best error? */
680         res = ERROR_INTERNET_INVALID_CA;
681         goto fail;
682     }
683     verify_res = pSSL_get_verify_result(connection->ssl_s);
684     if (verify_res != X509_V_OK)
685     {
686         ERR("couldn't verify the security of the connection, %ld\n", verify_res);
687         /* FIXME: we should set an error and return, but we only warn at
688          * the moment */
689     }
690
691     connection->useSSL = TRUE;
692     return ERROR_SUCCESS;
693
694 fail:
695     if (connection->ssl_s)
696     {
697         pSSL_shutdown(connection->ssl_s);
698         pSSL_free(connection->ssl_s);
699         connection->ssl_s = NULL;
700     }
701 #endif
702     return res;
703 }
704
705 /******************************************************************************
706  * NETCON_connect
707  * Connects to the specified address.
708  */
709 DWORD NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr,
710                     unsigned int addrlen)
711 {
712     int result;
713
714     result = connect(connection->socketFD, serv_addr, addrlen);
715     if (result == -1)
716     {
717         WARN("Unable to connect to host (%s)\n", strerror(errno));
718
719         closesocket(connection->socketFD);
720         connection->socketFD = -1;
721         return sock_get_error(errno);
722     }
723
724     return ERROR_SUCCESS;
725 }
726
727 /******************************************************************************
728  * NETCON_send
729  * Basically calls 'send()' unless we should use SSL
730  * number of chars send is put in *sent
731  */
732 DWORD NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags,
733                 int *sent /* out */)
734 {
735     if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED;
736     if (!connection->useSSL)
737     {
738         *sent = send(connection->socketFD, msg, len, flags);
739         if (*sent == -1)
740             return sock_get_error(errno);
741         return ERROR_SUCCESS;
742     }
743     else
744     {
745 #ifdef SONAME_LIBSSL
746         if (flags)
747             FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
748         *sent = pSSL_write(connection->ssl_s, msg, len);
749         if (*sent < 1 && len)
750             return ERROR_INTERNET_CONNECTION_ABORTED;
751         return ERROR_SUCCESS;
752 #else
753         return ERROR_NOT_SUPPORTED;
754 #endif
755     }
756 }
757
758 /******************************************************************************
759  * NETCON_recv
760  * Basically calls 'recv()' unless we should use SSL
761  * number of chars received is put in *recvd
762  */
763 DWORD NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags,
764                 int *recvd /* out */)
765 {
766     *recvd = 0;
767     if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED;
768     if (!len)
769         return ERROR_SUCCESS;
770     if (!connection->useSSL)
771     {
772         *recvd = recv(connection->socketFD, buf, len, flags);
773         return *recvd == -1 ? sock_get_error(errno) :  ERROR_SUCCESS;
774     }
775     else
776     {
777 #ifdef SONAME_LIBSSL
778         *recvd = pSSL_read(connection->ssl_s, buf, len);
779
780         /* Check if EOF was received */
781         if(!*recvd && (pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_ZERO_RETURN
782                     || pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_SYSCALL))
783             return ERROR_SUCCESS;
784
785         return *recvd > 0 ? ERROR_SUCCESS : ERROR_INTERNET_CONNECTION_ABORTED;
786 #else
787         return ERROR_NOT_SUPPORTED;
788 #endif
789     }
790 }
791
792 /******************************************************************************
793  * NETCON_query_data_available
794  * Returns the number of bytes of peeked data plus the number of bytes of
795  * queued, but unread data.
796  */
797 BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *available)
798 {
799     *available = 0;
800     if (!NETCON_connected(connection))
801         return FALSE;
802
803     if (!connection->useSSL)
804     {
805 #ifdef FIONREAD
806         int unread;
807         int retval = ioctlsocket(connection->socketFD, FIONREAD, &unread);
808         if (!retval)
809         {
810             TRACE("%d bytes of queued, but unread data\n", unread);
811             *available += unread;
812         }
813 #endif
814     }
815     else
816     {
817 #ifdef SONAME_LIBSSL
818         *available = pSSL_pending(connection->ssl_s);
819 #endif
820     }
821     return TRUE;
822 }
823
824 LPCVOID NETCON_GetCert(WININET_NETCONNECTION *connection)
825 {
826 #ifdef SONAME_LIBSSL
827     X509* cert;
828     LPCVOID r = NULL;
829
830     if (!connection->useSSL)
831         return NULL;
832
833     cert = pSSL_get_peer_certificate(connection->ssl_s);
834     r = X509_to_cert_context(cert);
835     return r;
836 #else
837     return NULL;
838 #endif
839 }
840
841 DWORD NETCON_set_timeout(WININET_NETCONNECTION *connection, BOOL send, int value)
842 {
843     int result;
844     struct timeval tv;
845
846     /* FIXME: we should probably store the timeout in the connection to set
847      * when we do connect */
848     if (!NETCON_connected(connection))
849         return ERROR_SUCCESS;
850
851     /* value is in milliseconds, convert to struct timeval */
852     tv.tv_sec = value / 1000;
853     tv.tv_usec = (value % 1000) * 1000;
854
855     result = setsockopt(connection->socketFD, SOL_SOCKET,
856                         send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv,
857                         sizeof(tv));
858
859     if (result == -1)
860     {
861         WARN("setsockopt failed (%s)\n", strerror(errno));
862         return sock_get_error(errno);
863     }
864
865     return ERROR_SUCCESS;
866 }