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