check for either iconv or libiconv.
[gnutls:gnutls.git] / lib / system.c
1 /*
2  * Copyright (C) 2010-2012 Free Software Foundation, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * The GnuTLS is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 3 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * 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 License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>
20  *
21  */
22
23 #include <system.h>
24 #include <gnutls_int.h>
25 #include <gnutls_errors.h>
26
27 #include <errno.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <c-ctype.h>
31
32 #ifdef _WIN32
33 # include <windows.h>
34 # include <wincrypt.h>
35 #  if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
36 typedef PCCRL_CONTEXT WINAPI (*Type_CertEnumCRLsInStore) (HCERTSTORE hCertStore, PCCRL_CONTEXT pPrevCrlContext);
37 static Type_CertEnumCRLsInStore Loaded_CertEnumCRLsInStore;
38 static HMODULE Crypt32_dll;
39 #  else
40 #   define Loaded_CertEnumCRLsInStore CertEnumCRLsInStore
41 #  endif
42 #else
43 # ifdef HAVE_PTHREAD_LOCKS
44 #  include <pthread.h>
45 # endif
46
47 # if defined(HAVE_GETPWUID_R)
48 #  include <pwd.h>
49 # endif
50 #endif
51
52 /* We need to disable gnulib's replacement wrappers to get native
53    Windows interfaces. */
54 #undef recv
55 #undef send
56 #undef select
57
58 /* System specific function wrappers.
59  */
60
61 #ifdef _WIN32
62 int
63 system_errno (gnutls_transport_ptr p)
64 {
65   int tmperr = WSAGetLastError ();
66   int ret = 0;
67   switch (tmperr)
68     {
69     case WSAEWOULDBLOCK:
70       ret = EAGAIN;
71       break;
72     case NO_ERROR:
73       ret = 0;
74       break;
75     case WSAEINTR:
76       ret = EINTR;
77       break;
78     case WSAEMSGSIZE:
79       ret = EMSGSIZE;
80       break;
81     default:
82       ret = EIO;
83       break;
84     }
85   WSASetLastError (tmperr);
86
87   return ret;
88 }
89
90 ssize_t
91 system_write (gnutls_transport_ptr ptr, const void *data, size_t data_size)
92 {
93   return send (GNUTLS_POINTER_TO_INT (ptr), data, data_size, 0);
94 }
95 #else /* POSIX */
96 int
97 system_errno (gnutls_transport_ptr_t ptr)
98 {
99 #if defined(_AIX) || defined(AIX)
100   if (errno == 0) errno = EAGAIN;
101 #endif
102
103   return errno;
104 }
105
106 ssize_t
107 system_writev (gnutls_transport_ptr_t ptr, const giovec_t * iovec,
108                int iovec_cnt)
109 {
110   return writev (GNUTLS_POINTER_TO_INT (ptr), (struct iovec *) iovec,
111                  iovec_cnt);
112
113 }
114 #endif
115
116 ssize_t
117 system_read (gnutls_transport_ptr_t ptr, void *data, size_t data_size)
118 {
119   return recv (GNUTLS_POINTER_TO_INT (ptr), data, data_size, 0);
120 }
121
122 /* Wait for data to be received within a timeout period in milliseconds.
123  * To catch a termination it will also try to receive 0 bytes from the
124  * socket if select reports to proceed.
125  *
126  * Returns -1 on error, 0 on timeout, positive value if data are available for reading.
127  */
128 int system_recv_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
129 {
130 fd_set rfds;
131 struct timeval tv;
132 int ret;
133 int fd = GNUTLS_POINTER_TO_INT(ptr);
134
135   FD_ZERO(&rfds);
136   FD_SET(fd, &rfds);
137   
138   tv.tv_sec = 0;
139   tv.tv_usec = ms * 1000;
140   
141   while(tv.tv_usec >= 1000000)
142     {
143       tv.tv_usec -= 1000000;
144       tv.tv_sec++;
145     }
146   
147   ret = select(fd+1, &rfds, NULL, NULL, &tv);
148   if (ret <= 0)
149     return ret;
150
151   return ret;
152 }
153
154 /* Thread stuff */
155
156 #ifdef HAVE_WIN32_LOCKS
157 static int
158 gnutls_system_mutex_init (void **priv)
159 {
160   CRITICAL_SECTION *lock = malloc (sizeof (CRITICAL_SECTION));
161
162   if (lock == NULL)
163     return GNUTLS_E_MEMORY_ERROR;
164
165   InitializeCriticalSection (lock);
166
167   *priv = lock;
168
169   return 0;
170 }
171
172 static int
173 gnutls_system_mutex_deinit (void **priv)
174 {
175   DeleteCriticalSection ((CRITICAL_SECTION *) * priv);
176   free (*priv);
177
178   return 0;
179 }
180
181 static int
182 gnutls_system_mutex_lock (void **priv)
183 {
184   EnterCriticalSection ((CRITICAL_SECTION *) * priv);
185   return 0;
186 }
187
188 static int
189 gnutls_system_mutex_unlock (void **priv)
190 {
191   LeaveCriticalSection ((CRITICAL_SECTION *) * priv);
192   return 0;
193 }
194
195 #endif /* WIN32_LOCKS */
196
197 #ifdef HAVE_PTHREAD_LOCKS
198
199 static int
200 gnutls_system_mutex_init (void **priv)
201 {
202   pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t));
203   int ret;
204
205   if (lock == NULL)
206     return GNUTLS_E_MEMORY_ERROR;
207
208   ret = pthread_mutex_init (lock, NULL);
209   if (ret)
210     {
211       free (lock);
212       gnutls_assert ();
213       return GNUTLS_E_LOCKING_ERROR;
214     }
215
216   *priv = lock;
217
218   return 0;
219 }
220
221 static int
222 gnutls_system_mutex_deinit (void **priv)
223 {
224   pthread_mutex_destroy ((pthread_mutex_t *) * priv);
225   free (*priv);
226   return 0;
227 }
228
229 static int
230 gnutls_system_mutex_lock (void **priv)
231 {
232   if (pthread_mutex_lock ((pthread_mutex_t *) * priv))
233     {
234       gnutls_assert ();
235       return GNUTLS_E_LOCKING_ERROR;
236     }
237
238   return 0;
239 }
240
241 static int
242 gnutls_system_mutex_unlock (void **priv)
243 {
244   if (pthread_mutex_unlock ((pthread_mutex_t *) * priv))
245     {
246       gnutls_assert ();
247       return GNUTLS_E_LOCKING_ERROR;
248     }
249
250   return 0;
251 }
252
253 #endif /* PTHREAD_LOCKS */
254
255 #ifdef HAVE_NO_LOCKS
256
257 static int
258 gnutls_system_mutex_init (void **priv)
259 {
260   return 0;
261 }
262
263 static int
264 gnutls_system_mutex_deinit (void **priv)
265 {
266   return 0;
267 }
268
269 static int
270 gnutls_system_mutex_lock (void **priv)
271 {
272   return 0;
273 }
274
275 static int
276 gnutls_system_mutex_unlock (void **priv)
277 {
278   return 0;
279 }
280
281 #endif /* NO_LOCKS */
282
283 gnutls_time_func gnutls_time = time;
284 mutex_init_func gnutls_mutex_init = gnutls_system_mutex_init;
285 mutex_deinit_func gnutls_mutex_deinit = gnutls_system_mutex_deinit;
286 mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock;
287 mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock;
288
289 int
290 gnutls_system_global_init ()
291 {
292 #ifdef _WIN32
293 # if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
294   HMODULE crypto;
295   crypto = LoadLibraryA ("Crypt32.dll");
296
297   if (crypto == NULL)
298     return GNUTLS_E_CRYPTO_INIT_FAILED;
299
300   Loaded_CertEnumCRLsInStore = (Type_CertEnumCRLsInStore) GetProcAddress (crypto, "CertEnumCRLsInStore");
301   if (Loaded_CertEnumCRLsInStore == NULL)
302     {
303       FreeLibrary (crypto);
304       return GNUTLS_E_CRYPTO_INIT_FAILED;
305     }
306
307   Crypt32_dll = crypto;
308 # endif
309 #endif
310   return 0;
311 }
312
313 void
314 gnutls_system_global_deinit ()
315 {
316 #ifdef _WIN32
317 # if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
318   FreeLibrary (Crypt32_dll);
319 # endif
320 #endif
321 }
322
323
324 #define CONFIG_PATH ".gnutls"
325
326 /* Returns a path to store user-specific configuration
327  * data.
328  */
329 int _gnutls_find_config_path(char* path, size_t max_size)
330 {
331 char tmp_home_dir[1024];
332 const char *home_dir = getenv ("HOME");
333
334 #ifdef _WIN32
335   if (home_dir == NULL || home_dir[0] == '\0')
336     {
337       const char *home_drive = getenv ("HOMEDRIVE");
338       const char *home_path = getenv ("HOMEPATH");
339
340       if (home_drive != NULL && home_path != NULL)
341         {
342           snprintf(tmp_home_dir, sizeof(tmp_home_dir), "%s%s", home_drive, home_path);
343         }
344       else
345         {
346           tmp_home_dir[0] = 0;
347         }
348       
349       home_dir = tmp_home_dir;
350     }
351 #elif defined(HAVE_GETPWUID_R)
352   if (home_dir == NULL || home_dir[0] == '\0')
353     {
354       struct passwd *pwd;
355       struct passwd _pwd;
356       char buf[1024];
357
358       getpwuid_r(getuid(), &_pwd, buf, sizeof(buf), &pwd);
359       if (pwd != NULL)
360         {
361           snprintf(tmp_home_dir, sizeof(tmp_home_dir), "%s", pwd->pw_dir);
362         }
363       else
364         {
365           tmp_home_dir[0] = 0;
366         }
367
368       home_dir = tmp_home_dir;
369     }
370 #else
371   if (home_dir == NULL || home_dir[0] == '\0')
372     {
373       tmp_home_dir[0] = 0;
374       home_dir = tmp_home_dir;
375     }
376 #endif
377
378   if (home_dir == NULL || home_dir[0] == 0)
379     path[0] = 0;
380   else
381     snprintf(path, max_size, "%s/"CONFIG_PATH, home_dir);
382       
383   return 0;
384 }
385
386 /**
387  * gnutls_x509_trust_list_add_system_trust:
388  * @list: The structure of the list
389  * @tl_flags: GNUTLS_TL_*
390  * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
391  *
392  * This function adds the system's default trusted certificate
393  * authorities to the trusted list. Note that on unsupported system
394  * this function returns %GNUTLS_E_UNIMPLEMENTED_FEATURE.
395  *
396  * Returns: The number of added elements or a negative error code on error.
397  *
398  * Since: 3.1
399  **/
400 int
401 gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list,
402                                         unsigned int tl_flags, unsigned int tl_vflags)
403 {
404 #if !defined(DEFAULT_TRUST_STORE_PKCS11) && !defined(DEFAULT_TRUST_STORE_FILE) && !defined(_WIN32)
405   return GNUTLS_E_UNIMPLEMENTED_FEATURE;
406 #else
407   int ret, r = 0;
408   const char* crl_file = 
409 # ifdef DEFAULT_CRL_FILE
410   DEFAULT_CRL_FILE;
411 # else
412   NULL;
413 # endif
414
415 # ifdef _WIN32
416   unsigned int i;
417
418   for (i=0;i<2;i++)
419   {
420     HCERTSTORE store;
421     const CERT_CONTEXT *cert;
422     const CRL_CONTEXT *crl;
423     gnutls_datum_t data;
424     
425     if (i==0) store = CertOpenSystemStore(0, "ROOT");
426     else store = CertOpenSystemStore(0, "CA");
427
428     if (store == NULL) return GNUTLS_E_FILE_ERROR;
429
430     cert = CertEnumCertificatesInStore(store, NULL);
431     crl = Loaded_CertEnumCRLsInStore(store, NULL);
432
433     while(cert != NULL) 
434       {
435         if (cert->dwCertEncodingType == X509_ASN_ENCODING)
436           {
437             data.data = cert->pbCertEncoded;
438             data.size = cert->cbCertEncoded;
439             if (gnutls_x509_trust_list_add_trust_mem(list, &data, NULL, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags) > 0)
440               r++;
441           }
442         cert = CertEnumCertificatesInStore(store, cert);
443       }
444
445     while(crl != NULL) 
446       {
447         if (crl->dwCertEncodingType == X509_ASN_ENCODING)
448           {
449             data.data = crl->pbCrlEncoded;
450             data.size = crl->cbCrlEncoded;
451             gnutls_x509_trust_list_add_trust_mem(list, NULL, &data, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags);
452           }
453         crl = Loaded_CertEnumCRLsInStore(store, crl);
454       }
455     CertCloseStore(store, 0);
456   }
457 # endif
458
459 # if defined(ENABLE_PKCS11) && defined(DEFAULT_TRUST_STORE_PKCS11)
460   ret = gnutls_x509_trust_list_add_trust_file(list, DEFAULT_TRUST_STORE_PKCS11, crl_file, 
461                                               GNUTLS_X509_FMT_DER, tl_flags, tl_vflags);
462   if (ret > 0)
463     r += ret;
464 # endif
465
466 # ifdef DEFAULT_TRUST_STORE_FILE
467   ret = gnutls_x509_trust_list_add_trust_file(list, DEFAULT_TRUST_STORE_FILE, crl_file, 
468                                               GNUTLS_X509_FMT_PEM, tl_flags, tl_vflags);
469   if (ret > 0)
470     r += ret;
471 # endif
472   return r;
473 #endif
474 }
475
476 #if defined(HAVE_ICONV) || defined(HAVE_LIBICONV)
477
478 # include <iconv.h>
479
480 int _gnutls_ucs2_to_utf8(const void* data, size_t size, gnutls_datum_t *output)
481 {
482 iconv_t conv;
483 int ret;
484 size_t orig, dstlen = size*2;
485 char* src = (void*)data;
486 char* dst, *pdst;
487
488   if (size == 0)
489     return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
490     
491   conv = iconv_open("UTF-8", "UTF-16BE");
492   if (conv == (iconv_t)-1)
493     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
494   
495   pdst = dst = gnutls_malloc(dstlen+1);
496   if (dst == NULL)
497     {
498       ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
499       goto cleanup;
500     }
501
502   orig = dstlen;
503   ret = iconv(conv, &src, &size, &pdst, &dstlen);
504   if (ret == -1)
505     {
506       ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
507       goto cleanup;
508     }
509     
510
511   output->data = (void*)dst;
512   output->size = orig-dstlen;
513   output->data[output->size] = 0;
514
515   ret = 0;
516   
517 cleanup:
518   iconv_close(conv);
519   
520   return ret;
521 }
522 #elif defined(_WIN32)
523 #include <winnls.h>
524
525 /* Can convert only english */
526 int _gnutls_ucs2_to_utf8(const void* data, size_t size, gnutls_datum_t *output)
527 {
528 int ret;
529 unsigned i;
530 int len = 0, src_len;
531 char* dst = NULL;
532 char* src = NULL;
533
534   src_len = size/2;
535
536   src = gnutls_malloc(size);
537   if (src == NULL)
538     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
539
540   /* convert to LE */
541   for (i=0;i<size;i+=2)
542     {
543       src[i] = ((char*)data)[1+i];
544       src[1+i] = ((char*)data)[i];
545     }
546   
547   ret = WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS, (void*)src, src_len,
548                             NULL, 0, NULL, NULL);
549   if (ret == 0)
550     {
551       ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
552       goto fail;
553     }
554
555   len = ret+1;
556   dst = gnutls_malloc(len);
557   if (dst == NULL)
558     {
559       ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
560       goto fail;
561     }
562   
563   ret = WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS, (void*)src, src_len,
564                             dst, len, NULL, NULL);
565   if (ret == 0)
566     {
567       ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
568       goto fail;
569     }
570   
571   output->data = dst;
572   output->size = ret;
573   ret = 0;
574   goto cleanup;
575   
576 fail:
577   gnutls_free(dst);
578
579 cleanup:
580   gnutls_free(src);
581   return ret;
582 }
583
584 #else
585
586 /* Can convert only english (ASCII) */
587 int _gnutls_ucs2_to_utf8(const void* data, size_t size, gnutls_datum_t *output)
588 {
589 unsigned int i, j;
590 char* dst;
591 const char *src = data;
592
593   if (size == 0 || size % 2 != 0)
594     return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
595
596   dst = gnutls_malloc(size+1);
597   if (dst == NULL)
598     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
599
600   for (i=j=0;i<size;i+=2,j++)
601     {
602       if (src[i] != 0 || !isascii(src[i+1]))
603         return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
604       dst[j] = src[i+1];
605     }
606     
607   output->data = (void*)dst;
608   output->size = j;
609   output->data[output->size] = 0;
610
611   return 0;
612 }
613 #endif