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

netconnection.c
Go to the documentation of this file.
00001 /*
00002  * Wininet - networking layer. Uses unix sockets or OpenSSL.
00003  *
00004  * Copyright 2002 TransGaming Technologies Inc.
00005  *
00006  * David Hammerton
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 #include "config.h"
00024 #include "wine/port.h"
00025 
00026 #define NONAMELESSUNION
00027 
00028 #if defined(__MINGW32__) || defined (_MSC_VER)
00029 #include <ws2tcpip.h>
00030 #endif
00031 
00032 #include <sys/types.h>
00033 #ifdef HAVE_POLL_H
00034 #include <poll.h>
00035 #endif
00036 #ifdef HAVE_SYS_POLL_H
00037 # include <sys/poll.h>
00038 #endif
00039 #ifdef HAVE_SYS_TIME_H
00040 # include <sys/time.h>
00041 #endif
00042 #ifdef HAVE_SYS_SOCKET_H
00043 # include <sys/socket.h>
00044 #endif
00045 #ifdef HAVE_SYS_FILIO_H
00046 # include <sys/filio.h>
00047 #endif
00048 #ifdef HAVE_UNISTD_H
00049 # include <unistd.h>
00050 #endif
00051 #ifdef HAVE_SYS_IOCTL_H
00052 # include <sys/ioctl.h>
00053 #endif
00054 #include <time.h>
00055 #ifdef HAVE_NETDB_H
00056 # include <netdb.h>
00057 #endif
00058 #ifdef HAVE_NETINET_IN_H
00059 # include <netinet/in.h>
00060 #endif
00061 #ifdef HAVE_NETINET_TCP_H
00062 # include <netinet/tcp.h>
00063 #endif
00064 #ifdef HAVE_OPENSSL_SSL_H
00065 # include <openssl/ssl.h>
00066 # include <openssl/opensslv.h>
00067 #undef FAR
00068 #undef DSA
00069 #endif
00070 
00071 #include <stdarg.h>
00072 #include <stdlib.h>
00073 #include <string.h>
00074 #include <stdio.h>
00075 #include <errno.h>
00076 #include <assert.h>
00077 
00078 #include "wine/library.h"
00079 #include "windef.h"
00080 #include "winbase.h"
00081 #include "wininet.h"
00082 #include "winerror.h"
00083 #include "wincrypt.h"
00084 
00085 #include "wine/debug.h"
00086 #include "internet.h"
00087 
00088 /* To avoid conflicts with the Unix socket headers. we only need it for
00089  * the error codes anyway. */
00090 #define USE_WS_PREFIX
00091 #include "winsock2.h"
00092 
00093 #define RESPONSE_TIMEOUT        30            /* FROM internet.c */
00094 
00095 
00096 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
00097 
00098 /* FIXME!!!!!!
00099  *    This should use winsock - To use winsock the functions will have to change a bit
00100  *        as they are designed for unix sockets.
00101  *    SSL stuff should use crypt32.dll
00102  */
00103 
00104 #ifdef SONAME_LIBSSL
00105 
00106 #include <openssl/err.h>
00107 
00108 static void *OpenSSL_ssl_handle;
00109 static void *OpenSSL_crypto_handle;
00110 
00111 #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER > 0x10000000)
00112 static const SSL_METHOD *meth;
00113 #else
00114 static SSL_METHOD *meth;
00115 #endif
00116 static SSL_CTX *ctx;
00117 static int hostname_idx;
00118 static int error_idx;
00119 static int conn_idx;
00120 
00121 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
00122 
00123 /* OpenSSL functions that we use */
00124 MAKE_FUNCPTR(SSL_library_init);
00125 MAKE_FUNCPTR(SSL_load_error_strings);
00126 MAKE_FUNCPTR(SSLv23_method);
00127 MAKE_FUNCPTR(SSL_CTX_free);
00128 MAKE_FUNCPTR(SSL_CTX_new);
00129 MAKE_FUNCPTR(SSL_new);
00130 MAKE_FUNCPTR(SSL_free);
00131 MAKE_FUNCPTR(SSL_set_fd);
00132 MAKE_FUNCPTR(SSL_connect);
00133 MAKE_FUNCPTR(SSL_shutdown);
00134 MAKE_FUNCPTR(SSL_write);
00135 MAKE_FUNCPTR(SSL_read);
00136 MAKE_FUNCPTR(SSL_pending);
00137 MAKE_FUNCPTR(SSL_get_error);
00138 MAKE_FUNCPTR(SSL_get_ex_new_index);
00139 MAKE_FUNCPTR(SSL_get_ex_data);
00140 MAKE_FUNCPTR(SSL_set_ex_data);
00141 MAKE_FUNCPTR(SSL_get_ex_data_X509_STORE_CTX_idx);
00142 MAKE_FUNCPTR(SSL_get_peer_certificate);
00143 MAKE_FUNCPTR(SSL_CTX_get_timeout);
00144 MAKE_FUNCPTR(SSL_CTX_set_timeout);
00145 MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths);
00146 MAKE_FUNCPTR(SSL_CTX_set_verify);
00147 MAKE_FUNCPTR(SSL_get_current_cipher);
00148 MAKE_FUNCPTR(SSL_CIPHER_get_bits);
00149 
00150 /* OpenSSL's libcrypto functions that we use */
00151 MAKE_FUNCPTR(BIO_new_fp);
00152 MAKE_FUNCPTR(CRYPTO_num_locks);
00153 MAKE_FUNCPTR(CRYPTO_set_id_callback);
00154 MAKE_FUNCPTR(CRYPTO_set_locking_callback);
00155 MAKE_FUNCPTR(ERR_free_strings);
00156 MAKE_FUNCPTR(ERR_get_error);
00157 MAKE_FUNCPTR(ERR_error_string);
00158 MAKE_FUNCPTR(X509_STORE_CTX_get_ex_data);
00159 MAKE_FUNCPTR(X509_STORE_CTX_get_chain);
00160 MAKE_FUNCPTR(i2d_X509);
00161 MAKE_FUNCPTR(sk_num);
00162 MAKE_FUNCPTR(sk_value);
00163 #undef MAKE_FUNCPTR
00164 
00165 static CRITICAL_SECTION *ssl_locks;
00166 static unsigned int num_ssl_locks;
00167 
00168 static unsigned long ssl_thread_id(void)
00169 {
00170     return GetCurrentThreadId();
00171 }
00172 
00173 static void ssl_lock_callback(int mode, int type, const char *file, int line)
00174 {
00175     if (mode & CRYPTO_LOCK)
00176         EnterCriticalSection(&ssl_locks[type]);
00177     else
00178         LeaveCriticalSection(&ssl_locks[type]);
00179 }
00180 
00181 static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
00182 {
00183     unsigned char* buffer,*p;
00184     INT len;
00185     BOOL malloced = FALSE;
00186     PCCERT_CONTEXT ret;
00187 
00188     p = NULL;
00189     len = pi2d_X509(cert,&p);
00190     /*
00191      * SSL 0.9.7 and above malloc the buffer if it is null.
00192      * however earlier version do not and so we would need to alloc the buffer.
00193      *
00194      * see the i2d_X509 man page for more details.
00195      */
00196     if (!p)
00197     {
00198         buffer = heap_alloc(len);
00199         p = buffer;
00200         len = pi2d_X509(cert,&p);
00201     }
00202     else
00203     {
00204         buffer = p;
00205         malloced = TRUE;
00206     }
00207 
00208     ret = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len);
00209 
00210     if (malloced)
00211         free(buffer);
00212     else
00213         HeapFree(GetProcessHeap(),0,buffer);
00214 
00215     return ret;
00216 }
00217 
00218 static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store,
00219     WCHAR *server, DWORD security_flags)
00220 {
00221     BOOL ret;
00222     CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
00223     PCCERT_CHAIN_CONTEXT chain;
00224     char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH;
00225     char *server_auth[] = { oid_server_auth };
00226     DWORD err = ERROR_SUCCESS, chainFlags = 0;
00227 
00228     TRACE("verifying %s\n", debugstr_w(server));
00229     chainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
00230     chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth;
00231     if (!(security_flags & SECURITY_FLAG_IGNORE_REVOCATION))
00232         chainFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
00233     if ((ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara,
00234         chainFlags, NULL, &chain)))
00235     {
00236         if (chain->TrustStatus.dwErrorStatus)
00237         {
00238             static const DWORD supportedErrors =
00239                 CERT_TRUST_IS_NOT_TIME_VALID |
00240                 CERT_TRUST_IS_UNTRUSTED_ROOT |
00241                 CERT_TRUST_IS_OFFLINE_REVOCATION |
00242                 CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
00243                 CERT_TRUST_IS_REVOKED |
00244                 CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
00245 
00246             if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID &&
00247                 !(security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID))
00248                 err = ERROR_INTERNET_SEC_CERT_DATE_INVALID;
00249             else if (chain->TrustStatus.dwErrorStatus &
00250                      CERT_TRUST_IS_UNTRUSTED_ROOT &&
00251                      !(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA))
00252                 err = ERROR_INTERNET_INVALID_CA;
00253             else if (!(security_flags & SECURITY_FLAG_IGNORE_REVOCATION) &&
00254                      ((chain->TrustStatus.dwErrorStatus &
00255                       CERT_TRUST_IS_OFFLINE_REVOCATION) ||
00256                       (chain->TrustStatus.dwErrorStatus &
00257                        CERT_TRUST_REVOCATION_STATUS_UNKNOWN)))
00258                 err = ERROR_INTERNET_SEC_CERT_NO_REV;
00259             else if (!(security_flags & SECURITY_FLAG_IGNORE_REVOCATION) &&
00260                      (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED))
00261                 err = ERROR_INTERNET_SEC_CERT_REVOKED;
00262             else if (!(security_flags & SECURITY_FLAG_IGNORE_WRONG_USAGE) &&
00263                      (chain->TrustStatus.dwErrorStatus &
00264                       CERT_TRUST_IS_NOT_VALID_FOR_USAGE))
00265                 err = ERROR_INTERNET_SEC_INVALID_CERT;
00266             else if (chain->TrustStatus.dwErrorStatus & ~supportedErrors)
00267                 err = ERROR_INTERNET_SEC_INVALID_CERT;
00268         }
00269         if (!err)
00270         {
00271             CERT_CHAIN_POLICY_PARA policyPara;
00272             SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara;
00273             CERT_CHAIN_POLICY_STATUS policyStatus;
00274             CERT_CHAIN_CONTEXT chainCopy;
00275 
00276             /* Clear chain->TrustStatus.dwErrorStatus so
00277              * CertVerifyCertificateChainPolicy will verify additional checks
00278              * rather than stopping with an existing, ignored error.
00279              */
00280             memcpy(&chainCopy, chain, sizeof(chainCopy));
00281             chainCopy.TrustStatus.dwErrorStatus = 0;
00282             sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara);
00283             sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER;
00284             sslExtraPolicyPara.pwszServerName = server;
00285             sslExtraPolicyPara.fdwChecks = security_flags;
00286             policyPara.cbSize = sizeof(policyPara);
00287             policyPara.dwFlags = 0;
00288             policyPara.pvExtraPolicyPara = &sslExtraPolicyPara;
00289             ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
00290                 &chainCopy, &policyPara, &policyStatus);
00291             /* Any error in the policy status indicates that the
00292              * policy couldn't be verified.
00293              */
00294             if (ret && policyStatus.dwError)
00295             {
00296                 if (policyStatus.dwError == CERT_E_CN_NO_MATCH)
00297                     err = ERROR_INTERNET_SEC_CERT_CN_INVALID;
00298                 else
00299                     err = ERROR_INTERNET_SEC_INVALID_CERT;
00300             }
00301         }
00302         CertFreeCertificateChain(chain);
00303     }
00304     TRACE("returning %08x\n", err);
00305     return err;
00306 }
00307 
00308 static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx)
00309 {
00310     SSL *ssl;
00311     WCHAR *server;
00312     BOOL ret = FALSE;
00313     HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
00314         CERT_STORE_CREATE_NEW_FLAG, NULL);
00315     netconn_t *conn;
00316 
00317     ssl = pX509_STORE_CTX_get_ex_data(ctx,
00318         pSSL_get_ex_data_X509_STORE_CTX_idx());
00319     server = pSSL_get_ex_data(ssl, hostname_idx);
00320     conn = pSSL_get_ex_data(ssl, conn_idx);
00321     if (store)
00322     {
00323         X509 *cert;
00324         int i;
00325         PCCERT_CONTEXT endCert = NULL;
00326         struct stack_st *chain = (struct stack_st *)pX509_STORE_CTX_get_chain( ctx );
00327 
00328         ret = TRUE;
00329         for (i = 0; ret && i < psk_num(chain); i++)
00330         {
00331             PCCERT_CONTEXT context;
00332 
00333             cert = (X509 *)psk_value(chain, i);
00334             if ((context = X509_to_cert_context(cert)))
00335             {
00336                 if (i == 0)
00337                     ret = CertAddCertificateContextToStore(store, context,
00338                         CERT_STORE_ADD_ALWAYS, &endCert);
00339                 else
00340                     ret = CertAddCertificateContextToStore(store, context,
00341                         CERT_STORE_ADD_ALWAYS, NULL);
00342                 CertFreeCertificateContext(context);
00343             }
00344         }
00345         if (!endCert) ret = FALSE;
00346         if (ret)
00347         {
00348             DWORD_PTR err = netconn_verify_cert(endCert, store, server,
00349                                                 conn->security_flags);
00350 
00351             if (err)
00352             {
00353                 pSSL_set_ex_data(ssl, error_idx, (void *)err);
00354                 ret = FALSE;
00355             }
00356         }
00357         CertFreeCertificateContext(endCert);
00358         CertCloseStore(store, 0);
00359     }
00360     return ret;
00361 }
00362 
00363 #endif
00364 
00365 static CRITICAL_SECTION init_ssl_cs;
00366 static CRITICAL_SECTION_DEBUG init_ssl_cs_debug =
00367 {
00368     0, 0, &init_ssl_cs,
00369     { &init_ssl_cs_debug.ProcessLocksList,
00370       &init_ssl_cs_debug.ProcessLocksList },
00371     0, 0, { (DWORD_PTR)(__FILE__ ": init_ssl_cs") }
00372 };
00373 static CRITICAL_SECTION init_ssl_cs = { &init_ssl_cs_debug, -1, 0, 0, 0, 0 };
00374 
00375 static DWORD init_openssl(void)
00376 {
00377 #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
00378     int i;
00379 
00380     if(OpenSSL_ssl_handle)
00381         return ERROR_SUCCESS;
00382 
00383     OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0);
00384     if(!OpenSSL_ssl_handle) {
00385         ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBSSL);
00386         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
00387     }
00388 
00389     OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0);
00390     if(!OpenSSL_crypto_handle) {
00391         ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBCRYPTO);
00392         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
00393     }
00394 
00395     /* mmm nice ugly macroness */
00396 #define DYNSSL(x) \
00397     p##x = wine_dlsym(OpenSSL_ssl_handle, #x, NULL, 0); \
00398     if (!p##x) { \
00399         ERR("failed to load symbol %s\n", #x); \
00400         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \
00401     }
00402 
00403     DYNSSL(SSL_library_init);
00404     DYNSSL(SSL_load_error_strings);
00405     DYNSSL(SSLv23_method);
00406     DYNSSL(SSL_CTX_free);
00407     DYNSSL(SSL_CTX_new);
00408     DYNSSL(SSL_new);
00409     DYNSSL(SSL_free);
00410     DYNSSL(SSL_set_fd);
00411     DYNSSL(SSL_connect);
00412     DYNSSL(SSL_shutdown);
00413     DYNSSL(SSL_write);
00414     DYNSSL(SSL_read);
00415     DYNSSL(SSL_pending);
00416     DYNSSL(SSL_get_error);
00417     DYNSSL(SSL_get_ex_new_index);
00418     DYNSSL(SSL_get_ex_data);
00419     DYNSSL(SSL_set_ex_data);
00420     DYNSSL(SSL_get_ex_data_X509_STORE_CTX_idx);
00421     DYNSSL(SSL_get_peer_certificate);
00422     DYNSSL(SSL_CTX_get_timeout);
00423     DYNSSL(SSL_CTX_set_timeout);
00424     DYNSSL(SSL_CTX_set_default_verify_paths);
00425     DYNSSL(SSL_CTX_set_verify);
00426     DYNSSL(SSL_get_current_cipher);
00427     DYNSSL(SSL_CIPHER_get_bits);
00428 #undef DYNSSL
00429 
00430 #define DYNCRYPTO(x) \
00431     p##x = wine_dlsym(OpenSSL_crypto_handle, #x, NULL, 0); \
00432     if (!p##x) { \
00433         ERR("failed to load symbol %s\n", #x); \
00434         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \
00435     }
00436 
00437     DYNCRYPTO(BIO_new_fp);
00438     DYNCRYPTO(CRYPTO_num_locks);
00439     DYNCRYPTO(CRYPTO_set_id_callback);
00440     DYNCRYPTO(CRYPTO_set_locking_callback);
00441     DYNCRYPTO(ERR_free_strings);
00442     DYNCRYPTO(ERR_get_error);
00443     DYNCRYPTO(ERR_error_string);
00444     DYNCRYPTO(X509_STORE_CTX_get_ex_data);
00445     DYNCRYPTO(X509_STORE_CTX_get_chain);
00446     DYNCRYPTO(i2d_X509);
00447     DYNCRYPTO(sk_num);
00448     DYNCRYPTO(sk_value);
00449 #undef DYNCRYPTO
00450 
00451     pSSL_library_init();
00452     pSSL_load_error_strings();
00453     pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */
00454 
00455     meth = pSSLv23_method();
00456     ctx = pSSL_CTX_new(meth);
00457     if(!pSSL_CTX_set_default_verify_paths(ctx)) {
00458         ERR("SSL_CTX_set_default_verify_paths failed: %s\n",
00459             pERR_error_string(pERR_get_error(), 0));
00460         return ERROR_OUTOFMEMORY;
00461     }
00462 
00463     hostname_idx = pSSL_get_ex_new_index(0, (void *)"hostname index", NULL, NULL, NULL);
00464     if(hostname_idx == -1) {
00465         ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0));
00466         return ERROR_OUTOFMEMORY;
00467     }
00468 
00469     error_idx = pSSL_get_ex_new_index(0, (void *)"error index", NULL, NULL, NULL);
00470     if(error_idx == -1) {
00471         ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0));
00472         return ERROR_OUTOFMEMORY;
00473     }
00474 
00475     conn_idx = pSSL_get_ex_new_index(0, (void *)"netconn index", NULL, NULL, NULL);
00476     if(conn_idx == -1) {
00477         ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0));
00478         return ERROR_OUTOFMEMORY;
00479     }
00480 
00481     pSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, netconn_secure_verify);
00482 
00483     pCRYPTO_set_id_callback(ssl_thread_id);
00484     num_ssl_locks = pCRYPTO_num_locks();
00485     ssl_locks = HeapAlloc(GetProcessHeap(), 0, num_ssl_locks * sizeof(CRITICAL_SECTION));
00486     if(!ssl_locks)
00487         return ERROR_OUTOFMEMORY;
00488 
00489     for(i = 0; i < num_ssl_locks; i++)
00490         InitializeCriticalSection(&ssl_locks[i]);
00491     pCRYPTO_set_locking_callback(ssl_lock_callback);
00492 
00493     return ERROR_SUCCESS;
00494 #else
00495     FIXME("can't use SSL, not compiled in.\n");
00496     return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
00497 #endif
00498 }
00499 
00500 DWORD create_netconn(BOOL useSSL, server_t *server, DWORD security_flags, netconn_t **ret)
00501 {
00502     netconn_t *netconn;
00503     int result, flag;
00504 
00505     if(useSSL) {
00506         DWORD res;
00507 
00508         TRACE("using SSL connection\n");
00509 
00510         EnterCriticalSection(&init_ssl_cs);
00511         res = init_openssl();
00512         LeaveCriticalSection(&init_ssl_cs);
00513         if(res != ERROR_SUCCESS)
00514             return res;
00515     }
00516 
00517     netconn = heap_alloc_zero(sizeof(*netconn));
00518     if(!netconn)
00519         return ERROR_OUTOFMEMORY;
00520 
00521     netconn->useSSL = useSSL;
00522     netconn->socketFD = -1;
00523     netconn->security_flags = security_flags;
00524     list_init(&netconn->pool_entry);
00525 
00526     assert(server->addr_len);
00527     result = netconn->socketFD = socket(server->addr.ss_family, SOCK_STREAM, 0);
00528     if(result != -1) {
00529         result = connect(netconn->socketFD, (struct sockaddr*)&server->addr, server->addr_len);
00530         if(result == -1)
00531             closesocket(netconn->socketFD);
00532     }
00533     if(result == -1) {
00534         heap_free(netconn);
00535         return sock_get_error(errno);
00536     }
00537 
00538 #ifdef TCP_NODELAY
00539     flag = 1;
00540     result = setsockopt(netconn->socketFD, IPPROTO_TCP, TCP_NODELAY, (void*)&flag, sizeof(flag));
00541     if(result < 0)
00542         WARN("setsockopt(TCP_NODELAY) failed\n");
00543 #endif
00544 
00545     server_addref(server);
00546     netconn->server = server;
00547 
00548     *ret = netconn;
00549     return ERROR_SUCCESS;
00550 }
00551 
00552 void free_netconn(netconn_t *netconn)
00553 {
00554     server_release(netconn->server);
00555 
00556 #ifdef SONAME_LIBSSL
00557     if (netconn->ssl_s) {
00558         pSSL_shutdown(netconn->ssl_s);
00559         pSSL_free(netconn->ssl_s);
00560     }
00561 #endif
00562 
00563     closesocket(netconn->socketFD);
00564     heap_free(netconn);
00565 }
00566 
00567 void NETCON_unload(void)
00568 {
00569 #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
00570     if (OpenSSL_crypto_handle)
00571     {
00572         pERR_free_strings();
00573         wine_dlclose(OpenSSL_crypto_handle, NULL, 0);
00574     }
00575     if (OpenSSL_ssl_handle)
00576     {
00577         if (ctx)
00578             pSSL_CTX_free(ctx);
00579         wine_dlclose(OpenSSL_ssl_handle, NULL, 0);
00580     }
00581     if (ssl_locks)
00582     {
00583         int i;
00584         for (i = 0; i < num_ssl_locks; i++) DeleteCriticalSection(&ssl_locks[i]);
00585         HeapFree(GetProcessHeap(), 0, ssl_locks);
00586     }
00587 #endif
00588 }
00589 
00590 #if 0
00591 /* translate a unix error code into a winsock one */
00592 int sock_get_error( int err )
00593 {
00594 #if !defined(__MINGW32__) && !defined (_MSC_VER)
00595     switch (err)
00596     {
00597         case EINTR:             return WSAEINTR;
00598         case EBADF:             return WSAEBADF;
00599         case EPERM:
00600         case EACCES:            return WSAEACCES;
00601         case EFAULT:            return WSAEFAULT;
00602         case EINVAL:            return WSAEINVAL;
00603         case EMFILE:            return WSAEMFILE;
00604         case EWOULDBLOCK:       return WSAEWOULDBLOCK;
00605         case EINPROGRESS:       return WSAEINPROGRESS;
00606         case EALREADY:          return WSAEALREADY;
00607         case ENOTSOCK:          return WSAENOTSOCK;
00608         case EDESTADDRREQ:      return WSAEDESTADDRREQ;
00609         case EMSGSIZE:          return WSAEMSGSIZE;
00610         case EPROTOTYPE:        return WSAEPROTOTYPE;
00611         case ENOPROTOOPT:       return WSAENOPROTOOPT;
00612         case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
00613         case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
00614         case EOPNOTSUPP:        return WSAEOPNOTSUPP;
00615         case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
00616         case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
00617         case EADDRINUSE:        return WSAEADDRINUSE;
00618         case EADDRNOTAVAIL:     return WSAEADDRNOTAVAIL;
00619         case ENETDOWN:          return WSAENETDOWN;
00620         case ENETUNREACH:       return WSAENETUNREACH;
00621         case ENETRESET:         return WSAENETRESET;
00622         case ECONNABORTED:      return WSAECONNABORTED;
00623         case EPIPE:
00624         case ECONNRESET:        return WSAECONNRESET;
00625         case ENOBUFS:           return WSAENOBUFS;
00626         case EISCONN:           return WSAEISCONN;
00627         case ENOTCONN:          return WSAENOTCONN;
00628         case ESHUTDOWN:         return WSAESHUTDOWN;
00629         case ETOOMANYREFS:      return WSAETOOMANYREFS;
00630         case ETIMEDOUT:         return WSAETIMEDOUT;
00631         case ECONNREFUSED:      return WSAECONNREFUSED;
00632         case ELOOP:             return WSAELOOP;
00633         case ENAMETOOLONG:      return WSAENAMETOOLONG;
00634         case EHOSTDOWN:         return WSAEHOSTDOWN;
00635         case EHOSTUNREACH:      return WSAEHOSTUNREACH;
00636         case ENOTEMPTY:         return WSAENOTEMPTY;
00637 #ifdef EPROCLIM
00638         case EPROCLIM:          return WSAEPROCLIM;
00639 #endif
00640 #ifdef EUSERS
00641         case EUSERS:            return WSAEUSERS;
00642 #endif
00643 #ifdef EDQUOT
00644         case EDQUOT:            return WSAEDQUOT;
00645 #endif
00646 #ifdef ESTALE
00647         case ESTALE:            return WSAESTALE;
00648 #endif
00649 #ifdef EREMOTE
00650         case EREMOTE:           return WSAEREMOTE;
00651 #endif
00652     default: errno=err; perror("sock_set_error"); return WSAEFAULT;
00653     }
00654 #endif
00655     return err;
00656 }
00657 #endif
00658 
00659 /******************************************************************************
00660  * NETCON_secure_connect
00661  * Initiates a secure connection over an existing plaintext connection.
00662  */
00663 DWORD NETCON_secure_connect(netconn_t *connection, LPWSTR hostname)
00664 {
00665     void *ssl_s;
00666     DWORD res = ERROR_NOT_SUPPORTED;
00667 
00668 #ifdef SONAME_LIBSSL
00669     /* can't connect if we are already connected */
00670     if (connection->ssl_s)
00671     {
00672         ERR("already connected\n");
00673         return ERROR_INTERNET_CANNOT_CONNECT;
00674     }
00675 
00676     ssl_s = pSSL_new(ctx);
00677     if (!ssl_s)
00678     {
00679         ERR("SSL_new failed: %s\n",
00680             pERR_error_string(pERR_get_error(), 0));
00681         return ERROR_OUTOFMEMORY;
00682     }
00683 
00684     if (!pSSL_set_fd(ssl_s, connection->socketFD))
00685     {
00686         ERR("SSL_set_fd failed: %s\n",
00687             pERR_error_string(pERR_get_error(), 0));
00688         res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
00689         goto fail;
00690     }
00691 
00692     if (!pSSL_set_ex_data(ssl_s, hostname_idx, hostname))
00693     {
00694         ERR("SSL_set_ex_data failed: %s\n",
00695             pERR_error_string(pERR_get_error(), 0));
00696         res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
00697         goto fail;
00698     }
00699     if (!pSSL_set_ex_data(ssl_s, conn_idx, connection))
00700     {
00701         ERR("SSL_set_ex_data failed: %s\n",
00702             pERR_error_string(pERR_get_error(), 0));
00703         res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
00704         goto fail;
00705     }
00706     if (pSSL_connect(ssl_s) <= 0)
00707     {
00708         res = (DWORD_PTR)pSSL_get_ex_data(ssl_s, error_idx);
00709         if (!res)
00710             res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
00711         ERR("SSL_connect failed: %d\n", res);
00712         goto fail;
00713     }
00714 
00715     connection->ssl_s = ssl_s;
00716     return ERROR_SUCCESS;
00717 
00718 fail:
00719     if (ssl_s)
00720     {
00721         pSSL_shutdown(ssl_s);
00722         pSSL_free(ssl_s);
00723     }
00724 #endif
00725     return res;
00726 }
00727 
00728 /******************************************************************************
00729  * NETCON_send
00730  * Basically calls 'send()' unless we should use SSL
00731  * number of chars send is put in *sent
00732  */
00733 DWORD NETCON_send(netconn_t *connection, const void *msg, size_t len, int flags,
00734         int *sent /* out */)
00735 {
00736     if (!connection->useSSL)
00737     {
00738     *sent = send(connection->socketFD, msg, len, flags);
00739     if (*sent == -1)
00740         return sock_get_error(errno);
00741         return ERROR_SUCCESS;
00742     }
00743     else
00744     {
00745 #ifdef SONAME_LIBSSL
00746         if(!connection->ssl_s) {
00747             FIXME("not connected\n");
00748             return ERROR_NOT_SUPPORTED;
00749         }
00750     if (flags)
00751             FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
00752     *sent = pSSL_write(connection->ssl_s, msg, len);
00753     if (*sent < 1 && len)
00754         return ERROR_INTERNET_CONNECTION_ABORTED;
00755         return ERROR_SUCCESS;
00756 #else
00757     return ERROR_NOT_SUPPORTED;
00758 #endif
00759     }
00760 }
00761 
00762 /******************************************************************************
00763  * NETCON_recv
00764  * Basically calls 'recv()' unless we should use SSL
00765  * number of chars received is put in *recvd
00766  */
00767 DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, int flags,
00768         int *recvd /* out */)
00769 {
00770     *recvd = 0;
00771     if (!len)
00772         return ERROR_SUCCESS;
00773     if (!connection->useSSL)
00774     {
00775     *recvd = recv(connection->socketFD, buf, len, flags);
00776     return *recvd == -1 ? sock_get_error(errno) :  ERROR_SUCCESS;
00777     }
00778     else
00779     {
00780 #ifdef SONAME_LIBSSL
00781         if(!connection->ssl_s) {
00782             FIXME("not connected\n");
00783             return ERROR_NOT_SUPPORTED;
00784         }
00785     *recvd = pSSL_read(connection->ssl_s, buf, len);
00786 
00787         /* Check if EOF was received */
00788         if(!*recvd && (pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_ZERO_RETURN
00789                     || pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_SYSCALL))
00790             return ERROR_SUCCESS;
00791 
00792         return *recvd > 0 ? ERROR_SUCCESS : ERROR_INTERNET_CONNECTION_ABORTED;
00793 #else
00794     return ERROR_NOT_SUPPORTED;
00795 #endif
00796     }
00797 }
00798 
00799 /******************************************************************************
00800  * NETCON_query_data_available
00801  * Returns the number of bytes of peeked data plus the number of bytes of
00802  * queued, but unread data.
00803  */
00804 BOOL NETCON_query_data_available(netconn_t *connection, DWORD *available)
00805 {
00806     *available = 0;
00807 
00808     if (!connection->useSSL)
00809     {
00810 #ifdef FIONREAD
00811         int unread;
00812         int retval = ioctlsocket(connection->socketFD, FIONREAD, &unread);
00813         if (!retval)
00814         {
00815             TRACE("%d bytes of queued, but unread data\n", unread);
00816             *available += unread;
00817         }
00818 #endif
00819     }
00820     else
00821     {
00822 #ifdef SONAME_LIBSSL
00823         *available = connection->ssl_s ? pSSL_pending(connection->ssl_s) : 0;
00824 #endif
00825     }
00826     return TRUE;
00827 }
00828 
00829 BOOL NETCON_is_alive(netconn_t *netconn)
00830 {
00831 #ifdef MSG_DONTWAIT
00832     ssize_t len;
00833     BYTE b;
00834 
00835     len = recv(netconn->socketFD, &b, 1, MSG_PEEK|MSG_DONTWAIT);
00836     return len == 1 || (len == -1 && errno == EWOULDBLOCK);
00837 #elif defined(__MINGW32__) || defined(_MSC_VER)
00838     ULONG mode;
00839     int len;
00840     char b;
00841 
00842     mode = 1;
00843     if(!ioctlsocket(netconn->socketFD, FIONBIO, &mode))
00844         return FALSE;
00845 
00846     len = recv(netconn->socketFD, &b, 1, MSG_PEEK);
00847 
00848     mode = 0;
00849     if(!ioctlsocket(netconn->socketFD, FIONBIO, &mode))
00850         return FALSE;
00851 
00852     return len == 1 || (len == -1 && errno == WSAEWOULDBLOCK);
00853 #else
00854     FIXME("not supported on this platform\n");
00855     return TRUE;
00856 #endif
00857 }
00858 
00859 LPCVOID NETCON_GetCert(netconn_t *connection)
00860 {
00861 #ifdef SONAME_LIBSSL
00862     X509* cert;
00863     LPCVOID r = NULL;
00864 
00865     if (!connection->ssl_s)
00866         return NULL;
00867 
00868     cert = pSSL_get_peer_certificate(connection->ssl_s);
00869     r = X509_to_cert_context(cert);
00870     return r;
00871 #else
00872     return NULL;
00873 #endif
00874 }
00875 
00876 int NETCON_GetCipherStrength(netconn_t *connection)
00877 {
00878 #ifdef SONAME_LIBSSL
00879 #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090707f)
00880     const SSL_CIPHER *cipher;
00881 #else
00882     SSL_CIPHER *cipher;
00883 #endif
00884     int bits = 0;
00885 
00886     if (!connection->ssl_s)
00887         return 0;
00888     cipher = pSSL_get_current_cipher(connection->ssl_s);
00889     if (!cipher)
00890         return 0;
00891     pSSL_CIPHER_get_bits(cipher, &bits);
00892     return bits;
00893 #else
00894     return 0;
00895 #endif
00896 }
00897 
00898 DWORD NETCON_set_timeout(netconn_t *connection, BOOL send, int value)
00899 {
00900     int result;
00901     struct timeval tv;
00902 
00903     /* value is in milliseconds, convert to struct timeval */
00904     tv.tv_sec = value / 1000;
00905     tv.tv_usec = (value % 1000) * 1000;
00906 
00907     result = setsockopt(connection->socketFD, SOL_SOCKET,
00908                         send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv,
00909                         sizeof(tv));
00910 
00911     if (result == -1)
00912     {
00913         WARN("setsockopt failed (%s)\n", strerror(errno));
00914         return sock_get_error(errno);
00915     }
00916 
00917     return ERROR_SUCCESS;
00918 }

Generated on Fri May 25 2012 04:24:58 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.