corrected copyright notices
[gnutls.git] / lib / system.c
blob834266759e3b42f19b171e4f757fe9f7d8033ee3
1 /*
2 * Copyright (C) 2010-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
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.
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.
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/>
23 #include <system.h>
24 #include <gnutls_int.h>
25 #include <gnutls_errors.h>
27 #include <errno.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <c-ctype.h>
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
47 # if defined(HAVE_GETPWUID_R)
48 # include <pwd.h>
49 # endif
50 #endif
52 /* We need to disable gnulib's replacement wrappers to get native
53 Windows interfaces. */
54 #undef recv
55 #undef send
56 #undef select
58 /* System specific function wrappers.
61 #ifdef _WIN32
62 int
63 system_errno (gnutls_transport_ptr p)
65 int tmperr = WSAGetLastError ();
66 int ret = 0;
67 switch (tmperr)
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;
85 WSASetLastError (tmperr);
87 return ret;
90 ssize_t
91 system_write (gnutls_transport_ptr ptr, const void *data, size_t data_size)
93 return send (GNUTLS_POINTER_TO_INT (ptr), data, data_size, 0);
95 #else /* POSIX */
96 int
97 system_errno (gnutls_transport_ptr_t ptr)
99 #if defined(_AIX) || defined(AIX)
100 if (errno == 0) errno = EAGAIN;
101 #endif
103 return errno;
106 ssize_t
107 system_writev (gnutls_transport_ptr_t ptr, const giovec_t * iovec,
108 int iovec_cnt)
110 return writev (GNUTLS_POINTER_TO_INT (ptr), (struct iovec *) iovec,
111 iovec_cnt);
114 #endif
116 ssize_t
117 system_read (gnutls_transport_ptr_t ptr, void *data, size_t data_size)
119 return recv (GNUTLS_POINTER_TO_INT (ptr), data, data_size, 0);
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.
126 * Returns -1 on error, 0 on timeout, positive value if data are available for reading.
128 int system_recv_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
130 fd_set rfds;
131 struct timeval tv;
132 int ret;
133 int fd = GNUTLS_POINTER_TO_INT(ptr);
135 FD_ZERO(&rfds);
136 FD_SET(fd, &rfds);
138 tv.tv_sec = 0;
139 tv.tv_usec = ms * 1000;
141 while(tv.tv_usec >= 1000000)
143 tv.tv_usec -= 1000000;
144 tv.tv_sec++;
147 ret = select(fd+1, &rfds, NULL, NULL, &tv);
148 if (ret <= 0)
149 return ret;
151 return ret;
154 /* Thread stuff */
156 #ifdef HAVE_WIN32_LOCKS
157 static int
158 gnutls_system_mutex_init (void **priv)
160 CRITICAL_SECTION *lock = malloc (sizeof (CRITICAL_SECTION));
162 if (lock == NULL)
163 return GNUTLS_E_MEMORY_ERROR;
165 InitializeCriticalSection (lock);
167 *priv = lock;
169 return 0;
172 static int
173 gnutls_system_mutex_deinit (void **priv)
175 DeleteCriticalSection ((CRITICAL_SECTION *) * priv);
176 free (*priv);
178 return 0;
181 static int
182 gnutls_system_mutex_lock (void **priv)
184 EnterCriticalSection ((CRITICAL_SECTION *) * priv);
185 return 0;
188 static int
189 gnutls_system_mutex_unlock (void **priv)
191 LeaveCriticalSection ((CRITICAL_SECTION *) * priv);
192 return 0;
195 #endif /* WIN32_LOCKS */
197 #ifdef HAVE_PTHREAD_LOCKS
199 static int
200 gnutls_system_mutex_init (void **priv)
202 pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t));
203 int ret;
205 if (lock == NULL)
206 return GNUTLS_E_MEMORY_ERROR;
208 ret = pthread_mutex_init (lock, NULL);
209 if (ret)
211 free (lock);
212 gnutls_assert ();
213 return GNUTLS_E_LOCKING_ERROR;
216 *priv = lock;
218 return 0;
221 static int
222 gnutls_system_mutex_deinit (void **priv)
224 pthread_mutex_destroy ((pthread_mutex_t *) * priv);
225 free (*priv);
226 return 0;
229 static int
230 gnutls_system_mutex_lock (void **priv)
232 if (pthread_mutex_lock ((pthread_mutex_t *) * priv))
234 gnutls_assert ();
235 return GNUTLS_E_LOCKING_ERROR;
238 return 0;
241 static int
242 gnutls_system_mutex_unlock (void **priv)
244 if (pthread_mutex_unlock ((pthread_mutex_t *) * priv))
246 gnutls_assert ();
247 return GNUTLS_E_LOCKING_ERROR;
250 return 0;
253 #endif /* PTHREAD_LOCKS */
255 #ifdef HAVE_NO_LOCKS
257 static int
258 gnutls_system_mutex_init (void **priv)
260 return 0;
263 static int
264 gnutls_system_mutex_deinit (void **priv)
266 return 0;
269 static int
270 gnutls_system_mutex_lock (void **priv)
272 return 0;
275 static int
276 gnutls_system_mutex_unlock (void **priv)
278 return 0;
281 #endif /* NO_LOCKS */
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;
290 gnutls_system_global_init ()
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");
297 if (crypto == NULL)
298 return GNUTLS_E_CRYPTO_INIT_FAILED;
300 Loaded_CertEnumCRLsInStore = (Type_CertEnumCRLsInStore) GetProcAddress (crypto, "CertEnumCRLsInStore");
301 if (Loaded_CertEnumCRLsInStore == NULL)
303 FreeLibrary (crypto);
304 return GNUTLS_E_CRYPTO_INIT_FAILED;
307 Crypt32_dll = crypto;
308 # endif
309 #endif
310 return 0;
313 void
314 gnutls_system_global_deinit ()
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
324 #define CONFIG_PATH ".gnutls"
326 /* Returns a path to store user-specific configuration
327 * data.
329 int _gnutls_find_config_path(char* path, size_t max_size)
331 char tmp_home_dir[1024];
332 const char *home_dir = getenv ("HOME");
334 #ifdef _WIN32
335 if (home_dir == NULL || home_dir[0] == '\0')
337 const char *home_drive = getenv ("HOMEDRIVE");
338 const char *home_path = getenv ("HOMEPATH");
340 if (home_drive != NULL && home_path != NULL)
342 snprintf(tmp_home_dir, sizeof(tmp_home_dir), "%s%s", home_drive, home_path);
344 else
346 tmp_home_dir[0] = 0;
349 home_dir = tmp_home_dir;
351 #elif defined(HAVE_GETPWUID_R)
352 if (home_dir == NULL || home_dir[0] == '\0')
354 struct passwd *pwd;
355 struct passwd _pwd;
356 char buf[1024];
358 getpwuid_r(getuid(), &_pwd, buf, sizeof(buf), &pwd);
359 if (pwd != NULL)
361 snprintf(tmp_home_dir, sizeof(tmp_home_dir), "%s", pwd->pw_dir);
363 else
365 tmp_home_dir[0] = 0;
368 home_dir = tmp_home_dir;
370 #else
371 if (home_dir == NULL || home_dir[0] == '\0')
373 tmp_home_dir[0] = 0;
374 home_dir = tmp_home_dir;
376 #endif
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);
383 return 0;
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
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.
396 * Returns: The number of added elements or a negative error code on error.
398 * Since: 3.1
401 gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list,
402 unsigned int tl_flags, unsigned int tl_vflags)
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
415 # ifdef _WIN32
416 unsigned int i;
418 for (i=0;i<2;i++)
420 HCERTSTORE store;
421 const CERT_CONTEXT *cert;
422 const CRL_CONTEXT *crl;
423 gnutls_datum_t data;
425 if (i==0) store = CertOpenSystemStore(0, "ROOT");
426 else store = CertOpenSystemStore(0, "CA");
428 if (store == NULL) return GNUTLS_E_FILE_ERROR;
430 cert = CertEnumCertificatesInStore(store, NULL);
431 crl = Loaded_CertEnumCRLsInStore(store, NULL);
433 while(cert != NULL)
435 if (cert->dwCertEncodingType == X509_ASN_ENCODING)
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++;
442 cert = CertEnumCertificatesInStore(store, cert);
445 while(crl != NULL)
447 if (crl->dwCertEncodingType == X509_ASN_ENCODING)
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);
453 crl = Loaded_CertEnumCRLsInStore(store, crl);
455 CertCloseStore(store, 0);
457 # endif
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
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
476 #if defined(HAVE_ICONV)
478 # include <iconv.h>
480 int _gnutls_ucs2_to_utf8(const void* data, size_t size, gnutls_datum_t *output)
482 iconv_t conv;
483 int ret;
484 size_t orig, dstlen = size*2;
485 char* src = (void*)data;
486 char* dst = NULL, *pdst;
488 if (size == 0)
489 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
491 conv = iconv_open("UTF-8", "UTF-16BE");
492 if (conv == (iconv_t)-1)
493 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
495 /* Note that dstlen has enough size for every possible input characters.
496 * (remember the in UTF-16 the characters in data are at most size/2,
497 * and we allocate 4 bytes per character).
499 pdst = dst = gnutls_malloc(dstlen+1);
500 if (dst == NULL)
502 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
503 goto fail;
506 orig = dstlen;
507 ret = iconv(conv, &src, &size, &pdst, &dstlen);
508 if (ret == -1)
510 ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
511 goto fail;
514 output->data = (void*)dst;
515 output->size = orig-dstlen;
516 output->data[output->size] = 0;
518 ret = 0;
519 goto cleanup;
521 fail:
522 gnutls_free(dst);
524 cleanup:
525 iconv_close(conv);
527 return ret;
529 #elif defined(_WIN32)
530 #include <winnls.h>
532 /* Can convert only english */
533 int _gnutls_ucs2_to_utf8(const void* data, size_t size, gnutls_datum_t *output)
535 int ret;
536 unsigned i;
537 int len = 0, src_len;
538 char* dst = NULL;
539 char* src = NULL;
541 src_len = size/2;
543 src = gnutls_malloc(size);
544 if (src == NULL)
545 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
547 /* convert to LE */
548 for (i=0;i<size;i+=2)
550 src[i] = ((char*)data)[1+i];
551 src[1+i] = ((char*)data)[i];
554 ret = WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS, (void*)src, src_len,
555 NULL, 0, NULL, NULL);
556 if (ret == 0)
558 ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
559 goto fail;
562 len = ret+1;
563 dst = gnutls_malloc(len);
564 if (dst == NULL)
566 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
567 goto fail;
570 ret = WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS, (void*)src, src_len,
571 dst, len, NULL, NULL);
572 if (ret == 0)
574 ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
575 goto fail;
578 output->data = dst;
579 output->size = ret;
580 ret = 0;
581 goto cleanup;
583 fail:
584 gnutls_free(dst);
586 cleanup:
587 gnutls_free(src);
588 return ret;
591 #else
593 /* Can convert only english (ASCII) */
594 int _gnutls_ucs2_to_utf8(const void* data, size_t size, gnutls_datum_t *output)
596 unsigned int i, j;
597 char* dst;
598 const char *src = data;
600 if (size == 0 || size % 2 != 0)
601 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
603 dst = gnutls_malloc(size+1);
604 if (dst == NULL)
605 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
607 for (i=j=0;i<size;i+=2,j++)
609 if (src[i] != 0 || !isascii(src[i+1]))
610 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
611 dst[j] = src[i+1];
614 output->data = (void*)dst;
615 output->size = j;
616 output->data[output->size] = 0;
618 return 0;
620 #endif