From 38b4dd48760be6a13ea059a54a43a826cfe46cfc Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 25 Jul 2016 15:47:19 +0200 Subject: split system.c to various files under system/ --- lib/Makefile.am | 6 +- lib/inet_ntop.c | 250 ----------------- lib/system.c | 725 +------------------------------------------------ lib/system/certs.c | 313 +++++++++++++++++++++ lib/system/iconv.c | 212 +++++++++++++++ lib/system/inet_ntop.c | 250 +++++++++++++++++ lib/system/sockets.c | 188 +++++++++++++ lib/system/threads.c | 168 ++++++++++++ lib/system/vasprintf.c | 84 ++++++ lib/vasprintf.c | 84 ------ 10 files changed, 1224 insertions(+), 1056 deletions(-) delete mode 100644 lib/inet_ntop.c create mode 100644 lib/system/certs.c create mode 100644 lib/system/iconv.c create mode 100644 lib/system/inet_ntop.c create mode 100644 lib/system/sockets.c create mode 100644 lib/system/threads.c create mode 100644 lib/system/vasprintf.c delete mode 100644 lib/vasprintf.c diff --git a/lib/Makefile.am b/lib/Makefile.am index 6eaf9b86e2..94a4d3c92d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -71,8 +71,10 @@ COBJECTS = range.c record.c compress.c debug.c cipher.c \ priority.c hash_int.c cipher_int.c session.c db.c x509_b64.c \ extensions.c auth.c sslv2_compat.c datum.c session_pack.c mpi.c \ pk.c cert.c global.c constate.c anon_cred.c pkix_asn1_tab.c gnutls_asn1_tab.c \ - mem.c fingerprint.c vasprintf.c vasprintf.h tls-sig.c ecc.c alert.c privkey_raw.c \ - system.c system/fastopen.c inet_ntop.c str.c state.c x509.c file.c supplemental.c \ + mem.c fingerprint.c tls-sig.c ecc.c alert.c privkey_raw.c \ + system/certs.c system/threads.c system/fastopen.c system/sockets.c \ + system/inet_ntop.c system/iconv.c system/vasprintf.c vasprintf.h system.c \ + str.c state.c x509.c file.c supplemental.c \ random.c crypto-api.c privkey.c pcert.c pubkey.c locks.c dtls.c \ system_override.c crypto-backend.c verify-tofu.c pin.c tpm.c fips.c \ safe-memfuncs.c inet_pton.c atfork.c atfork.h randomart.c \ diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c deleted file mode 100644 index 2ed11ba308..0000000000 --- a/lib/inet_ntop.c +++ /dev/null @@ -1,250 +0,0 @@ -/* inet_ntop.c -- convert IPv4 and IPv6 addresses from binary to text form - - Copyright (C) 2005-2006, 2008-2015 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -/* - * Copyright (c) 1996-1999 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -#include - -#ifndef HAVE_INET_NTOP - -# include -# include -# include -# include -# include "system.h" - -# ifndef IF_LINT -# define IF_LINT -#endif - -# ifndef HAVE_IPV6 -# define HAVE_IPV6 1 -# endif - -# ifndef HAVE_IPV4 -# define HAVE_IPV4 1 -# endif - -# define NS_IN6ADDRSZ 16 -# define NS_INT16SZ 2 - -/* - * WARNING: Don't even consider trying to compile this on a system where - * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. - */ -typedef int verify_int_size[4 <= sizeof (int) ? 1 : -1]; - -static const char *inet_ntop4 (const unsigned char *src, char *dst, unsigned size); -# if HAVE_IPV6 -static const char *inet_ntop6 (const unsigned char *src, char *dst, unsigned size); -# endif - - -/* char * - * inet_ntop(af, src, dst, size) - * convert a network format address to presentation format. - * return: - * pointer to presentation format address ('dst'), or NULL (see errno). - * author: - * Paul Vixie, 1996. - */ -const char * -inet_ntop (int af, const void *restrict src, - char *restrict dst, unsigned cnt) -{ - switch (af) - { -# if HAVE_IPV4 - case AF_INET: - return (inet_ntop4 (src, dst, cnt)); -# endif - -# if HAVE_IPV6 - case AF_INET6: - return (inet_ntop6 (src, dst, cnt)); -# endif - - default: - errno = EAFNOSUPPORT; - return (NULL); - } - /* NOTREACHED */ -} - -/* const char * - * inet_ntop4(src, dst, size) - * format an IPv4 address - * return: - * 'dst' (as a const) - * notes: - * (1) uses no statics - * (2) takes a u_char* not an in_addr as input - * author: - * Paul Vixie, 1996. - */ -static const char * -inet_ntop4 (const unsigned char *src, char *dst, unsigned size) -{ - char tmp[sizeof "255.255.255.255"]; - int len; - - len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]); - if (len < 0) - return NULL; - - if (len > size) - { - errno = ENOSPC; - return NULL; - } - - return strcpy (dst, tmp); -} - -# if HAVE_IPV6 - -/* const char * - * inet_ntop6(src, dst, size) - * convert IPv6 binary address into presentation (printable) format - * author: - * Paul Vixie, 1996. - */ -static const char * -inet_ntop6 (const unsigned char *src, char *dst, unsigned size) -{ - /* - * Note that int32_t and int16_t need only be "at least" large enough - * to contain a value of the specified size. On some systems, like - * Crays, there is no such thing as an integer variable with 16 bits. - * Keep this in mind if you think this function should have been coded - * to use pointer overlays. All the world's not a VAX. - */ - char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; - struct - { - int base, len; - } best, cur; - unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; - int i; - - /* - * Preprocess: - * Copy the input (bytewise) array into a wordwise array. - * Find the longest run of 0x00's in src[] for :: shorthanding. - */ - memset (words, '\0', sizeof words); - for (i = 0; i < NS_IN6ADDRSZ; i += 2) - words[i / 2] = (src[i] << 8) | src[i + 1]; - best.base = -1; - cur.base = -1; - IF_LINT(best.len = 0); - IF_LINT(cur.len = 0); - for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) - { - if (words[i] == 0) - { - if (cur.base == -1) - cur.base = i, cur.len = 1; - else - cur.len++; - } - else - { - if (cur.base != -1) - { - if (best.base == -1 || cur.len > best.len) - best = cur; - cur.base = -1; - } - } - } - if (cur.base != -1) - { - if (best.base == -1 || cur.len > best.len) - best = cur; - } - if (best.base != -1 && best.len < 2) - best.base = -1; - - /* - * Format the result. - */ - tp = tmp; - for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) - { - /* Are we inside the best run of 0x00's? */ - if (best.base != -1 && i >= best.base && i < (best.base + best.len)) - { - if (i == best.base) - *tp++ = ':'; - continue; - } - /* Are we following an initial run of 0x00s or any real hex? */ - if (i != 0) - *tp++ = ':'; - /* Is this address an encapsulated IPv4? */ - if (i == 6 && best.base == 0 && - (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) - { - if (!inet_ntop4 (src + 12, tp, sizeof tmp - (tp - tmp))) - return (NULL); - tp += strlen (tp); - break; - } - { - int len = sprintf (tp, "%x", words[i]); - if (len < 0) - return NULL; - tp += len; - } - } - /* Was it a trailing run of 0x00's? */ - if (best.base != -1 && (best.base + best.len) == - (NS_IN6ADDRSZ / NS_INT16SZ)) - *tp++ = ':'; - *tp++ = '\0'; - - /* - * Check for overflow, copy, and we're done. - */ - if ((unsigned) (tp - tmp) > size) - { - errno = ENOSPC; - return NULL; - } - - return strcpy (dst, tmp); -} - -# endif - -#endif diff --git a/lib/system.c b/lib/system.c index d1e1171da6..5ddd355904 100644 --- a/lib/system.c +++ b/lib/system.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2010-2015 Free Software Foundation, Inc. + * Copyright (C) 2010-2016 Free Software Foundation, Inc. + * Copyright (C) 2015-2016 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -30,306 +31,21 @@ #include #include #include +#include #ifdef _WIN32 # include -# include -# if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20 -typedef PCCRL_CONTEXT WINAPI(*CertEnumCRLsInStoreFunc) (HCERTSTORE - hCertStore, - PCCRL_CONTEXT - pPrevCrlContext); -static CertEnumCRLsInStoreFunc pCertEnumCRLsInStore; -static HMODULE Crypt32_dll; -# else -# define pCertEnumCRLsInStore CertEnumCRLsInStore -# endif - -#else /* !_WIN32 */ - -# include - -# ifdef HAVE_PTHREAD_LOCKS -# include -# endif - -# if defined(HAVE_GETPWUID_R) -# include -# endif #endif -/* System specific function wrappers. +/* System specific function wrappers for certificate stores. */ - -#ifdef _WIN32 -/* Do not use the gnulib functions for sending and receiving data. - * Using them makes gnutls only working with gnulib applications. - */ -#undef send -#undef recv -#undef select - -int system_errno(gnutls_transport_ptr p) -{ - int tmperr = WSAGetLastError(); - int ret = 0; - switch (tmperr) { - case WSAEWOULDBLOCK: - ret = EAGAIN; - break; - case NO_ERROR: - ret = 0; - break; - case WSAEINTR: - ret = EINTR; - break; - case WSAEMSGSIZE: - ret = EMSGSIZE; - break; - default: - ret = EIO; - break; - } - WSASetLastError(tmperr); - - return ret; -} - -ssize_t -system_write(gnutls_transport_ptr ptr, const void *data, size_t data_size) -{ - return send(GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0); -} -#else /* POSIX */ -int system_errno(gnutls_transport_ptr_t ptr) -{ -#if defined(_AIX) || defined(AIX) - if (errno == 0) - errno = EAGAIN; -#endif - - return errno; -} - -static ssize_t -_system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, - int iovec_cnt, int flags) -{ - struct msghdr hdr; - - memset(&hdr, 0, sizeof(hdr)); - hdr.msg_iov = (struct iovec *)iovec; - hdr.msg_iovlen = iovec_cnt; - - return sendmsg(GNUTLS_POINTER_TO_INT(ptr), &hdr, flags); -} - -#ifdef MSG_NOSIGNAL -ssize_t -system_writev_nosignal(gnutls_transport_ptr_t ptr, const giovec_t * iovec, - int iovec_cnt) -{ - return _system_writev(ptr, iovec, iovec_cnt, MSG_NOSIGNAL); -} - -#endif - -ssize_t -system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, - int iovec_cnt) -{ - return _system_writev(ptr, iovec, iovec_cnt, 0); -} - -#endif - - -ssize_t -system_read(gnutls_transport_ptr_t ptr, void *data, size_t data_size) -{ - return recv(GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0); -} - -/** - * gnutls_system_recv_timeout: - * @ptr: A gnutls_transport_ptr_t pointer - * @ms: The number of milliseconds to wait. - * - * Wait for data to be received from the provided socket (@ptr) within a - * timeout period in milliseconds, using select() on the provided @ptr. - * - * This function is provided as a helper for constructing custom - * callbacks for gnutls_transport_set_pull_timeout_function(), - * which can be used if you rely on socket file descriptors. - * - * Returns -1 on error, 0 on timeout, positive value if data are available for reading. - * - * Since: 3.4.0 - **/ -int gnutls_system_recv_timeout(gnutls_transport_ptr_t ptr, unsigned int ms) -{ - int ret; - int fd = GNUTLS_POINTER_TO_INT(ptr); -#ifndef _WIN32 - int timeo; - struct pollfd pfd; - - pfd.fd = fd; - pfd.events = POLLIN; - pfd.revents = 0; - - if (ms == GNUTLS_INDEFINITE_TIMEOUT) - timeo = -1; - else - timeo = ms; - do { - ret = poll(&pfd, 1, timeo); - } while(ret == -1 && errno == EINTR); -#else - fd_set rfds; - struct timeval _tv, *tv = NULL; - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - - if (ms != GNUTLS_INDEFINITE_TIMEOUT) { - _tv.tv_sec = ms/1000; - _tv.tv_usec = (ms % 1000) * 1000; - tv = &_tv; - } - - ret = select(fd + 1, &rfds, NULL, NULL, tv); -#endif - if (ret <= 0) - return ret; - - return ret; -} - -/* Thread stuff */ - -#ifdef HAVE_WIN32_LOCKS -static int gnutls_system_mutex_init(void **priv) -{ - CRITICAL_SECTION *lock = malloc(sizeof(CRITICAL_SECTION)); - - if (lock == NULL) - return GNUTLS_E_MEMORY_ERROR; - - InitializeCriticalSection(lock); - - *priv = lock; - - return 0; -} - -static int gnutls_system_mutex_deinit(void **priv) -{ - DeleteCriticalSection((CRITICAL_SECTION *) * priv); - free(*priv); - - return 0; -} - -static int gnutls_system_mutex_lock(void **priv) -{ - EnterCriticalSection((CRITICAL_SECTION *) * priv); - return 0; -} - -static int gnutls_system_mutex_unlock(void **priv) -{ - LeaveCriticalSection((CRITICAL_SECTION *) * priv); - return 0; -} - -#endif /* WIN32_LOCKS */ - -#ifdef HAVE_PTHREAD_LOCKS - -static int gnutls_system_mutex_init(void **priv) -{ - pthread_mutex_t *lock = malloc(sizeof(pthread_mutex_t)); - int ret; - - if (lock == NULL) - return GNUTLS_E_MEMORY_ERROR; - - ret = pthread_mutex_init(lock, NULL); - if (ret) { - free(lock); - gnutls_assert(); - return GNUTLS_E_LOCKING_ERROR; - } - - *priv = lock; - - return 0; -} - -static int gnutls_system_mutex_deinit(void **priv) -{ - pthread_mutex_destroy((pthread_mutex_t *) * priv); - free(*priv); - return 0; -} - -static int gnutls_system_mutex_lock(void **priv) -{ - if (pthread_mutex_lock((pthread_mutex_t *) * priv)) { - gnutls_assert(); - return GNUTLS_E_LOCKING_ERROR; - } - - return 0; -} - -static int gnutls_system_mutex_unlock(void **priv) -{ - if (pthread_mutex_unlock((pthread_mutex_t *) * priv)) { - gnutls_assert(); - return GNUTLS_E_LOCKING_ERROR; - } - - return 0; -} - -#endif /* PTHREAD_LOCKS */ - -#ifdef HAVE_NO_LOCKS - -static int gnutls_system_mutex_init(void **priv) -{ - return 0; -} - -static int gnutls_system_mutex_deinit(void **priv) -{ - return 0; -} - -static int gnutls_system_mutex_lock(void **priv) -{ - return 0; -} - -static int gnutls_system_mutex_unlock(void **priv) -{ - return 0; -} - -#endif /* NO_LOCKS */ - gnutls_time_func gnutls_time; -mutex_init_func gnutls_mutex_init = gnutls_system_mutex_init; -mutex_deinit_func gnutls_mutex_deinit = gnutls_system_mutex_deinit; -mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock; -mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock; int gnutls_system_global_init(void) { #ifdef _WIN32 #if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20 + /* used in system/certs.c */ HMODULE crypto; crypto = LoadLibraryA("Crypt32.dll"); @@ -362,434 +78,3 @@ void gnutls_system_global_deinit(void) } -#define CONFIG_PATH ".gnutls" - -/* Returns a path to store user-specific configuration - * data. - */ -int _gnutls_find_config_path(char *path, size_t max_size) -{ - const char *home_dir = secure_getenv("HOME"); - - if (home_dir != NULL && home_dir[0] != 0) { - snprintf(path, max_size, "%s/" CONFIG_PATH, home_dir); - return 0; - } - -#ifdef _WIN32 - if (home_dir == NULL || home_dir[0] == '\0') { - const char *home_drive = getenv("HOMEDRIVE"); - const char *home_path = getenv("HOMEPATH"); - - if (home_drive != NULL && home_path != NULL) { - snprintf(path, max_size, "%s%s\\" CONFIG_PATH, home_drive, home_path); - } else { - path[0] = 0; - } - } -#elif defined(HAVE_GETPWUID_R) - if (home_dir == NULL || home_dir[0] == '\0') { - struct passwd *pwd; - struct passwd _pwd; - int ret; - char tmp[512]; - - ret = getpwuid_r(getuid(), &_pwd, tmp, sizeof(tmp), &pwd); - if (ret == 0 && pwd != NULL) { - snprintf(path, max_size, "%s/" CONFIG_PATH, pwd->pw_dir); - } else { - path[0] = 0; - } - } -#else - if (home_dir == NULL || home_dir[0] == '\0') { - path[0] = 0; - } -#endif - - return 0; -} - -#if defined(DEFAULT_TRUST_STORE_FILE) || (defined(DEFAULT_TRUST_STORE_PKCS11) && defined(ENABLE_PKCS11)) -static -int -add_system_trust(gnutls_x509_trust_list_t list, - unsigned int tl_flags, unsigned int tl_vflags) -{ - int ret, r = 0; - const char *crl_file = -#ifdef DEFAULT_CRL_FILE - DEFAULT_CRL_FILE; -#else - NULL; -#endif - -#if defined(ENABLE_PKCS11) && defined(DEFAULT_TRUST_STORE_PKCS11) - ret = - gnutls_x509_trust_list_add_trust_file(list, - DEFAULT_TRUST_STORE_PKCS11, - crl_file, - GNUTLS_X509_FMT_DER, - tl_flags, tl_vflags); - if (ret > 0) - r += ret; -#endif - -#ifdef DEFAULT_TRUST_STORE_FILE - ret = - gnutls_x509_trust_list_add_trust_file(list, - DEFAULT_TRUST_STORE_FILE, - crl_file, - GNUTLS_X509_FMT_PEM, - tl_flags, tl_vflags); - if (ret > 0) - r += ret; -#endif - -#ifdef DEFAULT_BLACKLIST_FILE - ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM); - if (ret < 0) { - _gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE); - } -#endif - - return r; -} -#elif defined(_WIN32) -static -int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags, - unsigned int tl_vflags) -{ - unsigned int i; - int r = 0; - - for (i = 0; i < 2; i++) { - HCERTSTORE store; - const CERT_CONTEXT *cert; - const CRL_CONTEXT *crl; - gnutls_datum_t data; - - if (i == 0) - store = CertOpenSystemStore(0, "ROOT"); - else - store = CertOpenSystemStore(0, "CA"); - - if (store == NULL) - return GNUTLS_E_FILE_ERROR; - - cert = CertEnumCertificatesInStore(store, NULL); - crl = pCertEnumCRLsInStore(store, NULL); - - while (cert != NULL) { - if (cert->dwCertEncodingType == X509_ASN_ENCODING) { - data.data = cert->pbCertEncoded; - data.size = cert->cbCertEncoded; - if (gnutls_x509_trust_list_add_trust_mem - (list, &data, NULL, - GNUTLS_X509_FMT_DER, tl_flags, - tl_vflags) > 0) - r++; - } - cert = CertEnumCertificatesInStore(store, cert); - } - - while (crl != NULL) { - if (crl->dwCertEncodingType == X509_ASN_ENCODING) { - data.data = crl->pbCrlEncoded; - data.size = crl->cbCrlEncoded; - gnutls_x509_trust_list_add_trust_mem(list, - NULL, - &data, - GNUTLS_X509_FMT_DER, - tl_flags, - tl_vflags); - } - crl = pCertEnumCRLsInStore(store, crl); - } - CertCloseStore(store, 0); - } - -#ifdef DEFAULT_BLACKLIST_FILE - ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM); - if (ret < 0) { - _gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE); - } -#endif - - return r; -} -#elif defined(ANDROID) || defined(__ANDROID__) || defined(DEFAULT_TRUST_STORE_DIR) - -# include -# include - -# if defined(ANDROID) || defined(__ANDROID__) -# define DEFAULT_TRUST_STORE_DIR "/system/etc/security/cacerts/" - -static int load_revoked_certs(gnutls_x509_trust_list_t list, unsigned type) -{ - DIR *dirp; - struct dirent *d; - int ret; - int r = 0; - char path[GNUTLS_PATH_MAX]; - - dirp = opendir("/data/misc/keychain/cacerts-removed/"); - if (dirp != NULL) { - do { - d = readdir(dirp); - if (d != NULL && d->d_type == DT_REG) { - snprintf(path, sizeof(path), - "/data/misc/keychain/cacerts-removed/%s", - d->d_name); - - ret = - gnutls_x509_trust_list_remove_trust_file - (list, path, type); - if (ret >= 0) - r += ret; - } - } - while (d != NULL); - closedir(dirp); - } - - return r; -} -# endif - - -/* This works on android 4.x - */ -static -int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags, - unsigned int tl_vflags) -{ - int r = 0, ret; - - ret = gnutls_x509_trust_list_add_trust_dir(list, DEFAULT_TRUST_STORE_DIR, - NULL, GNUTLS_X509_FMT_PEM, tl_flags, tl_vflags); - if (ret >= 0) - r += ret; - -# if defined(ANDROID) || defined(__ANDROID__) - ret = load_revoked_certs(list, GNUTLS_X509_FMT_DER); - if (ret >= 0) - r -= ret; - - ret = gnutls_x509_trust_list_add_trust_dir(list, "/data/misc/keychain/cacerts-added/", - NULL, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags); - if (ret >= 0) - r += ret; -# endif - - return r; -} -#else - -#define add_system_trust(x,y,z) GNUTLS_E_UNIMPLEMENTED_FEATURE - -#endif - -/** - * gnutls_x509_trust_list_add_system_trust: - * @list: The structure of the list - * @tl_flags: GNUTLS_TL_* - * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL - * - * This function adds the system's default trusted certificate - * authorities to the trusted list. Note that on unsupported systems - * this function returns %GNUTLS_E_UNIMPLEMENTED_FEATURE. - * - * This function implies the flag %GNUTLS_TL_NO_DUPLICATES. - * - * Returns: The number of added elements or a negative error code on error. - * - * Since: 3.1 - **/ -int -gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list, - unsigned int tl_flags, - unsigned int tl_vflags) -{ - return add_system_trust(list, tl_flags|GNUTLS_TL_NO_DUPLICATES, tl_vflags); -} - -#if defined(_WIN32) -#include - -int _gnutls_ucs2_to_utf8(const void *data, size_t size, - gnutls_datum_t * output, unsigned be) -{ - int ret; - unsigned i; - int len = 0, src_len; - char *dst = NULL; - char *src = NULL; - static unsigned flags = 0; - static int checked = 0; - - if (checked == 0) { - /* Not all windows versions support MB_ERR_INVALID_CHARS */ - ret = - WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS, - L"hello", -1, NULL, 0, NULL, NULL); - if (ret > 0) - flags = MB_ERR_INVALID_CHARS; - checked = 1; - } - - if (((uint8_t *) data)[size] == 0 && ((uint8_t *) data)[size+1] == 0) { - size -= 2; - } - - src_len = wcslen(data); - - src = gnutls_malloc(size+2); - if (src == NULL) - return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); - - /* convert to LE */ - if (be) { - for (i = 0; i < size; i += 2) { - src[i] = ((uint8_t *) data)[1 + i]; - src[1 + i] = ((uint8_t *) data)[i]; - } - } else { - memcpy(src, data, size); - } - src[size] = 0; - src[size+1] = 0; - - ret = - WideCharToMultiByte(CP_UTF8, flags, - (void *) src, src_len, NULL, 0, - NULL, NULL); - if (ret == 0) { - _gnutls_debug_log("WideCharToMultiByte: %d\n", (int)GetLastError()); - ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - goto fail; - } - - len = ret + 1; - dst = gnutls_malloc(len); - if (dst == NULL) { - ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); - goto fail; - } - dst[0] = 0; - - ret = - WideCharToMultiByte(CP_UTF8, flags, - (void *) src, src_len, dst, len-1, NULL, - NULL); - if (ret == 0) { - ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - goto fail; - } - dst[len - 1] = 0; - - output->data = dst; - output->size = ret; - - ret = 0; - goto cleanup; - - fail: - gnutls_free(dst); - - cleanup: - gnutls_free(src); - return ret; -} - -#elif defined(HAVE_ICONV) || defined(HAVE_LIBICONV) - -#include - -int _gnutls_ucs2_to_utf8(const void *data, size_t size, - gnutls_datum_t * output, unsigned be) -{ - iconv_t conv; - int ret; - size_t orig, dstlen = size * 2; - char *src = (void *) data; - char *dst = NULL, *pdst; - - if (size == 0) - return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); - - if (be) { - conv = iconv_open("UTF-8", "UTF-16BE"); - } else { - conv = iconv_open("UTF-8", "UTF-16LE"); - } - if (conv == (iconv_t) - 1) - return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); - - /* Note that dstlen has enough size for every possible input characters. - * (remember the in UTF-16 the characters in data are at most size/2, - * and we allocate 4 bytes per character). - */ - pdst = dst = gnutls_malloc(dstlen + 1); - if (dst == NULL) { - ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); - goto fail; - } - - orig = dstlen; - ret = iconv(conv, &src, &size, &pdst, &dstlen); - if (ret == -1) { - ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - goto fail; - } - - output->data = (void *) dst; - output->size = orig - dstlen; - output->data[output->size] = 0; - - ret = 0; - goto cleanup; - - fail: - gnutls_free(dst); - - cleanup: - iconv_close(conv); - - return ret; -} - -#else - -/* Can convert only english (ASCII) */ -int _gnutls_ucs2_to_utf8(const void *data, size_t size, - gnutls_datum_t * output, unsigned be) -{ - unsigned int i, j; - char *dst; - const char *src = data; - - if (size == 0 || size % 2 != 0) - return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); - - dst = gnutls_malloc(size + 1); - if (dst == NULL) - return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); - - for (i = j = 0; i < size; i += 2, j++) { - if (src[i] != 0 || !c_isascii(src[i + 1])) - return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - if (be) - dst[j] = src[i + 1]; - else - dst[j] = src[i]; - } - - output->data = (void *) dst; - output->size = j; - output->data[output->size] = 0; - - return 0; -} -#endif diff --git a/lib/system/certs.c b/lib/system/certs.c new file mode 100644 index 0000000000..c7ca3547ea --- /dev/null +++ b/lib/system/certs.c @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2010-2016 Free Software Foundation, Inc. + * Copyright (C) 2015-2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + * + */ + +#include +#include +#include "gnutls_int.h" +#include "errors.h" + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# include +# if defined(__MINGW32__) && !defined(__MINGW64__) && __MINGW32_MAJOR_VERSION <= 3 && __MINGW32_MINOR_VERSION <= 20 +typedef PCCRL_CONTEXT WINAPI(*CertEnumCRLsInStoreFunc) (HCERTSTORE + hCertStore, + PCCRL_CONTEXT + pPrevCrlContext); +static CertEnumCRLsInStoreFunc pCertEnumCRLsInStore; +static HMODULE Crypt32_dll; +# else +# define pCertEnumCRLsInStore CertEnumCRLsInStore +# endif + +#else /* !_WIN32 */ + +# include + +# if defined(HAVE_GETPWUID_R) +# include +# endif +#endif + +/* System specific function wrappers for certificate stores. + */ + +#define CONFIG_PATH ".gnutls" + +/* Returns a path to store user-specific configuration + * data. + */ +int _gnutls_find_config_path(char *path, size_t max_size) +{ + const char *home_dir = secure_getenv("HOME"); + + if (home_dir != NULL && home_dir[0] != 0) { + snprintf(path, max_size, "%s/" CONFIG_PATH, home_dir); + return 0; + } + +#ifdef _WIN32 + if (home_dir == NULL || home_dir[0] == '\0') { + const char *home_drive = getenv("HOMEDRIVE"); + const char *home_path = getenv("HOMEPATH"); + + if (home_drive != NULL && home_path != NULL) { + snprintf(path, max_size, "%s%s\\" CONFIG_PATH, home_drive, home_path); + } else { + path[0] = 0; + } + } +#elif defined(HAVE_GETPWUID_R) + if (home_dir == NULL || home_dir[0] == '\0') { + struct passwd *pwd; + struct passwd _pwd; + int ret; + char tmp[512]; + + ret = getpwuid_r(getuid(), &_pwd, tmp, sizeof(tmp), &pwd); + if (ret == 0 && pwd != NULL) { + snprintf(path, max_size, "%s/" CONFIG_PATH, pwd->pw_dir); + } else { + path[0] = 0; + } + } +#else + if (home_dir == NULL || home_dir[0] == '\0') { + path[0] = 0; + } +#endif + + return 0; +} + +#if defined(DEFAULT_TRUST_STORE_FILE) || (defined(DEFAULT_TRUST_STORE_PKCS11) && defined(ENABLE_PKCS11)) +static +int +add_system_trust(gnutls_x509_trust_list_t list, + unsigned int tl_flags, unsigned int tl_vflags) +{ + int ret, r = 0; + const char *crl_file = +#ifdef DEFAULT_CRL_FILE + DEFAULT_CRL_FILE; +#else + NULL; +#endif + +#if defined(ENABLE_PKCS11) && defined(DEFAULT_TRUST_STORE_PKCS11) + ret = + gnutls_x509_trust_list_add_trust_file(list, + DEFAULT_TRUST_STORE_PKCS11, + crl_file, + GNUTLS_X509_FMT_DER, + tl_flags, tl_vflags); + if (ret > 0) + r += ret; +#endif + +#ifdef DEFAULT_TRUST_STORE_FILE + ret = + gnutls_x509_trust_list_add_trust_file(list, + DEFAULT_TRUST_STORE_FILE, + crl_file, + GNUTLS_X509_FMT_PEM, + tl_flags, tl_vflags); + if (ret > 0) + r += ret; +#endif + +#ifdef DEFAULT_BLACKLIST_FILE + ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + _gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE); + } +#endif + + return r; +} +#elif defined(_WIN32) +static +int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags, + unsigned int tl_vflags) +{ + unsigned int i; + int r = 0; + + for (i = 0; i < 2; i++) { + HCERTSTORE store; + const CERT_CONTEXT *cert; + const CRL_CONTEXT *crl; + gnutls_datum_t data; + + if (i == 0) + store = CertOpenSystemStore(0, "ROOT"); + else + store = CertOpenSystemStore(0, "CA"); + + if (store == NULL) + return GNUTLS_E_FILE_ERROR; + + cert = CertEnumCertificatesInStore(store, NULL); + crl = pCertEnumCRLsInStore(store, NULL); + + while (cert != NULL) { + if (cert->dwCertEncodingType == X509_ASN_ENCODING) { + data.data = cert->pbCertEncoded; + data.size = cert->cbCertEncoded; + if (gnutls_x509_trust_list_add_trust_mem + (list, &data, NULL, + GNUTLS_X509_FMT_DER, tl_flags, + tl_vflags) > 0) + r++; + } + cert = CertEnumCertificatesInStore(store, cert); + } + + while (crl != NULL) { + if (crl->dwCertEncodingType == X509_ASN_ENCODING) { + data.data = crl->pbCrlEncoded; + data.size = crl->cbCrlEncoded; + gnutls_x509_trust_list_add_trust_mem(list, + NULL, + &data, + GNUTLS_X509_FMT_DER, + tl_flags, + tl_vflags); + } + crl = pCertEnumCRLsInStore(store, crl); + } + CertCloseStore(store, 0); + } + +#ifdef DEFAULT_BLACKLIST_FILE + ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + _gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE); + } +#endif + + return r; +} +#elif defined(ANDROID) || defined(__ANDROID__) || defined(DEFAULT_TRUST_STORE_DIR) + +# include +# include + +# if defined(ANDROID) || defined(__ANDROID__) +# define DEFAULT_TRUST_STORE_DIR "/system/etc/security/cacerts/" + +static int load_revoked_certs(gnutls_x509_trust_list_t list, unsigned type) +{ + DIR *dirp; + struct dirent *d; + int ret; + int r = 0; + char path[GNUTLS_PATH_MAX]; + + dirp = opendir("/data/misc/keychain/cacerts-removed/"); + if (dirp != NULL) { + do { + d = readdir(dirp); + if (d != NULL && d->d_type == DT_REG) { + snprintf(path, sizeof(path), + "/data/misc/keychain/cacerts-removed/%s", + d->d_name); + + ret = + gnutls_x509_trust_list_remove_trust_file + (list, path, type); + if (ret >= 0) + r += ret; + } + } + while (d != NULL); + closedir(dirp); + } + + return r; +} +# endif + + +/* This works on android 4.x + */ +static +int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags, + unsigned int tl_vflags) +{ + int r = 0, ret; + + ret = gnutls_x509_trust_list_add_trust_dir(list, DEFAULT_TRUST_STORE_DIR, + NULL, GNUTLS_X509_FMT_PEM, tl_flags, tl_vflags); + if (ret >= 0) + r += ret; + +# if defined(ANDROID) || defined(__ANDROID__) + ret = load_revoked_certs(list, GNUTLS_X509_FMT_DER); + if (ret >= 0) + r -= ret; + + ret = gnutls_x509_trust_list_add_trust_dir(list, "/data/misc/keychain/cacerts-added/", + NULL, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags); + if (ret >= 0) + r += ret; +# endif + + return r; +} +#else + +#define add_system_trust(x,y,z) GNUTLS_E_UNIMPLEMENTED_FEATURE + +#endif + +/** + * gnutls_x509_trust_list_add_system_trust: + * @list: The structure of the list + * @tl_flags: GNUTLS_TL_* + * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL + * + * This function adds the system's default trusted certificate + * authorities to the trusted list. Note that on unsupported systems + * this function returns %GNUTLS_E_UNIMPLEMENTED_FEATURE. + * + * This function implies the flag %GNUTLS_TL_NO_DUPLICATES. + * + * Returns: The number of added elements or a negative error code on error. + * + * Since: 3.1 + **/ +int +gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list, + unsigned int tl_flags, + unsigned int tl_vflags) +{ + return add_system_trust(list, tl_flags|GNUTLS_TL_NO_DUPLICATES, tl_vflags); +} + diff --git a/lib/system/iconv.c b/lib/system/iconv.c new file mode 100644 index 0000000000..c0e4480d1f --- /dev/null +++ b/lib/system/iconv.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2010-2016 Free Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + * + */ + +#include +#include +#include "gnutls_int.h" +#include "errors.h" + +#include +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#include + +int _gnutls_ucs2_to_utf8(const void *data, size_t size, + gnutls_datum_t * output, unsigned be) +{ + int ret; + unsigned i; + int len = 0, src_len; + char *dst = NULL; + char *src = NULL; + static unsigned flags = 0; + static int checked = 0; + + if (checked == 0) { + /* Not all windows versions support MB_ERR_INVALID_CHARS */ + ret = + WideCharToMultiByte(CP_UTF8, MB_ERR_INVALID_CHARS, + L"hello", -1, NULL, 0, NULL, NULL); + if (ret > 0) + flags = MB_ERR_INVALID_CHARS; + checked = 1; + } + + if (((uint8_t *) data)[size] == 0 && ((uint8_t *) data)[size+1] == 0) { + size -= 2; + } + + src_len = wcslen(data); + + src = gnutls_malloc(size+2); + if (src == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + /* convert to LE */ + if (be) { + for (i = 0; i < size; i += 2) { + src[i] = ((uint8_t *) data)[1 + i]; + src[1 + i] = ((uint8_t *) data)[i]; + } + } else { + memcpy(src, data, size); + } + src[size] = 0; + src[size+1] = 0; + + ret = + WideCharToMultiByte(CP_UTF8, flags, + (void *) src, src_len, NULL, 0, + NULL, NULL); + if (ret == 0) { + _gnutls_debug_log("WideCharToMultiByte: %d\n", (int)GetLastError()); + ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + goto fail; + } + + len = ret + 1; + dst = gnutls_malloc(len); + if (dst == NULL) { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto fail; + } + dst[0] = 0; + + ret = + WideCharToMultiByte(CP_UTF8, flags, + (void *) src, src_len, dst, len-1, NULL, + NULL); + if (ret == 0) { + ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + goto fail; + } + dst[len - 1] = 0; + + output->data = dst; + output->size = ret; + + ret = 0; + goto cleanup; + + fail: + gnutls_free(dst); + + cleanup: + gnutls_free(src); + return ret; +} + +#elif defined(HAVE_ICONV) || defined(HAVE_LIBICONV) + +#include + +int _gnutls_ucs2_to_utf8(const void *data, size_t size, + gnutls_datum_t * output, unsigned be) +{ + iconv_t conv; + int ret; + size_t orig, dstlen = size * 2; + char *src = (void *) data; + char *dst = NULL, *pdst; + + if (size == 0) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + if (be) { + conv = iconv_open("UTF-8", "UTF-16BE"); + } else { + conv = iconv_open("UTF-8", "UTF-16LE"); + } + if (conv == (iconv_t) - 1) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + /* Note that dstlen has enough size for every possible input characters. + * (remember the in UTF-16 the characters in data are at most size/2, + * and we allocate 4 bytes per character). + */ + pdst = dst = gnutls_malloc(dstlen + 1); + if (dst == NULL) { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto fail; + } + + orig = dstlen; + ret = iconv(conv, &src, &size, &pdst, &dstlen); + if (ret == -1) { + ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + goto fail; + } + + output->data = (void *) dst; + output->size = orig - dstlen; + output->data[output->size] = 0; + + ret = 0; + goto cleanup; + + fail: + gnutls_free(dst); + + cleanup: + iconv_close(conv); + + return ret; +} + +#else + +/* Can convert only english (ASCII) */ +int _gnutls_ucs2_to_utf8(const void *data, size_t size, + gnutls_datum_t * output, unsigned be) +{ + unsigned int i, j; + char *dst; + const char *src = data; + + if (size == 0 || size % 2 != 0) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + dst = gnutls_malloc(size + 1); + if (dst == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + for (i = j = 0; i < size; i += 2, j++) { + if (src[i] != 0 || !c_isascii(src[i + 1])) + return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + if (be) + dst[j] = src[i + 1]; + else + dst[j] = src[i]; + } + + output->data = (void *) dst; + output->size = j; + output->data[output->size] = 0; + + return 0; +} +#endif diff --git a/lib/system/inet_ntop.c b/lib/system/inet_ntop.c new file mode 100644 index 0000000000..2ed11ba308 --- /dev/null +++ b/lib/system/inet_ntop.c @@ -0,0 +1,250 @@ +/* inet_ntop.c -- convert IPv4 and IPv6 addresses from binary to text form + + Copyright (C) 2005-2006, 2008-2015 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include + +#ifndef HAVE_INET_NTOP + +# include +# include +# include +# include +# include "system.h" + +# ifndef IF_LINT +# define IF_LINT +#endif + +# ifndef HAVE_IPV6 +# define HAVE_IPV6 1 +# endif + +# ifndef HAVE_IPV4 +# define HAVE_IPV4 1 +# endif + +# define NS_IN6ADDRSZ 16 +# define NS_INT16SZ 2 + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ +typedef int verify_int_size[4 <= sizeof (int) ? 1 : -1]; + +static const char *inet_ntop4 (const unsigned char *src, char *dst, unsigned size); +# if HAVE_IPV6 +static const char *inet_ntop6 (const unsigned char *src, char *dst, unsigned size); +# endif + + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address ('dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +inet_ntop (int af, const void *restrict src, + char *restrict dst, unsigned cnt) +{ + switch (af) + { +# if HAVE_IPV4 + case AF_INET: + return (inet_ntop4 (src, dst, cnt)); +# endif + +# if HAVE_IPV6 + case AF_INET6: + return (inet_ntop6 (src, dst, cnt)); +# endif + + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address + * return: + * 'dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4 (const unsigned char *src, char *dst, unsigned size) +{ + char tmp[sizeof "255.255.255.255"]; + int len; + + len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]); + if (len < 0) + return NULL; + + if (len > size) + { + errno = ENOSPC; + return NULL; + } + + return strcpy (dst, tmp); +} + +# if HAVE_IPV6 + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6 (const unsigned char *src, char *dst, unsigned size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct + { + int base, len; + } best, cur; + unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset (words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i += 2) + words[i / 2] = (src[i] << 8) | src[i + 1]; + best.base = -1; + cur.base = -1; + IF_LINT(best.len = 0); + IF_LINT(cur.len = 0); + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) + { + if (words[i] == 0) + { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } + else + { + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) + { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && i < (best.base + best.len)) + { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) + { + if (!inet_ntop4 (src + 12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen (tp); + break; + } + { + int len = sprintf (tp, "%x", words[i]); + if (len < 0) + return NULL; + tp += len; + } + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((unsigned) (tp - tmp) > size) + { + errno = ENOSPC; + return NULL; + } + + return strcpy (dst, tmp); +} + +# endif + +#endif diff --git a/lib/system/sockets.c b/lib/system/sockets.c new file mode 100644 index 0000000000..f399fc93a9 --- /dev/null +++ b/lib/system/sockets.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2010-2016 Free Software Foundation, Inc. + * Copyright (C) 2015-2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + * + */ + +#include +#include +#include "gnutls_int.h" +#include "errors.h" + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +#else /* !_WIN32 */ +# include +#endif + +/* System specific socket function wrappers. + */ + +#ifdef _WIN32 +/* Do not use the gnulib functions for sending and receiving data. + * Using them makes gnutls only working with gnulib applications. + */ +#undef send +#undef recv +#undef select + +int system_errno(gnutls_transport_ptr p) +{ + int tmperr = WSAGetLastError(); + int ret = 0; + switch (tmperr) { + case WSAEWOULDBLOCK: + ret = EAGAIN; + break; + case NO_ERROR: + ret = 0; + break; + case WSAEINTR: + ret = EINTR; + break; + case WSAEMSGSIZE: + ret = EMSGSIZE; + break; + default: + ret = EIO; + break; + } + WSASetLastError(tmperr); + + return ret; +} + +ssize_t +system_write(gnutls_transport_ptr ptr, const void *data, size_t data_size) +{ + return send(GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0); +} +#else /* POSIX */ +int system_errno(gnutls_transport_ptr_t ptr) +{ +#if defined(_AIX) || defined(AIX) + if (errno == 0) + errno = EAGAIN; +#endif + + return errno; +} + +static ssize_t +_system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, + int iovec_cnt, int flags) +{ + struct msghdr hdr; + + memset(&hdr, 0, sizeof(hdr)); + hdr.msg_iov = (struct iovec *)iovec; + hdr.msg_iovlen = iovec_cnt; + + return sendmsg(GNUTLS_POINTER_TO_INT(ptr), &hdr, flags); +} + +#ifdef MSG_NOSIGNAL +ssize_t +system_writev_nosignal(gnutls_transport_ptr_t ptr, const giovec_t * iovec, + int iovec_cnt) +{ + return _system_writev(ptr, iovec, iovec_cnt, MSG_NOSIGNAL); +} + +#endif + +ssize_t +system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, + int iovec_cnt) +{ + return _system_writev(ptr, iovec, iovec_cnt, 0); +} + +#endif + + +ssize_t +system_read(gnutls_transport_ptr_t ptr, void *data, size_t data_size) +{ + return recv(GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0); +} + +/** + * gnutls_system_recv_timeout: + * @ptr: A gnutls_transport_ptr_t pointer + * @ms: The number of milliseconds to wait. + * + * Wait for data to be received from the provided socket (@ptr) within a + * timeout period in milliseconds, using select() on the provided @ptr. + * + * This function is provided as a helper for constructing custom + * callbacks for gnutls_transport_set_pull_timeout_function(), + * which can be used if you rely on socket file descriptors. + * + * Returns -1 on error, 0 on timeout, positive value if data are available for reading. + * + * Since: 3.4.0 + **/ +int gnutls_system_recv_timeout(gnutls_transport_ptr_t ptr, unsigned int ms) +{ + int ret; + int fd = GNUTLS_POINTER_TO_INT(ptr); +#ifndef _WIN32 + int timeo; + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + + if (ms == GNUTLS_INDEFINITE_TIMEOUT) + timeo = -1; + else + timeo = ms; + do { + ret = poll(&pfd, 1, timeo); + } while(ret == -1 && errno == EINTR); +#else + fd_set rfds; + struct timeval _tv, *tv = NULL; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + if (ms != GNUTLS_INDEFINITE_TIMEOUT) { + _tv.tv_sec = ms/1000; + _tv.tv_usec = (ms % 1000) * 1000; + tv = &_tv; + } + + ret = select(fd + 1, &rfds, NULL, NULL, tv); +#endif + if (ret <= 0) + return ret; + + return ret; +} + diff --git a/lib/system/threads.c b/lib/system/threads.c new file mode 100644 index 0000000000..a9a2fa44a9 --- /dev/null +++ b/lib/system/threads.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2010-2016 Free Software Foundation, Inc. + * Copyright (C) 2015-2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + * + */ + +#include +#include +#include "gnutls_int.h" +#include "errors.h" + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# include + +#else /* !_WIN32 */ + +# ifdef HAVE_PTHREAD_LOCKS +# include +# endif + +#endif + +/* System specific lock function wrappers. + */ + +/* Thread stuff */ + +#ifdef HAVE_WIN32_LOCKS +static int gnutls_system_mutex_init(void **priv) +{ + CRITICAL_SECTION *lock = malloc(sizeof(CRITICAL_SECTION)); + + if (lock == NULL) + return GNUTLS_E_MEMORY_ERROR; + + InitializeCriticalSection(lock); + + *priv = lock; + + return 0; +} + +static int gnutls_system_mutex_deinit(void **priv) +{ + DeleteCriticalSection((CRITICAL_SECTION *) * priv); + free(*priv); + + return 0; +} + +static int gnutls_system_mutex_lock(void **priv) +{ + EnterCriticalSection((CRITICAL_SECTION *) * priv); + return 0; +} + +static int gnutls_system_mutex_unlock(void **priv) +{ + LeaveCriticalSection((CRITICAL_SECTION *) * priv); + return 0; +} + +#endif /* WIN32_LOCKS */ + +#ifdef HAVE_PTHREAD_LOCKS + +static int gnutls_system_mutex_init(void **priv) +{ + pthread_mutex_t *lock = malloc(sizeof(pthread_mutex_t)); + int ret; + + if (lock == NULL) + return GNUTLS_E_MEMORY_ERROR; + + ret = pthread_mutex_init(lock, NULL); + if (ret) { + free(lock); + gnutls_assert(); + return GNUTLS_E_LOCKING_ERROR; + } + + *priv = lock; + + return 0; +} + +static int gnutls_system_mutex_deinit(void **priv) +{ + pthread_mutex_destroy((pthread_mutex_t *) * priv); + free(*priv); + return 0; +} + +static int gnutls_system_mutex_lock(void **priv) +{ + if (pthread_mutex_lock((pthread_mutex_t *) * priv)) { + gnutls_assert(); + return GNUTLS_E_LOCKING_ERROR; + } + + return 0; +} + +static int gnutls_system_mutex_unlock(void **priv) +{ + if (pthread_mutex_unlock((pthread_mutex_t *) * priv)) { + gnutls_assert(); + return GNUTLS_E_LOCKING_ERROR; + } + + return 0; +} + +#endif /* PTHREAD_LOCKS */ + +#ifdef HAVE_NO_LOCKS + +static int gnutls_system_mutex_init(void **priv) +{ + return 0; +} + +static int gnutls_system_mutex_deinit(void **priv) +{ + return 0; +} + +static int gnutls_system_mutex_lock(void **priv) +{ + return 0; +} + +static int gnutls_system_mutex_unlock(void **priv) +{ + return 0; +} + +#endif /* NO_LOCKS */ + +mutex_init_func gnutls_mutex_init = gnutls_system_mutex_init; +mutex_deinit_func gnutls_mutex_deinit = gnutls_system_mutex_deinit; +mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock; +mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock; + diff --git a/lib/system/vasprintf.c b/lib/system/vasprintf.c new file mode 100644 index 0000000000..8362942a20 --- /dev/null +++ b/lib/system/vasprintf.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2008-2014 Intel Corporation. + * + * Authors: David Woodhouse + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "vasprintf.h" + +#ifndef HAVE_VASPRINTF + +int _gnutls_vasprintf(char **strp, const char *fmt, va_list ap) +{ + va_list ap2; + char *res = NULL; + int len = 160, len2; + int ret = 0; + int errno_save = -ENOMEM; + + res = malloc(160); + if (!res) + goto err; + + /* Use a copy of 'ap', preserving it in case we need to retry into + a larger buffer. 160 characters should be sufficient for most + strings in openconnect. */ +#ifdef HAVE_VA_COPY + va_copy(ap2, ap); +#elif defined(HAVE___VA_COPY) + __va_copy(ap2, ap); +#else +#error No va_copy()! + /* You could try this. */ + ap2 = ap; + /* Or this */ + *ap2 = *ap; +#endif + len = vsnprintf(res, 160, fmt, ap2); + va_end(ap2); + + if (len < 0) { + printf_err: + errno_save = errno; + free(res); + res = NULL; + goto err; + } + if (len >= 0 && len < 160) + goto out; + + free(res); + res = malloc(len+1); + if (!res) + goto err; + + len2 = vsnprintf(res, len+1, fmt, ap); + if (len2 < 0 || len2 > len) + goto printf_err; + + ret = 0; + goto out; + + err: + errno = errno_save; + ret = -1; + out: + *strp = res; + return ret; +} + +#endif diff --git a/lib/vasprintf.c b/lib/vasprintf.c deleted file mode 100644 index 8362942a20..0000000000 --- a/lib/vasprintf.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright © 2008-2014 Intel Corporation. - * - * Authors: David Woodhouse - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * version 2.1, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include "vasprintf.h" - -#ifndef HAVE_VASPRINTF - -int _gnutls_vasprintf(char **strp, const char *fmt, va_list ap) -{ - va_list ap2; - char *res = NULL; - int len = 160, len2; - int ret = 0; - int errno_save = -ENOMEM; - - res = malloc(160); - if (!res) - goto err; - - /* Use a copy of 'ap', preserving it in case we need to retry into - a larger buffer. 160 characters should be sufficient for most - strings in openconnect. */ -#ifdef HAVE_VA_COPY - va_copy(ap2, ap); -#elif defined(HAVE___VA_COPY) - __va_copy(ap2, ap); -#else -#error No va_copy()! - /* You could try this. */ - ap2 = ap; - /* Or this */ - *ap2 = *ap; -#endif - len = vsnprintf(res, 160, fmt, ap2); - va_end(ap2); - - if (len < 0) { - printf_err: - errno_save = errno; - free(res); - res = NULL; - goto err; - } - if (len >= 0 && len < 160) - goto out; - - free(res); - res = malloc(len+1); - if (!res) - goto err; - - len2 = vsnprintf(res, len+1, fmt, ap); - if (len2 < 0 || len2 > len) - goto printf_err; - - ret = 0; - goto out; - - err: - errno = errno_save; - ret = -1; - out: - *strp = res; - return ret; -} - -#endif -- cgit v1.2.1