documented updates
[gnutls.git] / lib / system.c
blobb22e07d590fd85d8d7f8942a92ad41216b3fdd36
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>
31 #ifdef _WIN32
32 # include <windows.h>
33 # include <wincrypt.h>
34 # if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
35 typedef PCCRL_CONTEXT WINAPI (*Type_CertEnumCRLsInStore) (HCERTSTORE hCertStore, PCCRL_CONTEXT pPrevCrlContext);
36 static Type_CertEnumCRLsInStore Loaded_CertEnumCRLsInStore;
37 static HMODULE Crypt32_dll;
38 # endif
40 #else
41 # ifdef HAVE_PTHREAD_LOCKS
42 # include <pthread.h>
43 # endif
45 # if defined(HAVE_GETPWUID_R)
46 # include <pwd.h>
47 # endif
48 #endif
50 /* We need to disable gnulib's replacement wrappers to get native
51 Windows interfaces. */
52 #undef recv
53 #undef send
54 #undef select
56 /* System specific function wrappers.
59 #ifdef _WIN32
60 int
61 system_errno (gnutls_transport_ptr p)
63 int tmperr = WSAGetLastError ();
64 int ret = 0;
65 switch (tmperr)
67 case WSAEWOULDBLOCK:
68 ret = EAGAIN;
69 break;
70 case NO_ERROR:
71 ret = 0;
72 break;
73 case WSAEINTR:
74 ret = EINTR;
75 break;
76 case WSAEMSGSIZE:
77 ret = EMSGSIZE;
78 break;
79 default:
80 ret = EIO;
81 break;
83 WSASetLastError (tmperr);
85 return ret;
88 ssize_t
89 system_write (gnutls_transport_ptr ptr, const void *data, size_t data_size)
91 return send (GNUTLS_POINTER_TO_INT (ptr), data, data_size, 0);
93 #else /* POSIX */
94 int
95 system_errno (gnutls_transport_ptr_t ptr)
97 #if defined(_AIX) || defined(AIX)
98 if (errno == 0) errno = EAGAIN;
99 #endif
101 return errno;
104 ssize_t
105 system_writev (gnutls_transport_ptr_t ptr, const giovec_t * iovec,
106 int iovec_cnt)
108 return writev (GNUTLS_POINTER_TO_INT (ptr), (struct iovec *) iovec,
109 iovec_cnt);
112 #endif
114 ssize_t
115 system_read (gnutls_transport_ptr_t ptr, void *data, size_t data_size)
117 return recv (GNUTLS_POINTER_TO_INT (ptr), data, data_size, 0);
120 /* Wait for data to be received within a timeout period in milliseconds.
121 * To catch a termination it will also try to receive 0 bytes from the
122 * socket if select reports to proceed.
124 * Returns -1 on error, 0 on timeout, positive value if data are available for reading.
126 int system_recv_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
128 fd_set rfds;
129 struct timeval tv;
130 int ret;
131 int fd = GNUTLS_POINTER_TO_INT(ptr);
133 FD_ZERO(&rfds);
134 FD_SET(fd, &rfds);
136 tv.tv_sec = 0;
137 tv.tv_usec = ms * 1000;
139 while(tv.tv_usec >= 1000000)
141 tv.tv_usec -= 1000000;
142 tv.tv_sec++;
145 ret = select(fd+1, &rfds, NULL, NULL, &tv);
146 if (ret <= 0)
147 return ret;
149 return ret;
152 /* Thread stuff */
154 #ifdef HAVE_WIN32_LOCKS
155 static int
156 gnutls_system_mutex_init (void **priv)
158 CRITICAL_SECTION *lock = malloc (sizeof (CRITICAL_SECTION));
160 if (lock == NULL)
161 return GNUTLS_E_MEMORY_ERROR;
163 InitializeCriticalSection (lock);
165 *priv = lock;
167 return 0;
170 static int
171 gnutls_system_mutex_deinit (void **priv)
173 DeleteCriticalSection ((CRITICAL_SECTION *) * priv);
174 free (*priv);
176 return 0;
179 static int
180 gnutls_system_mutex_lock (void **priv)
182 EnterCriticalSection ((CRITICAL_SECTION *) * priv);
183 return 0;
186 static int
187 gnutls_system_mutex_unlock (void **priv)
189 LeaveCriticalSection ((CRITICAL_SECTION *) * priv);
190 return 0;
193 #endif /* WIN32_LOCKS */
195 #ifdef HAVE_PTHREAD_LOCKS
197 static int
198 gnutls_system_mutex_init (void **priv)
200 pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t));
201 int ret;
203 if (lock == NULL)
204 return GNUTLS_E_MEMORY_ERROR;
206 ret = pthread_mutex_init (lock, NULL);
207 if (ret)
209 free (lock);
210 gnutls_assert ();
211 return GNUTLS_E_LOCKING_ERROR;
214 *priv = lock;
216 return 0;
219 static int
220 gnutls_system_mutex_deinit (void **priv)
222 pthread_mutex_destroy ((pthread_mutex_t *) * priv);
223 free (*priv);
224 return 0;
227 static int
228 gnutls_system_mutex_lock (void **priv)
230 if (pthread_mutex_lock ((pthread_mutex_t *) * priv))
232 gnutls_assert ();
233 return GNUTLS_E_LOCKING_ERROR;
236 return 0;
239 static int
240 gnutls_system_mutex_unlock (void **priv)
242 if (pthread_mutex_unlock ((pthread_mutex_t *) * priv))
244 gnutls_assert ();
245 return GNUTLS_E_LOCKING_ERROR;
248 return 0;
251 #endif /* PTHREAD_LOCKS */
253 #ifdef HAVE_NO_LOCKS
255 static int
256 gnutls_system_mutex_init (void **priv)
258 return 0;
261 static int
262 gnutls_system_mutex_deinit (void **priv)
264 return 0;
267 static int
268 gnutls_system_mutex_lock (void **priv)
270 return 0;
273 static int
274 gnutls_system_mutex_unlock (void **priv)
276 return 0;
279 #endif /* NO_LOCKS */
281 gnutls_time_func gnutls_time = time;
282 mutex_init_func gnutls_mutex_init = gnutls_system_mutex_init;
283 mutex_deinit_func gnutls_mutex_deinit = gnutls_system_mutex_deinit;
284 mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock;
285 mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock;
288 gnutls_system_global_init ()
290 #ifdef _WIN32
291 # if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
292 HMODULE crypto;
293 crypto = LoadLibraryA ("Crypt32.dll");
295 if (crypto == NULL)
296 return GNUTLS_E_CRYPTO_INIT_FAILED;
298 Loaded_CertEnumCRLsInStore = (Type_CertEnumCRLsInStore) GetProcAddress (crypto, "CertEnumCRLsInStore");
299 if (Loaded_CertEnumCRLsInStore == NULL)
301 FreeLibrary (crypto);
302 return GNUTLS_E_CRYPTO_INIT_FAILED;
305 Crypt32_dll = crypto;
306 # endif
307 #endif
308 return 0;
311 void
312 gnutls_system_global_deinit ()
314 #ifdef _WIN32
315 # if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
316 FreeLibrary (Crypt32_dll);
317 # endif
318 #endif
322 #define CONFIG_PATH ".gnutls"
324 /* Returns a path to store user-specific configuration
325 * data.
327 int _gnutls_find_config_path(char* path, size_t max_size)
329 char tmp_home_dir[1024];
330 const char *home_dir = getenv ("HOME");
332 #ifdef _WIN32
333 if (home_dir == NULL || home_dir[0] == '\0')
335 const char *home_drive = getenv ("HOMEDRIVE");
336 const char *home_path = getenv ("HOMEPATH");
338 if (home_drive != NULL && home_path != NULL)
340 snprintf(tmp_home_dir, sizeof(tmp_home_dir), "%s%s", home_drive, home_path);
342 else
344 tmp_home_dir[0] = 0;
347 home_dir = tmp_home_dir;
349 #elif defined(HAVE_GETPWUID_R)
350 if (home_dir == NULL || home_dir[0] == '\0')
352 struct passwd *pwd;
353 struct passwd _pwd;
354 char buf[1024];
356 getpwuid_r(getuid(), &_pwd, buf, sizeof(buf), &pwd);
357 if (pwd != NULL)
359 snprintf(tmp_home_dir, sizeof(tmp_home_dir), "%s", pwd->pw_dir);
361 else
363 tmp_home_dir[0] = 0;
366 home_dir = tmp_home_dir;
368 #else
369 if (home_dir == NULL || home_dir[0] == '\0')
371 tmp_home_dir[0] = 0;
372 home_dir = tmp_home_dir;
374 #endif
376 if (home_dir == NULL || home_dir[0] == 0)
377 path[0] = 0;
378 else
379 snprintf(path, max_size, "%s/"CONFIG_PATH, home_dir);
381 return 0;
385 * gnutls_x509_trust_list_add_system_trust:
386 * @list: The structure of the list
387 * @tl_flags: GNUTLS_TL_*
388 * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
390 * This function adds the system's default trusted certificate
391 * authorities to the trusted list. Note that on unsupported system
392 * this function returns %GNUTLS_E_UNIMPLEMENTED_FEATURE.
394 * Returns: The number of added elements or a negative error code on error.
396 * Since: 3.1
399 gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list,
400 unsigned int tl_flags, unsigned int tl_vflags)
402 #if !defined(DEFAULT_TRUST_STORE_PKCS11) && !defined(DEFAULT_TRUST_STORE_FILE) && !defined(_WIN32)
403 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
404 #else
405 int ret, r = 0;
406 const char* crl_file =
407 # ifdef DEFAULT_CRL_FILE
408 DEFAULT_CRL_FILE;
409 # else
410 NULL;
411 # endif
413 # ifdef _WIN32
414 unsigned int i;
416 for (i=0;i<2;i++)
418 HCERTSTORE store;
419 const CERT_CONTEXT *cert;
420 const CRL_CONTEXT *crl;
421 gnutls_datum_t data;
423 if (i==0) store = CertOpenSystemStore(0, "ROOT");
424 else store = CertOpenSystemStore(0, "CA");
426 if (store == NULL) return GNUTLS_E_FILE_ERROR;
428 cert = CertEnumCertificatesInStore(store, NULL);
429 crl = Loaded_CertEnumCRLsInStore(store, NULL);
431 while(cert != NULL)
433 if (cert->dwCertEncodingType == X509_ASN_ENCODING)
435 data.data = cert->pbCertEncoded;
436 data.size = cert->cbCertEncoded;
437 if (gnutls_x509_trust_list_add_trust_mem(list, &data, NULL, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags) > 0)
438 r++;
440 cert = CertEnumCertificatesInStore(store, cert);
443 while(crl != NULL)
445 if (crl->dwCertEncodingType == X509_ASN_ENCODING)
447 data.data = crl->pbCrlEncoded;
448 data.size = crl->cbCrlEncoded;
449 gnutls_x509_trust_list_add_trust_mem(list, NULL, &data, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags);
451 crl = Loaded_CertEnumCRLsInStore(store, crl);
453 CertCloseStore(store, 0);
455 # endif
457 # if defined(ENABLE_PKCS11) && defined(DEFAULT_TRUST_STORE_PKCS11)
458 ret = gnutls_x509_trust_list_add_trust_file(list, DEFAULT_TRUST_STORE_PKCS11, crl_file,
459 GNUTLS_X509_FMT_DER, tl_flags, tl_vflags);
460 if (ret > 0)
461 r += ret;
462 # endif
464 # ifdef DEFAULT_TRUST_STORE_FILE
465 ret = gnutls_x509_trust_list_add_trust_file(list, DEFAULT_TRUST_STORE_FILE, crl_file,
466 GNUTLS_X509_FMT_PEM, tl_flags, tl_vflags);
467 if (ret > 0)
468 r += ret;
469 # endif
470 return r;
471 #endif