ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

net.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2008 Hans Leidekker for CodeWeavers
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include "config.h"
00020 #include "wine/port.h"
00021 
00022 #include <stdarg.h>
00023 #include <stdio.h>
00024 #include <errno.h>
00025 
00026 #include <sys/types.h>
00027 #ifdef HAVE_SYS_SOCKET_H
00028 # include <sys/socket.h>
00029 #endif
00030 #ifdef HAVE_SYS_IOCTL_H
00031 # include <sys/ioctl.h>
00032 #endif
00033 #ifdef HAVE_SYS_FILIO_H
00034 # include <sys/filio.h>
00035 #endif
00036 #ifdef HAVE_POLL_H
00037 # include <poll.h>
00038 #endif
00039 #ifdef HAVE_OPENSSL_SSL_H
00040 # include <openssl/ssl.h>
00041 # include <openssl/opensslv.h>
00042 #undef FAR
00043 #undef DSA
00044 #endif
00045 
00046 #define NONAMELESSUNION
00047 
00048 #include "wine/debug.h"
00049 #include "wine/library.h"
00050 
00051 #include "windef.h"
00052 #include "winbase.h"
00053 #include "winhttp.h"
00054 #include "wincrypt.h"
00055 
00056 #include "winhttp_private.h"
00057 
00058 /* to avoid conflicts with the Unix socket headers */
00059 #define USE_WS_PREFIX
00060 #include "winsock2.h"
00061 
00062 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
00063 
00064 #ifndef HAVE_GETADDRINFO
00065 
00066 /* critical section to protect non-reentrant gethostbyname() */
00067 static CRITICAL_SECTION cs_gethostbyname;
00068 static CRITICAL_SECTION_DEBUG critsect_debug =
00069 {
00070     0, 0, &cs_gethostbyname,
00071     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
00072       0, 0, { (DWORD_PTR)(__FILE__ ": cs_gethostbyname") }
00073 };
00074 static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 };
00075 
00076 #endif
00077 
00078 #ifdef SONAME_LIBSSL
00079 
00080 #include <openssl/err.h>
00081 
00082 static CRITICAL_SECTION init_ssl_cs;
00083 static CRITICAL_SECTION_DEBUG init_ssl_cs_debug =
00084 {
00085     0, 0, &init_ssl_cs,
00086     { &init_ssl_cs_debug.ProcessLocksList,
00087       &init_ssl_cs_debug.ProcessLocksList },
00088     0, 0, { (DWORD_PTR)(__FILE__ ": init_ssl_cs") }
00089 };
00090 static CRITICAL_SECTION init_ssl_cs = { &init_ssl_cs_debug, -1, 0, 0, 0, 0 };
00091 
00092 static void *libssl_handle;
00093 static void *libcrypto_handle;
00094 
00095 #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER > 0x10000000)
00096 static const SSL_METHOD *method;
00097 #else
00098 static SSL_METHOD *method;
00099 #endif
00100 static SSL_CTX *ctx;
00101 static int hostname_idx;
00102 static int error_idx;
00103 static int conn_idx;
00104 
00105 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
00106 
00107 MAKE_FUNCPTR( SSL_library_init );
00108 MAKE_FUNCPTR( SSL_load_error_strings );
00109 MAKE_FUNCPTR( SSLv23_method );
00110 MAKE_FUNCPTR( SSL_CTX_free );
00111 MAKE_FUNCPTR( SSL_CTX_new );
00112 MAKE_FUNCPTR( SSL_new );
00113 MAKE_FUNCPTR( SSL_free );
00114 MAKE_FUNCPTR( SSL_set_fd );
00115 MAKE_FUNCPTR( SSL_connect );
00116 MAKE_FUNCPTR( SSL_shutdown );
00117 MAKE_FUNCPTR( SSL_write );
00118 MAKE_FUNCPTR( SSL_read );
00119 MAKE_FUNCPTR( SSL_get_error );
00120 MAKE_FUNCPTR( SSL_get_ex_new_index );
00121 MAKE_FUNCPTR( SSL_get_ex_data );
00122 MAKE_FUNCPTR( SSL_set_ex_data );
00123 MAKE_FUNCPTR( SSL_get_ex_data_X509_STORE_CTX_idx );
00124 MAKE_FUNCPTR( SSL_get_peer_certificate );
00125 MAKE_FUNCPTR( SSL_CTX_set_default_verify_paths );
00126 MAKE_FUNCPTR( SSL_CTX_set_verify );
00127 MAKE_FUNCPTR( SSL_get_current_cipher );
00128 MAKE_FUNCPTR( SSL_CIPHER_get_bits );
00129 
00130 MAKE_FUNCPTR( CRYPTO_num_locks );
00131 MAKE_FUNCPTR( CRYPTO_set_id_callback );
00132 MAKE_FUNCPTR( CRYPTO_set_locking_callback );
00133 MAKE_FUNCPTR( ERR_free_strings );
00134 MAKE_FUNCPTR( ERR_get_error );
00135 MAKE_FUNCPTR( ERR_error_string );
00136 MAKE_FUNCPTR( X509_STORE_CTX_get_ex_data );
00137 MAKE_FUNCPTR( X509_STORE_CTX_get_chain );
00138 MAKE_FUNCPTR( i2d_X509 );
00139 MAKE_FUNCPTR( sk_value );
00140 MAKE_FUNCPTR( sk_num );
00141 #undef MAKE_FUNCPTR
00142 
00143 static CRITICAL_SECTION *ssl_locks;
00144 static unsigned int num_ssl_locks;
00145 
00146 static unsigned long ssl_thread_id(void)
00147 {
00148     return GetCurrentThreadId();
00149 }
00150 
00151 static void ssl_lock_callback(int mode, int type, const char *file, int line)
00152 {
00153     if (mode & CRYPTO_LOCK)
00154         EnterCriticalSection( &ssl_locks[type] );
00155     else
00156         LeaveCriticalSection( &ssl_locks[type] );
00157 }
00158 
00159 #endif
00160 
00161 /* translate a unix error code into a winsock error code */
00162 #if 0
00163 static int sock_get_error( int err )
00164 {
00165 #if !defined(__MINGW32__) && !defined (_MSC_VER)
00166     switch (err)
00167     {
00168         case EINTR:             return WSAEINTR;
00169         case EBADF:             return WSAEBADF;
00170         case EPERM:
00171         case EACCES:            return WSAEACCES;
00172         case EFAULT:            return WSAEFAULT;
00173         case EINVAL:            return WSAEINVAL;
00174         case EMFILE:            return WSAEMFILE;
00175         case EWOULDBLOCK:       return WSAEWOULDBLOCK;
00176         case EINPROGRESS:       return WSAEINPROGRESS;
00177         case EALREADY:          return WSAEALREADY;
00178         case ENOTSOCK:          return WSAENOTSOCK;
00179         case EDESTADDRREQ:      return WSAEDESTADDRREQ;
00180         case EMSGSIZE:          return WSAEMSGSIZE;
00181         case EPROTOTYPE:        return WSAEPROTOTYPE;
00182         case ENOPROTOOPT:       return WSAENOPROTOOPT;
00183         case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
00184         case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
00185         case EOPNOTSUPP:        return WSAEOPNOTSUPP;
00186         case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
00187         case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
00188         case EADDRINUSE:        return WSAEADDRINUSE;
00189         case EADDRNOTAVAIL:     return WSAEADDRNOTAVAIL;
00190         case ENETDOWN:          return WSAENETDOWN;
00191         case ENETUNREACH:       return WSAENETUNREACH;
00192         case ENETRESET:         return WSAENETRESET;
00193         case ECONNABORTED:      return WSAECONNABORTED;
00194         case EPIPE:
00195         case ECONNRESET:        return WSAECONNRESET;
00196         case ENOBUFS:           return WSAENOBUFS;
00197         case EISCONN:           return WSAEISCONN;
00198         case ENOTCONN:          return WSAENOTCONN;
00199         case ESHUTDOWN:         return WSAESHUTDOWN;
00200         case ETOOMANYREFS:      return WSAETOOMANYREFS;
00201         case ETIMEDOUT:         return WSAETIMEDOUT;
00202         case ECONNREFUSED:      return WSAECONNREFUSED;
00203         case ELOOP:             return WSAELOOP;
00204         case ENAMETOOLONG:      return WSAENAMETOOLONG;
00205         case EHOSTDOWN:         return WSAEHOSTDOWN;
00206         case EHOSTUNREACH:      return WSAEHOSTUNREACH;
00207         case ENOTEMPTY:         return WSAENOTEMPTY;
00208 #ifdef EPROCLIM
00209         case EPROCLIM:          return WSAEPROCLIM;
00210 #endif
00211 #ifdef EUSERS
00212         case EUSERS:            return WSAEUSERS;
00213 #endif
00214 #ifdef EDQUOT
00215         case EDQUOT:            return WSAEDQUOT;
00216 #endif
00217 #ifdef ESTALE
00218         case ESTALE:            return WSAESTALE;
00219 #endif
00220 #ifdef EREMOTE
00221         case EREMOTE:           return WSAEREMOTE;
00222 #endif
00223     default: errno = err; perror( "sock_set_error" ); return WSAEFAULT;
00224     }
00225 #endif
00226     return err;
00227 }
00228 #else
00229 #define sock_get_error(x) WSAGetLastError()
00230 #endif
00231 
00232 #ifdef SONAME_LIBSSL
00233 static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
00234 {
00235     unsigned char *buffer, *p;
00236     int len;
00237     BOOL malloc = FALSE;
00238     PCCERT_CONTEXT ret;
00239 
00240     p = NULL;
00241     if ((len = pi2d_X509( cert, &p )) < 0) return NULL;
00242     /*
00243      * SSL 0.9.7 and above malloc the buffer if it is null.
00244      * however earlier version do not and so we would need to alloc the buffer.
00245      *
00246      * see the i2d_X509 man page for more details.
00247      */
00248     if (!p)
00249     {
00250         if (!(buffer = heap_alloc( len ))) return NULL;
00251         p = buffer;
00252         len = pi2d_X509( cert, &p );
00253     }
00254     else
00255     {
00256         buffer = p;
00257         malloc = TRUE;
00258     }
00259 
00260     ret = CertCreateCertificateContext( X509_ASN_ENCODING, buffer, len );
00261 
00262     if (malloc) free( buffer );
00263     else heap_free( buffer );
00264 
00265     return ret;
00266 }
00267 
00268 static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, HCERTSTORE store,
00269                                   WCHAR *server, DWORD security_flags )
00270 {
00271     BOOL ret;
00272     CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
00273     PCCERT_CHAIN_CONTEXT chain;
00274     char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH;
00275     char *server_auth[] = { oid_server_auth };
00276     DWORD err = ERROR_SUCCESS;
00277 
00278     TRACE("verifying %s\n", debugstr_w( server ));
00279     chainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
00280     chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth;
00281     if ((ret = CertGetCertificateChain( NULL, cert, NULL, store, &chainPara,
00282                                         CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
00283                                         NULL, &chain )))
00284     {
00285         if (chain->TrustStatus.dwErrorStatus)
00286         {
00287             static const DWORD supportedErrors =
00288                 CERT_TRUST_IS_NOT_TIME_VALID |
00289                 CERT_TRUST_IS_UNTRUSTED_ROOT |
00290                 CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
00291 
00292             if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
00293             {
00294                 if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID))
00295                     err = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID;
00296             }
00297             else if (chain->TrustStatus.dwErrorStatus &
00298                      CERT_TRUST_IS_UNTRUSTED_ROOT)
00299             {
00300                 if (!(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA))
00301                     err = ERROR_WINHTTP_SECURE_INVALID_CA;
00302             }
00303             else if ((chain->TrustStatus.dwErrorStatus &
00304                       CERT_TRUST_IS_OFFLINE_REVOCATION) ||
00305                      (chain->TrustStatus.dwErrorStatus &
00306                       CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
00307                 err = ERROR_WINHTTP_SECURE_CERT_REV_FAILED;
00308             else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)
00309                 err = ERROR_WINHTTP_SECURE_CERT_REVOKED;
00310             else if (chain->TrustStatus.dwErrorStatus &
00311                 CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
00312             {
00313                 if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE))
00314                     err = ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE;
00315             }
00316             else if (chain->TrustStatus.dwErrorStatus & ~supportedErrors)
00317                 err = ERROR_WINHTTP_SECURE_INVALID_CERT;
00318         }
00319         if (!err)
00320         {
00321             CERT_CHAIN_POLICY_PARA policyPara;
00322             SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara;
00323             CERT_CHAIN_POLICY_STATUS policyStatus;
00324             CERT_CHAIN_CONTEXT chainCopy;
00325 
00326             /* Clear chain->TrustStatus.dwErrorStatus so
00327              * CertVerifyCertificateChainPolicy will verify additional checks
00328              * rather than stopping with an existing, ignored error.
00329              */
00330             memcpy(&chainCopy, chain, sizeof(chainCopy));
00331             chainCopy.TrustStatus.dwErrorStatus = 0;
00332             sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara);
00333             sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER;
00334             sslExtraPolicyPara.pwszServerName = server;
00335             sslExtraPolicyPara.fdwChecks = security_flags;
00336             policyPara.cbSize = sizeof(policyPara);
00337             policyPara.dwFlags = 0;
00338             policyPara.pvExtraPolicyPara = &sslExtraPolicyPara;
00339             ret = CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL,
00340                                                     &chainCopy, &policyPara,
00341                                                     &policyStatus );
00342             /* Any error in the policy status indicates that the
00343              * policy couldn't be verified.
00344              */
00345             if (ret && policyStatus.dwError)
00346             {
00347                 if (policyStatus.dwError == CERT_E_CN_NO_MATCH)
00348                     err = ERROR_WINHTTP_SECURE_CERT_CN_INVALID;
00349                 else
00350                     err = ERROR_WINHTTP_SECURE_INVALID_CERT;
00351             }
00352         }
00353         CertFreeCertificateChain( chain );
00354     }
00355     else
00356         err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
00357     TRACE("returning %08x\n", err);
00358     return err;
00359 }
00360 
00361 static int netconn_secure_verify( int preverify_ok, X509_STORE_CTX *ctx )
00362 {
00363     SSL *ssl;
00364     WCHAR *server;
00365     BOOL ret = FALSE;
00366     netconn_t *conn;
00367     HCERTSTORE store = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0,
00368      CERT_STORE_CREATE_NEW_FLAG, NULL );
00369 
00370     ssl = pX509_STORE_CTX_get_ex_data( ctx, pSSL_get_ex_data_X509_STORE_CTX_idx() );
00371     server = pSSL_get_ex_data( ssl, hostname_idx );
00372     conn = pSSL_get_ex_data( ssl, conn_idx );
00373     if (store)
00374     {
00375         X509 *cert;
00376         int i;
00377         PCCERT_CONTEXT endCert = NULL;
00378         struct stack_st *chain = (struct stack_st *)pX509_STORE_CTX_get_chain( ctx );
00379 
00380         ret = TRUE;
00381         for (i = 0; ret && i < psk_num(chain); i++)
00382         {
00383             PCCERT_CONTEXT context;
00384 
00385             cert = (X509 *)psk_value(chain, i);
00386             if ((context = X509_to_cert_context( cert )))
00387             {
00388                 if (i == 0)
00389                     ret = CertAddCertificateContextToStore( store, context,
00390                         CERT_STORE_ADD_ALWAYS, &endCert );
00391                 else
00392                     ret = CertAddCertificateContextToStore( store, context,
00393                         CERT_STORE_ADD_ALWAYS, NULL );
00394                 CertFreeCertificateContext( context );
00395             }
00396         }
00397         if (!endCert) ret = FALSE;
00398         if (ret)
00399         {
00400             DWORD_PTR err = netconn_verify_cert( endCert, store, server,
00401                                                  conn->security_flags );
00402 
00403             if (err)
00404             {
00405                 pSSL_set_ex_data( ssl, error_idx, (void *)err );
00406                 ret = FALSE;
00407             }
00408         }
00409         CertFreeCertificateContext( endCert );
00410         CertCloseStore( store, 0 );
00411     }
00412     return ret;
00413 }
00414 #endif
00415 
00416 BOOL netconn_init( netconn_t *conn, BOOL secure )
00417 {
00418 #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
00419     int i;
00420 #endif
00421 
00422     conn->socket = -1;
00423     if (!secure) return TRUE;
00424 
00425 #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
00426     EnterCriticalSection( &init_ssl_cs );
00427     if (libssl_handle)
00428     {
00429         LeaveCriticalSection( &init_ssl_cs );
00430         return TRUE;
00431     }
00432     if (!(libssl_handle = wine_dlopen( SONAME_LIBSSL, RTLD_NOW, NULL, 0 )))
00433     {
00434         ERR("Trying to use SSL but couldn't load %s. Expect trouble.\n", SONAME_LIBSSL);
00435         set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
00436         LeaveCriticalSection( &init_ssl_cs );
00437         return FALSE;
00438     }
00439     if (!(libcrypto_handle = wine_dlopen( SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0 )))
00440     {
00441         ERR("Trying to use SSL but couldn't load %s. Expect trouble.\n", SONAME_LIBCRYPTO);
00442         set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
00443         LeaveCriticalSection( &init_ssl_cs );
00444         return FALSE;
00445     }
00446 #define LOAD_FUNCPTR(x) \
00447     if (!(p##x = wine_dlsym( libssl_handle, #x, NULL, 0 ))) \
00448     { \
00449         ERR("Failed to load symbol %s\n", #x); \
00450         set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); \
00451         LeaveCriticalSection( &init_ssl_cs ); \
00452         return FALSE; \
00453     }
00454     LOAD_FUNCPTR( SSL_library_init );
00455     LOAD_FUNCPTR( SSL_load_error_strings );
00456     LOAD_FUNCPTR( SSLv23_method );
00457     LOAD_FUNCPTR( SSL_CTX_free );
00458     LOAD_FUNCPTR( SSL_CTX_new );
00459     LOAD_FUNCPTR( SSL_new );
00460     LOAD_FUNCPTR( SSL_free );
00461     LOAD_FUNCPTR( SSL_set_fd );
00462     LOAD_FUNCPTR( SSL_connect );
00463     LOAD_FUNCPTR( SSL_shutdown );
00464     LOAD_FUNCPTR( SSL_write );
00465     LOAD_FUNCPTR( SSL_read );
00466     LOAD_FUNCPTR( SSL_get_error );
00467     LOAD_FUNCPTR( SSL_get_ex_new_index );
00468     LOAD_FUNCPTR( SSL_get_ex_data );
00469     LOAD_FUNCPTR( SSL_set_ex_data );
00470     LOAD_FUNCPTR( SSL_get_ex_data_X509_STORE_CTX_idx );
00471     LOAD_FUNCPTR( SSL_get_peer_certificate );
00472     LOAD_FUNCPTR( SSL_CTX_set_default_verify_paths );
00473     LOAD_FUNCPTR( SSL_CTX_set_verify );
00474     LOAD_FUNCPTR( SSL_get_current_cipher );
00475     LOAD_FUNCPTR( SSL_CIPHER_get_bits );
00476 #undef LOAD_FUNCPTR
00477 
00478 #define LOAD_FUNCPTR(x) \
00479     if (!(p##x = wine_dlsym( libcrypto_handle, #x, NULL, 0 ))) \
00480     { \
00481         ERR("Failed to load symbol %s\n", #x); \
00482         set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); \
00483         LeaveCriticalSection( &init_ssl_cs ); \
00484         return FALSE; \
00485     }
00486     LOAD_FUNCPTR( CRYPTO_num_locks );
00487     LOAD_FUNCPTR( CRYPTO_set_id_callback );
00488     LOAD_FUNCPTR( CRYPTO_set_locking_callback );
00489     LOAD_FUNCPTR( ERR_free_strings );
00490     LOAD_FUNCPTR( ERR_get_error );
00491     LOAD_FUNCPTR( ERR_error_string );
00492     LOAD_FUNCPTR( X509_STORE_CTX_get_ex_data );
00493     LOAD_FUNCPTR( X509_STORE_CTX_get_chain );
00494     LOAD_FUNCPTR( i2d_X509 );
00495     LOAD_FUNCPTR( sk_value );
00496     LOAD_FUNCPTR( sk_num );
00497 #undef LOAD_FUNCPTR
00498 
00499     pSSL_library_init();
00500     pSSL_load_error_strings();
00501 
00502     method = pSSLv23_method();
00503     ctx = pSSL_CTX_new( method );
00504     if (!pSSL_CTX_set_default_verify_paths( ctx ))
00505     {
00506         ERR("SSL_CTX_set_default_verify_paths failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
00507         set_last_error( ERROR_OUTOFMEMORY );
00508         LeaveCriticalSection( &init_ssl_cs );
00509         return FALSE;
00510     }
00511     hostname_idx = pSSL_get_ex_new_index( 0, (void *)"hostname index", NULL, NULL, NULL );
00512     if (hostname_idx == -1)
00513     {
00514         ERR("SSL_get_ex_new_index failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
00515         set_last_error( ERROR_OUTOFMEMORY );
00516         LeaveCriticalSection( &init_ssl_cs );
00517         return FALSE;
00518     }
00519     error_idx = pSSL_get_ex_new_index( 0, (void *)"error index", NULL, NULL, NULL );
00520     if (error_idx == -1)
00521     {
00522         ERR("SSL_get_ex_new_index failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
00523         set_last_error( ERROR_OUTOFMEMORY );
00524         LeaveCriticalSection( &init_ssl_cs );
00525         return FALSE;
00526     }
00527     conn_idx = pSSL_get_ex_new_index( 0, (void *)"netconn index", NULL, NULL, NULL );
00528     if (conn_idx == -1)
00529     {
00530         ERR("SSL_get_ex_new_index failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
00531         set_last_error( ERROR_OUTOFMEMORY );
00532         LeaveCriticalSection( &init_ssl_cs );
00533         return FALSE;
00534     }
00535     pSSL_CTX_set_verify( ctx, SSL_VERIFY_PEER, netconn_secure_verify );
00536 
00537     pCRYPTO_set_id_callback(ssl_thread_id);
00538     num_ssl_locks = pCRYPTO_num_locks();
00539     ssl_locks = HeapAlloc(GetProcessHeap(), 0, num_ssl_locks * sizeof(CRITICAL_SECTION));
00540     if (!ssl_locks)
00541     {
00542         set_last_error( ERROR_OUTOFMEMORY );
00543         LeaveCriticalSection( &init_ssl_cs );
00544         return FALSE;
00545     }
00546     for (i = 0; i < num_ssl_locks; i++) InitializeCriticalSection( &ssl_locks[i] );
00547     pCRYPTO_set_locking_callback(ssl_lock_callback);
00548 
00549     LeaveCriticalSection( &init_ssl_cs );
00550 #else
00551     WARN("SSL support not compiled in.\n");
00552     set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
00553     return FALSE;
00554 #endif
00555     return TRUE;
00556 }
00557 
00558 void netconn_unload( void )
00559 {
00560 #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
00561     if (libcrypto_handle)
00562     {
00563         pERR_free_strings();
00564         wine_dlclose( libcrypto_handle, NULL, 0 );
00565     }
00566     if (libssl_handle)
00567     {
00568         if (ctx)
00569             pSSL_CTX_free( ctx );
00570         wine_dlclose( libssl_handle, NULL, 0 );
00571     }
00572     if (ssl_locks)
00573     {
00574         int i;
00575         for (i = 0; i < num_ssl_locks; i++) DeleteCriticalSection( &ssl_locks[i] );
00576         HeapFree( GetProcessHeap(), 0, ssl_locks );
00577     }
00578 #endif
00579 }
00580 
00581 BOOL netconn_connected( netconn_t *conn )
00582 {
00583     return (conn->socket != -1);
00584 }
00585 
00586 BOOL netconn_create( netconn_t *conn, int domain, int type, int protocol )
00587 {
00588     if ((conn->socket = socket( domain, type, protocol )) == -1)
00589     {
00590         WARN("unable to create socket (%s)\n", strerror(errno));
00591         set_last_error( sock_get_error( errno ) );
00592         return FALSE;
00593     }
00594     return TRUE;
00595 }
00596 
00597 BOOL netconn_close( netconn_t *conn )
00598 {
00599     int res;
00600 
00601 #ifdef SONAME_LIBSSL
00602     if (conn->secure)
00603     {
00604         heap_free( conn->peek_msg_mem );
00605         conn->peek_msg_mem = NULL;
00606         conn->peek_msg = NULL;
00607         conn->peek_len = 0;
00608 
00609         pSSL_shutdown( conn->ssl_conn );
00610         pSSL_free( conn->ssl_conn );
00611 
00612         conn->ssl_conn = NULL;
00613         conn->secure = FALSE;
00614     }
00615 #endif
00616     res = closesocket( conn->socket );
00617     conn->socket = -1;
00618     if (res == -1)
00619     {
00620         set_last_error( sock_get_error( errno ) );
00621         return FALSE;
00622     }
00623     return TRUE;
00624 }
00625 
00626 BOOL netconn_connect( netconn_t *conn, const struct sockaddr *sockaddr, unsigned int addr_len, int timeout )
00627 {
00628     BOOL ret = FALSE;
00629     int res = 0, state;
00630 
00631     if (timeout > 0)
00632     {
00633         state = 1;
00634         ioctlsocket( conn->socket, FIONBIO, &state );
00635     }
00636     if (connect( conn->socket, sockaddr, addr_len ) < 0)
00637     {
00638         res = sock_get_error( errno );
00639         if (res == WSAEWOULDBLOCK || res == WSAEINPROGRESS)
00640         {
00641             fd_set outfd;
00642             struct timeval tv;
00643 
00644             FD_ZERO(&outfd);
00645             FD_SET(conn->socket, &outfd);
00646 
00647             tv.tv_sec = 0;
00648             tv.tv_usec = timeout * 1000;
00649 
00650             if (select( 0, NULL, &outfd, NULL, &tv ) > 0)
00651                 ret = TRUE;
00652             else
00653                 res = sock_get_error( errno );
00654         }
00655     }
00656     else
00657         ret = TRUE;
00658     if (timeout > 0)
00659     {
00660         state = 0;
00661         ioctlsocket( conn->socket, FIONBIO, &state );
00662     }
00663     if (!ret)
00664     {
00665         WARN("unable to connect to host (%d)\n", res);
00666         set_last_error( res );
00667     }
00668     return ret;
00669 }
00670 
00671 BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname )
00672 {
00673 #ifdef SONAME_LIBSSL
00674     if (!(conn->ssl_conn = pSSL_new( ctx )))
00675     {
00676         ERR("SSL_new failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
00677         set_last_error( ERROR_OUTOFMEMORY );
00678         goto fail;
00679     }
00680     if (!pSSL_set_ex_data( conn->ssl_conn, hostname_idx, hostname ))
00681     {
00682         ERR("SSL_set_ex_data failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
00683         set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
00684         goto fail;
00685     }
00686     if (!pSSL_set_ex_data( conn->ssl_conn, conn_idx, conn ))
00687     {
00688         ERR("SSL_set_ex_data failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
00689         set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
00690         return FALSE;
00691     }
00692     if (!pSSL_set_fd( conn->ssl_conn, conn->socket ))
00693     {
00694         ERR("SSL_set_fd failed: %s\n", pERR_error_string( pERR_get_error(), 0 ));
00695         set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR );
00696         goto fail;
00697     }
00698     if (pSSL_connect( conn->ssl_conn ) <= 0)
00699     {
00700         DWORD err;
00701 
00702         err = (DWORD_PTR)pSSL_get_ex_data( conn->ssl_conn, error_idx );
00703         if (!err) err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
00704         ERR("couldn't verify server certificate (%d)\n", err);
00705         set_last_error( err );
00706         goto fail;
00707     }
00708     TRACE("established SSL connection\n");
00709     conn->secure = TRUE;
00710     return TRUE;
00711 
00712 fail:
00713     if (conn->ssl_conn)
00714     {
00715         pSSL_shutdown( conn->ssl_conn );
00716         pSSL_free( conn->ssl_conn );
00717         conn->ssl_conn = NULL;
00718     }
00719 #endif
00720     return FALSE;
00721 }
00722 
00723 BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int flags, int *sent )
00724 {
00725     if (!netconn_connected( conn )) return FALSE;
00726     if (conn->secure)
00727     {
00728 #ifdef SONAME_LIBSSL
00729         if (flags) FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
00730         *sent = pSSL_write( conn->ssl_conn, msg, len );
00731         if (*sent < 1 && len) return FALSE;
00732         return TRUE;
00733 #else
00734         return FALSE;
00735 #endif
00736     }
00737     if ((*sent = send( conn->socket, msg, len, flags )) == -1)
00738     {
00739         set_last_error( sock_get_error( errno ) );
00740         return FALSE;
00741     }
00742     return TRUE;
00743 }
00744 
00745 BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd )
00746 {
00747     int ret;
00748 
00749     *recvd = 0;
00750     if (!netconn_connected( conn )) return FALSE;
00751     if (!len) return TRUE;
00752 
00753     if (conn->secure)
00754     {
00755 #ifdef SONAME_LIBSSL
00756         if (flags & ~(MSG_PEEK | MSG_WAITALL))
00757             FIXME("SSL_read does not support the following flags: %08x\n", flags);
00758 
00759         /* this ugly hack is all for MSG_PEEK */
00760         if (flags & MSG_PEEK && !conn->peek_msg)
00761         {
00762             if (!(conn->peek_msg = conn->peek_msg_mem = heap_alloc( len + 1 ))) return FALSE;
00763         }
00764         else if (flags & MSG_PEEK && conn->peek_msg)
00765         {
00766             if (len < conn->peek_len) FIXME("buffer isn't big enough, should we wrap?\n");
00767             *recvd = min( len, conn->peek_len );
00768             memcpy( buf, conn->peek_msg, *recvd );
00769             return TRUE;
00770         }
00771         else if (conn->peek_msg)
00772         {
00773             *recvd = min( len, conn->peek_len );
00774             memcpy( buf, conn->peek_msg, *recvd );
00775             conn->peek_len -= *recvd;
00776             conn->peek_msg += *recvd;
00777 
00778             if (conn->peek_len == 0)
00779             {
00780                 heap_free( conn->peek_msg_mem );
00781                 conn->peek_msg_mem = NULL;
00782                 conn->peek_msg = NULL;
00783             }
00784             /* check if we have enough data from the peek buffer */
00785             if (!(flags & MSG_WAITALL) || (*recvd == len)) return TRUE;
00786         }
00787         ret = pSSL_read( conn->ssl_conn, (char *)buf + *recvd, len - *recvd );
00788         if (ret < 0)
00789             return FALSE;
00790 
00791         /* check if EOF was received */
00792         if (!ret && (pSSL_get_error( conn->ssl_conn, ret ) == SSL_ERROR_ZERO_RETURN ||
00793                      pSSL_get_error( conn->ssl_conn, ret ) == SSL_ERROR_SYSCALL ))
00794         {
00795             netconn_close( conn );
00796             return TRUE;
00797         }
00798         if (flags & MSG_PEEK) /* must copy into buffer */
00799         {
00800             conn->peek_len = ret;
00801             if (!ret)
00802             {
00803                 heap_free( conn->peek_msg_mem );
00804                 conn->peek_msg_mem = NULL;
00805                 conn->peek_msg = NULL;
00806             }
00807             else memcpy( conn->peek_msg, buf, ret );
00808         }
00809         *recvd = ret;
00810         return TRUE;
00811 #else
00812         return FALSE;
00813 #endif
00814     }
00815     if ((*recvd = recv( conn->socket, buf, len, flags )) == -1)
00816     {
00817         set_last_error( sock_get_error( errno ) );
00818         return FALSE;
00819     }
00820     return TRUE;
00821 }
00822 
00823 BOOL netconn_query_data_available( netconn_t *conn, DWORD *available )
00824 {
00825 #ifdef FIONREAD
00826     int ret, unread;
00827 #endif
00828     *available = 0;
00829     if (!netconn_connected( conn )) return FALSE;
00830 
00831     if (conn->secure)
00832     {
00833 #ifdef SONAME_LIBSSL
00834         if (conn->peek_msg) *available = conn->peek_len;
00835 #endif
00836         return TRUE;
00837     }
00838 #ifdef FIONREAD
00839     if (!(ret = ioctlsocket( conn->socket, FIONREAD, &unread ))) *available = unread;
00840 #endif
00841     return TRUE;
00842 }
00843 
00844 BOOL netconn_get_next_line( netconn_t *conn, char *buffer, DWORD *buflen )
00845 {
00846     fd_set infd;
00847     BOOL ret = FALSE;
00848     DWORD recvd = 0;
00849 
00850     if (!netconn_connected( conn )) return FALSE;
00851 
00852     if (conn->secure)
00853     {
00854 #ifdef SONAME_LIBSSL
00855         while (recvd < *buflen)
00856         {
00857             int dummy;
00858             if (!netconn_recv( conn, &buffer[recvd], 1, 0, &dummy ))
00859             {
00860                 set_last_error( ERROR_CONNECTION_ABORTED );
00861                 break;
00862             }
00863             if (buffer[recvd] == '\n')
00864             {
00865                 ret = TRUE;
00866                 break;
00867             }
00868             if (buffer[recvd] != '\r') recvd++;
00869         }
00870         if (ret)
00871         {
00872             buffer[recvd++] = 0;
00873             *buflen = recvd;
00874             TRACE("received line %s\n", debugstr_a(buffer));
00875         }
00876         return ret;
00877 #else
00878         return FALSE;
00879 #endif
00880     }
00881 
00882     FD_ZERO(&infd);
00883     FD_SET(conn->socket, &infd);
00884 
00885     while (recvd < *buflen)
00886     {
00887         int res;
00888         struct timeval tv, *ptv;
00889         socklen_t len = sizeof(tv);
00890 
00891         if ((res = getsockopt( conn->socket, SOL_SOCKET, SO_RCVTIMEO, (void*)&tv, &len ) != -1))
00892             ptv = &tv;
00893         else
00894             ptv = NULL;
00895 
00896         if (select( 0, &infd, NULL, NULL, ptv ) > 0)
00897         {
00898             if ((res = recv( conn->socket, &buffer[recvd], 1, 0 )) <= 0)
00899             {
00900                 if (res == -1) set_last_error( sock_get_error( errno ) );
00901                 break;
00902             }
00903             if (buffer[recvd] == '\n')
00904             {
00905                 ret = TRUE;
00906                 break;
00907             }
00908             if (buffer[recvd] != '\r') recvd++;
00909         }
00910         else
00911         {
00912             set_last_error( ERROR_WINHTTP_TIMEOUT );
00913             break;
00914         }
00915     }
00916     if (ret)
00917     {
00918         buffer[recvd++] = 0;
00919         *buflen = recvd;
00920         TRACE("received line %s\n", debugstr_a(buffer));
00921     }
00922     return ret;
00923 }
00924 
00925 DWORD netconn_set_timeout( netconn_t *netconn, BOOL send, int value )
00926 {
00927     int res;
00928     struct timeval tv;
00929 
00930     /* value is in milliseconds, convert to struct timeval */
00931     tv.tv_sec = value / 1000;
00932     tv.tv_usec = (value % 1000) * 1000;
00933 
00934     if ((res = setsockopt( netconn->socket, SOL_SOCKET, send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv, sizeof(tv) ) == -1))
00935     {
00936         WARN("setsockopt failed (%s)\n", strerror( errno ));
00937         return sock_get_error( errno );
00938     }
00939     return ERROR_SUCCESS;
00940 }
00941 
00942 static DWORD resolve_hostname( WCHAR *hostnameW, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len )
00943 {
00944     char *hostname;
00945 #ifdef HAVE_GETADDRINFO
00946     struct addrinfo *res, hints;
00947     int ret;
00948 #else
00949     struct hostent *he;
00950     struct sockaddr_in *sin = (struct sockaddr_in *)sa;
00951 #endif
00952 
00953     if (!(hostname = strdupWA( hostnameW ))) return ERROR_OUTOFMEMORY;
00954 
00955 #ifdef HAVE_GETADDRINFO
00956     memset( &hints, 0, sizeof(struct addrinfo) );
00957     /* Prefer IPv4 to IPv6 addresses, since some web servers do not listen on
00958      * their IPv6 addresses even though they have IPv6 addresses in the DNS.
00959      */
00960     hints.ai_family = AF_INET;
00961 
00962     ret = getaddrinfo( hostname, NULL, &hints, &res );
00963     if (ret != 0)
00964     {
00965         TRACE("failed to get IPv4 address of %s (%s), retrying with IPv6\n", debugstr_w(hostnameW), gai_strerror(ret));
00966         hints.ai_family = AF_INET6;
00967         ret = getaddrinfo( hostname, NULL, &hints, &res );
00968         if (ret != 0)
00969         {
00970             TRACE("failed to get address of %s (%s)\n", debugstr_w(hostnameW), gai_strerror(ret));
00971             heap_free( hostname );
00972             return ERROR_WINHTTP_NAME_NOT_RESOLVED;
00973         }
00974     }
00975     heap_free( hostname );
00976     if (*sa_len < res->ai_addrlen)
00977     {
00978         WARN("address too small\n");
00979         freeaddrinfo( res );
00980         return ERROR_WINHTTP_NAME_NOT_RESOLVED;
00981     }
00982     *sa_len = res->ai_addrlen;
00983     memcpy( sa, res->ai_addr, res->ai_addrlen );
00984     /* Copy port */
00985     switch (res->ai_family)
00986     {
00987     case AF_INET:
00988         ((struct sockaddr_in *)sa)->sin_port = htons( port );
00989         break;
00990     case AF_INET6:
00991         ((struct sockaddr_in6 *)sa)->sin6_port = htons( port );
00992         break;
00993     }
00994 
00995     freeaddrinfo( res );
00996     return ERROR_SUCCESS;
00997 #else
00998     EnterCriticalSection( &cs_gethostbyname );
00999 
01000     he = gethostbyname( hostname );
01001     heap_free( hostname );
01002     if (!he)
01003     {
01004         TRACE("failed to get address of %s (%d)\n", debugstr_w(hostnameW), h_errno);
01005         LeaveCriticalSection( &cs_gethostbyname );
01006         return ERROR_WINHTTP_NAME_NOT_RESOLVED;
01007     }
01008     if (*sa_len < sizeof(struct sockaddr_in))
01009     {
01010         WARN("address too small\n");
01011         LeaveCriticalSection( &cs_gethostbyname );
01012         return ERROR_WINHTTP_NAME_NOT_RESOLVED;
01013     }
01014     *sa_len = sizeof(struct sockaddr_in);
01015     memset( sa, 0, sizeof(struct sockaddr_in) );
01016     memcpy( &sin->sin_addr, he->h_addr, he->h_length );
01017     sin->sin_family = he->h_addrtype;
01018     sin->sin_port = htons( port );
01019 
01020     LeaveCriticalSection( &cs_gethostbyname );
01021     return ERROR_SUCCESS;
01022 #endif
01023 }
01024 
01025 struct resolve_args
01026 {
01027     WCHAR           *hostname;
01028     INTERNET_PORT    port;
01029     struct sockaddr *sa;
01030     socklen_t       *sa_len;
01031 };
01032 
01033 static DWORD CALLBACK resolve_proc( LPVOID arg )
01034 {
01035     struct resolve_args *ra = arg;
01036     return resolve_hostname( ra->hostname, ra->port, ra->sa, ra->sa_len );
01037 }
01038 
01039 BOOL netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr *sa, socklen_t *sa_len, int timeout )
01040 {
01041     DWORD ret;
01042 
01043     if (timeout)
01044     {
01045         DWORD status;
01046         HANDLE thread;
01047         struct resolve_args ra;
01048 
01049         ra.hostname = hostname;
01050         ra.port     = port;
01051         ra.sa       = sa;
01052         ra.sa_len   = sa_len;
01053 
01054         thread = CreateThread( NULL, 0, resolve_proc, &ra, 0, NULL );
01055         if (!thread) return FALSE;
01056 
01057         status = WaitForSingleObject( thread, timeout );
01058         if (status == WAIT_OBJECT_0) GetExitCodeThread( thread, &ret );
01059         else ret = ERROR_WINHTTP_TIMEOUT;
01060         CloseHandle( thread );
01061     }
01062     else ret = resolve_hostname( hostname, port, sa, sa_len );
01063 
01064     if (ret)
01065     {
01066         set_last_error( ret );
01067         return FALSE;
01068     }
01069     return TRUE;
01070 }
01071 
01072 const void *netconn_get_certificate( netconn_t *conn )
01073 {
01074 #ifdef SONAME_LIBSSL
01075     X509 *cert;
01076     const CERT_CONTEXT *ret;
01077 
01078     if (!conn->secure) return NULL;
01079 
01080     if (!(cert = pSSL_get_peer_certificate( conn->ssl_conn ))) return NULL;
01081     ret = X509_to_cert_context( cert );
01082     return ret;
01083 #else
01084     return NULL;
01085 #endif
01086 }
01087 
01088 int netconn_get_cipher_strength( netconn_t *conn )
01089 {
01090 #ifdef SONAME_LIBSSL
01091 #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090707f)
01092     const SSL_CIPHER *cipher;
01093 #else
01094     SSL_CIPHER *cipher;
01095 #endif
01096     int bits = 0;
01097 
01098     if (!conn->secure) return 0;
01099     if (!(cipher = pSSL_get_current_cipher( conn->ssl_conn ))) return 0;
01100     pSSL_CIPHER_get_bits( cipher, &bits );
01101     return bits;
01102 #else
01103     return 0;
01104 #endif
01105 }

Generated on Fri May 25 2012 04:15:29 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.