From e971d6aded5af7b2d47107717b04a5d9bf521a29 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/system/certs.c | 303 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/system/iconv.c | 212 ++++++++++++++++++++++++++++++++++ lib/system/inet_ntop.c | 250 ++++++++++++++++++++++++++++++++++++++++ lib/system/inet_pton.c | 266 +++++++++++++++++++++++++++++++++++++++++++ lib/system/sockets.c | 188 ++++++++++++++++++++++++++++++ lib/system/threads.c | 168 +++++++++++++++++++++++++++ lib/system/vasprintf.c | 84 ++++++++++++++ 7 files changed, 1471 insertions(+) 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/inet_pton.c create mode 100644 lib/system/sockets.c create mode 100644 lib/system/threads.c create mode 100644 lib/system/vasprintf.c (limited to 'lib/system') 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 + * + */ + +#include +#include "gnutls_int.h" +#include "errors.h" + +#include +#include +#include +#include +#include +#include "system.h" + +#ifdef _WIN32 +# include +# include + +#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/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 + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include /* needed to define AF_ values on UNIX */ +#endif + +#ifdef HAVE_WINSOCK2_H +#include /* 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 +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_ARPA_NAMESER_H +#include +#endif + +#include +#include + +#include + +#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 + * + */ + +#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 -- cgit v1.2.1