Made error code consistent with the other text parsing functions.
[gnutls.git] / lib / system.c
blob39a65a3aa95743127d6f45392f69dc2997b84b31
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 # else
39 # define Loaded_CertEnumCRLsInStore CertEnumCRLsInStore
40 # endif
41 #else
42 # ifdef HAVE_PTHREAD_LOCKS
43 # include <pthread.h>
44 # endif
46 # if defined(HAVE_GETPWUID_R)
47 # include <pwd.h>
48 # endif
49 #endif
51 /* We need to disable gnulib's replacement wrappers to get native
52 Windows interfaces. */
53 #undef recv
54 #undef send
55 #undef select
57 /* System specific function wrappers.
60 #ifdef _WIN32
61 int
62 system_errno (gnutls_transport_ptr p)
64 int tmperr = WSAGetLastError ();
65 int ret = 0;
66 switch (tmperr)
68 case WSAEWOULDBLOCK:
69 ret = EAGAIN;
70 break;
71 case NO_ERROR:
72 ret = 0;
73 break;
74 case WSAEINTR:
75 ret = EINTR;
76 break;
77 case WSAEMSGSIZE:
78 ret = EMSGSIZE;
79 break;
80 default:
81 ret = EIO;
82 break;
84 WSASetLastError (tmperr);
86 return ret;
89 ssize_t
90 system_write (gnutls_transport_ptr ptr, const void *data, size_t data_size)
92 return send (GNUTLS_POINTER_TO_INT (ptr), data, data_size, 0);
94 #else /* POSIX */
95 int
96 system_errno (gnutls_transport_ptr_t ptr)
98 #if defined(_AIX) || defined(AIX)
99 if (errno == 0) errno = EAGAIN;
100 #endif
102 return errno;
105 ssize_t
106 system_writev (gnutls_transport_ptr_t ptr, const giovec_t * iovec,
107 int iovec_cnt)
109 return writev (GNUTLS_POINTER_TO_INT (ptr), (struct iovec *) iovec,
110 iovec_cnt);
113 #endif
115 ssize_t
116 system_read (gnutls_transport_ptr_t ptr, void *data, size_t data_size)
118 return recv (GNUTLS_POINTER_TO_INT (ptr), data, data_size, 0);
121 /* Wait for data to be received within a timeout period in milliseconds.
122 * To catch a termination it will also try to receive 0 bytes from the
123 * socket if select reports to proceed.
125 * Returns -1 on error, 0 on timeout, positive value if data are available for reading.
127 int system_recv_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
129 fd_set rfds;
130 struct timeval tv;
131 int ret;
132 int fd = GNUTLS_POINTER_TO_INT(ptr);
134 FD_ZERO(&rfds);
135 FD_SET(fd, &rfds);
137 tv.tv_sec = 0;
138 tv.tv_usec = ms * 1000;
140 while(tv.tv_usec >= 1000000)
142 tv.tv_usec -= 1000000;
143 tv.tv_sec++;
146 ret = select(fd+1, &rfds, NULL, NULL, &tv);
147 if (ret <= 0)
148 return ret;
150 return ret;
153 /* Thread stuff */
155 #ifdef HAVE_WIN32_LOCKS
156 static int
157 gnutls_system_mutex_init (void **priv)
159 CRITICAL_SECTION *lock = malloc (sizeof (CRITICAL_SECTION));
161 if (lock == NULL)
162 return GNUTLS_E_MEMORY_ERROR;
164 InitializeCriticalSection (lock);
166 *priv = lock;
168 return 0;
171 static int
172 gnutls_system_mutex_deinit (void **priv)
174 DeleteCriticalSection ((CRITICAL_SECTION *) * priv);
175 free (*priv);
177 return 0;
180 static int
181 gnutls_system_mutex_lock (void **priv)
183 EnterCriticalSection ((CRITICAL_SECTION *) * priv);
184 return 0;
187 static int
188 gnutls_system_mutex_unlock (void **priv)
190 LeaveCriticalSection ((CRITICAL_SECTION *) * priv);
191 return 0;
194 #endif /* WIN32_LOCKS */
196 #ifdef HAVE_PTHREAD_LOCKS
198 static int
199 gnutls_system_mutex_init (void **priv)
201 pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t));
202 int ret;
204 if (lock == NULL)
205 return GNUTLS_E_MEMORY_ERROR;
207 ret = pthread_mutex_init (lock, NULL);
208 if (ret)
210 free (lock);
211 gnutls_assert ();
212 return GNUTLS_E_LOCKING_ERROR;
215 *priv = lock;
217 return 0;
220 static int
221 gnutls_system_mutex_deinit (void **priv)
223 pthread_mutex_destroy ((pthread_mutex_t *) * priv);
224 free (*priv);
225 return 0;
228 static int
229 gnutls_system_mutex_lock (void **priv)
231 if (pthread_mutex_lock ((pthread_mutex_t *) * priv))
233 gnutls_assert ();
234 return GNUTLS_E_LOCKING_ERROR;
237 return 0;
240 static int
241 gnutls_system_mutex_unlock (void **priv)
243 if (pthread_mutex_unlock ((pthread_mutex_t *) * priv))
245 gnutls_assert ();
246 return GNUTLS_E_LOCKING_ERROR;
249 return 0;
252 #endif /* PTHREAD_LOCKS */
254 #ifdef HAVE_NO_LOCKS
256 static int
257 gnutls_system_mutex_init (void **priv)
259 return 0;
262 static int
263 gnutls_system_mutex_deinit (void **priv)
265 return 0;
268 static int
269 gnutls_system_mutex_lock (void **priv)
271 return 0;
274 static int
275 gnutls_system_mutex_unlock (void **priv)
277 return 0;
280 #endif /* NO_LOCKS */
282 gnutls_time_func gnutls_time = time;
283 mutex_init_func gnutls_mutex_init = gnutls_system_mutex_init;
284 mutex_deinit_func gnutls_mutex_deinit = gnutls_system_mutex_deinit;
285 mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock;
286 mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock;
289 gnutls_system_global_init ()
291 #ifdef _WIN32
292 # if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
293 HMODULE crypto;
294 crypto = LoadLibraryA ("Crypt32.dll");
296 if (crypto == NULL)
297 return GNUTLS_E_CRYPTO_INIT_FAILED;
299 Loaded_CertEnumCRLsInStore = (Type_CertEnumCRLsInStore) GetProcAddress (crypto, "CertEnumCRLsInStore");
300 if (Loaded_CertEnumCRLsInStore == NULL)
302 FreeLibrary (crypto);
303 return GNUTLS_E_CRYPTO_INIT_FAILED;
306 Crypt32_dll = crypto;
307 # endif
308 #endif
309 return 0;
312 void
313 gnutls_system_global_deinit ()
315 #ifdef _WIN32
316 # if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20
317 FreeLibrary (Crypt32_dll);
318 # endif
319 #endif
323 #define CONFIG_PATH ".gnutls"
325 /* Returns a path to store user-specific configuration
326 * data.
328 int _gnutls_find_config_path(char* path, size_t max_size)
330 char tmp_home_dir[1024];
331 const char *home_dir = getenv ("HOME");
333 #ifdef _WIN32
334 if (home_dir == NULL || home_dir[0] == '\0')
336 const char *home_drive = getenv ("HOMEDRIVE");
337 const char *home_path = getenv ("HOMEPATH");
339 if (home_drive != NULL && home_path != NULL)
341 snprintf(tmp_home_dir, sizeof(tmp_home_dir), "%s%s", home_drive, home_path);
343 else
345 tmp_home_dir[0] = 0;
348 home_dir = tmp_home_dir;
350 #elif defined(HAVE_GETPWUID_R)
351 if (home_dir == NULL || home_dir[0] == '\0')
353 struct passwd *pwd;
354 struct passwd _pwd;
355 char buf[1024];
357 getpwuid_r(getuid(), &_pwd, buf, sizeof(buf), &pwd);
358 if (pwd != NULL)
360 snprintf(tmp_home_dir, sizeof(tmp_home_dir), "%s", pwd->pw_dir);
362 else
364 tmp_home_dir[0] = 0;
367 home_dir = tmp_home_dir;
369 #else
370 if (home_dir == NULL || home_dir[0] == '\0')
372 tmp_home_dir[0] = 0;
373 home_dir = tmp_home_dir;
375 #endif
377 if (home_dir == NULL || home_dir[0] == 0)
378 path[0] = 0;
379 else
380 snprintf(path, max_size, "%s/"CONFIG_PATH, home_dir);
382 return 0;
386 * gnutls_x509_trust_list_add_system_trust:
387 * @list: The structure of the list
388 * @tl_flags: GNUTLS_TL_*
389 * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
391 * This function adds the system's default trusted certificate
392 * authorities to the trusted list. Note that on unsupported system
393 * this function returns %GNUTLS_E_UNIMPLEMENTED_FEATURE.
395 * Returns: The number of added elements or a negative error code on error.
397 * Since: 3.1
400 gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list,
401 unsigned int tl_flags, unsigned int tl_vflags)
403 #if !defined(DEFAULT_TRUST_STORE_PKCS11) && !defined(DEFAULT_TRUST_STORE_FILE) && !defined(_WIN32)
404 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
405 #else
406 int ret, r = 0;
407 const char* crl_file =
408 # ifdef DEFAULT_CRL_FILE
409 DEFAULT_CRL_FILE;
410 # else
411 NULL;
412 # endif
414 # ifdef _WIN32
415 unsigned int i;
417 for (i=0;i<2;i++)
419 HCERTSTORE store;
420 const CERT_CONTEXT *cert;
421 const CRL_CONTEXT *crl;
422 gnutls_datum_t data;
424 if (i==0) store = CertOpenSystemStore(0, "ROOT");
425 else store = CertOpenSystemStore(0, "CA");
427 if (store == NULL) return GNUTLS_E_FILE_ERROR;
429 cert = CertEnumCertificatesInStore(store, NULL);
430 crl = Loaded_CertEnumCRLsInStore(store, NULL);
432 while(cert != NULL)
434 if (cert->dwCertEncodingType == X509_ASN_ENCODING)
436 data.data = cert->pbCertEncoded;
437 data.size = cert->cbCertEncoded;
438 if (gnutls_x509_trust_list_add_trust_mem(list, &data, NULL, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags) > 0)
439 r++;
441 cert = CertEnumCertificatesInStore(store, cert);
444 while(crl != NULL)
446 if (crl->dwCertEncodingType == X509_ASN_ENCODING)
448 data.data = crl->pbCrlEncoded;
449 data.size = crl->cbCrlEncoded;
450 gnutls_x509_trust_list_add_trust_mem(list, NULL, &data, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags);
452 crl = Loaded_CertEnumCRLsInStore(store, crl);
454 CertCloseStore(store, 0);
456 # endif
458 # if defined(ENABLE_PKCS11) && defined(DEFAULT_TRUST_STORE_PKCS11)
459 ret = gnutls_x509_trust_list_add_trust_file(list, DEFAULT_TRUST_STORE_PKCS11, crl_file,
460 GNUTLS_X509_FMT_DER, tl_flags, tl_vflags);
461 if (ret > 0)
462 r += ret;
463 # endif
465 # ifdef DEFAULT_TRUST_STORE_FILE
466 ret = gnutls_x509_trust_list_add_trust_file(list, DEFAULT_TRUST_STORE_FILE, crl_file,
467 GNUTLS_X509_FMT_PEM, tl_flags, tl_vflags);
468 if (ret > 0)
469 r += ret;
470 # endif
471 return r;
472 #endif