Fixed definitions of TTTOOLINFOA/W_V1_SIZE and
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
31 #endif
32 #ifdef HAVE_SYS_SOCKET_H
33 # include <sys/socket.h>
34 #endif
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "wine/library.h"
43 #include "windef.h"
44 #include "winbase.h"
45 #include "wininet.h"
46 #include "winerror.h"
47
48 #include "wine/debug.h"
49 #include "internet.h"
50
51 #define RESPONSE_TIMEOUT        30            /* FROM internet.c */
52
53
54 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
55
56 /* FIXME!!!!!!
57  *    This should use winsock - To use winsock the funtions will have to change a bit
58  *        as they are designed for unix sockets.
59  *    SSL stuff should use crypt32.dll
60  */
61
62 #ifdef HAVE_OPENSSL_SSL_H
63
64 #ifndef SONAME_LIBSSL
65 #define SONAME_LIBSSL "libssl.so"
66 #endif
67 #ifndef SONAME_LIBCRYPTO
68 #define SONAME_LIBCRYPTO "libcrypto.so"
69 #endif
70
71 static void *OpenSSL_ssl_handle;
72 static void *OpenSSL_crypto_handle;
73
74 static SSL_METHOD *meth;
75 static SSL_CTX *ctx;
76
77 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
78
79 /* OpenSSL funtions that we use */
80 MAKE_FUNCPTR(SSL_library_init);
81 MAKE_FUNCPTR(SSL_load_error_strings);
82 MAKE_FUNCPTR(SSLv23_method);
83 MAKE_FUNCPTR(SSL_CTX_new);
84 MAKE_FUNCPTR(SSL_new);
85 MAKE_FUNCPTR(SSL_set_bio);
86 MAKE_FUNCPTR(SSL_connect);
87 MAKE_FUNCPTR(SSL_write);
88 MAKE_FUNCPTR(SSL_read);
89 MAKE_FUNCPTR(SSL_CTX_get_timeout);
90 MAKE_FUNCPTR(SSL_CTX_set_timeout);
91
92 /* OpenSSL's libcrypto functions that we use */
93 MAKE_FUNCPTR(BIO_new_socket);
94 MAKE_FUNCPTR(BIO_new_fp);
95 #undef MAKE_FUNCPTR
96
97 #endif
98
99 void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
100 {
101     connection->useSSL = useSSL;
102     connection->socketFD = -1;
103     if (connection->useSSL)
104     {
105 #ifdef HAVE_OPENSSL_SSL_H
106         TRACE("using SSL connection\n");
107         connection->ssl_sock = -1;
108         if (OpenSSL_ssl_handle) /* already initilzed everything */
109             return;
110         OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0);
111         if (!OpenSSL_ssl_handle)
112         {
113             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
114                 SONAME_LIBSSL);
115             connection->useSSL = FALSE;
116             return;
117         }
118         OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0);
119         if (!OpenSSL_crypto_handle)
120         {
121             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
122                 SONAME_LIBCRYPTO);
123             connection->useSSL = FALSE;
124             return;
125         }
126
127         /* mmm nice ugly macroness */
128 #define DYNSSL(x) \
129     p##x = wine_dlsym(OpenSSL_ssl_handle, #x, NULL, 0); \
130     if (!p##x) \
131     { \
132         ERR("failed to load symbol %s\n", #x); \
133         connection->useSSL = FALSE; \
134         return; \
135     }
136
137         DYNSSL(SSL_library_init);
138         DYNSSL(SSL_load_error_strings);
139         DYNSSL(SSLv23_method);
140         DYNSSL(SSL_CTX_new);
141         DYNSSL(SSL_new);
142         DYNSSL(SSL_set_bio);
143         DYNSSL(SSL_connect);
144         DYNSSL(SSL_write);
145         DYNSSL(SSL_read);
146         DYNSSL(SSL_CTX_get_timeout);
147         DYNSSL(SSL_CTX_set_timeout);
148 #undef DYNSSL
149
150 #define DYNCRYPTO(x) \
151     p##x = wine_dlsym(OpenSSL_crypto_handle, #x, NULL, 0); \
152     if (!p##x) \
153     { \
154         ERR("failed to load symbol %s\n", #x); \
155         connection->useSSL = FALSE; \
156         return; \
157     }
158         DYNCRYPTO(BIO_new_fp);
159         DYNCRYPTO(BIO_new_socket);
160 #undef DYNCRYPTO
161
162         pSSL_library_init();
163         pSSL_load_error_strings();
164         pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */
165
166         meth = pSSLv23_method();
167         /* FIXME: SECURITY PROBLEM! WE ARN'T VERIFYING THE HOSTS CERTIFICATES OR ANYTHING */
168 #else
169         FIXME("can't use SSL, not compiled in.\n");
170         connection->useSSL = FALSE;
171 #endif
172     }
173 }
174
175 BOOL NETCON_connected(WININET_NETCONNECTION *connection)
176 {
177     if (!connection->useSSL)
178     {
179         if (connection->socketFD == -1)
180             return FALSE;
181         return TRUE;
182     }
183     else
184     {
185 #ifdef HAVE_OPENSSL_SSL_H
186         if (connection->ssl_sock == -1)
187             return FALSE;
188         return TRUE;
189 #else
190         return FALSE;
191 #endif
192     }
193 }
194
195 /******************************************************************************
196  * NETCON_create
197  * Basically calls 'socket()' unless useSSL is supplised,
198  *  in which case we do other things.
199  */
200 BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain,
201               int type, int protocol)
202 {
203     if (!connection->useSSL)
204     {
205         connection->socketFD = socket(domain, type, protocol);
206         if (connection->socketFD == -1)
207             return FALSE;
208         return TRUE;
209     }
210     else
211     {
212 #ifdef HAVE_OPENSSL_SSL_H
213         connection->ssl_sock = socket(domain, type, protocol);
214         return TRUE;
215 #else
216         return FALSE;
217 #endif
218     }
219 }
220
221 /******************************************************************************
222  * NETCON_close
223  * Basically calls 'close()' unless we should use SSL
224  */
225 BOOL NETCON_close(WININET_NETCONNECTION *connection)
226 {
227     if (!NETCON_connected) return FALSE;
228     if (!connection->useSSL)
229     {
230         int result;
231         result = close(connection->socketFD);
232         connection->socketFD = -1;
233         if (result == -1)
234             return FALSE;
235         return TRUE;
236     }
237     else
238     {
239 #ifdef HAVE_OPENSSL_SSL_H
240         close(connection->ssl_sock);
241         connection->ssl_sock = -1;
242         /* FIXME should we call SSL_shutdown here?? Probably on whatever is the
243          * opposite of NETCON_init.... */
244         return TRUE;
245 #else
246         return FALSE;
247 #endif
248     }
249 }
250
251 /******************************************************************************
252  * NETCON_connect
253  * Basically calls 'connect()' unless we should use SSL
254  */
255 BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr,
256                     socklen_t addrlen)
257 {
258     if (!NETCON_connected) return FALSE;
259     if (!connection->useSSL)
260     {
261         int result;
262         result = connect(connection->socketFD, serv_addr, addrlen);
263         if (result == -1)
264             return FALSE;
265         return TRUE;
266     }
267     else
268     {
269 #ifdef HAVE_OPENSSL_SSL_H
270         BIO *sbio;
271
272         ctx = pSSL_CTX_new(meth);
273         connection->ssl_s = pSSL_new(ctx);
274
275         if (connect(connection->ssl_sock, serv_addr, addrlen) == -1)
276             return FALSE;
277
278         sbio = pBIO_new_socket(connection->ssl_sock, BIO_NOCLOSE);
279         pSSL_set_bio(connection->ssl_s, sbio, sbio);
280         if (pSSL_connect(connection->ssl_s) <= 0)
281         {
282             ERR("ssl couldn't connect\n");
283             return FALSE;
284         }
285         return TRUE;
286 #else
287         return FALSE;
288 #endif
289     }
290 }
291
292 /******************************************************************************
293  * NETCON_send
294  * Basically calls 'send()' unless we should use SSL
295  * number of chars send is put in *sent
296  */
297 BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags,
298                 int *sent /* out */)
299 {
300     if (!NETCON_connected) return FALSE;
301     if (!connection->useSSL)
302     {
303         *sent = send(connection->socketFD, msg, len, flags);
304         if (*sent == -1)
305             return FALSE;
306         return TRUE;
307     }
308     else
309     {
310 #ifdef HAVE_OPENSSL_SSL_H
311         if (flags)
312             FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
313         *sent = pSSL_write(connection->ssl_s, msg, len);
314         if (*sent < 1 && len)
315             return FALSE;
316         return TRUE;
317 #else
318         return FALSE;
319 #endif
320     }
321 }
322
323 /******************************************************************************
324  * NETCON_recv
325  * Basically calls 'recv()' unless we should use SSL
326  * number of chars receieved is put in *recvd
327  */
328 BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags,
329                 int *recvd /* out */)
330 {
331     if (!NETCON_connected) return FALSE;
332     if (!connection->useSSL)
333     {
334         *recvd = recv(connection->socketFD, buf, len, flags);
335         if (*recvd == -1)
336             return FALSE;
337         return TRUE;
338     }
339     else
340     {
341 #ifdef HAVE_OPENSSL_SSL_H
342         static char *peek_msg = NULL;
343         static char *peek_msg_mem = NULL;
344
345         if (flags & (~MSG_PEEK))
346             FIXME("SSL_read does not support the following flag: %08x\n", flags);
347
348         /* this ugly hack is all for MSG_PEEK. eww gross */
349         if (flags & MSG_PEEK && !peek_msg)
350         {
351             peek_msg = peek_msg_mem = HeapAlloc(GetProcessHeap(), 0, (sizeof(char) * len) + 1);
352         }
353         else if (flags & MSG_PEEK && peek_msg)
354         {
355             if (len < strlen(peek_msg))
356                 FIXME("buffer isn't big enough. Do the expect us to wrap?\n");
357             strncpy(buf, peek_msg, len);
358             *recvd = (strlen(peek_msg) <= len ? strlen(peek_msg) : len);
359             return TRUE;
360         }
361         else if (peek_msg)
362         {
363             strncpy(buf, peek_msg, len);
364             peek_msg += *recvd = min(len, strlen(peek_msg));
365             if (*peek_msg == '\0' || *(peek_msg - 1) == '\0')
366             {
367                 HeapFree(GetProcessHeap(), 0, peek_msg_mem);
368                 peek_msg_mem = NULL;
369                 peek_msg = NULL;
370             }
371             return TRUE;
372         }
373         *recvd = pSSL_read(connection->ssl_s, buf, len);
374         if (flags & MSG_PEEK) /* must copy stuff into buffer */
375         {
376             if (!*recvd)
377             {
378                 HeapFree(GetProcessHeap(), 0, peek_msg_mem);
379                 peek_msg_mem = NULL;
380                 peek_msg = NULL;
381             }
382             else
383             {
384                 strncpy(peek_msg, buf, *recvd);
385                 peek_msg[*recvd] = '\0';
386             }
387         }
388         if (*recvd < 1 && len)
389             return FALSE;
390         return TRUE;
391 #else
392         return FALSE;
393 #endif
394     }
395 }
396
397 /******************************************************************************
398  * NETCON_getNextLine
399  */
400 BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer)
401 {
402
403     TRACE("\n");
404
405     if (!NETCON_connected(connection)) return FALSE;
406
407     if (!connection->useSSL)
408     {
409         struct timeval tv;
410         fd_set infd;
411         BOOL bSuccess = FALSE;
412         INT nRecv = 0;
413
414         FD_ZERO(&infd);
415         FD_SET(connection->socketFD, &infd);
416         tv.tv_sec=RESPONSE_TIMEOUT;
417         tv.tv_usec=0;
418
419         while (nRecv < *dwBuffer)
420         {
421             if (select(connection->socketFD+1,&infd,NULL,NULL,&tv) > 0)
422             {
423                 if (recv(connection->socketFD, &lpszBuffer[nRecv], 1, 0) <= 0)
424                 {
425                     INTERNET_SetLastError(ERROR_CONNECTION_ABORTED); /* fixme: right error? */
426                     goto lend;
427                 }
428
429                 if (lpszBuffer[nRecv] == '\n')
430                 {
431                     bSuccess = TRUE;
432                     break;
433                 }
434                 if (lpszBuffer[nRecv] != '\r')
435                     nRecv++;
436             }
437             else
438             {
439                 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
440                 goto lend;
441             }
442         }
443
444     lend:             /* FIXME: don't use labels */
445         if (bSuccess)
446         {
447             lpszBuffer[nRecv] = '\0';
448             *dwBuffer = nRecv - 1;
449             TRACE(":%d %s\n", nRecv, lpszBuffer);
450             return TRUE;
451         }
452         else
453         {
454             return FALSE;
455         }
456     }
457     else
458     {
459 #ifdef HAVE_OPENSSL_SSL_H
460         long prev_timeout;
461         INT nRecv = 0;
462         BOOL success = TRUE;
463
464         prev_timeout = pSSL_CTX_get_timeout(ctx);
465         pSSL_CTX_set_timeout(ctx, RESPONSE_TIMEOUT);
466
467         while (nRecv < *dwBuffer)
468         {
469             int recv = 1;
470             if (!NETCON_recv(connection, &lpszBuffer[nRecv], 1, 0, &recv))
471             {
472                 INTERNET_SetLastError(ERROR_CONNECTION_ABORTED);
473                 success = FALSE;
474             }
475
476             if (lpszBuffer[nRecv] == '\n')
477             {
478                 success = TRUE;
479                 break;
480             }
481             if (lpszBuffer[nRecv] != '\r')
482                 nRecv++;
483         }
484
485         pSSL_CTX_set_timeout(ctx, prev_timeout);
486         if (success)
487         {
488             lpszBuffer[nRecv] = '\0';
489             *dwBuffer = nRecv - 1;
490             TRACE("_SSL:%d %s\n", nRecv, lpszBuffer);
491             return TRUE;
492         }
493         return FALSE;
494 #else
495         return FALSE;
496 #endif
497     }
498 }