advapi32/service: Make sure we fill all struct members.
[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 #ifdef HAVE_SYS_TIME_H
27 # include <sys/time.h>
28 #endif
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_SOCKET_H
31 # include <sys/socket.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #ifdef HAVE_SYS_IOCTL_H
37 # include <sys/ioctl.h>
38 #endif
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <errno.h>
44
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "wininet.h"
49 #include "winerror.h"
50
51 /* To avoid conflicts with the Unix socket headers. we only need it for
52  * the error codes anyway. */
53 #define USE_WS_PREFIX
54 #include "winsock2.h"
55
56 #include "wine/debug.h"
57 #include "internet.h"
58 #include "wincrypt.h"
59
60 #define RESPONSE_TIMEOUT        30            /* FROM internet.c */
61
62
63 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
64
65 /* FIXME!!!!!!
66  *    This should use winsock - To use winsock the functions will have to change a bit
67  *        as they are designed for unix sockets.
68  *    SSL stuff should use crypt32.dll
69  */
70
71 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
72
73 #include <openssl/err.h>
74
75 #ifndef SONAME_LIBSSL
76 #define SONAME_LIBSSL "libssl.so"
77 #endif
78 #ifndef SONAME_LIBCRYPTO
79 #define SONAME_LIBCRYPTO "libcrypto.so"
80 #endif
81
82 static void *OpenSSL_ssl_handle;
83 static void *OpenSSL_crypto_handle;
84
85 static SSL_METHOD *meth;
86 static SSL_CTX *ctx;
87
88 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
89
90 /* OpenSSL functions that we use */
91 MAKE_FUNCPTR(SSL_library_init);
92 MAKE_FUNCPTR(SSL_load_error_strings);
93 MAKE_FUNCPTR(SSLv23_method);
94 MAKE_FUNCPTR(SSL_CTX_new);
95 MAKE_FUNCPTR(SSL_new);
96 MAKE_FUNCPTR(SSL_free);
97 MAKE_FUNCPTR(SSL_set_fd);
98 MAKE_FUNCPTR(SSL_connect);
99 MAKE_FUNCPTR(SSL_shutdown);
100 MAKE_FUNCPTR(SSL_write);
101 MAKE_FUNCPTR(SSL_read);
102 MAKE_FUNCPTR(SSL_get_verify_result);
103 MAKE_FUNCPTR(SSL_get_peer_certificate);
104 MAKE_FUNCPTR(SSL_CTX_get_timeout);
105 MAKE_FUNCPTR(SSL_CTX_set_timeout);
106 MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths);
107 MAKE_FUNCPTR(i2d_X509);
108
109 /* OpenSSL's libcrypto functions that we use */
110 MAKE_FUNCPTR(BIO_new_fp);
111 MAKE_FUNCPTR(ERR_get_error);
112 MAKE_FUNCPTR(ERR_error_string);
113 #undef MAKE_FUNCPTR
114
115 #endif
116
117 BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
118 {
119     connection->useSSL = FALSE;
120     connection->socketFD = -1;
121     if (useSSL)
122     {
123 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
124         TRACE("using SSL connection\n");
125         if (OpenSSL_ssl_handle) /* already initialized everything */
126             return TRUE;
127         OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0);
128         if (!OpenSSL_ssl_handle)
129         {
130             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
131                 SONAME_LIBSSL);
132             INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR);
133             return FALSE;
134         }
135         OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0);
136         if (!OpenSSL_crypto_handle)
137         {
138             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
139                 SONAME_LIBCRYPTO);
140             INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR);
141             return FALSE;
142         }
143
144         /* mmm nice ugly macroness */
145 #define DYNSSL(x) \
146     p##x = wine_dlsym(OpenSSL_ssl_handle, #x, NULL, 0); \
147     if (!p##x) \
148     { \
149         ERR("failed to load symbol %s\n", #x); \
150         INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); \
151         return FALSE; \
152     }
153
154         DYNSSL(SSL_library_init);
155         DYNSSL(SSL_load_error_strings);
156         DYNSSL(SSLv23_method);
157         DYNSSL(SSL_CTX_new);
158         DYNSSL(SSL_new);
159         DYNSSL(SSL_free);
160         DYNSSL(SSL_set_fd);
161         DYNSSL(SSL_connect);
162         DYNSSL(SSL_shutdown);
163         DYNSSL(SSL_write);
164         DYNSSL(SSL_read);
165         DYNSSL(SSL_get_verify_result);
166         DYNSSL(SSL_get_peer_certificate);
167         DYNSSL(SSL_CTX_get_timeout);
168         DYNSSL(SSL_CTX_set_timeout);
169         DYNSSL(SSL_CTX_set_default_verify_paths);
170         DYNSSL(i2d_X509);
171 #undef DYNSSL
172
173 #define DYNCRYPTO(x) \
174     p##x = wine_dlsym(OpenSSL_crypto_handle, #x, NULL, 0); \
175     if (!p##x) \
176     { \
177         ERR("failed to load symbol %s\n", #x); \
178         INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); \
179         return FALSE; \
180     }
181         DYNCRYPTO(BIO_new_fp);
182         DYNCRYPTO(ERR_get_error);
183         DYNCRYPTO(ERR_error_string);
184 #undef DYNCRYPTO
185
186         pSSL_library_init();
187         pSSL_load_error_strings();
188         pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */
189
190         meth = pSSLv23_method();
191         connection->peek_msg = NULL;
192         connection->peek_msg_mem = NULL;
193 #else
194         FIXME("can't use SSL, not compiled in.\n");
195         INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR);
196         return FALSE;
197 #endif
198     }
199     return TRUE;
200 }
201
202 BOOL NETCON_connected(WININET_NETCONNECTION *connection)
203 {
204     if (connection->socketFD == -1)
205         return FALSE;
206     else
207         return TRUE;
208 }
209
210 /* translate a unix error code into a winsock one */
211 static int sock_get_error( int err )
212 {
213     switch (err)
214     {
215         case EINTR:             return WSAEINTR;
216         case EBADF:             return WSAEBADF;
217         case EPERM:
218         case EACCES:            return WSAEACCES;
219         case EFAULT:            return WSAEFAULT;
220         case EINVAL:            return WSAEINVAL;
221         case EMFILE:            return WSAEMFILE;
222         case EWOULDBLOCK:       return WSAEWOULDBLOCK;
223         case EINPROGRESS:       return WSAEINPROGRESS;
224         case EALREADY:          return WSAEALREADY;
225         case ENOTSOCK:          return WSAENOTSOCK;
226         case EDESTADDRREQ:      return WSAEDESTADDRREQ;
227         case EMSGSIZE:          return WSAEMSGSIZE;
228         case EPROTOTYPE:        return WSAEPROTOTYPE;
229         case ENOPROTOOPT:       return WSAENOPROTOOPT;
230         case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
231         case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
232         case EOPNOTSUPP:        return WSAEOPNOTSUPP;
233         case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
234         case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
235         case EADDRINUSE:        return WSAEADDRINUSE;
236         case EADDRNOTAVAIL:     return WSAEADDRNOTAVAIL;
237         case ENETDOWN:          return WSAENETDOWN;
238         case ENETUNREACH:       return WSAENETUNREACH;
239         case ENETRESET:         return WSAENETRESET;
240         case ECONNABORTED:      return WSAECONNABORTED;
241         case EPIPE:
242         case ECONNRESET:        return WSAECONNRESET;
243         case ENOBUFS:           return WSAENOBUFS;
244         case EISCONN:           return WSAEISCONN;
245         case ENOTCONN:          return WSAENOTCONN;
246         case ESHUTDOWN:         return WSAESHUTDOWN;
247         case ETOOMANYREFS:      return WSAETOOMANYREFS;
248         case ETIMEDOUT:         return WSAETIMEDOUT;
249         case ECONNREFUSED:      return WSAECONNREFUSED;
250         case ELOOP:             return WSAELOOP;
251         case ENAMETOOLONG:      return WSAENAMETOOLONG;
252         case EHOSTDOWN:         return WSAEHOSTDOWN;
253         case EHOSTUNREACH:      return WSAEHOSTUNREACH;
254         case ENOTEMPTY:         return WSAENOTEMPTY;
255 #ifdef EPROCLIM
256         case EPROCLIM:          return WSAEPROCLIM;
257 #endif
258 #ifdef EUSERS
259         case EUSERS:            return WSAEUSERS;
260 #endif
261 #ifdef EDQUOT
262         case EDQUOT:            return WSAEDQUOT;
263 #endif
264 #ifdef ESTALE
265         case ESTALE:            return WSAESTALE;
266 #endif
267 #ifdef EREMOTE
268         case EREMOTE:           return WSAEREMOTE;
269 #endif
270     default: errno=err; perror("sock_set_error"); return WSAEFAULT;
271     }
272 }
273
274 /******************************************************************************
275  * NETCON_create
276  * Basically calls 'socket()'
277  */
278 BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain,
279               int type, int protocol)
280 {
281 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
282     if (connection->useSSL)
283         return FALSE;
284 #endif
285
286     connection->socketFD = socket(domain, type, protocol);
287     if (connection->socketFD == -1)
288     {
289         INTERNET_SetLastError(sock_get_error(errno));
290         return FALSE;
291     }
292     return TRUE;
293 }
294
295 /******************************************************************************
296  * NETCON_close
297  * Basically calls 'close()' unless we should use SSL
298  */
299 BOOL NETCON_close(WININET_NETCONNECTION *connection)
300 {
301     int result;
302
303     if (!NETCON_connected(connection)) return FALSE;
304
305 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
306     if (connection->useSSL)
307     {
308         HeapFree(GetProcessHeap(),0,connection->peek_msg_mem);
309         connection->peek_msg = NULL;
310         connection->peek_msg_mem = NULL;
311         connection->peek_len = 0;
312
313         pSSL_shutdown(connection->ssl_s);
314         pSSL_free(connection->ssl_s);
315         connection->ssl_s = NULL;
316
317         connection->useSSL = FALSE;
318     }
319 #endif
320
321     result = closesocket(connection->socketFD);
322     connection->socketFD = -1;
323
324     if (result == -1)
325     {
326         INTERNET_SetLastError(sock_get_error(errno));
327         return FALSE;
328     }
329     return TRUE;
330 }
331 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
332 static BOOL check_hostname(X509 *cert, char *hostname)
333 {
334     /* FIXME: implement */
335     return TRUE;
336 }
337 #endif
338 /******************************************************************************
339  * NETCON_secure_connect
340  * Initiates a secure connection over an existing plaintext connection.
341  */
342 BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname)
343 {
344 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
345     long verify_res;
346     X509 *cert;
347     int len;
348     char *hostname_unix;
349
350     /* can't connect if we are already connected */
351     if (connection->useSSL)
352     {
353         ERR("already connected\n");
354         return FALSE;
355     }
356
357     ctx = pSSL_CTX_new(meth);
358     if (!pSSL_CTX_set_default_verify_paths(ctx))
359     {
360         ERR("SSL_CTX_set_default_verify_paths failed: %s\n",
361             pERR_error_string(pERR_get_error(), 0));
362         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
363         return FALSE;
364     }
365     connection->ssl_s = pSSL_new(ctx);
366     if (!connection->ssl_s)
367     {
368         ERR("SSL_new failed: %s\n",
369             pERR_error_string(pERR_get_error(), 0));
370         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
371         goto fail;
372     }
373
374     if (!pSSL_set_fd(connection->ssl_s, connection->socketFD))
375     {
376         ERR("SSL_set_fd failed: %s\n",
377             pERR_error_string(pERR_get_error(), 0));
378         INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR);
379         goto fail;
380     }
381
382     if (pSSL_connect(connection->ssl_s) <= 0)
383     {
384         ERR("SSL_connect failed: %s\n",
385             pERR_error_string(pERR_get_error(), 0));
386         INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR);
387         goto fail;
388     }
389     cert = pSSL_get_peer_certificate(connection->ssl_s);
390     if (!cert)
391     {
392         ERR("no certificate for server %s\n", debugstr_w(hostname));
393         /* FIXME: is this the best error? */
394         INTERNET_SetLastError(ERROR_INTERNET_INVALID_CA);
395         goto fail;
396     }
397     verify_res = pSSL_get_verify_result(connection->ssl_s);
398     if (verify_res != X509_V_OK)
399     {
400         ERR("couldn't verify the security of the connection, %ld\n", verify_res);
401         /* FIXME: we should set an error and return, but we only warn at
402          * the moment */
403     }
404
405     len = WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, NULL, 0, NULL, NULL);
406     hostname_unix = HeapAlloc(GetProcessHeap(), 0, len);
407     if (!hostname_unix)
408     {
409         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
410         goto fail;
411     }
412     WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, hostname_unix, len, NULL, NULL);
413
414     if (!check_hostname(cert, hostname_unix))
415     {
416         HeapFree(GetProcessHeap(), 0, hostname_unix);
417         INTERNET_SetLastError(ERROR_INTERNET_SEC_CERT_CN_INVALID);
418         goto fail;
419     }
420
421     HeapFree(GetProcessHeap(), 0, hostname_unix);
422     connection->useSSL = TRUE;
423     return TRUE;
424
425 fail:
426     if (connection->ssl_s)
427     {
428         pSSL_shutdown(connection->ssl_s);
429         pSSL_free(connection->ssl_s);
430         connection->ssl_s = NULL;
431     }
432 #endif
433     return FALSE;
434 }
435
436 /******************************************************************************
437  * NETCON_connect
438  * Connects to the specified address.
439  */
440 BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr,
441                     unsigned int addrlen)
442 {
443     int result;
444
445     if (!NETCON_connected(connection)) return FALSE;
446
447     result = connect(connection->socketFD, serv_addr, addrlen);
448     if (result == -1)
449     {
450         WARN("Unable to connect to host (%s)\n", strerror(errno));
451         INTERNET_SetLastError(sock_get_error(errno));
452
453         closesocket(connection->socketFD);
454         connection->socketFD = -1;
455         return FALSE;
456     }
457
458     return TRUE;
459 }
460
461 /******************************************************************************
462  * NETCON_send
463  * Basically calls 'send()' unless we should use SSL
464  * number of chars send is put in *sent
465  */
466 BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags,
467                 int *sent /* out */)
468 {
469     if (!NETCON_connected(connection)) return FALSE;
470     if (!connection->useSSL)
471     {
472         *sent = send(connection->socketFD, msg, len, flags);
473         if (*sent == -1)
474         {
475             INTERNET_SetLastError(sock_get_error(errno));
476             return FALSE;
477         }
478         return TRUE;
479     }
480     else
481     {
482 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
483         if (flags)
484             FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
485         *sent = pSSL_write(connection->ssl_s, msg, len);
486         if (*sent < 1 && len)
487             return FALSE;
488         return TRUE;
489 #else
490         return FALSE;
491 #endif
492     }
493 }
494
495 /******************************************************************************
496  * NETCON_recv
497  * Basically calls 'recv()' unless we should use SSL
498  * number of chars received is put in *recvd
499  */
500 BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags,
501                 int *recvd /* out */)
502 {
503     *recvd = 0;
504     if (!NETCON_connected(connection)) return FALSE;
505     if (!len)
506         return TRUE;
507     if (!connection->useSSL)
508     {
509         *recvd = recv(connection->socketFD, buf, len, flags);
510         if (*recvd == -1)
511         {
512             INTERNET_SetLastError(sock_get_error(errno));
513             return FALSE;
514         }
515         return TRUE;
516     }
517     else
518     {
519 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
520         if (flags & ~(MSG_PEEK|MSG_WAITALL))
521             FIXME("SSL_read does not support the following flag: %08x\n", flags);
522
523         /* this ugly hack is all for MSG_PEEK. eww gross */
524         if (flags & MSG_PEEK && !connection->peek_msg)
525         {
526             connection->peek_msg = connection->peek_msg_mem = HeapAlloc(GetProcessHeap(), 0, (sizeof(char) * len) + 1);
527         }
528         else if (flags & MSG_PEEK && connection->peek_msg)
529         {
530             if (len < connection->peek_len)
531                 FIXME("buffer isn't big enough. Do the expect us to wrap?\n");
532             *recvd = min(len, connection->peek_len);
533             memcpy(buf, connection->peek_msg, *recvd);
534             return TRUE;
535         }
536         else if (connection->peek_msg)
537         {
538             *recvd = min(len, connection->peek_len);
539             memcpy(buf, connection->peek_msg, *recvd);
540             connection->peek_len -= *recvd;
541             connection->peek_msg += *recvd;
542             if (connection->peek_len == 0)
543             {
544                 HeapFree(GetProcessHeap(), 0, connection->peek_msg_mem);
545                 connection->peek_msg_mem = NULL;
546                 connection->peek_msg = NULL;
547             }
548             /* check if we got enough data from the peek buffer */
549             if (!(flags & MSG_WAITALL) || (*recvd == len))
550                 return TRUE;
551             /* otherwise, fall through */
552         }
553         *recvd += pSSL_read(connection->ssl_s, (char*)buf + *recvd, len - *recvd);
554         if (flags & MSG_PEEK) /* must copy stuff into buffer */
555         {
556             connection->peek_len = *recvd;
557             if (!*recvd)
558             {
559                 HeapFree(GetProcessHeap(), 0, connection->peek_msg_mem);
560                 connection->peek_msg_mem = NULL;
561                 connection->peek_msg = NULL;
562             }
563             else
564                 memcpy(connection->peek_msg, buf, *recvd);
565         }
566         if (*recvd < 1 && len)
567             return FALSE;
568         return TRUE;
569 #else
570         return FALSE;
571 #endif
572     }
573 }
574
575 /******************************************************************************
576  * NETCON_query_data_available
577  * Returns the number of bytes of peeked data plus the number of bytes of
578  * queued, but unread data.
579  */
580 BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *available)
581 {
582     if (!NETCON_connected(connection))
583         return FALSE;
584
585     *available = 0;
586 #if defined HAVE_OPENSSL_SSL_H
587     if (connection->peek_msg) *available = connection->peek_len;
588 #endif
589
590 #ifdef FIONREAD
591     if (!connection->useSSL)
592     {
593         int unread;
594         int retval = ioctl(connection->socketFD, FIONREAD, &unread);
595         if (!retval)
596         {
597             TRACE("%d bytes of queued, but unread data\n", unread);
598             *available += unread;
599         }
600     }
601 #endif
602     return TRUE;
603 }
604
605 /******************************************************************************
606  * NETCON_getNextLine
607  */
608 BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer)
609 {
610
611     TRACE("\n");
612
613     if (!NETCON_connected(connection)) return FALSE;
614
615     if (!connection->useSSL)
616     {
617         struct timeval tv;
618         fd_set infd;
619         BOOL bSuccess = FALSE;
620         DWORD nRecv = 0;
621
622         FD_ZERO(&infd);
623         FD_SET(connection->socketFD, &infd);
624         tv.tv_sec=RESPONSE_TIMEOUT;
625         tv.tv_usec=0;
626
627         while (nRecv < *dwBuffer)
628         {
629             if (select(connection->socketFD+1,&infd,NULL,NULL,&tv) > 0)
630             {
631                 if (recv(connection->socketFD, &lpszBuffer[nRecv], 1, 0) <= 0)
632                 {
633                     INTERNET_SetLastError(sock_get_error(errno));
634                     goto lend;
635                 }
636
637                 if (lpszBuffer[nRecv] == '\n')
638                 {
639                     bSuccess = TRUE;
640                     break;
641                 }
642                 if (lpszBuffer[nRecv] != '\r')
643                     nRecv++;
644             }
645             else
646             {
647                 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
648                 goto lend;
649             }
650         }
651
652     lend:             /* FIXME: don't use labels */
653         if (bSuccess)
654         {
655             lpszBuffer[nRecv++] = '\0';
656             *dwBuffer = nRecv;
657             TRACE(":%u %s\n", nRecv, lpszBuffer);
658             return TRUE;
659         }
660         else
661         {
662             return FALSE;
663         }
664     }
665     else
666     {
667 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
668         long prev_timeout;
669         DWORD nRecv = 0;
670         BOOL success = TRUE;
671
672         prev_timeout = pSSL_CTX_get_timeout(ctx);
673         pSSL_CTX_set_timeout(ctx, RESPONSE_TIMEOUT);
674
675         while (nRecv < *dwBuffer)
676         {
677             int recv = 1;
678             if (!NETCON_recv(connection, &lpszBuffer[nRecv], 1, 0, &recv))
679             {
680                 INTERNET_SetLastError(ERROR_CONNECTION_ABORTED);
681                 success = FALSE;
682             }
683
684             if (lpszBuffer[nRecv] == '\n')
685             {
686                 success = TRUE;
687                 break;
688             }
689             if (lpszBuffer[nRecv] != '\r')
690                 nRecv++;
691         }
692
693         pSSL_CTX_set_timeout(ctx, prev_timeout);
694         if (success)
695         {
696             lpszBuffer[nRecv++] = '\0';
697             *dwBuffer = nRecv;
698             TRACE("_SSL:%u %s\n", nRecv, lpszBuffer);
699             return TRUE;
700         }
701         return FALSE;
702 #else
703         return FALSE;
704 #endif
705     }
706 }
707
708
709 LPCVOID NETCON_GetCert(WININET_NETCONNECTION *connection)
710 {
711
712 #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
713     X509* cert;
714     unsigned char* buffer,*p;
715     INT len;
716     BOOL malloced = FALSE;
717     LPCVOID r = NULL;
718
719     if (!connection->useSSL)
720         return NULL;
721
722     cert = pSSL_get_peer_certificate(connection->ssl_s);
723     p = NULL;
724     len = pi2d_X509(cert,&p);
725     /*
726      * SSL 0.9.7 and above malloc the buffer if it is null. 
727      * however earlier version do not and so we would need to alloc the buffer.
728      *
729      * see the i2d_X509 man page for more details.
730      */
731     if (!p)
732     {
733         buffer = HeapAlloc(GetProcessHeap(),0,len);
734         p = buffer;
735         len = pi2d_X509(cert,&p);
736     }
737     else
738     {
739         buffer = p;
740         malloced = TRUE;
741     }
742
743     r = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len);
744
745     if (malloced)
746         free(buffer);
747     else
748         HeapFree(GetProcessHeap(),0,buffer);
749
750     return r;
751 #else
752     return NULL;
753 #endif
754 }
755
756 BOOL NETCON_set_timeout(WININET_NETCONNECTION *connection, BOOL send, int value)
757 {
758     int result;
759     struct timeval tv;
760
761     /* FIXME: we should probably store the timeout in the connection to set
762      * when we do connect */
763     if (!NETCON_connected(connection))
764         return TRUE;
765
766     /* value is in milliseconds, convert to struct timeval */
767     tv.tv_sec = value / 1000;
768     tv.tv_usec = (value % 1000) * 1000;
769
770     result = setsockopt(connection->socketFD, SOL_SOCKET,
771                         send ? SO_SNDTIMEO : SO_RCVTIMEO, &tv,
772                         sizeof(tv));
773
774     if (result == -1)
775     {
776         WARN("setsockopt failed (%s)\n", strerror(errno));
777         INTERNET_SetLastError(sock_get_error(errno));
778         return FALSE;
779     }
780
781     return TRUE;
782 }