summaryrefslogtreecommitdiff
path: root/lib/system
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-07-25 15:47:19 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-07-27 08:58:53 +0200
commite971d6aded5af7b2d47107717b04a5d9bf521a29 (patch)
treed41447118e8cc99395081ae70817692c08394a5f /lib/system
parentef861381871a77719aac292d7ac3ee6a961b53cc (diff)
downloadgnutls-e971d6aded5af7b2d47107717b04a5d9bf521a29.tar.gz
split system.c to various files under system/
Diffstat (limited to 'lib/system')
-rw-r--r--lib/system/certs.c303
-rw-r--r--lib/system/iconv.c212
-rw-r--r--lib/system/inet_ntop.c250
-rw-r--r--lib/system/inet_pton.c266
-rw-r--r--lib/system/sockets.c188
-rw-r--r--lib/system/threads.c168
-rw-r--r--lib/system/vasprintf.c84
7 files changed, 1471 insertions, 0 deletions
diff --git a/lib/system/certs.c b/lib/system/certs.c
new file mode 100644
index 0000000000..e84fde3202
--- /dev/null
+++ b/lib/system/certs.c
@@ -0,0 +1,303 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <config.h>
+#include "gnutls_int.h"
+#include "errors.h"
+
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <c-ctype.h>
+#include "system.h"
+
+#ifdef _WIN32
+# include <windows.h>
+# include <wincrypt.h>
+
+#else /* !_WIN32 */
+
+# include <poll.h>
+
+# if defined(HAVE_GETPWUID_R)
+# include <pwd.h>
+# 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 <dirent.h>
+# include <unistd.h>
+
+# 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <config.h>
+#include <system.h>
+#include "gnutls_int.h"
+#include "errors.h"
+
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <c-ctype.h>
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <winnls.h>
+
+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 <iconv.h>
+
+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 <http://www.gnu.org/licenses/>. */
+
+/*
+ * 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 <config.h>
+
+#ifndef HAVE_INET_NTOP
+
+# include <stdio.h>
+# include <string.h>
+# include <errno.h>
+# include <sys/socket.h>
+# 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/inet_pton.c b/lib/system/inet_pton.c
new file mode 100644
index 0000000000..cc9254fd4c
--- /dev/null
+++ b/lib/system/inet_pton.c
@@ -0,0 +1,266 @@
+/*
+ * 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 <config.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h> /* needed to define AF_ values on UNIX */
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h> /* needed to define AF_ values on Windows */
+#if _MSC_VER < 1600 /* errno.h defines EAFNOSUPPORT in Windows VC10 (and presumably eventually in VC11 ...) */
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include <system.h>
+
+#ifndef HAVE_INET_PTON
+
+#ifndef NS_INADDRSZ
+#define NS_INADDRSZ 4
+#endif
+#ifndef NS_IN6ADDRSZ
+#define NS_IN6ADDRSZ 16
+#endif
+#ifndef NS_INT16SZ
+#define NS_INT16SZ 2
+#endif
+
+/*
+ * 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.
+ */
+
+static int inet_pton4 (const char *src, u_char *dst);
+static int inet_pton6 (const char *src, u_char *dst);
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+inet_pton(af, src, dst)
+ int af;
+ const char *src;
+ void *dst;
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+#endif
+
+#ifdef _WIN32
+int inet_aton(const char *cp, struct in_addr *inp)
+{
+ return inet_pton(AF_INET, cp, inp);
+}
+#endif
+
+#ifndef HAVE_INET_PTON
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+ const char *src;
+ u_char *dst;
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ u_char tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ size_t new = *tp * 10 + (pch - digits);
+
+ if (new > 255)
+ return (0);
+ *tp = (u_char) new;
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(src, dst)
+ const char *src;
+ u_char *dst;
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return (0);
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = (int) (tp - colonp);
+ int i;
+
+ if (tp == endp)
+ return (0);
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
+
+#endif /* HAVE_INET_PTON */
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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <config.h>
+#include <system.h>
+#include "gnutls_int.h"
+#include "errors.h"
+
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <c-ctype.h>
+
+#ifdef _WIN32
+# include <windows.h>
+#else /* !_WIN32 */
+# include <poll.h>
+#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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <config.h>
+#include <system.h>
+#include "gnutls_int.h"
+#include "errors.h"
+
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <c-ctype.h>
+
+#ifdef _WIN32
+# include <windows.h>
+# include <wincrypt.h>
+
+#else /* !_WIN32 */
+
+# ifdef HAVE_PTHREAD_LOCKS
+# include <pthread.h>
+# 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 <dwmw2@infradead.org>
+ *
+ * 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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#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