diff options
Diffstat (limited to 'src/common')
96 files changed, 0 insertions, 43832 deletions
diff --git a/src/common/Makefile.nmake b/src/common/Makefile.nmake deleted file mode 100644 index a1c819fffa..0000000000 --- a/src/common/Makefile.nmake +++ /dev/null @@ -1,28 +0,0 @@ -all: libor.lib libor-crypto.lib libor-event.lib - -CFLAGS = /O2 /MT /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common \ - /I ..\ext - -LIBOR_OBJECTS = address.obj backtrace.obj compat.obj container.obj di_ops.obj \ - log.obj memarea.obj mempool.obj procmon.obj sandbox.obj util.obj \ - util_codedigest.obj - -LIBOR_CRYPTO_OBJECTS = aes.obj crypto.obj crypto_format.obj compress.obj compress_zlib.obj \ - tortls.obj crypto_curve25519.obj curve25519-donna.obj - -LIBOR_EVENT_OBJECTS = compat_libevent.obj - -curve25519-donna.obj: ..\ext\curve25519_donna\curve25519-donna.c - $(CC) $(CFLAGS) /D inline=_inline /c ..\ext\curve25519_donna\curve25519-donna.c - -libor.lib: $(LIBOR_OBJECTS) - lib $(LIBOR_OBJECTS) /out:libor.lib - -libor-crypto.lib: $(LIBOR_CRYPTO_OBJECTS) - lib $(LIBOR_CRYPTO_OBJECTS) /out:libor-crypto.lib - -libor-event.lib: $(LIBOR_EVENT_OBJECTS) - lib $(LIBOR_EVENT_OBJECTS) /out:libor-event.lib - -clean: - del *.obj *.lib libor*.lib diff --git a/src/common/address.c b/src/common/address.c deleted file mode 100644 index 9446675712..0000000000 --- a/src/common/address.c +++ /dev/null @@ -1,2176 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file address.c - * \brief Functions to use and manipulate the tor_addr_t structure. - **/ - -#define ADDRESS_PRIVATE - -#include "orconfig.h" - -#ifdef _WIN32 -/* For access to structs needed by GetAdaptersAddresses */ -#ifndef WIN32_LEAN_AND_MEAN -#error "orconfig.h didn't define WIN32_LEAN_AND_MEAN" -#endif -#ifndef WINVER -#error "orconfig.h didn't define WINVER" -#endif -#ifndef _WIN32_WINNT -#error "orconfig.h didn't define _WIN32_WINNT" -#endif -#if WINVER < 0x0501 -#error "winver too low" -#endif -#if _WIN32_WINNT < 0x0501 -#error "winver too low" -#endif -#include <winsock2.h> -#include <process.h> -#include <windows.h> -#include <iphlpapi.h> -#endif /* defined(_WIN32) */ - -#include "compat.h" -#include "util.h" -#include "util_format.h" -#include "address.h" -#include "torlog.h" -#include "container.h" -#include "sandbox.h" - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> /* FreeBSD needs this to know what version it is */ -#endif -#ifdef HAVE_SYS_UN_H -#include <sys/un.h> -#endif -#ifdef HAVE_IFADDRS_H -#include <ifaddrs.h> -#endif -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif -#ifdef HAVE_NET_IF_H -#include <net/if.h> -#endif -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -/* tor_addr_is_null() and maybe other functions rely on AF_UNSPEC being 0 to - * work correctly. Bail out here if we've found a platform where AF_UNSPEC - * isn't 0. */ -#if AF_UNSPEC != 0 -#error We rely on AF_UNSPEC being 0. Let us know about your platform, please! -#endif - -/** Convert the tor_addr_t in <b>a</b>, with port in <b>port</b>, into a - * sockaddr object in *<b>sa_out</b> of object size <b>len</b>. If not enough - * room is available in sa_out, or on error, return 0. On success, return - * the length of the sockaddr. - * - * Interface note: ordinarily, we return -1 for error. We can't do that here, - * since socklen_t is unsigned on some platforms. - **/ -socklen_t -tor_addr_to_sockaddr(const tor_addr_t *a, - uint16_t port, - struct sockaddr *sa_out, - socklen_t len) -{ - memset(sa_out, 0, len); - - sa_family_t family = tor_addr_family(a); - if (family == AF_INET) { - struct sockaddr_in *sin; - if (len < (int)sizeof(struct sockaddr_in)) - return 0; - sin = (struct sockaddr_in *)sa_out; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin->sin_len = sizeof(struct sockaddr_in); -#endif - sin->sin_family = AF_INET; - sin->sin_port = htons(port); - sin->sin_addr.s_addr = tor_addr_to_ipv4n(a); - return sizeof(struct sockaddr_in); - } else if (family == AF_INET6) { - struct sockaddr_in6 *sin6; - if (len < (int)sizeof(struct sockaddr_in6)) - return 0; - sin6 = (struct sockaddr_in6 *)sa_out; -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN - sin6->sin6_len = sizeof(struct sockaddr_in6); -#endif - sin6->sin6_family = AF_INET6; - sin6->sin6_port = htons(port); - memcpy(&sin6->sin6_addr, tor_addr_to_in6_assert(a), - sizeof(struct in6_addr)); - return sizeof(struct sockaddr_in6); - } else { - return 0; - } -} - -/** Set address <b>a</b> to zero. This address belongs to - * the AF_UNIX family. */ -static void -tor_addr_make_af_unix(tor_addr_t *a) -{ - memset(a, 0, sizeof(*a)); - a->family = AF_UNIX; -} - -/** Set the tor_addr_t in <b>a</b> to contain the socket address contained in - * <b>sa</b>. IF <b>port_out</b> is non-NULL and <b>sa</b> contains a port, - * set *<b>port_out</b> to that port. Return 0 on success and -1 on - * failure. */ -int -tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, - uint16_t *port_out) -{ - tor_assert(a); - tor_assert(sa); - - /* This memset is redundant; leaving it in to avoid any future accidents, - however. */ - memset(a, 0, sizeof(*a)); - - if (sa->sa_family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in *) sa; - tor_addr_from_ipv4n(a, sin->sin_addr.s_addr); - if (port_out) - *port_out = ntohs(sin->sin_port); - } else if (sa->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; - tor_addr_from_in6(a, &sin6->sin6_addr); - if (port_out) - *port_out = ntohs(sin6->sin6_port); - } else if (sa->sa_family == AF_UNIX) { - tor_addr_make_af_unix(a); - return 0; - } else { - tor_addr_make_unspec(a); - return -1; - } - return 0; -} - -/** Return a newly allocated string holding the address described in - * <b>sa</b>. AF_UNIX, AF_UNSPEC, AF_INET, and AF_INET6 are supported. */ -char * -tor_sockaddr_to_str(const struct sockaddr *sa) -{ - char address[TOR_ADDR_BUF_LEN]; - char *result; - tor_addr_t addr; - uint16_t port; -#ifdef HAVE_SYS_UN_H - if (sa->sa_family == AF_UNIX) { - struct sockaddr_un *s_un = (struct sockaddr_un *)sa; - tor_asprintf(&result, "unix:%s", s_un->sun_path); - return result; - } -#endif /* defined(HAVE_SYS_UN_H) */ - if (sa->sa_family == AF_UNSPEC) - return tor_strdup("unspec"); - - if (tor_addr_from_sockaddr(&addr, sa, &port) < 0) - return NULL; - if (! tor_addr_to_str(address, &addr, sizeof(address), 1)) - return NULL; - tor_asprintf(&result, "%s:%d", address, (int)port); - return result; -} - -/** Set address <b>a</b> to the unspecified address. This address belongs to - * no family. */ -void -tor_addr_make_unspec(tor_addr_t *a) -{ - memset(a, 0, sizeof(*a)); - a->family = AF_UNSPEC; -} - -/** Set address <b>a</b> to the null address in address family <b>family</b>. - * The null address for AF_INET is 0.0.0.0. The null address for AF_INET6 is - * [::]. AF_UNSPEC is all null. */ -void -tor_addr_make_null(tor_addr_t *a, sa_family_t family) -{ - memset(a, 0, sizeof(*a)); - a->family = family; -} - -/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set - * *<b>addr</b> to the proper IP address and family. The <b>family</b> - * argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a - * <i>preferred</i> family, though another one may be returned if only one - * family is implemented for this address. - * - * Return 0 on success, -1 on failure; 1 on transient failure. - */ -MOCK_IMPL(int, -tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) -{ - /* Perhaps eventually this should be replaced by a tor_getaddrinfo or - * something. - */ - struct in_addr iaddr; - struct in6_addr iaddr6; - tor_assert(name); - tor_assert(addr); - tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC); - if (!*name) { - /* Empty address is an error. */ - return -1; - } else if (tor_inet_pton(AF_INET, name, &iaddr)) { - /* It's an IPv4 IP. */ - if (family == AF_INET6) - return -1; - tor_addr_from_in(addr, &iaddr); - return 0; - } else if (tor_inet_pton(AF_INET6, name, &iaddr6)) { - if (family == AF_INET) - return -1; - tor_addr_from_in6(addr, &iaddr6); - return 0; - } else { -#ifdef HAVE_GETADDRINFO - int err; - struct addrinfo *res=NULL, *res_p; - struct addrinfo *best=NULL; - struct addrinfo hints; - int result = -1; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = family; - hints.ai_socktype = SOCK_STREAM; - err = sandbox_getaddrinfo(name, NULL, &hints, &res); - /* The check for 'res' here shouldn't be necessary, but it makes static - * analysis tools happy. */ - if (!err && res) { - best = NULL; - for (res_p = res; res_p; res_p = res_p->ai_next) { - if (family == AF_UNSPEC) { - if (res_p->ai_family == AF_INET) { - best = res_p; - break; - } else if (res_p->ai_family == AF_INET6 && !best) { - best = res_p; - } - } else if (family == res_p->ai_family) { - best = res_p; - break; - } - } - if (!best) - best = res; - if (best->ai_family == AF_INET) { - tor_addr_from_in(addr, - &((struct sockaddr_in*)best->ai_addr)->sin_addr); - result = 0; - } else if (best->ai_family == AF_INET6) { - tor_addr_from_in6(addr, - &((struct sockaddr_in6*)best->ai_addr)->sin6_addr); - result = 0; - } - sandbox_freeaddrinfo(res); - return result; - } - return (err == EAI_AGAIN) ? 1 : -1; -#else /* !(defined(HAVE_GETADDRINFO)) */ - struct hostent *ent; - int err; -#ifdef HAVE_GETHOSTBYNAME_R_6_ARG - char buf[2048]; - struct hostent hostent; - int r; - r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err); -#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) - char buf[2048]; - struct hostent hostent; - ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err); -#elif defined(HAVE_GETHOSTBYNAME_R_3_ARG) - struct hostent_data data; - struct hostent hent; - memset(&data, 0, sizeof(data)); - err = gethostbyname_r(name, &hent, &data); - ent = err ? NULL : &hent; -#else - ent = gethostbyname(name); -#ifdef _WIN32 - err = WSAGetLastError(); -#else - err = h_errno; -#endif -#endif /* defined(HAVE_GETHOSTBYNAME_R_6_ARG) || ... */ - if (ent) { - if (ent->h_addrtype == AF_INET) { - tor_addr_from_in(addr, (struct in_addr*) ent->h_addr); - } else if (ent->h_addrtype == AF_INET6) { - tor_addr_from_in6(addr, (struct in6_addr*) ent->h_addr); - } else { - tor_assert(0); // LCOV_EXCL_LINE: gethostbyname() returned bizarre type - } - return 0; - } -#ifdef _WIN32 - return (err == WSATRY_AGAIN) ? 1 : -1; -#else - return (err == TRY_AGAIN) ? 1 : -1; -#endif -#endif /* defined(HAVE_GETADDRINFO) */ - } -} - -/** Return true iff <b>ip</b> is an IP reserved to localhost or local networks - * in RFC1918 or RFC4193 or RFC4291. (fec0::/10, deprecated by RFC3879, is - * also treated as internal for now.) - */ -int -tor_addr_is_internal_(const tor_addr_t *addr, int for_listening, - const char *filename, int lineno) -{ - uint32_t iph4 = 0; - uint32_t iph6[4]; - - tor_assert(addr); - sa_family_t v_family = tor_addr_family(addr); - - if (v_family == AF_INET) { - iph4 = tor_addr_to_ipv4h(addr); - } else if (v_family == AF_INET6) { - if (tor_addr_is_v4(addr)) { /* v4-mapped */ - uint32_t *addr32 = NULL; - v_family = AF_INET; - // Work around an incorrect NULL pointer dereference warning in - // "clang --analyze" due to limited analysis depth - addr32 = tor_addr_to_in6_addr32(addr); - // To improve performance, wrap this assertion in: - // #if !defined(__clang_analyzer__) || PARANOIA - tor_assert(addr32); - iph4 = ntohl(addr32[3]); - } - } - - if (v_family == AF_INET6) { - const uint32_t *a32 = tor_addr_to_in6_addr32(addr); - iph6[0] = ntohl(a32[0]); - iph6[1] = ntohl(a32[1]); - iph6[2] = ntohl(a32[2]); - iph6[3] = ntohl(a32[3]); - if (for_listening && !iph6[0] && !iph6[1] && !iph6[2] && !iph6[3]) /* :: */ - return 0; - - if (((iph6[0] & 0xfe000000) == 0xfc000000) || /* fc00/7 - RFC4193 */ - ((iph6[0] & 0xffc00000) == 0xfe800000) || /* fe80/10 - RFC4291 */ - ((iph6[0] & 0xffc00000) == 0xfec00000)) /* fec0/10 D- RFC3879 */ - return 1; - - if (!iph6[0] && !iph6[1] && !iph6[2] && - ((iph6[3] & 0xfffffffe) == 0x00000000)) /* ::/127 */ - return 1; - - return 0; - } else if (v_family == AF_INET) { - if (for_listening && !iph4) /* special case for binding to 0.0.0.0 */ - return 0; - if (((iph4 & 0xff000000) == 0x0a000000) || /* 10/8 */ - ((iph4 & 0xff000000) == 0x00000000) || /* 0/8 */ - ((iph4 & 0xff000000) == 0x7f000000) || /* 127/8 */ - ((iph4 & 0xffff0000) == 0xa9fe0000) || /* 169.254/16 */ - ((iph4 & 0xfff00000) == 0xac100000) || /* 172.16/12 */ - ((iph4 & 0xffff0000) == 0xc0a80000)) /* 192.168/16 */ - return 1; - return 0; - } - - /* unknown address family... assume it's not safe for external use */ - /* rather than tor_assert(0) */ - log_warn(LD_BUG, "tor_addr_is_internal() called from %s:%d with a " - "non-IP address of type %d", filename, lineno, (int)v_family); - tor_fragile_assert(); - return 1; -} - -/** Convert a tor_addr_t <b>addr</b> into a string, and store it in - * <b>dest</b> of size <b>len</b>. Returns a pointer to dest on success, - * or NULL on failure. If <b>decorate</b>, surround IPv6 addresses with - * brackets. - */ -const char * -tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate) -{ - const char *ptr; - tor_assert(addr && dest); - - switch (tor_addr_family(addr)) { - case AF_INET: - /* Shortest addr x.x.x.x + \0 */ - if (len < 8) - return NULL; - ptr = tor_inet_ntop(AF_INET, &addr->addr.in_addr, dest, len); - break; - case AF_INET6: - /* Shortest addr [ :: ] + \0 */ - if (len < (3 + (decorate ? 2 : 0))) - return NULL; - - if (decorate) - ptr = tor_inet_ntop(AF_INET6, &addr->addr.in6_addr, dest+1, len-2); - else - ptr = tor_inet_ntop(AF_INET6, &addr->addr.in6_addr, dest, len); - - if (ptr && decorate) { - *dest = '['; - memcpy(dest+strlen(dest), "]", 2); - tor_assert(ptr == dest+1); - ptr = dest; - } - break; - case AF_UNIX: - tor_snprintf(dest, len, "AF_UNIX"); - ptr = dest; - break; - default: - return NULL; - } - return ptr; -} - -/** Parse an .in-addr.arpa or .ip6.arpa address from <b>address</b>. Return 0 - * if this is not an .in-addr.arpa address or an .ip6.arpa address. Return -1 - * if this is an ill-formed .in-addr.arpa address or an .ip6.arpa address. - * Also return -1 if <b>family</b> is not AF_UNSPEC, and the parsed address - * family does not match <b>family</b>. On success, return 1, and store the - * result, if any, into <b>result</b>, if provided. - * - * If <b>accept_regular</b> is set and the address is in neither recognized - * reverse lookup hostname format, try parsing the address as a regular - * IPv4 or IPv6 address too. - */ -int -tor_addr_parse_PTR_name(tor_addr_t *result, const char *address, - int family, int accept_regular) -{ - if (!strcasecmpend(address, ".in-addr.arpa")) { - /* We have an in-addr.arpa address. */ - char buf[INET_NTOA_BUF_LEN]; - size_t len; - struct in_addr inaddr; - if (family == AF_INET6) - return -1; - - len = strlen(address) - strlen(".in-addr.arpa"); - if (len >= INET_NTOA_BUF_LEN) - return -1; /* Too long. */ - - memcpy(buf, address, len); - buf[len] = '\0'; - if (tor_inet_aton(buf, &inaddr) == 0) - return -1; /* malformed. */ - - /* reverse the bytes */ - inaddr.s_addr = (uint32_t) - (((inaddr.s_addr & 0x000000ff) << 24) - |((inaddr.s_addr & 0x0000ff00) << 8) - |((inaddr.s_addr & 0x00ff0000) >> 8) - |((inaddr.s_addr & 0xff000000) >> 24)); - - if (result) { - tor_addr_from_in(result, &inaddr); - } - return 1; - } - - if (!strcasecmpend(address, ".ip6.arpa")) { - const char *cp; - int n0, n1; - struct in6_addr in6; - - if (family == AF_INET) - return -1; - - cp = address; - for (int i = 0; i < 16; ++i) { - n0 = hex_decode_digit(*cp++); /* The low-order nybble appears first. */ - if (*cp++ != '.') return -1; /* Then a dot. */ - n1 = hex_decode_digit(*cp++); /* The high-order nybble appears first. */ - if (*cp++ != '.') return -1; /* Then another dot. */ - if (n0<0 || n1 < 0) /* Both nybbles must be hex. */ - return -1; - - /* We don't check the length of the string in here. But that's okay, - * since we already know that the string ends with ".ip6.arpa", and - * there is no way to frameshift .ip6.arpa so it fits into the pattern - * of hexdigit, period, hexdigit, period that we enforce above. - */ - - /* Assign from low-byte to high-byte. */ - in6.s6_addr[15-i] = n0 | (n1 << 4); - } - if (strcasecmp(cp, "ip6.arpa")) - return -1; - - if (result) { - tor_addr_from_in6(result, &in6); - } - return 1; - } - - if (accept_regular) { - tor_addr_t tmp; - int r = tor_addr_parse(&tmp, address); - if (r < 0) - return 0; - if (r != family && family != AF_UNSPEC) - return -1; - - if (result) - memcpy(result, &tmp, sizeof(tor_addr_t)); - - return 1; - } - - return 0; -} - -/** Convert <b>addr</b> to an in-addr.arpa name or a .ip6.arpa name, - * and store the result in the <b>outlen</b>-byte buffer at - * <b>out</b>. Returns a non-negative integer on success. - * Returns -1 on failure. */ -int -tor_addr_to_PTR_name(char *out, size_t outlen, - const tor_addr_t *addr) -{ - tor_assert(out); - tor_assert(addr); - - if (addr->family == AF_INET) { - uint32_t a = tor_addr_to_ipv4h(addr); - - return tor_snprintf(out, outlen, "%d.%d.%d.%d.in-addr.arpa", - (int)(uint8_t)((a )&0xff), - (int)(uint8_t)((a>>8 )&0xff), - (int)(uint8_t)((a>>16)&0xff), - (int)(uint8_t)((a>>24)&0xff)); - } else if (addr->family == AF_INET6) { - int i; - char *cp = out; - const uint8_t *bytes = tor_addr_to_in6_addr8(addr); - if (outlen < REVERSE_LOOKUP_NAME_BUF_LEN) - return -1; - for (i = 15; i >= 0; --i) { - uint8_t byte = bytes[i]; - *cp++ = "0123456789abcdef"[byte & 0x0f]; - *cp++ = '.'; - *cp++ = "0123456789abcdef"[byte >> 4]; - *cp++ = '.'; - } - memcpy(cp, "ip6.arpa", 9); /* 8 characters plus NUL */ - return 32 * 2 + 8; - } - return -1; -} - -/** Parse a string <b>s</b> containing an IPv4/IPv6 address, and possibly - * a mask and port or port range. Store the parsed address in - * <b>addr_out</b>, a mask (if any) in <b>mask_out</b>, and port(s) (if any) - * in <b>port_min_out</b> and <b>port_max_out</b>. - * - * The syntax is: - * Address OptMask OptPortRange - * Address ::= IPv4Address / "[" IPv6Address "]" / "*" - * OptMask ::= "/" Integer / - * OptPortRange ::= ":*" / ":" Integer / ":" Integer "-" Integer / - * - * - If mask, minport, or maxport are NULL, we do not want these - * options to be set; treat them as an error if present. - * - If the string has no mask, the mask is set to /32 (IPv4) or /128 (IPv6). - * - If the string has one port, it is placed in both min and max port - * variables. - * - If the string has no port(s), port_(min|max)_out are set to 1 and 65535. - * - * Return an address family on success, or -1 if an invalid address string is - * provided. - * - * If 'flags & TAPMP_EXTENDED_STAR' is false, then the wildcard address '*' - * yield an IPv4 wildcard. - * - * If 'flags & TAPMP_EXTENDED_STAR' is true, then the wildcard address '*' - * yields an AF_UNSPEC wildcard address, which expands to corresponding - * wildcard IPv4 and IPv6 rules, and the following change is made - * in the grammar above: - * Address ::= IPv4Address / "[" IPv6Address "]" / "*" / "*4" / "*6" - * with the new "*4" and "*6" productions creating a wildcard to match - * IPv4 or IPv6 addresses. - * - * If 'flags & TAPMP_EXTENDED_STAR' and 'flags & TAPMP_STAR_IPV4_ONLY' are - * both true, then the wildcard address '*' yields an IPv4 wildcard. - * - * If 'flags & TAPMP_EXTENDED_STAR' and 'flags & TAPMP_STAR_IPV6_ONLY' are - * both true, then the wildcard address '*' yields an IPv6 wildcard. - * - * TAPMP_STAR_IPV4_ONLY and TAPMP_STAR_IPV6_ONLY are mutually exclusive. */ -int -tor_addr_parse_mask_ports(const char *s, - unsigned flags, - tor_addr_t *addr_out, - maskbits_t *maskbits_out, - uint16_t *port_min_out, uint16_t *port_max_out) -{ - char *base = NULL, *address, *mask = NULL, *port = NULL, *rbracket = NULL; - char *endptr; - int any_flag=0, v4map=0; - sa_family_t family; - struct in6_addr in6_tmp; - struct in_addr in_tmp = { .s_addr = 0 }; - - tor_assert(s); - tor_assert(addr_out); - /* We can either only want an IPv4 address or only want an IPv6 address, - * but we can't only want IPv4 & IPv6 at the same time. */ - tor_assert(!((flags & TAPMP_STAR_IPV4_ONLY) - && (flags & TAPMP_STAR_IPV6_ONLY))); - - /** Longest possible length for an address, mask, and port-range combination. - * Includes IP, [], /mask, :, ports */ -#define MAX_ADDRESS_LENGTH (TOR_ADDR_BUF_LEN+2+(1+INET_NTOA_BUF_LEN)+12+1) - - if (strlen(s) > MAX_ADDRESS_LENGTH) { - log_warn(LD_GENERAL, "Impossibly long IP %s; rejecting", escaped(s)); - goto err; - } - base = tor_strdup(s); - - /* Break 'base' into separate strings. */ - address = base; - if (*address == '[') { /* Probably IPv6 */ - address++; - rbracket = strchr(address, ']'); - if (!rbracket) { - log_warn(LD_GENERAL, - "No closing IPv6 bracket in address pattern; rejecting."); - goto err; - } - } - mask = strchr((rbracket?rbracket:address),'/'); - port = strchr((mask?mask:(rbracket?rbracket:address)), ':'); - if (port) - *port++ = '\0'; - if (mask) - *mask++ = '\0'; - if (rbracket) - *rbracket = '\0'; - if (port && mask) - tor_assert(port > mask); - if (mask && rbracket) - tor_assert(mask > rbracket); - - /* Now "address" is the a.b.c.d|'*'|abcd::1 part... - * "mask" is the Mask|Maskbits part... - * and "port" is the *|port|min-max part. - */ - - /* Process the address portion */ - memset(addr_out, 0, sizeof(tor_addr_t)); - - if (!strcmp(address, "*")) { - if (flags & TAPMP_EXTENDED_STAR) { - if (flags & TAPMP_STAR_IPV4_ONLY) { - family = AF_INET; - tor_addr_from_ipv4h(addr_out, 0); - } else if (flags & TAPMP_STAR_IPV6_ONLY) { - static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; - family = AF_INET6; - tor_addr_from_ipv6_bytes(addr_out, nil_bytes); - } else { - family = AF_UNSPEC; - tor_addr_make_unspec(addr_out); - log_info(LD_GENERAL, - "'%s' expands into rules which apply to all IPv4 and IPv6 " - "addresses. (Use accept/reject *4:* for IPv4 or " - "accept[6]/reject[6] *6:* for IPv6.)", s); - } - } else { - family = AF_INET; - tor_addr_from_ipv4h(addr_out, 0); - } - any_flag = 1; - } else if (!strcmp(address, "*4") && (flags & TAPMP_EXTENDED_STAR)) { - family = AF_INET; - tor_addr_from_ipv4h(addr_out, 0); - any_flag = 1; - } else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) { - static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; - family = AF_INET6; - tor_addr_from_ipv6_bytes(addr_out, nil_bytes); - any_flag = 1; - } else if (tor_inet_pton(AF_INET6, address, &in6_tmp) > 0) { - family = AF_INET6; - tor_addr_from_in6(addr_out, &in6_tmp); - } else if (tor_inet_pton(AF_INET, address, &in_tmp) > 0) { - family = AF_INET; - tor_addr_from_in(addr_out, &in_tmp); - } else { - log_warn(LD_GENERAL, "Malformed IP %s in address pattern; rejecting.", - escaped(address)); - goto err; - } - - v4map = tor_addr_is_v4(addr_out); - - /* Parse mask */ - if (maskbits_out) { - int bits = 0; - struct in_addr v4mask; - - if (mask) { /* the caller (tried to) specify a mask */ - bits = (int) strtol(mask, &endptr, 10); - if (!*endptr) { /* strtol converted everything, so it was an integer */ - if ((bits<0 || bits>128) || - (family == AF_INET && bits > 32)) { - log_warn(LD_GENERAL, - "Bad number of mask bits (%d) on address range; rejecting.", - bits); - goto err; - } - } else { /* mask might still be an address-style mask */ - if (tor_inet_pton(AF_INET, mask, &v4mask) > 0) { - bits = addr_mask_get_bits(ntohl(v4mask.s_addr)); - if (bits < 0) { - log_warn(LD_GENERAL, - "IPv4-style mask %s is not a prefix address; rejecting.", - escaped(mask)); - goto err; - } - } else { /* Not IPv4; we don't do address-style IPv6 masks. */ - log_warn(LD_GENERAL, - "Malformed mask on address range %s; rejecting.", - escaped(s)); - goto err; - } - } - if (family == AF_INET6 && v4map) { - if (bits > 32 && bits < 96) { /* Crazy */ - log_warn(LD_GENERAL, - "Bad mask bits %d for V4-mapped V6 address; rejecting.", - bits); - goto err; - } - /* XXXX_IP6 is this really what we want? */ - bits = 96 + bits%32; /* map v4-mapped masks onto 96-128 bits */ - } - if (any_flag) { - log_warn(LD_GENERAL, - "Found bit prefix with wildcard address; rejecting"); - goto err; - } - } else { /* pick an appropriate mask, as none was given */ - if (any_flag) - bits = 0; /* This is okay whether it's V6 or V4 (FIX V4-mapped V6!) */ - else if (tor_addr_family(addr_out) == AF_INET) - bits = 32; - else if (tor_addr_family(addr_out) == AF_INET6) - bits = 128; - } - *maskbits_out = (maskbits_t) bits; - } else { - if (mask) { - log_warn(LD_GENERAL, - "Unexpected mask in address %s; rejecting", escaped(s)); - goto err; - } - } - - /* Parse port(s) */ - if (port_min_out) { - uint16_t port2; - if (!port_max_out) /* caller specified one port; fake the second one */ - port_max_out = &port2; - - if (parse_port_range(port, port_min_out, port_max_out) < 0) { - goto err; - } else if ((*port_min_out != *port_max_out) && port_max_out == &port2) { - log_warn(LD_GENERAL, - "Wanted one port from address range, but there are two."); - - port_max_out = NULL; /* caller specified one port, so set this back */ - goto err; - } - } else { - if (port) { - log_warn(LD_GENERAL, - "Unexpected ports in address %s; rejecting", escaped(s)); - goto err; - } - } - - tor_free(base); - return tor_addr_family(addr_out); - err: - tor_free(base); - return -1; -} - -/** Determine whether an address is IPv4, either native or IPv4-mapped IPv6. - * Note that this is about representation only, as any decent stack will - * reject IPv4-mapped addresses received on the wire (and won't use them - * on the wire either). - */ -int -tor_addr_is_v4(const tor_addr_t *addr) -{ - tor_assert(addr); - - if (tor_addr_family(addr) == AF_INET) - return 1; - - if (tor_addr_family(addr) == AF_INET6) { - /* First two don't need to be ordered */ - uint32_t *a32 = tor_addr_to_in6_addr32(addr); - if (a32[0] == 0 && a32[1] == 0 && ntohl(a32[2]) == 0x0000ffffu) - return 1; - } - - return 0; /* Not IPv4 - unknown family or a full-blood IPv6 address */ -} - -/** Determine whether an address <b>addr</b> is null, either all zeroes or - * belonging to family AF_UNSPEC. - */ -int -tor_addr_is_null(const tor_addr_t *addr) -{ - tor_assert(addr); - - switch (tor_addr_family(addr)) { - case AF_INET6: { - uint32_t *a32 = tor_addr_to_in6_addr32(addr); - return (a32[0] == 0) && (a32[1] == 0) && (a32[2] == 0) && (a32[3] == 0); - } - case AF_INET: - return (tor_addr_to_ipv4n(addr) == 0); - case AF_UNIX: - return 1; - case AF_UNSPEC: - return 1; - default: - log_warn(LD_BUG, "Called with unknown address family %d", - (int)tor_addr_family(addr)); - return 0; - } - //return 1; -} - -/** Return true iff <b>addr</b> is a loopback address */ -int -tor_addr_is_loopback(const tor_addr_t *addr) -{ - tor_assert(addr); - switch (tor_addr_family(addr)) { - case AF_INET6: { - /* ::1 */ - uint32_t *a32 = tor_addr_to_in6_addr32(addr); - return (a32[0] == 0) && (a32[1] == 0) && (a32[2] == 0) && - (ntohl(a32[3]) == 1); - } - case AF_INET: - /* 127.0.0.1 */ - return (tor_addr_to_ipv4h(addr) & 0xff000000) == 0x7f000000; - case AF_UNSPEC: - return 0; - /* LCOV_EXCL_START */ - default: - tor_fragile_assert(); - return 0; - /* LCOV_EXCL_STOP */ - } -} - -/* Is addr valid? - * Checks that addr is non-NULL and not tor_addr_is_null(). - * If for_listening is true, IPv4 addr 0.0.0.0 is allowed. - * It means "bind to all addresses on the local machine". */ -int -tor_addr_is_valid(const tor_addr_t *addr, int for_listening) -{ - /* NULL addresses are invalid regardless of for_listening */ - if (addr == NULL) { - return 0; - } - - /* Only allow IPv4 0.0.0.0 for_listening. */ - if (for_listening && addr->family == AF_INET - && tor_addr_to_ipv4h(addr) == 0) { - return 1; - } - - /* Otherwise, the address is valid if it's not tor_addr_is_null() */ - return !tor_addr_is_null(addr); -} - -/* Is the network-order IPv4 address v4n_addr valid? - * Checks that addr is not zero. - * Except if for_listening is true, where IPv4 addr 0.0.0.0 is allowed. */ -int -tor_addr_is_valid_ipv4n(uint32_t v4n_addr, int for_listening) -{ - /* Any IPv4 address is valid with for_listening. */ - if (for_listening) { - return 1; - } - - /* Otherwise, zero addresses are invalid. */ - return v4n_addr != 0; -} - -/* Is port valid? - * Checks that port is not 0. - * Except if for_listening is true, where port 0 is allowed. - * It means "OS chooses a port". */ -int -tor_port_is_valid(uint16_t port, int for_listening) -{ - /* Any port value is valid with for_listening. */ - if (for_listening) { - return 1; - } - - /* Otherwise, zero ports are invalid. */ - return port != 0; -} - -/** Set <b>dest</b> to equal the IPv4 address in <b>v4addr</b> (given in - * network order). */ -void -tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr) -{ - tor_assert(dest); - memset(dest, 0, sizeof(tor_addr_t)); - dest->family = AF_INET; - dest->addr.in_addr.s_addr = v4addr; -} - -/** Set <b>dest</b> to equal the IPv6 address in the 16 bytes at - * <b>ipv6_bytes</b>. */ -void -tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes) -{ - tor_assert(dest); - tor_assert(ipv6_bytes); - memset(dest, 0, sizeof(tor_addr_t)); - dest->family = AF_INET6; - memcpy(dest->addr.in6_addr.s6_addr, ipv6_bytes, 16); -} - -/** Set <b>dest</b> equal to the IPv6 address in the in6_addr <b>in6</b>. */ -void -tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6) -{ - tor_addr_from_ipv6_bytes(dest, (const char*)in6->s6_addr); -} - -/** Copy a tor_addr_t from <b>src</b> to <b>dest</b>. - */ -void -tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src) -{ - if (src == dest) - return; - tor_assert(src); - tor_assert(dest); - memcpy(dest, src, sizeof(tor_addr_t)); -} - -/** Copy a tor_addr_t from <b>src</b> to <b>dest</b>, taking extra care to - * copy only the well-defined portions. Used for computing hashes of - * addresses. - */ -void -tor_addr_copy_tight(tor_addr_t *dest, const tor_addr_t *src) -{ - tor_assert(src != dest); - tor_assert(src); - tor_assert(dest); - memset(dest, 0, sizeof(tor_addr_t)); - dest->family = src->family; - switch (tor_addr_family(src)) - { - case AF_INET: - dest->addr.in_addr.s_addr = src->addr.in_addr.s_addr; - break; - case AF_INET6: - memcpy(dest->addr.in6_addr.s6_addr, src->addr.in6_addr.s6_addr, 16); - case AF_UNSPEC: - break; - // LCOV_EXCL_START - default: - tor_fragile_assert(); - // LCOV_EXCL_STOP - } -} - -/** Given two addresses <b>addr1</b> and <b>addr2</b>, return 0 if the two - * addresses are equivalent under the mask mbits, less than 0 if addr1 - * precedes addr2, and greater than 0 otherwise. - * - * Different address families (IPv4 vs IPv6) are always considered unequal if - * <b>how</b> is CMP_EXACT; otherwise, IPv6-mapped IPv4 addresses are - * considered equivalent to their IPv4 equivalents. - * - * As a special case, all pointer-wise distinct AF_UNIX addresses are always - * considered unequal since tor_addr_t currently does not contain the - * information required to make the comparison. - */ -int -tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, - tor_addr_comparison_t how) -{ - return tor_addr_compare_masked(addr1, addr2, 128, how); -} - -/** As tor_addr_compare(), but only looks at the first <b>mask</b> bits of - * the address. - * - * Reduce over-specific masks (>128 for ipv6, >32 for ipv4) to 128 or 32. - * - * The mask is interpreted relative to <b>addr1</b>, so that if a is - * \::ffff:1.2.3.4, and b is 3.4.5.6, - * tor_addr_compare_masked(a,b,100,CMP_SEMANTIC) is the same as - * -tor_addr_compare_masked(b,a,4,CMP_SEMANTIC). - * - * We guarantee that the ordering from tor_addr_compare_masked is a total - * order on addresses, but not that it is any particular order, or that it - * will be the same from one version to the next. - */ -int -tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, - maskbits_t mbits, tor_addr_comparison_t how) -{ - /** Helper: Evaluates to -1 if a is less than b, 0 if a equals b, or 1 if a - * is greater than b. May evaluate a and b more than once. */ -#define TRISTATE(a,b) (((a)<(b))?-1: (((a)==(b))?0:1)) - sa_family_t family1, family2, v_family1, v_family2; - - tor_assert(addr1 && addr2); - - v_family1 = family1 = tor_addr_family(addr1); - v_family2 = family2 = tor_addr_family(addr2); - - if (family1==family2) { - /* When the families are the same, there's only one way to do the - * comparison: exactly. */ - int r; - switch (family1) { - case AF_UNSPEC: - return 0; /* All unspecified addresses are equal */ - case AF_INET: { - uint32_t a1 = tor_addr_to_ipv4h(addr1); - uint32_t a2 = tor_addr_to_ipv4h(addr2); - if (mbits <= 0) - return 0; - if (mbits > 32) - mbits = 32; - a1 >>= (32-mbits); - a2 >>= (32-mbits); - r = TRISTATE(a1, a2); - return r; - } - case AF_INET6: { - if (mbits > 128) - mbits = 128; - - const uint8_t *a1 = tor_addr_to_in6_addr8(addr1); - const uint8_t *a2 = tor_addr_to_in6_addr8(addr2); - const int bytes = mbits >> 3; - const int leftover_bits = mbits & 7; - if (bytes && (r = tor_memcmp(a1, a2, bytes))) { - return r; - } else if (leftover_bits) { - uint8_t b1 = a1[bytes] >> (8-leftover_bits); - uint8_t b2 = a2[bytes] >> (8-leftover_bits); - return TRISTATE(b1, b2); - } else { - return 0; - } - } - case AF_UNIX: - /* HACKHACKHACKHACKHACK: - * tor_addr_t doesn't contain a copy of sun_path, so it's not - * possible to compare this at all. - * - * Since the only time we currently actually should be comparing - * 2 AF_UNIX addresses is when dealing with ISO_CLIENTADDR (which - * is disabled for AF_UNIX SocksPorts anyway), this just does - * a pointer comparison. - * - * See: #20261. - */ - if (addr1 < addr2) - return -1; - else if (addr1 == addr2) - return 0; - else - return 1; - /* LCOV_EXCL_START */ - default: - tor_fragile_assert(); - return 0; - /* LCOV_EXCL_STOP */ - } - } else if (how == CMP_EXACT) { - /* Unequal families and an exact comparison? Stop now! */ - return TRISTATE(family1, family2); - } - - if (mbits == 0) - return 0; - - if (family1 == AF_INET6 && tor_addr_is_v4(addr1)) - v_family1 = AF_INET; - if (family2 == AF_INET6 && tor_addr_is_v4(addr2)) - v_family2 = AF_INET; - if (v_family1 == v_family2) { - /* One or both addresses are a mapped ipv4 address. */ - uint32_t a1, a2; - if (family1 == AF_INET6) { - a1 = tor_addr_to_mapped_ipv4h(addr1); - if (mbits <= 96) - return 0; - mbits -= 96; /* We just decided that the first 96 bits of a1 "match". */ - } else { - a1 = tor_addr_to_ipv4h(addr1); - } - if (family2 == AF_INET6) { - a2 = tor_addr_to_mapped_ipv4h(addr2); - } else { - a2 = tor_addr_to_ipv4h(addr2); - } - if (mbits > 32) mbits = 32; - a1 >>= (32-mbits); - a2 >>= (32-mbits); - return TRISTATE(a1, a2); - } else { - /* Unequal families, and semantic comparison, and no semantic family - * matches. */ - return TRISTATE(family1, family2); - } -} - -/** Input for siphash, to produce some output for an unspec value. */ -static const uint32_t unspec_hash_input[] = { 0x4e4df09f, 0x92985342 }; - -/** Return a hash code based on the address addr. DOCDOC extra */ -uint64_t -tor_addr_hash(const tor_addr_t *addr) -{ - switch (tor_addr_family(addr)) { - case AF_INET: - return siphash24g(&addr->addr.in_addr.s_addr, 4); - case AF_UNSPEC: - return siphash24g(unspec_hash_input, sizeof(unspec_hash_input)); - case AF_INET6: - return siphash24g(&addr->addr.in6_addr.s6_addr, 16); - /* LCOV_EXCL_START */ - default: - tor_fragile_assert(); - return 0; - /* LCOV_EXCL_STOP */ - } -} - -/** As tor_addr_hash, but use a particular siphash key. */ -uint64_t -tor_addr_keyed_hash(const struct sipkey *key, const tor_addr_t *addr) -{ - /* This is duplicate code with tor_addr_hash, since this function needs to - * be backportable all the way to 0.2.9. */ - - switch (tor_addr_family(addr)) { - case AF_INET: - return siphash24(&addr->addr.in_addr.s_addr, 4, key); - case AF_UNSPEC: - return siphash24(unspec_hash_input, sizeof(unspec_hash_input), key); - case AF_INET6: - return siphash24(&addr->addr.in6_addr.s6_addr, 16, key); - default: - /* LCOV_EXCL_START */ - tor_fragile_assert(); - return 0; - /* LCOV_EXCL_STOP */ - } -} - -/** Return a newly allocated string with a representation of <b>addr</b>. */ -char * -tor_addr_to_str_dup(const tor_addr_t *addr) -{ - char buf[TOR_ADDR_BUF_LEN]; - if (tor_addr_to_str(buf, addr, sizeof(buf), 0)) { - return tor_strdup(buf); - } else { - return tor_strdup("<unknown address type>"); - } -} - -/** Return a string representing the address <b>addr</b>. This string - * is statically allocated, and must not be freed. Each call to - * <b>fmt_addr_impl</b> invalidates the last result of the function. - * This function is not thread-safe. If <b>decorate</b> is set, add - * brackets to IPv6 addresses. - * - * It's better to use the wrapper macros of this function: - * <b>fmt_addr()</b> and <b>fmt_and_decorate_addr()</b>. - */ -const char * -fmt_addr_impl(const tor_addr_t *addr, int decorate) -{ - static char buf[TOR_ADDR_BUF_LEN]; - if (!addr) return "<null>"; - if (tor_addr_to_str(buf, addr, sizeof(buf), decorate)) - return buf; - else - return "???"; -} - -/** Return a string representing the pair <b>addr</b> and <b>port</b>. - * This calls fmt_and_decorate_addr internally, so IPv6 addresses will - * have brackets, and the caveats of fmt_addr_impl apply. - */ -const char * -fmt_addrport(const tor_addr_t *addr, uint16_t port) -{ - /* Add space for a colon and up to 5 digits. */ - static char buf[TOR_ADDR_BUF_LEN + 6]; - tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port); - return buf; -} - -/** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4 - * addresses. Also not thread-safe, also clobbers its return buffer on - * repeated calls. */ -const char * -fmt_addr32(uint32_t addr) -{ - static char buf[INET_NTOA_BUF_LEN]; - struct in_addr in; - in.s_addr = htonl(addr); - tor_inet_ntoa(&in, buf, sizeof(buf)); - return buf; -} - -/** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string - * may be an IPv4 address, an IPv6 address, or an IPv6 address surrounded by - * square brackets. - * - * Return an address family on success, or -1 if an invalid address string is - * provided. */ -int -tor_addr_parse(tor_addr_t *addr, const char *src) -{ - /* Holds substring of IPv6 address after removing square brackets */ - char *tmp = NULL; - int result; - struct in_addr in_tmp; - struct in6_addr in6_tmp; - tor_assert(addr && src); - if (src[0] == '[' && src[1]) - src = tmp = tor_strndup(src+1, strlen(src)-2); - - if (tor_inet_pton(AF_INET6, src, &in6_tmp) > 0) { - result = AF_INET6; - tor_addr_from_in6(addr, &in6_tmp); - } else if (tor_inet_pton(AF_INET, src, &in_tmp) > 0) { - result = AF_INET; - tor_addr_from_in(addr, &in_tmp); - } else { - result = -1; - } - - tor_free(tmp); - return result; -} - -/** Parse an address or address-port combination from <b>s</b>, resolve the - * address as needed, and put the result in <b>addr_out</b> and (optionally) - * <b>port_out</b>. Return 0 on success, negative on failure. */ -int -tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) -{ - const char *port; - tor_addr_t addr; - uint16_t portval; - char *tmp = NULL; - - tor_assert(s); - tor_assert(addr_out); - - s = eat_whitespace(s); - - if (*s == '[') { - port = strstr(s, "]"); - if (!port) - goto err; - tmp = tor_strndup(s+1, port-(s+1)); - port = port+1; - if (*port == ':') - port++; - else - port = NULL; - } else { - port = strchr(s, ':'); - if (port) - tmp = tor_strndup(s, port-s); - else - tmp = tor_strdup(s); - if (port) - ++port; - } - - if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0) - goto err; - tor_free(tmp); - - if (port) { - portval = (int) tor_parse_long(port, 10, 1, 65535, NULL, NULL); - if (!portval) - goto err; - } else { - portval = 0; - } - - if (port_out) - *port_out = portval; - tor_addr_copy(addr_out, &addr); - - return 0; - err: - tor_free(tmp); - return -1; -} - -#ifdef _WIN32 -typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)( - ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG); -#endif - -#ifdef HAVE_IFADDRS_TO_SMARTLIST -/* - * Convert a linked list consisting of <b>ifaddrs</b> structures - * into smartlist of <b>tor_addr_t</b> structures. - */ -STATIC smartlist_t * -ifaddrs_to_smartlist(const struct ifaddrs *ifa, sa_family_t family) -{ - smartlist_t *result = smartlist_new(); - const struct ifaddrs *i; - - for (i = ifa; i; i = i->ifa_next) { - tor_addr_t tmp; - if ((i->ifa_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) - continue; - if (!i->ifa_addr) - continue; - if (i->ifa_addr->sa_family != AF_INET && - i->ifa_addr->sa_family != AF_INET6) - continue; - if (family != AF_UNSPEC && i->ifa_addr->sa_family != family) - continue; - if (tor_addr_from_sockaddr(&tmp, i->ifa_addr, NULL) < 0) - continue; - smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); - } - - return result; -} - -/** Use getiffaddrs() function to get list of current machine - * network interface addresses. Represent the result by smartlist of - * <b>tor_addr_t</b> structures. - */ -STATIC smartlist_t * -get_interface_addresses_ifaddrs(int severity, sa_family_t family) -{ - - /* Most free Unixy systems provide getifaddrs, which gives us a linked list - * of struct ifaddrs. */ - struct ifaddrs *ifa = NULL; - smartlist_t *result; - if (getifaddrs(&ifa) < 0) { - log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s", - strerror(errno)); - return NULL; - } - - result = ifaddrs_to_smartlist(ifa, family); - - freeifaddrs(ifa); - - return result; -} -#endif /* defined(HAVE_IFADDRS_TO_SMARTLIST) */ - -#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST - -/** Convert a Windows-specific <b>addresses</b> linked list into smartlist - * of <b>tor_addr_t</b> structures. - */ - -STATIC smartlist_t * -ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses) -{ - smartlist_t *result = smartlist_new(); - const IP_ADAPTER_ADDRESSES *address; - - for (address = addresses; address; address = address->Next) { - const IP_ADAPTER_UNICAST_ADDRESS *a; - for (a = address->FirstUnicastAddress; a; a = a->Next) { - /* Yes, it's a linked list inside a linked list */ - const struct sockaddr *sa = a->Address.lpSockaddr; - tor_addr_t tmp; - if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) - continue; - if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) - continue; - smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); - } - } - - return result; -} - -/** Windows only: use GetAdaptersInfo() function to retrieve network interface - * addresses of current machine and return them to caller as smartlist of - * <b>tor_addr_t</b> structures. - */ -STATIC smartlist_t * -get_interface_addresses_win32(int severity, sa_family_t family) -{ - - /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a - "GetAdaptersInfo", but that's deprecated; let's just try - GetAdaptersAddresses and fall back to connect+getsockname. - */ - HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll")); - smartlist_t *result = NULL; - GetAdaptersAddresses_fn_t fn; - ULONG size, res; - IP_ADAPTER_ADDRESSES *addresses = NULL; - - (void) severity; - -#define FLAGS (GAA_FLAG_SKIP_ANYCAST | \ - GAA_FLAG_SKIP_MULTICAST | \ - GAA_FLAG_SKIP_DNS_SERVER) - - if (!lib) { - log_fn(severity, LD_NET, "Unable to load iphlpapi.dll"); - goto done; - } - - /* Cast through a void function pointer, to silence a spurious compiler - * warning on 64-bit Windows. This cast is safe, because we are casting to - * the correct type for GetAdaptersAddresses(). */ - if (!(fn = (GetAdaptersAddresses_fn_t)(void(*)(void)) - GetProcAddress(lib, "GetAdaptersAddresses"))) { - log_fn(severity, LD_NET, "Unable to obtain pointer to " - "GetAdaptersAddresses"); - goto done; - } - - /* Guess how much space we need. */ - size = 15*1024; - addresses = tor_malloc(size); - res = fn(family, FLAGS, NULL, addresses, &size); - if (res == ERROR_BUFFER_OVERFLOW) { - /* we didn't guess that we needed enough space; try again */ - tor_free(addresses); - addresses = tor_malloc(size); - res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); - } - if (res != NO_ERROR) { - log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res); - goto done; - } - - result = ip_adapter_addresses_to_smartlist(addresses); - - done: - if (lib) - FreeLibrary(lib); - tor_free(addresses); - return result; -} - -#endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */ - -#ifdef HAVE_IFCONF_TO_SMARTLIST - -/* Guess how much space we need. There shouldn't be any struct ifreqs - * larger than this, even on OS X where the struct's size is dynamic. */ -#define IFREQ_SIZE 4096 - -/* This is defined on Mac OS X */ -#ifndef _SIZEOF_ADDR_IFREQ -#define _SIZEOF_ADDR_IFREQ sizeof -#endif - -/* Free ifc->ifc_buf safely. */ -static void -ifconf_free_ifc_buf(struct ifconf *ifc) -{ - /* On macOS, tor_free() takes the address of ifc.ifc_buf, which leads to - * undefined behaviour, because pointer-to-pointers are expected to be - * aligned at 8-bytes, but the ifconf structure is packed. So we use - * raw_free() instead. */ - raw_free(ifc->ifc_buf); - ifc->ifc_buf = NULL; -} - -/** Convert <b>*buf</b>, an ifreq structure array of size <b>buflen</b>, - * into smartlist of <b>tor_addr_t</b> structures. - */ -STATIC smartlist_t * -ifreq_to_smartlist(char *buf, size_t buflen) -{ - smartlist_t *result = smartlist_new(); - char *end = buf + buflen; - - /* These acrobatics are due to alignment issues which trigger - * undefined behaviour traps on OSX. */ - struct ifreq *r = tor_malloc(IFREQ_SIZE); - - while (buf < end) { - /* Copy up to IFREQ_SIZE bytes into the struct ifreq, but don't overrun - * buf. */ - memcpy(r, buf, end - buf < IFREQ_SIZE ? end - buf : IFREQ_SIZE); - - const struct sockaddr *sa = &r->ifr_addr; - tor_addr_t tmp; - int valid_sa_family = (sa->sa_family == AF_INET || - sa->sa_family == AF_INET6); - - int conversion_success = (tor_addr_from_sockaddr(&tmp, sa, NULL) == 0); - - if (valid_sa_family && conversion_success) - smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); - - buf += _SIZEOF_ADDR_IFREQ(*r); - } - - tor_free(r); - return result; -} - -/** Use ioctl(.,SIOCGIFCONF,.) to get a list of current machine - * network interface addresses. Represent the result by smartlist of - * <b>tor_addr_t</b> structures. - */ -STATIC smartlist_t * -get_interface_addresses_ioctl(int severity, sa_family_t family) -{ - /* Some older unixy systems make us use ioctl(SIOCGIFCONF) */ - struct ifconf ifc; - ifc.ifc_buf = NULL; - int fd; - smartlist_t *result = NULL; - - /* This interface, AFAICT, only supports AF_INET addresses, - * except on AIX. For Solaris, we could use SIOCGLIFCONF. */ - - /* Bail out if family is neither AF_INET nor AF_UNSPEC since - * ioctl() technique supports non-IPv4 interface addresses on - * a small number of niche systems only. If family is AF_UNSPEC, - * fall back to getting AF_INET addresses only. */ - if (family == AF_UNSPEC) - family = AF_INET; - else if (family != AF_INET) - return NULL; - - fd = socket(family, SOCK_DGRAM, 0); - if (fd < 0) { - tor_log(severity, LD_NET, "socket failed: %s", strerror(errno)); - goto done; - } - - int mult = 1; - do { - mult *= 2; - ifc.ifc_len = mult * IFREQ_SIZE; - ifc.ifc_buf = tor_realloc(ifc.ifc_buf, ifc.ifc_len); - - tor_assert(ifc.ifc_buf); - - if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { - tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno)); - goto done; - } - /* Ensure we have least IFREQ_SIZE bytes unused at the end. Otherwise, we - * don't know if we got everything during ioctl. */ - } while (mult * IFREQ_SIZE - ifc.ifc_len <= IFREQ_SIZE); - result = ifreq_to_smartlist(ifc.ifc_buf, ifc.ifc_len); - - done: - if (fd >= 0) - close(fd); - ifconf_free_ifc_buf(&ifc); - return result; -} -#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */ - -/** Try to ask our network interfaces what addresses they are bound to. - * Return a new smartlist of tor_addr_t on success, and NULL on failure. - * (An empty smartlist indicates that we successfully learned that we have no - * addresses.) Log failure messages at <b>severity</b>. Only return the - * interface addresses of requested <b>family</b> and ignore the addresses - * of other address families. */ -MOCK_IMPL(smartlist_t *, -get_interface_addresses_raw,(int severity, sa_family_t family)) -{ - smartlist_t *result = NULL; -#if defined(HAVE_IFADDRS_TO_SMARTLIST) - if ((result = get_interface_addresses_ifaddrs(severity, family))) - return result; -#endif -#if defined(HAVE_IP_ADAPTER_TO_SMARTLIST) - if ((result = get_interface_addresses_win32(severity, family))) - return result; -#endif -#if defined(HAVE_IFCONF_TO_SMARTLIST) - if ((result = get_interface_addresses_ioctl(severity, family))) - return result; -#endif - (void) severity; - (void) result; - return NULL; -} - -/** Return true iff <b>a</b> is a multicast address. */ -int -tor_addr_is_multicast(const tor_addr_t *a) -{ - sa_family_t family = tor_addr_family(a); - if (family == AF_INET) { - uint32_t ipv4h = tor_addr_to_ipv4h(a); - if ((ipv4h >> 24) == 0xe0) - return 1; /* Multicast */ - } else if (family == AF_INET6) { - const uint8_t *a32 = tor_addr_to_in6_addr8(a); - if (a32[0] == 0xff) - return 1; - } - return 0; -} - -/** Attempt to retrieve IP address of current host by utilizing some - * UDP socket trickery. Only look for address of given <b>family</b> - * (only AF_INET and AF_INET6 are supported). Set result to *<b>addr</b>. - * Return 0 on success, -1 on failure. - */ -MOCK_IMPL(int, -get_interface_address6_via_udp_socket_hack,(int severity, - sa_family_t family, - tor_addr_t *addr)) -{ - struct sockaddr_storage target_addr; - int sock=-1, r=-1; - socklen_t addr_len; - - memset(addr, 0, sizeof(tor_addr_t)); - memset(&target_addr, 0, sizeof(target_addr)); - - /* Don't worry: no packets are sent. We just need to use a real address - * on the actual Internet. */ - if (family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&target_addr; - /* Use the "discard" service port */ - sin6->sin6_port = htons(9); - sock = tor_open_socket(PF_INET6,SOCK_DGRAM,IPPROTO_UDP); - addr_len = (socklen_t)sizeof(struct sockaddr_in6); - sin6->sin6_family = AF_INET6; - S6_ADDR16(sin6->sin6_addr)[0] = htons(0x2002); /* 2002:: */ - } else if (family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in*)&target_addr; - /* Use the "discard" service port */ - sin->sin_port = htons(9); - sock = tor_open_socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); - addr_len = (socklen_t)sizeof(struct sockaddr_in); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = htonl(0x12000001); /* 18.0.0.1 */ - } else { - return -1; - } - - if (sock < 0) { - int e = tor_socket_errno(-1); - log_fn(severity, LD_NET, "unable to create socket: %s", - tor_socket_strerror(e)); - goto err; - } - - if (tor_connect_socket(sock,(struct sockaddr *)&target_addr, - addr_len) < 0) { - int e = tor_socket_errno(sock); - log_fn(severity, LD_NET, "connect() failed: %s", tor_socket_strerror(e)); - goto err; - } - - if (tor_addr_from_getsockname(addr, sock) < 0) { - int e = tor_socket_errno(sock); - log_fn(severity, LD_NET, "getsockname() to determine interface failed: %s", - tor_socket_strerror(e)); - goto err; - } - - if (tor_addr_is_loopback(addr) || tor_addr_is_multicast(addr)) { - log_fn(severity, LD_NET, "Address that we determined via UDP socket" - " magic is unsuitable for public comms."); - } else { - r=0; - } - - err: - if (sock >= 0) - tor_close_socket(sock); - if (r == -1) - memset(addr, 0, sizeof(tor_addr_t)); - return r; -} - -/** Set *<b>addr</b> to an arbitrary IP address (if any) of an interface that - * connects to the Internet. Prefer public IP addresses to internal IP - * addresses. This address should only be used in checking whether our - * address has changed, as it may be an internal IP address. Return 0 on - * success, -1 on failure. - * Prefer get_interface_address6_list for a list of all addresses on all - * interfaces which connect to the Internet. - */ -MOCK_IMPL(int, -get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) -{ - smartlist_t *addrs; - int rv = -1; - tor_assert(addr); - - memset(addr, 0, sizeof(tor_addr_t)); - - /* Get a list of public or internal IPs in arbitrary order */ - addrs = get_interface_address6_list(severity, family, 1); - - /* Find the first non-internal address, or the last internal address - * Ideally, we want the default route, see #12377 for details */ - SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { - tor_addr_copy(addr, a); - rv = 0; - - /* If we found a non-internal address, declare success. Otherwise, - * keep looking. */ - if (!tor_addr_is_internal(a, 0)) - break; - } SMARTLIST_FOREACH_END(a); - - interface_address6_list_free(addrs); - return rv; -} - -/** Free a smartlist of IP addresses returned by get_interface_address6_list. - */ -void -interface_address6_list_free_(smartlist_t *addrs) -{ - if (addrs != NULL) { - SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a)); - smartlist_free(addrs); - } -} - -/** Return a smartlist of the IP addresses of type family from all interfaces - * on the server. Excludes loopback and multicast addresses. Only includes - * internal addresses if include_internal is true. (Note that a relay behind - * NAT may use an internal address to connect to the Internet.) - * An empty smartlist means that there are no addresses of the selected type - * matching these criteria. - * Returns NULL on failure. - * Use interface_address6_list_free to free the returned list. - */ -MOCK_IMPL(smartlist_t *, -get_interface_address6_list,(int severity, - sa_family_t family, - int include_internal)) -{ - smartlist_t *addrs; - tor_addr_t addr; - - /* Try to do this the smart way if possible. */ - if ((addrs = get_interface_addresses_raw(severity, family))) { - SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) - { - if (tor_addr_is_loopback(a) || - tor_addr_is_multicast(a)) { - SMARTLIST_DEL_CURRENT_KEEPORDER(addrs, a); - tor_free(a); - continue; - } - - if (!include_internal && tor_addr_is_internal(a, 0)) { - SMARTLIST_DEL_CURRENT_KEEPORDER(addrs, a); - tor_free(a); - continue; - } - } SMARTLIST_FOREACH_END(a); - } - - if (addrs && smartlist_len(addrs) > 0) { - return addrs; - } - - /* if we removed all entries as unsuitable */ - if (addrs) { - smartlist_free(addrs); - } - - /* Okay, the smart way is out. */ - addrs = smartlist_new(); - - if (family == AF_INET || family == AF_UNSPEC) { - if (get_interface_address6_via_udp_socket_hack(severity,AF_INET, - &addr) == 0) { - if (include_internal || !tor_addr_is_internal(&addr, 0)) { - smartlist_add(addrs, tor_memdup(&addr, sizeof(addr))); - } - } - } - - if (family == AF_INET6 || family == AF_UNSPEC) { - if (get_interface_address6_via_udp_socket_hack(severity,AF_INET6, - &addr) == 0) { - if (include_internal || !tor_addr_is_internal(&addr, 0)) { - smartlist_add(addrs, tor_memdup(&addr, sizeof(addr))); - } - } - } - - return addrs; -} - -/* ====== - * IPv4 helpers - * XXXX IPv6 deprecate some of these. - */ - -/** Given an address of the form "ip:port", try to divide it into its - * ip and port portions, setting *<b>address_out</b> to a newly - * allocated string holding the address portion and *<b>port_out</b> - * to the port. - * - * Don't do DNS lookups and don't allow domain names in the "ip" field. - * - * If <b>default_port</b> is less than 0, don't accept <b>addrport</b> of the - * form "ip" or "ip:0". Otherwise, accept those forms, and set - * *<b>port_out</b> to <b>default_port</b>. - * - * Return 0 on success, -1 on failure. */ -int -tor_addr_port_parse(int severity, const char *addrport, - tor_addr_t *address_out, uint16_t *port_out, - int default_port) -{ - int retval = -1; - int r; - char *addr_tmp = NULL; - - tor_assert(addrport); - tor_assert(address_out); - tor_assert(port_out); - - r = tor_addr_port_split(severity, addrport, &addr_tmp, port_out); - if (r < 0) - goto done; - - if (!*port_out) { - if (default_port >= 0) - *port_out = default_port; - else - goto done; - } - - /* make sure that address_out is an IP address */ - if (tor_addr_parse(address_out, addr_tmp) < 0) - goto done; - - retval = 0; - - done: - tor_free(addr_tmp); - return retval; -} - -/** Given an address of the form "host[:port]", try to divide it into its host - * and port portions, setting *<b>address_out</b> to a newly allocated string - * holding the address portion and *<b>port_out</b> to the port (or 0 if no - * port is given). Return 0 on success, -1 on failure. */ -int -tor_addr_port_split(int severity, const char *addrport, - char **address_out, uint16_t *port_out) -{ - tor_addr_t a_tmp; - tor_assert(addrport); - tor_assert(address_out); - tor_assert(port_out); - /* We need to check for IPv6 manually because addr_port_lookup() doesn't - * do a good job on IPv6 addresses that lack a port. */ - if (tor_addr_parse(&a_tmp, addrport) == AF_INET6) { - *port_out = 0; - *address_out = tor_strdup(addrport); - return 0; - } - - return addr_port_lookup(severity, addrport, address_out, NULL, port_out); -} - -/** Parse a string of the form "host[:port]" from <b>addrport</b>. If - * <b>address</b> is provided, set *<b>address</b> to a copy of the - * host portion of the string. If <b>addr</b> is provided, try to - * resolve the host portion of the string and store it into - * *<b>addr</b> (in host byte order). If <b>port_out</b> is provided, - * store the port number into *<b>port_out</b>, or 0 if no port is given. - * If <b>port_out</b> is NULL, then there must be no port number in - * <b>addrport</b>. - * Return 0 on success, -1 on failure. - */ -int -addr_port_lookup(int severity, const char *addrport, char **address, - uint32_t *addr, uint16_t *port_out) -{ - const char *colon; - char *address_ = NULL; - int port_; - int ok = 1; - - tor_assert(addrport); - - colon = strrchr(addrport, ':'); - if (colon) { - address_ = tor_strndup(addrport, colon-addrport); - port_ = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL); - if (!port_) { - log_fn(severity, LD_GENERAL, "Port %s out of range", escaped(colon+1)); - ok = 0; - } - if (!port_out) { - char *esc_addrport = esc_for_log(addrport); - log_fn(severity, LD_GENERAL, - "Port %s given on %s when not required", - escaped(colon+1), esc_addrport); - tor_free(esc_addrport); - ok = 0; - } - } else { - address_ = tor_strdup(addrport); - port_ = 0; - } - - if (addr) { - /* There's an addr pointer, so we need to resolve the hostname. */ - if (tor_lookup_hostname(address_,addr)) { - log_fn(severity, LD_NET, "Couldn't look up %s", escaped(address_)); - ok = 0; - *addr = 0; - } - } - - if (address && ok) { - *address = address_; - } else { - if (address) - *address = NULL; - tor_free(address_); - } - if (port_out) - *port_out = ok ? ((uint16_t) port_) : 0; - - return ok ? 0 : -1; -} - -/** If <b>mask</b> is an address mask for a bit-prefix, return the number of - * bits. Otherwise, return -1. */ -int -addr_mask_get_bits(uint32_t mask) -{ - int i; - if (mask == 0) - return 0; - if (mask == 0xFFFFFFFFu) - return 32; - for (i=1; i<=32; ++i) { - if (mask == (uint32_t) ~((1u<<(32-i))-1)) { - return i; - } - } - return -1; -} - -/** Parse a string <b>s</b> in the format of (*|port(-maxport)?)?, setting the - * various *out pointers as appropriate. Return 0 on success, -1 on failure. - */ -int -parse_port_range(const char *port, uint16_t *port_min_out, - uint16_t *port_max_out) -{ - int port_min, port_max, ok; - tor_assert(port_min_out); - tor_assert(port_max_out); - - if (!port || *port == '\0' || strcmp(port, "*") == 0) { - port_min = 1; - port_max = 65535; - } else { - char *endptr = NULL; - port_min = (int)tor_parse_long(port, 10, 0, 65535, &ok, &endptr); - if (!ok) { - log_warn(LD_GENERAL, - "Malformed port %s on address range; rejecting.", - escaped(port)); - return -1; - } else if (endptr && *endptr == '-') { - port = endptr+1; - endptr = NULL; - port_max = (int)tor_parse_long(port, 10, 1, 65535, &ok, &endptr); - if (!ok) { - log_warn(LD_GENERAL, - "Malformed port %s on address range; rejecting.", - escaped(port)); - return -1; - } - } else { - port_max = port_min; - } - if (port_min > port_max) { - log_warn(LD_GENERAL, "Insane port range on address policy; rejecting."); - return -1; - } - } - - if (port_min < 1) - port_min = 1; - if (port_max > 65535) - port_max = 65535; - - *port_min_out = (uint16_t) port_min; - *port_max_out = (uint16_t) port_max; - - return 0; -} - -/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual), - * write it as a string into the <b>buf_len</b>-byte buffer in - * <b>buf</b>. Returns a non-negative integer on success. - * Returns -1 on failure. - */ -int -tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) -{ - uint32_t a = ntohl(in->s_addr); - return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", - (int)(uint8_t)((a>>24)&0xff), - (int)(uint8_t)((a>>16)&0xff), - (int)(uint8_t)((a>>8 )&0xff), - (int)(uint8_t)((a )&0xff)); -} - -/** Given a host-order <b>addr</b>, call tor_inet_ntop() on it - * and return a strdup of the resulting address. - */ -char * -tor_dup_ip(uint32_t addr) -{ - char buf[TOR_ADDR_BUF_LEN]; - struct in_addr in; - - in.s_addr = htonl(addr); - tor_inet_ntop(AF_INET, &in, buf, sizeof(buf)); - return tor_strdup(buf); -} - -/** - * Set *<b>addr</b> to a host-order IPv4 address (if any) of an - * interface that connects to the Internet. Prefer public IP addresses to - * internal IP addresses. This address should only be used in checking - * whether our address has changed, as it may be an internal IPv4 address. - * Return 0 on success, -1 on failure. - * Prefer get_interface_address_list6 for a list of all IPv4 and IPv6 - * addresses on all interfaces which connect to the Internet. - */ -MOCK_IMPL(int, -get_interface_address,(int severity, uint32_t *addr)) -{ - tor_addr_t local_addr; - int r; - - memset(addr, 0, sizeof(uint32_t)); - - r = get_interface_address6(severity, AF_INET, &local_addr); - if (r>=0) - *addr = tor_addr_to_ipv4h(&local_addr); - return r; -} - -/** Return true if we can tell that <b>name</b> is a canonical name for the - * loopback address. Return true also for *.local hostnames, which are - * multicast DNS names for hosts on the local network. */ -int -tor_addr_hostname_is_local(const char *name) -{ - return !strcasecmp(name, "localhost") || - !strcasecmp(name, "local") || - !strcasecmpend(name, ".local"); -} - -/** Return a newly allocated tor_addr_port_t with <b>addr</b> and - <b>port</b> filled in. */ -tor_addr_port_t * -tor_addr_port_new(const tor_addr_t *addr, uint16_t port) -{ - tor_addr_port_t *ap = tor_malloc_zero(sizeof(tor_addr_port_t)); - if (addr) - tor_addr_copy(&ap->addr, addr); - ap->port = port; - return ap; -} - -/** Return true iff <a>a</b> and <b>b</b> are the same address and port */ -int -tor_addr_port_eq(const tor_addr_port_t *a, - const tor_addr_port_t *b) -{ - return tor_addr_eq(&a->addr, &b->addr) && a->port == b->port; -} - diff --git a/src/common/address.h b/src/common/address.h deleted file mode 100644 index c9d9543dee..0000000000 --- a/src/common/address.h +++ /dev/null @@ -1,379 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file address.h - * \brief Headers for address.h - **/ - -#ifndef TOR_ADDRESS_H -#define TOR_ADDRESS_H - -//#include <sys/sockio.h> -#include "orconfig.h" -#include "torint.h" -#include "compat.h" -#include "container.h" - -#ifdef ADDRESS_PRIVATE - -#if defined(HAVE_SYS_IOCTL_H) -#include <sys/ioctl.h> -#endif - -#ifdef HAVE_GETIFADDRS -#define HAVE_IFADDRS_TO_SMARTLIST -#endif - -#ifdef _WIN32 -#define HAVE_IP_ADAPTER_TO_SMARTLIST -#endif - -#if defined(SIOCGIFCONF) && defined(HAVE_IOCTL) -#define HAVE_IFCONF_TO_SMARTLIST -#endif - -#if defined(HAVE_NET_IF_H) -#include <net/if.h> // for struct ifconf -#endif - -#if defined(HAVE_IFADDRS_TO_SMARTLIST) -#include <ifaddrs.h> -#endif - -// TODO win32 specific includes -#endif /* defined(ADDRESS_PRIVATE) */ - -/** The number of bits from an address to consider while doing a masked - * comparison. */ -typedef uint8_t maskbits_t; - -struct in_addr; -/** Holds an IPv4 or IPv6 address. (Uses less memory than struct - * sockaddr_storage.) */ -typedef struct tor_addr_t -{ - sa_family_t family; - union { - uint32_t dummy_; /* This field is here so we have something to initialize - * with a reliable cross-platform type. */ - struct in_addr in_addr; - struct in6_addr in6_addr; - } addr; -} tor_addr_t; - -/** Holds an IP address and a TCP/UDP port. */ -typedef struct tor_addr_port_t -{ - tor_addr_t addr; - uint16_t port; -} tor_addr_port_t; - -#define TOR_ADDR_NULL {AF_UNSPEC, {0}} - -static inline const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a); -static inline const struct in6_addr *tor_addr_to_in6_assert( - const tor_addr_t *a); -static inline uint32_t tor_addr_to_ipv4n(const tor_addr_t *a); -static inline uint32_t tor_addr_to_ipv4h(const tor_addr_t *a); -static inline uint32_t tor_addr_to_mapped_ipv4h(const tor_addr_t *a); -static inline sa_family_t tor_addr_family(const tor_addr_t *a); -static inline const struct in_addr *tor_addr_to_in(const tor_addr_t *a); -static inline int tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u); - -socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port, - struct sockaddr *sa_out, socklen_t len); -int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, - uint16_t *port_out); -void tor_addr_make_unspec(tor_addr_t *a); -void tor_addr_make_null(tor_addr_t *a, sa_family_t family); -char *tor_sockaddr_to_str(const struct sockaddr *sa); - -/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not - * an IPv6 address. */ -static inline const struct in6_addr * -tor_addr_to_in6(const tor_addr_t *a) -{ - return a->family == AF_INET6 ? &a->addr.in6_addr : NULL; -} - -/** As tor_addr_to_in6, but assert that the address truly is an IPv6 - * address. */ -static inline const struct in6_addr * -tor_addr_to_in6_assert(const tor_addr_t *a) -{ - tor_assert(a->family == AF_INET6); - return &a->addr.in6_addr; -} - -/** Given an IPv6 address <b>x</b>, yield it as an array of uint8_t. - * - * Requires that <b>x</b> is actually an IPv6 address. - */ -#define tor_addr_to_in6_addr8(x) tor_addr_to_in6_assert(x)->s6_addr - -/** Given an IPv6 address <b>x</b>, yield it as an array of uint16_t. - * - * Requires that <b>x</b> is actually an IPv6 address. - */ -#define tor_addr_to_in6_addr16(x) S6_ADDR16(*tor_addr_to_in6_assert(x)) -/** Given an IPv6 address <b>x</b>, yield it as an array of uint32_t. - * - * Requires that <b>x</b> is actually an IPv6 address. - */ -#define tor_addr_to_in6_addr32(x) S6_ADDR32(*tor_addr_to_in6_assert(x)) - -/** Return an IPv4 address in network order for <b>a</b>, or 0 if - * <b>a</b> is not an IPv4 address. */ -static inline uint32_t -tor_addr_to_ipv4n(const tor_addr_t *a) -{ - return a->family == AF_INET ? a->addr.in_addr.s_addr : 0; -} -/** Return an IPv4 address in host order for <b>a</b>, or 0 if - * <b>a</b> is not an IPv4 address. */ -static inline uint32_t -tor_addr_to_ipv4h(const tor_addr_t *a) -{ - return ntohl(tor_addr_to_ipv4n(a)); -} -/** Given an IPv6 address, return its mapped IPv4 address in host order, or - * 0 if <b>a</b> is not an IPv6 address. - * - * (Does not check whether the address is really a mapped address */ -static inline uint32_t -tor_addr_to_mapped_ipv4h(const tor_addr_t *a) -{ - if (a->family == AF_INET6) { - uint32_t *addr32 = NULL; - // Work around an incorrect NULL pointer dereference warning in - // "clang --analyze" due to limited analysis depth - addr32 = tor_addr_to_in6_addr32(a); - // To improve performance, wrap this assertion in: - // #if !defined(__clang_analyzer__) || PARANOIA - tor_assert(addr32); - return ntohl(addr32[3]); - } else { - return 0; - } -} -/** Return the address family of <b>a</b>. Possible values are: - * AF_INET6, AF_INET, AF_UNSPEC. */ -static inline sa_family_t -tor_addr_family(const tor_addr_t *a) -{ - return a->family; -} -/** Return an in_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not - * an IPv4 address. */ -static inline const struct in_addr * -tor_addr_to_in(const tor_addr_t *a) -{ - return a->family == AF_INET ? &a->addr.in_addr : NULL; -} -/** Return true iff <b>a</b> is an IPv4 address equal to the host-ordered - * address in <b>u</b>. */ -static inline int -tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u) -{ - return a->family == AF_INET ? (tor_addr_to_ipv4h(a) == u) : 0; -} - -/** Length of a buffer that you need to allocate to be sure you can encode - * any tor_addr_t. - * - * This allows enough space for - * "[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]", - * plus a terminating NUL. - */ -#define TOR_ADDR_BUF_LEN 48 - -MOCK_DECL(int, tor_addr_lookup,(const char *name, uint16_t family, - tor_addr_t *addr_out)); -char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC; - -/** Wrapper function of fmt_addr_impl(). It does not decorate IPv6 - * addresses. */ -#define fmt_addr(a) fmt_addr_impl((a), 0) -/** Wrapper function of fmt_addr_impl(). It decorates IPv6 - * addresses. */ -#define fmt_and_decorate_addr(a) fmt_addr_impl((a), 1) -const char *fmt_addr_impl(const tor_addr_t *addr, int decorate); -const char *fmt_addrport(const tor_addr_t *addr, uint16_t port); -const char * fmt_addr32(uint32_t addr); - -MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family, -tor_addr_t *addr)); -void interface_address6_list_free_(smartlist_t * addrs);// XXXX -#define interface_address6_list_free(addrs) \ - FREE_AND_NULL(smartlist_t, interface_address6_list_free_, (addrs)) -MOCK_DECL(smartlist_t *,get_interface_address6_list,(int severity, - sa_family_t family, - int include_internal)); - -/** Flag to specify how to do a comparison between addresses. In an "exact" - * comparison, addresses are equivalent only if they are in the same family - * with the same value. In a "semantic" comparison, IPv4 addresses match all - * IPv6 encodings of those addresses. */ -typedef enum { - CMP_EXACT, - CMP_SEMANTIC, -} tor_addr_comparison_t; - -int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, - tor_addr_comparison_t how); -int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, - maskbits_t mask, tor_addr_comparison_t how); -/** Return true iff a and b are the same address. The comparison is done - * "exactly". */ -#define tor_addr_eq(a,b) (0==tor_addr_compare((a),(b),CMP_EXACT)) - -uint64_t tor_addr_hash(const tor_addr_t *addr); -struct sipkey; -uint64_t tor_addr_keyed_hash(const struct sipkey *key, const tor_addr_t *addr); -int tor_addr_is_v4(const tor_addr_t *addr); -int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening, - const char *filename, int lineno); -#define tor_addr_is_internal(addr, for_listening) \ - tor_addr_is_internal_((addr), (for_listening), SHORT_FILE__, __LINE__) -int tor_addr_is_multicast(const tor_addr_t *a); - -/** Longest length that can be required for a reverse lookup name. */ -/* 32 nybbles, 32 dots, 8 characters of "ip6.arpa", 1 NUL: 73 characters. */ -#define REVERSE_LOOKUP_NAME_BUF_LEN 73 -int tor_addr_to_PTR_name(char *out, size_t outlen, - const tor_addr_t *addr); -int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address, - int family, int accept_regular); - -int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, - uint16_t *port_out); - -/* Does the address * yield an AF_UNSPEC wildcard address (1), - * which expands to corresponding wildcard IPv4 and IPv6 rules, and do we - * allow *4 and *6 for IPv4 and IPv6 wildcards, respectively; - * or does the address * yield IPv4 wildcard address (0). */ -#define TAPMP_EXTENDED_STAR 1 -/* Does the address * yield an IPv4 wildcard address rule (1); - * or does it yield wildcard IPv4 and IPv6 rules (0) */ -#define TAPMP_STAR_IPV4_ONLY (1 << 1) -/* Does the address * yield an IPv6 wildcard address rule (1); - * or does it yield wildcard IPv4 and IPv6 rules (0) */ -#define TAPMP_STAR_IPV6_ONLY (1 << 2) -/* TAPMP_STAR_IPV4_ONLY and TAPMP_STAR_IPV6_ONLY are mutually exclusive. */ -int tor_addr_parse_mask_ports(const char *s, unsigned flags, - tor_addr_t *addr_out, maskbits_t *mask_out, - uint16_t *port_min_out, uint16_t *port_max_out); -const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, - int decorate); -int tor_addr_parse(tor_addr_t *addr, const char *src); -void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src); -void tor_addr_copy_tight(tor_addr_t *dest, const tor_addr_t *src); -void tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr); -/** Set <b>dest</b> to the IPv4 address encoded in <b>v4addr</b> in host - * order. */ -#define tor_addr_from_ipv4h(dest, v4addr) \ - tor_addr_from_ipv4n((dest), htonl(v4addr)) -void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes); -/** Set <b>dest</b> to the IPv4 address incoded in <b>in</b>. */ -#define tor_addr_from_in(dest, in) \ - tor_addr_from_ipv4n((dest), (in)->s_addr); -void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6); -int tor_addr_is_null(const tor_addr_t *addr); -int tor_addr_is_loopback(const tor_addr_t *addr); - -int tor_addr_is_valid(const tor_addr_t *addr, int for_listening); -int tor_addr_is_valid_ipv4n(uint32_t v4n_addr, int for_listening); -#define tor_addr_is_valid_ipv4h(v4h_addr, for_listening) \ - tor_addr_is_valid_ipv4n(htonl(v4h_addr), (for_listening)) -int tor_port_is_valid(uint16_t port, int for_listening); -/* Are addr and port both valid? */ -#define tor_addr_port_is_valid(addr, port, for_listening) \ - (tor_addr_is_valid((addr), (for_listening)) && \ - tor_port_is_valid((port), (for_listening))) -/* Are ap->addr and ap->port both valid? */ -#define tor_addr_port_is_valid_ap(ap, for_listening) \ - tor_addr_port_is_valid(&(ap)->addr, (ap)->port, (for_listening)) -/* Are the network-order v4addr and port both valid? */ -#define tor_addr_port_is_valid_ipv4n(v4n_addr, port, for_listening) \ - (tor_addr_is_valid_ipv4n((v4n_addr), (for_listening)) && \ - tor_port_is_valid((port), (for_listening))) -/* Are the host-order v4addr and port both valid? */ -#define tor_addr_port_is_valid_ipv4h(v4h_addr, port, for_listening) \ - (tor_addr_is_valid_ipv4h((v4h_addr), (for_listening)) && \ - tor_port_is_valid((port), (for_listening))) - -int tor_addr_port_split(int severity, const char *addrport, - char **address_out, uint16_t *port_out); - -int tor_addr_port_parse(int severity, const char *addrport, - tor_addr_t *address_out, uint16_t *port_out, - int default_port); - -int tor_addr_hostname_is_local(const char *name); - -/* IPv4 helpers */ -int addr_port_lookup(int severity, const char *addrport, char **address, - uint32_t *addr, uint16_t *port_out); -int parse_port_range(const char *port, uint16_t *port_min_out, - uint16_t *port_max_out); -int addr_mask_get_bits(uint32_t mask); -/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/ -#define INET_NTOA_BUF_LEN 16 -int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); -char *tor_dup_ip(uint32_t addr) ATTR_MALLOC; -MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr)); -#define interface_address_list_free(lst)\ - interface_address6_list_free(lst) -/** Return a smartlist of the IPv4 addresses of all interfaces on the server. - * Excludes loopback and multicast addresses. Only includes internal addresses - * if include_internal is true. (Note that a relay behind NAT may use an - * internal address to connect to the Internet.) - * An empty smartlist means that there are no IPv4 addresses. - * Returns NULL on failure. - * Use free_interface_address_list to free the returned list. - */ -static inline smartlist_t * -get_interface_address_list(int severity, int include_internal) -{ - return get_interface_address6_list(severity, AF_INET, include_internal); -} - -tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port); -int tor_addr_port_eq(const tor_addr_port_t *a, - const tor_addr_port_t *b); - -#ifdef ADDRESS_PRIVATE -MOCK_DECL(smartlist_t *,get_interface_addresses_raw,(int severity, - sa_family_t family)); -MOCK_DECL(int,get_interface_address6_via_udp_socket_hack,(int severity, - sa_family_t family, - tor_addr_t *addr)); - -#ifdef HAVE_IFADDRS_TO_SMARTLIST -STATIC smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa, - sa_family_t family); -STATIC smartlist_t *get_interface_addresses_ifaddrs(int severity, - sa_family_t family); -#endif /* defined(HAVE_IFADDRS_TO_SMARTLIST) */ - -#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST -STATIC smartlist_t *ip_adapter_addresses_to_smartlist( - const IP_ADAPTER_ADDRESSES *addresses); -STATIC smartlist_t *get_interface_addresses_win32(int severity, - sa_family_t family); -#endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */ - -#ifdef HAVE_IFCONF_TO_SMARTLIST -STATIC smartlist_t *ifreq_to_smartlist(char *ifr, - size_t buflen); -STATIC smartlist_t *get_interface_addresses_ioctl(int severity, - sa_family_t family); -#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */ - -#endif /* defined(ADDRESS_PRIVATE) */ - -#endif /* !defined(TOR_ADDRESS_H) */ - diff --git a/src/common/address_set.c b/src/common/address_set.c deleted file mode 100644 index b2f4bb4c95..0000000000 --- a/src/common/address_set.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file address_set.c - * \brief Implementation for a set of addresses. - * - * This module was first written on a semi-emergency basis to improve the - * robustness of the anti-DoS module. As such, it's written in a pretty - * conservative way, and should be susceptible to improvement later on. - **/ - -#include "orconfig.h" -#include "address_set.h" -#include "address.h" -#include "compat.h" -#include "container.h" -#include "crypto_rand.h" -#include "util.h" -#include "siphash.h" - -/** How many 64-bit siphash values to extract per address */ -#define N_HASHES 2 -/** How many bloom-filter bits we set per address. This is twice the N_HASHES - * value, since we split the siphash output into two 32-bit values. */ -#define N_BITS_PER_ITEM (N_HASHES * 2) - -/* XXXX This code is largely duplicated with digestset_t. We should merge - * them together into a common bloom-filter implementation. I'm keeping - * them separate for now, though, since this module needs to be backported - * all the way to 0.2.9. - * - * The main difference between digestset_t and this code is that we use - * independent siphashes rather than messing around with bit-shifts. The - * approach here is probably more sound, and we should prefer it if&when we - * unify the implementations. - */ - -struct address_set_t { - /** siphash keys to make N_HASHES independent hashes for each address. */ - struct sipkey key[N_HASHES]; - int mask; /**< One less than the number of bits in <b>ba</b>; always one less - * than a power of two. */ - bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ -}; - -/** - * Allocate and return an address_set, suitable for holding up to - * <b>max_address_guess</b> distinct values. - */ -address_set_t * -address_set_new(int max_addresses_guess) -{ - /* See digestset_new() for rationale on this equation. */ - int n_bits = 1u << (tor_log2(max_addresses_guess)+5); - - address_set_t *set = tor_malloc_zero(sizeof(address_set_t)); - set->mask = n_bits - 1; - set->ba = bitarray_init_zero(n_bits); - crypto_rand((char*) set->key, sizeof(set->key)); - - return set; -} - -/** - * Release all storage associated with <b>set</b>. - */ -void -address_set_free(address_set_t *set) -{ - if (! set) - return; - - bitarray_free(set->ba); - tor_free(set); -} - -/** Yield the bit index corresponding to 'val' for set. */ -#define BIT(set, val) ((val) & (set)->mask) - -/** - * Add <b>addr</b> to <b>set</b>. - * - * All future queries for <b>addr</b> in set will return true. Removing - * items is not possible. - */ -void -address_set_add(address_set_t *set, const struct tor_addr_t *addr) -{ - int i; - for (i = 0; i < N_HASHES; ++i) { - uint64_t h = tor_addr_keyed_hash(&set->key[i], addr); - uint32_t high_bits = (uint32_t)(h >> 32); - uint32_t low_bits = (uint32_t)(h); - bitarray_set(set->ba, BIT(set, high_bits)); - bitarray_set(set->ba, BIT(set, low_bits)); - } -} - -/** As address_set_add(), but take an ipv4 address in host order. */ -void -address_set_add_ipv4h(address_set_t *set, uint32_t addr) -{ - tor_addr_t a; - tor_addr_from_ipv4h(&a, addr); - address_set_add(set, &a); -} - -/** - * Return true if <b>addr</b> is a member of <b>set</b>. (And probably, - * return false if <b>addr</b> is not a member of set.) - */ -int -address_set_probably_contains(address_set_t *set, - const struct tor_addr_t *addr) -{ - int i, matches = 0; - for (i = 0; i < N_HASHES; ++i) { - uint64_t h = tor_addr_keyed_hash(&set->key[i], addr); - uint32_t high_bits = (uint32_t)(h >> 32); - uint32_t low_bits = (uint32_t)(h); - // Note that !! is necessary here, since bitarray_is_set does not - // necessarily return 1 on true. - matches += !! bitarray_is_set(set->ba, BIT(set, high_bits)); - matches += !! bitarray_is_set(set->ba, BIT(set, low_bits)); - } - return matches == N_BITS_PER_ITEM; -} - diff --git a/src/common/address_set.h b/src/common/address_set.h deleted file mode 100644 index 28d29f3fdf..0000000000 --- a/src/common/address_set.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file address_set.h - * \brief Types to handle sets of addresses. - * - * This module was first written on a semi-emergency basis to improve the - * robustness of the anti-DoS module. As such, it's written in a pretty - * conservative way, and should be susceptible to improvement later on. - **/ - -#ifndef TOR_ADDRESS_SET_H -#define TOR_ADDRESS_SET_H - -#include "orconfig.h" -#include "torint.h" - -/** - * An address_set_t represents a set of tor_addr_t values. The implementation - * is probabilistic: false negatives cannot occur but false positives are - * possible. - */ -typedef struct address_set_t address_set_t; -struct tor_addr_t; - -address_set_t *address_set_new(int max_addresses_guess); -void address_set_free(address_set_t *set); -void address_set_add(address_set_t *set, const struct tor_addr_t *addr); -void address_set_add_ipv4h(address_set_t *set, uint32_t addr); -int address_set_probably_contains(address_set_t *set, - const struct tor_addr_t *addr); - -#endif - diff --git a/src/common/aes.c b/src/common/aes.c deleted file mode 100644 index 49bb54762f..0000000000 --- a/src/common/aes.c +++ /dev/null @@ -1,410 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file aes.c - * \brief Implements a counter-mode stream cipher on top of AES. - **/ - -#include "orconfig.h" - -#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ - #include <winsock2.h> - #include <ws2tcpip.h> -#endif - -#include "compat_openssl.h" -#include <openssl/opensslv.h> -#include "crypto_openssl_mgt.h" - -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) -#error "We require OpenSSL >= 1.0.0" -#endif - -DISABLE_GCC_WARNING(redundant-decls) - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <openssl/aes.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/modes.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#include "compat.h" -#include "aes.h" -#include "util.h" -#include "torlog.h" -#include "di_ops.h" -#include "crypto_util.h" - -#ifdef ANDROID -/* Android's OpenSSL seems to have removed all of its Engine support. */ -#define DISABLE_ENGINES -#endif - -/* We have five strategies for implementing AES counter mode. - * - * Best with x86 and x86_64: Use EVP_aes_*_ctr() and EVP_EncryptUpdate(). - * This is possible with OpenSSL 1.0.1, where the counter-mode implementation - * can use bit-sliced or vectorized AES or AESNI as appropriate. - * - * Otherwise: Pick the best possible AES block implementation that OpenSSL - * gives us, and the best possible counter-mode implementation, and combine - * them. - */ -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,1,0) - -/* With newer OpenSSL versions, the older fallback modes don't compile. So - * don't use them, even if we lack specific acceleration. */ - -#define USE_EVP_AES_CTR - -#elif OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,0,1) && \ - (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || \ - defined(_M_AMD64) || defined(_M_X64) || defined(__INTEL__)) - -#define USE_EVP_AES_CTR - -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,1,0) || ... */ - -/* We have 2 strategies for getting the AES block cipher: Via OpenSSL's - * AES_encrypt function, or via OpenSSL's EVP_EncryptUpdate function. - * - * If there's any hardware acceleration in play, we want to be using EVP_* so - * we can get it. Otherwise, we'll want AES_*, which seems to be about 5% - * faster than indirecting through the EVP layer. - */ - -/* We have 2 strategies for getting a plug-in counter mode: use our own, or - * use OpenSSL's. - * - * Here we have a counter mode that's faster than the one shipping with - * OpenSSL pre-1.0 (by about 10%!). But OpenSSL 1.0.0 added a counter mode - * implementation faster than the one here (by about 7%). So we pick which - * one to used based on the Openssl version above. (OpenSSL 1.0.0a fixed a - * critical bug in that counter mode implementation, so we need to test to - * make sure that we have a fixed version.) - */ - -#ifdef USE_EVP_AES_CTR - -/* We don't actually define the struct here. */ - -aes_cnt_cipher_t * -aes_new_cipher(const uint8_t *key, const uint8_t *iv, int key_bits) -{ - EVP_CIPHER_CTX *cipher = EVP_CIPHER_CTX_new(); - const EVP_CIPHER *c; - switch (key_bits) { - case 128: c = EVP_aes_128_ctr(); break; - case 192: c = EVP_aes_192_ctr(); break; - case 256: c = EVP_aes_256_ctr(); break; - default: tor_assert(0); // LCOV_EXCL_LINE - } - EVP_EncryptInit(cipher, c, key, iv); - return (aes_cnt_cipher_t *) cipher; -} -void -aes_cipher_free_(aes_cnt_cipher_t *cipher_) -{ - if (!cipher_) - return; - EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; -#ifdef OPENSSL_1_1_API - EVP_CIPHER_CTX_reset(cipher); -#else - EVP_CIPHER_CTX_cleanup(cipher); -#endif - EVP_CIPHER_CTX_free(cipher); -} -void -aes_crypt_inplace(aes_cnt_cipher_t *cipher_, char *data, size_t len) -{ - int outl; - EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; - - tor_assert(len < INT_MAX); - - EVP_EncryptUpdate(cipher, (unsigned char*)data, - &outl, (unsigned char*)data, (int)len); -} -int -evaluate_evp_for_aes(int force_val) -{ - (void) force_val; - log_info(LD_CRYPTO, "This version of OpenSSL has a known-good EVP " - "counter-mode implementation. Using it."); - return 0; -} -int -evaluate_ctr_for_aes(void) -{ - return 0; -} -#else /* !(defined(USE_EVP_AES_CTR)) */ - -/*======================================================================*/ -/* Interface to AES code, and counter implementation */ - -/** Implements an AES counter-mode cipher. */ -struct aes_cnt_cipher { -/** This next element (however it's defined) is the AES key. */ - union { - EVP_CIPHER_CTX evp; - AES_KEY aes; - } key; - -#if !defined(WORDS_BIGENDIAN) -#define USING_COUNTER_VARS - /** These four values, together, implement a 128-bit counter, with - * counter0 as the low-order word and counter3 as the high-order word. */ - uint32_t counter3; - uint32_t counter2; - uint32_t counter1; - uint32_t counter0; -#endif /* !defined(WORDS_BIGENDIAN) */ - - union { - /** The counter, in big-endian order, as bytes. */ - uint8_t buf[16]; - /** The counter, in big-endian order, as big-endian words. Note that - * on big-endian platforms, this is redundant with counter3...0, - * so we just use these values instead. */ - uint32_t buf32[4]; - } ctr_buf; - - /** The encrypted value of ctr_buf. */ - uint8_t buf[16]; - /** Our current stream position within buf. */ - unsigned int pos; - - /** True iff we're using the evp implementation of this cipher. */ - uint8_t using_evp; -}; - -/** True iff we should prefer the EVP implementation for AES, either because - * we're testing it or because we have hardware acceleration configured */ -static int should_use_EVP = 0; - -/** Check whether we should use the EVP interface for AES. If <b>force_val</b> - * is nonnegative, we use use EVP iff it is true. Otherwise, we use EVP - * if there is an engine enabled for aes-ecb. */ -int -evaluate_evp_for_aes(int force_val) -{ - ENGINE *e; - - if (force_val >= 0) { - should_use_EVP = force_val; - return 0; - } -#ifdef DISABLE_ENGINES - should_use_EVP = 0; -#else - e = ENGINE_get_cipher_engine(NID_aes_128_ecb); - - if (e) { - log_info(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.", - ENGINE_get_name(e)); - should_use_EVP = 1; - } else { - log_info(LD_CRYPTO, "No AES engine found; using AES_* functions."); - should_use_EVP = 0; - } -#endif /* defined(DISABLE_ENGINES) */ - - return 0; -} - -/** Test the OpenSSL counter mode implementation to see whether it has the - * counter-mode bug from OpenSSL 1.0.0. If the implementation works, then - * we will use it for future encryption/decryption operations. - * - * We can't just look at the OpenSSL version, since some distributions update - * their OpenSSL packages without changing the version number. - **/ -int -evaluate_ctr_for_aes(void) -{ - /* Result of encrypting an all-zero block with an all-zero 128-bit AES key. - * This should be the same as encrypting an all-zero block with an all-zero - * 128-bit AES key in counter mode, starting at position 0 of the stream. - */ - static const unsigned char encrypt_zero[] = - "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e"; - unsigned char zero[16]; - unsigned char output[16]; - unsigned char ivec[16]; - unsigned char ivec_tmp[16]; - unsigned int pos, i; - AES_KEY key; - memset(zero, 0, sizeof(zero)); - memset(ivec, 0, sizeof(ivec)); - AES_set_encrypt_key(zero, 128, &key); - - pos = 0; - /* Encrypting a block one byte at a time should make the error manifest - * itself for known bogus openssl versions. */ - for (i=0; i<16; ++i) - AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos); - - if (fast_memneq(output, encrypt_zero, 16)) { - /* Counter mode is buggy */ - /* LCOV_EXCL_START */ - log_err(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; " - "quitting tor."); - exit(1); // exit ok: openssl is broken. - /* LCOV_EXCL_STOP */ - } - return 0; -} - -#if !defined(USING_COUNTER_VARS) -#define COUNTER(c, n) ((c)->ctr_buf.buf32[3-(n)]) -#else -#define COUNTER(c, n) ((c)->counter ## n) -#endif - -static void aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, - int key_bits); -static void aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv); - -/** - * Return a newly allocated counter-mode AES128 cipher implementation, - * using the 128-bit key <b>key</b> and the 128-bit IV <b>iv</b>. - */ -aes_cnt_cipher_t* -aes_new_cipher(const uint8_t *key, const uint8_t *iv, int bits) -{ - aes_cnt_cipher_t* result = tor_malloc_zero(sizeof(aes_cnt_cipher_t)); - - aes_set_key(result, key, bits); - aes_set_iv(result, iv); - - return result; -} - -/** Set the key of <b>cipher</b> to <b>key</b>, which is - * <b>key_bits</b> bits long (must be 128, 192, or 256). Also resets - * the counter to 0. - */ -static void -aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, int key_bits) -{ - if (should_use_EVP) { - const EVP_CIPHER *c = 0; - switch (key_bits) { - case 128: c = EVP_aes_128_ecb(); break; - case 192: c = EVP_aes_192_ecb(); break; - case 256: c = EVP_aes_256_ecb(); break; - default: tor_assert(0); // LCOV_EXCL_LINE - } - EVP_EncryptInit(&cipher->key.evp, c, key, NULL); - cipher->using_evp = 1; - } else { - AES_set_encrypt_key(key, key_bits,&cipher->key.aes); - cipher->using_evp = 0; - } - -#ifdef USING_COUNTER_VARS - cipher->counter0 = 0; - cipher->counter1 = 0; - cipher->counter2 = 0; - cipher->counter3 = 0; -#endif /* defined(USING_COUNTER_VARS) */ - - memset(cipher->ctr_buf.buf, 0, sizeof(cipher->ctr_buf.buf)); - - cipher->pos = 0; - - memset(cipher->buf, 0, sizeof(cipher->buf)); -} - -/** Release storage held by <b>cipher</b> - */ -void -aes_cipher_free_(aes_cnt_cipher_t *cipher) -{ - if (!cipher) - return; - if (cipher->using_evp) { - EVP_CIPHER_CTX_cleanup(&cipher->key.evp); - } - memwipe(cipher, 0, sizeof(aes_cnt_cipher_t)); - tor_free(cipher); -} - -#if defined(USING_COUNTER_VARS) -#define UPDATE_CTR_BUF(c, n) STMT_BEGIN \ - (c)->ctr_buf.buf32[3-(n)] = htonl((c)->counter ## n); \ - STMT_END -#else -#define UPDATE_CTR_BUF(c, n) -#endif /* defined(USING_COUNTER_VARS) */ - -/* Helper function to use EVP with openssl's counter-mode wrapper. */ -static void -evp_block128_fn(const uint8_t in[16], - uint8_t out[16], - const void *key) -{ - EVP_CIPHER_CTX *ctx = (void*)key; - int inl=16, outl=16; - EVP_EncryptUpdate(ctx, out, &outl, in, inl); -} - -/** Encrypt <b>len</b> bytes from <b>input</b>, storing the results in place. - * Uses the key in <b>cipher</b>, and advances the counter by <b>len</b> bytes - * as it encrypts. - */ -void -aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) -{ - /* Note that the "128" below refers to the length of the counter, - * not the length of the AES key. */ - if (cipher->using_evp) { - /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If - * it weren't disabled, it might be better just to use that. - */ - CRYPTO_ctr128_encrypt((const unsigned char *)data, - (unsigned char *)data, - len, - &cipher->key.evp, - cipher->ctr_buf.buf, - cipher->buf, - &cipher->pos, - evp_block128_fn); - } else { - AES_ctr128_encrypt((const unsigned char *)data, - (unsigned char *)data, - len, - &cipher->key.aes, - cipher->ctr_buf.buf, - cipher->buf, - &cipher->pos); - } -} - -/** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value - * in <b>iv</b>. */ -static void -aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv) -{ -#ifdef USING_COUNTER_VARS - cipher->counter3 = ntohl(get_uint32(iv)); - cipher->counter2 = ntohl(get_uint32(iv+4)); - cipher->counter1 = ntohl(get_uint32(iv+8)); - cipher->counter0 = ntohl(get_uint32(iv+12)); -#endif /* defined(USING_COUNTER_VARS) */ - cipher->pos = 0; - memcpy(cipher->ctr_buf.buf, iv, 16); -} - -#endif /* defined(USE_EVP_AES_CTR) */ diff --git a/src/common/aes.h b/src/common/aes.h deleted file mode 100644 index 0b17cd55a4..0000000000 --- a/src/common/aes.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/* Implements a minimal interface to counter-mode AES. */ - -#ifndef TOR_AES_H -#define TOR_AES_H - -/** - * \file aes.h - * \brief Headers for aes.c - */ - -typedef struct aes_cnt_cipher aes_cnt_cipher_t; - -aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv, - int key_bits); -void aes_cipher_free_(aes_cnt_cipher_t *cipher); -#define aes_cipher_free(cipher) \ - FREE_AND_NULL(aes_cnt_cipher_t, aes_cipher_free_, (cipher)) -void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len); - -int evaluate_evp_for_aes(int force_value); -int evaluate_ctr_for_aes(void); - -#endif /* !defined(TOR_AES_H) */ - diff --git a/src/common/backtrace.c b/src/common/backtrace.c deleted file mode 100644 index f2498b2aa6..0000000000 --- a/src/common/backtrace.c +++ /dev/null @@ -1,248 +0,0 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file backtrace.c - * - * \brief Functions to produce backtraces on bugs, crashes, or assertion - * failures. - * - * Currently, we've only got an implementation here using the backtrace() - * family of functions, which are sometimes provided by libc and sometimes - * provided by libexecinfo. We tie into the sigaction() backend in order to - * detect crashes. - */ - -#include "orconfig.h" -#include "compat.h" -#include "util.h" -#include "torlog.h" - -#ifdef HAVE_EXECINFO_H -#include <execinfo.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif - -#ifdef HAVE_CYGWIN_SIGNAL_H -#include <cygwin/signal.h> -#elif defined(HAVE_SYS_UCONTEXT_H) -#include <sys/ucontext.h> -#elif defined(HAVE_UCONTEXT_H) -#include <ucontext.h> -#endif /* defined(HAVE_CYGWIN_SIGNAL_H) || ... */ - -#define EXPOSE_CLEAN_BACKTRACE -#include "backtrace.h" - -#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ - defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) -#define USE_BACKTRACE -#endif - -#if !defined(USE_BACKTRACE) -#define NO_BACKTRACE_IMPL -#endif - -/** Version of Tor to report in backtrace messages. */ -static char *bt_version = NULL; - -#ifdef USE_BACKTRACE -/** Largest stack depth to try to dump. */ -#define MAX_DEPTH 256 -/** Static allocation of stack to dump. This is static so we avoid stack - * pressure. */ -static void *cb_buf[MAX_DEPTH]; -/** Protects cb_buf from concurrent access */ -static tor_mutex_t cb_buf_mutex; - -/** Change a stacktrace in <b>stack</b> of depth <b>depth</b> so that it will - * log the correct function from which a signal was received with context - * <b>ctx</b>. (When we get a signal, the current function will not have - * called any other function, and will therefore have not pushed its address - * onto the stack. Fortunately, we usually have the program counter in the - * ucontext_t structure. - */ -void -clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx) -{ -#ifdef PC_FROM_UCONTEXT -#if defined(__linux__) - const size_t n = 1; -#elif defined(__darwin__) || defined(__APPLE__) || defined(OpenBSD) \ - || defined(__FreeBSD__) - const size_t n = 2; -#else - const size_t n = 1; -#endif /* defined(__linux__) || ... */ - if (depth <= n) - return; - - stack[n] = (void*) ctx->PC_FROM_UCONTEXT; -#else /* !(defined(PC_FROM_UCONTEXT)) */ - (void) depth; - (void) ctx; - (void) stack; -#endif /* defined(PC_FROM_UCONTEXT) */ -} - -/** Log a message <b>msg</b> at <b>severity</b> in <b>domain</b>, and follow - * that with a backtrace log. */ -void -log_backtrace(int severity, int domain, const char *msg) -{ - size_t depth; - char **symbols; - size_t i; - - tor_mutex_acquire(&cb_buf_mutex); - - depth = backtrace(cb_buf, MAX_DEPTH); - symbols = backtrace_symbols(cb_buf, (int)depth); - - tor_log(severity, domain, "%s. Stack trace:", msg); - if (!symbols) { - /* LCOV_EXCL_START -- we can't provoke this. */ - tor_log(severity, domain, " Unable to generate backtrace."); - goto done; - /* LCOV_EXCL_STOP */ - } - for (i=0; i < depth; ++i) { - tor_log(severity, domain, " %s", symbols[i]); - } - raw_free(symbols); - - done: - tor_mutex_release(&cb_buf_mutex); -} - -static void crash_handler(int sig, siginfo_t *si, void *ctx_) - __attribute__((noreturn)); - -/** Signal handler: write a crash message with a stack trace, and die. */ -static void -crash_handler(int sig, siginfo_t *si, void *ctx_) -{ - char buf[40]; - size_t depth; - ucontext_t *ctx = (ucontext_t *) ctx_; - int n_fds, i; - const int *fds = NULL; - - (void) si; - - depth = backtrace(cb_buf, MAX_DEPTH); - /* Clean up the top stack frame so we get the real function - * name for the most recently failing function. */ - clean_backtrace(cb_buf, depth, ctx); - - format_dec_number_sigsafe((unsigned)sig, buf, sizeof(buf)); - - tor_log_err_sigsafe(bt_version, " died: Caught signal ", buf, "\n", - NULL); - - n_fds = tor_log_get_sigsafe_err_fds(&fds); - for (i=0; i < n_fds; ++i) - backtrace_symbols_fd(cb_buf, (int)depth, fds[i]); - - abort(); -} - -/** Install signal handlers as needed so that when we crash, we produce a - * useful stack trace. Return 0 on success, -1 on failure. */ -static int -install_bt_handler(void) -{ - int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS, - SIGIO, -1 }; - int i, rv=0; - - struct sigaction sa; - - tor_mutex_init(&cb_buf_mutex); - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = crash_handler; - sa.sa_flags = SA_SIGINFO; - sigfillset(&sa.sa_mask); - - for (i = 0; trap_signals[i] >= 0; ++i) { - if (sigaction(trap_signals[i], &sa, NULL) == -1) { - /* LCOV_EXCL_START */ - log_warn(LD_BUG, "Sigaction failed: %s", strerror(errno)); - rv = -1; - /* LCOV_EXCL_STOP */ - } - } - - { - /* Now, generate (but do not log) a backtrace. This ensures that - * libc has pre-loaded the symbols we need to dump things, so that later - * reads won't be denied by the sandbox code */ - char **symbols; - size_t depth = backtrace(cb_buf, MAX_DEPTH); - symbols = backtrace_symbols(cb_buf, (int) depth); - if (symbols) - raw_free(symbols); - } - - return rv; -} - -/** Uninstall crash handlers. */ -static void -remove_bt_handler(void) -{ - tor_mutex_uninit(&cb_buf_mutex); -} -#endif /* defined(USE_BACKTRACE) */ - -#ifdef NO_BACKTRACE_IMPL -void -log_backtrace(int severity, int domain, const char *msg) -{ - tor_log(severity, domain, "%s. (Stack trace not available)", msg); -} - -static int -install_bt_handler(void) -{ - return 0; -} - -static void -remove_bt_handler(void) -{ -} -#endif /* defined(NO_BACKTRACE_IMPL) */ - -/** Set up code to handle generating error messages on crashes. */ -int -configure_backtrace_handler(const char *tor_version) -{ - tor_free(bt_version); - if (tor_version) - tor_asprintf(&bt_version, "Tor %s", tor_version); - else - tor_asprintf(&bt_version, "Tor"); - - return install_bt_handler(); -} - -/** Perform end-of-process cleanup for code that generates error messages on - * crashes. */ -void -clean_up_backtrace_handler(void) -{ - remove_bt_handler(); - - tor_free(bt_version); -} - diff --git a/src/common/backtrace.h b/src/common/backtrace.h deleted file mode 100644 index 3d0ab8a90a..0000000000 --- a/src/common/backtrace.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_BACKTRACE_H -#define TOR_BACKTRACE_H - -#include "orconfig.h" - -void log_backtrace(int severity, int domain, const char *msg); -int configure_backtrace_handler(const char *tor_version); -void clean_up_backtrace_handler(void); - -#ifdef EXPOSE_CLEAN_BACKTRACE -#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ - defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) -void clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx); -#endif -#endif /* defined(EXPOSE_CLEAN_BACKTRACE) */ - -#endif /* !defined(TOR_BACKTRACE_H) */ - diff --git a/src/common/buffers.c b/src/common/buffers.c deleted file mode 100644 index a01add9bef..0000000000 --- a/src/common/buffers.c +++ /dev/null @@ -1,1146 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file buffers.c - * \brief Implements a generic buffer interface. - * - * A buf_t is a (fairly) opaque byte-oriented FIFO that can read to or flush - * from memory, sockets, file descriptors, TLS connections, or another buf_t. - * Buffers are implemented as linked lists of memory chunks. - * - * All socket-backed and TLS-based connection_t objects have a pair of - * buffers: one for incoming data, and one for outcoming data. These are fed - * and drained from functions in connection.c, trigged by events that are - * monitored in main.c. - **/ - -#define BUFFERS_PRIVATE -#include "orconfig.h" -#include <stddef.h> -#include "buffers.h" -#include "compat.h" -#include "compress.h" -#include "util.h" -#include "torint.h" -#include "torlog.h" -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -//#define PARANOIA - -#ifdef PARANOIA -/** Helper: If PARANOIA is defined, assert that the buffer in local variable - * <b>buf</b> is well-formed. */ -#define check() STMT_BEGIN buf_assert_ok(buf); STMT_END -#else -#define check() STMT_NIL -#endif /* defined(PARANOIA) */ - -/* Implementation notes: - * - * After flirting with memmove, and dallying with ring-buffers, we're finally - * getting up to speed with the 1970s and implementing buffers as a linked - * list of small chunks. Each buffer has such a list; data is removed from - * the head of the list, and added at the tail. The list is singly linked, - * and the buffer keeps a pointer to the head and the tail. - * - * Every chunk, except the tail, contains at least one byte of data. Data in - * each chunk is contiguous. - * - * When you need to treat the first N characters on a buffer as a contiguous - * string, use the buf_pullup function to make them so. Don't do this more - * than necessary. - * - * The major free Unix kernels have handled buffers like this since, like, - * forever. - */ - -/* Chunk manipulation functions */ - -#define CHUNK_HEADER_LEN offsetof(chunk_t, mem[0]) - -/* We leave this many NUL bytes at the end of the buffer. */ -#ifdef DISABLE_MEMORY_SENTINELS -#define SENTINEL_LEN 0 -#else -#define SENTINEL_LEN 4 -#endif - -/* Header size plus NUL bytes at the end */ -#define CHUNK_OVERHEAD (CHUNK_HEADER_LEN + SENTINEL_LEN) - -/** Return the number of bytes needed to allocate a chunk to hold - * <b>memlen</b> bytes. */ -#define CHUNK_ALLOC_SIZE(memlen) (CHUNK_OVERHEAD + (memlen)) -/** Return the number of usable bytes in a chunk allocated with - * malloc(<b>memlen</b>). */ -#define CHUNK_SIZE_WITH_ALLOC(memlen) ((memlen) - CHUNK_OVERHEAD) - -#define DEBUG_SENTINEL - -#if defined(DEBUG_SENTINEL) && !defined(DISABLE_MEMORY_SENTINELS) -#define DBG_S(s) s -#else -#define DBG_S(s) (void)0 -#endif - -#ifdef DISABLE_MEMORY_SENTINELS -#define CHUNK_SET_SENTINEL(chunk, alloclen) STMT_NIL -#else -#define CHUNK_SET_SENTINEL(chunk, alloclen) do { \ - uint8_t *a = (uint8_t*) &(chunk)->mem[(chunk)->memlen]; \ - DBG_S(uint8_t *b = &((uint8_t*)(chunk))[(alloclen)-SENTINEL_LEN]); \ - DBG_S(tor_assert(a == b)); \ - memset(a,0,SENTINEL_LEN); \ - } while (0) -#endif /* defined(DISABLE_MEMORY_SENTINELS) */ - -/** Move all bytes stored in <b>chunk</b> to the front of <b>chunk</b>->mem, - * to free up space at the end. */ -static inline void -chunk_repack(chunk_t *chunk) -{ - if (chunk->datalen && chunk->data != &chunk->mem[0]) { - memmove(chunk->mem, chunk->data, chunk->datalen); - } - chunk->data = &chunk->mem[0]; -} - -/** Keep track of total size of allocated chunks for consistency asserts */ -static size_t total_bytes_allocated_in_chunks = 0; -static void -buf_chunk_free_unchecked(chunk_t *chunk) -{ - if (!chunk) - return; -#ifdef DEBUG_CHUNK_ALLOC - tor_assert(CHUNK_ALLOC_SIZE(chunk->memlen) == chunk->DBG_alloc); -#endif - tor_assert(total_bytes_allocated_in_chunks >= - CHUNK_ALLOC_SIZE(chunk->memlen)); - total_bytes_allocated_in_chunks -= CHUNK_ALLOC_SIZE(chunk->memlen); - tor_free(chunk); -} -static inline chunk_t * -chunk_new_with_alloc_size(size_t alloc) -{ - chunk_t *ch; - ch = tor_malloc(alloc); - ch->next = NULL; - ch->datalen = 0; -#ifdef DEBUG_CHUNK_ALLOC - ch->DBG_alloc = alloc; -#endif - ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc); - total_bytes_allocated_in_chunks += alloc; - ch->data = &ch->mem[0]; - CHUNK_SET_SENTINEL(ch, alloc); - return ch; -} - -/** Expand <b>chunk</b> until it can hold <b>sz</b> bytes, and return a - * new pointer to <b>chunk</b>. Old pointers are no longer valid. */ -static inline chunk_t * -chunk_grow(chunk_t *chunk, size_t sz) -{ - off_t offset; - const size_t memlen_orig = chunk->memlen; - const size_t orig_alloc = CHUNK_ALLOC_SIZE(memlen_orig); - const size_t new_alloc = CHUNK_ALLOC_SIZE(sz); - tor_assert(sz > chunk->memlen); - offset = chunk->data - chunk->mem; - chunk = tor_realloc(chunk, new_alloc); - chunk->memlen = sz; - chunk->data = chunk->mem + offset; -#ifdef DEBUG_CHUNK_ALLOC - tor_assert(chunk->DBG_alloc == orig_alloc); - chunk->DBG_alloc = new_alloc; -#endif - total_bytes_allocated_in_chunks += new_alloc - orig_alloc; - CHUNK_SET_SENTINEL(chunk, new_alloc); - return chunk; -} - -/** Every chunk should take up at least this many bytes. */ -#define MIN_CHUNK_ALLOC 256 -/** No chunk should take up more than this many bytes. */ -#define MAX_CHUNK_ALLOC 65536 - -/** Return the allocation size we'd like to use to hold <b>target</b> - * bytes. */ -size_t -buf_preferred_chunk_size(size_t target) -{ - tor_assert(target <= SIZE_T_CEILING - CHUNK_OVERHEAD); - if (CHUNK_ALLOC_SIZE(target) >= MAX_CHUNK_ALLOC) - return CHUNK_ALLOC_SIZE(target); - size_t sz = MIN_CHUNK_ALLOC; - while (CHUNK_SIZE_WITH_ALLOC(sz) < target) { - sz <<= 1; - } - return sz; -} - -/** Collapse data from the first N chunks from <b>buf</b> into buf->head, - * growing it as necessary, until buf->head has the first <b>bytes</b> bytes - * of data from the buffer, or until buf->head has all the data in <b>buf</b>. - * - * Set *<b>head_out</b> to point to the first byte of available data, and - * *<b>len_out</b> to the number of bytes of data available at - * *<b>head_out</b>. Note that *<b>len_out</b> may be more or less than - * <b>bytes</b>, depending on the number of bytes available. - */ -void -buf_pullup(buf_t *buf, size_t bytes, const char **head_out, size_t *len_out) -{ - chunk_t *dest, *src; - size_t capacity; - if (!buf->head) { - *head_out = NULL; - *len_out = 0; - return; - } - - check(); - if (buf->datalen < bytes) - bytes = buf->datalen; - - capacity = bytes; - if (buf->head->datalen >= bytes) { - *head_out = buf->head->data; - *len_out = buf->head->datalen; - return; - } - - if (buf->head->memlen >= capacity) { - /* We don't need to grow the first chunk, but we might need to repack it.*/ - size_t needed = capacity - buf->head->datalen; - if (CHUNK_REMAINING_CAPACITY(buf->head) < needed) - chunk_repack(buf->head); - tor_assert(CHUNK_REMAINING_CAPACITY(buf->head) >= needed); - } else { - chunk_t *newhead; - size_t newsize; - /* We need to grow the chunk. */ - chunk_repack(buf->head); - newsize = CHUNK_SIZE_WITH_ALLOC(buf_preferred_chunk_size(capacity)); - newhead = chunk_grow(buf->head, newsize); - tor_assert(newhead->memlen >= capacity); - if (newhead != buf->head) { - if (buf->tail == buf->head) - buf->tail = newhead; - buf->head = newhead; - } - } - - dest = buf->head; - while (dest->datalen < bytes) { - size_t n = bytes - dest->datalen; - src = dest->next; - tor_assert(src); - if (n >= src->datalen) { - memcpy(CHUNK_WRITE_PTR(dest), src->data, src->datalen); - dest->datalen += src->datalen; - dest->next = src->next; - if (buf->tail == src) - buf->tail = dest; - buf_chunk_free_unchecked(src); - } else { - memcpy(CHUNK_WRITE_PTR(dest), src->data, n); - dest->datalen += n; - src->data += n; - src->datalen -= n; - tor_assert(dest->datalen == bytes); - } - } - - check(); - *head_out = buf->head->data; - *len_out = buf->head->datalen; -} - -#ifdef TOR_UNIT_TESTS -/* Write sz bytes from cp into a newly allocated buffer buf. - * Returns NULL when passed a NULL cp or zero sz. - * Asserts on failure: only for use in unit tests. - * buf must be freed using buf_free(). */ -buf_t * -buf_new_with_data(const char *cp, size_t sz) -{ - /* Validate arguments */ - if (!cp || sz <= 0) { - return NULL; - } - - tor_assert(sz < SSIZE_T_CEILING); - - /* Allocate a buffer */ - buf_t *buf = buf_new_with_capacity(sz); - tor_assert(buf); - buf_assert_ok(buf); - tor_assert(!buf->head); - - /* Allocate a chunk that is sz bytes long */ - buf->head = chunk_new_with_alloc_size(CHUNK_ALLOC_SIZE(sz)); - buf->tail = buf->head; - tor_assert(buf->head); - buf_assert_ok(buf); - tor_assert(buf_allocation(buf) >= sz); - - /* Copy the data and size the buffers */ - tor_assert(sz <= buf_slack(buf)); - tor_assert(sz <= CHUNK_REMAINING_CAPACITY(buf->head)); - memcpy(&buf->head->mem[0], cp, sz); - buf->datalen = sz; - buf->head->datalen = sz; - buf->head->data = &buf->head->mem[0]; - buf_assert_ok(buf); - - /* Make sure everything is large enough */ - tor_assert(buf_allocation(buf) >= sz); - tor_assert(buf_allocation(buf) >= buf_datalen(buf) + buf_slack(buf)); - /* Does the buffer implementation allocate more than the requested size? - * (for example, by rounding up). If so, these checks will fail. */ - tor_assert(buf_datalen(buf) == sz); - tor_assert(buf_slack(buf) == 0); - - return buf; -} -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Remove the first <b>n</b> bytes from buf. */ -void -buf_drain(buf_t *buf, size_t n) -{ - tor_assert(buf->datalen >= n); - while (n) { - tor_assert(buf->head); - if (buf->head->datalen > n) { - buf->head->datalen -= n; - buf->head->data += n; - buf->datalen -= n; - return; - } else { - chunk_t *victim = buf->head; - n -= victim->datalen; - buf->datalen -= victim->datalen; - buf->head = victim->next; - if (buf->tail == victim) - buf->tail = NULL; - buf_chunk_free_unchecked(victim); - } - } - check(); -} - -/** Create and return a new buf with default chunk capacity <b>size</b>. - */ -buf_t * -buf_new_with_capacity(size_t size) -{ - buf_t *b = buf_new(); - b->default_chunk_size = buf_preferred_chunk_size(size); - return b; -} - -/** Allocate and return a new buffer with default capacity. */ -buf_t * -buf_new(void) -{ - buf_t *buf = tor_malloc_zero(sizeof(buf_t)); - buf->magic = BUFFER_MAGIC; - buf->default_chunk_size = 4096; - return buf; -} - -size_t -buf_get_default_chunk_size(const buf_t *buf) -{ - return buf->default_chunk_size; -} - -/** Remove all data from <b>buf</b>. */ -void -buf_clear(buf_t *buf) -{ - chunk_t *chunk, *next; - buf->datalen = 0; - for (chunk = buf->head; chunk; chunk = next) { - next = chunk->next; - buf_chunk_free_unchecked(chunk); - } - buf->head = buf->tail = NULL; -} - -/** Return the number of bytes stored in <b>buf</b> */ -MOCK_IMPL(size_t, -buf_datalen, (const buf_t *buf)) -{ - return buf->datalen; -} - -/** Return the total length of all chunks used in <b>buf</b>. */ -size_t -buf_allocation(const buf_t *buf) -{ - size_t total = 0; - const chunk_t *chunk; - for (chunk = buf->head; chunk; chunk = chunk->next) { - total += CHUNK_ALLOC_SIZE(chunk->memlen); - } - return total; -} - -/** Return the number of bytes that can be added to <b>buf</b> without - * performing any additional allocation. */ -size_t -buf_slack(const buf_t *buf) -{ - if (!buf->tail) - return 0; - else - return CHUNK_REMAINING_CAPACITY(buf->tail); -} - -/** Release storage held by <b>buf</b>. */ -void -buf_free_(buf_t *buf) -{ - if (!buf) - return; - - buf_clear(buf); - buf->magic = 0xdeadbeef; - tor_free(buf); -} - -/** Return a new copy of <b>in_chunk</b> */ -static chunk_t * -chunk_copy(const chunk_t *in_chunk) -{ - chunk_t *newch = tor_memdup(in_chunk, CHUNK_ALLOC_SIZE(in_chunk->memlen)); - total_bytes_allocated_in_chunks += CHUNK_ALLOC_SIZE(in_chunk->memlen); -#ifdef DEBUG_CHUNK_ALLOC - newch->DBG_alloc = CHUNK_ALLOC_SIZE(in_chunk->memlen); -#endif - newch->next = NULL; - if (in_chunk->data) { - off_t offset = in_chunk->data - in_chunk->mem; - newch->data = newch->mem + offset; - } - return newch; -} - -/** Return a new copy of <b>buf</b> */ -buf_t * -buf_copy(const buf_t *buf) -{ - chunk_t *ch; - buf_t *out = buf_new(); - out->default_chunk_size = buf->default_chunk_size; - for (ch = buf->head; ch; ch = ch->next) { - chunk_t *newch = chunk_copy(ch); - if (out->tail) { - out->tail->next = newch; - out->tail = newch; - } else { - out->head = out->tail = newch; - } - } - out->datalen = buf->datalen; - return out; -} - -/** Append a new chunk with enough capacity to hold <b>capacity</b> bytes to - * the tail of <b>buf</b>. If <b>capped</b>, don't allocate a chunk bigger - * than MAX_CHUNK_ALLOC. */ -chunk_t * -buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped) -{ - chunk_t *chunk; - - if (CHUNK_ALLOC_SIZE(capacity) < buf->default_chunk_size) { - chunk = chunk_new_with_alloc_size(buf->default_chunk_size); - } else if (capped && CHUNK_ALLOC_SIZE(capacity) > MAX_CHUNK_ALLOC) { - chunk = chunk_new_with_alloc_size(MAX_CHUNK_ALLOC); - } else { - chunk = chunk_new_with_alloc_size(buf_preferred_chunk_size(capacity)); - } - - chunk->inserted_time = monotime_coarse_get_stamp(); - - if (buf->tail) { - tor_assert(buf->head); - buf->tail->next = chunk; - buf->tail = chunk; - } else { - tor_assert(!buf->head); - buf->head = buf->tail = chunk; - } - check(); - return chunk; -} - -/** Return the age of the oldest chunk in the buffer <b>buf</b>, in - * timestamp units. Requires the current monotonic timestamp as its - * input <b>now</b>. - */ -uint32_t -buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now) -{ - if (buf->head) { - return now - buf->head->inserted_time; - } else { - return 0; - } -} - -size_t -buf_get_total_allocation(void) -{ - return total_bytes_allocated_in_chunks; -} - -/** Read up to <b>at_most</b> bytes from the socket <b>fd</b> into - * <b>chunk</b> (which must be on <b>buf</b>). If we get an EOF, set - * *<b>reached_eof</b> to 1. Return -1 on error, 0 on eof or blocking, - * and the number of bytes read otherwise. */ -static inline int -read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, - int *reached_eof, int *socket_error) -{ - ssize_t read_result; - if (at_most > CHUNK_REMAINING_CAPACITY(chunk)) - at_most = CHUNK_REMAINING_CAPACITY(chunk); - read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0); - - if (read_result < 0) { - int e = tor_socket_errno(fd); - if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ -#ifdef _WIN32 - if (e == WSAENOBUFS) - log_warn(LD_NET,"recv() failed: WSAENOBUFS. Not enough ram?"); -#endif - *socket_error = e; - return -1; - } - return 0; /* would block. */ - } else if (read_result == 0) { - log_debug(LD_NET,"Encountered eof on fd %d", (int)fd); - *reached_eof = 1; - return 0; - } else { /* actually got bytes. */ - buf->datalen += read_result; - chunk->datalen += read_result; - log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result, - (int)buf->datalen); - tor_assert(read_result < INT_MAX); - return (int)read_result; - } -} - -/** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most - * <b>at_most</b> bytes, growing the buffer as necessary. If recv() returns 0 - * (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on - * error; else return the number of bytes read. - */ -/* XXXX indicate "read blocked" somehow? */ -int -buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, - int *reached_eof, - int *socket_error) -{ - /* XXXX It's stupid to overload the return values for these functions: - * "error status" and "number of bytes read" are not mutually exclusive. - */ - int r = 0; - size_t total_read = 0; - - check(); - tor_assert(reached_eof); - tor_assert(SOCKET_OK(s)); - - if (BUG(buf->datalen >= INT_MAX)) - return -1; - if (BUG(buf->datalen >= INT_MAX - at_most)) - return -1; - - while (at_most > total_read) { - size_t readlen = at_most - total_read; - chunk_t *chunk; - if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { - chunk = buf_add_chunk_with_capacity(buf, at_most, 1); - if (readlen > chunk->memlen) - readlen = chunk->memlen; - } else { - size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); - chunk = buf->tail; - if (cap < readlen) - readlen = cap; - } - - r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error); - check(); - if (r < 0) - return r; /* Error */ - tor_assert(total_read+r < INT_MAX); - total_read += r; - if ((size_t)r < readlen) { /* eof, block, or no more to read. */ - break; - } - } - return (int)total_read; -} - -/** Helper for buf_flush_to_socket(): try to write <b>sz</b> bytes from chunk - * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. On success, deduct - * the bytes written from *<b>buf_flushlen</b>. Return the number of bytes - * written on success, 0 on blocking, -1 on failure. - */ -static inline int -flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz, - size_t *buf_flushlen) -{ - ssize_t write_result; - - if (sz > chunk->datalen) - sz = chunk->datalen; - write_result = tor_socket_send(s, chunk->data, sz, 0); - - if (write_result < 0) { - int e = tor_socket_errno(s); - if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ -#ifdef _WIN32 - if (e == WSAENOBUFS) - log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?"); -#endif - return -1; - } - log_debug(LD_NET,"write() would block, returning."); - return 0; - } else { - *buf_flushlen -= write_result; - buf_drain(buf, write_result); - tor_assert(write_result < INT_MAX); - return (int)write_result; - } -} - -/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most - * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by - * the number of bytes actually written, and remove the written bytes - * from the buffer. Return the number of bytes written on success, - * -1 on failure. Return 0 if write() would block. - */ -int -buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen) -{ - /* XXXX It's stupid to overload the return values for these functions: - * "error status" and "number of bytes flushed" are not mutually exclusive. - */ - int r; - size_t flushed = 0; - tor_assert(buf_flushlen); - tor_assert(SOCKET_OK(s)); - if (BUG(*buf_flushlen > buf->datalen)) { - *buf_flushlen = buf->datalen; - } - if (BUG(sz > *buf_flushlen)) { - sz = *buf_flushlen; - } - - check(); - while (sz) { - size_t flushlen0; - tor_assert(buf->head); - if (buf->head->datalen >= sz) - flushlen0 = sz; - else - flushlen0 = buf->head->datalen; - - r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen); - check(); - if (r < 0) - return r; - flushed += r; - sz -= r; - if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */ - break; - } - tor_assert(flushed < INT_MAX); - return (int)flushed; -} - -/** Append <b>string_len</b> bytes from <b>string</b> to the end of - * <b>buf</b>. - * - * Return the new length of the buffer on success, -1 on failure. - */ -int -buf_add(buf_t *buf, const char *string, size_t string_len) -{ - if (!string_len) - return (int)buf->datalen; - check(); - - if (BUG(buf->datalen >= INT_MAX)) - return -1; - if (BUG(buf->datalen >= INT_MAX - string_len)) - return -1; - - while (string_len) { - size_t copy; - if (!buf->tail || !CHUNK_REMAINING_CAPACITY(buf->tail)) - buf_add_chunk_with_capacity(buf, string_len, 1); - - copy = CHUNK_REMAINING_CAPACITY(buf->tail); - if (copy > string_len) - copy = string_len; - memcpy(CHUNK_WRITE_PTR(buf->tail), string, copy); - string_len -= copy; - string += copy; - buf->datalen += copy; - buf->tail->datalen += copy; - } - - check(); - tor_assert(buf->datalen < INT_MAX); - return (int)buf->datalen; -} - -/** Add a nul-terminated <b>string</b> to <b>buf</b>, not including the - * terminating NUL. */ -void -buf_add_string(buf_t *buf, const char *string) -{ - buf_add(buf, string, strlen(string)); -} - -/** As tor_snprintf, but write the results into a buf_t */ -void -buf_add_printf(buf_t *buf, const char *format, ...) -{ - va_list ap; - va_start(ap,format); - buf_add_vprintf(buf, format, ap); - va_end(ap); -} - -/** As tor_vsnprintf, but write the results into a buf_t. */ -void -buf_add_vprintf(buf_t *buf, const char *format, va_list args) -{ - /* XXXX Faster implementations are easy enough, but let's optimize later */ - char *tmp; - tor_vasprintf(&tmp, format, args); - buf_add(buf, tmp, strlen(tmp)); - tor_free(tmp); -} - -/** Return a heap-allocated string containing the contents of <b>buf</b>, plus - * a NUL byte. If <b>sz_out</b> is provided, set *<b>sz_out</b> to the length - * of the returned string, not including the terminating NUL. */ -char * -buf_extract(buf_t *buf, size_t *sz_out) -{ - tor_assert(buf); - - size_t sz = buf_datalen(buf); - char *result; - result = tor_malloc(sz+1); - buf_peek(buf, result, sz); - result[sz] = 0; - if (sz_out) - *sz_out = sz; - return result; -} - -/** Helper: copy the first <b>string_len</b> bytes from <b>buf</b> - * onto <b>string</b>. - */ -void -buf_peek(const buf_t *buf, char *string, size_t string_len) -{ - chunk_t *chunk; - - tor_assert(string); - /* make sure we don't ask for too much */ - tor_assert(string_len <= buf->datalen); - /* buf_assert_ok(buf); */ - - chunk = buf->head; - while (string_len) { - size_t copy = string_len; - tor_assert(chunk); - if (chunk->datalen < copy) - copy = chunk->datalen; - memcpy(string, chunk->data, copy); - string_len -= copy; - string += copy; - chunk = chunk->next; - } -} - -/** Remove <b>string_len</b> bytes from the front of <b>buf</b>, and store - * them into <b>string</b>. Return the new buffer size. <b>string_len</b> - * must be \<= the number of bytes on the buffer. - */ -int -buf_get_bytes(buf_t *buf, char *string, size_t string_len) -{ - /* There must be string_len bytes in buf; write them onto string, - * then memmove buf back (that is, remove them from buf). - * - * Return the number of bytes still on the buffer. */ - - check(); - buf_peek(buf, string, string_len); - buf_drain(buf, string_len); - check(); - tor_assert(buf->datalen < INT_MAX); - return (int)buf->datalen; -} - -/** Move up to *<b>buf_flushlen</b> bytes from <b>buf_in</b> to - * <b>buf_out</b>, and modify *<b>buf_flushlen</b> appropriately. - * Return the number of bytes actually copied. - */ -int -buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen) -{ - /* We can do way better here, but this doesn't turn up in any profiles. */ - char b[4096]; - size_t cp, len; - - if (BUG(buf_out->datalen >= INT_MAX)) - return -1; - if (BUG(buf_out->datalen >= INT_MAX - *buf_flushlen)) - return -1; - - len = *buf_flushlen; - if (len > buf_in->datalen) - len = buf_in->datalen; - - cp = len; /* Remember the number of bytes we intend to copy. */ - tor_assert(cp < INT_MAX); - while (len) { - /* This isn't the most efficient implementation one could imagine, since - * it does two copies instead of 1, but I kinda doubt that this will be - * critical path. */ - size_t n = len > sizeof(b) ? sizeof(b) : len; - buf_get_bytes(buf_in, b, n); - buf_add(buf_out, b, n); - len -= n; - } - *buf_flushlen -= cp; - return (int)cp; -} - -/** Moves all data from <b>buf_in</b> to <b>buf_out</b>, without copying. - */ -void -buf_move_all(buf_t *buf_out, buf_t *buf_in) -{ - tor_assert(buf_out); - if (!buf_in) - return; - - if (buf_out->head == NULL) { - buf_out->head = buf_in->head; - buf_out->tail = buf_in->tail; - } else { - buf_out->tail->next = buf_in->head; - buf_out->tail = buf_in->tail; - } - - buf_out->datalen += buf_in->datalen; - buf_in->head = buf_in->tail = NULL; - buf_in->datalen = 0; -} - -/** Internal structure: represents a position in a buffer. */ -typedef struct buf_pos_t { - const chunk_t *chunk; /**< Which chunk are we pointing to? */ - int pos;/**< Which character inside the chunk's data are we pointing to? */ - size_t chunk_pos; /**< Total length of all previous chunks. */ -} buf_pos_t; - -/** Initialize <b>out</b> to point to the first character of <b>buf</b>.*/ -static void -buf_pos_init(const buf_t *buf, buf_pos_t *out) -{ - out->chunk = buf->head; - out->pos = 0; - out->chunk_pos = 0; -} - -/** Advance <b>out</b> to the first appearance of <b>ch</b> at the current - * position of <b>out</b>, or later. Return -1 if no instances are found; - * otherwise returns the absolute position of the character. */ -static off_t -buf_find_pos_of_char(char ch, buf_pos_t *out) -{ - const chunk_t *chunk; - int pos; - tor_assert(out); - if (out->chunk) { - if (out->chunk->datalen) { - tor_assert(out->pos < (off_t)out->chunk->datalen); - } else { - tor_assert(out->pos == 0); - } - } - pos = out->pos; - for (chunk = out->chunk; chunk; chunk = chunk->next) { - char *cp = memchr(chunk->data+pos, ch, chunk->datalen - pos); - if (cp) { - out->chunk = chunk; - tor_assert(cp - chunk->data < INT_MAX); - out->pos = (int)(cp - chunk->data); - return out->chunk_pos + out->pos; - } else { - out->chunk_pos += chunk->datalen; - pos = 0; - } - } - return -1; -} - -/** Advance <b>pos</b> by a single character, if there are any more characters - * in the buffer. Returns 0 on success, -1 on failure. */ -static inline int -buf_pos_inc(buf_pos_t *pos) -{ - ++pos->pos; - if (pos->pos == (off_t)pos->chunk->datalen) { - if (!pos->chunk->next) - return -1; - pos->chunk_pos += pos->chunk->datalen; - pos->chunk = pos->chunk->next; - pos->pos = 0; - } - return 0; -} - -/** Return true iff the <b>n</b>-character string in <b>s</b> appears - * (verbatim) at <b>pos</b>. */ -static int -buf_matches_at_pos(const buf_pos_t *pos, const char *s, size_t n) -{ - buf_pos_t p; - if (!n) - return 1; - - memcpy(&p, pos, sizeof(p)); - - while (1) { - char ch = p.chunk->data[p.pos]; - if (ch != *s) - return 0; - ++s; - /* If we're out of characters that don't match, we match. Check this - * _before_ we test incrementing pos, in case we're at the end of the - * string. */ - if (--n == 0) - return 1; - if (buf_pos_inc(&p)<0) - return 0; - } -} - -/** Return the first position in <b>buf</b> at which the <b>n</b>-character - * string <b>s</b> occurs, or -1 if it does not occur. */ -int -buf_find_string_offset(const buf_t *buf, const char *s, size_t n) -{ - buf_pos_t pos; - buf_pos_init(buf, &pos); - while (buf_find_pos_of_char(*s, &pos) >= 0) { - if (buf_matches_at_pos(&pos, s, n)) { - tor_assert(pos.chunk_pos + pos.pos < INT_MAX); - return (int)(pos.chunk_pos + pos.pos); - } else { - if (buf_pos_inc(&pos)<0) - return -1; - } - } - return -1; -} - -/** Return 1 iff <b>buf</b> starts with <b>cmd</b>. <b>cmd</b> must be a null - * terminated string, of no more than PEEK_BUF_STARTSWITH_MAX bytes. */ -int -buf_peek_startswith(const buf_t *buf, const char *cmd) -{ - char tmp[PEEK_BUF_STARTSWITH_MAX]; - size_t clen = strlen(cmd); - if (clen == 0) - return 1; - if (BUG(clen > sizeof(tmp))) - return 0; - if (buf->datalen < clen) - return 0; - buf_peek(buf, tmp, clen); - return fast_memeq(tmp, cmd, clen); -} - -/** Return the index within <b>buf</b> at which <b>ch</b> first appears, - * or -1 if <b>ch</b> does not appear on buf. */ -static off_t -buf_find_offset_of_char(buf_t *buf, char ch) -{ - chunk_t *chunk; - off_t offset = 0; - for (chunk = buf->head; chunk; chunk = chunk->next) { - char *cp = memchr(chunk->data, ch, chunk->datalen); - if (cp) - return offset + (cp - chunk->data); - else - offset += chunk->datalen; - } - return -1; -} - -/** Try to read a single LF-terminated line from <b>buf</b>, and write it - * (including the LF), NUL-terminated, into the *<b>data_len</b> byte buffer - * at <b>data_out</b>. Set *<b>data_len</b> to the number of bytes in the - * line, not counting the terminating NUL. Return 1 if we read a whole line, - * return 0 if we don't have a whole line yet, and return -1 if the line - * length exceeds *<b>data_len</b>. - */ -int -buf_get_line(buf_t *buf, char *data_out, size_t *data_len) -{ - size_t sz; - off_t offset; - - if (!buf->head) - return 0; - - offset = buf_find_offset_of_char(buf, '\n'); - if (offset < 0) - return 0; - sz = (size_t) offset; - if (sz+2 > *data_len) { - *data_len = sz + 2; - return -1; - } - buf_get_bytes(buf, data_out, sz+1); - data_out[sz+1] = '\0'; - *data_len = sz+1; - return 1; -} - -/** Compress or uncompress the <b>data_len</b> bytes in <b>data</b> using the - * compression state <b>state</b>, appending the result to <b>buf</b>. If - * <b>done</b> is true, flush the data in the state and finish the - * compression/uncompression. Return -1 on failure, 0 on success. */ -int -buf_add_compress(buf_t *buf, tor_compress_state_t *state, - const char *data, size_t data_len, - const int done) -{ - char *next; - size_t old_avail, avail; - int over = 0; - - do { - int need_new_chunk = 0; - if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) { - size_t cap = data_len / 4; - buf_add_chunk_with_capacity(buf, cap, 1); - } - next = CHUNK_WRITE_PTR(buf->tail); - avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail); - switch (tor_compress_process(state, &next, &avail, - &data, &data_len, done)) { - case TOR_COMPRESS_DONE: - over = 1; - break; - case TOR_COMPRESS_ERROR: - return -1; - case TOR_COMPRESS_OK: - if (data_len == 0) { - tor_assert_nonfatal(!done); - over = 1; - } - break; - case TOR_COMPRESS_BUFFER_FULL: - if (avail) { - /* The compression module says we need more room - * (TOR_COMPRESS_BUFFER_FULL). Start a new chunk automatically, - * whether were going to or not. */ - need_new_chunk = 1; - } - if (data_len == 0 && !done) { - /* We've consumed all the input data, though, so there's no - * point in forging ahead right now. */ - over = 1; - } - break; - } - buf->datalen += old_avail - avail; - buf->tail->datalen += old_avail - avail; - if (need_new_chunk) { - buf_add_chunk_with_capacity(buf, data_len/4, 1); - } - - } while (!over); - check(); - return 0; -} - -/** Set *<b>output</b> to contain a copy of the data in *<b>input</b> */ -int -buf_set_to_copy(buf_t **output, - const buf_t *input) -{ - if (*output) - buf_free(*output); - *output = buf_copy(input); - return 0; -} - -/** Log an error and exit if <b>buf</b> is corrupted. - */ -void -buf_assert_ok(buf_t *buf) -{ - tor_assert(buf); - tor_assert(buf->magic == BUFFER_MAGIC); - - if (! buf->head) { - tor_assert(!buf->tail); - tor_assert(buf->datalen == 0); - } else { - chunk_t *ch; - size_t total = 0; - tor_assert(buf->tail); - for (ch = buf->head; ch; ch = ch->next) { - total += ch->datalen; - tor_assert(ch->datalen <= ch->memlen); - tor_assert(ch->data >= &ch->mem[0]); - tor_assert(ch->data <= &ch->mem[0]+ch->memlen); - if (ch->data == &ch->mem[0]+ch->memlen) { - /* LCOV_EXCL_START */ - static int warned = 0; - if (! warned) { - log_warn(LD_BUG, "Invariant violation in buf.c related to #15083"); - warned = 1; - } - /* LCOV_EXCL_STOP */ - } - tor_assert(ch->data+ch->datalen <= &ch->mem[0] + ch->memlen); - if (!ch->next) - tor_assert(ch == buf->tail); - } - tor_assert(buf->datalen == total); - } -} - diff --git a/src/common/buffers.h b/src/common/buffers.h deleted file mode 100644 index 4275152de2..0000000000 --- a/src/common/buffers.h +++ /dev/null @@ -1,131 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file buffers.h - * \brief Header file for buffers.c. - **/ - -#ifndef TOR_BUFFERS_H -#define TOR_BUFFERS_H - -#include "compat.h" -#include "torint.h" -#include "testsupport.h" - -typedef struct buf_t buf_t; - -struct tor_compress_state_t; - -buf_t *buf_new(void); -buf_t *buf_new_with_capacity(size_t size); -size_t buf_get_default_chunk_size(const buf_t *buf); -void buf_free_(buf_t *buf); -#define buf_free(b) FREE_AND_NULL(buf_t, buf_free_, (b)) -void buf_clear(buf_t *buf); -buf_t *buf_copy(const buf_t *buf); - -MOCK_DECL(size_t, buf_datalen, (const buf_t *buf)); -size_t buf_allocation(const buf_t *buf); -size_t buf_slack(const buf_t *buf); - -uint32_t buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now); -size_t buf_get_total_allocation(void); - -int buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, - int *reached_eof, - int *socket_error); - -int buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen); - -int buf_add(buf_t *buf, const char *string, size_t string_len); -void buf_add_string(buf_t *buf, const char *string); -void buf_add_printf(buf_t *buf, const char *format, ...) - CHECK_PRINTF(2, 3); -void buf_add_vprintf(buf_t *buf, const char *format, va_list args) - CHECK_PRINTF(2, 0); -int buf_add_compress(buf_t *buf, struct tor_compress_state_t *state, - const char *data, size_t data_len, int done); -int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen); -void buf_move_all(buf_t *buf_out, buf_t *buf_in); -void buf_peek(const buf_t *buf, char *string, size_t string_len); -void buf_drain(buf_t *buf, size_t n); -int buf_get_bytes(buf_t *buf, char *string, size_t string_len); -int buf_get_line(buf_t *buf, char *data_out, size_t *data_len); - -#define PEEK_BUF_STARTSWITH_MAX 16 -int buf_peek_startswith(const buf_t *buf, const char *cmd); - -int buf_set_to_copy(buf_t **output, - const buf_t *input); - -void buf_assert_ok(buf_t *buf); - -int buf_find_string_offset(const buf_t *buf, const char *s, size_t n); -void buf_pullup(buf_t *buf, size_t bytes, - const char **head_out, size_t *len_out); -char *buf_extract(buf_t *buf, size_t *sz_out); - -#ifdef BUFFERS_PRIVATE -#ifdef TOR_UNIT_TESTS -buf_t *buf_new_with_data(const char *cp, size_t sz); -#endif -size_t buf_preferred_chunk_size(size_t target); - -#define DEBUG_CHUNK_ALLOC -/** A single chunk on a buffer. */ -typedef struct chunk_t { - struct chunk_t *next; /**< The next chunk on the buffer. */ - size_t datalen; /**< The number of bytes stored in this chunk */ - size_t memlen; /**< The number of usable bytes of storage in <b>mem</b>. */ -#ifdef DEBUG_CHUNK_ALLOC - size_t DBG_alloc; -#endif - char *data; /**< A pointer to the first byte of data stored in <b>mem</b>. */ - uint32_t inserted_time; /**< Timestamp when this chunk was inserted. */ - char mem[FLEXIBLE_ARRAY_MEMBER]; /**< The actual memory used for storage in - * this chunk. */ -} chunk_t; - -/** Magic value for buf_t.magic, to catch pointer errors. */ -#define BUFFER_MAGIC 0xB0FFF312u -/** A resizeable buffer, optimized for reading and writing. */ -struct buf_t { - uint32_t magic; /**< Magic cookie for debugging: Must be set to - * BUFFER_MAGIC. */ - size_t datalen; /**< How many bytes is this buffer holding right now? */ - size_t default_chunk_size; /**< Don't allocate any chunks smaller than - * this for this buffer. */ - chunk_t *head; /**< First chunk in the list, or NULL for none. */ - chunk_t *tail; /**< Last chunk in the list, or NULL for none. */ -}; - -chunk_t *buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped); -/** If a read onto the end of a chunk would be smaller than this number, then - * just start a new chunk. */ -#define MIN_READ_LEN 8 - -/** Return the number of bytes that can be written onto <b>chunk</b> without - * running out of space. */ -static inline size_t -CHUNK_REMAINING_CAPACITY(const chunk_t *chunk) -{ - return (chunk->mem + chunk->memlen) - (chunk->data + chunk->datalen); -} - -/** Return the next character in <b>chunk</b> onto which data can be appended. - * If the chunk is full, this might be off the end of chunk->mem. */ -static inline char * -CHUNK_WRITE_PTR(chunk_t *chunk) -{ - return chunk->data + chunk->datalen; -} - -#endif /* defined(BUFFERS_PRIVATE) */ - -#endif /* !defined(TOR_BUFFERS_H) */ - diff --git a/src/common/buffers_tls.c b/src/common/buffers_tls.c deleted file mode 100644 index 041f78b818..0000000000 --- a/src/common/buffers_tls.c +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#define BUFFERS_PRIVATE -#include "orconfig.h" -#include <stddef.h> -#include "buffers.h" -#include "buffers_tls.h" -#include "compat.h" -#include "compress.h" -#include "util.h" -#include "torint.h" -#include "torlog.h" -#include "tortls.h" -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -/** As read_to_chunk(), but return (negative) error code on error, blocking, - * or TLS, and the number of bytes read otherwise. */ -static inline int -read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls, - size_t at_most) -{ - int read_result; - - tor_assert(CHUNK_REMAINING_CAPACITY(chunk) >= at_most); - read_result = tor_tls_read(tls, CHUNK_WRITE_PTR(chunk), at_most); - if (read_result < 0) - return read_result; - buf->datalen += read_result; - chunk->datalen += read_result; - return read_result; -} - -/** As read_to_buf, but reads from a TLS connection, and returns a TLS - * status value rather than the number of bytes read. - * - * Using TLS on OR connections complicates matters in two ways. - * - * First, a TLS stream has its own read buffer independent of the - * connection's read buffer. (TLS needs to read an entire frame from - * the network before it can decrypt any data. Thus, trying to read 1 - * byte from TLS can require that several KB be read from the network - * and decrypted. The extra data is stored in TLS's decrypt buffer.) - * Because the data hasn't been read by Tor (it's still inside the TLS), - * this means that sometimes a connection "has stuff to read" even when - * poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is - * used in connection.c to detect TLS objects with non-empty internal - * buffers and read from them again. - * - * Second, the TLS stream's events do not correspond directly to network - * events: sometimes, before a TLS stream can read, the network must be - * ready to write -- or vice versa. - */ -int -buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most) -{ - int r = 0; - size_t total_read = 0; - - check_no_tls_errors(); - - if (BUG(buf->datalen >= INT_MAX)) - return -1; - if (BUG(buf->datalen >= INT_MAX - at_most)) - return -1; - - while (at_most > total_read) { - size_t readlen = at_most - total_read; - chunk_t *chunk; - if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { - chunk = buf_add_chunk_with_capacity(buf, at_most, 1); - if (readlen > chunk->memlen) - readlen = chunk->memlen; - } else { - size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); - chunk = buf->tail; - if (cap < readlen) - readlen = cap; - } - - r = read_to_chunk_tls(buf, chunk, tls, readlen); - if (r < 0) - return r; /* Error */ - tor_assert(total_read+r < INT_MAX); - total_read += r; - if ((size_t)r < readlen) /* eof, block, or no more to read. */ - break; - } - return (int)total_read; -} - -/** Helper for buf_flush_to_tls(): try to write <b>sz</b> bytes from chunk - * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. (Tries to write - * more if there is a forced pending write size.) On success, deduct the - * bytes written from *<b>buf_flushlen</b>. Return the number of bytes - * written on success, and a TOR_TLS error code on failure or blocking. - */ -static inline int -flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, - size_t sz, size_t *buf_flushlen) -{ - int r; - size_t forced; - char *data; - - forced = tor_tls_get_forced_write_size(tls); - if (forced > sz) - sz = forced; - if (chunk) { - data = chunk->data; - tor_assert(sz <= chunk->datalen); - } else { - data = NULL; - tor_assert(sz == 0); - } - r = tor_tls_write(tls, data, sz); - if (r < 0) - return r; - if (*buf_flushlen > (size_t)r) - *buf_flushlen -= r; - else - *buf_flushlen = 0; - buf_drain(buf, r); - log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.", - r,(int)*buf_flushlen,(int)buf->datalen); - return r; -} - -/** As buf_flush_to_socket(), but writes data to a TLS connection. Can write - * more than <b>flushlen</b> bytes. - */ -int -buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen, - size_t *buf_flushlen) -{ - int r; - size_t flushed = 0; - ssize_t sz; - tor_assert(buf_flushlen); - if (BUG(*buf_flushlen > buf->datalen)) { - *buf_flushlen = buf->datalen; - } - if (BUG(flushlen > *buf_flushlen)) { - flushlen = *buf_flushlen; - } - sz = (ssize_t) flushlen; - - /* we want to let tls write even if flushlen is zero, because it might - * have a partial record pending */ - check_no_tls_errors(); - - do { - size_t flushlen0; - if (buf->head) { - if ((ssize_t)buf->head->datalen >= sz) - flushlen0 = sz; - else - flushlen0 = buf->head->datalen; - } else { - flushlen0 = 0; - } - - r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen); - if (r < 0) - return r; - flushed += r; - sz -= r; - if (r == 0) /* Can't flush any more now. */ - break; - } while (sz > 0); - tor_assert(flushed < INT_MAX); - return (int)flushed; -} - diff --git a/src/common/buffers_tls.h b/src/common/buffers_tls.h deleted file mode 100644 index 2f9fda45a0..0000000000 --- a/src/common/buffers_tls.h +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_BUFFERS_TLS_H -#define TOR_BUFFERS_TLS_H - -struct buf_t; -struct tor_tls_t; - -int buf_read_from_tls(struct buf_t *buf, - struct tor_tls_t *tls, size_t at_most); -int buf_flush_to_tls(struct buf_t *buf, struct tor_tls_t *tls, - size_t sz, size_t *buf_flushlen); - -#endif /* !defined(TOR_BUFFERS_TLS_H) */ - diff --git a/src/common/ciphers.inc b/src/common/ciphers.inc deleted file mode 100644 index 0084b3e325..0000000000 --- a/src/common/ciphers.inc +++ /dev/null @@ -1,100 +0,0 @@ -/* This is an include file used to define the list of ciphers clients should - * advertise. Before including it, you should define the CIPHER and XCIPHER - * macros. - * - * This file was automatically generated by get_mozilla_ciphers.py; - * TLSv1.3 ciphers were added manually. - */ - -/* Here are the TLS1.3 ciphers. Note that we don't have XCIPHER instances - * here, since we don't want to ever fake them. - */ -#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 - CIPHER(0x1301, TLS1_3_TXT_AES_128_GCM_SHA256) -#endif -#ifdef TLS1_3_TXT_AES_256_GCM_SHA384 - CIPHER(0x1302, TLS1_3_TXT_AES_256_GCM_SHA384) -#endif -#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256 - CIPHER(0x1303, TLS1_3_TXT_CHACHA20_POLY1305_SHA256) -#endif -#ifdef TLS1_3_TXT_AES_128_CCM_SHA256 - CIPHER(0x1304, TLS1_3_TXT_AES_128_CCM_SHA256) -#endif - -/* Here's the machine-generated list. */ -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - CIPHER(0xc02b, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) -#else - XCIPHER(0xc02b, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - CIPHER(0xc02f, TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256) -#else - XCIPHER(0xc02f, TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256) -#endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 - CIPHER(0xcca9, TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305) -#else - XCIPHER(0xcca9, TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 - CIPHER(0xcca8, TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305) -#else - XCIPHER(0xcca8, TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305) -#endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - CIPHER(0xc02c, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) -#else - XCIPHER(0xc02c, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - CIPHER(0xc030, TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384) -#else - XCIPHER(0xc030, TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384) -#endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - CIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -#else - XCIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -#endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - CIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -#else - XCIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA - CIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) -#else - XCIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA - CIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) -#else - XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA - CIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) -#else - XCIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA - CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) -#else - XCIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) -#endif -#ifdef TLS1_TXT_RSA_WITH_AES_128_SHA - CIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA) -#else - XCIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA) -#endif -#ifdef TLS1_TXT_RSA_WITH_AES_256_SHA - CIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) -#else - XCIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) -#endif -#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA - CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) -#else - XCIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) -#endif diff --git a/src/common/compat.c b/src/common/compat.c deleted file mode 100644 index 6fdd6ecf00..0000000000 --- a/src/common/compat.c +++ /dev/null @@ -1,3531 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat.c - * \brief Wrappers to make calls more portable. This code defines - * functions such as tor_snprintf, get/set various data types, - * renaming, setting socket options, switching user IDs. It is basically - * where the non-portable items are conditionally included depending on - * the platform. - **/ - -#define COMPAT_PRIVATE -#include "compat.h" - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <sys/locking.h> -#endif - -#ifdef HAVE_UNAME -#include <sys/utsname.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_SYSCTL_H -#include <sys/sysctl.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_UTIME_H -#include <utime.h> -#endif -#ifdef HAVE_SYS_UTIME_H -#include <sys/utime.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <sys/fcntl.h> -#endif -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#ifdef HAVE_GRP_H -#include <grp.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_CRT_EXTERNS_H -#include <crt_externs.h> -#endif -#ifdef HAVE_SYS_STATVFS_H -#include <sys/statvfs.h> -#endif -#ifdef HAVE_SYS_CAPABILITY_H -#include <sys/capability.h> -#endif - -#ifdef _WIN32 -#include <conio.h> -#include <wchar.h> -/* Some mingw headers lack these. :p */ -#if defined(HAVE_DECL__GETWCH) && !HAVE_DECL__GETWCH -wint_t _getwch(void); -#endif -#ifndef WEOF -#define WEOF (wchar_t)(0xFFFF) -#endif -#if defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY -static inline void -SecureZeroMemory(PVOID ptr, SIZE_T cnt) -{ - volatile char *vcptr = (volatile char*)ptr; - while (cnt--) - *vcptr++ = 0; -} -#endif /* defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY */ -#elif defined(HAVE_READPASSPHRASE_H) -#include <readpassphrase.h> -#else -#include "tor_readpassphrase.h" -#endif /* defined(_WIN32) || ... */ - -/* Includes for the process attaching prevention */ -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) -/* Only use the linux prctl; the IRIX prctl is totally different */ -#include <sys/prctl.h> -#elif defined(__APPLE__) -#include <sys/ptrace.h> -#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) || ... */ - -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> /* FreeBSD needs this to know what version it is */ -#endif -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_MMAP -#include <sys/mman.h> -#endif -#ifdef HAVE_SYS_SYSLIMITS_H -#include <sys/syslimits.h> -#endif -#ifdef HAVE_SYS_FILE_H -#include <sys/file.h> -#endif - -#include "torlog.h" -#include "util.h" -#include "container.h" -#include "address.h" -#include "sandbox.h" - -/* Inline the strl functions if the platform doesn't have them. */ -#ifndef HAVE_STRLCPY -#include "strlcpy.c" -#endif -#ifndef HAVE_STRLCAT -#include "strlcat.c" -#endif - -/* When set_max_file_descriptors() is called, update this with the max file - * descriptor value so we can use it to check the limit when opening a new - * socket. Default value is what Debian sets as the default hard limit. */ -static int max_sockets = 1024; - -/** As open(path, flags, mode), but return an fd with the close-on-exec mode - * set. */ -int -tor_open_cloexec(const char *path, int flags, unsigned mode) -{ - int fd; - const char *p = sandbox_intern_string(path); -#ifdef O_CLOEXEC - fd = open(p, flags|O_CLOEXEC, mode); - if (fd >= 0) - return fd; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with O_CLOEXEC support, we - * are running on one without. */ - if (errno != EINVAL) - return -1; -#endif /* defined(O_CLOEXEC) */ - - log_debug(LD_FS, "Opening %s with flags %x", p, flags); - fd = open(p, flags, mode); -#ifdef FD_CLOEXEC - if (fd >= 0) { - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - close(fd); - return -1; - } - } -#endif /* defined(FD_CLOEXEC) */ - return fd; -} - -/** As fopen(path,mode), but ensures that the O_CLOEXEC bit is set on the - * underlying file handle. */ -FILE * -tor_fopen_cloexec(const char *path, const char *mode) -{ - FILE *result = fopen(path, mode); -#ifdef FD_CLOEXEC - if (result != NULL) { - if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - fclose(result); - return NULL; - } - } -#endif /* defined(FD_CLOEXEC) */ - return result; -} - -/** As rename(), but work correctly with the sandbox. */ -int -tor_rename(const char *path_old, const char *path_new) -{ - log_debug(LD_FS, "Renaming %s to %s", path_old, path_new); - return rename(sandbox_intern_string(path_old), - sandbox_intern_string(path_new)); -} - -#if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN) -/** Try to create a memory mapping for <b>filename</b> and return it. On - * failure, return NULL. Sets errno properly, using ERANGE to mean - * "empty file". Must only be called on trusted Tor-owned files, as changing - * the underlying file's size causes unspecified behavior. */ -tor_mmap_t * -tor_mmap_file(const char *filename) -{ - int fd; /* router file */ - char *string; - int result; - tor_mmap_t *res; - size_t size, filesize; - struct stat st; - - tor_assert(filename); - - fd = tor_open_cloexec(filename, O_RDONLY, 0); - if (fd<0) { - int save_errno = errno; - int severity = (errno == ENOENT) ? LOG_INFO : LOG_WARN; - log_fn(severity, LD_FS,"Could not open \"%s\" for mmap(): %s",filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - /* Get the size of the file */ - result = fstat(fd, &st); - if (result != 0) { - int save_errno = errno; - log_warn(LD_FS, - "Couldn't fstat opened descriptor for \"%s\" during mmap: %s", - filename, strerror(errno)); - close(fd); - errno = save_errno; - return NULL; - } - size = filesize = (size_t)(st.st_size); - - if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) { - log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename); - errno = EFBIG; - close(fd); - return NULL; - } - if (!size) { - /* Zero-length file. If we call mmap on it, it will succeed but - * return NULL, and bad things will happen. So just fail. */ - log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); - errno = ERANGE; - close(fd); - return NULL; - } - - string = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); - close(fd); - if (string == MAP_FAILED) { - int save_errno = errno; - log_warn(LD_FS,"Could not mmap file \"%s\": %s", filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - res = tor_malloc_zero(sizeof(tor_mmap_t)); - res->data = string; - res->size = filesize; - res->mapping_size = size; - - return res; -} -/** Release storage held for a memory mapping; returns 0 on success, - * or -1 on failure (and logs a warning). */ -int -tor_munmap_file(tor_mmap_t *handle) -{ - int res; - - if (handle == NULL) - return 0; - - res = munmap((char*)handle->data, handle->mapping_size); - if (res == 0) { - /* munmap() succeeded */ - tor_free(handle); - } else { - log_warn(LD_FS, "Failed to munmap() in tor_munmap_file(): %s", - strerror(errno)); - res = -1; - } - - return res; -} -#elif defined(_WIN32) -tor_mmap_t * -tor_mmap_file(const char *filename) -{ - TCHAR tfilename[MAX_PATH]= {0}; - tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t)); - int empty = 0; - HANDLE file_handle = INVALID_HANDLE_VALUE; - DWORD size_low, size_high; - uint64_t real_size; - res->mmap_handle = NULL; -#ifdef UNICODE - mbstowcs(tfilename,filename,MAX_PATH); -#else - strlcpy(tfilename,filename,MAX_PATH); -#endif - file_handle = CreateFile(tfilename, - GENERIC_READ, FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0); - - if (file_handle == INVALID_HANDLE_VALUE) - goto win_err; - - size_low = GetFileSize(file_handle, &size_high); - - if (size_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { - log_warn(LD_FS,"Error getting size of \"%s\".",filename); - goto win_err; - } - if (size_low == 0 && size_high == 0) { - log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); - empty = 1; - goto err; - } - real_size = (((uint64_t)size_high)<<32) | size_low; - if (real_size > SIZE_MAX) { - log_warn(LD_FS,"File \"%s\" is too big to map; not trying.",filename); - goto err; - } - res->size = real_size; - - res->mmap_handle = CreateFileMapping(file_handle, - NULL, - PAGE_READONLY, - size_high, - size_low, - NULL); - if (res->mmap_handle == NULL) - goto win_err; - res->data = (char*) MapViewOfFile(res->mmap_handle, - FILE_MAP_READ, - 0, 0, 0); - if (!res->data) - goto win_err; - - CloseHandle(file_handle); - return res; - win_err: { - DWORD e = GetLastError(); - int severity = (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) ? - LOG_INFO : LOG_WARN; - char *msg = format_win32_error(e); - log_fn(severity, LD_FS, "Couldn't mmap file \"%s\": %s", filename, msg); - tor_free(msg); - if (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) - errno = ENOENT; - else - errno = EINVAL; - } - err: - if (empty) - errno = ERANGE; - if (file_handle != INVALID_HANDLE_VALUE) - CloseHandle(file_handle); - tor_munmap_file(res); - return NULL; -} - -/* Unmap the file, and return 0 for success or -1 for failure */ -int -tor_munmap_file(tor_mmap_t *handle) -{ - if (handle == NULL) - return 0; - - if (handle->data) { - /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would - have to be redefined as non-const. */ - BOOL ok = UnmapViewOfFile( (LPVOID) handle->data); - if (!ok) { - log_warn(LD_FS, "Failed to UnmapViewOfFile() in tor_munmap_file(): %d", - (int)GetLastError()); - } - } - - if (handle->mmap_handle != NULL) - CloseHandle(handle->mmap_handle); - tor_free(handle); - - return 0; -} -#else -#error "cannot implement tor_mmap_file" -#endif /* defined(HAVE_MMAP) || ... || ... */ - -/** Replacement for snprintf. Differs from platform snprintf in two - * ways: First, always NUL-terminates its output. Second, always - * returns -1 if the result is truncated. (Note that this return - * behavior does <i>not</i> conform to C99; it just happens to be - * easier to emulate "return -1" with conformant implementations than - * it is to emulate "return number that would be written" with - * non-conformant implementations.) */ -int -tor_snprintf(char *str, size_t size, const char *format, ...) -{ - va_list ap; - int r; - va_start(ap,format); - r = tor_vsnprintf(str,size,format,ap); - va_end(ap); - return r; -} - -/** Replacement for vsnprintf; behavior differs as tor_snprintf differs from - * snprintf. - */ -int -tor_vsnprintf(char *str, size_t size, const char *format, va_list args) -{ - int r; - if (size == 0) - return -1; /* no place for the NUL */ - if (size > SIZE_T_CEILING) - return -1; -#ifdef _WIN32 - r = _vsnprintf(str, size, format, args); -#else - r = vsnprintf(str, size, format, args); -#endif - str[size-1] = '\0'; - if (r < 0 || r >= (ssize_t)size) - return -1; - return r; -} - -/** - * Portable asprintf implementation. Does a printf() into a newly malloc'd - * string. Sets *<b>strp</b> to this string, and returns its length (not - * including the terminating NUL character). - * - * You can treat this function as if its implementation were something like - <pre> - char buf[_INFINITY_]; - tor_snprintf(buf, sizeof(buf), fmt, args); - *strp = tor_strdup(buf); - return strlen(*strp): - </pre> - * Where _INFINITY_ is an imaginary constant so big that any string can fit - * into it. - */ -int -tor_asprintf(char **strp, const char *fmt, ...) -{ - int r; - va_list args; - va_start(args, fmt); - r = tor_vasprintf(strp, fmt, args); - va_end(args); - if (!*strp || r < 0) { - /* LCOV_EXCL_START */ - log_err(LD_BUG, "Internal error in asprintf"); - tor_assert(0); - /* LCOV_EXCL_STOP */ - } - return r; -} - -/** - * Portable vasprintf implementation. Does a printf() into a newly malloc'd - * string. Differs from regular vasprintf in the same ways that - * tor_asprintf() differs from regular asprintf. - */ -int -tor_vasprintf(char **strp, const char *fmt, va_list args) -{ - /* use a temporary variable in case *strp is in args. */ - char *strp_tmp=NULL; -#ifdef HAVE_VASPRINTF - /* If the platform gives us one, use it. */ - int r = vasprintf(&strp_tmp, fmt, args); - if (r < 0) - *strp = NULL; - else - *strp = strp_tmp; - return r; -#elif defined(HAVE__VSCPRINTF) - /* On Windows, _vsnprintf won't tell us the length of the string if it - * overflows, so we need to use _vcsprintf to tell how much to allocate */ - int len, r; - va_list tmp_args; - va_copy(tmp_args, args); - len = _vscprintf(fmt, tmp_args); - va_end(tmp_args); - if (len < 0) { - *strp = NULL; - return -1; - } - strp_tmp = tor_malloc(len + 1); - r = _vsnprintf(strp_tmp, len+1, fmt, args); - if (r != len) { - tor_free(strp_tmp); - *strp = NULL; - return -1; - } - *strp = strp_tmp; - return len; -#else - /* Everywhere else, we have a decent vsnprintf that tells us how many - * characters we need. We give it a try on a short buffer first, since - * it might be nice to avoid the second vsnprintf call. - */ - char buf[128]; - int len, r; - va_list tmp_args; - va_copy(tmp_args, args); - /* vsnprintf() was properly checked but tor_vsnprintf() available so - * why not use it? */ - len = tor_vsnprintf(buf, sizeof(buf), fmt, tmp_args); - va_end(tmp_args); - if (len < (int)sizeof(buf)) { - *strp = tor_strdup(buf); - return len; - } - strp_tmp = tor_malloc(len+1); - /* use of tor_vsnprintf() will ensure string is null terminated */ - r = tor_vsnprintf(strp_tmp, len+1, fmt, args); - if (r != len) { - tor_free(strp_tmp); - *strp = NULL; - return -1; - } - *strp = strp_tmp; - return len; -#endif /* defined(HAVE_VASPRINTF) || ... */ -} - -/** Given <b>hlen</b> bytes at <b>haystack</b> and <b>nlen</b> bytes at - * <b>needle</b>, return a pointer to the first occurrence of the needle - * within the haystack, or NULL if there is no such occurrence. - * - * This function is <em>not</em> timing-safe. - * - * Requires that <b>nlen</b> be greater than zero. - */ -const void * -tor_memmem(const void *_haystack, size_t hlen, - const void *_needle, size_t nlen) -{ -#if defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) - tor_assert(nlen); - return memmem(_haystack, hlen, _needle, nlen); -#else - /* This isn't as fast as the GLIBC implementation, but it doesn't need to - * be. */ - const char *p, *last_possible_start; - const char *haystack = (const char*)_haystack; - const char *needle = (const char*)_needle; - char first; - tor_assert(nlen); - - if (nlen > hlen) - return NULL; - - p = haystack; - /* Last position at which the needle could start. */ - last_possible_start = haystack + hlen - nlen; - first = *(const char*)needle; - while ((p = memchr(p, first, last_possible_start + 1 - p))) { - if (fast_memeq(p, needle, nlen)) - return p; - if (++p > last_possible_start) { - /* This comparison shouldn't be necessary, since if p was previously - * equal to last_possible_start, the next memchr call would be - * "memchr(p, first, 0)", which will return NULL. But it clarifies the - * logic. */ - return NULL; - } - } - return NULL; -#endif /* defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) */ -} - -/** - * Tables to implement ctypes-replacement TOR_IS*() functions. Each table - * has 256 bits to look up whether a character is in some set or not. This - * fails on non-ASCII platforms, but it is hard to find a platform whose - * character set is not a superset of ASCII nowadays. */ - -/**@{*/ -const uint32_t TOR_ISALPHA_TABLE[8] = - { 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; -const uint32_t TOR_ISALNUM_TABLE[8] = - { 0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; -const uint32_t TOR_ISSPACE_TABLE[8] = { 0x3e00, 0x1, 0, 0, 0, 0, 0, 0 }; -const uint32_t TOR_ISXDIGIT_TABLE[8] = - { 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 }; -const uint32_t TOR_ISDIGIT_TABLE[8] = { 0, 0x3ff0000, 0, 0, 0, 0, 0, 0 }; -const uint32_t TOR_ISPRINT_TABLE[8] = - { 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 }; -const uint32_t TOR_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 }; -const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 }; - -/** Upper-casing and lowercasing tables to map characters to upper/lowercase - * equivalents. Used by tor_toupper() and tor_tolower(). */ -/**@{*/ -const uint8_t TOR_TOUPPER_TABLE[256] = { - 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, - 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, - 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, - 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, - 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, - 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, - 96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, - 80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127, - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, -}; -const uint8_t TOR_TOLOWER_TABLE[256] = { - 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, - 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, - 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, - 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, - 64,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95, - 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, -}; -/**@}*/ - -/** Helper for tor_strtok_r_impl: Advances cp past all characters in - * <b>sep</b>, and returns its new value. */ -static char * -strtok_helper(char *cp, const char *sep) -{ - if (sep[1]) { - while (*cp && strchr(sep, *cp)) - ++cp; - } else { - while (*cp && *cp == *sep) - ++cp; - } - return cp; -} - -/** Implementation of strtok_r for platforms whose coders haven't figured out - * how to write one. Hey, retrograde libc developers! You can use this code - * here for free! */ -char * -tor_strtok_r_impl(char *str, const char *sep, char **lasts) -{ - char *cp, *start; - tor_assert(*sep); - if (str) { - str = strtok_helper(str, sep); - if (!*str) - return NULL; - start = cp = *lasts = str; - } else if (!*lasts || !**lasts) { - return NULL; - } else { - start = cp = *lasts; - } - - if (sep[1]) { - while (*cp && !strchr(sep, *cp)) - ++cp; - } else { - cp = strchr(cp, *sep); - } - - if (!cp || !*cp) { - *lasts = NULL; - } else { - *cp++ = '\0'; - *lasts = strtok_helper(cp, sep); - } - return start; -} - -#ifdef _WIN32 -/** Take a filename and return a pointer to its final element. This - * function is called on __FILE__ to fix a MSVC nit where __FILE__ - * contains the full path to the file. This is bad, because it - * confuses users to find the home directory of the person who - * compiled the binary in their warning messages. - */ -const char * -tor_fix_source_file(const char *fname) -{ - const char *cp1, *cp2, *r; - cp1 = strrchr(fname, '/'); - cp2 = strrchr(fname, '\\'); - if (cp1 && cp2) { - r = (cp1<cp2)?(cp2+1):(cp1+1); - } else if (cp1) { - r = cp1+1; - } else if (cp2) { - r = cp2+1; - } else { - r = fname; - } - return r; -} -#endif /* defined(_WIN32) */ - -/** - * Read a 16-bit value beginning at <b>cp</b>. Equivalent to - * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid - * unaligned memory access. - */ -uint16_t -get_uint16(const void *cp) -{ - uint16_t v; - memcpy(&v,cp,2); - return v; -} -/** - * Read a 32-bit value beginning at <b>cp</b>. Equivalent to - * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid - * unaligned memory access. - */ -uint32_t -get_uint32(const void *cp) -{ - uint32_t v; - memcpy(&v,cp,4); - return v; -} -/** - * Read a 64-bit value beginning at <b>cp</b>. Equivalent to - * *(uint64_t*)(cp), but will not cause segfaults on platforms that forbid - * unaligned memory access. - */ -uint64_t -get_uint64(const void *cp) -{ - uint64_t v; - memcpy(&v,cp,8); - return v; -} - -/** - * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to - * *(uint16_t*)(cp) = v, but will not cause segfaults on platforms that forbid - * unaligned memory access. */ -void -set_uint16(void *cp, uint16_t v) -{ - memcpy(cp,&v,2); -} -/** - * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to - * *(uint32_t*)(cp) = v, but will not cause segfaults on platforms that forbid - * unaligned memory access. */ -void -set_uint32(void *cp, uint32_t v) -{ - memcpy(cp,&v,4); -} -/** - * Set a 64-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to - * *(uint64_t*)(cp) = v, but will not cause segfaults on platforms that forbid - * unaligned memory access. */ -void -set_uint64(void *cp, uint64_t v) -{ - memcpy(cp,&v,8); -} - -/** - * Rename the file <b>from</b> to the file <b>to</b>. On Unix, this is - * the same as rename(2). On windows, this removes <b>to</b> first if - * it already exists. - * Returns 0 on success. Returns -1 and sets errno on failure. - */ -int -replace_file(const char *from, const char *to) -{ -#ifndef _WIN32 - return tor_rename(from, to); -#else - switch (file_status(to)) - { - case FN_NOENT: - break; - case FN_FILE: - case FN_EMPTY: - if (unlink(to)) return -1; - break; - case FN_ERROR: - return -1; - case FN_DIR: - errno = EISDIR; - return -1; - } - return tor_rename(from,to); -#endif /* !defined(_WIN32) */ -} - -/** Change <b>fname</b>'s modification time to now. */ -int -touch_file(const char *fname) -{ - if (utime(fname, NULL)!=0) - return -1; - return 0; -} - -/** Represents a lockfile on which we hold the lock. */ -struct tor_lockfile_t { - /** Name of the file */ - char *filename; - /** File descriptor used to hold the file open */ - int fd; -}; - -/** Try to get a lock on the lockfile <b>filename</b>, creating it as - * necessary. If someone else has the lock and <b>blocking</b> is true, - * wait until the lock is available. Otherwise return immediately whether - * we succeeded or not. - * - * Set *<b>locked_out</b> to true if somebody else had the lock, and to false - * otherwise. - * - * Return a <b>tor_lockfile_t</b> on success, NULL on failure. - * - * (Implementation note: because we need to fall back to fcntl on some - * platforms, these locks are per-process, not per-thread. If you want - * to do in-process locking, use tor_mutex_t like a normal person. - * On Windows, when <b>blocking</b> is true, the maximum time that - * is actually waited is 10 seconds, after which NULL is returned - * and <b>locked_out</b> is set to 1.) - */ -tor_lockfile_t * -tor_lockfile_lock(const char *filename, int blocking, int *locked_out) -{ - tor_lockfile_t *result; - int fd; - *locked_out = 0; - - log_info(LD_FS, "Locking \"%s\"", filename); - fd = tor_open_cloexec(filename, O_RDWR|O_CREAT|O_TRUNC, 0600); - if (fd < 0) { - log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename, - strerror(errno)); - return NULL; - } - -#ifdef _WIN32 - _lseek(fd, 0, SEEK_SET); - if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) { - if (errno != EACCES && errno != EDEADLOCK) - log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); - else - *locked_out = 1; - close(fd); - return NULL; - } -#elif defined(HAVE_FLOCK) - if (flock(fd, LOCK_EX|(blocking ? 0 : LOCK_NB)) < 0) { - if (errno != EWOULDBLOCK) - log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); - else - *locked_out = 1; - close(fd); - return NULL; - } -#else - { - struct flock lock; - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - if (fcntl(fd, blocking ? F_SETLKW : F_SETLK, &lock) < 0) { - if (errno != EACCES && errno != EAGAIN) - log_warn(LD_FS, "Couldn't lock \"%s\": %s", filename, strerror(errno)); - else - *locked_out = 1; - close(fd); - return NULL; - } - } -#endif /* defined(_WIN32) || ... */ - - result = tor_malloc(sizeof(tor_lockfile_t)); - result->filename = tor_strdup(filename); - result->fd = fd; - return result; -} - -/** Release the lock held as <b>lockfile</b>. */ -void -tor_lockfile_unlock(tor_lockfile_t *lockfile) -{ - tor_assert(lockfile); - - log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename); -#ifdef _WIN32 - _lseek(lockfile->fd, 0, SEEK_SET); - if (_locking(lockfile->fd, _LK_UNLCK, 1) < 0) { - log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename, - strerror(errno)); - } -#elif defined(HAVE_FLOCK) - if (flock(lockfile->fd, LOCK_UN) < 0) { - log_warn(LD_FS, "Error unlocking \"%s\": %s", lockfile->filename, - strerror(errno)); - } -#else - /* Closing the lockfile is sufficient. */ -#endif /* defined(_WIN32) || ... */ - - close(lockfile->fd); - lockfile->fd = -1; - tor_free(lockfile->filename); - tor_free(lockfile); -} - -/** @{ */ -/** Some old versions of Unix didn't define constants for these values, - * and instead expect you to say 0, 1, or 2. */ -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif -#ifndef SEEK_END -#define SEEK_END 2 -#endif -/** @} */ - -/** Return the position of <b>fd</b> with respect to the start of the file. */ -off_t -tor_fd_getpos(int fd) -{ -#ifdef _WIN32 - return (off_t) _lseek(fd, 0, SEEK_CUR); -#else - return (off_t) lseek(fd, 0, SEEK_CUR); -#endif -} - -/** Move <b>fd</b> to the end of the file. Return -1 on error, 0 on success. - * If the file is a pipe, do nothing and succeed. - **/ -int -tor_fd_seekend(int fd) -{ -#ifdef _WIN32 - return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; -#else - off_t rc = lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; -#ifdef ESPIPE - /* If we get an error and ESPIPE, then it's a pipe or a socket of a fifo: - * no need to worry. */ - if (rc < 0 && errno == ESPIPE) - rc = 0; -#endif /* defined(ESPIPE) */ - return (rc < 0) ? -1 : 0; -#endif /* defined(_WIN32) */ -} - -/** Move <b>fd</b> to position <b>pos</b> in the file. Return -1 on error, 0 - * on success. */ -int -tor_fd_setpos(int fd, off_t pos) -{ -#ifdef _WIN32 - return _lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; -#else - return lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; -#endif -} - -/** Replacement for ftruncate(fd, 0): move to the front of the file and remove - * all the rest of the file. Return -1 on error, 0 on success. */ -int -tor_ftruncate(int fd) -{ - /* Rumor has it that some versions of ftruncate do not move the file pointer. - */ - if (tor_fd_setpos(fd, 0) < 0) - return -1; - -#ifdef _WIN32 - return _chsize(fd, 0); -#else - return ftruncate(fd, 0); -#endif -} - -#undef DEBUG_SOCKET_COUNTING -#ifdef DEBUG_SOCKET_COUNTING -/** A bitarray of all fds that should be passed to tor_socket_close(). Only - * used if DEBUG_SOCKET_COUNTING is defined. */ -static bitarray_t *open_sockets = NULL; -/** The size of <b>open_sockets</b>, in bits. */ -static int max_socket = -1; -#endif /* defined(DEBUG_SOCKET_COUNTING) */ - -/** Count of number of sockets currently open. (Undercounts sockets opened by - * eventdns and libevent.) */ -static int n_sockets_open = 0; - -/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */ -static tor_mutex_t *socket_accounting_mutex = NULL; - -/** Helper: acquire the socket accounting lock. */ -static inline void -socket_accounting_lock(void) -{ - if (PREDICT_UNLIKELY(!socket_accounting_mutex)) - socket_accounting_mutex = tor_mutex_new(); - tor_mutex_acquire(socket_accounting_mutex); -} - -/** Helper: release the socket accounting lock. */ -static inline void -socket_accounting_unlock(void) -{ - tor_mutex_release(socket_accounting_mutex); -} - -/** As close(), but guaranteed to work for sockets across platforms (including - * Windows, where close()ing a socket doesn't work. Returns 0 on success and - * the socket error code on failure. */ -int -tor_close_socket_simple(tor_socket_t s) -{ - int r = 0; - - /* On Windows, you have to call close() on fds returned by open(), - * and closesocket() on fds returned by socket(). On Unix, everything - * gets close()'d. We abstract this difference by always using - * tor_close_socket to close sockets, and always using close() on - * files. - */ - #if defined(_WIN32) - r = closesocket(s); - #else - r = close(s); - #endif - - if (r != 0) { - int err = tor_socket_errno(-1); - log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err)); - return err; - } - - return r; -} - -/** As tor_close_socket_simple(), but keeps track of the number - * of open sockets. Returns 0 on success, -1 on failure. */ -MOCK_IMPL(int, -tor_close_socket,(tor_socket_t s)) -{ - int r = tor_close_socket_simple(s); - - socket_accounting_lock(); -#ifdef DEBUG_SOCKET_COUNTING - if (s > max_socket || ! bitarray_is_set(open_sockets, s)) { - log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_" - "socket(), or that was already closed or something.", s); - } else { - tor_assert(open_sockets && s <= max_socket); - bitarray_clear(open_sockets, s); - } -#endif /* defined(DEBUG_SOCKET_COUNTING) */ - if (r == 0) { - --n_sockets_open; - } else { -#ifdef _WIN32 - if (r != WSAENOTSOCK) - --n_sockets_open; -#else - if (r != EBADF) - --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force. -#endif /* defined(_WIN32) */ - r = -1; - } - - tor_assert_nonfatal(n_sockets_open >= 0); - socket_accounting_unlock(); - return r; -} - -/** @{ */ -#ifdef DEBUG_SOCKET_COUNTING -/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is - * now an open socket. */ -static inline void -mark_socket_open(tor_socket_t s) -{ - /* XXXX This bitarray business will NOT work on windows: sockets aren't - small ints there. */ - if (s > max_socket) { - if (max_socket == -1) { - open_sockets = bitarray_init_zero(s+128); - max_socket = s+128; - } else { - open_sockets = bitarray_expand(open_sockets, max_socket, s+128); - max_socket = s+128; - } - } - if (bitarray_is_set(open_sockets, s)) { - log_warn(LD_BUG, "I thought that %d was already open, but socket() just " - "gave it to me!", s); - } - bitarray_set(open_sockets, s); -} -#else /* !(defined(DEBUG_SOCKET_COUNTING)) */ -#define mark_socket_open(s) ((void) (s)) -#endif /* defined(DEBUG_SOCKET_COUNTING) */ -/** @} */ - -/** As socket(), but counts the number of open sockets. */ -MOCK_IMPL(tor_socket_t, -tor_open_socket,(int domain, int type, int protocol)) -{ - return tor_open_socket_with_extensions(domain, type, protocol, 1, 0); -} - -/** Mockable wrapper for connect(). */ -MOCK_IMPL(tor_socket_t, -tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address, - socklen_t address_len)) -{ - return connect(sock,address,address_len); -} - -/** As socket(), but creates a nonblocking socket and - * counts the number of open sockets. */ -tor_socket_t -tor_open_socket_nonblocking(int domain, int type, int protocol) -{ - return tor_open_socket_with_extensions(domain, type, protocol, 1, 1); -} - -/** As socket(), but counts the number of open sockets and handles - * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. - * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate - * if the corresponding extension should be used.*/ -tor_socket_t -tor_open_socket_with_extensions(int domain, int type, int protocol, - int cloexec, int nonblock) -{ - tor_socket_t s; - - /* We are about to create a new file descriptor so make sure we have - * enough of them. */ - if (get_n_open_sockets() >= max_sockets - 1) { -#ifdef _WIN32 - WSASetLastError(WSAEMFILE); -#else - errno = EMFILE; -#endif - return TOR_INVALID_SOCKET; - } - -#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) - int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | - (nonblock ? SOCK_NONBLOCK : 0); - s = socket(domain, type|ext_flags, protocol); - if (SOCKET_OK(s)) - goto socket_ok; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK - * support, we are running on one without. */ - if (errno != EINVAL) - return s; -#endif /* defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) */ - - s = socket(domain, type, protocol); - if (! SOCKET_OK(s)) - return s; - -#if defined(FD_CLOEXEC) - if (cloexec) { - if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } -#else /* !(defined(FD_CLOEXEC)) */ - (void)cloexec; -#endif /* defined(FD_CLOEXEC) */ - - if (nonblock) { - if (set_socket_nonblocking(s) == -1) { - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } - - goto socket_ok; /* So that socket_ok will not be unused. */ - - socket_ok: - tor_take_socket_ownership(s); - return s; -} - -/** - * For socket accounting: remember that we are the owner of the socket - * <b>s</b>. This will prevent us from overallocating sockets, and prevent us - * from asserting later when we close the socket <b>s</b>. - */ -void -tor_take_socket_ownership(tor_socket_t s) -{ - socket_accounting_lock(); - ++n_sockets_open; - mark_socket_open(s); - socket_accounting_unlock(); -} - -/** As accept(), but counts the number of open sockets. */ -tor_socket_t -tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len) -{ - return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0); -} - -/** As accept(), but returns a nonblocking socket and - * counts the number of open sockets. */ -tor_socket_t -tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr, - socklen_t *len) -{ - return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1); -} - -/** As accept(), but counts the number of open sockets and handles - * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. - * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate - * if the corresponding extension should be used.*/ -tor_socket_t -tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr, - socklen_t *len, int cloexec, int nonblock) -{ - tor_socket_t s; - - /* We are about to create a new file descriptor so make sure we have - * enough of them. */ - if (get_n_open_sockets() >= max_sockets - 1) { -#ifdef _WIN32 - WSASetLastError(WSAEMFILE); -#else - errno = EMFILE; -#endif - return TOR_INVALID_SOCKET; - } - -#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) \ - && defined(SOCK_NONBLOCK) - int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | - (nonblock ? SOCK_NONBLOCK : 0); - s = accept4(sockfd, addr, len, ext_flags); - if (SOCKET_OK(s)) - goto socket_ok; - /* If we got an error, see if it is ENOSYS. ENOSYS indicates that, - * even though we were built on a system with accept4 support, we - * are running on one without. Also, check for EINVAL, which indicates that - * we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */ - if (errno != EINVAL && errno != ENOSYS) - return s; -#endif /* defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) ... */ - - s = accept(sockfd, addr, len); - if (!SOCKET_OK(s)) - return s; - -#if defined(FD_CLOEXEC) - if (cloexec) { - if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno)); - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } -#else /* !(defined(FD_CLOEXEC)) */ - (void)cloexec; -#endif /* defined(FD_CLOEXEC) */ - - if (nonblock) { - if (set_socket_nonblocking(s) == -1) { - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } - - goto socket_ok; /* So that socket_ok will not be unused. */ - - socket_ok: - tor_take_socket_ownership(s); - return s; -} - -/** Return the number of sockets we currently have opened. */ -int -get_n_open_sockets(void) -{ - int n; - socket_accounting_lock(); - n = n_sockets_open; - socket_accounting_unlock(); - return n; -} - -/** Mockable wrapper for getsockname(). */ -MOCK_IMPL(int, -tor_getsockname,(tor_socket_t sock, struct sockaddr *address, - socklen_t *address_len)) -{ - return getsockname(sock, address, address_len); -} - -/** - * Find the local address associated with the socket <b>sock</b>, and - * place it in *<b>addr_out</b>. Return 0 on success, -1 on failure. - * - * (As tor_getsockname, but instead places the result in a tor_addr_t.) */ -int -tor_addr_from_getsockname(tor_addr_t *addr_out, tor_socket_t sock) -{ - struct sockaddr_storage ss; - socklen_t ss_len = sizeof(ss); - memset(&ss, 0, sizeof(ss)); - - if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0) - return -1; - - return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL); -} - -/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1 - * on failure. - */ -int -set_socket_nonblocking(tor_socket_t sock) -{ -#if defined(_WIN32) - unsigned long nonblocking = 1; - ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking); -#else - int flags; - - flags = fcntl(sock, F_GETFL, 0); - if (flags == -1) { - log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno)); - return -1; - } - flags |= O_NONBLOCK; - if (fcntl(sock, F_SETFL, flags) == -1) { - log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno)); - return -1; - } -#endif /* defined(_WIN32) */ - - return 0; -} - -/** - * Allocate a pair of connected sockets. (Like socketpair(family, - * type,protocol,fd), but works on systems that don't have - * socketpair.) - * - * Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported. - * - * Note that on systems without socketpair, this call will fail if - * localhost is inaccessible (for example, if the networking - * stack is down). And even if it succeeds, the socket pair will not - * be able to read while localhost is down later (the socket pair may - * even close, depending on OS-specific timeouts). - * - * Returns 0 on success and -errno on failure; do not rely on the value - * of errno or WSAGetLastError(). - **/ -/* It would be nicer just to set errno, but that won't work for windows. */ -int -tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) -{ -//don't use win32 socketpairs (they are always bad) -#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32) - int r; - -#ifdef SOCK_CLOEXEC - r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd); - if (r == 0) - goto sockets_ok; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with SOCK_CLOEXEC support, we - * are running on one without. */ - if (errno != EINVAL) - return -errno; -#endif /* defined(SOCK_CLOEXEC) */ - - r = socketpair(family, type, protocol, fd); - if (r < 0) - return -errno; - -#if defined(FD_CLOEXEC) - if (SOCKET_OK(fd[0])) { - r = fcntl(fd[0], F_SETFD, FD_CLOEXEC); - if (r == -1) { - close(fd[0]); - close(fd[1]); - return -errno; - } - } - if (SOCKET_OK(fd[1])) { - r = fcntl(fd[1], F_SETFD, FD_CLOEXEC); - if (r == -1) { - close(fd[0]); - close(fd[1]); - return -errno; - } - } -#endif /* defined(FD_CLOEXEC) */ - goto sockets_ok; /* So that sockets_ok will not be unused. */ - - sockets_ok: - socket_accounting_lock(); - if (SOCKET_OK(fd[0])) { - ++n_sockets_open; - mark_socket_open(fd[0]); - } - if (SOCKET_OK(fd[1])) { - ++n_sockets_open; - mark_socket_open(fd[1]); - } - socket_accounting_unlock(); - - return 0; -#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */ - return tor_ersatz_socketpair(family, type, protocol, fd); -#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */ -} - -#ifdef NEED_ERSATZ_SOCKETPAIR - -static inline socklen_t -SIZEOF_SOCKADDR(int domain) -{ - switch (domain) { - case AF_INET: - return sizeof(struct sockaddr_in); - case AF_INET6: - return sizeof(struct sockaddr_in6); - default: - return 0; - } -} - -/** - * Helper used to implement socketpair on systems that lack it, by - * making a direct connection to localhost. - */ -STATIC int -tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) -{ - /* This socketpair does not work when localhost is down. So - * it's really not the same thing at all. But it's close enough - * for now, and really, when localhost is down sometimes, we - * have other problems too. - */ - tor_socket_t listener = TOR_INVALID_SOCKET; - tor_socket_t connector = TOR_INVALID_SOCKET; - tor_socket_t acceptor = TOR_INVALID_SOCKET; - tor_addr_t listen_tor_addr; - struct sockaddr_storage connect_addr_ss, listen_addr_ss; - struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss; - uint16_t listen_port = 0; - tor_addr_t connect_tor_addr; - uint16_t connect_port = 0; - struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss; - socklen_t size; - int saved_errno = -1; - int ersatz_domain = AF_INET; - - memset(&connect_tor_addr, 0, sizeof(connect_tor_addr)); - memset(&connect_addr_ss, 0, sizeof(connect_addr_ss)); - memset(&listen_tor_addr, 0, sizeof(listen_tor_addr)); - memset(&listen_addr_ss, 0, sizeof(listen_addr_ss)); - - if (protocol -#ifdef AF_UNIX - || family != AF_UNIX -#endif - ) { -#ifdef _WIN32 - return -WSAEAFNOSUPPORT; -#else - return -EAFNOSUPPORT; -#endif - } - if (!fd) { - return -EINVAL; - } - - listener = tor_open_socket(ersatz_domain, type, 0); - if (!SOCKET_OK(listener)) { - int first_errno = tor_socket_errno(-1); - if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT) - && ersatz_domain == AF_INET) { - /* Assume we're on an IPv6-only system */ - ersatz_domain = AF_INET6; - listener = tor_open_socket(ersatz_domain, type, 0); - if (!SOCKET_OK(listener)) { - /* Keep the previous behaviour, which was to return the IPv4 error. - * (This may be less informative on IPv6-only systems.) - * XX/teor - is there a better way to decide which errno to return? - * (I doubt we care much either way, once there is an error.) - */ - return -first_errno; - } - } - } - /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we - * risk exposing a socketpair on a routable IP address. (Some BSD jails - * use a routable address for localhost. Fortunately, they have the real - * AF_UNIX socketpair.) */ - if (ersatz_domain == AF_INET) { - tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK); - } else { - tor_addr_parse(&listen_tor_addr, "[::1]"); - } - tor_assert(tor_addr_is_loopback(&listen_tor_addr)); - size = tor_addr_to_sockaddr(&listen_tor_addr, - 0 /* kernel chooses port. */, - listen_addr, - sizeof(listen_addr_ss)); - if (bind(listener, listen_addr, size) == -1) - goto tidy_up_and_fail; - if (listen(listener, 1) == -1) - goto tidy_up_and_fail; - - connector = tor_open_socket(ersatz_domain, type, 0); - if (!SOCKET_OK(connector)) - goto tidy_up_and_fail; - /* We want to find out the port number to connect to. */ - size = sizeof(connect_addr_ss); - if (getsockname(listener, connect_addr, &size) == -1) - goto tidy_up_and_fail; - if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)) - goto abort_tidy_up_and_fail; - if (connect(connector, connect_addr, size) == -1) - goto tidy_up_and_fail; - - size = sizeof(listen_addr_ss); - acceptor = tor_accept_socket(listener, listen_addr, &size); - if (!SOCKET_OK(acceptor)) - goto tidy_up_and_fail; - if (size != SIZEOF_SOCKADDR(listen_addr->sa_family)) - goto abort_tidy_up_and_fail; - /* Now check we are talking to ourself by matching port and host on the - two sockets. */ - if (getsockname(connector, connect_addr, &size) == -1) - goto tidy_up_and_fail; - /* Set *_tor_addr and *_port to the address and port that was used */ - tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port); - tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port); - if (size != SIZEOF_SOCKADDR (connect_addr->sa_family) - || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC) - || listen_port != connect_port) { - goto abort_tidy_up_and_fail; - } - tor_close_socket(listener); - fd[0] = connector; - fd[1] = acceptor; - - return 0; - - abort_tidy_up_and_fail: -#ifdef _WIN32 - saved_errno = WSAECONNABORTED; -#else - saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */ -#endif - tidy_up_and_fail: - if (saved_errno < 0) - saved_errno = errno; - if (SOCKET_OK(listener)) - tor_close_socket(listener); - if (SOCKET_OK(connector)) - tor_close_socket(connector); - if (SOCKET_OK(acceptor)) - tor_close_socket(acceptor); - return -saved_errno; -} - -#undef SIZEOF_SOCKADDR - -#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */ - -/* Return the maximum number of allowed sockets. */ -int -get_max_sockets(void) -{ - return max_sockets; -} - -/** Number of extra file descriptors to keep in reserve beyond those that we - * tell Tor it's allowed to use. */ -#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */ - -/** Learn the maximum allowed number of file descriptors, and tell the - * system we want to use up to that number. (Some systems have a low soft - * limit, and let us set it higher.) We compute this by finding the largest - * number that we can use. - * - * If the limit is below the reserved file descriptor value (ULIMIT_BUFFER), - * return -1 and <b>max_out</b> is untouched. - * - * If we can't find a number greater than or equal to <b>limit</b>, then we - * fail by returning -1 and <b>max_out</b> is untouched. - * - * If we are unable to set the limit value because of setrlimit() failing, - * return 0 and <b>max_out</b> is set to the current maximum value returned - * by getrlimit(). - * - * Otherwise, return 0 and store the maximum we found inside <b>max_out</b> - * and set <b>max_sockets</b> with that value as well.*/ -int -set_max_file_descriptors(rlim_t limit, int *max_out) -{ - if (limit < ULIMIT_BUFFER) { - log_warn(LD_CONFIG, - "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER); - return -1; - } - - /* Define some maximum connections values for systems where we cannot - * automatically determine a limit. Re Cygwin, see - * http://archives.seul.org/or/talk/Aug-2006/msg00210.html - * For an iPhone, 9999 should work. For Windows and all other unknown - * systems we use 15000 as the default. */ -#ifndef HAVE_GETRLIMIT -#if defined(CYGWIN) || defined(__CYGWIN__) - const char *platform = "Cygwin"; - const unsigned long MAX_CONNECTIONS = 3200; -#elif defined(_WIN32) - const char *platform = "Windows"; - const unsigned long MAX_CONNECTIONS = 15000; -#else - const char *platform = "unknown platforms with no getrlimit()"; - const unsigned long MAX_CONNECTIONS = 15000; -#endif /* defined(CYGWIN) || defined(__CYGWIN__) || ... */ - log_fn(LOG_INFO, LD_NET, - "This platform is missing getrlimit(). Proceeding."); - if (limit > MAX_CONNECTIONS) { - log_warn(LD_CONFIG, - "We do not support more than %lu file descriptors " - "on %s. Tried to raise to %lu.", - (unsigned long)MAX_CONNECTIONS, platform, (unsigned long)limit); - return -1; - } - limit = MAX_CONNECTIONS; -#else /* !(!defined(HAVE_GETRLIMIT)) */ - struct rlimit rlim; - - if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { - log_warn(LD_NET, "Could not get maximum number of file descriptors: %s", - strerror(errno)); - return -1; - } - if (rlim.rlim_max < limit) { - log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're " - "limited to %lu. Please change your ulimit -n.", - (unsigned long)limit, (unsigned long)rlim.rlim_max); - return -1; - } - - if (rlim.rlim_max > rlim.rlim_cur) { - log_info(LD_NET,"Raising max file descriptors from %lu to %lu.", - (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max); - } - /* Set the current limit value so if the attempt to set the limit to the - * max fails at least we'll have a valid value of maximum sockets. */ - *max_out = max_sockets = (int)rlim.rlim_cur - ULIMIT_BUFFER; - rlim.rlim_cur = rlim.rlim_max; - - if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { - int couldnt_set = 1; - const int setrlimit_errno = errno; -#ifdef OPEN_MAX - uint64_t try_limit = OPEN_MAX - ULIMIT_BUFFER; - if (errno == EINVAL && try_limit < (uint64_t) rlim.rlim_cur) { - /* On some platforms, OPEN_MAX is the real limit, and getrlimit() is - * full of nasty lies. I'm looking at you, OSX 10.5.... */ - rlim.rlim_cur = MIN((rlim_t) try_limit, rlim.rlim_cur); - if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) { - if (rlim.rlim_cur < (rlim_t)limit) { - log_warn(LD_CONFIG, "We are limited to %lu file descriptors by " - "OPEN_MAX (%lu), and ConnLimit is %lu. Changing " - "ConnLimit; sorry.", - (unsigned long)try_limit, (unsigned long)OPEN_MAX, - (unsigned long)limit); - } else { - log_info(LD_CONFIG, "Dropped connection limit to %lu based on " - "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit " - "lied to us.", - (unsigned long)try_limit, (unsigned long)OPEN_MAX, - (unsigned long)rlim.rlim_max); - } - couldnt_set = 0; - } - } -#endif /* defined(OPEN_MAX) */ - if (couldnt_set) { - log_warn(LD_CONFIG,"Couldn't set maximum number of file descriptors: %s", - strerror(setrlimit_errno)); - } - } - /* leave some overhead for logs, etc, */ - limit = rlim.rlim_cur; -#endif /* !defined(HAVE_GETRLIMIT) */ - - if (limit > INT_MAX) - limit = INT_MAX; - tor_assert(max_out); - *max_out = max_sockets = (int)limit - ULIMIT_BUFFER; - return 0; -} - -#ifndef _WIN32 -/** Log details of current user and group credentials. Return 0 on - * success. Logs and return -1 on failure. - */ -static int -log_credential_status(void) -{ -/** Log level to use when describing non-error UID/GID status. */ -#define CREDENTIAL_LOG_LEVEL LOG_INFO - /* Real, effective and saved UIDs */ - uid_t ruid, euid, suid; - /* Read, effective and saved GIDs */ - gid_t rgid, egid, sgid; - /* Supplementary groups */ - gid_t *sup_gids = NULL; - int sup_gids_size; - /* Number of supplementary groups */ - int ngids; - - /* log UIDs */ -#ifdef HAVE_GETRESUID - if (getresuid(&ruid, &euid, &suid) != 0 ) { - log_warn(LD_GENERAL, "Error getting changed UIDs: %s", strerror(errno)); - return -1; - } else { - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "UID is %u (real), %u (effective), %u (saved)", - (unsigned)ruid, (unsigned)euid, (unsigned)suid); - } -#else /* !(defined(HAVE_GETRESUID)) */ - /* getresuid is not present on MacOS X, so we can't get the saved (E)UID */ - ruid = getuid(); - euid = geteuid(); - (void)suid; - - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "UID is %u (real), %u (effective), unknown (saved)", - (unsigned)ruid, (unsigned)euid); -#endif /* defined(HAVE_GETRESUID) */ - - /* log GIDs */ -#ifdef HAVE_GETRESGID - if (getresgid(&rgid, &egid, &sgid) != 0 ) { - log_warn(LD_GENERAL, "Error getting changed GIDs: %s", strerror(errno)); - return -1; - } else { - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "GID is %u (real), %u (effective), %u (saved)", - (unsigned)rgid, (unsigned)egid, (unsigned)sgid); - } -#else /* !(defined(HAVE_GETRESGID)) */ - /* getresgid is not present on MacOS X, so we can't get the saved (E)GID */ - rgid = getgid(); - egid = getegid(); - (void)sgid; - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "GID is %u (real), %u (effective), unknown (saved)", - (unsigned)rgid, (unsigned)egid); -#endif /* defined(HAVE_GETRESGID) */ - - /* log supplementary groups */ - sup_gids_size = 64; - sup_gids = tor_calloc(64, sizeof(gid_t)); - while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 && - errno == EINVAL && - sup_gids_size < NGROUPS_MAX) { - sup_gids_size *= 2; - sup_gids = tor_reallocarray(sup_gids, sizeof(gid_t), sup_gids_size); - } - - if (ngids < 0) { - log_warn(LD_GENERAL, "Error getting supplementary GIDs: %s", - strerror(errno)); - tor_free(sup_gids); - return -1; - } else { - int i, retval = 0; - char *s = NULL; - smartlist_t *elts = smartlist_new(); - - for (i = 0; i<ngids; i++) { - smartlist_add_asprintf(elts, "%u", (unsigned)sup_gids[i]); - } - - s = smartlist_join_strings(elts, " ", 0, NULL); - - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Supplementary groups are: %s",s); - - tor_free(s); - SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); - smartlist_free(elts); - tor_free(sup_gids); - - return retval; - } - - return 0; -} -#endif /* !defined(_WIN32) */ - -#ifndef _WIN32 -/** Cached struct from the last getpwname() call we did successfully. */ -static struct passwd *passwd_cached = NULL; - -/** Helper: copy a struct passwd object. - * - * We only copy the fields pw_uid, pw_gid, pw_name, pw_dir. Tor doesn't use - * any others, and I don't want to run into incompatibilities. - */ -static struct passwd * -tor_passwd_dup(const struct passwd *pw) -{ - struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd)); - if (pw->pw_name) - new_pw->pw_name = tor_strdup(pw->pw_name); - if (pw->pw_dir) - new_pw->pw_dir = tor_strdup(pw->pw_dir); - new_pw->pw_uid = pw->pw_uid; - new_pw->pw_gid = pw->pw_gid; - - return new_pw; -} - -#define tor_passwd_free(pw) \ - FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw)) - -/** Helper: free one of our cached 'struct passwd' values. */ -static void -tor_passwd_free_(struct passwd *pw) -{ - if (!pw) - return; - - tor_free(pw->pw_name); - tor_free(pw->pw_dir); - tor_free(pw); -} - -/** Wrapper around getpwnam() that caches result. Used so that we don't need - * to give the sandbox access to /etc/passwd. - * - * The following fields alone will definitely be copied in the output: pw_uid, - * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. - * - * When called with a NULL argument, this function clears storage associated - * with static variables it uses. - **/ -const struct passwd * -tor_getpwnam(const char *username) -{ - struct passwd *pw; - - if (username == NULL) { - tor_passwd_free(passwd_cached); - passwd_cached = NULL; - return NULL; - } - - if ((pw = getpwnam(username))) { - tor_passwd_free(passwd_cached); - passwd_cached = tor_passwd_dup(pw); - log_info(LD_GENERAL, "Caching new entry %s for %s", - passwd_cached->pw_name, username); - return pw; - } - - /* Lookup failed */ - if (! passwd_cached || ! passwd_cached->pw_name) - return NULL; - - if (! strcmp(username, passwd_cached->pw_name)) - return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky - - return NULL; -} - -/** Wrapper around getpwnam() that can use cached result from - * tor_getpwnam(). Used so that we don't need to give the sandbox access to - * /etc/passwd. - * - * The following fields alone will definitely be copied in the output: pw_uid, - * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. - */ -const struct passwd * -tor_getpwuid(uid_t uid) -{ - struct passwd *pw; - - if ((pw = getpwuid(uid))) { - return pw; - } - - /* Lookup failed */ - if (! passwd_cached) - return NULL; - - if (uid == passwd_cached->pw_uid) - return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky - - return NULL; -} -#endif /* !defined(_WIN32) */ - -/** Return true iff we were compiled with capability support, and capabilities - * seem to work. **/ -int -have_capability_support(void) -{ -#ifdef HAVE_LINUX_CAPABILITIES - cap_t caps = cap_get_proc(); - if (caps == NULL) - return 0; - cap_free(caps); - return 1; -#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ - return 0; -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ -} - -#ifdef HAVE_LINUX_CAPABILITIES -/** Helper. Drop all capabilities but a small set, and set PR_KEEPCAPS as - * appropriate. - * - * If pre_setuid, retain only CAP_NET_BIND_SERVICE, CAP_SETUID, and - * CAP_SETGID, and use PR_KEEPCAPS to ensure that capabilities persist across - * setuid(). - * - * If not pre_setuid, retain only CAP_NET_BIND_SERVICE, and disable - * PR_KEEPCAPS. - * - * Return 0 on success, and -1 on failure. - */ -static int -drop_capabilities(int pre_setuid) -{ - /* We keep these three capabilities, and these only, as we setuid. - * After we setuid, we drop all but the first. */ - const cap_value_t caplist[] = { - CAP_NET_BIND_SERVICE, CAP_SETUID, CAP_SETGID - }; - const char *where = pre_setuid ? "pre-setuid" : "post-setuid"; - const int n_effective = pre_setuid ? 3 : 1; - const int n_permitted = pre_setuid ? 3 : 1; - const int n_inheritable = 1; - const int keepcaps = pre_setuid ? 1 : 0; - - /* Sets whether we keep capabilities across a setuid. */ - if (prctl(PR_SET_KEEPCAPS, keepcaps) < 0) { - log_warn(LD_CONFIG, "Unable to call prctl() %s: %s", - where, strerror(errno)); - return -1; - } - - cap_t caps = cap_get_proc(); - if (!caps) { - log_warn(LD_CONFIG, "Unable to call cap_get_proc() %s: %s", - where, strerror(errno)); - return -1; - } - cap_clear(caps); - - cap_set_flag(caps, CAP_EFFECTIVE, n_effective, caplist, CAP_SET); - cap_set_flag(caps, CAP_PERMITTED, n_permitted, caplist, CAP_SET); - cap_set_flag(caps, CAP_INHERITABLE, n_inheritable, caplist, CAP_SET); - - int r = cap_set_proc(caps); - cap_free(caps); - if (r < 0) { - log_warn(LD_CONFIG, "No permission to set capabilities %s: %s", - where, strerror(errno)); - return -1; - } - - return 0; -} -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ - -/** Call setuid and setgid to run as <b>user</b> and switch to their - * primary group. Return 0 on success. On failure, log and return -1. - * - * If SWITCH_ID_KEEP_BINDLOW is set in 'flags', try to use the capability - * system to retain the abilitity to bind low ports. - * - * If SWITCH_ID_WARN_IF_NO_CAPS is set in flags, also warn if we have - * don't have capability support. - */ -int -switch_id(const char *user, const unsigned flags) -{ -#ifndef _WIN32 - const struct passwd *pw = NULL; - uid_t old_uid; - gid_t old_gid; - static int have_already_switched_id = 0; - const int keep_bindlow = !!(flags & SWITCH_ID_KEEP_BINDLOW); - const int warn_if_no_caps = !!(flags & SWITCH_ID_WARN_IF_NO_CAPS); - - tor_assert(user); - - if (have_already_switched_id) - return 0; - - /* Log the initial credential state */ - if (log_credential_status()) - return -1; - - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Changing user and groups"); - - /* Get old UID/GID to check if we changed correctly */ - old_uid = getuid(); - old_gid = getgid(); - - /* Lookup the user and group information, if we have a problem, bail out. */ - pw = tor_getpwnam(user); - if (pw == NULL) { - log_warn(LD_CONFIG, "Error setting configured user: %s not found", user); - return -1; - } - -#ifdef HAVE_LINUX_CAPABILITIES - (void) warn_if_no_caps; - if (keep_bindlow) { - if (drop_capabilities(1)) - return -1; - } -#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ - (void) keep_bindlow; - if (warn_if_no_caps) { - log_warn(LD_CONFIG, "KeepBindCapabilities set, but no capability support " - "on this system."); - } -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ - - /* Properly switch egid,gid,euid,uid here or bail out */ - if (setgroups(1, &pw->pw_gid)) { - log_warn(LD_GENERAL, "Error setting groups to gid %d: \"%s\".", - (int)pw->pw_gid, strerror(errno)); - if (old_uid == pw->pw_uid) { - log_warn(LD_GENERAL, "Tor is already running as %s. You do not need " - "the \"User\" option if you are already running as the user " - "you want to be. (If you did not set the User option in your " - "torrc, check whether it was specified on the command line " - "by a startup script.)", user); - } else { - log_warn(LD_GENERAL, "If you set the \"User\" option, you must start Tor" - " as root."); - } - return -1; - } - - if (setegid(pw->pw_gid)) { - log_warn(LD_GENERAL, "Error setting egid to %d: %s", - (int)pw->pw_gid, strerror(errno)); - return -1; - } - - if (setgid(pw->pw_gid)) { - log_warn(LD_GENERAL, "Error setting gid to %d: %s", - (int)pw->pw_gid, strerror(errno)); - return -1; - } - - if (setuid(pw->pw_uid)) { - log_warn(LD_GENERAL, "Error setting configured uid to %s (%d): %s", - user, (int)pw->pw_uid, strerror(errno)); - return -1; - } - - if (seteuid(pw->pw_uid)) { - log_warn(LD_GENERAL, "Error setting configured euid to %s (%d): %s", - user, (int)pw->pw_uid, strerror(errno)); - return -1; - } - - /* This is how OpenBSD rolls: - if (setgroups(1, &pw->pw_gid) || setegid(pw->pw_gid) || - setgid(pw->pw_gid) || setuid(pw->pw_uid) || seteuid(pw->pw_uid)) { - setgid(pw->pw_gid) || seteuid(pw->pw_uid) || setuid(pw->pw_uid)) { - log_warn(LD_GENERAL, "Error setting configured UID/GID: %s", - strerror(errno)); - return -1; - } - */ - - /* We've properly switched egid, gid, euid, uid, and supplementary groups if - * we're here. */ -#ifdef HAVE_LINUX_CAPABILITIES - if (keep_bindlow) { - if (drop_capabilities(0)) - return -1; - } -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ - -#if !defined(CYGWIN) && !defined(__CYGWIN__) - /* If we tried to drop privilege to a group/user other than root, attempt to - * restore root (E)(U|G)ID, and abort if the operation succeeds */ - - /* Only check for privilege dropping if we were asked to be non-root */ - if (pw->pw_uid) { - /* Try changing GID/EGID */ - if (pw->pw_gid != old_gid && - (setgid(old_gid) != -1 || setegid(old_gid) != -1)) { - log_warn(LD_GENERAL, "Was able to restore group credentials even after " - "switching GID: this means that the setgid code didn't work."); - return -1; - } - - /* Try changing UID/EUID */ - if (pw->pw_uid != old_uid && - (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) { - log_warn(LD_GENERAL, "Was able to restore user credentials even after " - "switching UID: this means that the setuid code didn't work."); - return -1; - } - } -#endif /* !defined(CYGWIN) && !defined(__CYGWIN__) */ - - /* Check what really happened */ - if (log_credential_status()) { - return -1; - } - - have_already_switched_id = 1; /* mark success so we never try again */ - -#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && \ - defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) - if (pw->pw_uid) { - /* Re-enable core dumps if we're not running as root. */ - log_info(LD_CONFIG, "Re-enabling coredumps"); - if (prctl(PR_SET_DUMPABLE, 1)) { - log_warn(LD_CONFIG, "Unable to re-enable coredumps: %s",strerror(errno)); - } - } -#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && ... */ - return 0; - -#else /* !(!defined(_WIN32)) */ - (void)user; - (void)flags; - - log_warn(LD_CONFIG, "Switching users is unsupported on your OS."); - return -1; -#endif /* !defined(_WIN32) */ -} - -/* We only use the linux prctl for now. There is no Win32 support; this may - * also work on various BSD systems and Mac OS X - send testing feedback! - * - * On recent Gnu/Linux kernels it is possible to create a system-wide policy - * that will prevent non-root processes from attaching to other processes - * unless they are the parent process; thus gdb can attach to programs that - * they execute but they cannot attach to other processes running as the same - * user. The system wide policy may be set with the sysctl - * kernel.yama.ptrace_scope or by inspecting - * /proc/sys/kernel/yama/ptrace_scope and it is 1 by default on Ubuntu 11.04. - * - * This ptrace scope will be ignored on Gnu/Linux for users with - * CAP_SYS_PTRACE and so it is very likely that root will still be able to - * attach to the Tor process. - */ -/** Attempt to disable debugger attachment: return 1 on success, -1 on - * failure, and 0 if we don't know how to try on this platform. */ -int -tor_disable_debugger_attach(void) -{ - int r = -1; - log_debug(LD_CONFIG, - "Attemping to disable debugger attachment to Tor for " - "unprivileged users."); -#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) \ - && defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) -#define TRIED_TO_DISABLE - r = prctl(PR_SET_DUMPABLE, 0); -#elif defined(__APPLE__) && defined(PT_DENY_ATTACH) -#define TRIED_TO_ATTACH - r = ptrace(PT_DENY_ATTACH, 0, 0, 0); -#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) ... || ... */ - - // XXX: TODO - Mac OS X has dtrace and this may be disabled. - // XXX: TODO - Windows probably has something similar -#ifdef TRIED_TO_DISABLE - if (r == 0) { - log_debug(LD_CONFIG,"Debugger attachment disabled for " - "unprivileged users."); - return 1; - } else { - log_warn(LD_CONFIG, "Unable to disable debugger attaching: %s", - strerror(errno)); - } -#endif /* defined(TRIED_TO_DISABLE) */ -#undef TRIED_TO_DISABLE - return r; -} - -#ifdef HAVE_PWD_H -/** Allocate and return a string containing the home directory for the - * user <b>username</b>. Only works on posix-like systems. */ -char * -get_user_homedir(const char *username) -{ - const struct passwd *pw; - tor_assert(username); - - if (!(pw = tor_getpwnam(username))) { - log_err(LD_CONFIG,"User \"%s\" not found.", username); - return NULL; - } - return tor_strdup(pw->pw_dir); -} -#endif /* defined(HAVE_PWD_H) */ - -/** Modify <b>fname</b> to contain the name of its parent directory. Doesn't - * actually examine the filesystem; does a purely syntactic modification. - * - * The parent of the root director is considered to be iteself. - * - * Path separators are the forward slash (/) everywhere and additionally - * the backslash (\) on Win32. - * - * Cuts off any number of trailing path separators but otherwise ignores - * them for purposes of finding the parent directory. - * - * Returns 0 if a parent directory was successfully found, -1 otherwise (fname - * did not have any path separators or only had them at the end). - * */ -int -get_parent_directory(char *fname) -{ - char *cp; - int at_end = 1; - tor_assert(fname); -#ifdef _WIN32 - /* If we start with, say, c:, then don't consider that the start of the path - */ - if (fname[0] && fname[1] == ':') { - fname += 2; - } -#endif /* defined(_WIN32) */ - /* Now we want to remove all path-separators at the end of the string, - * and to remove the end of the string starting with the path separator - * before the last non-path-separator. In perl, this would be - * s#[/]*$##; s#/[^/]*$##; - * on a unixy platform. - */ - cp = fname + strlen(fname); - at_end = 1; - while (--cp >= fname) { - int is_sep = (*cp == '/' -#ifdef _WIN32 - || *cp == '\\' -#endif - ); - if (is_sep) { - if (cp == fname) { - /* This is the first separator in the file name; don't remove it! */ - cp[1] = '\0'; - return 0; - } - *cp = '\0'; - if (! at_end) - return 0; - } else { - at_end = 0; - } - } - return -1; -} - -#ifndef _WIN32 -/** Return a newly allocated string containing the output of getcwd(). Return - * NULL on failure. (We can't just use getcwd() into a PATH_MAX buffer, since - * Hurd hasn't got a PATH_MAX.) - */ -static char * -alloc_getcwd(void) -{ -#ifdef HAVE_GET_CURRENT_DIR_NAME - /* Glibc makes this nice and simple for us. */ - char *cwd = get_current_dir_name(); - char *result = NULL; - if (cwd) { - /* We make a copy here, in case tor_malloc() is not malloc(). */ - result = tor_strdup(cwd); - raw_free(cwd); // alias for free to avoid tripping check-spaces. - } - return result; -#else /* !(defined(HAVE_GET_CURRENT_DIR_NAME)) */ - size_t size = 1024; - char *buf = NULL; - char *ptr = NULL; - - while (ptr == NULL) { - buf = tor_realloc(buf, size); - ptr = getcwd(buf, size); - - if (ptr == NULL && errno != ERANGE) { - tor_free(buf); - return NULL; - } - - size *= 2; - } - return buf; -#endif /* defined(HAVE_GET_CURRENT_DIR_NAME) */ -} -#endif /* !defined(_WIN32) */ - -/** Expand possibly relative path <b>fname</b> to an absolute path. - * Return a newly allocated string, possibly equal to <b>fname</b>. */ -char * -make_path_absolute(char *fname) -{ -#ifdef _WIN32 - char *absfname_malloced = _fullpath(NULL, fname, 1); - - /* We don't want to assume that tor_free can free a string allocated - * with malloc. On failure, return fname (it's better than nothing). */ - char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname); - if (absfname_malloced) raw_free(absfname_malloced); - - return absfname; -#else /* !(defined(_WIN32)) */ - char *absfname = NULL, *path = NULL; - - tor_assert(fname); - - if (fname[0] == '/') { - absfname = tor_strdup(fname); - } else { - path = alloc_getcwd(); - if (path) { - tor_asprintf(&absfname, "%s/%s", path, fname); - tor_free(path); - } else { - /* LCOV_EXCL_START Can't make getcwd fail. */ - /* If getcwd failed, the best we can do here is keep using the - * relative path. (Perhaps / isn't readable by this UID/GID.) */ - log_warn(LD_GENERAL, "Unable to find current working directory: %s", - strerror(errno)); - absfname = tor_strdup(fname); - /* LCOV_EXCL_STOP */ - } - } - return absfname; -#endif /* defined(_WIN32) */ -} - -#ifndef HAVE__NSGETENVIRON -#ifndef HAVE_EXTERN_ENVIRON_DECLARED -/* Some platforms declare environ under some circumstances, others don't. */ -#ifndef RUNNING_DOXYGEN -extern char **environ; -#endif -#endif /* !defined(HAVE_EXTERN_ENVIRON_DECLARED) */ -#endif /* !defined(HAVE__NSGETENVIRON) */ - -/** Return the current environment. This is a portable replacement for - * 'environ'. */ -char ** -get_environment(void) -{ -#ifdef HAVE__NSGETENVIRON - /* This is for compatibility between OSX versions. Otherwise (for example) - * when we do a mostly-static build on OSX 10.7, the resulting binary won't - * work on OSX 10.6. */ - return *_NSGetEnviron(); -#else /* !(defined(HAVE__NSGETENVIRON)) */ - return environ; -#endif /* defined(HAVE__NSGETENVIRON) */ -} - -/** Get name of current host and write it to <b>name</b> array, whose - * length is specified by <b>namelen</b> argument. Return 0 upon - * successful completion; otherwise return return -1. (Currently, - * this function is merely a mockable wrapper for POSIX gethostname().) - */ -MOCK_IMPL(int, -tor_gethostname,(char *name, size_t namelen)) -{ - return gethostname(name,namelen); -} - -/** Set *addr to the IP address (in dotted-quad notation) stored in *str. - * Return 1 on success, 0 if *str is badly formatted. - * (Like inet_aton(str,addr), but works on Windows and Solaris.) - */ -int -tor_inet_aton(const char *str, struct in_addr* addr) -{ - unsigned a,b,c,d; - char more; - if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4) - return 0; - if (a > 255) return 0; - if (b > 255) return 0; - if (c > 255) return 0; - if (d > 255) return 0; - addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); - return 1; -} - -/** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or - * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the - * address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns - * <b>dst</b> on success, NULL on failure. - * - * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it: - * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6 - * support.) */ -const char * -tor_inet_ntop(int af, const void *src, char *dst, size_t len) -{ - if (af == AF_INET) { - if (tor_inet_ntoa(src, dst, len) < 0) - return NULL; - else - return dst; - } else if (af == AF_INET6) { - const struct in6_addr *addr = src; - char buf[64], *cp; - int longestGapLen = 0, longestGapPos = -1, i, - curGapPos = -1, curGapLen = 0; - uint16_t words[8]; - for (i = 0; i < 8; ++i) { - words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1]; - } - if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && - words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) || - (words[5] == 0xffff))) { - /* This is an IPv4 address. */ - if (words[5] == 0) { - tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d", - addr->s6_addr[12], addr->s6_addr[13], - addr->s6_addr[14], addr->s6_addr[15]); - } else { - tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5], - addr->s6_addr[12], addr->s6_addr[13], - addr->s6_addr[14], addr->s6_addr[15]); - } - if ((strlen(buf) + 1) > len) /* +1 for \0 */ - return NULL; - strlcpy(dst, buf, len); - return dst; - } - i = 0; - while (i < 8) { - if (words[i] == 0) { - curGapPos = i++; - curGapLen = 1; - while (i<8 && words[i] == 0) { - ++i; ++curGapLen; - } - if (curGapLen > longestGapLen) { - longestGapPos = curGapPos; - longestGapLen = curGapLen; - } - } else { - ++i; - } - } - if (longestGapLen<=1) - longestGapPos = -1; - - cp = buf; - for (i = 0; i < 8; ++i) { - if (words[i] == 0 && longestGapPos == i) { - if (i == 0) - *cp++ = ':'; - *cp++ = ':'; - while (i < 8 && words[i] == 0) - ++i; - --i; /* to compensate for loop increment. */ - } else { - tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]); - cp += strlen(cp); - if (i != 7) - *cp++ = ':'; - } - } - *cp = '\0'; - if ((strlen(buf) + 1) > len) /* +1 for \0 */ - return NULL; - strlcpy(dst, buf, len); - return dst; - } else { - return NULL; - } -} - -/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b> - * encoding an IPv4 address or IPv6 address correspondingly, try to parse the - * address and store the result in <b>dst</b> (which must have space for a - * struct in_addr or a struct in6_addr, as appropriate). Return 1 on success, - * 0 on a bad parse, and -1 on a bad <b>af</b>. - * - * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor - * sometimes needs to format ipv6 addresses even on platforms without ipv6 - * support.) */ -int -tor_inet_pton(int af, const char *src, void *dst) -{ - if (af == AF_INET) { - return tor_inet_aton(src, dst); - } else if (af == AF_INET6) { - struct in6_addr *out = dst; - uint16_t words[8]; - int gapPos = -1, i, setWords=0; - const char *dot = strchr(src, '.'); - const char *eow; /* end of words. */ - memset(words, 0xf8, sizeof(words)); - if (dot == src) - return 0; - else if (!dot) - eow = src+strlen(src); - else { - unsigned byte1,byte2,byte3,byte4; - char more; - for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow) - ; - if (*eow != ':') - return 0; - ++eow; - - /* We use "scanf" because some platform inet_aton()s are too lax - * about IPv4 addresses of the form "1.2.3" */ - if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c", - &byte1,&byte2,&byte3,&byte4,&more) != 4) - return 0; - - if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255) - return 0; - - words[6] = (byte1<<8) | byte2; - words[7] = (byte3<<8) | byte4; - setWords += 2; - } - - i = 0; - while (src < eow) { - if (i > 7) - return 0; - if (TOR_ISXDIGIT(*src)) { - char *next; - ssize_t len; - long r = strtol(src, &next, 16); - if (next == NULL || next == src) { - /* The 'next == src' error case can happen on versions of openbsd - * which treat "0xfoo" as an error, rather than as "0" followed by - * "xfoo". */ - return 0; - } - - len = *next == '\0' ? eow - src : next - src; - if (len > 4) - return 0; - if (len > 1 && !TOR_ISXDIGIT(src[1])) - return 0; /* 0x is not valid */ - - tor_assert(r >= 0); - tor_assert(r < 65536); - words[i++] = (uint16_t)r; - setWords++; - src = next; - if (*src != ':' && src != eow) - return 0; - ++src; - } else if (*src == ':' && i > 0 && gapPos == -1) { - gapPos = i; - ++src; - } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' && - gapPos == -1) { - gapPos = i; - src += 2; - } else { - return 0; - } - } - - if (setWords > 8 || - (setWords == 8 && gapPos != -1) || - (setWords < 8 && gapPos == -1)) - return 0; - - if (gapPos >= 0) { - int nToMove = setWords - (dot ? 2 : 0) - gapPos; - int gapLen = 8 - setWords; - tor_assert(nToMove >= 0); - memmove(&words[gapPos+gapLen], &words[gapPos], - sizeof(uint16_t)*nToMove); - memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen); - } - for (i = 0; i < 8; ++i) { - out->s6_addr[2*i ] = words[i] >> 8; - out->s6_addr[2*i+1] = words[i] & 0xff; - } - - return 1; - } else { - return -1; - } -} - -/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set - * *<b>addr</b> to the proper IP address, in host byte order. Returns 0 - * on success, -1 on failure; 1 on transient failure. - * - * (This function exists because standard windows gethostbyname - * doesn't treat raw IP addresses properly.) - */ - -MOCK_IMPL(int, -tor_lookup_hostname,(const char *name, uint32_t *addr)) -{ - tor_addr_t myaddr; - int ret; - - if ((ret = tor_addr_lookup(name, AF_INET, &myaddr))) - return ret; - - if (tor_addr_family(&myaddr) == AF_INET) { - *addr = tor_addr_to_ipv4h(&myaddr); - return ret; - } - - return -1; -} - -/** Hold the result of our call to <b>uname</b>. */ -static char uname_result[256]; -/** True iff uname_result is set. */ -static int uname_result_is_set = 0; - -/** Return a pointer to a description of our platform. - */ -MOCK_IMPL(const char *, -get_uname,(void)) -{ -#ifdef HAVE_UNAME - struct utsname u; -#endif - if (!uname_result_is_set) { -#ifdef HAVE_UNAME - if (uname(&u) != -1) { - /* (Linux says 0 is success, Solaris says 1 is success) */ - strlcpy(uname_result, u.sysname, sizeof(uname_result)); - } else -#endif /* defined(HAVE_UNAME) */ - { -#ifdef _WIN32 - OSVERSIONINFOEX info; - int i; - const char *plat = NULL; - static struct { - unsigned major; unsigned minor; const char *version; - } win_version_table[] = { - { 6, 2, "Windows 8" }, - { 6, 1, "Windows 7" }, - { 6, 0, "Windows Vista" }, - { 5, 2, "Windows Server 2003" }, - { 5, 1, "Windows XP" }, - { 5, 0, "Windows 2000" }, - /* { 4, 0, "Windows NT 4.0" }, */ - { 4, 90, "Windows Me" }, - { 4, 10, "Windows 98" }, - /* { 4, 0, "Windows 95" } */ - { 3, 51, "Windows NT 3.51" }, - { 0, 0, NULL } - }; - memset(&info, 0, sizeof(info)); - info.dwOSVersionInfoSize = sizeof(info); - if (! GetVersionEx((LPOSVERSIONINFO)&info)) { - strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx" - " doesn't work.", sizeof(uname_result)); - uname_result_is_set = 1; - return uname_result; - } - if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) { - if (info.dwPlatformId == VER_PLATFORM_WIN32_NT) - plat = "Windows NT 4.0"; - else - plat = "Windows 95"; - } else { - for (i=0; win_version_table[i].major>0; ++i) { - if (win_version_table[i].major == info.dwMajorVersion && - win_version_table[i].minor == info.dwMinorVersion) { - plat = win_version_table[i].version; - break; - } - } - } - if (plat) { - strlcpy(uname_result, plat, sizeof(uname_result)); - } else { - if (info.dwMajorVersion > 6 || - (info.dwMajorVersion==6 && info.dwMinorVersion>2)) - tor_snprintf(uname_result, sizeof(uname_result), - "Very recent version of Windows [major=%d,minor=%d]", - (int)info.dwMajorVersion,(int)info.dwMinorVersion); - else - tor_snprintf(uname_result, sizeof(uname_result), - "Unrecognized version of Windows [major=%d,minor=%d]", - (int)info.dwMajorVersion,(int)info.dwMinorVersion); - } -#ifdef VER_NT_SERVER - if (info.wProductType == VER_NT_SERVER || - info.wProductType == VER_NT_DOMAIN_CONTROLLER) { - strlcat(uname_result, " [server]", sizeof(uname_result)); - } -#endif /* defined(VER_NT_SERVER) */ -#else /* !(defined(_WIN32)) */ - /* LCOV_EXCL_START -- can't provoke uname failure */ - strlcpy(uname_result, "Unknown platform", sizeof(uname_result)); - /* LCOV_EXCL_STOP */ -#endif /* defined(_WIN32) */ - } - uname_result_is_set = 1; - } - return uname_result; -} - -/* - * Process control - */ - -/** Implementation logic for compute_num_cpus(). */ -static int -compute_num_cpus_impl(void) -{ -#ifdef _WIN32 - SYSTEM_INFO info; - memset(&info, 0, sizeof(info)); - GetSystemInfo(&info); - if (info.dwNumberOfProcessors >= 1 && info.dwNumberOfProcessors < INT_MAX) - return (int)info.dwNumberOfProcessors; - else - return -1; -#elif defined(HAVE_SYSCONF) -#ifdef _SC_NPROCESSORS_CONF - long cpus_conf = sysconf(_SC_NPROCESSORS_CONF); -#else - long cpus_conf = -1; -#endif -#ifdef _SC_NPROCESSORS_ONLN - long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN); -#else - long cpus_onln = -1; -#endif - long cpus = -1; - - if (cpus_conf > 0 && cpus_onln < 0) { - cpus = cpus_conf; - } else if (cpus_onln > 0 && cpus_conf < 0) { - cpus = cpus_onln; - } else if (cpus_onln > 0 && cpus_conf > 0) { - if (cpus_onln < cpus_conf) { - log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them " - "are available. Telling Tor to only use %ld. You can over" - "ride this with the NumCPUs option", - cpus_conf, cpus_onln, cpus_onln); - } - cpus = cpus_onln; - } - - if (cpus >= 1 && cpus < INT_MAX) - return (int)cpus; - else - return -1; -#else - return -1; -#endif /* defined(_WIN32) || ... */ -} - -#define MAX_DETECTABLE_CPUS 16 - -/** Return how many CPUs we are running with. We assume that nobody is - * using hot-swappable CPUs, so we don't recompute this after the first - * time. Return -1 if we don't know how to tell the number of CPUs on this - * system. - */ -int -compute_num_cpus(void) -{ - static int num_cpus = -2; - if (num_cpus == -2) { - num_cpus = compute_num_cpus_impl(); - tor_assert(num_cpus != -2); - if (num_cpus > MAX_DETECTABLE_CPUS) { - /* LCOV_EXCL_START */ - log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I " - "will not autodetect any more than %d, though. If you " - "want to configure more, set NumCPUs in your torrc", - num_cpus, MAX_DETECTABLE_CPUS); - num_cpus = MAX_DETECTABLE_CPUS; - /* LCOV_EXCL_STOP */ - } - } - return num_cpus; -} - -#if !defined(_WIN32) -/** Defined iff we need to add locks when defining fake versions of reentrant - * versions of time-related functions. */ -#define TIME_FNS_NEED_LOCKS -#endif - -/** Helper: Deal with confused or out-of-bounds values from localtime_r and - * friends. (On some platforms, they can give out-of-bounds values or can - * return NULL.) If <b>islocal</b>, this is a localtime result; otherwise - * it's from gmtime. The function returns <b>r</b>, when given <b>timep</b> - * as its input. If we need to store new results, store them in - * <b>resultbuf</b>. */ -static struct tm * -correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, - struct tm *r) -{ - const char *outcome; - - if (PREDICT_LIKELY(r)) { - /* We can't strftime dates after 9999 CE, and we want to avoid dates - * before 1 CE (avoiding the year 0 issue and negative years). */ - if (r->tm_year > 8099) { - r->tm_year = 8099; - r->tm_mon = 11; - r->tm_mday = 31; - r->tm_yday = 364; - r->tm_wday = 6; - r->tm_hour = 23; - r->tm_min = 59; - r->tm_sec = 59; - } else if (r->tm_year < (1-1900)) { - r->tm_year = (1-1900); - r->tm_mon = 0; - r->tm_mday = 1; - r->tm_yday = 0; - r->tm_wday = 0; - r->tm_hour = 0; - r->tm_min = 0; - r->tm_sec = 0; - } - return r; - } - - /* If we get here, gmtime or localtime returned NULL. It might have done - * this because of overrun or underrun, or it might have done it because of - * some other weird issue. */ - if (timep) { - if (*timep < 0) { - r = resultbuf; - r->tm_year = 70; /* 1970 CE */ - r->tm_mon = 0; - r->tm_mday = 1; - r->tm_yday = 0; - r->tm_wday = 0; - r->tm_hour = 0; - r->tm_min = 0 ; - r->tm_sec = 0; - outcome = "Rounding up to 1970"; - goto done; - } else if (*timep >= INT32_MAX) { - /* Rounding down to INT32_MAX isn't so great, but keep in mind that we - * only do it if gmtime/localtime tells us NULL. */ - r = resultbuf; - r->tm_year = 137; /* 2037 CE */ - r->tm_mon = 11; - r->tm_mday = 31; - r->tm_yday = 364; - r->tm_wday = 6; - r->tm_hour = 23; - r->tm_min = 59; - r->tm_sec = 59; - outcome = "Rounding down to 2037"; - goto done; - } - } - - /* If we get here, then gmtime/localtime failed without getting an extreme - * value for *timep */ - /* LCOV_EXCL_START */ - tor_fragile_assert(); - r = resultbuf; - memset(resultbuf, 0, sizeof(struct tm)); - outcome="can't recover"; - /* LCOV_EXCL_STOP */ - done: - log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s", - islocal?"localtime":"gmtime", - timep?I64_PRINTF_ARG(*timep):0, - strerror(errno), - outcome); - return r; -} - -/** @{ */ -/** As localtime_r, but defined for platforms that don't have it: - * - * Convert *<b>timep</b> to a struct tm in local time, and store the value in - * *<b>result</b>. Return the result on success, or NULL on failure. - */ -#ifdef HAVE_LOCALTIME_R -struct tm * -tor_localtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - r = localtime_r(timep, result); - return correct_tm(1, timep, result, r); -} -#elif defined(TIME_FNS_NEED_LOCKS) -struct tm * -tor_localtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - static tor_mutex_t *m=NULL; - if (!m) { m=tor_mutex_new(); } - tor_assert(result); - tor_mutex_acquire(m); - r = localtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - tor_mutex_release(m); - return correct_tm(1, timep, result, r); -} -#else -struct tm * -tor_localtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - tor_assert(result); - r = localtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - return correct_tm(1, timep, result, r); -} -#endif /* defined(HAVE_LOCALTIME_R) || ... */ -/** @} */ - -/** @{ */ -/** As gmtime_r, but defined for platforms that don't have it: - * - * Convert *<b>timep</b> to a struct tm in UTC, and store the value in - * *<b>result</b>. Return the result on success, or NULL on failure. - */ -#ifdef HAVE_GMTIME_R -struct tm * -tor_gmtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - r = gmtime_r(timep, result); - return correct_tm(0, timep, result, r); -} -#elif defined(TIME_FNS_NEED_LOCKS) -struct tm * -tor_gmtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - static tor_mutex_t *m=NULL; - if (!m) { m=tor_mutex_new(); } - tor_assert(result); - tor_mutex_acquire(m); - r = gmtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - tor_mutex_release(m); - return correct_tm(0, timep, result, r); -} -#else -struct tm * -tor_gmtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - tor_assert(result); - r = gmtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - return correct_tm(0, timep, result, r); -} -#endif /* defined(HAVE_GMTIME_R) || ... */ - -#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK) -#define HAVE_UNIX_MLOCKALL -#endif - -#ifdef HAVE_UNIX_MLOCKALL -/** Attempt to raise the current and max rlimit to infinity for our process. - * This only needs to be done once and can probably only be done when we have - * not already dropped privileges. - */ -static int -tor_set_max_memlock(void) -{ - /* Future consideration for Windows is probably SetProcessWorkingSetSize - * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK - * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx - */ - - struct rlimit limit; - - /* RLIM_INFINITY is -1 on some platforms. */ - limit.rlim_cur = RLIM_INFINITY; - limit.rlim_max = RLIM_INFINITY; - - if (setrlimit(RLIMIT_MEMLOCK, &limit) == -1) { - if (errno == EPERM) { - log_warn(LD_GENERAL, "You appear to lack permissions to change memory " - "limits. Are you root?"); - } - log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s", - strerror(errno)); - return -1; - } - - return 0; -} -#endif /* defined(HAVE_UNIX_MLOCKALL) */ - -/** Attempt to lock all current and all future memory pages. - * This should only be called once and while we're privileged. - * Like mlockall() we return 0 when we're successful and -1 when we're not. - * Unlike mlockall() we return 1 if we've already attempted to lock memory. - */ -int -tor_mlockall(void) -{ - static int memory_lock_attempted = 0; - - if (memory_lock_attempted) { - return 1; - } - - memory_lock_attempted = 1; - - /* - * Future consideration for Windows may be VirtualLock - * VirtualLock appears to implement mlock() but not mlockall() - * - * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx - */ - -#ifdef HAVE_UNIX_MLOCKALL - if (tor_set_max_memlock() == 0) { - log_debug(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY."); - } - - if (mlockall(MCL_CURRENT|MCL_FUTURE) == 0) { - log_info(LD_GENERAL, "Insecure OS paging is effectively disabled."); - return 0; - } else { - if (errno == ENOSYS) { - /* Apple - it's 2009! I'm looking at you. Grrr. */ - log_notice(LD_GENERAL, "It appears that mlockall() is not available on " - "your platform."); - } else if (errno == EPERM) { - log_notice(LD_GENERAL, "It appears that you lack the permissions to " - "lock memory. Are you root?"); - } - log_notice(LD_GENERAL, "Unable to lock all current and future memory " - "pages: %s", strerror(errno)); - return -1; - } -#else /* !(defined(HAVE_UNIX_MLOCKALL)) */ - log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?"); - return -1; -#endif /* defined(HAVE_UNIX_MLOCKALL) */ -} - -/** - * On Windows, WSAEWOULDBLOCK is not always correct: when you see it, - * you need to ask the socket for its actual errno. Also, you need to - * get your errors from WSAGetLastError, not errno. (If you supply a - * socket of -1, we check WSAGetLastError, but don't correct - * WSAEWOULDBLOCKs.) - * - * The upshot of all of this is that when a socket call fails, you - * should call tor_socket_errno <em>at most once</em> on the failing - * socket to get the error. - */ -#if defined(_WIN32) -int -tor_socket_errno(tor_socket_t sock) -{ - int optval, optvallen=sizeof(optval); - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK && SOCKET_OK(sock)) { - if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen)) - return err; - if (optval) - return optval; - } - return err; -} -#endif /* defined(_WIN32) */ - -#if defined(_WIN32) -#define E(code, s) { code, (s " [" #code " ]") } -struct { int code; const char *msg; } windows_socket_errors[] = { - E(WSAEINTR, "Interrupted function call"), - E(WSAEACCES, "Permission denied"), - E(WSAEFAULT, "Bad address"), - E(WSAEINVAL, "Invalid argument"), - E(WSAEMFILE, "Too many open files"), - E(WSAEWOULDBLOCK, "Resource temporarily unavailable"), - E(WSAEINPROGRESS, "Operation now in progress"), - E(WSAEALREADY, "Operation already in progress"), - E(WSAENOTSOCK, "Socket operation on nonsocket"), - E(WSAEDESTADDRREQ, "Destination address required"), - E(WSAEMSGSIZE, "Message too long"), - E(WSAEPROTOTYPE, "Protocol wrong for socket"), - E(WSAENOPROTOOPT, "Bad protocol option"), - E(WSAEPROTONOSUPPORT, "Protocol not supported"), - E(WSAESOCKTNOSUPPORT, "Socket type not supported"), - /* What's the difference between NOTSUPP and NOSUPPORT? :) */ - E(WSAEOPNOTSUPP, "Operation not supported"), - E(WSAEPFNOSUPPORT, "Protocol family not supported"), - E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"), - E(WSAEADDRINUSE, "Address already in use"), - E(WSAEADDRNOTAVAIL, "Cannot assign requested address"), - E(WSAENETDOWN, "Network is down"), - E(WSAENETUNREACH, "Network is unreachable"), - E(WSAENETRESET, "Network dropped connection on reset"), - E(WSAECONNABORTED, "Software caused connection abort"), - E(WSAECONNRESET, "Connection reset by peer"), - E(WSAENOBUFS, "No buffer space available"), - E(WSAEISCONN, "Socket is already connected"), - E(WSAENOTCONN, "Socket is not connected"), - E(WSAESHUTDOWN, "Cannot send after socket shutdown"), - E(WSAETIMEDOUT, "Connection timed out"), - E(WSAECONNREFUSED, "Connection refused"), - E(WSAEHOSTDOWN, "Host is down"), - E(WSAEHOSTUNREACH, "No route to host"), - E(WSAEPROCLIM, "Too many processes"), - /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */ - E(WSASYSNOTREADY, "Network subsystem is unavailable"), - E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"), - E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"), - E(WSAEDISCON, "Graceful shutdown now in progress"), -#ifdef WSATYPE_NOT_FOUND - E(WSATYPE_NOT_FOUND, "Class type not found"), -#endif - E(WSAHOST_NOT_FOUND, "Host not found"), - E(WSATRY_AGAIN, "Nonauthoritative host not found"), - E(WSANO_RECOVERY, "This is a nonrecoverable error"), - E(WSANO_DATA, "Valid name, no data record of requested type)"), - - /* There are some more error codes whose numeric values are marked - * <b>OS dependent</b>. They start with WSA_, apparently for the same - * reason that practitioners of some craft traditions deliberately - * introduce imperfections into their baskets and rugs "to allow the - * evil spirits to escape." If we catch them, then our binaries - * might not report consistent results across versions of Windows. - * Thus, I'm going to let them all fall through. - */ - { -1, NULL }, -}; -/** There does not seem to be a strerror equivalent for Winsock errors. - * Naturally, we have to roll our own. - */ -const char * -tor_socket_strerror(int e) -{ - int i; - for (i=0; windows_socket_errors[i].code >= 0; ++i) { - if (e == windows_socket_errors[i].code) - return windows_socket_errors[i].msg; - } - return strerror(e); -} -#endif /* defined(_WIN32) */ - -/** Called before we make any calls to network-related functions. - * (Some operating systems require their network libraries to be - * initialized.) */ -int -network_init(void) -{ -#ifdef _WIN32 - /* This silly exercise is necessary before windows will allow - * gethostbyname to work. */ - WSADATA WSAData; - int r; - r = WSAStartup(0x101,&WSAData); - if (r) { - log_warn(LD_NET,"Error initializing windows network layer: code was %d",r); - return -1; - } - if (sizeof(SOCKET) != sizeof(tor_socket_t)) { - log_warn(LD_BUG,"The tor_socket_t type does not match SOCKET in size; Tor " - "might not work. (Sizes are %d and %d respectively.)", - (int)sizeof(tor_socket_t), (int)sizeof(SOCKET)); - } - /* WSAData.iMaxSockets might show the max sockets we're allowed to use. - * We might use it to complain if we're trying to be a server but have - * too few sockets available. */ -#endif /* defined(_WIN32) */ - return 0; -} - -#ifdef _WIN32 -/** Return a newly allocated string describing the windows system error code - * <b>err</b>. Note that error codes are different from errno. Error codes - * come from GetLastError() when a winapi call fails. errno is set only when - * ANSI functions fail. Whee. */ -char * -format_win32_error(DWORD err) -{ - TCHAR *str = NULL; - char *result; - DWORD n; - - /* Somebody once decided that this interface was better than strerror(). */ - n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, - MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), - (LPVOID)&str, - 0, NULL); - - if (str && n) { -#ifdef UNICODE - size_t len; - if (n > 128*1024) - len = (128 * 1024) * 2 + 1; /* This shouldn't be possible, but let's - * make sure. */ - else - len = n * 2 + 1; - result = tor_malloc(len); - wcstombs(result,str,len); - result[len-1] = '\0'; -#else /* !(defined(UNICODE)) */ - result = tor_strdup(str); -#endif /* defined(UNICODE) */ - } else { - result = tor_strdup("<unformattable error>"); - } - if (str) { - LocalFree(str); /* LocalFree != free() */ - } - return result; -} -#endif /* defined(_WIN32) */ - -#if defined(HW_PHYSMEM64) -/* This appears to be an OpenBSD thing */ -#define INT64_HW_MEM HW_PHYSMEM64 -#elif defined(HW_MEMSIZE) -/* OSX defines this one */ -#define INT64_HW_MEM HW_MEMSIZE -#endif /* defined(HW_PHYSMEM64) || ... */ - -/** - * Helper: try to detect the total system memory, and return it. On failure, - * return 0. - */ -static uint64_t -get_total_system_memory_impl(void) -{ -#if defined(__linux__) - /* On linux, sysctl is deprecated. Because proc is so awesome that you - * shouldn't _want_ to write portable code, I guess? */ - unsigned long long result=0; - int fd = -1; - char *s = NULL; - const char *cp; - size_t file_size=0; - if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0))) - return 0; - s = read_file_to_str_until_eof(fd, 65536, &file_size); - if (!s) - goto err; - cp = strstr(s, "MemTotal:"); - if (!cp) - goto err; - /* Use the system sscanf so that space will match a wider number of space */ - if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1) - goto err; - - close(fd); - tor_free(s); - return result * 1024; - - /* LCOV_EXCL_START Can't reach this unless proc is broken. */ - err: - tor_free(s); - close(fd); - return 0; - /* LCOV_EXCL_STOP */ -#elif defined (_WIN32) - /* Windows has MEMORYSTATUSEX; pretty straightforward. */ - MEMORYSTATUSEX ms; - memset(&ms, 0, sizeof(ms)); - ms.dwLength = sizeof(ms); - if (! GlobalMemoryStatusEx(&ms)) - return 0; - - return ms.ullTotalPhys; - -#elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM) - /* On many systems, HW_PYHSMEM is clipped to 32 bits; let's use a better - * variant if we know about it. */ - uint64_t memsize = 0; - size_t len = sizeof(memsize); - int mib[2] = {CTL_HW, INT64_HW_MEM}; - if (sysctl(mib,2,&memsize,&len,NULL,0)) - return 0; - - return memsize; - -#elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM) - /* On some systems (like FreeBSD I hope) you can use a size_t with - * HW_PHYSMEM. */ - size_t memsize=0; - size_t len = sizeof(memsize); - int mib[2] = {CTL_HW, HW_USERMEM}; - if (sysctl(mib,2,&memsize,&len,NULL,0)) - return 0; - - return memsize; - -#else - /* I have no clue. */ - return 0; -#endif /* defined(__linux__) || ... */ -} - -/** - * Try to find out how much physical memory the system has. On success, - * return 0 and set *<b>mem_out</b> to that value. On failure, return -1. - */ -MOCK_IMPL(int, -get_total_system_memory, (size_t *mem_out)) -{ - static size_t mem_cached=0; - uint64_t m = get_total_system_memory_impl(); - if (0 == m) { - /* LCOV_EXCL_START -- can't make this happen without mocking. */ - /* We couldn't find our memory total */ - if (0 == mem_cached) { - /* We have no cached value either */ - *mem_out = 0; - return -1; - } - - *mem_out = mem_cached; - return 0; - /* LCOV_EXCL_STOP */ - } - -#if SIZE_MAX != UINT64_MAX - if (m > SIZE_MAX) { - /* I think this could happen if we're a 32-bit Tor running on a 64-bit - * system: we could have more system memory than would fit in a - * size_t. */ - m = SIZE_MAX; - } -#endif /* SIZE_MAX != UINT64_MAX */ - - *mem_out = mem_cached = (size_t) m; - - return 0; -} - -/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b> - * bytes of passphrase into <b>output</b>. Return the number of bytes in - * the passphrase, excluding terminating NUL. - */ -ssize_t -tor_getpass(const char *prompt, char *output, size_t buflen) -{ - tor_assert(buflen <= SSIZE_MAX); - tor_assert(buflen >= 1); -#if defined(HAVE_READPASSPHRASE) - char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF); - if (pwd == NULL) - return -1; - return strlen(pwd); -#elif defined(_WIN32) - int r = -1; - while (*prompt) { - _putch(*prompt++); - } - - tor_assert(buflen <= INT_MAX); - wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t)); - - wchar_t *ptr = buf, *lastch = buf + buflen - 1; - while (ptr < lastch) { - wint_t ch = _getwch(); - switch (ch) { - case '\r': - case '\n': - case WEOF: - goto done_reading; - case 3: - goto done; /* Can't actually read ctrl-c this way. */ - case '\b': - if (ptr > buf) - --ptr; - continue; - case 0: - case 0xe0: - ch = _getwch(); /* Ignore; this is a function or arrow key */ - break; - default: - *ptr++ = ch; - break; - } - } - done_reading: - ; - -#ifndef WC_ERR_INVALID_CHARS -#define WC_ERR_INVALID_CHARS 0x80 -#endif - - /* Now convert it to UTF-8 */ - r = WideCharToMultiByte(CP_UTF8, - WC_NO_BEST_FIT_CHARS|WC_ERR_INVALID_CHARS, - buf, (int)(ptr-buf), - output, (int)(buflen-1), - NULL, NULL); - if (r <= 0) { - r = -1; - goto done; - } - - tor_assert(r < (int)buflen); - - output[r] = 0; - - done: - SecureZeroMemory(buf, sizeof(wchar_t)*buflen); - tor_free(buf); - return r; -#else -#error "No implementation for tor_getpass found!" -#endif /* defined(HAVE_READPASSPHRASE) || ... */ -} - -/** Return the amount of free disk space we have permission to use, in - * bytes. Return -1 if the amount of free space can't be determined. */ -int64_t -tor_get_avail_disk_space(const char *path) -{ -#ifdef HAVE_STATVFS - struct statvfs st; - int r; - memset(&st, 0, sizeof(st)); - - r = statvfs(path, &st); - if (r < 0) - return -1; - - int64_t result = st.f_bavail; - if (st.f_frsize) { - result *= st.f_frsize; - } else if (st.f_bsize) { - result *= st.f_bsize; - } else { - return -1; - } - - return result; -#elif defined(_WIN32) - ULARGE_INTEGER freeBytesAvail; - BOOL ok; - - ok = GetDiskFreeSpaceEx(path, &freeBytesAvail, NULL, NULL); - if (!ok) { - return -1; - } - return (int64_t)freeBytesAvail.QuadPart; -#else - (void)path; - errno = ENOSYS; - return -1; -#endif /* defined(HAVE_STATVFS) || ... */ -} - diff --git a/src/common/compat.h b/src/common/compat.h deleted file mode 100644 index c7e7f8d9ef..0000000000 --- a/src/common/compat.h +++ /dev/null @@ -1,757 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_COMPAT_H -#define TOR_COMPAT_H - -#include "orconfig.h" -#ifdef _WIN32 -#include <winsock2.h> -#include <ws2tcpip.h> -#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY -#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747b -#endif -#endif -#include "torint.h" -#include "testsupport.h" -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#include <stdarg.h> -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_NETINET6_IN6_H -#include <netinet6/in6.h> -#endif - -#include "compat_time.h" - -#if defined(__has_feature) -# if __has_feature(address_sanitizer) -/* Some of the fancy glibc strcmp() macros include references to memory that - * clang rejects because it is off the end of a less-than-3. Clang hates this, - * even though those references never actually happen. */ -# undef strcmp -#endif /* __has_feature(address_sanitizer) */ -#endif /* defined(__has_feature) */ - -#include <stdio.h> -#include <errno.h> - -#ifndef NULL_REP_IS_ZERO_BYTES -#error "It seems your platform does not represent NULL as zero. We can't cope." -#endif - -#ifndef DOUBLE_0_REP_IS_ZERO_BYTES -#error "It seems your platform does not represent 0.0 as zeros. We can't cope." -#endif - -#if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32 -#error "It seems that you encode characters in something other than ASCII." -#endif - -/* ===== Compiler compatibility */ - -/* GCC can check printf and scanf types on arbitrary functions. */ -#ifdef __GNUC__ -#define CHECK_PRINTF(formatIdx, firstArg) \ - __attribute__ ((format(printf, formatIdx, firstArg))) -#else -#define CHECK_PRINTF(formatIdx, firstArg) -#endif /* defined(__GNUC__) */ -#ifdef __GNUC__ -#define CHECK_SCANF(formatIdx, firstArg) \ - __attribute__ ((format(scanf, formatIdx, firstArg))) -#else -#define CHECK_SCANF(formatIdx, firstArg) -#endif /* defined(__GNUC__) */ - -/* What GCC do we have? */ -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#else -#define GCC_VERSION 0 -#endif - -/* Temporarily enable and disable warnings. */ -#ifdef __GNUC__ -# define PRAGMA_STRINGIFY_(s) #s -# define PRAGMA_JOIN_STRINGIFY_(a,b) PRAGMA_STRINGIFY_(a ## b) -/* Support for macro-generated pragmas (c99) */ -# define PRAGMA_(x) _Pragma (#x) -# ifdef __clang__ -# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(clang diagnostic x) -# else -# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(GCC diagnostic x) -# endif -# if defined(__clang__) || GCC_VERSION >= 406 -/* we have push/pop support */ -# define DISABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(push) \ - PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) -# define ENABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(pop) -#else /* !(defined(__clang__) || GCC_VERSION >= 406) */ -/* older version of gcc: no push/pop support. */ -# define DISABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) -# define ENABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(warning PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) -#endif /* defined(__clang__) || GCC_VERSION >= 406 */ -#else /* !(defined(__GNUC__)) */ -/* not gcc at all */ -# define DISABLE_GCC_WARNING(warning) -# define ENABLE_GCC_WARNING(warning) -#endif /* defined(__GNUC__) */ - -/* inline is __inline on windows. */ -#ifdef _WIN32 -#define inline __inline -#endif - -/* Try to get a reasonable __func__ substitute in place. */ -#if defined(_MSC_VER) - -#define __func__ __FUNCTION__ - -#else -/* For platforms where autoconf works, make sure __func__ is defined - * sanely. */ -#ifndef HAVE_MACRO__func__ -#ifdef HAVE_MACRO__FUNCTION__ -#define __func__ __FUNCTION__ -#elif HAVE_MACRO__FUNC__ -#define __func__ __FUNC__ -#else -#define __func__ "???" -#endif /* defined(HAVE_MACRO__FUNCTION__) || ... */ -#endif /* !defined(HAVE_MACRO__func__) */ -#endif /* defined(_MSC_VER) */ - -#define U64_TO_DBL(x) ((double) (x)) -#define DBL_TO_U64(x) ((uint64_t) (x)) - -#ifdef ENUM_VALS_ARE_SIGNED -#define ENUM_BF(t) unsigned -#else -/** Wrapper for having a bitfield of an enumerated type. Where possible, we - * just use the enumerated type (so the compiler can help us and notice - * problems), but if enumerated types are unsigned, we must use unsigned, - * so that the loss of precision doesn't make large values negative. */ -#define ENUM_BF(t) t -#endif /* defined(ENUM_VALS_ARE_SIGNED) */ - -/* GCC has several useful attributes. */ -#if defined(__GNUC__) && __GNUC__ >= 3 -#define ATTR_NORETURN __attribute__((noreturn)) -#define ATTR_CONST __attribute__((const)) -#define ATTR_MALLOC __attribute__((malloc)) -#define ATTR_NORETURN __attribute__((noreturn)) -#define ATTR_WUR __attribute__((warn_unused_result)) -/* Alas, nonnull is not at present a good idea for us. We'd like to get - * warnings when we pass NULL where we shouldn't (which nonnull does, albeit - * spottily), but we don't want to tell the compiler to make optimizations - * with the assumption that the argument can't be NULL (since this would make - * many of our checks go away, and make our code less robust against - * programming errors). Unfortunately, nonnull currently does both of these - * things, and there's no good way to split them up. - * - * #define ATTR_NONNULL(x) __attribute__((nonnull x)) */ -#define ATTR_NONNULL(x) -#define ATTR_UNUSED __attribute__ ((unused)) - -/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value - * of <b>exp</b> will probably be true. - * - * In other words, "if (PREDICT_LIKELY(foo))" is the same as "if (foo)", - * except that it tells the compiler that the branch will be taken most of the - * time. This can generate slightly better code with some CPUs. - */ -#define PREDICT_LIKELY(exp) __builtin_expect(!!(exp), 1) -/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value - * of <b>exp</b> will probably be false. - * - * In other words, "if (PREDICT_UNLIKELY(foo))" is the same as "if (foo)", - * except that it tells the compiler that the branch will usually not be - * taken. This can generate slightly better code with some CPUs. - */ -#define PREDICT_UNLIKELY(exp) __builtin_expect(!!(exp), 0) -#else /* !(defined(__GNUC__) && __GNUC__ >= 3) */ -#define ATTR_NORETURN -#define ATTR_CONST -#define ATTR_MALLOC -#define ATTR_NORETURN -#define ATTR_NONNULL(x) -#define ATTR_UNUSED -#define ATTR_WUR -#define PREDICT_LIKELY(exp) (exp) -#define PREDICT_UNLIKELY(exp) (exp) -#endif /* defined(__GNUC__) && __GNUC__ >= 3 */ - -/** Expands to a syntactically valid empty statement. */ -#define STMT_NIL (void)0 - -/** Expands to a syntactically valid empty statement, explicitly (void)ing its - * argument. */ -#define STMT_VOID(a) while (0) { (void)(a); } - -#ifdef __GNUC__ -/** STMT_BEGIN and STMT_END are used to wrap blocks inside macros so that - * the macro can be used as if it were a single C statement. */ -#define STMT_BEGIN (void) ({ -#define STMT_END }) -#elif defined(sun) || defined(__sun__) -#define STMT_BEGIN if (1) { -#define STMT_END } else STMT_NIL -#else -#define STMT_BEGIN do { -#define STMT_END } while (0) -#endif /* defined(__GNUC__) || ... */ - -/* Some tools (like coccinelle) don't like to see operators as macro - * arguments. */ -#define OP_LT < -#define OP_GT > -#define OP_GE >= -#define OP_LE <= -#define OP_EQ == -#define OP_NE != - -/* ===== String compatibility */ -#ifdef _WIN32 -/* Windows names string functions differently from most other platforms. */ -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#endif - -#if defined __APPLE__ -/* On OSX 10.9 and later, the overlap-checking code for strlcat would - * appear to have a severe bug that can sometimes cause aborts in Tor. - * Instead, use the non-checking variants. This is sad. - * - * See https://trac.torproject.org/projects/tor/ticket/15205 - */ -#undef strlcat -#undef strlcpy -#endif /* defined __APPLE__ */ - -#ifndef HAVE_STRLCAT -size_t strlcat(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2)); -#endif -#ifndef HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2)); -#endif - -#ifdef _MSC_VER -/** Casts the uint64_t value in <b>a</b> to the right type for an argument - * to printf. */ -#define U64_PRINTF_ARG(a) (a) -/** Casts the uint64_t* value in <b>a</b> to the right type for an argument - * to scanf. */ -#define U64_SCANF_ARG(a) (a) -/** Expands to a literal uint64_t-typed constant for the value <b>n</b>. */ -#define U64_LITERAL(n) (n ## ui64) -#define I64_PRINTF_ARG(a) (a) -#define I64_SCANF_ARG(a) (a) -#define I64_LITERAL(n) (n ## i64) -#else /* !(defined(_MSC_VER)) */ -#define U64_PRINTF_ARG(a) ((long long unsigned int)(a)) -#define U64_SCANF_ARG(a) ((long long unsigned int*)(a)) -#define U64_LITERAL(n) (n ## llu) -#define I64_PRINTF_ARG(a) ((long long signed int)(a)) -#define I64_SCANF_ARG(a) ((long long signed int*)(a)) -#define I64_LITERAL(n) (n ## ll) -#endif /* defined(_MSC_VER) */ - -#if defined(__MINGW32__) || defined(__MINGW64__) -#define MINGW_ANY -#endif - -#if defined(_MSC_VER) || defined(MINGW_ANY) -/** The formatting string used to put a uint64_t value in a printf() or - * scanf() function. See also U64_PRINTF_ARG and U64_SCANF_ARG. */ -#define U64_FORMAT "%I64u" -#define I64_FORMAT "%I64d" -#else /* !(defined(_MSC_VER) || defined(MINGW_ANY)) */ -#define U64_FORMAT "%llu" -#define I64_FORMAT "%lld" -#endif /* defined(_MSC_VER) || defined(MINGW_ANY) */ - -#if (SIZEOF_INTPTR_T == SIZEOF_INT) -#define INTPTR_T_FORMAT "%d" -#define INTPTR_PRINTF_ARG(x) ((int)(x)) -#elif (SIZEOF_INTPTR_T == SIZEOF_LONG) -#define INTPTR_T_FORMAT "%ld" -#define INTPTR_PRINTF_ARG(x) ((long)(x)) -#elif (SIZEOF_INTPTR_T == 8) -#define INTPTR_T_FORMAT I64_FORMAT -#define INTPTR_PRINTF_ARG(x) I64_PRINTF_ARG(x) -#else -#error Unknown: SIZEOF_INTPTR_T -#endif /* (SIZEOF_INTPTR_T == SIZEOF_INT) || ... */ - -/** Represents an mmaped file. Allocated via tor_mmap_file; freed with - * tor_munmap_file. */ -typedef struct tor_mmap_t { - const char *data; /**< Mapping of the file's contents. */ - size_t size; /**< Size of the file. */ - - /* None of the fields below should be accessed from outside compat.c */ -#ifdef HAVE_MMAP - size_t mapping_size; /**< Size of the actual mapping. (This is this file - * size, rounded up to the nearest page.) */ -#elif defined _WIN32 - HANDLE mmap_handle; -#endif /* defined(HAVE_MMAP) || ... */ - -} tor_mmap_t; - -tor_mmap_t *tor_mmap_file(const char *filename) ATTR_NONNULL((1)); -int tor_munmap_file(tor_mmap_t *handle) ATTR_NONNULL((1)); - -int tor_snprintf(char *str, size_t size, const char *format, ...) - CHECK_PRINTF(3,4) ATTR_NONNULL((1,3)); -int tor_vsnprintf(char *str, size_t size, const char *format, va_list args) - CHECK_PRINTF(3,0) ATTR_NONNULL((1,3)); - -int tor_asprintf(char **strp, const char *fmt, ...) - CHECK_PRINTF(2,3); -int tor_vasprintf(char **strp, const char *fmt, va_list args) - CHECK_PRINTF(2,0); - -const void *tor_memmem(const void *haystack, size_t hlen, const void *needle, - size_t nlen) ATTR_NONNULL((1,3)); -static const void *tor_memstr(const void *haystack, size_t hlen, - const char *needle) ATTR_NONNULL((1,3)); -static inline const void * -tor_memstr(const void *haystack, size_t hlen, const char *needle) -{ - return tor_memmem(haystack, hlen, needle, strlen(needle)); -} - -/* Much of the time when we're checking ctypes, we're doing spec compliance, - * which all assumes we're doing ASCII. */ -#define DECLARE_CTYPE_FN(name) \ - static int TOR_##name(char c); \ - extern const uint32_t TOR_##name##_TABLE[]; \ - static inline int TOR_##name(char c) { \ - uint8_t u = c; \ - return !!(TOR_##name##_TABLE[(u >> 5) & 7] & (1u << (u & 31))); \ - } -DECLARE_CTYPE_FN(ISALPHA) -DECLARE_CTYPE_FN(ISALNUM) -DECLARE_CTYPE_FN(ISSPACE) -DECLARE_CTYPE_FN(ISDIGIT) -DECLARE_CTYPE_FN(ISXDIGIT) -DECLARE_CTYPE_FN(ISPRINT) -DECLARE_CTYPE_FN(ISLOWER) -DECLARE_CTYPE_FN(ISUPPER) -extern const uint8_t TOR_TOUPPER_TABLE[]; -extern const uint8_t TOR_TOLOWER_TABLE[]; -#define TOR_TOLOWER(c) (TOR_TOLOWER_TABLE[(uint8_t)c]) -#define TOR_TOUPPER(c) (TOR_TOUPPER_TABLE[(uint8_t)c]) - -char *tor_strtok_r_impl(char *str, const char *sep, char **lasts); -#ifdef HAVE_STRTOK_R -#define tor_strtok_r(str, sep, lasts) strtok_r(str, sep, lasts) -#else -#define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts) -#endif - -#ifdef _WIN32 -#define SHORT_FILE__ (tor_fix_source_file(__FILE__)) -const char *tor_fix_source_file(const char *fname); -#else -#define SHORT_FILE__ (__FILE__) -#define tor_fix_source_file(s) (s) -#endif /* defined(_WIN32) */ - -/* ===== Time compatibility */ - -struct tm *tor_localtime_r(const time_t *timep, struct tm *result); -struct tm *tor_gmtime_r(const time_t *timep, struct tm *result); - -#ifndef timeradd -/** Replacement for timeradd on platforms that do not have it: sets tvout to - * the sum of tv1 and tv2. */ -#define timeradd(tv1,tv2,tvout) \ - do { \ - (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ - (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \ - if ((tvout)->tv_usec >= 1000000) { \ - (tvout)->tv_usec -= 1000000; \ - (tvout)->tv_sec++; \ - } \ - } while (0) -#endif /* !defined(timeradd) */ - -#ifndef timersub -/** Replacement for timersub on platforms that do not have it: sets tvout to - * tv1 minus tv2. */ -#define timersub(tv1,tv2,tvout) \ - do { \ - (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \ - (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec; \ - if ((tvout)->tv_usec < 0) { \ - (tvout)->tv_usec += 1000000; \ - (tvout)->tv_sec--; \ - } \ - } while (0) -#endif /* !defined(timersub) */ - -#ifndef timercmp -/** Replacement for timercmp on platforms that do not have it: returns true - * iff the relational operator "op" makes the expression tv1 op tv2 true. - * - * Note that while this definition should work for all boolean operators, some - * platforms' native timercmp definitions do not support >=, <=, or ==. So - * don't use those. - */ -#define timercmp(tv1,tv2,op) \ - (((tv1)->tv_sec == (tv2)->tv_sec) ? \ - ((tv1)->tv_usec op (tv2)->tv_usec) : \ - ((tv1)->tv_sec op (tv2)->tv_sec)) -#endif /* !defined(timercmp) */ - -/* ===== File compatibility */ -int tor_open_cloexec(const char *path, int flags, unsigned mode); -FILE *tor_fopen_cloexec(const char *path, const char *mode); -int tor_rename(const char *path_old, const char *path_new); - -int replace_file(const char *from, const char *to); -int touch_file(const char *fname); - -typedef struct tor_lockfile_t tor_lockfile_t; -tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking, - int *locked_out); -void tor_lockfile_unlock(tor_lockfile_t *lockfile); - -off_t tor_fd_getpos(int fd); -int tor_fd_setpos(int fd, off_t pos); -int tor_fd_seekend(int fd); -int tor_ftruncate(int fd); - -int64_t tor_get_avail_disk_space(const char *path); - -#ifdef _WIN32 -#define PATH_SEPARATOR "\\" -#else -#define PATH_SEPARATOR "/" -#endif - -/* ===== Net compatibility */ - -#if (SIZEOF_SOCKLEN_T == 0) -typedef int socklen_t; -#endif - -#ifdef _WIN32 -/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that - * any inadvertent checks for the socket being <= 0 or > 0 will probably - * still work. */ -#define tor_socket_t intptr_t -#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT -#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET) -#define TOR_INVALID_SOCKET INVALID_SOCKET -#else /* !(defined(_WIN32)) */ -/** Type used for a network socket. */ -#define tor_socket_t int -#define TOR_SOCKET_T_FORMAT "%d" -/** Macro: true iff 's' is a possible value for a valid initialized socket. */ -#define SOCKET_OK(s) ((s) >= 0) -/** Error/uninitialized value for a tor_socket_t. */ -#define TOR_INVALID_SOCKET (-1) -#endif /* defined(_WIN32) */ - -int tor_close_socket_simple(tor_socket_t s); -MOCK_DECL(int, tor_close_socket, (tor_socket_t s)); -void tor_take_socket_ownership(tor_socket_t s); -tor_socket_t tor_open_socket_with_extensions( - int domain, int type, int protocol, - int cloexec, int nonblock); -MOCK_DECL(tor_socket_t, -tor_open_socket,(int domain, int type, int protocol)); -tor_socket_t tor_open_socket_nonblocking(int domain, int type, int protocol); -tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, - socklen_t *len); -tor_socket_t tor_accept_socket_nonblocking(tor_socket_t sockfd, - struct sockaddr *addr, - socklen_t *len); -tor_socket_t tor_accept_socket_with_extensions(tor_socket_t sockfd, - struct sockaddr *addr, - socklen_t *len, - int cloexec, int nonblock); -MOCK_DECL(tor_socket_t, -tor_connect_socket,(tor_socket_t socket,const struct sockaddr *address, - socklen_t address_len)); -int get_n_open_sockets(void); - -MOCK_DECL(int, -tor_getsockname,(tor_socket_t socket, struct sockaddr *address, - socklen_t *address_len)); -struct tor_addr_t; -int tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock); - -#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags) -#define tor_socket_recv(s, buf, len, flags) recv(s, buf, len, flags) - -/** Implementation of struct in6_addr for platforms that do not have it. - * Generally, these platforms are ones without IPv6 support, but we want to - * have a working in6_addr there anyway, so we can use it to parse IPv6 - * addresses. */ -#if !defined(HAVE_STRUCT_IN6_ADDR) -struct in6_addr -{ - union { - uint8_t u6_addr8[16]; - uint16_t u6_addr16[8]; - uint32_t u6_addr32[4]; - } in6_u; -#define s6_addr in6_u.u6_addr8 -#define s6_addr16 in6_u.u6_addr16 -#define s6_addr32 in6_u.u6_addr32 -}; -#endif /* !defined(HAVE_STRUCT_IN6_ADDR) */ - -/** @{ */ -/** Many BSD variants seem not to define these. */ -#if defined(__APPLE__) || defined(__darwin__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#ifndef s6_addr16 -#define s6_addr16 __u6_addr.__u6_addr16 -#endif -#ifndef s6_addr32 -#define s6_addr32 __u6_addr.__u6_addr32 -#endif -#endif /* defined(__APPLE__) || defined(__darwin__) || ... */ -/** @} */ - -#ifndef HAVE_SA_FAMILY_T -typedef uint16_t sa_family_t; -#endif - -/** @{ */ -/** Apparently, MS and Solaris don't define s6_addr16 or s6_addr32; these - * macros get you a pointer to s6_addr32 or local equivalent. */ -#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR32 -#define S6_ADDR32(x) ((uint32_t*)(x).s6_addr32) -#else -#define S6_ADDR32(x) ((uint32_t*)((char*)&(x).s6_addr)) -#endif -#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR16 -#define S6_ADDR16(x) ((uint16_t*)(x).s6_addr16) -#else -#define S6_ADDR16(x) ((uint16_t*)((char*)&(x).s6_addr)) -#endif -/** @} */ - -/** Implementation of struct sockaddr_in6 on platforms that do not have - * it. See notes on struct in6_addr. */ -#if !defined(HAVE_STRUCT_SOCKADDR_IN6) -struct sockaddr_in6 { - sa_family_t sin6_family; - uint16_t sin6_port; - // uint32_t sin6_flowinfo; - struct in6_addr sin6_addr; - // uint32_t sin6_scope_id; -}; -#endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */ - -MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen)); -int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2)); -const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); -int tor_inet_pton(int af, const char *src, void *dst); -MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr)); -int set_socket_nonblocking(tor_socket_t socket); -int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]); -int network_init(void); - -/* For stupid historical reasons, windows sockets have an independent - * set of errnos, and an independent way to get them. Also, you can't - * always believe WSAEWOULDBLOCK. Use the macros below to compare - * errnos against expected values, and use tor_socket_errno to find - * the actual errno after a socket operation fails. - */ -#if defined(_WIN32) -/** Expands to WSA<b>e</b> on Windows, and to <b>e</b> elsewhere. */ -#define SOCK_ERRNO(e) WSA##e -/** Return true if e is EAGAIN or the local equivalent. */ -#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK) -/** Return true if e is EINPROGRESS or the local equivalent. */ -#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS) -/** Return true if e is EINPROGRESS or the local equivalent as returned by - * a call to connect(). */ -#define ERRNO_IS_CONN_EINPROGRESS(e) \ - ((e) == WSAEINPROGRESS || (e)== WSAEINVAL || (e) == WSAEWOULDBLOCK) -/** Return true if e is EAGAIN or another error indicating that a call to - * accept() has no pending connections to return. */ -#define ERRNO_IS_ACCEPT_EAGAIN(e) ERRNO_IS_EAGAIN(e) -/** Return true if e is EMFILE or another error indicating that a call to - * accept() has failed because we're out of fds or something. */ -#define ERRNO_IS_RESOURCE_LIMIT(e) \ - ((e) == WSAEMFILE || (e) == WSAENOBUFS) -/** Return true if e is EADDRINUSE or the local equivalent. */ -#define ERRNO_IS_EADDRINUSE(e) ((e) == WSAEADDRINUSE) -/** Return true if e is EINTR or the local equivalent */ -#define ERRNO_IS_EINTR(e) ((e) == WSAEINTR || 0) -int tor_socket_errno(tor_socket_t sock); -const char *tor_socket_strerror(int e); -#else /* !(defined(_WIN32)) */ -#define SOCK_ERRNO(e) e -#if EAGAIN == EWOULDBLOCK -/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */ -#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || 0) -#else -#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK) -#endif /* EAGAIN == EWOULDBLOCK */ -#define ERRNO_IS_EINTR(e) ((e) == EINTR || 0) -#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0) -#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0) -#define ERRNO_IS_ACCEPT_EAGAIN(e) \ - (ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED) -#define ERRNO_IS_RESOURCE_LIMIT(e) \ - ((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM) -#define ERRNO_IS_EADDRINUSE(e) (((e) == EADDRINUSE) || 0) -#define tor_socket_errno(sock) (errno) -#define tor_socket_strerror(e) strerror(e) -#endif /* defined(_WIN32) */ - -/** Specified SOCKS5 status codes. */ -typedef enum { - SOCKS5_SUCCEEDED = 0x00, - SOCKS5_GENERAL_ERROR = 0x01, - SOCKS5_NOT_ALLOWED = 0x02, - SOCKS5_NET_UNREACHABLE = 0x03, - SOCKS5_HOST_UNREACHABLE = 0x04, - SOCKS5_CONNECTION_REFUSED = 0x05, - SOCKS5_TTL_EXPIRED = 0x06, - SOCKS5_COMMAND_NOT_SUPPORTED = 0x07, - SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08, -} socks5_reply_status_t; - -/* ===== OS compatibility */ -MOCK_DECL(const char *, get_uname, (void)); - -uint16_t get_uint16(const void *cp) ATTR_NONNULL((1)); -uint32_t get_uint32(const void *cp) ATTR_NONNULL((1)); -uint64_t get_uint64(const void *cp) ATTR_NONNULL((1)); -void set_uint16(void *cp, uint16_t v) ATTR_NONNULL((1)); -void set_uint32(void *cp, uint32_t v) ATTR_NONNULL((1)); -void set_uint64(void *cp, uint64_t v) ATTR_NONNULL((1)); - -/* These uint8 variants are defined to make the code more uniform. */ -#define get_uint8(cp) (*(const uint8_t*)(cp)) -static void set_uint8(void *cp, uint8_t v); -static inline void -set_uint8(void *cp, uint8_t v) -{ - *(uint8_t*)cp = v; -} - -#if !defined(HAVE_RLIM_T) -typedef unsigned long rlim_t; -#endif -int get_max_sockets(void); -int set_max_file_descriptors(rlim_t limit, int *max); -int tor_disable_debugger_attach(void); - -#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_CAP_SET_PROC) -#define HAVE_LINUX_CAPABILITIES -#endif - -int have_capability_support(void); - -/** Flag for switch_id; see switch_id() for documentation */ -#define SWITCH_ID_KEEP_BINDLOW (1<<0) -/** Flag for switch_id; see switch_id() for documentation */ -#define SWITCH_ID_WARN_IF_NO_CAPS (1<<1) -int switch_id(const char *user, unsigned flags); -#ifdef HAVE_PWD_H -char *get_user_homedir(const char *username); -#endif - -#ifndef _WIN32 -const struct passwd *tor_getpwnam(const char *username); -const struct passwd *tor_getpwuid(uid_t uid); -#endif - -int get_parent_directory(char *fname); -char *make_path_absolute(char *fname); - -char **get_environment(void); - -MOCK_DECL(int, get_total_system_memory, (size_t *mem_out)); - -int compute_num_cpus(void); - -int tor_mlockall(void); - -/** Macros for MIN/MAX. Never use these when the arguments could have - * side-effects. - * {With GCC extensions we could probably define a safer MIN/MAX. But - * depending on that safety would be dangerous, since not every platform - * has it.} - **/ -#ifndef MAX -#define MAX(a,b) ( ((a)<(b)) ? (b) : (a) ) -#endif -#ifndef MIN -#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) ) -#endif - -/* Platform-specific helpers. */ -#ifdef _WIN32 -char *format_win32_error(DWORD err); -#endif - -/*for some reason my compiler doesn't have these version flags defined - a nice homework assignment for someone one day is to define the rest*/ -//these are the values as given on MSDN -#ifdef _WIN32 - -#ifndef VER_SUITE_EMBEDDEDNT -#define VER_SUITE_EMBEDDEDNT 0x00000040 -#endif - -#ifndef VER_SUITE_SINGLEUSERTS -#define VER_SUITE_SINGLEUSERTS 0x00000100 -#endif - -#endif /* defined(_WIN32) */ - -#ifdef COMPAT_PRIVATE -#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS) -#define NEED_ERSATZ_SOCKETPAIR -STATIC int tor_ersatz_socketpair(int family, int type, int protocol, - tor_socket_t fd[2]); -#endif -#endif /* defined(COMPAT_PRIVATE) */ - -ssize_t tor_getpass(const char *prompt, char *output, size_t buflen); - -/* This needs some of the declarations above so we include it here. */ -#include "compat_threads.h" - -#endif /* !defined(TOR_COMPAT_H) */ - diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c deleted file mode 100644 index e60eb148d8..0000000000 --- a/src/common/compat_libevent.c +++ /dev/null @@ -1,536 +0,0 @@ -/* Copyright (c) 2009-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat_libevent.c - * \brief Wrappers and utility functions for Libevent. - */ - -#include "orconfig.h" -#include "compat.h" -#define COMPAT_LIBEVENT_PRIVATE -#include "compat_libevent.h" - -#include "crypto_rand.h" - -#include "util.h" -#include "torlog.h" - -#include <event2/event.h> -#include <event2/thread.h> - -/** A string which, if it appears in a libevent log, should be ignored. */ -static const char *suppress_msg = NULL; -/** Callback function passed to event_set_log() so we can intercept - * log messages from libevent. */ -STATIC void -libevent_logging_callback(int severity, const char *msg) -{ - char buf[1024]; - size_t n; - if (suppress_msg && strstr(msg, suppress_msg)) - return; - n = strlcpy(buf, msg, sizeof(buf)); - if (n && n < sizeof(buf) && buf[n-1] == '\n') { - buf[n-1] = '\0'; - } - switch (severity) { - case _EVENT_LOG_DEBUG: - log_debug(LD_NOCB|LD_NET, "Message from libevent: %s", buf); - break; - case _EVENT_LOG_MSG: - log_info(LD_NOCB|LD_NET, "Message from libevent: %s", buf); - break; - case _EVENT_LOG_WARN: - log_warn(LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf); - break; - case _EVENT_LOG_ERR: - log_err(LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf); - break; - default: - log_warn(LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s", - severity, buf); - break; - } -} -/** Set hook to intercept log messages from libevent. */ -void -configure_libevent_logging(void) -{ - event_set_log_callback(libevent_logging_callback); -} - -/** Ignore any libevent log message that contains <b>msg</b>. */ -void -suppress_libevent_log_msg(const char *msg) -{ - suppress_msg = msg; -} - -/* Wrapper for event_free() that tolerates tor_event_free(NULL) */ -void -tor_event_free_(struct event *ev) -{ - if (ev == NULL) - return; - event_free(ev); -} - -/** Global event base for use by the main thread. */ -static struct event_base *the_event_base = NULL; - -/** - * @defgroup postloop post-loop event helpers - * - * If we're not careful, Libevent can susceptible to infinite event chains: - * one event can activate another, whose callback activates another, whose - * callback activates another, ad infinitum. While this is happening, - * Libevent won't be checking timeouts, socket-based events, signals, and so - * on. - * - * We solve this problem by marking some events as "post-loop". A post-loop - * event behaves like any ordinary event, but any events that _it_ activates - * cannot run until Libevent has checked for other events at least once. - * - * @{ */ - -/** - * An event that stops Libevent from running any more events on the current - * iteration of its loop, until it has re-checked for socket events, signal - * events, timeouts, etc. - */ -static struct event *rescan_mainloop_ev = NULL; - -/** - * Callback to implement rescan_mainloop_ev: it simply exits the mainloop, - * and relies on Tor to re-enter the mainloop since no error has occurred. - */ -static void -rescan_mainloop_cb(evutil_socket_t fd, short events, void *arg) -{ - (void)fd; - (void)events; - struct event_base *the_base = arg; - event_base_loopbreak(the_base); -} - -/** @} */ - -/* This is what passes for version detection on OSX. We set - * MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before - * 10.4.0 (aka 1040). */ -#ifdef __APPLE__ -#ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ -#define MACOSX_KQUEUE_IS_BROKEN \ - (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040) -#else -#define MACOSX_KQUEUE_IS_BROKEN 0 -#endif /* defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) */ -#endif /* defined(__APPLE__) */ - -/** Initialize the Libevent library and set up the event base. */ -void -tor_libevent_initialize(tor_libevent_cfg *torcfg) -{ - tor_assert(the_event_base == NULL); - /* some paths below don't use torcfg, so avoid unused variable warnings */ - (void)torcfg; - - { - int attempts = 0; - struct event_config *cfg; - - ++attempts; - cfg = event_config_new(); - tor_assert(cfg); - - /* Telling Libevent not to try to turn locking on can avoid a needless - * socketpair() attempt. */ - event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK); - - if (torcfg->num_cpus > 0) - event_config_set_num_cpus_hint(cfg, torcfg->num_cpus); - - /* We can enable changelist support with epoll, since we don't give - * Libevent any dup'd fds. This lets us avoid some syscalls. */ - event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST); - - the_event_base = event_base_new_with_config(cfg); - - event_config_free(cfg); - } - - if (!the_event_base) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue."); - exit(1); // exit ok: libevent is broken. - /* LCOV_EXCL_STOP */ - } - - rescan_mainloop_ev = event_new(the_event_base, -1, 0, - rescan_mainloop_cb, the_event_base); - if (!rescan_mainloop_ev) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL, "Unable to create rescan event: cannot continue."); - exit(1); // exit ok: libevent is broken. - /* LCOV_EXCL_STOP */ - } - - log_info(LD_GENERAL, - "Initialized libevent version %s using method %s. Good.", - event_get_version(), tor_libevent_get_method()); -} - -/** Return the current Libevent event base that we're set up to use. */ -MOCK_IMPL(struct event_base *, -tor_libevent_get_base, (void)) -{ - tor_assert(the_event_base != NULL); - return the_event_base; -} - -/** Return the name of the Libevent backend we're using. */ -const char * -tor_libevent_get_method(void) -{ - return event_base_get_method(the_event_base); -} - -/** Return a string representation of the version of the currently running - * version of Libevent. */ -const char * -tor_libevent_get_version_str(void) -{ - return event_get_version(); -} - -/** Return a string representation of the version of Libevent that was used -* at compilation time. */ -const char * -tor_libevent_get_header_version_str(void) -{ - return LIBEVENT_VERSION; -} - -/** Represents a timer that's run every N microseconds by Libevent. */ -struct periodic_timer_t { - /** Underlying event used to implement this periodic event. */ - struct event *ev; - /** The callback we'll be invoking whenever the event triggers */ - void (*cb)(struct periodic_timer_t *, void *); - /** User-supplied data for the callback */ - void *data; -}; - -/** Libevent callback to implement a periodic event. */ -static void -periodic_timer_cb(evutil_socket_t fd, short what, void *arg) -{ - periodic_timer_t *timer = arg; - (void) what; - (void) fd; - timer->cb(timer, timer->data); -} - -/** Create and schedule a new timer that will run every <b>tv</b> in - * the event loop of <b>base</b>. When the timer fires, it will - * run the timer in <b>cb</b> with the user-supplied data in <b>data</b>. */ -periodic_timer_t * -periodic_timer_new(struct event_base *base, - const struct timeval *tv, - void (*cb)(periodic_timer_t *timer, void *data), - void *data) -{ - periodic_timer_t *timer; - tor_assert(base); - tor_assert(tv); - tor_assert(cb); - timer = tor_malloc_zero(sizeof(periodic_timer_t)); - if (!(timer->ev = tor_event_new(base, -1, EV_PERSIST, - periodic_timer_cb, timer))) { - tor_free(timer); - return NULL; - } - timer->cb = cb; - timer->data = data; - periodic_timer_launch(timer, tv); - return timer; -} - -/** - * Launch the timer <b>timer</b> to run at <b>tv</b> from now, and every - * <b>tv</b> thereafter. - * - * If the timer is already enabled, this function does nothing. - */ -void -periodic_timer_launch(periodic_timer_t *timer, const struct timeval *tv) -{ - tor_assert(timer); - if (event_pending(timer->ev, EV_TIMEOUT, NULL)) - return; - event_add(timer->ev, tv); -} - -/** - * Disable the provided <b>timer</b>, but do not free it. - * - * You can reenable the same timer later with periodic_timer_launch. - * - * If the timer is already disabled, this function does nothing. - */ -void -periodic_timer_disable(periodic_timer_t *timer) -{ - tor_assert(timer); - (void) event_del(timer->ev); -} - -/** Stop and free a periodic timer */ -void -periodic_timer_free_(periodic_timer_t *timer) -{ - if (!timer) - return; - tor_event_free(timer->ev); - tor_free(timer); -} - -/** - * Type used to represent events that run directly from the main loop, - * either because they are activated from elsewhere in the code, or - * because they have a simple timeout. - * - * We use this type to avoid exposing Libevent's API throughout the rest - * of the codebase. - * - * This type can't be used for all events: it doesn't handle events that - * are triggered by signals or by sockets. - */ -struct mainloop_event_t { - struct event *ev; - void (*cb)(mainloop_event_t *, void *); - void *userdata; -}; - -/** - * Internal: Implements mainloop event using a libevent event. - */ -static void -mainloop_event_cb(evutil_socket_t fd, short what, void *arg) -{ - (void)fd; - (void)what; - mainloop_event_t *mev = arg; - mev->cb(mev, mev->userdata); -} - -/** - * As mainloop_event_cb, but implements a post-loop event. - */ -static void -mainloop_event_postloop_cb(evutil_socket_t fd, short what, void *arg) -{ - (void)fd; - (void)what; - - /* Note that if rescan_mainloop_ev is already activated, - * event_active() will do nothing: only the first post-loop event that - * happens each time through the event loop will cause it to be - * activated. - * - * Because event_active() puts events on a FIFO queue, every event - * that is made active _after_ rescan_mainloop_ev will get its - * callback run after rescan_mainloop_cb is called -- that is, on the - * next iteration of the loop. - */ - event_active(rescan_mainloop_ev, EV_READ, 1); - - mainloop_event_t *mev = arg; - mev->cb(mev, mev->userdata); -} - -/** - * Helper for mainloop_event_new() and mainloop_event_postloop_new(). - */ -static mainloop_event_t * -mainloop_event_new_impl(int postloop, - void (*cb)(mainloop_event_t *, void *), - void *userdata) -{ - tor_assert(cb); - - struct event_base *base = tor_libevent_get_base(); - mainloop_event_t *mev = tor_malloc_zero(sizeof(mainloop_event_t)); - mev->ev = tor_event_new(base, -1, 0, - postloop ? mainloop_event_postloop_cb : mainloop_event_cb, - mev); - tor_assert(mev->ev); - mev->cb = cb; - mev->userdata = userdata; - return mev; -} - -/** - * Create and return a new mainloop_event_t to run the function <b>cb</b>. - * - * When run, the callback function will be passed the mainloop_event_t - * and <b>userdata</b> as its arguments. The <b>userdata</b> pointer - * must remain valid for as long as the mainloop_event_t event exists: - * it is your responsibility to free it. - * - * The event is not scheduled by default: Use mainloop_event_activate() - * or mainloop_event_schedule() to make it run. - */ -mainloop_event_t * -mainloop_event_new(void (*cb)(mainloop_event_t *, void *), - void *userdata) -{ - return mainloop_event_new_impl(0, cb, userdata); -} - -/** - * As mainloop_event_new(), but create a post-loop event. - * - * A post-loop event behaves like any ordinary event, but any events - * that _it_ activates cannot run until Libevent has checked for other - * events at least once. - */ -mainloop_event_t * -mainloop_event_postloop_new(void (*cb)(mainloop_event_t *, void *), - void *userdata) -{ - return mainloop_event_new_impl(1, cb, userdata); -} - -/** - * Schedule <b>event</b> to run in the main loop, immediately. If it is - * not scheduled, it will run anyway. If it is already scheduled to run - * later, it will run now instead. This function will have no effect if - * the event is already scheduled to run. - * - * This function may only be called from the main thread. - */ -void -mainloop_event_activate(mainloop_event_t *event) -{ - tor_assert(event); - event_active(event->ev, EV_READ, 1); -} - -/** Schedule <b>event</b> to run in the main loop, after a delay of <b>tv</b>. - * - * If the event is scheduled for a different time, cancel it and run - * after this delay instead. If the event is currently pending to run - * <em>now</b>, has no effect. - * - * Do not call this function with <b>tv</b> == NULL -- use - * mainloop_event_activate() instead. - * - * This function may only be called from the main thread. - */ -int -mainloop_event_schedule(mainloop_event_t *event, const struct timeval *tv) -{ - tor_assert(event); - if (BUG(tv == NULL)) { - // LCOV_EXCL_START - mainloop_event_activate(event); - return 0; - // LCOV_EXCL_STOP - } - return event_add(event->ev, tv); -} - -/** Cancel <b>event</b> if it is currently active or pending. (Do nothing if - * the event is not currently active or pending.) */ -void -mainloop_event_cancel(mainloop_event_t *event) -{ - if (!event) - return; - (void) event_del(event->ev); -} - -/** Cancel <b>event</b> and release all storage associated with it. */ -void -mainloop_event_free_(mainloop_event_t *event) -{ - if (!event) - return; - tor_event_free(event->ev); - memset(event, 0xb8, sizeof(*event)); - tor_free(event); -} - -int -tor_init_libevent_rng(void) -{ - int rv = 0; - char buf[256]; - if (evutil_secure_rng_init() < 0) { - rv = -1; - } - crypto_rand(buf, 32); -#ifdef HAVE_EVUTIL_SECURE_RNG_ADD_BYTES - evutil_secure_rng_add_bytes(buf, 32); -#endif - evutil_secure_rng_get_bytes(buf, sizeof(buf)); - return rv; -} - -/** - * Un-initialize libevent in preparation for an exit - */ -void -tor_libevent_free_all(void) -{ - tor_event_free(rescan_mainloop_ev); - if (the_event_base) - event_base_free(the_event_base); - the_event_base = NULL; -} - -/** - * Run the event loop for the provided event_base, handling events until - * something stops it. If <b>once</b> is set, then just poll-and-run - * once, then exit. Return 0 on success, -1 if an error occurred, or 1 - * if we exited because no events were pending or active. - * - * This isn't reentrant or multithreaded. - */ -int -tor_libevent_run_event_loop(struct event_base *base, int once) -{ - const int flags = once ? EVLOOP_ONCE : 0; - return event_base_loop(base, flags); -} - -/** Tell the event loop to exit after <b>delay</b>. If <b>delay</b> is NULL, - * instead exit after we're done running the currently active events. */ -void -tor_libevent_exit_loop_after_delay(struct event_base *base, - const struct timeval *delay) -{ - event_base_loopexit(base, delay); -} - -/** Tell the event loop to exit after running whichever callback is currently - * active. */ -void -tor_libevent_exit_loop_after_callback(struct event_base *base) -{ - event_base_loopbreak(base); -} - -#if defined(TOR_UNIT_TESTS) -/** For testing: called post-fork to make libevent reinitialize - * kernel structures. */ -void -tor_libevent_postfork(void) -{ - int r = event_reinit(tor_libevent_get_base()); - tor_assert(r == 0); -} -#endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h deleted file mode 100644 index 286a268122..0000000000 --- a/src/common/compat_libevent.h +++ /dev/null @@ -1,98 +0,0 @@ -/* Copyright (c) 2009-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_COMPAT_LIBEVENT_H -#define TOR_COMPAT_LIBEVENT_H - -#include "orconfig.h" -#include "testsupport.h" - -void configure_libevent_logging(void); -void suppress_libevent_log_msg(const char *msg); - -#define tor_event_new event_new -#define tor_evtimer_new evtimer_new -#define tor_evsignal_new evsignal_new -#define tor_evdns_add_server_port(sock, tcp, cb, data) \ - evdns_add_server_port_with_base(tor_libevent_get_base(), \ - (sock),(tcp),(cb),(data)); - -struct event; -struct event_base; - -void tor_event_free_(struct event *ev); -#define tor_event_free(ev) \ - FREE_AND_NULL(struct event, tor_event_free_, (ev)) - -typedef struct periodic_timer_t periodic_timer_t; - -periodic_timer_t *periodic_timer_new(struct event_base *base, - const struct timeval *tv, - void (*cb)(periodic_timer_t *timer, void *data), - void *data); -void periodic_timer_free_(periodic_timer_t *); -void periodic_timer_launch(periodic_timer_t *, const struct timeval *tv); -void periodic_timer_disable(periodic_timer_t *); -#define periodic_timer_free(t) \ - FREE_AND_NULL(periodic_timer_t, periodic_timer_free_, (t)) - -typedef struct mainloop_event_t mainloop_event_t; -mainloop_event_t *mainloop_event_new(void (*cb)(mainloop_event_t *, void *), - void *userdata); -mainloop_event_t * mainloop_event_postloop_new( - void (*cb)(mainloop_event_t *, void *), - void *userdata); -void mainloop_event_activate(mainloop_event_t *event); -int mainloop_event_schedule(mainloop_event_t *event, - const struct timeval *delay); -void mainloop_event_cancel(mainloop_event_t *event); -void mainloop_event_free_(mainloop_event_t *event); -#define mainloop_event_free(event) \ - FREE_AND_NULL(mainloop_event_t, mainloop_event_free_, (event)) - -/** Defines a configuration for using libevent with Tor: passed as an argument - * to tor_libevent_initialize() to describe how we want to set up. */ -typedef struct tor_libevent_cfg { - /** How many CPUs should we use (not currently useful). */ - int num_cpus; - /** How many milliseconds should we allow between updating bandwidth limits? - * (Not currently useful). */ - int msec_per_tick; -} tor_libevent_cfg; - -void tor_libevent_initialize(tor_libevent_cfg *cfg); -MOCK_DECL(struct event_base *, tor_libevent_get_base, (void)); -const char *tor_libevent_get_method(void); -void tor_check_libevent_header_compatibility(void); -const char *tor_libevent_get_version_str(void); -const char *tor_libevent_get_header_version_str(void); -void tor_libevent_free_all(void); - -int tor_init_libevent_rng(void); - -#ifdef TOR_UNIT_TESTS -void tor_libevent_postfork(void); -#endif - -int tor_libevent_run_event_loop(struct event_base *base, int once); -void tor_libevent_exit_loop_after_delay(struct event_base *base, - const struct timeval *delay); -void tor_libevent_exit_loop_after_callback(struct event_base *base); - -#ifdef COMPAT_LIBEVENT_PRIVATE - -/** Macro: returns the number of a Libevent version as a 4-byte number, - with the first three bytes representing the major, minor, and patchlevel - respectively of the library. The fourth byte is unused. - - This is equivalent to the format of LIBEVENT_VERSION_NUMBER on Libevent - 2.0.1 or later. */ -#define V(major, minor, patch) \ - (((major) << 24) | ((minor) << 16) | ((patch) << 8)) - -STATIC void -libevent_logging_callback(int severity, const char *msg); -#endif /* defined(COMPAT_LIBEVENT_PRIVATE) */ - -#endif /* !defined(TOR_COMPAT_LIBEVENT_H) */ - diff --git a/src/common/compat_openssl.h b/src/common/compat_openssl.h deleted file mode 100644 index d1481fb46c..0000000000 --- a/src/common/compat_openssl.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_COMPAT_OPENSSL_H -#define TOR_COMPAT_OPENSSL_H - -#include <openssl/opensslv.h> -#include "crypto_openssl_mgt.h" - -/** - * \file compat_openssl.h - * - * \brief compatibility definitions for working with different openssl forks - **/ - -#if !defined(LIBRESSL_VERSION_NUMBER) && \ - OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,1) -#error "We require OpenSSL >= 1.0.1" -#endif - -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && \ - ! defined(LIBRESSL_VERSION_NUMBER) -/* We define this macro if we're trying to build with the majorly refactored - * API in OpenSSL 1.1 */ -#define OPENSSL_1_1_API -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && ... */ - -#ifndef OPENSSL_VERSION -#define OPENSSL_VERSION SSLEAY_VERSION -#endif - -#ifndef OPENSSL_1_1_API -#define OpenSSL_version(v) SSLeay_version(v) -#define OpenSSL_version_num() SSLeay() -#define RAND_OpenSSL() RAND_SSLeay() -#define STATE_IS_SW_SERVER_HELLO(st) \ - (((st) == SSL3_ST_SW_SRVR_HELLO_A) || \ - ((st) == SSL3_ST_SW_SRVR_HELLO_B)) -#define OSSL_HANDSHAKE_STATE int -#define CONST_IF_OPENSSL_1_1_API -#else /* !(!defined(OPENSSL_1_1_API)) */ -#define STATE_IS_SW_SERVER_HELLO(st) \ - ((st) == TLS_ST_SW_SRVR_HELLO) -#define CONST_IF_OPENSSL_1_1_API const -#endif /* !defined(OPENSSL_1_1_API) */ - -#endif /* !defined(TOR_COMPAT_OPENSSL_H) */ - diff --git a/src/common/compat_pthreads.c b/src/common/compat_pthreads.c deleted file mode 100644 index 002274c469..0000000000 --- a/src/common/compat_pthreads.c +++ /dev/null @@ -1,350 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat_pthreads.c - * - * \brief Implementation for the pthreads-based multithreading backend - * functions. - */ - -#include "orconfig.h" -#include <pthread.h> -#include <signal.h> -#include <time.h> - -#include "compat.h" -#include "torlog.h" -#include "util.h" - -/** Wraps a void (*)(void*) function and its argument so we can - * invoke them in a way pthreads would expect. - */ -typedef struct tor_pthread_data_t { - void (*func)(void *); - void *data; -} tor_pthread_data_t; -/** Given a tor_pthread_data_t <b>_data</b>, call _data->func(d->data) - * and free _data. Used to make sure we can call functions the way pthread - * expects. */ -static void * -tor_pthread_helper_fn(void *_data) -{ - tor_pthread_data_t *data = _data; - void (*func)(void*); - void *arg; - /* mask signals to worker threads to avoid SIGPIPE, etc */ - sigset_t sigs; - /* We're in a subthread; don't handle any signals here. */ - sigfillset(&sigs); - pthread_sigmask(SIG_SETMASK, &sigs, NULL); - - func = data->func; - arg = data->data; - tor_free(_data); - func(arg); - return NULL; -} -/** - * A pthread attribute to make threads start detached. - */ -static pthread_attr_t attr_detached; -/** True iff we've called tor_threads_init() */ -static int threads_initialized = 0; - -/** Minimalist interface to run a void function in the background. On - * Unix calls pthread_create, on win32 calls beginthread. Returns -1 on - * failure. - * func should not return, but rather should call spawn_exit. - * - * NOTE: if <b>data</b> is used, it should not be allocated on the stack, - * since in a multithreaded environment, there is no way to be sure that - * the caller's stack will still be around when the called function is - * running. - */ -int -spawn_func(void (*func)(void *), void *data) -{ - pthread_t thread; - tor_pthread_data_t *d; - if (PREDICT_UNLIKELY(!threads_initialized)) { - tor_threads_init(); - } - d = tor_malloc(sizeof(tor_pthread_data_t)); - d->data = data; - d->func = func; - if (pthread_create(&thread, &attr_detached, tor_pthread_helper_fn, d)) { - tor_free(d); - return -1; - } - - return 0; -} - -/** End the current thread/process. - */ -void -spawn_exit(void) -{ - pthread_exit(NULL); -} - -/** A mutex attribute that we're going to use to tell pthreads that we want - * "recursive" mutexes (i.e., once we can re-lock if we're already holding - * them.) */ -static pthread_mutexattr_t attr_recursive; - -/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set - * up with tor_mutex_init() or tor_mutex_new(); not both. */ -void -tor_mutex_init(tor_mutex_t *mutex) -{ - if (PREDICT_UNLIKELY(!threads_initialized)) - tor_threads_init(); // LCOV_EXCL_LINE - const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d creating a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} - -/** As tor_mutex_init, but initialize a mutex suitable that may be - * non-recursive, if the OS supports that. */ -void -tor_mutex_init_nonrecursive(tor_mutex_t *mutex) -{ - int err; - if (!threads_initialized) - tor_threads_init(); // LCOV_EXCL_LINE - err = pthread_mutex_init(&mutex->mutex, NULL); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d creating a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} - -/** Wait until <b>m</b> is free, then acquire it. */ -void -tor_mutex_acquire(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_lock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d locking a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} -/** Release the lock <b>m</b> so another thread can have it. */ -void -tor_mutex_release(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_unlock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d unlocking a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} -/** Clean up the mutex <b>m</b> so that it no longer uses any system - * resources. Does not free <b>m</b>. This function must only be called on - * mutexes from tor_mutex_init(). */ -void -tor_mutex_uninit(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_destroy(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d destroying a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} -/** Return an integer representing this thread. */ -unsigned long -tor_get_thread_id(void) -{ - union { - pthread_t thr; - unsigned long id; - } r; - r.thr = pthread_self(); - return r.id; -} - -/* Conditions. */ - -/** Initialize an already-allocated condition variable. */ -int -tor_cond_init(tor_cond_t *cond) -{ - pthread_condattr_t condattr; - - memset(cond, 0, sizeof(tor_cond_t)); - /* Default condition attribute. Might be used if clock monotonic is - * available else this won't affect anything. */ - if (pthread_condattr_init(&condattr)) { - return -1; - } - -#if defined(HAVE_CLOCK_GETTIME) -#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \ - defined(CLOCK_MONOTONIC) - /* Use monotonic time so when we timedwait() on it, any clock adjustment - * won't affect the timeout value. */ - if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) { - return -1; - } -#define USE_COND_CLOCK CLOCK_MONOTONIC -#else /* !(defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && ...) */ - /* On OSX Sierra, there is no pthread_condattr_setclock, so we are stuck - * with the realtime clock. - */ -#define USE_COND_CLOCK CLOCK_REALTIME -#endif /* defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && ... */ -#endif /* defined(HAVE_CLOCK_GETTIME) */ - if (pthread_cond_init(&cond->cond, &condattr)) { - return -1; - } - return 0; -} - -/** Release all resources held by <b>cond</b>, but do not free <b>cond</b> - * itself. */ -void -tor_cond_uninit(tor_cond_t *cond) -{ - if (pthread_cond_destroy(&cond->cond)) { - // LCOV_EXCL_START - log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno)); - return; - // LCOV_EXCL_STOP - } -} -/** Wait until one of the tor_cond_signal functions is called on <b>cond</b>. - * (If <b>tv</b> is set, and that amount of time passes with no signal to - * <b>cond</b>, return anyway. All waiters on the condition must wait holding - * the same <b>mutex</b>. All signallers should hold that mutex. The mutex - * needs to have been allocated with tor_mutex_init_for_cond(). - * - * Returns 0 on success, -1 on failure, 1 on timeout. */ -int -tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv) -{ - int r; - if (tv == NULL) { - while (1) { - r = pthread_cond_wait(&cond->cond, &mutex->mutex); - if (r == EINTR) { - /* EINTR should be impossible according to POSIX, but POSIX, like the - * Pirate's Code, is apparently treated "more like what you'd call - * guidelines than actual rules." */ - continue; // LCOV_EXCL_LINE - } - return r ? -1 : 0; - } - } else { - struct timeval tvnow, tvsum; - struct timespec ts; - while (1) { -#if defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK) - if (clock_gettime(USE_COND_CLOCK, &ts) < 0) { - return -1; - } - tvnow.tv_sec = ts.tv_sec; - tvnow.tv_usec = (int)(ts.tv_nsec / 1000); - timeradd(tv, &tvnow, &tvsum); -#else /* !(defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK)) */ - if (gettimeofday(&tvnow, NULL) < 0) - return -1; - timeradd(tv, &tvnow, &tvsum); -#endif /* defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK) */ - - ts.tv_sec = tvsum.tv_sec; - ts.tv_nsec = tvsum.tv_usec * 1000; - - r = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &ts); - if (r == 0) - return 0; - else if (r == ETIMEDOUT) - return 1; - else if (r == EINTR) - continue; - else - return -1; - } - } -} -/** Wake up one of the waiters on <b>cond</b>. */ -void -tor_cond_signal_one(tor_cond_t *cond) -{ - pthread_cond_signal(&cond->cond); -} -/** Wake up all of the waiters on <b>cond</b>. */ -void -tor_cond_signal_all(tor_cond_t *cond) -{ - pthread_cond_broadcast(&cond->cond); -} - -int -tor_threadlocal_init(tor_threadlocal_t *threadlocal) -{ - int err = pthread_key_create(&threadlocal->key, NULL); - return err ? -1 : 0; -} - -void -tor_threadlocal_destroy(tor_threadlocal_t *threadlocal) -{ - pthread_key_delete(threadlocal->key); - memset(threadlocal, 0, sizeof(tor_threadlocal_t)); -} - -void * -tor_threadlocal_get(tor_threadlocal_t *threadlocal) -{ - return pthread_getspecific(threadlocal->key); -} - -void -tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value) -{ - int err = pthread_setspecific(threadlocal->key, value); - tor_assert(err == 0); -} - -/** Set up common structures for use by threading. */ -void -tor_threads_init(void) -{ - if (!threads_initialized) { - pthread_mutexattr_init(&attr_recursive); - pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE); - const int ret1 = pthread_attr_init(&attr_detached); - tor_assert(ret1 == 0); -#ifndef PTHREAD_CREATE_DETACHED -#define PTHREAD_CREATE_DETACHED 1 -#endif - const int ret2 = - pthread_attr_setdetachstate(&attr_detached, PTHREAD_CREATE_DETACHED); - tor_assert(ret2 == 0); - threads_initialized = 1; - set_main_thread(); - } -} - diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c deleted file mode 100644 index 9f64c06342..0000000000 --- a/src/common/compat_threads.c +++ /dev/null @@ -1,406 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat_threads.c - * - * \brief Cross-platform threading and inter-thread communication logic. - * (Platform-specific parts are written in the other compat_*threads - * modules.) - */ - -#include "orconfig.h" -#include <stdlib.h> -#include "compat.h" -#include "compat_threads.h" - -#include "util.h" -#include "torlog.h" - -#ifdef HAVE_SYS_EVENTFD_H -#include <sys/eventfd.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -/** Return a newly allocated, ready-for-use mutex. */ -tor_mutex_t * -tor_mutex_new(void) -{ - tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); - tor_mutex_init(m); - return m; -} -/** Return a newly allocated, ready-for-use mutex. This one might be - * non-recursive, if that's faster. */ -tor_mutex_t * -tor_mutex_new_nonrecursive(void) -{ - tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); - tor_mutex_init_nonrecursive(m); - return m; -} -/** Release all storage and system resources held by <b>m</b>. */ -void -tor_mutex_free_(tor_mutex_t *m) -{ - if (!m) - return; - tor_mutex_uninit(m); - tor_free(m); -} - -/** Allocate and return a new condition variable. */ -tor_cond_t * -tor_cond_new(void) -{ - tor_cond_t *cond = tor_malloc(sizeof(tor_cond_t)); - if (BUG(tor_cond_init(cond)<0)) - tor_free(cond); // LCOV_EXCL_LINE - return cond; -} - -/** Free all storage held in <b>c</b>. */ -void -tor_cond_free_(tor_cond_t *c) -{ - if (!c) - return; - tor_cond_uninit(c); - tor_free(c); -} - -/** Identity of the "main" thread */ -static unsigned long main_thread_id = -1; - -/** Start considering the current thread to be the 'main thread'. This has - * no effect on anything besides in_main_thread(). */ -void -set_main_thread(void) -{ - main_thread_id = tor_get_thread_id(); -} -/** Return true iff called from the main thread. */ -int -in_main_thread(void) -{ - return main_thread_id == tor_get_thread_id(); -} - -#if defined(HAVE_EVENTFD) || defined(HAVE_PIPE) -/* As write(), but retry on EINTR, and return the negative error code on - * error. */ -static int -write_ni(int fd, const void *buf, size_t n) -{ - int r; - again: - r = (int) write(fd, buf, n); - if (r < 0) { - if (errno == EINTR) - goto again; - else - return -errno; - } - return r; -} -/* As read(), but retry on EINTR, and return the negative error code on error. - */ -static int -read_ni(int fd, void *buf, size_t n) -{ - int r; - again: - r = (int) read(fd, buf, n); - if (r < 0) { - if (errno == EINTR) - goto again; - else - return -errno; - } - return r; -} -#endif /* defined(HAVE_EVENTFD) || defined(HAVE_PIPE) */ - -/** As send(), but retry on EINTR, and return the negative error code on - * error. */ -static int -send_ni(int fd, const void *buf, size_t n, int flags) -{ - int r; - again: - r = (int) send(fd, buf, n, flags); - if (r < 0) { - int error = tor_socket_errno(fd); - if (ERRNO_IS_EINTR(error)) - goto again; - else - return -error; - } - return r; -} - -/** As recv(), but retry on EINTR, and return the negative error code on - * error. */ -static int -recv_ni(int fd, void *buf, size_t n, int flags) -{ - int r; - again: - r = (int) recv(fd, buf, n, flags); - if (r < 0) { - int error = tor_socket_errno(fd); - if (ERRNO_IS_EINTR(error)) - goto again; - else - return -error; - } - return r; -} - -#ifdef HAVE_EVENTFD -/* Increment the event count on an eventfd <b>fd</b> */ -static int -eventfd_alert(int fd) -{ - uint64_t u = 1; - int r = write_ni(fd, (void*)&u, sizeof(u)); - if (r < 0 && -r != EAGAIN) - return -1; - return 0; -} - -/* Drain all events from an eventfd <b>fd</b>. */ -static int -eventfd_drain(int fd) -{ - uint64_t u = 0; - int r = read_ni(fd, (void*)&u, sizeof(u)); - if (r < 0 && -r != EAGAIN) - return r; - return 0; -} -#endif /* defined(HAVE_EVENTFD) */ - -#ifdef HAVE_PIPE -/** Send a byte over a pipe. Return 0 on success or EAGAIN; -1 on error */ -static int -pipe_alert(int fd) -{ - ssize_t r = write_ni(fd, "x", 1); - if (r < 0 && -r != EAGAIN) - return (int)r; - return 0; -} - -/** Drain all input from a pipe <b>fd</b> and ignore it. Return 0 on - * success, -1 on error. */ -static int -pipe_drain(int fd) -{ - char buf[32]; - ssize_t r; - do { - r = read_ni(fd, buf, sizeof(buf)); - } while (r > 0); - if (r < 0 && errno != EAGAIN) - return -errno; - /* A value of r = 0 means EOF on the fd so successfully drained. */ - return 0; -} -#endif /* defined(HAVE_PIPE) */ - -/** Send a byte on socket <b>fd</b>t. Return 0 on success or EAGAIN, - * -1 on error. */ -static int -sock_alert(tor_socket_t fd) -{ - ssize_t r = send_ni(fd, "x", 1, 0); - if (r < 0 && !ERRNO_IS_EAGAIN(-r)) - return (int)r; - return 0; -} - -/** Drain all the input from a socket <b>fd</b>, and ignore it. Return 0 on - * success, -errno on error. */ -static int -sock_drain(tor_socket_t fd) -{ - char buf[32]; - ssize_t r; - do { - r = recv_ni(fd, buf, sizeof(buf), 0); - } while (r > 0); - if (r < 0 && !ERRNO_IS_EAGAIN(-r)) - return (int)r; - /* A value of r = 0 means EOF on the fd so successfully drained. */ - return 0; -} - -/** Allocate a new set of alert sockets, and set the appropriate function - * pointers, in <b>socks_out</b>. */ -int -alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags) -{ - tor_socket_t socks[2] = { TOR_INVALID_SOCKET, TOR_INVALID_SOCKET }; - -#ifdef HAVE_EVENTFD - /* First, we try the Linux eventfd() syscall. This gives a 64-bit counter - * associated with a single file descriptor. */ -#if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) - if (!(flags & ASOCKS_NOEVENTFD2)) - socks[0] = eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK); -#endif - if (socks[0] < 0 && !(flags & ASOCKS_NOEVENTFD)) { - socks[0] = eventfd(0,0); - if (socks[0] >= 0) { - if (fcntl(socks[0], F_SETFD, FD_CLOEXEC) < 0 || - set_socket_nonblocking(socks[0]) < 0) { - // LCOV_EXCL_START -- if eventfd succeeds, fcntl will. - tor_assert_nonfatal_unreached(); - close(socks[0]); - return -1; - // LCOV_EXCL_STOP - } - } - } - if (socks[0] >= 0) { - socks_out->read_fd = socks_out->write_fd = socks[0]; - socks_out->alert_fn = eventfd_alert; - socks_out->drain_fn = eventfd_drain; - return 0; - } -#endif /* defined(HAVE_EVENTFD) */ - -#ifdef HAVE_PIPE2 - /* Now we're going to try pipes. First type the pipe2() syscall, if we - * have it, so we can save some calls... */ - if (!(flags & ASOCKS_NOPIPE2) && - pipe2(socks, O_NONBLOCK|O_CLOEXEC) == 0) { - socks_out->read_fd = socks[0]; - socks_out->write_fd = socks[1]; - socks_out->alert_fn = pipe_alert; - socks_out->drain_fn = pipe_drain; - return 0; - } -#endif /* defined(HAVE_PIPE2) */ - -#ifdef HAVE_PIPE - /* Now try the regular pipe() syscall. Pipes have a bit lower overhead than - * socketpairs, fwict. */ - if (!(flags & ASOCKS_NOPIPE) && - pipe(socks) == 0) { - if (fcntl(socks[0], F_SETFD, FD_CLOEXEC) < 0 || - fcntl(socks[1], F_SETFD, FD_CLOEXEC) < 0 || - set_socket_nonblocking(socks[0]) < 0 || - set_socket_nonblocking(socks[1]) < 0) { - // LCOV_EXCL_START -- if pipe succeeds, you can fcntl the output - tor_assert_nonfatal_unreached(); - close(socks[0]); - close(socks[1]); - return -1; - // LCOV_EXCL_STOP - } - socks_out->read_fd = socks[0]; - socks_out->write_fd = socks[1]; - socks_out->alert_fn = pipe_alert; - socks_out->drain_fn = pipe_drain; - return 0; - } -#endif /* defined(HAVE_PIPE) */ - - /* If nothing else worked, fall back on socketpair(). */ - if (!(flags & ASOCKS_NOSOCKETPAIR) && - tor_socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == 0) { - if (set_socket_nonblocking(socks[0]) < 0 || - set_socket_nonblocking(socks[1])) { - // LCOV_EXCL_START -- if socketpair worked, you can make it nonblocking. - tor_assert_nonfatal_unreached(); - tor_close_socket(socks[0]); - tor_close_socket(socks[1]); - return -1; - // LCOV_EXCL_STOP - } - socks_out->read_fd = socks[0]; - socks_out->write_fd = socks[1]; - socks_out->alert_fn = sock_alert; - socks_out->drain_fn = sock_drain; - return 0; - } - return -1; -} - -/** Close the sockets in <b>socks</b>. */ -void -alert_sockets_close(alert_sockets_t *socks) -{ - if (socks->alert_fn == sock_alert) { - /* they are sockets. */ - tor_close_socket(socks->read_fd); - tor_close_socket(socks->write_fd); - } else { - close(socks->read_fd); - if (socks->write_fd != socks->read_fd) - close(socks->write_fd); - } - socks->read_fd = socks->write_fd = -1; -} - -#ifndef HAVE_WORKING_STDATOMIC -/** Initialize a new atomic counter with the value 0 */ -void -atomic_counter_init(atomic_counter_t *counter) -{ - memset(counter, 0, sizeof(*counter)); - tor_mutex_init_nonrecursive(&counter->mutex); -} -/** Clean up all resources held by an atomic counter. */ -void -atomic_counter_destroy(atomic_counter_t *counter) -{ - tor_mutex_uninit(&counter->mutex); - memset(counter, 0, sizeof(*counter)); -} -/** Add a value to an atomic counter. */ -void -atomic_counter_add(atomic_counter_t *counter, size_t add) -{ - tor_mutex_acquire(&counter->mutex); - counter->val += add; - tor_mutex_release(&counter->mutex); -} -/** Subtract a value from an atomic counter. */ -void -atomic_counter_sub(atomic_counter_t *counter, size_t sub) -{ - // this relies on unsigned overflow, but that's fine. - atomic_counter_add(counter, -sub); -} -/** Return the current value of an atomic counter */ -size_t -atomic_counter_get(atomic_counter_t *counter) -{ - size_t val; - tor_mutex_acquire(&counter->mutex); - val = counter->val; - tor_mutex_release(&counter->mutex); - return val; -} -/** Replace the value of an atomic counter; return the old one. */ -size_t -atomic_counter_exchange(atomic_counter_t *counter, size_t newval) -{ - size_t oldval; - tor_mutex_acquire(&counter->mutex); - oldval = counter->val; - counter->val = newval; - tor_mutex_release(&counter->mutex); - return oldval; -} -#endif /* !defined(HAVE_WORKING_STDATOMIC) */ diff --git a/src/common/compat_threads.h b/src/common/compat_threads.h deleted file mode 100644 index 8bf8225689..0000000000 --- a/src/common/compat_threads.h +++ /dev/null @@ -1,226 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_COMPAT_THREADS_H -#define TOR_COMPAT_THREADS_H - -#include "orconfig.h" -#include "torint.h" -#include "testsupport.h" - -#if defined(HAVE_PTHREAD_H) && !defined(_WIN32) -#include <pthread.h> -#endif - -#if defined(HAVE_STDATOMIC_H) && defined(STDATOMIC_WORKS) -#define HAVE_WORKING_STDATOMIC -#endif - -#ifdef HAVE_WORKING_STDATOMIC -#include <stdatomic.h> -#endif - -#if defined(_WIN32) -#define USE_WIN32_THREADS -#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE) -#define USE_PTHREADS -#else -#error "No threading system was found" -#endif /* defined(_WIN32) || ... */ - -int spawn_func(void (*func)(void *), void *data); -void spawn_exit(void) ATTR_NORETURN; - -/* Because we use threads instead of processes on most platforms (Windows, - * Linux, etc), we need locking for them. On platforms with poor thread - * support or broken gethostbyname_r, these functions are no-ops. */ - -/** A generic lock structure for multithreaded builds. */ -typedef struct tor_mutex_t { -#if defined(USE_WIN32_THREADS) - /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */ - CRITICAL_SECTION mutex; -#elif defined(USE_PTHREADS) - /** Pthreads-only: with pthreads, we implement locks with - * pthread_mutex_t. */ - pthread_mutex_t mutex; -#else - /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */ - int _unused; -#endif /* defined(USE_WIN32_THREADS) || ... */ -} tor_mutex_t; - -tor_mutex_t *tor_mutex_new(void); -tor_mutex_t *tor_mutex_new_nonrecursive(void); -void tor_mutex_init(tor_mutex_t *m); -void tor_mutex_init_nonrecursive(tor_mutex_t *m); -void tor_mutex_acquire(tor_mutex_t *m); -void tor_mutex_release(tor_mutex_t *m); -void tor_mutex_free_(tor_mutex_t *m); -#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m)) -void tor_mutex_uninit(tor_mutex_t *m); -unsigned long tor_get_thread_id(void); -void tor_threads_init(void); - -/** Conditions need nonrecursive mutexes with pthreads. */ -#define tor_mutex_init_for_cond(m) tor_mutex_init_nonrecursive(m) - -void set_main_thread(void); -int in_main_thread(void); - -typedef struct tor_cond_t { -#ifdef USE_PTHREADS - pthread_cond_t cond; -#elif defined(USE_WIN32_THREADS) - HANDLE event; - - CRITICAL_SECTION lock; - int n_waiting; - int n_to_wake; - int generation; -#else -#error no known condition implementation. -#endif /* defined(USE_PTHREADS) || ... */ -} tor_cond_t; - -tor_cond_t *tor_cond_new(void); -void tor_cond_free_(tor_cond_t *cond); -#define tor_cond_free(c) FREE_AND_NULL(tor_cond_t, tor_cond_free_, (c)) -int tor_cond_init(tor_cond_t *cond); -void tor_cond_uninit(tor_cond_t *cond); -int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, - const struct timeval *tv); -void tor_cond_signal_one(tor_cond_t *cond); -void tor_cond_signal_all(tor_cond_t *cond); - -/** Helper type used to manage waking up the main thread while it's in - * the libevent main loop. Used by the work queue code. */ -typedef struct alert_sockets_s { - /* XXXX This structure needs a better name. */ - /** Socket that the main thread should listen for EV_READ events on. - * Note that this socket may be a regular fd on a non-Windows platform. - */ - tor_socket_t read_fd; - /** Socket to use when alerting the main thread. */ - tor_socket_t write_fd; - /** Function to alert the main thread */ - int (*alert_fn)(tor_socket_t write_fd); - /** Function to make the main thread no longer alerted. */ - int (*drain_fn)(tor_socket_t read_fd); -} alert_sockets_t; - -/* Flags to disable one or more alert_sockets backends. */ -#define ASOCKS_NOEVENTFD2 (1u<<0) -#define ASOCKS_NOEVENTFD (1u<<1) -#define ASOCKS_NOPIPE2 (1u<<2) -#define ASOCKS_NOPIPE (1u<<3) -#define ASOCKS_NOSOCKETPAIR (1u<<4) - -int alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags); -void alert_sockets_close(alert_sockets_t *socks); - -typedef struct tor_threadlocal_s { -#ifdef _WIN32 - DWORD index; -#else - pthread_key_t key; -#endif -} tor_threadlocal_t; - -/** Initialize a thread-local variable. - * - * After you call this function on a tor_threadlocal_t, you can call - * tor_threadlocal_set to change the current value of this variable for the - * current thread, and tor_threadlocal_get to retrieve the current value for - * the current thread. Each thread has its own value. - **/ -int tor_threadlocal_init(tor_threadlocal_t *threadlocal); -/** - * Release all resource associated with a thread-local variable. - */ -void tor_threadlocal_destroy(tor_threadlocal_t *threadlocal); -/** - * Return the current value of a thread-local variable for this thread. - * - * It's undefined behavior to use this function if the threadlocal hasn't - * been initialized, or has been destroyed. - */ -void *tor_threadlocal_get(tor_threadlocal_t *threadlocal); -/** - * Change the current value of a thread-local variable for this thread to - * <b>value</b>. - * - * It's undefined behavior to use this function if the threadlocal hasn't - * been initialized, or has been destroyed. - */ -void tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value); - -/** - * Atomic counter type; holds a size_t value. - */ -#ifdef HAVE_WORKING_STDATOMIC -typedef struct atomic_counter_t { - atomic_size_t val; -} atomic_counter_t; -#define ATOMIC_LINKAGE static -#else /* !(defined(HAVE_WORKING_STDATOMIC)) */ -typedef struct atomic_counter_t { - tor_mutex_t mutex; - size_t val; -} atomic_counter_t; -#define ATOMIC_LINKAGE -#endif /* defined(HAVE_WORKING_STDATOMIC) */ - -ATOMIC_LINKAGE void atomic_counter_init(atomic_counter_t *counter); -ATOMIC_LINKAGE void atomic_counter_destroy(atomic_counter_t *counter); -ATOMIC_LINKAGE void atomic_counter_add(atomic_counter_t *counter, size_t add); -ATOMIC_LINKAGE void atomic_counter_sub(atomic_counter_t *counter, size_t sub); -ATOMIC_LINKAGE size_t atomic_counter_get(atomic_counter_t *counter); -ATOMIC_LINKAGE size_t atomic_counter_exchange(atomic_counter_t *counter, - size_t newval); -#undef ATOMIC_LINKAGE - -#ifdef HAVE_WORKING_STDATOMIC -/** Initialize a new atomic counter with the value 0 */ -static inline void -atomic_counter_init(atomic_counter_t *counter) -{ - atomic_init(&counter->val, 0); -} -/** Clean up all resources held by an atomic counter. */ -static inline void -atomic_counter_destroy(atomic_counter_t *counter) -{ - (void)counter; -} -/** Add a value to an atomic counter. */ -static inline void -atomic_counter_add(atomic_counter_t *counter, size_t add) -{ - (void) atomic_fetch_add(&counter->val, add); -} -/** Subtract a value from an atomic counter. */ -static inline void -atomic_counter_sub(atomic_counter_t *counter, size_t sub) -{ - (void) atomic_fetch_sub(&counter->val, sub); -} -/** Return the current value of an atomic counter */ -static inline size_t -atomic_counter_get(atomic_counter_t *counter) -{ - return atomic_load(&counter->val); -} -/** Replace the value of an atomic counter; return the old one. */ -static inline size_t -atomic_counter_exchange(atomic_counter_t *counter, size_t newval) -{ - return atomic_exchange(&counter->val, newval); -} - -#else /* !(defined(HAVE_WORKING_STDATOMIC)) */ -#endif /* defined(HAVE_WORKING_STDATOMIC) */ - -#endif /* !defined(TOR_COMPAT_THREADS_H) */ diff --git a/src/common/compat_time.c b/src/common/compat_time.c deleted file mode 100644 index 93b527def0..0000000000 --- a/src/common/compat_time.c +++ /dev/null @@ -1,913 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat_time.c - * \brief Portable wrappers for finding out the current time, running - * timers, etc. - **/ - -#define COMPAT_TIME_PRIVATE -#include "compat.h" - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#endif - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef TOR_UNIT_TESTS -#if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H) -/* as fallback implementation for tor_sleep_msec */ -#include <sys/select.h> -#endif -#endif /* defined(TOR_UNIT_TESTS) */ - -#ifdef __APPLE__ -#include <mach/mach_time.h> -#endif - -#include "torlog.h" -#include "util.h" -#include "container.h" - -#ifndef HAVE_GETTIMEOFDAY -#ifdef HAVE_FTIME -#include <sys/timeb.h> -#endif -#endif - -#ifdef _WIN32 -#undef HAVE_CLOCK_GETTIME -#endif - -#ifdef TOR_UNIT_TESTS -/** Delay for <b>msec</b> milliseconds. Only used in tests. */ -void -tor_sleep_msec(int msec) -{ -#ifdef _WIN32 - Sleep(msec); -#elif defined(HAVE_USLEEP) - sleep(msec / 1000); - /* Some usleep()s hate sleeping more than 1 sec */ - usleep((msec % 1000) * 1000); -#elif defined(HAVE_SYS_SELECT_H) - struct timeval tv = { msec / 1000, (msec % 1000) * 1000}; - select(0, NULL, NULL, NULL, &tv); -#else - sleep(CEIL_DIV(msec, 1000)); -#endif /* defined(_WIN32) || ... */ -} -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Set *timeval to the current time of day. On error, log and terminate. - * (Same as gettimeofday(timeval,NULL), but never returns -1.) - */ -MOCK_IMPL(void, -tor_gettimeofday, (struct timeval *timeval)) -{ -#ifdef _WIN32 - /* Epoch bias copied from perl: number of units between windows epoch and - * Unix epoch. */ -#define EPOCH_BIAS U64_LITERAL(116444736000000000) -#define UNITS_PER_SEC U64_LITERAL(10000000) -#define USEC_PER_SEC U64_LITERAL(1000000) -#define UNITS_PER_USEC U64_LITERAL(10) - union { - uint64_t ft_64; - FILETIME ft_ft; - } ft; - /* number of 100-nsec units since Jan 1, 1601 */ - GetSystemTimeAsFileTime(&ft.ft_ft); - if (ft.ft_64 < EPOCH_BIAS) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"System time is before 1970; failing."); - exit(1); // exit ok: system clock is broken. - /* LCOV_EXCL_STOP */ - } - ft.ft_64 -= EPOCH_BIAS; - timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); - timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); -#elif defined(HAVE_GETTIMEOFDAY) - if (gettimeofday(timeval, NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"gettimeofday failed."); - /* If gettimeofday dies, we have either given a bad timezone (we didn't), - or segfaulted.*/ - exit(1); // exit ok: gettimeofday failed. - /* LCOV_EXCL_STOP */ - } -#elif defined(HAVE_FTIME) - struct timeb tb; - ftime(&tb); - timeval->tv_sec = tb.time; - timeval->tv_usec = tb.millitm * 1000; -#else -#error "No way to get time." -#endif /* defined(_WIN32) || ... */ - return; -} - -#define ONE_MILLION ((int64_t) (1000 * 1000)) -#define ONE_BILLION ((int64_t) (1000 * 1000 * 1000)) - -/** True iff monotime_init has been called. */ -static int monotime_initialized = 0; - -static monotime_t initialized_at; -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT -static monotime_coarse_t initialized_at_coarse; -#endif - -#ifdef TOR_UNIT_TESTS -/** True if we are running unit tests and overriding the current monotonic - * time. Note that mocked monotonic time might not be monotonic. - */ -static int monotime_mocking_enabled = 0; -static monotime_t initialized_at_saved; - -static int64_t mock_time_nsec = 0; -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT -static int64_t mock_time_nsec_coarse = 0; -static monotime_coarse_t initialized_at_coarse_saved; -#endif - -void -monotime_enable_test_mocking(void) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - - tor_assert_nonfatal(monotime_mocking_enabled == 0); - monotime_mocking_enabled = 1; - memcpy(&initialized_at_saved, - &initialized_at, sizeof(monotime_t)); - memset(&initialized_at, 0, sizeof(monotime_t)); -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT - memcpy(&initialized_at_coarse_saved, - &initialized_at_coarse, sizeof(monotime_coarse_t)); - memset(&initialized_at_coarse, 0, sizeof(monotime_coarse_t)); -#endif -} - -void -monotime_disable_test_mocking(void) -{ - tor_assert_nonfatal(monotime_mocking_enabled == 1); - monotime_mocking_enabled = 0; - - memcpy(&initialized_at, - &initialized_at_saved, sizeof(monotime_t)); -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT - memcpy(&initialized_at_coarse, - &initialized_at_coarse_saved, sizeof(monotime_coarse_t)); -#endif -} - -void -monotime_set_mock_time_nsec(int64_t nsec) -{ - tor_assert_nonfatal(monotime_mocking_enabled == 1); - mock_time_nsec = nsec; -} - -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT -void -monotime_coarse_set_mock_time_nsec(int64_t nsec) -{ - tor_assert_nonfatal(monotime_mocking_enabled == 1); - mock_time_nsec_coarse = nsec; -} -#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ -#endif /* defined(TOR_UNIT_TESTS) */ - -/* "ratchet" functions for monotonic time. */ - -#if defined(_WIN32) || defined(TOR_UNIT_TESTS) - -/** Protected by lock: last value returned by monotime_get(). */ -static int64_t last_pctr = 0; -/** Protected by lock: offset we must add to monotonic time values. */ -static int64_t pctr_offset = 0; -/* If we are using GetTickCount(), how many times has it rolled over? */ -static uint32_t rollover_count = 0; -/* If we are using GetTickCount(), what's the last value it returned? */ -static int64_t last_tick_count = 0; - -/** Helper for windows: Called with a sequence of times that are supposed - * to be monotonic; increments them as appropriate so that they actually - * _are_ monotonic. - * - * Caller must hold lock. */ -STATIC int64_t -ratchet_performance_counter(int64_t count_raw) -{ - /* must hold lock */ - const int64_t count_adjusted = count_raw + pctr_offset; - - if (PREDICT_UNLIKELY(count_adjusted < last_pctr)) { - /* Monotonicity failed! Pretend no time elapsed. */ - pctr_offset = last_pctr - count_raw; - return last_pctr; - } else { - last_pctr = count_adjusted; - return count_adjusted; - } -} - -STATIC int64_t -ratchet_coarse_performance_counter(const int64_t count_raw) -{ - int64_t count = count_raw + (((int64_t)rollover_count) << 32); - while (PREDICT_UNLIKELY(count < last_tick_count)) { - ++rollover_count; - count = count_raw + (((int64_t)rollover_count) << 32); - } - last_tick_count = count; - return count; -} -#endif /* defined(_WIN32) || defined(TOR_UNIT_TESTS) */ - -#if defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) -static struct timeval last_timeofday = { 0, 0 }; -static struct timeval timeofday_offset = { 0, 0 }; - -/** Helper for gettimeofday(): Called with a sequence of times that are - * supposed to be monotonic; increments them as appropriate so that they - * actually _are_ monotonic. - * - * Caller must hold lock. */ -STATIC void -ratchet_timeval(const struct timeval *timeval_raw, struct timeval *out) -{ - /* must hold lock */ - timeradd(timeval_raw, &timeofday_offset, out); - if (PREDICT_UNLIKELY(timercmp(out, &last_timeofday, OP_LT))) { - /* time ran backwards. Instead, declare that no time occurred. */ - timersub(&last_timeofday, timeval_raw, &timeofday_offset); - memcpy(out, &last_timeofday, sizeof(struct timeval)); - } else { - memcpy(&last_timeofday, out, sizeof(struct timeval)); - } -} -#endif /* defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) */ - -#ifdef TOR_UNIT_TESTS -/** For testing: reset all the ratchets */ -void -monotime_reset_ratchets_for_testing(void) -{ - last_pctr = pctr_offset = last_tick_count = 0; - rollover_count = 0; - memset(&last_timeofday, 0, sizeof(struct timeval)); - memset(&timeofday_offset, 0, sizeof(struct timeval)); -} -#endif /* defined(TOR_UNIT_TESTS) */ - -#ifdef __APPLE__ - -/** Initialized on startup: tells is how to convert from ticks to - * nanoseconds. - */ -static struct mach_timebase_info mach_time_info; -static struct mach_timebase_info mach_time_info_msec_cvt; -static int32_t mach_time_msec_cvt_threshold; -static int monotime_shift = 0; - -static void -monotime_init_internal(void) -{ - tor_assert(!monotime_initialized); - int r = mach_timebase_info(&mach_time_info); - tor_assert(r == 0); - tor_assert(mach_time_info.denom != 0); - - { - // approximate only. - uint64_t ns_per_tick = mach_time_info.numer / mach_time_info.denom; - uint64_t ms_per_tick = ns_per_tick * ONE_MILLION; - // requires that tor_log2(0) == 0. - monotime_shift = tor_log2(ms_per_tick); - } - { - // For converting ticks to milliseconds in a 32-bit-friendly way, we - // will first right-shift by 20, and then multiply by 2048/1953, since - // (1<<20) * 1953/2048 is about 1e6. We precompute a new numerator and - // denominator here to avoid multiple multiplies. - mach_time_info_msec_cvt.numer = mach_time_info.numer * 2048; - mach_time_info_msec_cvt.denom = mach_time_info.denom * 1953; - // For any value above this amount, we should divide before multiplying, - // to avoid overflow. For a value below this, we should multiply - // before dividing, to improve accuracy. - mach_time_msec_cvt_threshold = INT32_MAX / mach_time_info_msec_cvt.numer; - } -} - -/** - * Set "out" to the most recent monotonic time value - */ -void -monotime_get(monotime_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->abstime_ = (mock_time_nsec * mach_time_info.denom) - / mach_time_info.numer; - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - out->abstime_ = mach_absolute_time(); -} - -#if defined(HAVE_MACH_APPROXIMATE_TIME) -void -monotime_coarse_get(monotime_coarse_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->abstime_ = (mock_time_nsec_coarse * mach_time_info.denom) - / mach_time_info.numer; - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - out->abstime_ = mach_approximate_time(); -} -#endif - -/** - * Return the number of nanoseconds between <b>start</b> and <b>end</b>. - */ -int64_t -monotime_diff_nsec(const monotime_t *start, - const monotime_t *end) -{ - if (BUG(mach_time_info.denom == 0)) { - monotime_init(); - } - const int64_t diff_ticks = end->abstime_ - start->abstime_; - const int64_t diff_nsec = - (diff_ticks * mach_time_info.numer) / mach_time_info.denom; - return diff_nsec; -} - -int32_t -monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - if (BUG(mach_time_info.denom == 0)) { - monotime_init(); - } - const int64_t diff_ticks = end->abstime_ - start->abstime_; - - /* We already require in di_ops.c that right-shift performs a sign-extend. */ - const int32_t diff_microticks = (int32_t)(diff_ticks >> 20); - - if (diff_microticks >= mach_time_msec_cvt_threshold) { - return (diff_microticks / mach_time_info_msec_cvt.denom) * - mach_time_info_msec_cvt.numer; - } else { - return (diff_microticks * mach_time_info_msec_cvt.numer) / - mach_time_info_msec_cvt.denom; - } -} - -uint32_t -monotime_coarse_to_stamp(const monotime_coarse_t *t) -{ - return (uint32_t)(t->abstime_ >> monotime_shift); -} - -int -monotime_is_zero(const monotime_t *val) -{ - return val->abstime_ == 0; -} - -void -monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) -{ - const uint64_t nsec = msec * ONE_MILLION; - const uint64_t ticks = (nsec * mach_time_info.denom) / mach_time_info.numer; - out->abstime_ = val->abstime_ + ticks; -} - -/* end of "__APPLE__" */ -#elif defined(HAVE_CLOCK_GETTIME) - -#ifdef CLOCK_MONOTONIC_COARSE -/** - * Which clock should we use for coarse-grained monotonic time? By default - * this is CLOCK_MONOTONIC_COARSE, but it might not work -- for example, - * if we're compiled with newer Linux headers and then we try to run on - * an old Linux kernel. In that case, we will fall back to CLOCK_MONOTONIC. - */ -static int clock_monotonic_coarse = CLOCK_MONOTONIC_COARSE; -#endif /* defined(CLOCK_MONOTONIC_COARSE) */ - -static void -monotime_init_internal(void) -{ -#ifdef CLOCK_MONOTONIC_COARSE - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) < 0) { - log_info(LD_GENERAL, "CLOCK_MONOTONIC_COARSE isn't working (%s); " - "falling back to CLOCK_MONOTONIC.", strerror(errno)); - clock_monotonic_coarse = CLOCK_MONOTONIC; - } -#endif /* defined(CLOCK_MONOTONIC_COARSE) */ -} - -void -monotime_get(monotime_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->ts_.tv_sec = (time_t) (mock_time_nsec / ONE_BILLION); - out->ts_.tv_nsec = (int) (mock_time_nsec % ONE_BILLION); - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - int r = clock_gettime(CLOCK_MONOTONIC, &out->ts_); - tor_assert(r == 0); -} - -#ifdef CLOCK_MONOTONIC_COARSE -void -monotime_coarse_get(monotime_coarse_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->ts_.tv_sec = (time_t) (mock_time_nsec_coarse / ONE_BILLION); - out->ts_.tv_nsec = (int) (mock_time_nsec_coarse % ONE_BILLION); - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - int r = clock_gettime(clock_monotonic_coarse, &out->ts_); - if (PREDICT_UNLIKELY(r < 0) && - errno == EINVAL && - clock_monotonic_coarse == CLOCK_MONOTONIC_COARSE) { - /* We should have caught this at startup in monotime_init_internal! - */ - log_warn(LD_BUG, "Falling back to non-coarse monotonic time %s initial " - "system start?", monotime_initialized?"after":"without"); - clock_monotonic_coarse = CLOCK_MONOTONIC; - r = clock_gettime(clock_monotonic_coarse, &out->ts_); - } - - tor_assert(r == 0); -} -#endif /* defined(CLOCK_MONOTONIC_COARSE) */ - -int64_t -monotime_diff_nsec(const monotime_t *start, - const monotime_t *end) -{ - const int64_t diff_sec = end->ts_.tv_sec - start->ts_.tv_sec; - const int64_t diff_nsec = diff_sec * ONE_BILLION + - (end->ts_.tv_nsec - start->ts_.tv_nsec); - - return diff_nsec; -} - -int32_t -monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - const int32_t diff_sec = (int32_t)(end->ts_.tv_sec - start->ts_.tv_sec); - const int32_t diff_nsec = (int32_t)(end->ts_.tv_nsec - start->ts_.tv_nsec); - return diff_sec * 1000 + diff_nsec / ONE_MILLION; -} - -/* This value is ONE_BILLION >> 20. */ -static const uint32_t STAMP_TICKS_PER_SECOND = 953; - -uint32_t -monotime_coarse_to_stamp(const monotime_coarse_t *t) -{ - uint32_t nsec = (uint32_t)t->ts_.tv_nsec; - uint32_t sec = (uint32_t)t->ts_.tv_sec; - - return (sec * STAMP_TICKS_PER_SECOND) + (nsec >> 20); -} - -int -monotime_is_zero(const monotime_t *val) -{ - return val->ts_.tv_sec == 0 && val->ts_.tv_nsec == 0; -} - -void -monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) -{ - const uint32_t sec = msec / 1000; - const uint32_t msec_remainder = msec % 1000; - out->ts_.tv_sec = val->ts_.tv_sec + sec; - out->ts_.tv_nsec = val->ts_.tv_nsec + (msec_remainder * ONE_MILLION); - if (out->ts_.tv_nsec > ONE_BILLION) { - out->ts_.tv_nsec -= ONE_BILLION; - out->ts_.tv_sec += 1; - } -} - -/* end of "HAVE_CLOCK_GETTIME" */ -#elif defined (_WIN32) - -/** Result of QueryPerformanceFrequency, in terms needed to - * convert ticks to nanoseconds. */ -static int64_t nsec_per_tick_numer = 1; -static int64_t nsec_per_tick_denom = 1; - -/** Lock to protect last_pctr and pctr_offset */ -static CRITICAL_SECTION monotime_lock; -/** Lock to protect rollover_count and last_tick_count */ -static CRITICAL_SECTION monotime_coarse_lock; - -typedef ULONGLONG (WINAPI *GetTickCount64_fn_t)(void); -static GetTickCount64_fn_t GetTickCount64_fn = NULL; - -static void -monotime_init_internal(void) -{ - tor_assert(!monotime_initialized); - BOOL ok = InitializeCriticalSectionAndSpinCount(&monotime_lock, 200); - tor_assert(ok); - ok = InitializeCriticalSectionAndSpinCount(&monotime_coarse_lock, 200); - tor_assert(ok); - LARGE_INTEGER li; - ok = QueryPerformanceFrequency(&li); - tor_assert(ok); - tor_assert(li.QuadPart); - - uint64_t n = ONE_BILLION; - uint64_t d = li.QuadPart; - /* We need to simplify this or we'll probably overflow the int64. */ - simplify_fraction64(&n, &d); - tor_assert(n <= INT64_MAX); - tor_assert(d <= INT64_MAX); - - nsec_per_tick_numer = (int64_t) n; - nsec_per_tick_denom = (int64_t) d; - - last_pctr = 0; - pctr_offset = 0; - - HANDLE h = load_windows_system_library(TEXT("kernel32.dll")); - if (h) { - GetTickCount64_fn = (GetTickCount64_fn_t) - GetProcAddress(h, "GetTickCount64"); - } - // FreeLibrary(h) ? -} - -void -monotime_get(monotime_t *out) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->pcount_ = (mock_time_nsec * nsec_per_tick_denom) - / nsec_per_tick_numer; - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - - /* Alas, QueryPerformanceCounter is not always monotonic: see bug list at - - https://www.python.org/dev/peps/pep-0418/#windows-queryperformancecounter - */ - - EnterCriticalSection(&monotime_lock); - LARGE_INTEGER res; - BOOL ok = QueryPerformanceCounter(&res); - tor_assert(ok); - const int64_t count_raw = res.QuadPart; - out->pcount_ = ratchet_performance_counter(count_raw); - LeaveCriticalSection(&monotime_lock); -} - -void -monotime_coarse_get(monotime_coarse_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->tick_count_ = mock_time_nsec_coarse / ONE_MILLION; - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - - if (GetTickCount64_fn) { - out->tick_count_ = (int64_t)GetTickCount64_fn(); - } else { - EnterCriticalSection(&monotime_coarse_lock); - DWORD tick = GetTickCount(); - out->tick_count_ = ratchet_coarse_performance_counter(tick); - LeaveCriticalSection(&monotime_coarse_lock); - } -} - -int64_t -monotime_diff_nsec(const monotime_t *start, - const monotime_t *end) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - const int64_t diff_ticks = end->pcount_ - start->pcount_; - return (diff_ticks * nsec_per_tick_numer) / nsec_per_tick_denom; -} - -int64_t -monotime_coarse_diff_msec(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - const int64_t diff_ticks = end->tick_count_ - start->tick_count_; - return diff_ticks; -} - -int32_t -monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - return (int32_t)monotime_coarse_diff_msec(start, end); -} - -int64_t -monotime_coarse_diff_usec(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - return monotime_coarse_diff_msec(start, end) * 1000; -} - -int64_t -monotime_coarse_diff_nsec(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - return monotime_coarse_diff_msec(start, end) * ONE_MILLION; -} - -static const uint32_t STAMP_TICKS_PER_SECOND = 1000; - -uint32_t -monotime_coarse_to_stamp(const monotime_coarse_t *t) -{ - return (uint32_t) t->tick_count_; -} - -int -monotime_is_zero(const monotime_t *val) -{ - return val->pcount_ == 0; -} - -int -monotime_coarse_is_zero(const monotime_coarse_t *val) -{ - return val->tick_count_ == 0; -} - -void -monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) -{ - const uint64_t nsec = msec * ONE_MILLION; - const uint64_t ticks = (nsec * nsec_per_tick_denom) / nsec_per_tick_numer; - out->pcount_ = val->pcount_ + ticks; -} - -void -monotime_coarse_add_msec(monotime_coarse_t *out, const monotime_coarse_t *val, - uint32_t msec) -{ - out->tick_count_ = val->tick_count_ + msec; -} - -/* end of "_WIN32" */ -#elif defined(MONOTIME_USING_GETTIMEOFDAY) - -static tor_mutex_t monotime_lock; - -/** Initialize the monotonic timer subsystem. */ -static void -monotime_init_internal(void) -{ - tor_assert(!monotime_initialized); - tor_mutex_init(&monotime_lock); -} - -void -monotime_get(monotime_t *out) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - - tor_mutex_acquire(&monotime_lock); - struct timeval timeval_raw; - tor_gettimeofday(&timeval_raw); - ratchet_timeval(&timeval_raw, &out->tv_); - tor_mutex_release(&monotime_lock); -} - -int64_t -monotime_diff_nsec(const monotime_t *start, - const monotime_t *end) -{ - struct timeval diff; - timersub(&end->tv_, &start->tv_, &diff); - return (diff.tv_sec * ONE_BILLION + diff.tv_usec * 1000); -} - -int32_t -monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - struct timeval diff; - timersub(&end->tv_, &start->tv_, &diff); - return diff.tv_sec * 1000 + diff.tv_usec / 1000; -} - -/* This value is ONE_MILLION >> 10. */ -static const uint32_t STAMP_TICKS_PER_SECOND = 976; - -uint32_t -monotime_coarse_to_stamp(const monotime_coarse_t *t) -{ - const uint32_t usec = (uint32_t)t->tv_.tv_usec; - const uint32_t sec = (uint32_t)t->tv_.tv_sec; - return (sec * STAMP_TICKS_PER_SECOND) | (nsec >> 10); -} - -int -monotime_is_zero(const monotime_t *val) -{ - return val->tv_.tv_sec == 0 && val->tv_.tv_usec == 0; -} - -void -monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) -{ - const uint32_t sec = msec / 1000; - const uint32_t msec_remainder = msec % 1000; - out->tv_.tv_sec = val->tv_.tv_sec + sec; - out->tv_.tv_usec = val->tv_.tv_nsec + (msec_remainder * 1000); - if (out->tv_.tv_usec > ONE_MILLION) { - out->tv_.tv_usec -= ONE_MILLION; - out->tv_.tv_sec += 1; - } -} - -/* end of "MONOTIME_USING_GETTIMEOFDAY" */ -#else -#error "No way to implement monotonic timers." -#endif /* defined(__APPLE__) || ... */ - -/** - * Initialize the monotonic timer subsystem. Must be called before any - * monotonic timer functions. This function is idempotent. - */ -void -monotime_init(void) -{ - if (!monotime_initialized) { - monotime_init_internal(); - monotime_initialized = 1; - monotime_get(&initialized_at); -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT - monotime_coarse_get(&initialized_at_coarse); -#endif - } -} - -void -monotime_zero(monotime_t *out) -{ - memset(out, 0, sizeof(*out)); -} -#ifdef MONOTIME_COARSE_TYPE_IS_DIFFERENT -void -monotime_coarse_zero(monotime_coarse_t *out) -{ - memset(out, 0, sizeof(*out)); -} -#endif - -int64_t -monotime_diff_usec(const monotime_t *start, - const monotime_t *end) -{ - const int64_t nsec = monotime_diff_nsec(start, end); - return CEIL_DIV(nsec, 1000); -} - -int64_t -monotime_diff_msec(const monotime_t *start, - const monotime_t *end) -{ - const int64_t nsec = monotime_diff_nsec(start, end); - return CEIL_DIV(nsec, ONE_MILLION); -} - -uint64_t -monotime_absolute_nsec(void) -{ - monotime_t now; - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - - monotime_get(&now); - return monotime_diff_nsec(&initialized_at, &now); -} - -uint64_t -monotime_absolute_usec(void) -{ - return monotime_absolute_nsec() / 1000; -} - -uint64_t -monotime_absolute_msec(void) -{ - return monotime_absolute_nsec() / ONE_MILLION; -} - -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT -uint64_t -monotime_coarse_absolute_nsec(void) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - - monotime_coarse_t now; - monotime_coarse_get(&now); - return monotime_coarse_diff_nsec(&initialized_at_coarse, &now); -} - -uint64_t -monotime_coarse_absolute_usec(void) -{ - return monotime_coarse_absolute_nsec() / 1000; -} - -uint64_t -monotime_coarse_absolute_msec(void) -{ - return monotime_coarse_absolute_nsec() / ONE_MILLION; -} -#else -#define initialized_at_coarse initialized_at -#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ - -/** - * Return the current time "stamp" as described by monotime_coarse_to_stamp. - */ -uint32_t -monotime_coarse_get_stamp(void) -{ - monotime_coarse_t now; - monotime_coarse_get(&now); - return monotime_coarse_to_stamp(&now); -} - -#ifdef __APPLE__ -uint64_t -monotime_coarse_stamp_units_to_approx_msec(uint64_t units) -{ - /* Recover as much precision as we can. */ - uint64_t abstime_diff = (units << monotime_shift); - return (abstime_diff * mach_time_info.numer) / - (mach_time_info.denom * ONE_MILLION); -} -uint64_t -monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) -{ - uint64_t abstime_val = - (((uint64_t)msec) * ONE_MILLION * mach_time_info.denom) / - mach_time_info.numer; - return abstime_val >> monotime_shift; -} -#else -uint64_t -monotime_coarse_stamp_units_to_approx_msec(uint64_t units) -{ - return (units * 1000) / STAMP_TICKS_PER_SECOND; -} -uint64_t -monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) -{ - return (msec * STAMP_TICKS_PER_SECOND) / 1000; -} -#endif - diff --git a/src/common/compat_time.h b/src/common/compat_time.h deleted file mode 100644 index f241aa5eba..0000000000 --- a/src/common/compat_time.h +++ /dev/null @@ -1,234 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat_time.h - * - * \brief Functions and types for monotonic times. - * - * monotime_* functions try to provide a high-resolution monotonic timer with - * something the best resolution the system provides. monotime_coarse_* - * functions run faster (if the operating system gives us a way to do that) - * but produce a less accurate timer: accuracy will probably be on the order - * of tens of milliseconds. - */ - -#ifndef TOR_COMPAT_TIME_H -#define TOR_COMPAT_TIME_H - -#include "orconfig.h" -#ifdef _WIN32 -#undef HAVE_CLOCK_GETTIME -#endif - -#if defined(HAVE_CLOCK_GETTIME) -/* to ensure definition of CLOCK_MONOTONIC_COARSE if it's there */ -#include <time.h> -#endif - -#if !defined(HAVE_STRUCT_TIMEVAL_TV_SEC) -/** Implementation of timeval for platforms that don't have it. */ -struct timeval { - time_t tv_sec; - unsigned int tv_usec; -}; -#endif /* !defined(HAVE_STRUCT_TIMEVAL_TV_SEC) */ - -/** Represents a monotonic timer in a platform-dependent way. */ -typedef struct monotime_t { -#ifdef __APPLE__ - /* On apple, there is a 64-bit counter whose precision we must look up. */ - uint64_t abstime_; -#elif defined(HAVE_CLOCK_GETTIME) - /* It sure would be nice to use clock_gettime(). Posix is a nice thing. */ - struct timespec ts_; -#elif defined (_WIN32) - /* On Windows, there is a 64-bit counter whose precision we must look up. */ - int64_t pcount_; -#else -#define MONOTIME_USING_GETTIMEOFDAY - /* Otherwise, we will be stuck using gettimeofday. */ - struct timeval tv_; -#endif /* defined(__APPLE__) || ... */ -} monotime_t; - -#if defined(CLOCK_MONOTONIC_COARSE) && \ - defined(HAVE_CLOCK_GETTIME) -#define MONOTIME_COARSE_FN_IS_DIFFERENT -#define monotime_coarse_t monotime_t -#elif defined(_WIN32) -#define MONOTIME_COARSE_FN_IS_DIFFERENT -#define MONOTIME_COARSE_TYPE_IS_DIFFERENT -/** Represents a coarse monotonic time in a platform-independent way. */ -typedef struct monotime_coarse_t { - uint64_t tick_count_; -} monotime_coarse_t; -#elif defined(__APPLE__) && defined(HAVE_MACH_APPROXIMATE_TIME) -#define MONOTIME_COARSE_FN_IS_DIFFERENT -#define monotime_coarse_t monotime_t -#else -#define monotime_coarse_t monotime_t -#endif /* defined(CLOCK_MONOTONIC_COARSE) && ... || ... */ - -/** - * Initialize the timing subsystem. This function is idempotent. - */ -void monotime_init(void); -/** - * Set <b>out</b> to the current time. - */ -void monotime_get(monotime_t *out); -/** - * Return the number of nanoseconds between <b>start</b> and <b>end</b>. - */ -int64_t monotime_diff_nsec(const monotime_t *start, const monotime_t *end); -/** - * Return the number of microseconds between <b>start</b> and <b>end</b>. - */ -int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end); -/** - * Return the number of milliseconds between <b>start</b> and <b>end</b>. - */ -int64_t monotime_diff_msec(const monotime_t *start, const monotime_t *end); -/** - * Return the number of nanoseconds since the timer system was initialized. - */ -uint64_t monotime_absolute_nsec(void); -/** - * Return the number of microseconds since the timer system was initialized. - */ -uint64_t monotime_absolute_usec(void); -/** - * Return the number of milliseconds since the timer system was initialized. - */ -uint64_t monotime_absolute_msec(void); - -/** - * Set <b>out</b> to zero. - */ -void monotime_zero(monotime_t *out); -/** - * Return true iff <b>out</b> is zero - */ -int monotime_is_zero(const monotime_t *out); - -/** - * Set <b>out</b> to N milliseconds after <b>val</b>. - */ -/* XXXX We should add a more generic function here if we ever need to */ -void monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec); - -#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT) -/** - * Set <b>out</b> to the current coarse time. - */ -void monotime_coarse_get(monotime_coarse_t *out); -uint64_t monotime_coarse_absolute_nsec(void); -uint64_t monotime_coarse_absolute_usec(void); -uint64_t monotime_coarse_absolute_msec(void); -#else /* !(defined(MONOTIME_COARSE_FN_IS_DIFFERENT)) */ -#define monotime_coarse_get monotime_get -#define monotime_coarse_absolute_nsec monotime_absolute_nsec -#define monotime_coarse_absolute_usec monotime_absolute_usec -#define monotime_coarse_absolute_msec monotime_absolute_msec -#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ - -/** - * Return a "timestamp" approximation for a coarse monotonic timer. - * This timestamp is meant to be fast to calculate and easy to - * compare, and have a unit of something roughly around 1 msec. - * - * It will wrap over from time to time. - * - * It has no defined zero point. - */ -uint32_t monotime_coarse_to_stamp(const monotime_coarse_t *t); -/** - * Convert a difference, expressed in the units of monotime_coarse_to_stamp, - * into an approximate number of milliseconds. - */ -uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units); -uint64_t monotime_msec_to_approx_coarse_stamp_units(uint64_t msec); -uint32_t monotime_coarse_get_stamp(void); - -#if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) -int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start, - const monotime_coarse_t *end); -int64_t monotime_coarse_diff_usec(const monotime_coarse_t *start, - const monotime_coarse_t *end); -int64_t monotime_coarse_diff_msec(const monotime_coarse_t *start, - const monotime_coarse_t *end); -void monotime_coarse_zero(monotime_coarse_t *out); -int monotime_coarse_is_zero(const monotime_coarse_t *val); -void monotime_coarse_add_msec(monotime_coarse_t *out, - const monotime_coarse_t *val, uint32_t msec); -#else /* !(defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)) */ -#define monotime_coarse_diff_nsec monotime_diff_nsec -#define monotime_coarse_diff_usec monotime_diff_usec -#define monotime_coarse_diff_msec monotime_diff_msec -#define monotime_coarse_zero monotime_zero -#define monotime_coarse_is_zero monotime_is_zero -#define monotime_coarse_add_msec monotime_add_msec -#endif /* defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) */ - -/** - * As monotime_coarse_diff_msec, but avoid 64-bit division. - * - * Requires that the difference fit into an int32_t; not for use with - * large time differences. - */ -int32_t monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end); - -/** - * As monotime_coarse_diff_msec, but avoid 64-bit division if it is expensive. - * - * Requires that the difference fit into an int32_t; not for use with - * large time differences. - */ -static inline int32_t -monotime_coarse_diff_msec32(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ -#if SIZEOF_VOID_P == 8 - // on a 64-bit platform, let's assume 64/64 division is cheap. - return (int32_t) monotime_coarse_diff_msec(start, end); -#else -#define USING_32BIT_MSEC_HACK - return monotime_coarse_diff_msec32_(start, end); -#endif -} - -MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval)); - -#ifdef TOR_UNIT_TESTS -void tor_sleep_msec(int msec); - -void monotime_enable_test_mocking(void); -void monotime_disable_test_mocking(void); -void monotime_set_mock_time_nsec(int64_t); -#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT) -void monotime_coarse_set_mock_time_nsec(int64_t); -#else -#define monotime_coarse_set_mock_time_nsec monotime_set_mock_time_nsec -#endif -#endif /* defined(TOR_UNIT_TESTS) */ - -#ifdef COMPAT_TIME_PRIVATE -#if defined(_WIN32) || defined(TOR_UNIT_TESTS) -STATIC int64_t ratchet_performance_counter(int64_t count_raw); -STATIC int64_t ratchet_coarse_performance_counter(int64_t count_raw); -#endif -#if defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) -STATIC void ratchet_timeval(const struct timeval *timeval_raw, - struct timeval *out); -#endif -#ifdef TOR_UNIT_TESTS -void monotime_reset_ratchets_for_testing(void); -#endif -#endif /* defined(COMPAT_TIME_PRIVATE) */ - -#endif /* !defined(TOR_COMPAT_TIME_H) */ - diff --git a/src/common/compat_winthreads.c b/src/common/compat_winthreads.c deleted file mode 100644 index 7021344f6e..0000000000 --- a/src/common/compat_winthreads.c +++ /dev/null @@ -1,251 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat_winthreads.c - * - * \brief Implementation for the windows-based multithreading backend - * functions. - */ - -#ifdef _WIN32 - -#include "compat.h" -#include <windows.h> -#include <process.h> -#include "util.h" -#include "container.h" -#include "torlog.h" - -/* This value is more or less total cargo-cult */ -#define SPIN_COUNT 2000 - -/** Minimalist interface to run a void function in the background. On - * Unix calls fork, on win32 calls beginthread. Returns -1 on failure. - * func should not return, but rather should call spawn_exit. - * - * NOTE: if <b>data</b> is used, it should not be allocated on the stack, - * since in a multithreaded environment, there is no way to be sure that - * the caller's stack will still be around when the called function is - * running. - */ -int -spawn_func(void (*func)(void *), void *data) -{ - int rv; - rv = (int)_beginthread(func, 0, data); - if (rv == (int)-1) - return -1; - return 0; -} - -/** End the current thread/process. - */ -void -spawn_exit(void) -{ - _endthread(); - // LCOV_EXCL_START - //we should never get here. my compiler thinks that _endthread returns, this - //is an attempt to fool it. - tor_assert(0); - _exit(0); // exit ok: unreachable. - // LCOV_EXCL_STOP -} - -void -tor_mutex_init(tor_mutex_t *m) -{ - InitializeCriticalSection(&m->mutex); -} -void -tor_mutex_init_nonrecursive(tor_mutex_t *m) -{ - InitializeCriticalSection(&m->mutex); -} - -void -tor_mutex_uninit(tor_mutex_t *m) -{ - DeleteCriticalSection(&m->mutex); -} -void -tor_mutex_acquire(tor_mutex_t *m) -{ - tor_assert(m); - EnterCriticalSection(&m->mutex); -} -void -tor_mutex_release(tor_mutex_t *m) -{ - LeaveCriticalSection(&m->mutex); -} -unsigned long -tor_get_thread_id(void) -{ - return (unsigned long)GetCurrentThreadId(); -} - -int -tor_cond_init(tor_cond_t *cond) -{ - memset(cond, 0, sizeof(tor_cond_t)); - if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) { - return -1; - } - if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) { - DeleteCriticalSection(&cond->lock); - return -1; - } - cond->n_waiting = cond->n_to_wake = cond->generation = 0; - return 0; -} -void -tor_cond_uninit(tor_cond_t *cond) -{ - DeleteCriticalSection(&cond->lock); - CloseHandle(cond->event); -} - -static void -tor_cond_signal_impl(tor_cond_t *cond, int broadcast) -{ - EnterCriticalSection(&cond->lock); - if (broadcast) - cond->n_to_wake = cond->n_waiting; - else - ++cond->n_to_wake; - cond->generation++; - SetEvent(cond->event); - LeaveCriticalSection(&cond->lock); -} -void -tor_cond_signal_one(tor_cond_t *cond) -{ - tor_cond_signal_impl(cond, 0); -} -void -tor_cond_signal_all(tor_cond_t *cond) -{ - tor_cond_signal_impl(cond, 1); -} - -int -tor_threadlocal_init(tor_threadlocal_t *threadlocal) -{ - threadlocal->index = TlsAlloc(); - return (threadlocal->index == TLS_OUT_OF_INDEXES) ? -1 : 0; -} - -void -tor_threadlocal_destroy(tor_threadlocal_t *threadlocal) -{ - TlsFree(threadlocal->index); - memset(threadlocal, 0, sizeof(tor_threadlocal_t)); -} - -void * -tor_threadlocal_get(tor_threadlocal_t *threadlocal) -{ - void *value = TlsGetValue(threadlocal->index); - if (value == NULL) { - DWORD err = GetLastError(); - if (err != ERROR_SUCCESS) { - char *msg = format_win32_error(err); - log_err(LD_GENERAL, "Error retrieving thread-local value: %s", msg); - tor_free(msg); - tor_assert(err == ERROR_SUCCESS); - } - } - return value; -} - -void -tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value) -{ - BOOL ok = TlsSetValue(threadlocal->index, value); - if (!ok) { - DWORD err = GetLastError(); - char *msg = format_win32_error(err); - log_err(LD_GENERAL, "Error adjusting thread-local value: %s", msg); - tor_free(msg); - tor_assert(ok); - } -} - -int -tor_cond_wait(tor_cond_t *cond, tor_mutex_t *lock_, const struct timeval *tv) -{ - CRITICAL_SECTION *lock = &lock_->mutex; - int generation_at_start; - int waiting = 1; - int result = -1; - DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime; - if (tv) - ms_orig = ms = tv->tv_sec*1000 + (tv->tv_usec+999)/1000; - - EnterCriticalSection(&cond->lock); - ++cond->n_waiting; - generation_at_start = cond->generation; - LeaveCriticalSection(&cond->lock); - - LeaveCriticalSection(lock); - - startTime = GetTickCount(); - do { - DWORD res; - res = WaitForSingleObject(cond->event, ms); - EnterCriticalSection(&cond->lock); - if (cond->n_to_wake && - cond->generation != generation_at_start) { - --cond->n_to_wake; - --cond->n_waiting; - result = 0; - waiting = 0; - goto out; - } else if (res != WAIT_OBJECT_0) { - result = (res==WAIT_TIMEOUT) ? 1 : -1; - --cond->n_waiting; - waiting = 0; - goto out; - } else if (ms != INFINITE) { - endTime = GetTickCount(); - if (startTime + ms_orig <= endTime) { - result = 1; /* Timeout */ - --cond->n_waiting; - waiting = 0; - goto out; - } else { - ms = startTime + ms_orig - endTime; - } - } - /* If we make it here, we are still waiting. */ - if (cond->n_to_wake == 0) { - /* There is nobody else who should wake up; reset - * the event. */ - ResetEvent(cond->event); - } - out: - LeaveCriticalSection(&cond->lock); - } while (waiting); - - EnterCriticalSection(lock); - - EnterCriticalSection(&cond->lock); - if (!cond->n_waiting) - ResetEvent(cond->event); - LeaveCriticalSection(&cond->lock); - - return result; -} - -void -tor_threads_init(void) -{ - set_main_thread(); -} - -#endif /* defined(_WIN32) */ - diff --git a/src/common/compress.c b/src/common/compress.c deleted file mode 100644 index cb1549f1aa..0000000000 --- a/src/common/compress.c +++ /dev/null @@ -1,675 +0,0 @@ -/* Copyright (c) 2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress.c - * \brief Common compression API. - **/ - -#include "orconfig.h" - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <string.h> -#include "torint.h" - -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif - -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_lzma.h" -#include "compress_none.h" -#include "compress_zlib.h" -#include "compress_zstd.h" - -/** Total number of bytes allocated for compression state overhead. */ -static atomic_counter_t total_compress_allocation; - -/** @{ */ -/* These macros define the maximum allowable compression factor. Anything of - * size greater than CHECK_FOR_COMPRESSION_BOMB_AFTER is not allowed to - * have an uncompression factor (uncompressed size:compressed size ratio) of - * any greater than MAX_UNCOMPRESSION_FACTOR. - * - * Picking a value for MAX_UNCOMPRESSION_FACTOR is a trade-off: we want it to - * be small to limit the attack multiplier, but we also want it to be large - * enough so that no legitimate document --even ones we might invent in the - * future -- ever compresses by a factor of greater than - * MAX_UNCOMPRESSION_FACTOR. Within those parameters, there's a reasonably - * large range of possible values. IMO, anything over 8 is probably safe; IMO - * anything under 50 is probably sufficient. - */ -#define MAX_UNCOMPRESSION_FACTOR 25 -#define CHECK_FOR_COMPRESSION_BOMB_AFTER (1024*64) -/** @} */ - -/** Return true if uncompressing an input of size <b>in_size</b> to an input of - * size at least <b>size_out</b> looks like a compression bomb. */ -MOCK_IMPL(int, -tor_compress_is_compression_bomb,(size_t size_in, size_t size_out)) -{ - if (size_in == 0 || size_out < CHECK_FOR_COMPRESSION_BOMB_AFTER) - return 0; - - return (size_out / size_in > MAX_UNCOMPRESSION_FACTOR); -} - -/** Guess the size that <b>in_len</b> will be after compression or - * decompression. */ -static size_t -guess_compress_size(int compress, compress_method_t method, - compression_level_t compression_level, - size_t in_len) -{ - // ignore these for now. - (void)compression_level; - if (method == NO_METHOD) { - /* Guess that we'll need an extra byte, to avoid a needless realloc - * for nul-termination */ - return (in_len < SIZE_MAX) ? in_len + 1 : in_len; - } - - /* Always guess a factor of 2. */ - if (compress) { - in_len /= 2; - } else { - if (in_len < SIZE_T_CEILING/2) - in_len *= 2; - } - return MAX(in_len, 1024); -} - -/** Internal function to implement tor_compress/tor_uncompress, depending on - * whether <b>compress</b> is set. All arguments are as for tor_compress or - * tor_uncompress. */ -static int -tor_compress_impl(int compress, - char **out, size_t *out_len, - const char *in, size_t in_len, - compress_method_t method, - compression_level_t compression_level, - int complete_only, - int protocol_warn_level) -{ - tor_compress_state_t *stream; - int rv; - - stream = tor_compress_new(compress, method, compression_level); - - if (stream == NULL) { - log_warn(LD_GENERAL, "NULL stream while %scompressing", - compress?"":"de"); - log_debug(LD_GENERAL, "method: %d level: %d at len: %lu", - method, compression_level, (unsigned long)in_len); - return -1; - } - - size_t in_len_orig = in_len; - size_t out_remaining, out_alloc; - char *outptr; - - out_remaining = out_alloc = - guess_compress_size(compress, method, compression_level, in_len); - *out = outptr = tor_malloc(out_remaining); - - const int finish = complete_only || compress; - - while (1) { - switch (tor_compress_process(stream, - &outptr, &out_remaining, - &in, &in_len, finish)) { - case TOR_COMPRESS_DONE: - if (in_len == 0 || compress) { - goto done; - } else { - // More data is present, and we're decompressing. So we may need to - // reinitialize the stream if we are handling multiple concatenated - // inputs. - tor_compress_free(stream); - stream = tor_compress_new(compress, method, compression_level); - if (stream == NULL) { - log_warn(LD_GENERAL, "NULL stream while %scompressing", - compress?"":"de"); - goto err; - } - } - break; - case TOR_COMPRESS_OK: - if (compress || complete_only) { - log_fn(protocol_warn_level, LD_PROTOCOL, - "Unexpected %s while %scompressing", - complete_only?"end of input":"result", - compress?"":"de"); - log_debug(LD_GENERAL, "method: %d level: %d at len: %lu", - method, compression_level, (unsigned long)in_len); - goto err; - } else { - if (in_len == 0) { - goto done; - } - } - break; - case TOR_COMPRESS_BUFFER_FULL: { - if (!compress && outptr < *out+out_alloc) { - // A buffer error in this case means that we have a problem - // with our input. - log_fn(protocol_warn_level, LD_PROTOCOL, - "Possible truncated or corrupt compressed data"); - goto err; - } - if (out_alloc >= SIZE_T_CEILING / 2) { - log_warn(LD_GENERAL, "While %scompressing data: ran out of space.", - compress?"":"un"); - goto err; - } - if (!compress && - tor_compress_is_compression_bomb(in_len_orig, out_alloc)) { - // This should already have been caught down in the backend logic. - // LCOV_EXCL_START - tor_assert_nonfatal_unreached(); - goto err; - // LCOV_EXCL_STOP - } - const size_t offset = outptr - *out; - out_alloc *= 2; - *out = tor_realloc(*out, out_alloc); - outptr = *out + offset; - out_remaining = out_alloc - offset; - break; - } - case TOR_COMPRESS_ERROR: - log_fn(protocol_warn_level, LD_GENERAL, - "Error while %scompressing data: bad input?", - compress?"":"un"); - goto err; // bad data. - - // LCOV_EXCL_START - default: - tor_assert_nonfatal_unreached(); - goto err; - // LCOV_EXCL_STOP - } - } - done: - *out_len = outptr - *out; - if (compress && tor_compress_is_compression_bomb(*out_len, in_len_orig)) { - log_warn(LD_BUG, "We compressed something and got an insanely high " - "compression factor; other Tors would think this was a " - "compression bomb."); - goto err; - } - if (!compress) { - // NUL-terminate our output. - if (out_alloc == *out_len) - *out = tor_realloc(*out, out_alloc + 1); - (*out)[*out_len] = '\0'; - } - rv = 0; - goto out; - - err: - tor_free(*out); - *out_len = 0; - rv = -1; - goto out; - - out: - tor_compress_free(stream); - return rv; -} - -/** Given <b>in_len</b> bytes at <b>in</b>, compress them into a newly - * allocated buffer, using the method described in <b>method</b>. Store the - * compressed string in *<b>out</b>, and its length in *<b>out_len</b>. - * Return 0 on success, -1 on failure. - */ -int -tor_compress(char **out, size_t *out_len, - const char *in, size_t in_len, - compress_method_t method) -{ - return tor_compress_impl(1, out, out_len, in, in_len, method, - BEST_COMPRESSION, - 1, LOG_WARN); -} - -/** Given zero or more compressed strings of total length <b>in_len</b> bytes - * at <b>in</b>, uncompress them into a newly allocated buffer, using the - * method described in <b>method</b>. Store the uncompressed string in - * *<b>out</b>, and its length in *<b>out_len</b>. Return 0 on success, -1 on - * failure. - * - * If any bytes are written to <b>out</b>, an extra byte NUL is always - * written at the end, but not counted in <b>out_len</b>. This is a - * safety feature to ensure that the output can be treated as a - * NUL-terminated string -- though of course, callers should check - * out_len anyway. - * - * If <b>complete_only</b> is true, we consider a truncated input as a - * failure; otherwise we decompress as much as we can. Warn about truncated - * or corrupt inputs at <b>protocol_warn_level</b>. - */ -int -tor_uncompress(char **out, size_t *out_len, - const char *in, size_t in_len, - compress_method_t method, - int complete_only, - int protocol_warn_level) -{ - return tor_compress_impl(0, out, out_len, in, in_len, method, - BEST_COMPRESSION, - complete_only, protocol_warn_level); -} - -/** Try to tell whether the <b>in_len</b>-byte string in <b>in</b> is likely - * to be compressed or not. If it is, return the likeliest compression method. - * Otherwise, return UNKNOWN_METHOD. - */ -compress_method_t -detect_compression_method(const char *in, size_t in_len) -{ - if (in_len > 2 && fast_memeq(in, "\x1f\x8b", 2)) { - return GZIP_METHOD; - } else if (in_len > 2 && (in[0] & 0x0f) == 8 && - (ntohs(get_uint16(in)) % 31) == 0) { - return ZLIB_METHOD; - } else if (in_len > 2 && - fast_memeq(in, "\x5d\x00\x00", 3)) { - return LZMA_METHOD; - } else if (in_len > 3 && - fast_memeq(in, "\x28\xb5\x2f\xfd", 4)) { - return ZSTD_METHOD; - } else { - return UNKNOWN_METHOD; - } -} - -/** Return 1 if a given <b>method</b> is supported; otherwise 0. */ -int -tor_compress_supports_method(compress_method_t method) -{ - switch (method) { - case GZIP_METHOD: - case ZLIB_METHOD: - return tor_zlib_method_supported(); - case LZMA_METHOD: - return tor_lzma_method_supported(); - case ZSTD_METHOD: - return tor_zstd_method_supported(); - case NO_METHOD: - return 1; - case UNKNOWN_METHOD: - default: - return 0; - } -} - -/** - * Return a bitmask of the supported compression types, where 1<<m is - * set in the bitmask if and only if compression with method <b>m</b> is - * supported. - */ -unsigned -tor_compress_get_supported_method_bitmask(void) -{ - static unsigned supported = 0; - if (supported == 0) { - compress_method_t m; - for (m = NO_METHOD; m <= UNKNOWN_METHOD; ++m) { - if (tor_compress_supports_method(m)) { - supported |= (1u << m); - } - } - } - return supported; -} - -/** Table of compression method names. These should have an "x-" prefix, - * if they are not listed in the IANA content coding registry. */ -static const struct { - const char *name; - compress_method_t method; -} compression_method_names[] = { - { "gzip", GZIP_METHOD }, - { "deflate", ZLIB_METHOD }, - // We call this "x-tor-lzma" rather than "x-lzma", because we impose a - // lower maximum memory usage on the decoding side. - { "x-tor-lzma", LZMA_METHOD }, - { "x-zstd" , ZSTD_METHOD }, - { "identity", NO_METHOD }, - - /* Later entries in this table are not canonical; these are recognized but - * not emitted. */ - { "x-gzip", GZIP_METHOD }, -}; - -/** Return the canonical string representation of the compression method - * <b>method</b>, or NULL if the method isn't recognized. */ -const char * -compression_method_get_name(compress_method_t method) -{ - unsigned i; - for (i = 0; i < ARRAY_LENGTH(compression_method_names); ++i) { - if (method == compression_method_names[i].method) - return compression_method_names[i].name; - } - return NULL; -} - -/** Table of compression human readable method names. */ -static const struct { - compress_method_t method; - const char *name; -} compression_method_human_names[] = { - { NO_METHOD, "uncompressed" }, - { GZIP_METHOD, "gzipped" }, - { ZLIB_METHOD, "deflated" }, - { LZMA_METHOD, "LZMA compressed" }, - { ZSTD_METHOD, "Zstandard compressed" }, - { UNKNOWN_METHOD, "unknown encoding" }, -}; - -/** Return a human readable string representation of the compression method - * <b>method</b>, or NULL if the method isn't recognized. */ -const char * -compression_method_get_human_name(compress_method_t method) -{ - unsigned i; - for (i = 0; i < ARRAY_LENGTH(compression_method_human_names); ++i) { - if (method == compression_method_human_names[i].method) - return compression_method_human_names[i].name; - } - return NULL; -} - -/** Return the compression method represented by the string <b>name</b>, or - * UNKNOWN_METHOD if the string isn't recognized. */ -compress_method_t -compression_method_get_by_name(const char *name) -{ - unsigned i; - for (i = 0; i < ARRAY_LENGTH(compression_method_names); ++i) { - if (!strcmp(compression_method_names[i].name, name)) - return compression_method_names[i].method; - } - return UNKNOWN_METHOD; -} - -/** Return a string representation of the version of the library providing the - * compression method given in <b>method</b>. Returns NULL if <b>method</b> is - * unknown or unsupported. */ -const char * -tor_compress_version_str(compress_method_t method) -{ - switch (method) { - case GZIP_METHOD: - case ZLIB_METHOD: - return tor_zlib_get_version_str(); - case LZMA_METHOD: - return tor_lzma_get_version_str(); - case ZSTD_METHOD: - return tor_zstd_get_version_str(); - case NO_METHOD: - case UNKNOWN_METHOD: - default: - return NULL; - } -} - -/** Return a string representation of the version of the library, found at - * compile time, providing the compression method given in <b>method</b>. - * Returns NULL if <b>method</b> is unknown or unsupported. */ -const char * -tor_compress_header_version_str(compress_method_t method) -{ - switch (method) { - case GZIP_METHOD: - case ZLIB_METHOD: - return tor_zlib_get_header_version_str(); - case LZMA_METHOD: - return tor_lzma_get_header_version_str(); - case ZSTD_METHOD: - return tor_zstd_get_header_version_str(); - case NO_METHOD: - case UNKNOWN_METHOD: - default: - return NULL; - } -} - -/** Return the approximate number of bytes allocated for all - * supported compression schemas. */ -size_t -tor_compress_get_total_allocation(void) -{ - return atomic_counter_get(&total_compress_allocation) + - tor_zlib_get_total_allocation() + - tor_lzma_get_total_allocation() + - tor_zstd_get_total_allocation(); -} - -/** Internal state for an incremental compression/decompression. The body of - * this struct is not exposed. */ -struct tor_compress_state_t { - compress_method_t method; /**< The compression method. */ - - union { - tor_zlib_compress_state_t *zlib_state; - tor_lzma_compress_state_t *lzma_state; - tor_zstd_compress_state_t *zstd_state; - } u; /**< Compression backend state. */ -}; - -/** Construct and return a tor_compress_state_t object using <b>method</b>. If - * <b>compress</b>, it's for compression; otherwise it's for decompression. */ -tor_compress_state_t * -tor_compress_new(int compress, compress_method_t method, - compression_level_t compression_level) -{ - tor_compress_state_t *state; - - state = tor_malloc_zero(sizeof(tor_compress_state_t)); - state->method = method; - - switch (method) { - case GZIP_METHOD: - case ZLIB_METHOD: { - tor_zlib_compress_state_t *zlib_state = - tor_zlib_compress_new(compress, method, compression_level); - - if (zlib_state == NULL) - goto err; - - state->u.zlib_state = zlib_state; - break; - } - case LZMA_METHOD: { - tor_lzma_compress_state_t *lzma_state = - tor_lzma_compress_new(compress, method, compression_level); - - if (lzma_state == NULL) - goto err; - - state->u.lzma_state = lzma_state; - break; - } - case ZSTD_METHOD: { - tor_zstd_compress_state_t *zstd_state = - tor_zstd_compress_new(compress, method, compression_level); - - if (zstd_state == NULL) - goto err; - - state->u.zstd_state = zstd_state; - break; - } - case NO_METHOD: { - break; - } - case UNKNOWN_METHOD: - goto err; - } - - atomic_counter_add(&total_compress_allocation, - sizeof(tor_compress_state_t)); - return state; - - err: - tor_free(state); - return NULL; -} - -/** Compress/decompress some bytes using <b>state</b>. Read up to - * *<b>in_len</b> bytes from *<b>in</b>, and write up to *<b>out_len</b> bytes - * to *<b>out</b>, adjusting the values as we go. If <b>finish</b> is true, - * we've reached the end of the input. - * - * Return TOR_COMPRESS_DONE if we've finished the entire - * compression/decompression. - * Return TOR_COMPRESS_OK if we're processed everything from the input. - * Return TOR_COMPRESS_BUFFER_FULL if we're out of space on <b>out</b>. - * Return TOR_COMPRESS_ERROR if the stream is corrupt. - */ -tor_compress_output_t -tor_compress_process(tor_compress_state_t *state, - char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish) -{ - tor_assert(state != NULL); - const size_t in_len_orig = *in_len; - const size_t out_len_orig = *out_len; - tor_compress_output_t rv; - - if (*out_len == 0 && (*in_len > 0 || finish)) { - // If we still have input data, but no space for output data, we might as - // well return early and let the caller do the reallocation of the out - // variable. - return TOR_COMPRESS_BUFFER_FULL; - } - - switch (state->method) { - case GZIP_METHOD: - case ZLIB_METHOD: - rv = tor_zlib_compress_process(state->u.zlib_state, - out, out_len, in, in_len, - finish); - break; - case LZMA_METHOD: - rv = tor_lzma_compress_process(state->u.lzma_state, - out, out_len, in, in_len, - finish); - break; - case ZSTD_METHOD: - rv = tor_zstd_compress_process(state->u.zstd_state, - out, out_len, in, in_len, - finish); - break; - case NO_METHOD: - rv = tor_cnone_compress_process(out, out_len, in, in_len, - finish); - break; - default: - case UNKNOWN_METHOD: - goto err; - } - if (BUG((rv == TOR_COMPRESS_OK) && - *in_len == in_len_orig && - *out_len == out_len_orig)) { - log_warn(LD_GENERAL, - "More info on the bug: method == %s, finish == %d, " - " *in_len == in_len_orig == %lu, " - "*out_len == out_len_orig == %lu", - compression_method_get_human_name(state->method), finish, - (unsigned long)in_len_orig, (unsigned long)out_len_orig); - return TOR_COMPRESS_ERROR; - } - - return rv; - err: - return TOR_COMPRESS_ERROR; -} - -/** Deallocate <b>state</b>. */ -void -tor_compress_free_(tor_compress_state_t *state) -{ - if (state == NULL) - return; - - switch (state->method) { - case GZIP_METHOD: - case ZLIB_METHOD: - tor_zlib_compress_free(state->u.zlib_state); - break; - case LZMA_METHOD: - tor_lzma_compress_free(state->u.lzma_state); - break; - case ZSTD_METHOD: - tor_zstd_compress_free(state->u.zstd_state); - break; - case NO_METHOD: - break; - case UNKNOWN_METHOD: - break; - } - - atomic_counter_sub(&total_compress_allocation, - sizeof(tor_compress_state_t)); - tor_free(state); -} - -/** Return the approximate number of bytes allocated for <b>state</b>. */ -size_t -tor_compress_state_size(const tor_compress_state_t *state) -{ - tor_assert(state != NULL); - - size_t size = sizeof(tor_compress_state_t); - - switch (state->method) { - case GZIP_METHOD: - case ZLIB_METHOD: - size += tor_zlib_compress_state_size(state->u.zlib_state); - break; - case LZMA_METHOD: - size += tor_lzma_compress_state_size(state->u.lzma_state); - break; - case ZSTD_METHOD: - size += tor_zstd_compress_state_size(state->u.zstd_state); - break; - case NO_METHOD: - case UNKNOWN_METHOD: - break; - } - - return size; -} - -/** Initialize all compression modules. */ -void -tor_compress_init(void) -{ - atomic_counter_init(&total_compress_allocation); - - tor_zlib_init(); - tor_lzma_init(); - tor_zstd_init(); -} - -/** Warn if we had any problems while setting up our compression libraries. - * - * (This isn't part of tor_compress_init, since the logs aren't set up yet.) - */ -void -tor_compress_log_init_warnings(void) -{ - tor_zstd_warn_if_version_mismatched(); -} - diff --git a/src/common/compress.h b/src/common/compress.h deleted file mode 100644 index 65d63a4386..0000000000 --- a/src/common/compress.h +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress.h - * \brief Headers for compress.c - **/ - -#ifndef TOR_COMPRESS_H -#define TOR_COMPRESS_H - -/** Enumeration of what kind of compression to use. Only ZLIB_METHOD and - * GZIP_METHOD is guaranteed to be supported by the compress/uncompress - * functions here. Call tor_compress_supports_method() to check if a given - * compression schema is supported by Tor. */ -typedef enum { - NO_METHOD=0, // This method must be first. - GZIP_METHOD=1, - ZLIB_METHOD=2, - LZMA_METHOD=3, - ZSTD_METHOD=4, - UNKNOWN_METHOD=5, // This method must be last. Add new ones in the middle. -} compress_method_t; - -/** - * Enumeration to define tradeoffs between memory usage and compression level. - * BEST_COMPRESSION saves the most bandwidth; LOW_COMPRESSION saves the most - * memory. - **/ -typedef enum { - BEST_COMPRESSION, HIGH_COMPRESSION, MEDIUM_COMPRESSION, LOW_COMPRESSION -} compression_level_t; - -int tor_compress(char **out, size_t *out_len, - const char *in, size_t in_len, - compress_method_t method); - -int tor_uncompress(char **out, size_t *out_len, - const char *in, size_t in_len, - compress_method_t method, - int complete_only, - int protocol_warn_level); - -compress_method_t detect_compression_method(const char *in, size_t in_len); - -MOCK_DECL(int,tor_compress_is_compression_bomb,(size_t size_in, - size_t size_out)); - -int tor_compress_supports_method(compress_method_t method); -unsigned tor_compress_get_supported_method_bitmask(void); -const char *compression_method_get_name(compress_method_t method); -const char *compression_method_get_human_name(compress_method_t method); -compress_method_t compression_method_get_by_name(const char *name); - -const char *tor_compress_version_str(compress_method_t method); - -const char *tor_compress_header_version_str(compress_method_t method); - -size_t tor_compress_get_total_allocation(void); - -/** Return values from tor_compress_process; see that function's documentation - * for details. */ -typedef enum { - TOR_COMPRESS_OK, - TOR_COMPRESS_DONE, - TOR_COMPRESS_BUFFER_FULL, - TOR_COMPRESS_ERROR -} tor_compress_output_t; - -/** Internal state for an incremental compression/decompression. */ -typedef struct tor_compress_state_t tor_compress_state_t; - -tor_compress_state_t *tor_compress_new(int compress, - compress_method_t method, - compression_level_t level); - -tor_compress_output_t tor_compress_process(tor_compress_state_t *state, - char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish); -void tor_compress_free_(tor_compress_state_t *state); -#define tor_compress_free(st) \ - FREE_AND_NULL(tor_compress_state_t, tor_compress_free_, (st)) - -size_t tor_compress_state_size(const tor_compress_state_t *state); - -void tor_compress_init(void); -void tor_compress_log_init_warnings(void); - -#endif /* !defined(TOR_COMPRESS_H) */ - diff --git a/src/common/compress_lzma.c b/src/common/compress_lzma.c deleted file mode 100644 index 051c59ba2d..0000000000 --- a/src/common/compress_lzma.c +++ /dev/null @@ -1,361 +0,0 @@ -/* Copyright (c) 2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress_lzma.c - * \brief Compression backend for LZMA. - * - * This module should never be invoked directly. Use the compress module - * instead. - **/ - -#include "orconfig.h" - -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_lzma.h" - -#ifdef HAVE_LZMA -#include <lzma.h> -#endif - -/** The maximum amount of memory we allow the LZMA decoder to use, in bytes. */ -#define MEMORY_LIMIT (16 * 1024 * 1024) - -/** Total number of bytes allocated for LZMA state. */ -static atomic_counter_t total_lzma_allocation; - -#ifdef HAVE_LZMA -/** Given <b>level</b> return the memory level. */ -static int -memory_level(compression_level_t level) -{ - switch (level) { - default: - case BEST_COMPRESSION: - case HIGH_COMPRESSION: return 6; - case MEDIUM_COMPRESSION: return 4; - case LOW_COMPRESSION: return 2; - } -} - -/** Convert a given <b>error</b> to a human readable error string. */ -static const char * -lzma_error_str(lzma_ret error) -{ - switch (error) { - case LZMA_OK: - return "Operation completed successfully"; - case LZMA_STREAM_END: - return "End of stream"; - case LZMA_NO_CHECK: - return "Input stream lacks integrity check"; - case LZMA_UNSUPPORTED_CHECK: - return "Unable to calculate integrity check"; - case LZMA_GET_CHECK: - return "Integrity check available"; - case LZMA_MEM_ERROR: - return "Unable to allocate memory"; - case LZMA_MEMLIMIT_ERROR: - return "Memory limit reached"; - case LZMA_FORMAT_ERROR: - return "Unknown file format"; - case LZMA_OPTIONS_ERROR: - return "Unsupported options"; - case LZMA_DATA_ERROR: - return "Corrupt input data"; - case LZMA_BUF_ERROR: - return "Unable to progress"; - case LZMA_PROG_ERROR: - return "Programming error"; - default: - return "Unknown LZMA error"; - } -} -#endif /* defined(HAVE_LZMA) */ - -/** Return 1 if LZMA compression is supported; otherwise 0. */ -int -tor_lzma_method_supported(void) -{ -#ifdef HAVE_LZMA - return 1; -#else - return 0; -#endif -} - -/** Return a string representation of the version of the currently running - * version of liblzma. Returns NULL if LZMA is unsupported. */ -const char * -tor_lzma_get_version_str(void) -{ -#ifdef HAVE_LZMA - return lzma_version_string(); -#else - return NULL; -#endif -} - -/** Return a string representation of the version of liblzma used at - * compilation time. Returns NULL if LZMA is unsupported. */ -const char * -tor_lzma_get_header_version_str(void) -{ -#ifdef HAVE_LZMA - return LZMA_VERSION_STRING; -#else - return NULL; -#endif -} - -/** Internal LZMA state for incremental compression/decompression. - * The body of this struct is not exposed. */ -struct tor_lzma_compress_state_t { -#ifdef HAVE_LZMA - lzma_stream stream; /**< The LZMA stream. */ -#endif - - int compress; /**< True if we are compressing; false if we are inflating */ - - /** Number of bytes read so far. Used to detect compression bombs. */ - size_t input_so_far; - /** Number of bytes written so far. Used to detect compression bombs. */ - size_t output_so_far; - - /** Approximate number of bytes allocated for this object. */ - size_t allocation; -}; - -#ifdef HAVE_LZMA -/** Return an approximate number of bytes stored in memory to hold the LZMA - * encoder/decoder state. */ -static size_t -tor_lzma_state_size_precalc(int compress, compression_level_t level) -{ - uint64_t memory_usage; - - if (compress) - memory_usage = lzma_easy_encoder_memusage(memory_level(level)); - else - memory_usage = lzma_easy_decoder_memusage(memory_level(level)); - - if (memory_usage == UINT64_MAX) { - // LCOV_EXCL_START - log_warn(LD_GENERAL, "Unsupported compression level passed to LZMA %s", - compress ? "encoder" : "decoder"); - goto err; - // LCOV_EXCL_STOP - } - - if (memory_usage + sizeof(tor_lzma_compress_state_t) > SIZE_MAX) - memory_usage = SIZE_MAX; - else - memory_usage += sizeof(tor_lzma_compress_state_t); - - return (size_t)memory_usage; - - // LCOV_EXCL_START - err: - return 0; - // LCOV_EXCL_STOP -} -#endif /* defined(HAVE_LZMA) */ - -/** Construct and return a tor_lzma_compress_state_t object using - * <b>method</b>. If <b>compress</b>, it's for compression; otherwise it's for - * decompression. */ -tor_lzma_compress_state_t * -tor_lzma_compress_new(int compress, - compress_method_t method, - compression_level_t level) -{ - tor_assert(method == LZMA_METHOD); - -#ifdef HAVE_LZMA - tor_lzma_compress_state_t *result; - lzma_ret retval; - lzma_options_lzma stream_options; - - // Note that we do not explicitly initialize the lzma_stream object here, - // since the LZMA_STREAM_INIT "just" initializes all members to 0, which is - // also what `tor_malloc_zero()` does. - result = tor_malloc_zero(sizeof(tor_lzma_compress_state_t)); - result->compress = compress; - result->allocation = tor_lzma_state_size_precalc(compress, level); - - if (compress) { - lzma_lzma_preset(&stream_options, memory_level(level)); - - retval = lzma_alone_encoder(&result->stream, &stream_options); - - if (retval != LZMA_OK) { - // LCOV_EXCL_START - log_warn(LD_GENERAL, "Error from LZMA encoder: %s (%u).", - lzma_error_str(retval), retval); - goto err; - // LCOV_EXCL_STOP - } - } else { - retval = lzma_alone_decoder(&result->stream, MEMORY_LIMIT); - - if (retval != LZMA_OK) { - // LCOV_EXCL_START - log_warn(LD_GENERAL, "Error from LZMA decoder: %s (%u).", - lzma_error_str(retval), retval); - goto err; - // LCOV_EXCL_STOP - } - } - - atomic_counter_add(&total_lzma_allocation, result->allocation); - return result; - - /* LCOV_EXCL_START */ - err: - tor_free(result); - return NULL; - /* LCOV_EXCL_STOP */ -#else /* !(defined(HAVE_LZMA)) */ - (void)compress; - (void)method; - (void)level; - - return NULL; -#endif /* defined(HAVE_LZMA) */ -} - -/** Compress/decompress some bytes using <b>state</b>. Read up to - * *<b>in_len</b> bytes from *<b>in</b>, and write up to *<b>out_len</b> bytes - * to *<b>out</b>, adjusting the values as we go. If <b>finish</b> is true, - * we've reached the end of the input. - * - * Return TOR_COMPRESS_DONE if we've finished the entire - * compression/decompression. - * Return TOR_COMPRESS_OK if we're processed everything from the input. - * Return TOR_COMPRESS_BUFFER_FULL if we're out of space on <b>out</b>. - * Return TOR_COMPRESS_ERROR if the stream is corrupt. - */ -tor_compress_output_t -tor_lzma_compress_process(tor_lzma_compress_state_t *state, - char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish) -{ -#ifdef HAVE_LZMA - lzma_ret retval; - lzma_action action; - - tor_assert(state != NULL); - tor_assert(*in_len <= UINT_MAX); - tor_assert(*out_len <= UINT_MAX); - - state->stream.next_in = (unsigned char *)*in; - state->stream.avail_in = *in_len; - state->stream.next_out = (unsigned char *)*out; - state->stream.avail_out = *out_len; - - action = finish ? LZMA_FINISH : LZMA_RUN; - - retval = lzma_code(&state->stream, action); - - state->input_so_far += state->stream.next_in - ((unsigned char *)*in); - state->output_so_far += state->stream.next_out - ((unsigned char *)*out); - - *out = (char *)state->stream.next_out; - *out_len = state->stream.avail_out; - *in = (const char *)state->stream.next_in; - *in_len = state->stream.avail_in; - - if (! state->compress && - tor_compress_is_compression_bomb(state->input_so_far, - state->output_so_far)) { - log_warn(LD_DIR, "Possible compression bomb; abandoning stream."); - return TOR_COMPRESS_ERROR; - } - - switch (retval) { - case LZMA_OK: - if (state->stream.avail_out == 0 || finish) - return TOR_COMPRESS_BUFFER_FULL; - - return TOR_COMPRESS_OK; - - case LZMA_BUF_ERROR: - if (state->stream.avail_in == 0 && !finish) - return TOR_COMPRESS_OK; - - return TOR_COMPRESS_BUFFER_FULL; - - case LZMA_STREAM_END: - return TOR_COMPRESS_DONE; - - // We list all the possible values of `lzma_ret` here to silence the - // `switch-enum` warning and to detect if a new member was added. - case LZMA_NO_CHECK: - case LZMA_UNSUPPORTED_CHECK: - case LZMA_GET_CHECK: - case LZMA_MEM_ERROR: - case LZMA_MEMLIMIT_ERROR: - case LZMA_FORMAT_ERROR: - case LZMA_OPTIONS_ERROR: - case LZMA_DATA_ERROR: - case LZMA_PROG_ERROR: - default: - log_warn(LD_GENERAL, "LZMA %s didn't finish: %s.", - state->compress ? "compression" : "decompression", - lzma_error_str(retval)); - return TOR_COMPRESS_ERROR; - } -#else /* !(defined(HAVE_LZMA)) */ - (void)state; - (void)out; - (void)out_len; - (void)in; - (void)in_len; - (void)finish; - return TOR_COMPRESS_ERROR; -#endif /* defined(HAVE_LZMA) */ -} - -/** Deallocate <b>state</b>. */ -void -tor_lzma_compress_free_(tor_lzma_compress_state_t *state) -{ - if (state == NULL) - return; - - atomic_counter_sub(&total_lzma_allocation, state->allocation); - -#ifdef HAVE_LZMA - lzma_end(&state->stream); -#endif - - tor_free(state); -} - -/** Return the approximate number of bytes allocated for <b>state</b>. */ -size_t -tor_lzma_compress_state_size(const tor_lzma_compress_state_t *state) -{ - tor_assert(state != NULL); - return state->allocation; -} - -/** Return the approximate number of bytes allocated for all LZMA states. */ -size_t -tor_lzma_get_total_allocation(void) -{ - return atomic_counter_get(&total_lzma_allocation); -} - -/** Initialize the lzma module */ -void -tor_lzma_init(void) -{ - atomic_counter_init(&total_lzma_allocation); -} - diff --git a/src/common/compress_lzma.h b/src/common/compress_lzma.h deleted file mode 100644 index 38a447c1f3..0000000000 --- a/src/common/compress_lzma.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress_lzma.h - * \brief Header for compress_lzma.c - **/ - -#ifndef TOR_COMPRESS_LZMA_H -#define TOR_COMPRESS_LZMA_H - -int tor_lzma_method_supported(void); - -const char *tor_lzma_get_version_str(void); - -const char *tor_lzma_get_header_version_str(void); - -/** Internal state for an incremental LZMA compression/decompression. */ -typedef struct tor_lzma_compress_state_t tor_lzma_compress_state_t; - -tor_lzma_compress_state_t * -tor_lzma_compress_new(int compress, - compress_method_t method, - compression_level_t compression_level); - -tor_compress_output_t -tor_lzma_compress_process(tor_lzma_compress_state_t *state, - char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish); - -void tor_lzma_compress_free_(tor_lzma_compress_state_t *state); -#define tor_lzma_compress_free(st) \ - FREE_AND_NULL(tor_lzma_compress_state_t, \ - tor_lzma_compress_free_, (st)) - -size_t tor_lzma_compress_state_size(const tor_lzma_compress_state_t *state); - -size_t tor_lzma_get_total_allocation(void); - -void tor_lzma_init(void); - -#endif /* !defined(TOR_COMPRESS_LZMA_H) */ - diff --git a/src/common/compress_none.c b/src/common/compress_none.c deleted file mode 100644 index 34314e4af7..0000000000 --- a/src/common/compress_none.c +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (c) 2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress_none.c - * \brief Compression backend for identity compression. - * - * We actually define this backend so that we can treat the identity transform - * as another case of compression. - * - * This module should never be invoked directly. Use the compress module - * instead. - **/ - -#include "orconfig.h" - -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_none.h" - -/** Transfer some bytes using the identity transformation. Read up to - * *<b>in_len</b> bytes from *<b>in</b>, and write up to *<b>out_len</b> bytes - * to *<b>out</b>, adjusting the values as we go. If <b>finish</b> is true, - * we've reached the end of the input. - * - * Return TOR_COMPRESS_DONE if we've finished the entire - * compression/decompression. - * Return TOR_COMPRESS_OK if we're processed everything from the input. - * Return TOR_COMPRESS_BUFFER_FULL if we're out of space on <b>out</b>. - * Return TOR_COMPRESS_ERROR if the stream is corrupt. - */ -tor_compress_output_t -tor_cnone_compress_process(char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish) -{ - size_t n_to_copy = MIN(*in_len, *out_len); - - memcpy(*out, *in, n_to_copy); - *out += n_to_copy; - *in += n_to_copy; - *out_len -= n_to_copy; - *in_len -= n_to_copy; - if (*in_len == 0) { - return finish ? TOR_COMPRESS_DONE : TOR_COMPRESS_OK; - } else { - return TOR_COMPRESS_BUFFER_FULL; - } -} - diff --git a/src/common/compress_none.h b/src/common/compress_none.h deleted file mode 100644 index 77c3cef47b..0000000000 --- a/src/common/compress_none.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress_none.h - * \brief Header for compress_none.c - **/ - -#ifndef TOR_COMPRESS_NONE_H -#define TOR_COMPRESS_NONE_H - -tor_compress_output_t -tor_cnone_compress_process(char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish); - -#endif /* !defined(TOR_COMPRESS_NONE_H) */ - diff --git a/src/common/compress_zlib.c b/src/common/compress_zlib.c deleted file mode 100644 index 23d71d27be..0000000000 --- a/src/common/compress_zlib.c +++ /dev/null @@ -1,304 +0,0 @@ -/* Copyright (c) 2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress_zlib.c - * \brief Compression backend for gzip and zlib. - * - * This module should never be invoked directly. Use the compress module - * instead. - **/ - -#include "orconfig.h" - -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_zlib.h" - -/* zlib 1.2.4 and 1.2.5 do some "clever" things with macros. Instead of - saying "(defined(FOO) ? FOO : 0)" they like to say "FOO-0", on the theory - that nobody will care if the compile outputs a no-such-identifier warning. - - Sorry, but we like -Werror over here, so I guess we need to define these. - I hope that zlib 1.2.6 doesn't break these too. -*/ -#ifndef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE 0 -#endif -#ifndef _LFS64_LARGEFILE -#define _LFS64_LARGEFILE 0 -#endif -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 0 -#endif -#ifndef off64_t -#define off64_t int64_t -#endif - -#include <zlib.h> - -#if defined ZLIB_VERNUM && ZLIB_VERNUM < 0x1200 -#error "We require zlib version 1.2 or later." -#endif - -static size_t tor_zlib_state_size_precalc(int inflate, - int windowbits, int memlevel); - -/** Total number of bytes allocated for zlib state */ -static atomic_counter_t total_zlib_allocation; - -/** Given <b>level</b> return the memory level. */ -static int -memory_level(compression_level_t level) -{ - switch (level) { - default: - case BEST_COMPRESSION: return 9; - case HIGH_COMPRESSION: return 8; - case MEDIUM_COMPRESSION: return 7; - case LOW_COMPRESSION: return 6; - } -} - -/** Return the 'bits' value to tell zlib to use <b>method</b>.*/ -static inline int -method_bits(compress_method_t method, compression_level_t level) -{ - /* Bits+16 means "use gzip" in zlib >= 1.2 */ - const int flag = method == GZIP_METHOD ? 16 : 0; - switch (level) { - default: - case BEST_COMPRESSION: - case HIGH_COMPRESSION: return flag + 15; - case MEDIUM_COMPRESSION: return flag + 13; - case LOW_COMPRESSION: return flag + 11; - } -} - -/** Return 1 if zlib/gzip compression is supported; otherwise 0. */ -int -tor_zlib_method_supported(void) -{ - /* We currently always support zlib/gzip, but we keep this function around in - * case we some day decide to deprecate zlib/gzip support. - */ - return 1; -} - -/** Return a string representation of the version of the currently running - * version of zlib. */ -const char * -tor_zlib_get_version_str(void) -{ - return zlibVersion(); -} - -/** Return a string representation of the version of the version of zlib -* used at compilation. */ -const char * -tor_zlib_get_header_version_str(void) -{ - return ZLIB_VERSION; -} - -/** Internal zlib state for an incremental compression/decompression. - * The body of this struct is not exposed. */ -struct tor_zlib_compress_state_t { - struct z_stream_s stream; /**< The zlib stream */ - int compress; /**< True if we are compressing; false if we are inflating */ - - /** Number of bytes read so far. Used to detect zlib bombs. */ - size_t input_so_far; - /** Number of bytes written so far. Used to detect zlib bombs. */ - size_t output_so_far; - - /** Approximate number of bytes allocated for this object. */ - size_t allocation; -}; - -/** Return an approximate number of bytes used in RAM to hold a state with - * window bits <b>windowBits</b> and compression level 'memlevel' */ -static size_t -tor_zlib_state_size_precalc(int inflate_, int windowbits, int memlevel) -{ - windowbits &= 15; - -#define A_FEW_KILOBYTES 2048 - - if (inflate_) { - /* From zconf.h: - - "The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects." - */ - return sizeof(tor_zlib_compress_state_t) + sizeof(struct z_stream_s) + - (1 << 15) + A_FEW_KILOBYTES; - } else { - /* Also from zconf.h: - - "The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - ... plus a few kilobytes for small objects." - */ - return sizeof(tor_zlib_compress_state_t) + sizeof(struct z_stream_s) + - (1 << (windowbits + 2)) + (1 << (memlevel + 9)) + A_FEW_KILOBYTES; - } -#undef A_FEW_KILOBYTES -} - -/** Construct and return a tor_zlib_compress_state_t object using - * <b>method</b>. If <b>compress</b>, it's for compression; otherwise it's for - * decompression. */ -tor_zlib_compress_state_t * -tor_zlib_compress_new(int compress_, - compress_method_t method, - compression_level_t compression_level) -{ - tor_zlib_compress_state_t *out; - int bits, memlevel; - - if (! compress_) { - /* use this setting for decompression, since we might have the - * max number of window bits */ - compression_level = BEST_COMPRESSION; - } - - out = tor_malloc_zero(sizeof(tor_zlib_compress_state_t)); - out->stream.zalloc = Z_NULL; - out->stream.zfree = Z_NULL; - out->stream.opaque = NULL; - out->compress = compress_; - bits = method_bits(method, compression_level); - memlevel = memory_level(compression_level); - if (compress_) { - if (deflateInit2(&out->stream, Z_BEST_COMPRESSION, Z_DEFLATED, - bits, memlevel, - Z_DEFAULT_STRATEGY) != Z_OK) - goto err; // LCOV_EXCL_LINE - } else { - if (inflateInit2(&out->stream, bits) != Z_OK) - goto err; // LCOV_EXCL_LINE - } - out->allocation = tor_zlib_state_size_precalc(!compress_, bits, memlevel); - - atomic_counter_add(&total_zlib_allocation, out->allocation); - - return out; - - err: - tor_free(out); - return NULL; -} - -/** Compress/decompress some bytes using <b>state</b>. Read up to - * *<b>in_len</b> bytes from *<b>in</b>, and write up to *<b>out_len</b> bytes - * to *<b>out</b>, adjusting the values as we go. If <b>finish</b> is true, - * we've reached the end of the input. - * - * Return TOR_COMPRESS_DONE if we've finished the entire - * compression/decompression. - * Return TOR_COMPRESS_OK if we're processed everything from the input. - * Return TOR_COMPRESS_BUFFER_FULL if we're out of space on <b>out</b>. - * Return TOR_COMPRESS_ERROR if the stream is corrupt. - */ -tor_compress_output_t -tor_zlib_compress_process(tor_zlib_compress_state_t *state, - char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish) -{ - int err; - tor_assert(state != NULL); - if (*in_len > UINT_MAX || - *out_len > UINT_MAX) { - return TOR_COMPRESS_ERROR; - } - - state->stream.next_in = (unsigned char*) *in; - state->stream.avail_in = (unsigned int)*in_len; - state->stream.next_out = (unsigned char*) *out; - state->stream.avail_out = (unsigned int)*out_len; - - if (state->compress) { - err = deflate(&state->stream, finish ? Z_FINISH : Z_NO_FLUSH); - } else { - err = inflate(&state->stream, finish ? Z_FINISH : Z_SYNC_FLUSH); - } - - state->input_so_far += state->stream.next_in - ((unsigned char*)*in); - state->output_so_far += state->stream.next_out - ((unsigned char*)*out); - - *out = (char*) state->stream.next_out; - *out_len = state->stream.avail_out; - *in = (const char *) state->stream.next_in; - *in_len = state->stream.avail_in; - - if (! state->compress && - tor_compress_is_compression_bomb(state->input_so_far, - state->output_so_far)) { - log_warn(LD_DIR, "Possible zlib bomb; abandoning stream."); - return TOR_COMPRESS_ERROR; - } - - switch (err) - { - case Z_STREAM_END: - return TOR_COMPRESS_DONE; - case Z_BUF_ERROR: - if (state->stream.avail_in == 0 && !finish) - return TOR_COMPRESS_OK; - return TOR_COMPRESS_BUFFER_FULL; - case Z_OK: - if (state->stream.avail_out == 0 || finish) - return TOR_COMPRESS_BUFFER_FULL; - return TOR_COMPRESS_OK; - default: - log_warn(LD_GENERAL, "Gzip returned an error: %s", - state->stream.msg ? state->stream.msg : "<no message>"); - return TOR_COMPRESS_ERROR; - } -} - -/** Deallocate <b>state</b>. */ -void -tor_zlib_compress_free_(tor_zlib_compress_state_t *state) -{ - if (state == NULL) - return; - - atomic_counter_sub(&total_zlib_allocation, state->allocation); - - if (state->compress) - deflateEnd(&state->stream); - else - inflateEnd(&state->stream); - - tor_free(state); -} - -/** Return the approximate number of bytes allocated for <b>state</b>. */ -size_t -tor_zlib_compress_state_size(const tor_zlib_compress_state_t *state) -{ - tor_assert(state != NULL); - return state->allocation; -} - -/** Return the approximate number of bytes allocated for all zlib states. */ -size_t -tor_zlib_get_total_allocation(void) -{ - return atomic_counter_get(&total_zlib_allocation); -} - -/** Set up global state for the zlib module */ -void -tor_zlib_init(void) -{ - atomic_counter_init(&total_zlib_allocation); -} - diff --git a/src/common/compress_zlib.h b/src/common/compress_zlib.h deleted file mode 100644 index e3c1a2b339..0000000000 --- a/src/common/compress_zlib.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress_zlib.h - * \brief Header for compress_zlib.c - **/ - -#ifndef TOR_COMPRESS_ZLIB_H -#define TOR_COMPRESS_ZLIB_H - -int tor_zlib_method_supported(void); - -const char *tor_zlib_get_version_str(void); - -const char *tor_zlib_get_header_version_str(void); - -/** Internal state for an incremental zlib/gzip compression/decompression. */ -typedef struct tor_zlib_compress_state_t tor_zlib_compress_state_t; - -tor_zlib_compress_state_t * -tor_zlib_compress_new(int compress, - compress_method_t method, - compression_level_t compression_level); - -tor_compress_output_t -tor_zlib_compress_process(tor_zlib_compress_state_t *state, - char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish); - -void tor_zlib_compress_free_(tor_zlib_compress_state_t *state); -#define tor_zlib_compress_free(st) \ - FREE_AND_NULL(tor_zlib_compress_state_t, \ - tor_zlib_compress_free_, (st)) - -size_t tor_zlib_compress_state_size(const tor_zlib_compress_state_t *state); - -size_t tor_zlib_get_total_allocation(void); - -void tor_zlib_init(void); - -#endif /* !defined(TOR_COMPRESS_ZLIB_H) */ - diff --git a/src/common/compress_zstd.c b/src/common/compress_zstd.c deleted file mode 100644 index dc8b4d621d..0000000000 --- a/src/common/compress_zstd.c +++ /dev/null @@ -1,540 +0,0 @@ -/* Copyright (c) 2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress_zstd.c - * \brief Compression backend for Zstandard. - * - * This module should never be invoked directly. Use the compress module - * instead. - **/ - -#include "orconfig.h" - -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_zstd.h" - -#ifdef ENABLE_ZSTD_ADVANCED_APIS -/* This is a lie, but we make sure it doesn't get us in trouble by wrapping - * all invocations of zstd's static-only functions in a check to make sure - * that the compile-time version matches the run-time version. */ -#define ZSTD_STATIC_LINKING_ONLY -#endif - -#ifdef HAVE_ZSTD -#ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE -DISABLE_GCC_WARNING(unused-const-variable) -#endif -#include <zstd.h> -#ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE -ENABLE_GCC_WARNING(unused-const-variable) -#endif -#endif - -/** Total number of bytes allocated for Zstandard state. */ -static atomic_counter_t total_zstd_allocation; - -#ifdef HAVE_ZSTD -/** Given <b>level</b> return the memory level. */ -static int -memory_level(compression_level_t level) -{ - switch (level) { - default: - case BEST_COMPRESSION: - case HIGH_COMPRESSION: return 9; - case MEDIUM_COMPRESSION: return 8; - case LOW_COMPRESSION: return 7; - } -} -#endif /* defined(HAVE_ZSTD) */ - -/** Return 1 if Zstandard compression is supported; otherwise 0. */ -int -tor_zstd_method_supported(void) -{ -#ifdef HAVE_ZSTD - return 1; -#else - return 0; -#endif -} - -#ifdef HAVE_ZSTD -/** Format a zstd version number as a string in <b>buf</b>. */ -static void -tor_zstd_format_version(char *buf, size_t buflen, unsigned version_number) -{ - tor_snprintf(buf, buflen, - "%u.%u.%u", - version_number / 10000 % 100, - version_number / 100 % 100, - version_number % 100); -} -#endif - -#define VERSION_STR_MAX_LEN 16 /* more than enough space for 99.99.99 */ - -/** Return a string representation of the version of the currently running - * version of libzstd. Returns NULL if Zstandard is unsupported. */ -const char * -tor_zstd_get_version_str(void) -{ -#ifdef HAVE_ZSTD - static char version_str[VERSION_STR_MAX_LEN]; - - tor_zstd_format_version(version_str, sizeof(version_str), - ZSTD_versionNumber()); - - return version_str; -#else /* !(defined(HAVE_ZSTD)) */ - return NULL; -#endif /* defined(HAVE_ZSTD) */ -} - -/** Return a string representation of the version of the version of libzstd - * used at compilation time. Returns NULL if Zstandard is unsupported. */ -const char * -tor_zstd_get_header_version_str(void) -{ -#ifdef HAVE_ZSTD - return ZSTD_VERSION_STRING; -#else - return NULL; -#endif -} - -#ifdef TOR_UNIT_TESTS -static int static_apis_disable_for_testing = 0; -#endif - -/** Return true iff we can use the "static-only" APIs. */ -int -tor_zstd_can_use_static_apis(void) -{ -#if defined(ZSTD_STATIC_LINKING_ONLY) && defined(HAVE_ZSTD) -#ifdef TOR_UNIT_TESTS - if (static_apis_disable_for_testing) { - return 0; - } -#endif - return (ZSTD_VERSION_NUMBER == ZSTD_versionNumber()); -#else - return 0; -#endif -} - -/** Internal Zstandard state for incremental compression/decompression. - * The body of this struct is not exposed. */ -struct tor_zstd_compress_state_t { -#ifdef HAVE_ZSTD - union { - /** Compression stream. Used when <b>compress</b> is true. */ - ZSTD_CStream *compress_stream; - /** Decompression stream. Used when <b>compress</b> is false. */ - ZSTD_DStream *decompress_stream; - } u; /**< Zstandard stream objects. */ -#endif /* defined(HAVE_ZSTD) */ - - int compress; /**< True if we are compressing; false if we are inflating */ - int have_called_end; /**< True if we are compressing and we've called - * ZSTD_endStream */ - - /** Number of bytes read so far. Used to detect compression bombs. */ - size_t input_so_far; - /** Number of bytes written so far. Used to detect compression bombs. */ - size_t output_so_far; - - /** Approximate number of bytes allocated for this object. */ - size_t allocation; -}; - -#ifdef HAVE_ZSTD -/** Return an approximate number of bytes stored in memory to hold the - * Zstandard compression/decompression state. This is a fake estimate - * based on inspecting the zstd source: tor_zstd_state_size_precalc() is - * more accurate when it's allowed to use "static-only" functions */ -static size_t -tor_zstd_state_size_precalc_fake(int compress, int preset) -{ - tor_assert(preset > 0); - - size_t memory_usage = sizeof(tor_zstd_compress_state_t); - - // The Zstandard library provides a number of functions that would be useful - // here, but they are, unfortunately, still considered experimental and are - // thus only available in libzstd if we link against the library statically. - // - // The code in this function tries to approximate the calculations without - // being able to use the following: - // - // - We do not have access to neither the internal members of ZSTD_CStream - // and ZSTD_DStream and their internal context objects. - // - // - We cannot use ZSTD_sizeof_CStream() and ZSTD_sizeof_DStream() since they - // are unexposed. - // - // In the future it might be useful to check if libzstd have started - // providing these functions in a stable manner and simplify this function. - if (compress) { - // We try to approximate the ZSTD_sizeof_CStream(ZSTD_CStream *stream) - // function here. This function uses the following fields to make its - // estimate: - - // - sizeof(ZSTD_CStream): Around 192 bytes on a 64-bit machine: - memory_usage += 192; - - // - ZSTD_sizeof_CCtx(stream->cctx): This function requires access to - // variables that are not exposed via the public API. We use a _very_ - // simplified function to calculate the estimated amount of bytes used in - // this struct. - // memory_usage += (preset - 0.5) * 1024 * 1024; - memory_usage += (preset * 1024 * 1024) - (512 * 1024); - // - ZSTD_sizeof_CDict(stream->cdictLocal): Unused in Tor: 0 bytes. - // - stream->outBuffSize: 128 KB: - memory_usage += 128 * 1024; - // - stream->inBuffSize: 2048 KB: - memory_usage += 2048 * 1024; - } else { - // We try to approximate the ZSTD_sizeof_DStream(ZSTD_DStream *stream) - // function here. This function uses the following fields to make its - // estimate: - - // - sizeof(ZSTD_DStream): Around 208 bytes on a 64-bit machine: - memory_usage += 208; - // - ZSTD_sizeof_DCtx(stream->dctx): Around 150 KB. - memory_usage += 150 * 1024; - - // - ZSTD_sizeof_DDict(stream->ddictLocal): Unused in Tor: 0 bytes. - // - stream->inBuffSize: 0 KB. - // - stream->outBuffSize: 0 KB. - } - - return memory_usage; -} - -/** Return an approximate number of bytes stored in memory to hold the - * Zstandard compression/decompression state. */ -static size_t -tor_zstd_state_size_precalc(int compress, int preset) -{ -#ifdef ZSTD_STATIC_LINKING_ONLY - if (tor_zstd_can_use_static_apis()) { - if (compress) { -#ifdef HAVE_ZSTD_ESTIMATECSTREAMSIZE - return ZSTD_estimateCStreamSize(preset); -#endif - } else { -#ifdef HAVE_ZSTD_ESTIMATEDCTXSIZE - /* Could use DStream, but that takes a windowSize. */ - return ZSTD_estimateDCtxSize(); -#endif - } - } -#endif - return tor_zstd_state_size_precalc_fake(compress, preset); -} -#endif /* defined(HAVE_ZSTD) */ - -/** Construct and return a tor_zstd_compress_state_t object using - * <b>method</b>. If <b>compress</b>, it's for compression; otherwise it's for - * decompression. */ -tor_zstd_compress_state_t * -tor_zstd_compress_new(int compress, - compress_method_t method, - compression_level_t level) -{ - tor_assert(method == ZSTD_METHOD); - -#ifdef HAVE_ZSTD - const int preset = memory_level(level); - tor_zstd_compress_state_t *result; - size_t retval; - - result = tor_malloc_zero(sizeof(tor_zstd_compress_state_t)); - result->compress = compress; - result->allocation = tor_zstd_state_size_precalc(compress, preset); - - if (compress) { - result->u.compress_stream = ZSTD_createCStream(); - - if (result->u.compress_stream == NULL) { - // LCOV_EXCL_START - log_warn(LD_GENERAL, "Error while creating Zstandard compression " - "stream"); - goto err; - // LCOV_EXCL_STOP - } - - retval = ZSTD_initCStream(result->u.compress_stream, preset); - - if (ZSTD_isError(retval)) { - // LCOV_EXCL_START - log_warn(LD_GENERAL, "Zstandard stream initialization error: %s", - ZSTD_getErrorName(retval)); - goto err; - // LCOV_EXCL_STOP - } - } else { - result->u.decompress_stream = ZSTD_createDStream(); - - if (result->u.decompress_stream == NULL) { - // LCOV_EXCL_START - log_warn(LD_GENERAL, "Error while creating Zstandard decompression " - "stream"); - goto err; - // LCOV_EXCL_STOP - } - - retval = ZSTD_initDStream(result->u.decompress_stream); - - if (ZSTD_isError(retval)) { - // LCOV_EXCL_START - log_warn(LD_GENERAL, "Zstandard stream initialization error: %s", - ZSTD_getErrorName(retval)); - goto err; - // LCOV_EXCL_STOP - } - } - - atomic_counter_add(&total_zstd_allocation, result->allocation); - return result; - - err: - // LCOV_EXCL_START - if (compress) { - ZSTD_freeCStream(result->u.compress_stream); - } else { - ZSTD_freeDStream(result->u.decompress_stream); - } - - tor_free(result); - return NULL; - // LCOV_EXCL_STOP -#else /* !(defined(HAVE_ZSTD)) */ - (void)compress; - (void)method; - (void)level; - - return NULL; -#endif /* defined(HAVE_ZSTD) */ -} - -/** Compress/decompress some bytes using <b>state</b>. Read up to - * *<b>in_len</b> bytes from *<b>in</b>, and write up to *<b>out_len</b> bytes - * to *<b>out</b>, adjusting the values as we go. If <b>finish</b> is true, - * we've reached the end of the input. - * - * Return TOR_COMPRESS_DONE if we've finished the entire - * compression/decompression. - * Return TOR_COMPRESS_OK if we're processed everything from the input. - * Return TOR_COMPRESS_BUFFER_FULL if we're out of space on <b>out</b>. - * Return TOR_COMPRESS_ERROR if the stream is corrupt. - */ -tor_compress_output_t -tor_zstd_compress_process(tor_zstd_compress_state_t *state, - char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish) -{ -#ifdef HAVE_ZSTD - size_t retval; - - tor_assert(state != NULL); - tor_assert(*in_len <= UINT_MAX); - tor_assert(*out_len <= UINT_MAX); - - ZSTD_inBuffer input = { *in, *in_len, 0 }; - ZSTD_outBuffer output = { *out, *out_len, 0 }; - - if (BUG(finish == 0 && state->have_called_end)) { - finish = 1; - } - - if (state->compress) { - if (! state->have_called_end) - retval = ZSTD_compressStream(state->u.compress_stream, - &output, &input); - else - retval = 0; - } else { - retval = ZSTD_decompressStream(state->u.decompress_stream, - &output, &input); - } - - state->input_so_far += input.pos; - state->output_so_far += output.pos; - - *out = (char *)output.dst + output.pos; - *out_len = output.size - output.pos; - *in = (char *)input.src + input.pos; - *in_len = input.size - input.pos; - - if (! state->compress && - tor_compress_is_compression_bomb(state->input_so_far, - state->output_so_far)) { - log_warn(LD_DIR, "Possible compression bomb; abandoning stream."); - return TOR_COMPRESS_ERROR; - } - - if (ZSTD_isError(retval)) { - log_warn(LD_GENERAL, "Zstandard %s didn't finish: %s.", - state->compress ? "compression" : "decompression", - ZSTD_getErrorName(retval)); - return TOR_COMPRESS_ERROR; - } - - if (state->compress && !state->have_called_end) { - retval = ZSTD_flushStream(state->u.compress_stream, &output); - - *out = (char *)output.dst + output.pos; - *out_len = output.size - output.pos; - - if (ZSTD_isError(retval)) { - log_warn(LD_GENERAL, "Zstandard compression unable to flush: %s.", - ZSTD_getErrorName(retval)); - return TOR_COMPRESS_ERROR; - } - - // ZSTD_flushStream returns 0 if the frame is done, or >0 if it - // is incomplete. - if (retval > 0) { - return TOR_COMPRESS_BUFFER_FULL; - } - } - - if (!finish) { - // The caller says we're not done with the input, so no need to write an - // epilogue. - return TOR_COMPRESS_OK; - } else if (state->compress) { - if (*in_len) { - // We say that we're not done with the input, so we can't write an - // epilogue. - return TOR_COMPRESS_OK; - } - - retval = ZSTD_endStream(state->u.compress_stream, &output); - state->have_called_end = 1; - *out = (char *)output.dst + output.pos; - *out_len = output.size - output.pos; - - if (ZSTD_isError(retval)) { - log_warn(LD_GENERAL, "Zstandard compression unable to write " - "epilogue: %s.", - ZSTD_getErrorName(retval)); - return TOR_COMPRESS_ERROR; - } - - // endStream returns the number of bytes that is needed to write the - // epilogue. - if (retval > 0) - return TOR_COMPRESS_BUFFER_FULL; - - return TOR_COMPRESS_DONE; - } else /* if (!state->compress) */ { - // ZSTD_decompressStream returns 0 if the frame is done, or >0 if it - // is incomplete. - // We check this above. - tor_assert_nonfatal(!ZSTD_isError(retval)); - // Start a new frame if this frame is done - if (retval == 0) - return TOR_COMPRESS_DONE; - // Don't check out_len, it might have some space left if the next output - // chunk is larger than the remaining space - else if (*in_len > 0) - return TOR_COMPRESS_BUFFER_FULL; - else - return TOR_COMPRESS_OK; - } - -#else /* !(defined(HAVE_ZSTD)) */ - (void)state; - (void)out; - (void)out_len; - (void)in; - (void)in_len; - (void)finish; - - return TOR_COMPRESS_ERROR; -#endif /* defined(HAVE_ZSTD) */ -} - -/** Deallocate <b>state</b>. */ -void -tor_zstd_compress_free_(tor_zstd_compress_state_t *state) -{ - if (state == NULL) - return; - - atomic_counter_sub(&total_zstd_allocation, state->allocation); - -#ifdef HAVE_ZSTD - if (state->compress) { - ZSTD_freeCStream(state->u.compress_stream); - } else { - ZSTD_freeDStream(state->u.decompress_stream); - } -#endif /* defined(HAVE_ZSTD) */ - - tor_free(state); -} - -/** Return the approximate number of bytes allocated for <b>state</b>. */ -size_t -tor_zstd_compress_state_size(const tor_zstd_compress_state_t *state) -{ - tor_assert(state != NULL); - return state->allocation; -} - -/** Return the approximate number of bytes allocated for all Zstandard - * states. */ -size_t -tor_zstd_get_total_allocation(void) -{ - return atomic_counter_get(&total_zstd_allocation); -} - -/** Initialize the zstd module */ -void -tor_zstd_init(void) -{ - atomic_counter_init(&total_zstd_allocation); -} - -/** Warn if the header and library versions don't match. */ -void -tor_zstd_warn_if_version_mismatched(void) -{ -#if defined(HAVE_ZSTD) && defined(ENABLE_ZSTD_ADVANCED_APIS) - if (! tor_zstd_can_use_static_apis()) { - char header_version[VERSION_STR_MAX_LEN]; - char runtime_version[VERSION_STR_MAX_LEN]; - tor_zstd_format_version(header_version, sizeof(header_version), - ZSTD_VERSION_NUMBER); - tor_zstd_format_version(runtime_version, sizeof(runtime_version), - ZSTD_versionNumber()); - - log_warn(LD_GENERAL, - "Tor was compiled with zstd %s, but is running with zstd %s. " - "For safety, we'll avoid using advanced zstd functionality.", - header_version, runtime_version); - } -#endif -} - -#ifdef TOR_UNIT_TESTS -/** Testing only: disable usage of static-only APIs, so we can make sure that - * we still work without them. */ -void -tor_zstd_set_static_apis_disabled_for_testing(int disabled) -{ - static_apis_disable_for_testing = disabled; -} -#endif - diff --git a/src/common/compress_zstd.h b/src/common/compress_zstd.h deleted file mode 100644 index bd42cf65ce..0000000000 --- a/src/common/compress_zstd.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compress_zstd.h - * \brief Header for compress_zstd.c - **/ - -#ifndef TOR_COMPRESS_ZSTD_H -#define TOR_COMPRESS_ZSTD_H - -int tor_zstd_method_supported(void); - -const char *tor_zstd_get_version_str(void); - -const char *tor_zstd_get_header_version_str(void); - -int tor_zstd_can_use_static_apis(void); - -/** Internal state for an incremental Zstandard compression/decompression. */ -typedef struct tor_zstd_compress_state_t tor_zstd_compress_state_t; - -tor_zstd_compress_state_t * -tor_zstd_compress_new(int compress, - compress_method_t method, - compression_level_t compression_level); - -tor_compress_output_t -tor_zstd_compress_process(tor_zstd_compress_state_t *state, - char **out, size_t *out_len, - const char **in, size_t *in_len, - int finish); - -void tor_zstd_compress_free_(tor_zstd_compress_state_t *state); -#define tor_zstd_compress_free(st) \ - FREE_AND_NULL(tor_zstd_compress_state_t, \ - tor_zstd_compress_free_, (st)) - -size_t tor_zstd_compress_state_size(const tor_zstd_compress_state_t *state); - -size_t tor_zstd_get_total_allocation(void); - -void tor_zstd_init(void); -void tor_zstd_warn_if_version_mismatched(void); - -#ifdef TOR_UNIT_TESTS -void tor_zstd_set_static_apis_disabled_for_testing(int disabled); -#endif - -#endif /* !defined(TOR_COMPRESS_ZSTD_H) */ - diff --git a/src/common/confline.c b/src/common/confline.c deleted file mode 100644 index bf613ab742..0000000000 --- a/src/common/confline.c +++ /dev/null @@ -1,538 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#include "compat.h" -#include "confline.h" -#include "torlog.h" -#include "util.h" -#include "container.h" - -static int config_get_lines_aux(const char *string, config_line_t **result, - int extended, int allow_include, - int *has_include, smartlist_t *opened_lst, - int recursion_level, config_line_t **last); -static smartlist_t *config_get_file_list(const char *path, - smartlist_t *opened_files); -static int config_get_included_config(const char *path, int recursion_level, - int extended, config_line_t **config, - config_line_t **config_last, - smartlist_t *opened_lst); -static int config_process_include(const char *path, int recursion_level, - int extended, config_line_t **list, - config_line_t **list_last, - smartlist_t *opened_lst); - -/** Helper: allocate a new configuration option mapping 'key' to 'val', - * append it to *<b>lst</b>. */ -void -config_line_append(config_line_t **lst, - const char *key, - const char *val) -{ - tor_assert(lst); - - config_line_t *newline; - - newline = tor_malloc_zero(sizeof(config_line_t)); - newline->key = tor_strdup(key); - newline->value = tor_strdup(val); - newline->next = NULL; - while (*lst) - lst = &((*lst)->next); - - (*lst) = newline; -} - -/** Helper: allocate a new configuration option mapping 'key' to 'val', - * and prepend it to *<b>lst</b> */ -void -config_line_prepend(config_line_t **lst, - const char *key, - const char *val) -{ - tor_assert(lst); - - config_line_t *newline; - - newline = tor_malloc_zero(sizeof(config_line_t)); - newline->key = tor_strdup(key); - newline->value = tor_strdup(val); - newline->next = *lst; - *lst = newline; -} - -/** Return the first line in <b>lines</b> whose key is exactly <b>key</b>, or - * NULL if no such key exists. - * - * (In options parsing, this is for handling commandline-only options only; - * other options should be looked up in the appropriate data structure.) */ -const config_line_t * -config_line_find(const config_line_t *lines, - const char *key) -{ - const config_line_t *cl; - for (cl = lines; cl; cl = cl->next) { - if (!strcmp(cl->key, key)) - return cl; - } - return NULL; -} - -/** Auxiliary function that does all the work of config_get_lines. - * <b>recursion_level</b> is the count of how many nested %includes we have. - * <b>opened_lst</b> will have a list of opened files if provided. - * Returns the a pointer to the last element of the <b>result</b> in - * <b>last</b>. */ -static int -config_get_lines_aux(const char *string, config_line_t **result, int extended, - int allow_include, int *has_include, - smartlist_t *opened_lst, int recursion_level, - config_line_t **last) -{ - config_line_t *list = NULL, **next, *list_last = NULL; - char *k, *v; - const char *parse_err; - int include_used = 0; - - if (recursion_level > MAX_INCLUDE_RECURSION_LEVEL) { - log_warn(LD_CONFIG, "Error while parsing configuration: more than %d " - "nested %%includes.", MAX_INCLUDE_RECURSION_LEVEL); - return -1; - } - - next = &list; - do { - k = v = NULL; - string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err); - if (!string) { - log_warn(LD_CONFIG, "Error while parsing configuration: %s", - parse_err?parse_err:"<unknown>"); - config_free_lines(list); - tor_free(k); - tor_free(v); - return -1; - } - if (k && v) { - unsigned command = CONFIG_LINE_NORMAL; - if (extended) { - if (k[0] == '+') { - char *k_new = tor_strdup(k+1); - tor_free(k); - k = k_new; - command = CONFIG_LINE_APPEND; - } else if (k[0] == '/') { - char *k_new = tor_strdup(k+1); - tor_free(k); - k = k_new; - tor_free(v); - v = tor_strdup(""); - command = CONFIG_LINE_CLEAR; - } - } - - if (allow_include && !strcmp(k, "%include")) { - tor_free(k); - include_used = 1; - - config_line_t *include_list; - if (config_process_include(v, recursion_level, extended, &include_list, - &list_last, opened_lst) < 0) { - log_warn(LD_CONFIG, "Error reading included configuration " - "file or directory: \"%s\".", v); - config_free_lines(list); - tor_free(v); - return -1; - } - *next = include_list; - if (list_last) - next = &list_last->next; - tor_free(v); - } else { - /* This list can get long, so we keep a pointer to the end of it - * rather than using config_line_append over and over and getting - * n^2 performance. */ - *next = tor_malloc_zero(sizeof(**next)); - (*next)->key = k; - (*next)->value = v; - (*next)->next = NULL; - (*next)->command = command; - list_last = *next; - next = &((*next)->next); - } - } else { - tor_free(k); - tor_free(v); - } - } while (*string); - - if (last) { - *last = list_last; - } - if (has_include) { - *has_include = include_used; - } - *result = list; - return 0; -} - -/** Helper: parse the config string and strdup into key/value - * strings. Set *result to the list, or NULL if parsing the string - * failed. Set *has_include to 1 if <b>result</b> has values from - * %included files. <b>opened_lst</b> will have a list of opened files if - * provided. Return 0 on success, -1 on failure. Warn and ignore any - * misformatted lines. - * - * If <b>extended</b> is set, then treat keys beginning with / and with + as - * indicating "clear" and "append" respectively. */ -int -config_get_lines_include(const char *string, config_line_t **result, - int extended, int *has_include, - smartlist_t *opened_lst) -{ - return config_get_lines_aux(string, result, extended, 1, has_include, - opened_lst, 1, NULL); -} - -/** Same as config_get_lines_include but does not allow %include */ -int -config_get_lines(const char *string, config_line_t **result, int extended) -{ - return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1, - NULL); -} - -/** Adds a list of configuration files present on <b>path</b> to - * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file, - * only that file will be added to <b>file_list</b>. If it is a directory, - * all paths for files on that directory root (no recursion) except for files - * whose name starts with a dot will be added to <b>file_list</b>. - * <b>opened_files</b> will have a list of files opened by this function - * if provided. Return 0 on success, -1 on failure. Ignores empty files. - */ -static smartlist_t * -config_get_file_list(const char *path, smartlist_t *opened_files) -{ - smartlist_t *file_list = smartlist_new(); - - if (opened_files) { - smartlist_add_strdup(opened_files, path); - } - - file_status_t file_type = file_status(path); - if (file_type == FN_FILE) { - smartlist_add_strdup(file_list, path); - return file_list; - } else if (file_type == FN_DIR) { - smartlist_t *all_files = tor_listdir(path); - if (!all_files) { - smartlist_free(file_list); - return NULL; - } - smartlist_sort_strings(all_files); - SMARTLIST_FOREACH_BEGIN(all_files, char *, f) { - if (f[0] == '.') { - tor_free(f); - continue; - } - - char *fullname; - tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f); - tor_free(f); - - if (opened_files) { - smartlist_add_strdup(opened_files, fullname); - } - - if (file_status(fullname) != FN_FILE) { - tor_free(fullname); - continue; - } - smartlist_add(file_list, fullname); - } SMARTLIST_FOREACH_END(f); - smartlist_free(all_files); - return file_list; - } else if (file_type == FN_EMPTY) { - return file_list; - } else { - smartlist_free(file_list); - return NULL; - } -} - -/** Creates a list of config lines present on included <b>path</b>. - * Set <b>config</b> to the list and <b>config_last</b> to the last element of - * <b>config</b>. <b>opened_lst</b> will have a list of opened files if - * provided. Return 0 on success, -1 on failure. */ -static int -config_get_included_config(const char *path, int recursion_level, int extended, - config_line_t **config, config_line_t **config_last, - smartlist_t *opened_lst) -{ - char *included_conf = read_file_to_str(path, 0, NULL); - if (!included_conf) { - return -1; - } - - if (config_get_lines_aux(included_conf, config, extended, 1, NULL, - opened_lst, recursion_level+1, config_last) < 0) { - tor_free(included_conf); - return -1; - } - - tor_free(included_conf); - return 0; -} - -/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the - * list of configuration settings obtained and <b>list_last</b> to the last - * element of the same list. <b>opened_lst</b> will have a list of opened - * files if provided. Return 0 on success, -1 on failure. */ -static int -config_process_include(const char *path, int recursion_level, int extended, - config_line_t **list, config_line_t **list_last, - smartlist_t *opened_lst) -{ - config_line_t *ret_list = NULL; - config_line_t **next = &ret_list; - - smartlist_t *config_files = config_get_file_list(path, opened_lst); - if (!config_files) { - return -1; - } - - int rv = -1; - SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) { - config_line_t *included_config = NULL; - if (config_get_included_config(config_file, recursion_level, extended, - &included_config, list_last, - opened_lst) < 0) { - goto done; - } - - *next = included_config; - if (*list_last) - next = &(*list_last)->next; - - } SMARTLIST_FOREACH_END(config_file); - *list = ret_list; - rv = 0; - - done: - SMARTLIST_FOREACH(config_files, char *, f, tor_free(f)); - smartlist_free(config_files); - return rv; -} - -/** - * Free all the configuration lines on the linked list <b>front</b>. - */ -void -config_free_lines_(config_line_t *front) -{ - config_line_t *tmp; - - while (front) { - tmp = front; - front = tmp->next; - - tor_free(tmp->key); - tor_free(tmp->value); - tor_free(tmp); - } -} - -/** Return a newly allocated deep copy of the lines in <b>inp</b>. */ -config_line_t * -config_lines_dup(const config_line_t *inp) -{ - return config_lines_dup_and_filter(inp, NULL); -} - -/** Return a newly allocated deep copy of the lines in <b>inp</b>, - * but only the ones whose keys begin with <b>key</b> (case-insensitive). - * If <b>key</b> is NULL, do not filter. */ -config_line_t * -config_lines_dup_and_filter(const config_line_t *inp, - const char *key) -{ - config_line_t *result = NULL; - config_line_t **next_out = &result; - while (inp) { - if (key && strcasecmpstart(inp->key, key)) { - inp = inp->next; - continue; - } - *next_out = tor_malloc_zero(sizeof(config_line_t)); - (*next_out)->key = tor_strdup(inp->key); - (*next_out)->value = tor_strdup(inp->value); - inp = inp->next; - next_out = &((*next_out)->next); - } - (*next_out) = NULL; - return result; -} - -/** Return true iff a and b contain identical keys and values in identical - * order. */ -int -config_lines_eq(config_line_t *a, config_line_t *b) -{ - while (a && b) { - if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value)) - return 0; - a = a->next; - b = b->next; - } - if (a || b) - return 0; - return 1; -} - -/** Return the number of lines in <b>a</b> whose key is <b>key</b>. */ -int -config_count_key(const config_line_t *a, const char *key) -{ - int n = 0; - while (a) { - if (!strcasecmp(a->key, key)) { - ++n; - } - a = a->next; - } - return n; -} - -/** Given a string containing part of a configuration file or similar format, - * advance past comments and whitespace and try to parse a single line. If we - * parse a line successfully, set *<b>key_out</b> to a new string holding the - * key portion and *<b>value_out</b> to a new string holding the value portion - * of the line, and return a pointer to the start of the next line. If we run - * out of data, return a pointer to the end of the string. If we encounter an - * error, return NULL and set *<b>err_out</b> (if provided) to an error - * message. - */ -const char * -parse_config_line_from_str_verbose(const char *line, char **key_out, - char **value_out, - const char **err_out) -{ - /* - See torrc_format.txt for a description of the (silly) format this parses. - */ - const char *key, *val, *cp; - int continuation = 0; - - tor_assert(key_out); - tor_assert(value_out); - - *key_out = *value_out = NULL; - key = val = NULL; - /* Skip until the first keyword. */ - while (1) { - while (TOR_ISSPACE(*line)) - ++line; - if (*line == '#') { - while (*line && *line != '\n') - ++line; - } else { - break; - } - } - - if (!*line) { /* End of string? */ - *key_out = *value_out = NULL; - return line; - } - - /* Skip until the next space or \ followed by newline. */ - key = line; - while (*line && !TOR_ISSPACE(*line) && *line != '#' && - ! (line[0] == '\\' && line[1] == '\n')) - ++line; - *key_out = tor_strndup(key, line-key); - - /* Skip until the value. */ - while (*line == ' ' || *line == '\t') - ++line; - - val = line; - - /* Find the end of the line. */ - if (*line == '\"') { // XXX No continuation handling is done here - if (!(line = unescape_string(line, value_out, NULL))) { - if (err_out) - *err_out = "Invalid escape sequence in quoted string"; - return NULL; - } - while (*line == ' ' || *line == '\t') - ++line; - if (*line == '\r' && *(++line) == '\n') - ++line; - if (*line && *line != '#' && *line != '\n') { - if (err_out) - *err_out = "Excess data after quoted string"; - return NULL; - } - } else { - /* Look for the end of the line. */ - while (*line && *line != '\n' && (*line != '#' || continuation)) { - if (*line == '\\' && line[1] == '\n') { - continuation = 1; - line += 2; - } else if (*line == '#') { - do { - ++line; - } while (*line && *line != '\n'); - if (*line == '\n') - ++line; - } else { - ++line; - } - } - - if (*line == '\n') { - cp = line++; - } else { - cp = line; - } - /* Now back cp up to be the last nonspace character */ - while (cp>val && TOR_ISSPACE(*(cp-1))) - --cp; - - tor_assert(cp >= val); - - /* Now copy out and decode the value. */ - *value_out = tor_strndup(val, cp-val); - if (continuation) { - char *v_out, *v_in; - v_out = v_in = *value_out; - while (*v_in) { - if (*v_in == '#') { - do { - ++v_in; - } while (*v_in && *v_in != '\n'); - if (*v_in == '\n') - ++v_in; - } else if (v_in[0] == '\\' && v_in[1] == '\n') { - v_in += 2; - } else { - *v_out++ = *v_in++; - } - } - *v_out = '\0'; - } - } - - if (*line == '#') { - do { - ++line; - } while (*line && *line != '\n'); - } - while (TOR_ISSPACE(*line)) ++line; - - return line; -} - diff --git a/src/common/confline.h b/src/common/confline.h deleted file mode 100644 index 772a9bbbdc..0000000000 --- a/src/common/confline.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CONFLINE_H -#define TOR_CONFLINE_H - -#include "container.h" - -/** Ordinary configuration line. */ -#define CONFIG_LINE_NORMAL 0 -/** Appends to previous configuration for the same option, even if we - * would ordinary replace it. */ -#define CONFIG_LINE_APPEND 1 -/* Removes all previous configuration for an option. */ -#define CONFIG_LINE_CLEAR 2 - -#define MAX_INCLUDE_RECURSION_LEVEL 31 - -/** A linked list of lines in a config file, or elsewhere */ -typedef struct config_line_t { - char *key; - char *value; - struct config_line_t *next; - - /** What special treatment (if any) does this line require? */ - unsigned int command:2; - /** If true, subsequent assignments to this linelist should replace - * it, not extend it. Set only on the first item in a linelist in an - * or_options_t. */ - unsigned int fragile:1; -} config_line_t; - -void config_line_append(config_line_t **lst, - const char *key, const char *val); -void config_line_prepend(config_line_t **lst, - const char *key, const char *val); -config_line_t *config_lines_dup(const config_line_t *inp); -config_line_t *config_lines_dup_and_filter(const config_line_t *inp, - const char *key); -const config_line_t *config_line_find(const config_line_t *lines, - const char *key); -int config_lines_eq(config_line_t *a, config_line_t *b); -int config_count_key(const config_line_t *a, const char *key); -int config_get_lines(const char *string, config_line_t **result, int extended); -int config_get_lines_include(const char *string, config_line_t **result, - int extended, int *has_include, - smartlist_t *opened_lst); -void config_free_lines_(config_line_t *front); -#define config_free_lines(front) \ - do { \ - config_free_lines_(front); \ - (front) = NULL; \ - } while (0) -const char *parse_config_line_from_str_verbose(const char *line, - char **key_out, char **value_out, - const char **err_out); -#endif /* !defined(TOR_CONFLINE_H) */ - diff --git a/src/common/container.c b/src/common/container.c deleted file mode 100644 index 5386e6458b..0000000000 --- a/src/common/container.c +++ /dev/null @@ -1,1542 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file container.c - * \brief Implements a smartlist (a resizable array) along - * with helper functions to use smartlists. Also includes - * hash table implementations of a string-to-void* map, and of - * a digest-to-void* map. - **/ - -#include "compat.h" -#include "util.h" -#include "torlog.h" -#include "container.h" -#include "crypto_digest.h" - -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#include "ht.h" - -/** All newly allocated smartlists have this capacity. */ -#define SMARTLIST_DEFAULT_CAPACITY 16 - -/** Allocate and return an empty smartlist. - */ -MOCK_IMPL(smartlist_t *, -smartlist_new,(void)) -{ - smartlist_t *sl = tor_malloc(sizeof(smartlist_t)); - sl->num_used = 0; - sl->capacity = SMARTLIST_DEFAULT_CAPACITY; - sl->list = tor_calloc(sizeof(void *), sl->capacity); - return sl; -} - -/** Deallocate a smartlist. Does not release storage associated with the - * list's elements. - */ -MOCK_IMPL(void, -smartlist_free_,(smartlist_t *sl)) -{ - if (!sl) - return; - tor_free(sl->list); - tor_free(sl); -} - -/** Remove all elements from the list. - */ -void -smartlist_clear(smartlist_t *sl) -{ - memset(sl->list, 0, sizeof(void *) * sl->num_used); - sl->num_used = 0; -} - -#if SIZE_MAX < INT_MAX -#error "We don't support systems where size_t is smaller than int." -#endif - -/** Make sure that <b>sl</b> can hold at least <b>size</b> entries. */ -static inline void -smartlist_ensure_capacity(smartlist_t *sl, size_t size) -{ - /* Set MAX_CAPACITY to MIN(INT_MAX, SIZE_MAX / sizeof(void*)) */ -#if (SIZE_MAX/SIZEOF_VOID_P) > INT_MAX -#define MAX_CAPACITY (INT_MAX) -#else -#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*)))) -#endif - - tor_assert(size <= MAX_CAPACITY); - - if (size > (size_t) sl->capacity) { - size_t higher = (size_t) sl->capacity; - if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) { - higher = MAX_CAPACITY; - } else { - while (size > higher) - higher *= 2; - } - sl->list = tor_reallocarray(sl->list, sizeof(void *), - ((size_t)higher)); - memset(sl->list + sl->capacity, 0, - sizeof(void *) * (higher - sl->capacity)); - sl->capacity = (int) higher; - } -#undef ASSERT_CAPACITY -#undef MAX_CAPACITY -} - -/** Append element to the end of the list. */ -void -smartlist_add(smartlist_t *sl, void *element) -{ - smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); - sl->list[sl->num_used++] = element; -} - -/** Append each element from S2 to the end of S1. */ -void -smartlist_add_all(smartlist_t *s1, const smartlist_t *s2) -{ - size_t new_size = (size_t)s1->num_used + (size_t)s2->num_used; - tor_assert(new_size >= (size_t) s1->num_used); /* check for overflow. */ - smartlist_ensure_capacity(s1, new_size); - memcpy(s1->list + s1->num_used, s2->list, s2->num_used*sizeof(void*)); - tor_assert(new_size <= INT_MAX); /* redundant. */ - s1->num_used = (int) new_size; -} - -/** Remove all elements E from sl such that E==element. Preserve - * the order of any elements before E, but elements after E can be - * rearranged. - */ -void -smartlist_remove(smartlist_t *sl, const void *element) -{ - int i; - if (element == NULL) - return; - for (i=0; i < sl->num_used; i++) - if (sl->list[i] == element) { - sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ - i--; /* so we process the new i'th element */ - sl->list[sl->num_used] = NULL; - } -} - -/** As <b>smartlist_remove</b>, but do not change the order of - * any elements not removed */ -void -smartlist_remove_keeporder(smartlist_t *sl, const void *element) -{ - int i, j, num_used_orig = sl->num_used; - if (element == NULL) - return; - - for (i=j=0; j < num_used_orig; ++j) { - if (sl->list[j] == element) { - --sl->num_used; - } else { - sl->list[i++] = sl->list[j]; - } - } -} - -/** If <b>sl</b> is nonempty, remove and return the final element. Otherwise, - * return NULL. */ -void * -smartlist_pop_last(smartlist_t *sl) -{ - tor_assert(sl); - if (sl->num_used) { - void *tmp = sl->list[--sl->num_used]; - sl->list[sl->num_used] = NULL; - return tmp; - } else - return NULL; -} - -/** Reverse the order of the items in <b>sl</b>. */ -void -smartlist_reverse(smartlist_t *sl) -{ - int i, j; - void *tmp; - tor_assert(sl); - for (i = 0, j = sl->num_used-1; i < j; ++i, --j) { - tmp = sl->list[i]; - sl->list[i] = sl->list[j]; - sl->list[j] = tmp; - } -} - -/** If there are any strings in sl equal to element, remove and free them. - * Does not preserve order. */ -void -smartlist_string_remove(smartlist_t *sl, const char *element) -{ - int i; - tor_assert(sl); - tor_assert(element); - for (i = 0; i < sl->num_used; ++i) { - if (!strcmp(element, sl->list[i])) { - tor_free(sl->list[i]); - sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ - i--; /* so we process the new i'th element */ - sl->list[sl->num_used] = NULL; - } - } -} - -/** Return true iff some element E of sl has E==element. - */ -int -smartlist_contains(const smartlist_t *sl, const void *element) -{ - int i; - for (i=0; i < sl->num_used; i++) - if (sl->list[i] == element) - return 1; - return 0; -} - -/** Return true iff <b>sl</b> has some element E such that - * !strcmp(E,<b>element</b>) - */ -int -smartlist_contains_string(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return 0; - for (i=0; i < sl->num_used; i++) - if (strcmp((const char*)sl->list[i],element)==0) - return 1; - return 0; -} - -/** If <b>element</b> is equal to an element of <b>sl</b>, return that - * element's index. Otherwise, return -1. */ -int -smartlist_string_pos(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return -1; - for (i=0; i < sl->num_used; i++) - if (strcmp((const char*)sl->list[i],element)==0) - return i; - return -1; -} - -/** If <b>element</b> is the same pointer as an element of <b>sl</b>, return - * that element's index. Otherwise, return -1. */ -int -smartlist_pos(const smartlist_t *sl, const void *element) -{ - int i; - if (!sl) return -1; - for (i=0; i < sl->num_used; i++) - if (element == sl->list[i]) - return i; - return -1; -} - -/** Return true iff <b>sl</b> has some element E such that - * !strcasecmp(E,<b>element</b>) - */ -int -smartlist_contains_string_case(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return 0; - for (i=0; i < sl->num_used; i++) - if (strcasecmp((const char*)sl->list[i],element)==0) - return 1; - return 0; -} - -/** Return true iff <b>sl</b> has some element E such that E is equal - * to the decimal encoding of <b>num</b>. - */ -int -smartlist_contains_int_as_string(const smartlist_t *sl, int num) -{ - char buf[32]; /* long enough for 64-bit int, and then some. */ - tor_snprintf(buf,sizeof(buf),"%d", num); - return smartlist_contains_string(sl, buf); -} - -/** Return true iff the two lists contain the same strings in the same - * order, or if they are both NULL. */ -int -smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2) -{ - if (sl1 == NULL) - return sl2 == NULL; - if (sl2 == NULL) - return 0; - if (smartlist_len(sl1) != smartlist_len(sl2)) - return 0; - SMARTLIST_FOREACH(sl1, const char *, cp1, { - const char *cp2 = smartlist_get(sl2, cp1_sl_idx); - if (strcmp(cp1, cp2)) - return 0; - }); - return 1; -} - -/** Return true iff the two lists contain the same int pointer values in - * the same order, or if they are both NULL. */ -int -smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2) -{ - if (sl1 == NULL) - return sl2 == NULL; - if (sl2 == NULL) - return 0; - if (smartlist_len(sl1) != smartlist_len(sl2)) - return 0; - SMARTLIST_FOREACH(sl1, int *, cp1, { - int *cp2 = smartlist_get(sl2, cp1_sl_idx); - if (*cp1 != *cp2) - return 0; - }); - return 1; -} - -/** Return true iff <b>sl</b> has some element E such that - * tor_memeq(E,<b>element</b>,DIGEST_LEN) - */ -int -smartlist_contains_digest(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return 0; - for (i=0; i < sl->num_used; i++) - if (tor_memeq((const char*)sl->list[i],element,DIGEST_LEN)) - return 1; - return 0; -} - -/** Return true iff some element E of sl2 has smartlist_contains(sl1,E). - */ -int -smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) -{ - int i; - for (i=0; i < sl2->num_used; i++) - if (smartlist_contains(sl1, sl2->list[i])) - return 1; - return 0; -} - -/** Remove every element E of sl1 such that !smartlist_contains(sl2,E). - * Does not preserve the order of sl1. - */ -void -smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) -{ - int i; - for (i=0; i < sl1->num_used; i++) - if (!smartlist_contains(sl2, sl1->list[i])) { - sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */ - i--; /* so we process the new i'th element */ - sl1->list[sl1->num_used] = NULL; - } -} - -/** Remove every element E of sl1 such that smartlist_contains(sl2,E). - * Does not preserve the order of sl1. - */ -void -smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) -{ - int i; - for (i=0; i < sl2->num_used; i++) - smartlist_remove(sl1, sl2->list[i]); -} - -/** Remove the <b>idx</b>th element of sl; if idx is not the last - * element, swap the last element of sl into the <b>idx</b>th space. - */ -void -smartlist_del(smartlist_t *sl, int idx) -{ - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(idx < sl->num_used); - sl->list[idx] = sl->list[--sl->num_used]; - sl->list[sl->num_used] = NULL; -} - -/** Remove the <b>idx</b>th element of sl; if idx is not the last element, - * moving all subsequent elements back one space. Return the old value - * of the <b>idx</b>th element. - */ -void -smartlist_del_keeporder(smartlist_t *sl, int idx) -{ - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(idx < sl->num_used); - --sl->num_used; - if (idx < sl->num_used) - memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx)); - sl->list[sl->num_used] = NULL; -} - -/** Insert the value <b>val</b> as the new <b>idx</b>th element of - * <b>sl</b>, moving all items previously at <b>idx</b> or later - * forward one space. - */ -void -smartlist_insert(smartlist_t *sl, int idx, void *val) -{ - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(idx <= sl->num_used); - if (idx == sl->num_used) { - smartlist_add(sl, val); - } else { - smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); - /* Move other elements away */ - if (idx < sl->num_used) - memmove(sl->list + idx + 1, sl->list + idx, - sizeof(void*)*(sl->num_used-idx)); - sl->num_used++; - sl->list[idx] = val; - } -} - -/** - * Split a string <b>str</b> along all occurrences of <b>sep</b>, - * appending the (newly allocated) split strings, in order, to - * <b>sl</b>. Return the number of strings added to <b>sl</b>. - * - * If <b>flags</b>&SPLIT_SKIP_SPACE is true, remove initial and - * trailing space from each entry. - * If <b>flags</b>&SPLIT_IGNORE_BLANK is true, remove any entries - * of length 0. - * If <b>flags</b>&SPLIT_STRIP_SPACE is true, strip spaces from each - * split string. - * - * If <b>max</b>\>0, divide the string into no more than <b>max</b> pieces. If - * <b>sep</b> is NULL, split on any sequence of horizontal space. - */ -int -smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, - int flags, int max) -{ - const char *cp, *end, *next; - int n = 0; - - tor_assert(sl); - tor_assert(str); - - cp = str; - while (1) { - if (flags&SPLIT_SKIP_SPACE) { - while (TOR_ISSPACE(*cp)) ++cp; - } - - if (max>0 && n == max-1) { - end = strchr(cp,'\0'); - } else if (sep) { - end = strstr(cp,sep); - if (!end) - end = strchr(cp,'\0'); - } else { - for (end = cp; *end && *end != '\t' && *end != ' '; ++end) - ; - } - - tor_assert(end); - - if (!*end) { - next = NULL; - } else if (sep) { - next = end+strlen(sep); - } else { - next = end+1; - while (*next == '\t' || *next == ' ') - ++next; - } - - if (flags&SPLIT_SKIP_SPACE) { - while (end > cp && TOR_ISSPACE(*(end-1))) - --end; - } - if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) { - char *string = tor_strndup(cp, end-cp); - if (flags&SPLIT_STRIP_SPACE) - tor_strstrip(string, " "); - smartlist_add(sl, string); - ++n; - } - if (!next) - break; - cp = next; - } - - return n; -} - -/** Allocate and return a new string containing the concatenation of - * the elements of <b>sl</b>, in order, separated by <b>join</b>. If - * <b>terminate</b> is true, also terminate the string with <b>join</b>. - * If <b>len_out</b> is not NULL, set <b>len_out</b> to the length of - * the returned string. Requires that every element of <b>sl</b> is - * NUL-terminated string. - */ -char * -smartlist_join_strings(smartlist_t *sl, const char *join, - int terminate, size_t *len_out) -{ - return smartlist_join_strings2(sl,join,strlen(join),terminate,len_out); -} - -/** As smartlist_join_strings, but instead of separating/terminated with a - * NUL-terminated string <b>join</b>, uses the <b>join_len</b>-byte sequence - * at <b>join</b>. (Useful for generating a sequence of NUL-terminated - * strings.) - */ -char * -smartlist_join_strings2(smartlist_t *sl, const char *join, - size_t join_len, int terminate, size_t *len_out) -{ - int i; - size_t n = 0; - char *r = NULL, *dst, *src; - - tor_assert(sl); - tor_assert(join); - - if (terminate) - n = join_len; - - for (i = 0; i < sl->num_used; ++i) { - n += strlen(sl->list[i]); - if (i+1 < sl->num_used) /* avoid double-counting the last one */ - n += join_len; - } - dst = r = tor_malloc(n+1); - for (i = 0; i < sl->num_used; ) { - for (src = sl->list[i]; *src; ) - *dst++ = *src++; - if (++i < sl->num_used) { - memcpy(dst, join, join_len); - dst += join_len; - } - } - if (terminate) { - memcpy(dst, join, join_len); - dst += join_len; - } - *dst = '\0'; - - if (len_out) - *len_out = dst-r; - return r; -} - -/** Sort the members of <b>sl</b> into an order defined by - * the ordering function <b>compare</b>, which returns less then 0 if a - * precedes b, greater than 0 if b precedes a, and 0 if a 'equals' b. - */ -void -smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b)) -{ - if (!sl->num_used) - return; - qsort(sl->list, sl->num_used, sizeof(void*), - (int (*)(const void *,const void*))compare); -} - -/** Given a smartlist <b>sl</b> sorted with the function <b>compare</b>, - * return the most frequent member in the list. Break ties in favor of - * later elements. If the list is empty, return NULL. If count_out is - * non-null, set it to the count of the most frequent member. - */ -void * -smartlist_get_most_frequent_(const smartlist_t *sl, - int (*compare)(const void **a, const void **b), - int *count_out) -{ - const void *most_frequent = NULL; - int most_frequent_count = 0; - - const void *cur = NULL; - int i, count=0; - - if (!sl->num_used) { - if (count_out) - *count_out = 0; - return NULL; - } - for (i = 0; i < sl->num_used; ++i) { - const void *item = sl->list[i]; - if (cur && 0 == compare(&cur, &item)) { - ++count; - } else { - if (cur && count >= most_frequent_count) { - most_frequent = cur; - most_frequent_count = count; - } - cur = item; - count = 1; - } - } - if (cur && count >= most_frequent_count) { - most_frequent = cur; - most_frequent_count = count; - } - if (count_out) - *count_out = most_frequent_count; - return (void*)most_frequent; -} - -/** Given a sorted smartlist <b>sl</b> and the comparison function used to - * sort it, remove all duplicate members. If free_fn is provided, calls - * free_fn on each duplicate. Otherwise, just removes them. Preserves order. - */ -void -smartlist_uniq(smartlist_t *sl, - int (*compare)(const void **a, const void **b), - void (*free_fn)(void *a)) -{ - int i; - for (i=1; i < sl->num_used; ++i) { - if (compare((const void **)&(sl->list[i-1]), - (const void **)&(sl->list[i])) == 0) { - if (free_fn) - free_fn(sl->list[i]); - smartlist_del_keeporder(sl, i--); - } - } -} - -/** Assuming the members of <b>sl</b> are in order, return a pointer to the - * member that matches <b>key</b>. Ordering and matching are defined by a - * <b>compare</b> function that returns 0 on a match; less than 0 if key is - * less than member, and greater than 0 if key is greater then member. - */ -void * -smartlist_bsearch(smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member)) -{ - int found, idx; - idx = smartlist_bsearch_idx(sl, key, compare, &found); - return found ? smartlist_get(sl, idx) : NULL; -} - -/** Assuming the members of <b>sl</b> are in order, return the index of the - * member that matches <b>key</b>. If no member matches, return the index of - * the first member greater than <b>key</b>, or smartlist_len(sl) if no member - * is greater than <b>key</b>. Set <b>found_out</b> to true on a match, to - * false otherwise. Ordering and matching are defined by a <b>compare</b> - * function that returns 0 on a match; less than 0 if key is less than member, - * and greater than 0 if key is greater then member. - */ -int -smartlist_bsearch_idx(const smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member), - int *found_out) -{ - int hi, lo, cmp, mid, len, diff; - - tor_assert(sl); - tor_assert(compare); - tor_assert(found_out); - - len = smartlist_len(sl); - - /* Check for the trivial case of a zero-length list */ - if (len == 0) { - *found_out = 0; - /* We already know smartlist_len(sl) is 0 in this case */ - return 0; - } - - /* Okay, we have a real search to do */ - tor_assert(len > 0); - lo = 0; - hi = len - 1; - - /* - * These invariants are always true: - * - * For all i such that 0 <= i < lo, sl[i] < key - * For all i such that hi < i <= len, sl[i] > key - */ - - while (lo <= hi) { - diff = hi - lo; - /* - * We want mid = (lo + hi) / 2, but that could lead to overflow, so - * instead diff = hi - lo (non-negative because of loop condition), and - * then hi = lo + diff, mid = (lo + lo + diff) / 2 = lo + (diff / 2). - */ - mid = lo + (diff / 2); - cmp = compare(key, (const void**) &(sl->list[mid])); - if (cmp == 0) { - /* sl[mid] == key; we found it */ - *found_out = 1; - return mid; - } else if (cmp > 0) { - /* - * key > sl[mid] and an index i such that sl[i] == key must - * have i > mid if it exists. - */ - - /* - * Since lo <= mid <= hi, hi can only decrease on each iteration (by - * being set to mid - 1) and hi is initially len - 1, mid < len should - * always hold, and this is not symmetric with the left end of list - * mid > 0 test below. A key greater than the right end of the list - * should eventually lead to lo == hi == mid == len - 1, and then - * we set lo to len below and fall out to the same exit we hit for - * a key in the middle of the list but not matching. Thus, we just - * assert for consistency here rather than handle a mid == len case. - */ - tor_assert(mid < len); - /* Move lo to the element immediately after sl[mid] */ - lo = mid + 1; - } else { - /* This should always be true in this case */ - tor_assert(cmp < 0); - - /* - * key < sl[mid] and an index i such that sl[i] == key must - * have i < mid if it exists. - */ - - if (mid > 0) { - /* Normal case, move hi to the element immediately before sl[mid] */ - hi = mid - 1; - } else { - /* These should always be true in this case */ - tor_assert(mid == lo); - tor_assert(mid == 0); - /* - * We were at the beginning of the list and concluded that every - * element e compares e > key. - */ - *found_out = 0; - return 0; - } - } - } - - /* - * lo > hi; we have no element matching key but we have elements falling - * on both sides of it. The lo index points to the first element > key. - */ - tor_assert(lo == hi + 1); /* All other cases should have been handled */ - tor_assert(lo >= 0); - tor_assert(lo <= len); - tor_assert(hi >= 0); - tor_assert(hi <= len); - - if (lo < len) { - cmp = compare(key, (const void **) &(sl->list[lo])); - tor_assert(cmp < 0); - } else { - cmp = compare(key, (const void **) &(sl->list[len-1])); - tor_assert(cmp > 0); - } - - *found_out = 0; - return lo; -} - -/** Helper: compare two const char **s. */ -static int -compare_string_ptrs_(const void **_a, const void **_b) -{ - return strcmp((const char*)*_a, (const char*)*_b); -} - -/** Sort a smartlist <b>sl</b> containing strings into lexically ascending - * order. */ -void -smartlist_sort_strings(smartlist_t *sl) -{ - smartlist_sort(sl, compare_string_ptrs_); -} - -/** Return the most frequent string in the sorted list <b>sl</b> */ -const char * -smartlist_get_most_frequent_string(smartlist_t *sl) -{ - return smartlist_get_most_frequent(sl, compare_string_ptrs_); -} - -/** Return the most frequent string in the sorted list <b>sl</b>. - * If <b>count_out</b> is provided, set <b>count_out</b> to the - * number of times that string appears. - */ -const char * -smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out) -{ - return smartlist_get_most_frequent_(sl, compare_string_ptrs_, count_out); -} - -/** Remove duplicate strings from a sorted list, and free them with tor_free(). - */ -void -smartlist_uniq_strings(smartlist_t *sl) -{ - smartlist_uniq(sl, compare_string_ptrs_, tor_free_); -} - -/** Helper: compare two pointers. */ -static int -compare_ptrs_(const void **_a, const void **_b) -{ - const void *a = *_a, *b = *_b; - if (a<b) - return -1; - else if (a==b) - return 0; - else - return 1; -} - -/** Sort <b>sl</b> in ascending order of the pointers it contains. */ -void -smartlist_sort_pointers(smartlist_t *sl) -{ - smartlist_sort(sl, compare_ptrs_); -} - -/* Heap-based priority queue implementation for O(lg N) insert and remove. - * Recall that the heap property is that, for every index I, h[I] < - * H[LEFT_CHILD[I]] and h[I] < H[RIGHT_CHILD[I]]. - * - * For us to remove items other than the topmost item, each item must store - * its own index within the heap. When calling the pqueue functions, tell - * them about the offset of the field that stores the index within the item. - * - * Example: - * - * typedef struct timer_t { - * struct timeval tv; - * int heap_index; - * } timer_t; - * - * static int compare(const void *p1, const void *p2) { - * const timer_t *t1 = p1, *t2 = p2; - * if (t1->tv.tv_sec < t2->tv.tv_sec) { - * return -1; - * } else if (t1->tv.tv_sec > t2->tv.tv_sec) { - * return 1; - * } else { - * return t1->tv.tv_usec - t2->tv_usec; - * } - * } - * - * void timer_heap_insert(smartlist_t *heap, timer_t *timer) { - * smartlist_pqueue_add(heap, compare, offsetof(timer_t, heap_index), - * timer); - * } - * - * void timer_heap_pop(smartlist_t *heap) { - * return smartlist_pqueue_pop(heap, compare, - * offsetof(timer_t, heap_index)); - * } - */ - -/** @{ */ -/** Functions to manipulate heap indices to find a node's parent and children. - * - * For a 1-indexed array, we would use LEFT_CHILD[x] = 2*x and RIGHT_CHILD[x] - * = 2*x + 1. But this is C, so we have to adjust a little. */ - -/* MAX_PARENT_IDX is the largest IDX in the smartlist which might have - * children whose indices fit inside an int. - * LEFT_CHILD(MAX_PARENT_IDX) == INT_MAX-2; - * RIGHT_CHILD(MAX_PARENT_IDX) == INT_MAX-1; - * LEFT_CHILD(MAX_PARENT_IDX + 1) == INT_MAX // impossible, see max list size. - */ -#define MAX_PARENT_IDX ((INT_MAX - 2) / 2) -/* If this is true, then i is small enough to potentially have children - * in the smartlist, and it is save to use LEFT_CHILD/RIGHT_CHILD on it. */ -#define IDX_MAY_HAVE_CHILDREN(i) ((i) <= MAX_PARENT_IDX) -#define LEFT_CHILD(i) ( 2*(i) + 1 ) -#define RIGHT_CHILD(i) ( 2*(i) + 2 ) -#define PARENT(i) ( ((i)-1) / 2 ) -/** }@ */ - -/** @{ */ -/** Helper macros for heaps: Given a local variable <b>idx_field_offset</b> - * set to the offset of an integer index within the heap element structure, - * IDX_OF_ITEM(p) gives you the index of p, and IDXP(p) gives you a pointer to - * where p's index is stored. Given additionally a local smartlist <b>sl</b>, - * UPDATE_IDX(i) sets the index of the element at <b>i</b> to the correct - * value (that is, to <b>i</b>). - */ -#define IDXP(p) ((int*)STRUCT_VAR_P(p, idx_field_offset)) - -#define UPDATE_IDX(i) do { \ - void *updated = sl->list[i]; \ - *IDXP(updated) = i; \ - } while (0) - -#define IDX_OF_ITEM(p) (*IDXP(p)) -/** @} */ - -/** Helper. <b>sl</b> may have at most one violation of the heap property: - * the item at <b>idx</b> may be greater than one or both of its children. - * Restore the heap property. */ -static inline void -smartlist_heapify(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - int idx) -{ - while (1) { - if (! IDX_MAY_HAVE_CHILDREN(idx)) { - /* idx is so large that it cannot have any children, since doing so - * would mean the smartlist was over-capacity. Therefore it cannot - * violate the heap property by being greater than a child (since it - * doesn't have any). */ - return; - } - - int left_idx = LEFT_CHILD(idx); - int best_idx; - - if (left_idx >= sl->num_used) - return; - if (compare(sl->list[idx],sl->list[left_idx]) < 0) - best_idx = idx; - else - best_idx = left_idx; - if (left_idx+1 < sl->num_used && - compare(sl->list[left_idx+1],sl->list[best_idx]) < 0) - best_idx = left_idx + 1; - - if (best_idx == idx) { - return; - } else { - void *tmp = sl->list[idx]; - sl->list[idx] = sl->list[best_idx]; - sl->list[best_idx] = tmp; - UPDATE_IDX(idx); - UPDATE_IDX(best_idx); - - idx = best_idx; - } - } -} - -/** Insert <b>item</b> into the heap stored in <b>sl</b>, where order is - * determined by <b>compare</b> and the offset of the item in the heap is - * stored in an int-typed field at position <b>idx_field_offset</b> within - * item. - */ -void -smartlist_pqueue_add(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item) -{ - int idx; - smartlist_add(sl,item); - UPDATE_IDX(sl->num_used-1); - - for (idx = sl->num_used - 1; idx; ) { - int parent = PARENT(idx); - if (compare(sl->list[idx], sl->list[parent]) < 0) { - void *tmp = sl->list[parent]; - sl->list[parent] = sl->list[idx]; - sl->list[idx] = tmp; - UPDATE_IDX(parent); - UPDATE_IDX(idx); - idx = parent; - } else { - return; - } - } -} - -/** Remove and return the top-priority item from the heap stored in <b>sl</b>, - * where order is determined by <b>compare</b> and the item's position is - * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must - * not be empty. */ -void * -smartlist_pqueue_pop(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset) -{ - void *top; - tor_assert(sl->num_used); - - top = sl->list[0]; - *IDXP(top)=-1; - if (--sl->num_used) { - sl->list[0] = sl->list[sl->num_used]; - sl->list[sl->num_used] = NULL; - UPDATE_IDX(0); - smartlist_heapify(sl, compare, idx_field_offset, 0); - } - sl->list[sl->num_used] = NULL; - return top; -} - -/** Remove the item <b>item</b> from the heap stored in <b>sl</b>, - * where order is determined by <b>compare</b> and the item's position is - * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must - * not be empty. */ -void -smartlist_pqueue_remove(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item) -{ - int idx = IDX_OF_ITEM(item); - tor_assert(idx >= 0); - tor_assert(sl->list[idx] == item); - --sl->num_used; - *IDXP(item) = -1; - if (idx == sl->num_used) { - sl->list[sl->num_used] = NULL; - return; - } else { - sl->list[idx] = sl->list[sl->num_used]; - sl->list[sl->num_used] = NULL; - UPDATE_IDX(idx); - smartlist_heapify(sl, compare, idx_field_offset, idx); - } -} - -/** Assert that the heap property is correctly maintained by the heap stored - * in <b>sl</b>, where order is determined by <b>compare</b>. */ -void -smartlist_pqueue_assert_ok(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset) -{ - int i; - for (i = sl->num_used - 1; i >= 0; --i) { - if (i>0) - tor_assert(compare(sl->list[PARENT(i)], sl->list[i]) <= 0); - tor_assert(IDX_OF_ITEM(sl->list[i]) == i); - } -} - -/** Helper: compare two DIGEST_LEN digests. */ -static int -compare_digests_(const void **_a, const void **_b) -{ - return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST_LEN); -} - -/** Sort the list of DIGEST_LEN-byte digests into ascending order. */ -void -smartlist_sort_digests(smartlist_t *sl) -{ - smartlist_sort(sl, compare_digests_); -} - -/** Remove duplicate digests from a sorted list, and free them with tor_free(). - */ -void -smartlist_uniq_digests(smartlist_t *sl) -{ - smartlist_uniq(sl, compare_digests_, tor_free_); -} - -/** Helper: compare two DIGEST256_LEN digests. */ -static int -compare_digests256_(const void **_a, const void **_b) -{ - return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN); -} - -/** Sort the list of DIGEST256_LEN-byte digests into ascending order. */ -void -smartlist_sort_digests256(smartlist_t *sl) -{ - smartlist_sort(sl, compare_digests256_); -} - -/** Return the most frequent member of the sorted list of DIGEST256_LEN - * digests in <b>sl</b> */ -const uint8_t * -smartlist_get_most_frequent_digest256(smartlist_t *sl) -{ - return smartlist_get_most_frequent(sl, compare_digests256_); -} - -/** Remove duplicate 256-bit digests from a sorted list, and free them with - * tor_free(). - */ -void -smartlist_uniq_digests256(smartlist_t *sl) -{ - smartlist_uniq(sl, compare_digests256_, tor_free_); -} - -/** Helper: Declare an entry type and a map type to implement a mapping using - * ht.h. The map type will be called <b>maptype</b>. The key part of each - * entry is declared using the C declaration <b>keydecl</b>. All functions - * and types associated with the map get prefixed with <b>prefix</b> */ -#define DEFINE_MAP_STRUCTS(maptype, keydecl, prefix) \ - typedef struct prefix ## entry_t { \ - HT_ENTRY(prefix ## entry_t) node; \ - void *val; \ - keydecl; \ - } prefix ## entry_t; \ - struct maptype { \ - HT_HEAD(prefix ## impl, prefix ## entry_t) head; \ - } - -DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_); -DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_); -DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_); - -/** Helper: compare strmap_entry_t objects by key value. */ -static inline int -strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b) -{ - return !strcmp(a->key, b->key); -} - -/** Helper: return a hash value for a strmap_entry_t. */ -static inline unsigned int -strmap_entry_hash(const strmap_entry_t *a) -{ - return (unsigned) siphash24g(a->key, strlen(a->key)); -} - -/** Helper: compare digestmap_entry_t objects by key value. */ -static inline int -digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b) -{ - return tor_memeq(a->key, b->key, DIGEST_LEN); -} - -/** Helper: return a hash value for a digest_map_t. */ -static inline unsigned int -digestmap_entry_hash(const digestmap_entry_t *a) -{ - return (unsigned) siphash24g(a->key, DIGEST_LEN); -} - -/** Helper: compare digestmap_entry_t objects by key value. */ -static inline int -digest256map_entries_eq(const digest256map_entry_t *a, - const digest256map_entry_t *b) -{ - return tor_memeq(a->key, b->key, DIGEST256_LEN); -} - -/** Helper: return a hash value for a digest_map_t. */ -static inline unsigned int -digest256map_entry_hash(const digest256map_entry_t *a) -{ - return (unsigned) siphash24g(a->key, DIGEST256_LEN); -} - -HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash, - strmap_entries_eq) -HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash, - strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) - -HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, - digestmap_entries_eq) -HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, - digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) - -HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node, - digest256map_entry_hash, - digest256map_entries_eq) -HT_GENERATE2(digest256map_impl, digest256map_entry_t, node, - digest256map_entry_hash, - digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_) - -#define strmap_entry_free(ent) \ - FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent)) -#define digestmap_entry_free(ent) \ - FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent)) -#define digest256map_entry_free(ent) \ - FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent)) - -static inline void -strmap_entry_free_(strmap_entry_t *ent) -{ - tor_free(ent->key); - tor_free(ent); -} -static inline void -digestmap_entry_free_(digestmap_entry_t *ent) -{ - tor_free(ent); -} -static inline void -digest256map_entry_free_(digest256map_entry_t *ent) -{ - tor_free(ent); -} - -static inline void -strmap_assign_tmp_key(strmap_entry_t *ent, const char *key) -{ - ent->key = (char*)key; -} -static inline void -digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key) -{ - memcpy(ent->key, key, DIGEST_LEN); -} -static inline void -digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key) -{ - memcpy(ent->key, key, DIGEST256_LEN); -} -static inline void -strmap_assign_key(strmap_entry_t *ent, const char *key) -{ - ent->key = tor_strdup(key); -} -static inline void -digestmap_assign_key(digestmap_entry_t *ent, const char *key) -{ - memcpy(ent->key, key, DIGEST_LEN); -} -static inline void -digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key) -{ - memcpy(ent->key, key, DIGEST256_LEN); -} - -/** - * Macro: implement all the functions for a map that are declared in - * container.h by the DECLARE_MAP_FNS() macro. You must additionally define a - * prefix_entry_free_() function to free entries (and their keys), a - * prefix_assign_tmp_key() function to temporarily set a stack-allocated - * entry to hold a key, and a prefix_assign_key() function to set a - * heap-allocated entry to hold a key. - */ -#define IMPLEMENT_MAP_FNS(maptype, keytype, prefix) \ - /** Create and return a new empty map. */ \ - MOCK_IMPL(maptype *, \ - prefix##_new,(void)) \ - { \ - maptype *result; \ - result = tor_malloc(sizeof(maptype)); \ - HT_INIT(prefix##_impl, &result->head); \ - return result; \ - } \ - \ - /** Return the item from <b>map</b> whose key matches <b>key</b>, or \ - * NULL if no such value exists. */ \ - void * \ - prefix##_get(const maptype *map, const keytype key) \ - { \ - prefix ##_entry_t *resolve; \ - prefix ##_entry_t search; \ - tor_assert(map); \ - tor_assert(key); \ - prefix ##_assign_tmp_key(&search, key); \ - resolve = HT_FIND(prefix ##_impl, &map->head, &search); \ - if (resolve) { \ - return resolve->val; \ - } else { \ - return NULL; \ - } \ - } \ - \ - /** Add an entry to <b>map</b> mapping <b>key</b> to <b>val</b>; \ - * return the previous value, or NULL if no such value existed. */ \ - void * \ - prefix##_set(maptype *map, const keytype key, void *val) \ - { \ - prefix##_entry_t search; \ - void *oldval; \ - tor_assert(map); \ - tor_assert(key); \ - tor_assert(val); \ - prefix##_assign_tmp_key(&search, key); \ - /* We a lot of our time in this function, so the code below is */ \ - /* meant to optimize the check/alloc/set cycle by avoiding the two */\ - /* trips to the hash table that we would do in the unoptimized */ \ - /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \ - /* HT_SET_HASH and HT_FIND_P.) */ \ - HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \ - &(map->head), \ - prefix##_entry_t, &search, ptr, \ - { \ - /* we found an entry. */ \ - oldval = (*ptr)->val; \ - (*ptr)->val = val; \ - return oldval; \ - }, \ - { \ - /* We didn't find the entry. */ \ - prefix##_entry_t *newent = \ - tor_malloc_zero(sizeof(prefix##_entry_t)); \ - prefix##_assign_key(newent, key); \ - newent->val = val; \ - HT_FOI_INSERT_(node, &(map->head), \ - &search, newent, ptr); \ - return NULL; \ - }); \ - } \ - \ - /** Remove the value currently associated with <b>key</b> from the map. \ - * Return the value if one was set, or NULL if there was no entry for \ - * <b>key</b>. \ - * \ - * Note: you must free any storage associated with the returned value. \ - */ \ - void * \ - prefix##_remove(maptype *map, const keytype key) \ - { \ - prefix##_entry_t *resolve; \ - prefix##_entry_t search; \ - void *oldval; \ - tor_assert(map); \ - tor_assert(key); \ - prefix##_assign_tmp_key(&search, key); \ - resolve = HT_REMOVE(prefix##_impl, &map->head, &search); \ - if (resolve) { \ - oldval = resolve->val; \ - prefix##_entry_free(resolve); \ - return oldval; \ - } else { \ - return NULL; \ - } \ - } \ - \ - /** Return the number of elements in <b>map</b>. */ \ - int \ - prefix##_size(const maptype *map) \ - { \ - return HT_SIZE(&map->head); \ - } \ - \ - /** Return true iff <b>map</b> has no entries. */ \ - int \ - prefix##_isempty(const maptype *map) \ - { \ - return HT_EMPTY(&map->head); \ - } \ - \ - /** Assert that <b>map</b> is not corrupt. */ \ - void \ - prefix##_assert_ok(const maptype *map) \ - { \ - tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head)); \ - } \ - \ - /** Remove all entries from <b>map</b>, and deallocate storage for \ - * those entries. If free_val is provided, invoked it every value in \ - * <b>map</b>. */ \ - MOCK_IMPL(void, \ - prefix##_free_, (maptype *map, void (*free_val)(void*))) \ - { \ - prefix##_entry_t **ent, **next, *this; \ - if (!map) \ - return; \ - for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \ - ent = next) { \ - this = *ent; \ - next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \ - if (free_val) \ - free_val(this->val); \ - prefix##_entry_free(this); \ - } \ - tor_assert(HT_EMPTY(&map->head)); \ - HT_CLEAR(prefix##_impl, &map->head); \ - tor_free(map); \ - } \ - \ - /** return an <b>iterator</b> pointer to the front of a map. \ - * \ - * Iterator example: \ - * \ - * \code \ - * // uppercase values in "map", removing empty values. \ - * \ - * strmap_iter_t *iter; \ - * const char *key; \ - * void *val; \ - * char *cp; \ - * \ - * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) { \ - * strmap_iter_get(iter, &key, &val); \ - * cp = (char*)val; \ - * if (!*cp) { \ - * iter = strmap_iter_next_rmv(map,iter); \ - * free(val); \ - * } else { \ - * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp); \ - */ \ - prefix##_iter_t * \ - prefix##_iter_init(maptype *map) \ - { \ - tor_assert(map); \ - return HT_START(prefix##_impl, &map->head); \ - } \ - \ - /** Advance <b>iter</b> a single step to the next entry, and return \ - * its new value. */ \ - prefix##_iter_t * \ - prefix##_iter_next(maptype *map, prefix##_iter_t *iter) \ - { \ - tor_assert(map); \ - tor_assert(iter); \ - return HT_NEXT(prefix##_impl, &map->head, iter); \ - } \ - /** Advance <b>iter</b> a single step to the next entry, removing the \ - * current entry, and return its new value. */ \ - prefix##_iter_t * \ - prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter) \ - { \ - prefix##_entry_t *rmv; \ - tor_assert(map); \ - tor_assert(iter); \ - tor_assert(*iter); \ - rmv = *iter; \ - iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter); \ - prefix##_entry_free(rmv); \ - return iter; \ - } \ - /** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed \ - * to by iter. */ \ - void \ - prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp, \ - void **valp) \ - { \ - tor_assert(iter); \ - tor_assert(*iter); \ - tor_assert(keyp); \ - tor_assert(valp); \ - *keyp = (*iter)->key; \ - *valp = (*iter)->val; \ - } \ - /** Return true iff <b>iter</b> has advanced past the last entry of \ - * <b>map</b>. */ \ - int \ - prefix##_iter_done(prefix##_iter_t *iter) \ - { \ - return iter == NULL; \ - } - -IMPLEMENT_MAP_FNS(strmap_t, char *, strmap) -IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap) -IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map) - -/** Same as strmap_set, but first converts <b>key</b> to lowercase. */ -void * -strmap_set_lc(strmap_t *map, const char *key, void *val) -{ - /* We could be a little faster by using strcasecmp instead, and a separate - * type, but I don't think it matters. */ - void *v; - char *lc_key = tor_strdup(key); - tor_strlower(lc_key); - v = strmap_set(map,lc_key,val); - tor_free(lc_key); - return v; -} - -/** Same as strmap_get, but first converts <b>key</b> to lowercase. */ -void * -strmap_get_lc(const strmap_t *map, const char *key) -{ - void *v; - char *lc_key = tor_strdup(key); - tor_strlower(lc_key); - v = strmap_get(map,lc_key); - tor_free(lc_key); - return v; -} - -/** Same as strmap_remove, but first converts <b>key</b> to lowercase */ -void * -strmap_remove_lc(strmap_t *map, const char *key) -{ - void *v; - char *lc_key = tor_strdup(key); - tor_strlower(lc_key); - v = strmap_remove(map,lc_key); - tor_free(lc_key); - return v; -} - -/** Declare a function called <b>funcname</b> that acts as a find_nth_FOO - * function for an array of type <b>elt_t</b>*. - * - * NOTE: The implementation kind of sucks: It's O(n log n), whereas finding - * the kth element of an n-element list can be done in O(n). Then again, this - * implementation is not in critical path, and it is obviously correct. */ -#define IMPLEMENT_ORDER_FUNC(funcname, elt_t) \ - static int \ - _cmp_ ## elt_t(const void *_a, const void *_b) \ - { \ - const elt_t *a = _a, *b = _b; \ - if (*a<*b) \ - return -1; \ - else if (*a>*b) \ - return 1; \ - else \ - return 0; \ - } \ - elt_t \ - funcname(elt_t *array, int n_elements, int nth) \ - { \ - tor_assert(nth >= 0); \ - tor_assert(nth < n_elements); \ - qsort(array, n_elements, sizeof(elt_t), _cmp_ ##elt_t); \ - return array[nth]; \ - } - -IMPLEMENT_ORDER_FUNC(find_nth_int, int) -IMPLEMENT_ORDER_FUNC(find_nth_time, time_t) -IMPLEMENT_ORDER_FUNC(find_nth_double, double) -IMPLEMENT_ORDER_FUNC(find_nth_uint32, uint32_t) -IMPLEMENT_ORDER_FUNC(find_nth_int32, int32_t) -IMPLEMENT_ORDER_FUNC(find_nth_long, long) - -/** Return a newly allocated digestset_t, optimized to hold a total of - * <b>max_elements</b> digests with a reasonably low false positive weight. */ -digestset_t * -digestset_new(int max_elements) -{ - /* The probability of false positives is about P=(1 - exp(-kn/m))^k, where k - * is the number of hash functions per entry, m is the bits in the array, - * and n is the number of elements inserted. For us, k==4, n<=max_elements, - * and m==n_bits= approximately max_elements*32. This gives - * P<(1-exp(-4*n/(32*n)))^4 == (1-exp(1/-8))^4 == .00019 - * - * It would be more optimal in space vs false positives to get this false - * positive rate by going for k==13, and m==18.5n, but we also want to - * conserve CPU, and k==13 is pretty big. - */ - int n_bits = 1u << (tor_log2(max_elements)+5); - digestset_t *r = tor_malloc(sizeof(digestset_t)); - r->mask = n_bits - 1; - r->ba = bitarray_init_zero(n_bits); - return r; -} - -/** Free all storage held in <b>set</b>. */ -void -digestset_free_(digestset_t *set) -{ - if (!set) - return; - bitarray_free(set->ba); - tor_free(set); -} - diff --git a/src/common/container.h b/src/common/container.h deleted file mode 100644 index 5d2dce5416..0000000000 --- a/src/common/container.h +++ /dev/null @@ -1,742 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CONTAINER_H -#define TOR_CONTAINER_H - -#include "util.h" -#include "siphash.h" - -/** A resizeable list of pointers, with associated helpful functionality. - * - * The members of this struct are exposed only so that macros and inlines can - * use them; all access to smartlist internals should go through the functions - * and macros defined here. - **/ -typedef struct smartlist_t { - /** @{ */ - /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements - * before it needs to be resized. Only the first <b>num_used</b> (\<= - * capacity) elements point to valid data. - */ - void **list; - int num_used; - int capacity; - /** @} */ -} smartlist_t; - -MOCK_DECL(smartlist_t *, smartlist_new, (void)); -MOCK_DECL(void, smartlist_free_, (smartlist_t *sl)); -#define smartlist_free(sl) FREE_AND_NULL(smartlist_t, smartlist_free_, (sl)) - -void smartlist_clear(smartlist_t *sl); -void smartlist_add(smartlist_t *sl, void *element); -void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2); -void smartlist_remove(smartlist_t *sl, const void *element); -void smartlist_remove_keeporder(smartlist_t *sl, const void *element); -void *smartlist_pop_last(smartlist_t *sl); -void smartlist_reverse(smartlist_t *sl); -void smartlist_string_remove(smartlist_t *sl, const char *element); -int smartlist_contains(const smartlist_t *sl, const void *element); -int smartlist_contains_string(const smartlist_t *sl, const char *element); -int smartlist_pos(const smartlist_t *sl, const void *element); -int smartlist_string_pos(const smartlist_t *, const char *elt); -int smartlist_contains_string_case(const smartlist_t *sl, const char *element); -int smartlist_contains_int_as_string(const smartlist_t *sl, int num); -int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2); -int smartlist_contains_digest(const smartlist_t *sl, const char *element); -int smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2); -int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2); -void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2); -void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2); - -/* smartlist_choose() is defined in crypto.[ch] */ -#ifdef DEBUG_SMARTLIST -/** Return the number of items in sl. - */ -static inline int smartlist_len(const smartlist_t *sl); -static inline int smartlist_len(const smartlist_t *sl) { - tor_assert(sl); - return (sl)->num_used; -} -/** Return the <b>idx</b>th element of sl. - */ -static inline void *smartlist_get(const smartlist_t *sl, int idx); -static inline void *smartlist_get(const smartlist_t *sl, int idx) { - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(sl->num_used > idx); - return sl->list[idx]; -} -static inline void smartlist_set(smartlist_t *sl, int idx, void *val) { - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(sl->num_used > idx); - sl->list[idx] = val; -} -#else /* !(defined(DEBUG_SMARTLIST)) */ -#define smartlist_len(sl) ((sl)->num_used) -#define smartlist_get(sl, idx) ((sl)->list[idx]) -#define smartlist_set(sl, idx, val) ((sl)->list[idx] = (val)) -#endif /* defined(DEBUG_SMARTLIST) */ - -/** Exchange the elements at indices <b>idx1</b> and <b>idx2</b> of the - * smartlist <b>sl</b>. */ -static inline void smartlist_swap(smartlist_t *sl, int idx1, int idx2) -{ - if (idx1 != idx2) { - void *elt = smartlist_get(sl, idx1); - smartlist_set(sl, idx1, smartlist_get(sl, idx2)); - smartlist_set(sl, idx2, elt); - } -} - -void smartlist_del(smartlist_t *sl, int idx); -void smartlist_del_keeporder(smartlist_t *sl, int idx); -void smartlist_insert(smartlist_t *sl, int idx, void *val); -void smartlist_sort(smartlist_t *sl, - int (*compare)(const void **a, const void **b)); -void *smartlist_get_most_frequent_(const smartlist_t *sl, - int (*compare)(const void **a, const void **b), - int *count_out); -#define smartlist_get_most_frequent(sl, compare) \ - smartlist_get_most_frequent_((sl), (compare), NULL) -void smartlist_uniq(smartlist_t *sl, - int (*compare)(const void **a, const void **b), - void (*free_fn)(void *elt)); - -void smartlist_sort_strings(smartlist_t *sl); -void smartlist_sort_digests(smartlist_t *sl); -void smartlist_sort_digests256(smartlist_t *sl); -void smartlist_sort_pointers(smartlist_t *sl); - -const char *smartlist_get_most_frequent_string(smartlist_t *sl); -const char *smartlist_get_most_frequent_string_(smartlist_t *sl, - int *count_out); -const uint8_t *smartlist_get_most_frequent_digest256(smartlist_t *sl); - -void smartlist_uniq_strings(smartlist_t *sl); -void smartlist_uniq_digests(smartlist_t *sl); -void smartlist_uniq_digests256(smartlist_t *sl); -void *smartlist_bsearch(smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member)); -int smartlist_bsearch_idx(const smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member), - int *found_out); - -void smartlist_pqueue_add(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item); -void *smartlist_pqueue_pop(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset); -void smartlist_pqueue_remove(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item); -void smartlist_pqueue_assert_ok(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset); - -#define SPLIT_SKIP_SPACE 0x01 -#define SPLIT_IGNORE_BLANK 0x02 -#define SPLIT_STRIP_SPACE 0x04 -int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, - int flags, int max); -char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, - size_t *len_out) ATTR_MALLOC; -char *smartlist_join_strings2(smartlist_t *sl, const char *join, - size_t join_len, int terminate, size_t *len_out) - ATTR_MALLOC; - -/** Iterate over the items in a smartlist <b>sl</b>, in order. For each item, - * assign it to a new local variable of type <b>type</b> named <b>var</b>, and - * execute the statements inside the loop body. Inside the loop, the loop - * index can be accessed as <b>var</b>_sl_idx and the length of the list can - * be accessed as <b>var</b>_sl_len. - * - * NOTE: Do not change the length of the list while the loop is in progress, - * unless you adjust the _sl_len variable correspondingly. See second example - * below. - * - * Example use: - * <pre> - * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); - * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { - * printf("%d: %s\n", cp_sl_idx, cp); - * tor_free(cp); - * } SMARTLIST_FOREACH_END(cp); - * smartlist_free(list); - * </pre> - * - * Example use (advanced): - * <pre> - * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { - * if (!strcmp(cp, "junk")) { - * tor_free(cp); - * SMARTLIST_DEL_CURRENT(list, cp); - * } - * } SMARTLIST_FOREACH_END(cp); - * </pre> - */ -/* Note: these macros use token pasting, and reach into smartlist internals. - * This can make them a little daunting. Here's the approximate unpacking of - * the above examples, for entertainment value: - * - * <pre> - * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); - * { - * int cp_sl_idx, cp_sl_len = smartlist_len(list); - * char *cp; - * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { - * cp = smartlist_get(list, cp_sl_idx); - * printf("%d: %s\n", cp_sl_idx, cp); - * tor_free(cp); - * } - * } - * smartlist_free(list); - * </pre> - * - * <pre> - * { - * int cp_sl_idx, cp_sl_len = smartlist_len(list); - * char *cp; - * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { - * cp = smartlist_get(list, cp_sl_idx); - * if (!strcmp(cp, "junk")) { - * tor_free(cp); - * smartlist_del(list, cp_sl_idx); - * --cp_sl_idx; - * --cp_sl_len; - * } - * } - * } - * </pre> - */ -#define SMARTLIST_FOREACH_BEGIN(sl, type, var) \ - STMT_BEGIN \ - int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \ - type var; \ - for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len; \ - ++var ## _sl_idx) { \ - var = (sl)->list[var ## _sl_idx]; - -#define SMARTLIST_FOREACH_END(var) \ - var = NULL; \ - (void) var ## _sl_idx; \ - } STMT_END - -/** - * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using - * <b>cmd</b> as the loop body. This wrapper is here for convenience with - * very short loops. - * - * By convention, we do not use this for loops which nest, or for loops over - * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those. - */ -#define SMARTLIST_FOREACH(sl, type, var, cmd) \ - SMARTLIST_FOREACH_BEGIN(sl,type,var) { \ - cmd; \ - } SMARTLIST_FOREACH_END(var) - -/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed - * with the variable <b>var</b>, remove the current element in a way that - * won't confuse the loop. */ -#define SMARTLIST_DEL_CURRENT(sl, var) \ - STMT_BEGIN \ - smartlist_del(sl, var ## _sl_idx); \ - --var ## _sl_idx; \ - --var ## _sl_len; \ - STMT_END - -/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed - * with the variable <b>var</b>, remove the current element in a way that - * won't confuse the loop. */ -#define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \ - STMT_BEGIN \ - smartlist_del_keeporder(sl, var ## _sl_idx); \ - --var ## _sl_idx; \ - --var ## _sl_len; \ - STMT_END - -/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed - * with the variable <b>var</b>, replace the current element with <b>val</b>. - * Does not deallocate the current value of <b>var</b>. - */ -#define SMARTLIST_REPLACE_CURRENT(sl, var, val) \ - STMT_BEGIN \ - smartlist_set(sl, var ## _sl_idx, val); \ - STMT_END - -/* Helper: Given two lists of items, possibly of different types, such that - * both lists are sorted on some common field (as determined by a comparison - * expression <b>cmpexpr</b>), and such that one list (<b>sl1</b>) has no - * duplicates on the common field, loop through the lists in lockstep, and - * execute <b>unmatched_var2</b> on items in var2 that do not appear in - * var1. - * - * WARNING: It isn't safe to add remove elements from either list while the - * loop is in progress. - * - * Example use: - * SMARTLIST_FOREACH_JOIN(routerstatus_list, routerstatus_t *, rs, - * routerinfo_list, routerinfo_t *, ri, - * tor_memcmp(rs->identity_digest, ri->identity_digest, 20), - * log_info(LD_GENERAL,"No match for %s", ri->nickname)) { - * log_info(LD_GENERAL, "%s matches routerstatus %p", ri->nickname, rs); - * } SMARTLIST_FOREACH_JOIN_END(rs, ri); - **/ -/* The example above unpacks (approximately) to: - * int rs_sl_idx = 0, rs_sl_len = smartlist_len(routerstatus_list); - * int ri_sl_idx, ri_sl_len = smartlist_len(routerinfo_list); - * int rs_ri_cmp; - * routerstatus_t *rs; - * routerinfo_t *ri; - * for (; ri_sl_idx < ri_sl_len; ++ri_sl_idx) { - * ri = smartlist_get(routerinfo_list, ri_sl_idx); - * while (rs_sl_idx < rs_sl_len) { - * rs = smartlist_get(routerstatus_list, rs_sl_idx); - * rs_ri_cmp = tor_memcmp(rs->identity_digest, ri->identity_digest, 20); - * if (rs_ri_cmp > 0) { - * break; - * } else if (rs_ri_cmp == 0) { - * goto matched_ri; - * } else { - * ++rs_sl_idx; - * } - * } - * log_info(LD_GENERAL,"No match for %s", ri->nickname); - * continue; - * matched_ri: { - * log_info(LD_GENERAL,"%s matches with routerstatus %p",ri->nickname,rs); - * } - * } - */ -#define SMARTLIST_FOREACH_JOIN(sl1, type1, var1, sl2, type2, var2, \ - cmpexpr, unmatched_var2) \ - STMT_BEGIN \ - int var1 ## _sl_idx = 0, var1 ## _sl_len=(sl1)->num_used; \ - int var2 ## _sl_idx = 0, var2 ## _sl_len=(sl2)->num_used; \ - int var1 ## _ ## var2 ## _cmp; \ - type1 var1; \ - type2 var2; \ - for (; var2##_sl_idx < var2##_sl_len; ++var2##_sl_idx) { \ - var2 = (sl2)->list[var2##_sl_idx]; \ - while (var1##_sl_idx < var1##_sl_len) { \ - var1 = (sl1)->list[var1##_sl_idx]; \ - var1##_##var2##_cmp = (cmpexpr); \ - if (var1##_##var2##_cmp > 0) { \ - break; \ - } else if (var1##_##var2##_cmp == 0) { \ - goto matched_##var2; \ - } else { \ - ++var1##_sl_idx; \ - } \ - } \ - /* Ran out of v1, or no match for var2. */ \ - unmatched_var2; \ - continue; \ - matched_##var2: ; \ - -#define SMARTLIST_FOREACH_JOIN_END(var1, var2) \ - } \ - STMT_END - -#define DECLARE_MAP_FNS(maptype, keytype, prefix) \ - typedef struct maptype maptype; \ - typedef struct prefix##entry_t *prefix##iter_t; \ - MOCK_DECL(maptype*, prefix##new, (void)); \ - void* prefix##set(maptype *map, keytype key, void *val); \ - void* prefix##get(const maptype *map, keytype key); \ - void* prefix##remove(maptype *map, keytype key); \ - MOCK_DECL(void, prefix##free_, (maptype *map, void (*free_val)(void*))); \ - int prefix##isempty(const maptype *map); \ - int prefix##size(const maptype *map); \ - prefix##iter_t *prefix##iter_init(maptype *map); \ - prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter); \ - prefix##iter_t *prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter); \ - void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \ - int prefix##iter_done(prefix##iter_t *iter); \ - void prefix##assert_ok(const maptype *map) - -/* Map from const char * to void *. Implemented with a hash table. */ -DECLARE_MAP_FNS(strmap_t, const char *, strmap_); -/* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */ -DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_); -/* Map from const uint8_t[DIGEST256_LEN] to void *. Implemented with a hash - * table. */ -DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); - -#define MAP_FREE_AND_NULL(maptype, map, fn) \ - do { \ - maptype ## _free_((map), (fn)); \ - (map) = NULL; \ - } while (0) - -#define strmap_free(map, fn) MAP_FREE_AND_NULL(strmap, (map), (fn)) -#define digestmap_free(map, fn) MAP_FREE_AND_NULL(digestmap, (map), (fn)) -#define digest256map_free(map, fn) MAP_FREE_AND_NULL(digest256map, (map), (fn)) - -#undef DECLARE_MAP_FNS - -/** Iterates over the key-value pairs in a map <b>map</b> in order. - * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap_ or digestmap_). - * The map's keys and values are of type keytype and valtype respectively; - * each iteration assigns them to keyvar and valvar. - * - * Example use: - * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { - * // use k and r - * } MAP_FOREACH_END. - */ -/* Unpacks to, approximately: - * { - * digestmap_iter_t *k_iter; - * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); - * k_iter = digestmap_iter_next(m, k_iter)) { - * const char *k; - * void *r_voidp; - * routerinfo_t *r; - * digestmap_iter_get(k_iter, &k, &r_voidp); - * r = r_voidp; - * // use k and r - * } - * } - */ -#define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar) \ - STMT_BEGIN \ - prefix##iter_t *keyvar##_iter; \ - for (keyvar##_iter = prefix##iter_init(map); \ - !prefix##iter_done(keyvar##_iter); \ - keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) { \ - keytype keyvar; \ - void *valvar##_voidp; \ - valtype valvar; \ - prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ - valvar = valvar##_voidp; - -/** As MAP_FOREACH, except allows members to be removed from the map - * during the iteration via MAP_DEL_CURRENT. Example use: - * - * Example use: - * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { - * if (is_very_old(r)) - * MAP_DEL_CURRENT(k); - * } MAP_FOREACH_END. - **/ -/* Unpacks to, approximately: - * { - * digestmap_iter_t *k_iter; - * int k_del=0; - * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); - * k_iter = k_del ? digestmap_iter_next(m, k_iter) - * : digestmap_iter_next_rmv(m, k_iter)) { - * const char *k; - * void *r_voidp; - * routerinfo_t *r; - * k_del=0; - * digestmap_iter_get(k_iter, &k, &r_voidp); - * r = r_voidp; - * if (is_very_old(r)) { - * k_del = 1; - * } - * } - * } - */ -#define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \ - STMT_BEGIN \ - prefix##iter_t *keyvar##_iter; \ - int keyvar##_del=0; \ - for (keyvar##_iter = prefix##iter_init(map); \ - !prefix##iter_done(keyvar##_iter); \ - keyvar##_iter = keyvar##_del ? \ - prefix##iter_next_rmv(map, keyvar##_iter) : \ - prefix##iter_next(map, keyvar##_iter)) { \ - keytype keyvar; \ - void *valvar##_voidp; \ - valtype valvar; \ - keyvar##_del=0; \ - prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ - valvar = valvar##_voidp; - -/** Used with MAP_FOREACH_MODIFY to remove the currently-iterated-upon - * member of the map. */ -#define MAP_DEL_CURRENT(keyvar) \ - STMT_BEGIN \ - keyvar##_del = 1; \ - STMT_END - -/** Used to end a MAP_FOREACH() block. */ -#define MAP_FOREACH_END } STMT_END ; - -/** As MAP_FOREACH, but does not require declaration of prefix or keytype. - * Example use: - * DIGESTMAP_FOREACH(m, k, routerinfo_t *, r) { - * // use k and r - * } DIGESTMAP_FOREACH_END. - */ -#define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar) - -/** As MAP_FOREACH_MODIFY, but does not require declaration of prefix or - * keytype. - * Example use: - * DIGESTMAP_FOREACH_MODIFY(m, k, routerinfo_t *, r) { - * if (is_very_old(r)) - * MAP_DEL_CURRENT(k); - * } DIGESTMAP_FOREACH_END. - */ -#define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar) -/** Used to end a DIGESTMAP_FOREACH() block. */ -#define DIGESTMAP_FOREACH_END MAP_FOREACH_END - -#define DIGEST256MAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(digest256map_, map, const uint8_t *, keyvar, valtype, valvar) -#define DIGEST256MAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(digest256map_, map, const uint8_t *, \ - keyvar, valtype, valvar) -#define DIGEST256MAP_FOREACH_END MAP_FOREACH_END - -#define STRMAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar) -#define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar) -#define STRMAP_FOREACH_END MAP_FOREACH_END - -void* strmap_set_lc(strmap_t *map, const char *key, void *val); -void* strmap_get_lc(const strmap_t *map, const char *key); -void* strmap_remove_lc(strmap_t *map, const char *key); - -#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \ - typedef struct maptype maptype; \ - typedef struct prefix##iter_t *prefix##iter_t; \ - ATTR_UNUSED static inline maptype* \ - prefix##new(void) \ - { \ - return (maptype*)digestmap_new(); \ - } \ - ATTR_UNUSED static inline digestmap_t* \ - prefix##to_digestmap(maptype *map) \ - { \ - return (digestmap_t*)map; \ - } \ - ATTR_UNUSED static inline valtype* \ - prefix##get(maptype *map, const char *key) \ - { \ - return (valtype*)digestmap_get((digestmap_t*)map, key); \ - } \ - ATTR_UNUSED static inline valtype* \ - prefix##set(maptype *map, const char *key, valtype *val) \ - { \ - return (valtype*)digestmap_set((digestmap_t*)map, key, val); \ - } \ - ATTR_UNUSED static inline valtype* \ - prefix##remove(maptype *map, const char *key) \ - { \ - return (valtype*)digestmap_remove((digestmap_t*)map, key); \ - } \ - ATTR_UNUSED static inline void \ - prefix##f##ree_(maptype *map, void (*free_val)(void*)) \ - { \ - digestmap_free_((digestmap_t*)map, free_val); \ - } \ - ATTR_UNUSED static inline int \ - prefix##isempty(maptype *map) \ - { \ - return digestmap_isempty((digestmap_t*)map); \ - } \ - ATTR_UNUSED static inline int \ - prefix##size(maptype *map) \ - { \ - return digestmap_size((digestmap_t*)map); \ - } \ - ATTR_UNUSED static inline \ - prefix##iter_t *prefix##iter_init(maptype *map) \ - { \ - return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \ - } \ - ATTR_UNUSED static inline \ - prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter) \ - { \ - return (prefix##iter_t*) digestmap_iter_next( \ - (digestmap_t*)map, (digestmap_iter_t*)iter); \ - } \ - ATTR_UNUSED static inline prefix##iter_t* \ - prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter) \ - { \ - return (prefix##iter_t*) digestmap_iter_next_rmv( \ - (digestmap_t*)map, (digestmap_iter_t*)iter); \ - } \ - ATTR_UNUSED static inline void \ - prefix##iter_get(prefix##iter_t *iter, \ - const char **keyp, \ - valtype **valp) \ - { \ - void *v; \ - digestmap_iter_get((digestmap_iter_t*) iter, keyp, &v); \ - *valp = v; \ - } \ - ATTR_UNUSED static inline int \ - prefix##iter_done(prefix##iter_t *iter) \ - { \ - return digestmap_iter_done((digestmap_iter_t*)iter); \ - } - -#if SIZEOF_INT == 4 -#define BITARRAY_SHIFT 5 -#elif SIZEOF_INT == 8 -#define BITARRAY_SHIFT 6 -#else -#error "int is neither 4 nor 8 bytes. I can't deal with that." -#endif /* SIZEOF_INT == 4 || ... */ -#define BITARRAY_MASK ((1u<<BITARRAY_SHIFT)-1) - -/** A random-access array of one-bit-wide elements. */ -typedef unsigned int bitarray_t; -/** Create a new bit array that can hold <b>n_bits</b> bits. */ -static inline bitarray_t * -bitarray_init_zero(unsigned int n_bits) -{ - /* round up to the next int. */ - size_t sz = (n_bits+BITARRAY_MASK) >> BITARRAY_SHIFT; - return tor_calloc(sz, sizeof(unsigned int)); -} -/** Expand <b>ba</b> from holding <b>n_bits_old</b> to <b>n_bits_new</b>, - * clearing all new bits. Returns a possibly changed pointer to the - * bitarray. */ -static inline bitarray_t * -bitarray_expand(bitarray_t *ba, - unsigned int n_bits_old, unsigned int n_bits_new) -{ - size_t sz_old = (n_bits_old+BITARRAY_MASK) >> BITARRAY_SHIFT; - size_t sz_new = (n_bits_new+BITARRAY_MASK) >> BITARRAY_SHIFT; - char *ptr; - if (sz_new <= sz_old) - return ba; - ptr = tor_reallocarray(ba, sz_new, sizeof(unsigned int)); - /* This memset does nothing to the older excess bytes. But they were - * already set to 0 by bitarry_init_zero. */ - memset(ptr+sz_old*sizeof(unsigned int), 0, - (sz_new-sz_old)*sizeof(unsigned int)); - return (bitarray_t*) ptr; -} -/** Free the bit array <b>ba</b>. */ -static inline void -bitarray_free_(bitarray_t *ba) -{ - tor_free(ba); -} -#define bitarray_free(ba) FREE_AND_NULL(bitarray_t, bitarray_free_, (ba)) - -/** Set the <b>bit</b>th bit in <b>b</b> to 1. */ -static inline void -bitarray_set(bitarray_t *b, int bit) -{ - b[bit >> BITARRAY_SHIFT] |= (1u << (bit & BITARRAY_MASK)); -} -/** Set the <b>bit</b>th bit in <b>b</b> to 0. */ -static inline void -bitarray_clear(bitarray_t *b, int bit) -{ - b[bit >> BITARRAY_SHIFT] &= ~ (1u << (bit & BITARRAY_MASK)); -} -/** Return true iff <b>bit</b>th bit in <b>b</b> is nonzero. NOTE: does - * not necessarily return 1 on true. */ -static inline unsigned int -bitarray_is_set(bitarray_t *b, int bit) -{ - return b[bit >> BITARRAY_SHIFT] & (1u << (bit & BITARRAY_MASK)); -} - -/** A set of digests, implemented as a Bloom filter. */ -typedef struct { - int mask; /**< One less than the number of bits in <b>ba</b>; always one less - * than a power of two. */ - bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ -} digestset_t; - -#define BIT(n) ((n) & set->mask) -/** Add the digest <b>digest</b> to <b>set</b>. */ -static inline void -digestset_add(digestset_t *set, const char *digest) -{ - const uint64_t x = siphash24g(digest, 20); - const uint32_t d1 = (uint32_t) x; - const uint32_t d2 = (uint32_t)( (x>>16) + x); - const uint32_t d3 = (uint32_t)( (x>>32) + x); - const uint32_t d4 = (uint32_t)( (x>>48) + x); - bitarray_set(set->ba, BIT(d1)); - bitarray_set(set->ba, BIT(d2)); - bitarray_set(set->ba, BIT(d3)); - bitarray_set(set->ba, BIT(d4)); -} - -/** If <b>digest</b> is in <b>set</b>, return nonzero. Otherwise, - * <em>probably</em> return zero. */ -static inline int -digestset_contains(const digestset_t *set, const char *digest) -{ - const uint64_t x = siphash24g(digest, 20); - const uint32_t d1 = (uint32_t) x; - const uint32_t d2 = (uint32_t)( (x>>16) + x); - const uint32_t d3 = (uint32_t)( (x>>32) + x); - const uint32_t d4 = (uint32_t)( (x>>48) + x); - return bitarray_is_set(set->ba, BIT(d1)) && - bitarray_is_set(set->ba, BIT(d2)) && - bitarray_is_set(set->ba, BIT(d3)) && - bitarray_is_set(set->ba, BIT(d4)); -} -#undef BIT - -digestset_t *digestset_new(int max_elements); -void digestset_free_(digestset_t* set); -#define digestset_free(set) FREE_AND_NULL(digestset_t, digestset_free_, (set)) - -/* These functions, given an <b>array</b> of <b>n_elements</b>, return the - * <b>nth</b> lowest element. <b>nth</b>=0 gives the lowest element; - * <b>n_elements</b>-1 gives the highest; and (<b>n_elements</b>-1) / 2 gives - * the median. As a side effect, the elements of <b>array</b> are sorted. */ -int find_nth_int(int *array, int n_elements, int nth); -time_t find_nth_time(time_t *array, int n_elements, int nth); -double find_nth_double(double *array, int n_elements, int nth); -int32_t find_nth_int32(int32_t *array, int n_elements, int nth); -uint32_t find_nth_uint32(uint32_t *array, int n_elements, int nth); -long find_nth_long(long *array, int n_elements, int nth); -static inline int -median_int(int *array, int n_elements) -{ - return find_nth_int(array, n_elements, (n_elements-1)/2); -} -static inline time_t -median_time(time_t *array, int n_elements) -{ - return find_nth_time(array, n_elements, (n_elements-1)/2); -} -static inline double -median_double(double *array, int n_elements) -{ - return find_nth_double(array, n_elements, (n_elements-1)/2); -} -static inline uint32_t -median_uint32(uint32_t *array, int n_elements) -{ - return find_nth_uint32(array, n_elements, (n_elements-1)/2); -} -static inline int32_t -median_int32(int32_t *array, int n_elements) -{ - return find_nth_int32(array, n_elements, (n_elements-1)/2); -} - -static inline uint32_t -third_quartile_uint32(uint32_t *array, int n_elements) -{ - return find_nth_uint32(array, n_elements, (n_elements*3)/4); -} - -#endif /* !defined(TOR_CONTAINER_H) */ - diff --git a/src/common/crypto.c b/src/common/crypto.c deleted file mode 100644 index d5b7c96916..0000000000 --- a/src/common/crypto.c +++ /dev/null @@ -1,1118 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto.c - * \brief Wrapper functions to present a consistent interface to - * public-key and symmetric cryptography operations from OpenSSL and - * other places. - **/ - -#include "orconfig.h" - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <wincrypt.h> -/* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually - * use either definition. */ -#undef OCSP_RESPONSE -#endif /* defined(_WIN32) */ - -#define CRYPTO_PRIVATE -#include "compat_openssl.h" -#include "crypto.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_ed25519.h" -#include "crypto_format.h" -#include "crypto_rand.h" -#include "crypto_rsa.h" -#include "crypto_util.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/err.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/conf.h> -#include <openssl/hmac.h> -#include <openssl/ssl.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#else -#pragma GCC diagnostic warning "-Wredundant-decls" -#endif -#endif /* __GNUC__ && GCC_VERSION >= 402 */ - -#ifdef HAVE_CTYPE_H -#include <ctype.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "torlog.h" -#include "torint.h" -#include "aes.h" -#include "util.h" -#include "container.h" -#include "compat.h" -#include "sandbox.h" -#include "util_format.h" - -#include "keccak-tiny/keccak-tiny.h" - -/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake - * while we're waiting for the second.*/ -struct crypto_dh_t { - DH *dh; /**< The openssl DH object */ -}; - -static int tor_check_dh_key(int severity, const BIGNUM *bn); - -/** Boolean: has OpenSSL's crypto been initialized? */ -static int crypto_early_initialized_ = 0; - -/** Boolean: has OpenSSL's crypto been initialized? */ -static int crypto_global_initialized_ = 0; - -/** Log all pending crypto errors at level <b>severity</b>. Use - * <b>doing</b> to describe our current activities. - */ -static void -crypto_log_errors(int severity, const char *doing) -{ - unsigned long err; - const char *msg, *lib, *func; - while ((err = ERR_get_error()) != 0) { - msg = (const char*)ERR_reason_error_string(err); - lib = (const char*)ERR_lib_error_string(err); - func = (const char*)ERR_func_error_string(err); - if (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (BUG(!doing)) doing = "(null)"; - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); - } -} - -#ifndef DISABLE_ENGINES -/** Log any OpenSSL engines we're using at NOTICE. */ -static void -log_engine(const char *fn, ENGINE *e) -{ - if (e) { - const char *name, *id; - name = ENGINE_get_name(e); - id = ENGINE_get_id(e); - log_notice(LD_CRYPTO, "Default OpenSSL engine for %s is %s [%s]", - fn, name?name:"?", id?id:"?"); - } else { - log_info(LD_CRYPTO, "Using default implementation for %s", fn); - } -} -#endif /* !defined(DISABLE_ENGINES) */ - -#ifndef DISABLE_ENGINES -/** Try to load an engine in a shared library via fully qualified path. - */ -static ENGINE * -try_load_engine(const char *path, const char *engine) -{ - ENGINE *e = ENGINE_by_id("dynamic"); - if (e) { - if (!ENGINE_ctrl_cmd_string(e, "ID", engine, 0) || - !ENGINE_ctrl_cmd_string(e, "DIR_LOAD", "2", 0) || - !ENGINE_ctrl_cmd_string(e, "DIR_ADD", path, 0) || - !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { - ENGINE_free(e); - e = NULL; - } - } - return e; -} -#endif /* !defined(DISABLE_ENGINES) */ - -static int have_seeded_siphash = 0; - -/** Set up the siphash key if we haven't already done so. */ -int -crypto_init_siphash_key(void) -{ - struct sipkey key; - if (have_seeded_siphash) - return 0; - - crypto_rand((char*) &key, sizeof(key)); - siphash_set_global_key(&key); - have_seeded_siphash = 1; - return 0; -} - -/** Initialize the crypto library. Return 0 on success, -1 on failure. - */ -int -crypto_early_init(void) -{ - if (!crypto_early_initialized_) { - - crypto_early_initialized_ = 1; - -#ifdef OPENSSL_1_1_API - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | - OPENSSL_INIT_LOAD_CRYPTO_STRINGS | - OPENSSL_INIT_ADD_ALL_CIPHERS | - OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); -#else - ERR_load_crypto_strings(); - OpenSSL_add_all_algorithms(); -#endif - - setup_openssl_threading(); - - unsigned long version_num = OpenSSL_version_num(); - const char *version_str = OpenSSL_version(OPENSSL_VERSION); - if (version_num == OPENSSL_VERSION_NUMBER && - !strcmp(version_str, OPENSSL_VERSION_TEXT)) { - log_info(LD_CRYPTO, "OpenSSL version matches version from headers " - "(%lx: %s).", version_num, version_str); - } else { - log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " - "version we're running with. If you get weird crashes, that " - "might be why. (Compiled with %lx: %s; running with %lx: %s).", - (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, - version_num, version_str); - } - - crypto_force_rand_ssleay(); - - if (crypto_seed_rng() < 0) - return -1; - if (crypto_init_siphash_key() < 0) - return -1; - - curve25519_init(); - ed25519_init(); - } - return 0; -} - -/** Initialize the crypto library. Return 0 on success, -1 on failure. - */ -int -crypto_global_init(int useAccel, const char *accelName, const char *accelDir) -{ - if (!crypto_global_initialized_) { - if (crypto_early_init() < 0) - return -1; - - crypto_global_initialized_ = 1; - - if (useAccel > 0) { -#ifdef DISABLE_ENGINES - (void)accelName; - (void)accelDir; - log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled."); -#else - ENGINE *e = NULL; - - log_info(LD_CRYPTO, "Initializing OpenSSL engine support."); - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); - - if (accelName) { - if (accelDir) { - log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\"" - " via path \"%s\".", accelName, accelDir); - e = try_load_engine(accelName, accelDir); - } else { - log_info(LD_CRYPTO, "Initializing dynamic OpenSSL engine \"%s\"" - " acceleration support.", accelName); - e = ENGINE_by_id(accelName); - } - if (!e) { - log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".", - accelName); - } else { - log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".", - accelName); - } - } - if (e) { - log_info(LD_CRYPTO, "Loaded OpenSSL hardware acceleration engine," - " setting default ciphers."); - ENGINE_set_default(e, ENGINE_METHOD_ALL); - } - /* Log, if available, the intersection of the set of algorithms - used by Tor and the set of algorithms available in the engine */ - log_engine("RSA", ENGINE_get_default_RSA()); - log_engine("DH", ENGINE_get_default_DH()); -#ifdef OPENSSL_1_1_API - log_engine("EC", ENGINE_get_default_EC()); -#else - log_engine("ECDH", ENGINE_get_default_ECDH()); - log_engine("ECDSA", ENGINE_get_default_ECDSA()); -#endif /* defined(OPENSSL_1_1_API) */ - log_engine("RAND", ENGINE_get_default_RAND()); - log_engine("RAND (which we will not use)", ENGINE_get_default_RAND()); - log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1)); - log_engine("3DES-CBC", ENGINE_get_cipher_engine(NID_des_ede3_cbc)); - log_engine("AES-128-ECB", ENGINE_get_cipher_engine(NID_aes_128_ecb)); - log_engine("AES-128-CBC", ENGINE_get_cipher_engine(NID_aes_128_cbc)); -#ifdef NID_aes_128_ctr - log_engine("AES-128-CTR", ENGINE_get_cipher_engine(NID_aes_128_ctr)); -#endif -#ifdef NID_aes_128_gcm - log_engine("AES-128-GCM", ENGINE_get_cipher_engine(NID_aes_128_gcm)); -#endif - log_engine("AES-256-CBC", ENGINE_get_cipher_engine(NID_aes_256_cbc)); -#ifdef NID_aes_256_gcm - log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm)); -#endif - -#endif /* defined(DISABLE_ENGINES) */ - } else { - log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); - } - - if (crypto_force_rand_ssleay()) { - if (crypto_seed_rng() < 0) - return -1; - } - - evaluate_evp_for_aes(-1); - evaluate_ctr_for_aes(); - } - return 0; -} - -/** Free crypto resources held by this thread. */ -void -crypto_thread_cleanup(void) -{ -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif -} - -/** Used by tortls.c: Get the DH* from a crypto_dh_t. - */ -DH * -crypto_dh_get_dh_(crypto_dh_t *dh) -{ - return dh->dh; -} - -/** Allocate and return a new symmetric cipher using the provided key and iv. - * The key is <b>bits</b> bits long; the IV is CIPHER_IV_LEN bytes. Both - * must be provided. Key length must be 128, 192, or 256 */ -crypto_cipher_t * -crypto_cipher_new_with_iv_and_bits(const uint8_t *key, - const uint8_t *iv, - int bits) -{ - tor_assert(key); - tor_assert(iv); - - return aes_new_cipher((const uint8_t*)key, (const uint8_t*)iv, bits); -} - -/** Allocate and return a new symmetric cipher using the provided key and iv. - * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. Both - * must be provided. - */ -crypto_cipher_t * -crypto_cipher_new_with_iv(const char *key, const char *iv) -{ - return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)iv, - 128); -} - -/** Return a new crypto_cipher_t with the provided <b>key</b> and an IV of all - * zero bytes and key length <b>bits</b>. Key length must be 128, 192, or - * 256. */ -crypto_cipher_t * -crypto_cipher_new_with_bits(const char *key, int bits) -{ - char zeroiv[CIPHER_IV_LEN]; - memset(zeroiv, 0, sizeof(zeroiv)); - return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)zeroiv, - bits); -} - -/** Return a new crypto_cipher_t with the provided <b>key</b> (of - * CIPHER_KEY_LEN bytes) and an IV of all zero bytes. */ -crypto_cipher_t * -crypto_cipher_new(const char *key) -{ - return crypto_cipher_new_with_bits(key, 128); -} - -/** Free a symmetric cipher. - */ -void -crypto_cipher_free_(crypto_cipher_t *env) -{ - if (!env) - return; - - aes_cipher_free(env); -} - -/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces - * every four characters. */ -void -crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) -{ - int n = 0; - char *end = out+outlen; - tor_assert(outlen < SIZE_T_CEILING); - - while (*in && out<end) { - *out++ = *in++; - if (++n == 4 && *in && out<end) { - n = 0; - *out++ = ' '; - } - } - tor_assert(out<end); - *out = '\0'; -} - -/* symmetric crypto */ - -/** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher - * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * Does not check for failure. - */ -int -crypto_cipher_encrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen) -{ - tor_assert(env); - tor_assert(env); - tor_assert(from); - tor_assert(fromlen); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - memcpy(to, from, fromlen); - aes_crypt_inplace(env, to, fromlen); - return 0; -} - -/** Decrypt <b>fromlen</b> bytes from <b>from</b> using the cipher - * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * Does not check for failure. - */ -int -crypto_cipher_decrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen) -{ - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - memcpy(to, from, fromlen); - aes_crypt_inplace(env, to, fromlen); - return 0; -} - -/** Encrypt <b>len</b> bytes on <b>from</b> using the cipher in <b>env</b>; - * on success. Does not check for failure. - */ -void -crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len) -{ - tor_assert(len < SIZE_T_CEILING); - aes_crypt_inplace(env, buf, len); -} - -/** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in - * <b>key</b> to the buffer in <b>to</b> of length - * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> plus - * CIPHER_IV_LEN bytes for the initialization vector. On success, return the - * number of bytes written, on failure, return -1. - */ -int -crypto_cipher_encrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen) -{ - crypto_cipher_t *cipher; - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - - if (fromlen < 1) - return -1; - if (tolen < fromlen + CIPHER_IV_LEN) - return -1; - - char iv[CIPHER_IV_LEN]; - crypto_rand(iv, sizeof(iv)); - cipher = crypto_cipher_new_with_iv(key, iv); - - memcpy(to, iv, CIPHER_IV_LEN); - crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen); - crypto_cipher_free(cipher); - memwipe(iv, 0, sizeof(iv)); - return (int)(fromlen + CIPHER_IV_LEN); -} - -/** Decrypt <b>fromlen</b> bytes (at least 1+CIPHER_IV_LEN) from <b>from</b> - * with the key in <b>key</b> to the buffer in <b>to</b> of length - * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> minus - * CIPHER_IV_LEN bytes for the initialization vector. On success, return the - * number of bytes written, on failure, return -1. - */ -int -crypto_cipher_decrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen) -{ - crypto_cipher_t *cipher; - tor_assert(key); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - - if (fromlen <= CIPHER_IV_LEN) - return -1; - if (tolen < fromlen - CIPHER_IV_LEN) - return -1; - - cipher = crypto_cipher_new_with_iv(key, from); - - crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN); - crypto_cipher_free(cipher); - return (int)(fromlen - CIPHER_IV_LEN); -} - -/* DH */ - -/** Our DH 'g' parameter */ -#define DH_GENERATOR 2 - -/** Shared P parameter for our circuit-crypto DH key exchanges. */ -static BIGNUM *dh_param_p = NULL; -/** Shared P parameter for our TLS DH key exchanges. */ -static BIGNUM *dh_param_p_tls = NULL; -/** Shared G parameter for our DH key exchanges. */ -static BIGNUM *dh_param_g = NULL; - -/** Validate a given set of Diffie-Hellman parameters. This is moderately - * computationally expensive (milliseconds), so should only be called when - * the DH parameters change. Returns 0 on success, * -1 on failure. - */ -static int -crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g) -{ - DH *dh = NULL; - int ret = -1; - - /* Copy into a temporary DH object, just so that DH_check() can be called. */ - if (!(dh = DH_new())) - goto out; -#ifdef OPENSSL_1_1_API - BIGNUM *dh_p, *dh_g; - if (!(dh_p = BN_dup(p))) - goto out; - if (!(dh_g = BN_dup(g))) - goto out; - if (!DH_set0_pqg(dh, dh_p, NULL, dh_g)) - goto out; -#else /* !(defined(OPENSSL_1_1_API)) */ - if (!(dh->p = BN_dup(p))) - goto out; - if (!(dh->g = BN_dup(g))) - goto out; -#endif /* defined(OPENSSL_1_1_API) */ - - /* Perform the validation. */ - int codes = 0; - if (!DH_check(dh, &codes)) - goto out; - if (BN_is_word(g, DH_GENERATOR_2)) { - /* Per https://wiki.openssl.org/index.php/Diffie-Hellman_parameters - * - * OpenSSL checks the prime is congruent to 11 when g = 2; while the - * IETF's primes are congruent to 23 when g = 2. - */ - BN_ULONG residue = BN_mod_word(p, 24); - if (residue == 11 || residue == 23) - codes &= ~DH_NOT_SUITABLE_GENERATOR; - } - if (codes != 0) /* Specifics on why the params suck is irrelevant. */ - goto out; - - /* Things are probably not evil. */ - ret = 0; - - out: - if (dh) - DH_free(dh); - return ret; -} - -/** Set the global Diffie-Hellman generator, used for both TLS and internal - * DH stuff. - */ -static void -crypto_set_dh_generator(void) -{ - BIGNUM *generator; - int r; - - if (dh_param_g) - return; - - generator = BN_new(); - tor_assert(generator); - - r = BN_set_word(generator, DH_GENERATOR); - tor_assert(r); - - dh_param_g = generator; -} - -/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH - * modulus. */ -void -crypto_set_tls_dh_prime(void) -{ - BIGNUM *tls_prime = NULL; - int r; - - /* If the space is occupied, free the previous TLS DH prime */ - if (BUG(dh_param_p_tls)) { - /* LCOV_EXCL_START - * - * We shouldn't be calling this twice. - */ - BN_clear_free(dh_param_p_tls); - dh_param_p_tls = NULL; - /* LCOV_EXCL_STOP */ - } - - tls_prime = BN_new(); - tor_assert(tls_prime); - - /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see - * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this - * prime. - */ - r = BN_hex2bn(&tls_prime, - "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" - "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" - "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" - "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" - "B0E7393E0F24218EB3"); - tor_assert(r); - - tor_assert(tls_prime); - - dh_param_p_tls = tls_prime; - crypto_set_dh_generator(); - tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g)); -} - -/** Initialize dh_param_p and dh_param_g if they are not already - * set. */ -static void -init_dh_param(void) -{ - BIGNUM *circuit_dh_prime; - int r; - if (BUG(dh_param_p && dh_param_g)) - return; // LCOV_EXCL_LINE This function isn't supposed to be called twice. - - circuit_dh_prime = BN_new(); - tor_assert(circuit_dh_prime); - - /* This is from rfc2409, section 6.2. It's a safe prime, and - supposedly it equals: - 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. - */ - r = BN_hex2bn(&circuit_dh_prime, - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" - "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" - "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" - "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE65381FFFFFFFFFFFFFFFF"); - tor_assert(r); - - /* Set the new values as the global DH parameters. */ - dh_param_p = circuit_dh_prime; - crypto_set_dh_generator(); - tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g)); - - if (!dh_param_p_tls) { - crypto_set_tls_dh_prime(); - } -} - -/** Number of bits to use when choosing the x or y value in a Diffie-Hellman - * handshake. Since we exponentiate by this value, choosing a smaller one - * lets our handhake go faster. - */ -#define DH_PRIVATE_KEY_BITS 320 - -/** Allocate and return a new DH object for a key exchange. Returns NULL on - * failure. - */ -crypto_dh_t * -crypto_dh_new(int dh_type) -{ - crypto_dh_t *res = tor_malloc_zero(sizeof(crypto_dh_t)); - - tor_assert(dh_type == DH_TYPE_CIRCUIT || dh_type == DH_TYPE_TLS || - dh_type == DH_TYPE_REND); - - if (!dh_param_p) - init_dh_param(); - - if (!(res->dh = DH_new())) - goto err; - -#ifdef OPENSSL_1_1_API - BIGNUM *dh_p = NULL, *dh_g = NULL; - - if (dh_type == DH_TYPE_TLS) { - dh_p = BN_dup(dh_param_p_tls); - } else { - dh_p = BN_dup(dh_param_p); - } - if (!dh_p) - goto err; - - dh_g = BN_dup(dh_param_g); - if (!dh_g) { - BN_free(dh_p); - goto err; - } - - if (!DH_set0_pqg(res->dh, dh_p, NULL, dh_g)) { - goto err; - } - - if (!DH_set_length(res->dh, DH_PRIVATE_KEY_BITS)) - goto err; -#else /* !(defined(OPENSSL_1_1_API)) */ - if (dh_type == DH_TYPE_TLS) { - if (!(res->dh->p = BN_dup(dh_param_p_tls))) - goto err; - } else { - if (!(res->dh->p = BN_dup(dh_param_p))) - goto err; - } - - if (!(res->dh->g = BN_dup(dh_param_g))) - goto err; - - res->dh->length = DH_PRIVATE_KEY_BITS; -#endif /* defined(OPENSSL_1_1_API) */ - - return res; - - /* LCOV_EXCL_START - * This error condition is only reached when an allocation fails */ - err: - crypto_log_errors(LOG_WARN, "creating DH object"); - if (res->dh) DH_free(res->dh); /* frees p and g too */ - tor_free(res); - return NULL; - /* LCOV_EXCL_STOP */ -} - -/** Return a copy of <b>dh</b>, sharing its internal state. */ -crypto_dh_t * -crypto_dh_dup(const crypto_dh_t *dh) -{ - crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t)); - tor_assert(dh); - tor_assert(dh->dh); - dh_new->dh = dh->dh; - DH_up_ref(dh->dh); - return dh_new; -} - -/** Return the length of the DH key in <b>dh</b>, in bytes. - */ -int -crypto_dh_get_bytes(crypto_dh_t *dh) -{ - tor_assert(dh); - return DH_size(dh->dh); -} - -/** Generate \<x,g^x\> for our part of the key exchange. Return 0 on - * success, -1 on failure. - */ -int -crypto_dh_generate_public(crypto_dh_t *dh) -{ -#ifndef OPENSSL_1_1_API - again: -#endif - if (!DH_generate_key(dh->dh)) { - /* LCOV_EXCL_START - * To test this we would need some way to tell openssl to break DH. */ - crypto_log_errors(LOG_WARN, "generating DH key"); - return -1; - /* LCOV_EXCL_STOP */ - } -#ifdef OPENSSL_1_1_API - /* OpenSSL 1.1.x doesn't appear to let you regenerate a DH key, without - * recreating the DH object. I have no idea what sort of aliasing madness - * can occur here, so do the check, and just bail on failure. - */ - const BIGNUM *pub_key, *priv_key; - DH_get0_key(dh->dh, &pub_key, &priv_key); - if (tor_check_dh_key(LOG_WARN, pub_key)<0) { - log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" - "the-universe chances really do happen. Treating as a failure."); - return -1; - } -#else /* !(defined(OPENSSL_1_1_API)) */ - if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { - /* LCOV_EXCL_START - * If this happens, then openssl's DH implementation is busted. */ - log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" - "the-universe chances really do happen. Trying again."); - /* Free and clear the keys, so OpenSSL will actually try again. */ - BN_clear_free(dh->dh->pub_key); - BN_clear_free(dh->dh->priv_key); - dh->dh->pub_key = dh->dh->priv_key = NULL; - goto again; - /* LCOV_EXCL_STOP */ - } -#endif /* defined(OPENSSL_1_1_API) */ - return 0; -} - -/** Generate g^x as necessary, and write the g^x for the key exchange - * as a <b>pubkey_len</b>-byte value into <b>pubkey</b>. Return 0 on - * success, -1 on failure. <b>pubkey_len</b> must be \>= DH_BYTES. - */ -int -crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len) -{ - int bytes; - tor_assert(dh); - - const BIGNUM *dh_pub; - -#ifdef OPENSSL_1_1_API - const BIGNUM *dh_priv; - DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif /* defined(OPENSSL_1_1_API) */ - - if (!dh_pub) { - if (crypto_dh_generate_public(dh)<0) - return -1; - else { -#ifdef OPENSSL_1_1_API - DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif - } - } - - tor_assert(dh_pub); - bytes = BN_num_bytes(dh_pub); - tor_assert(bytes >= 0); - if (pubkey_len < (size_t)bytes) { - log_warn(LD_CRYPTO, - "Weird! pubkey_len (%d) was smaller than DH_BYTES (%d)", - (int) pubkey_len, bytes); - return -1; - } - - memset(pubkey, 0, pubkey_len); - BN_bn2bin(dh_pub, (unsigned char*)(pubkey+(pubkey_len-bytes))); - - return 0; -} - -/** Check for bad Diffie-Hellman public keys (g^x). Return 0 if the key is - * okay (in the subgroup [2,p-2]), or -1 if it's bad. - * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips. - */ -static int -tor_check_dh_key(int severity, const BIGNUM *bn) -{ - BIGNUM *x; - char *s; - tor_assert(bn); - x = BN_new(); - tor_assert(x); - if (BUG(!dh_param_p)) - init_dh_param(); //LCOV_EXCL_LINE we already checked whether we did this. - BN_set_word(x, 1); - if (BN_cmp(bn,x)<=0) { - log_fn(severity, LD_CRYPTO, "DH key must be at least 2."); - goto err; - } - BN_copy(x,dh_param_p); - BN_sub_word(x, 1); - if (BN_cmp(bn,x)>=0) { - log_fn(severity, LD_CRYPTO, "DH key must be at most p-2."); - goto err; - } - BN_clear_free(x); - return 0; - err: - BN_clear_free(x); - s = BN_bn2hex(bn); - log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s); - OPENSSL_free(s); - return -1; -} - -/** Given a DH key exchange object, and our peer's value of g^y (as a - * <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate - * <b>secret_bytes_out</b> bytes of shared key material and write them - * to <b>secret_out</b>. Return the number of bytes generated on success, - * or -1 on failure. - * - * (We generate key material by computing - * SHA1( g^xy || "\x00" ) || SHA1( g^xy || "\x01" ) || ... - * where || is concatenation.) - */ -ssize_t -crypto_dh_compute_secret(int severity, crypto_dh_t *dh, - const char *pubkey, size_t pubkey_len, - char *secret_out, size_t secret_bytes_out) -{ - char *secret_tmp = NULL; - BIGNUM *pubkey_bn = NULL; - size_t secret_len=0, secret_tmp_len=0; - int result=0; - tor_assert(dh); - tor_assert(secret_bytes_out/DIGEST_LEN <= 255); - tor_assert(pubkey_len < INT_MAX); - - if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey, - (int)pubkey_len, NULL))) - goto error; - if (tor_check_dh_key(severity, pubkey_bn)<0) { - /* Check for invalid public keys. */ - log_fn(severity, LD_CRYPTO,"Rejected invalid g^x"); - goto error; - } - secret_tmp_len = crypto_dh_get_bytes(dh); - secret_tmp = tor_malloc(secret_tmp_len); - result = DH_compute_key((unsigned char*)secret_tmp, pubkey_bn, dh->dh); - if (result < 0) { - log_warn(LD_CRYPTO,"DH_compute_key() failed."); - goto error; - } - secret_len = result; - if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len, - (uint8_t*)secret_out, secret_bytes_out)<0) - goto error; - secret_len = secret_bytes_out; - - goto done; - error: - result = -1; - done: - crypto_log_errors(LOG_WARN, "completing DH handshake"); - if (pubkey_bn) - BN_clear_free(pubkey_bn); - if (secret_tmp) { - memwipe(secret_tmp, 0, secret_tmp_len); - tor_free(secret_tmp); - } - if (result < 0) - return result; - else - return secret_len; -} - -/** Given <b>key_in_len</b> bytes of negotiated randomness in <b>key_in</b> - * ("K"), expand it into <b>key_out_len</b> bytes of negotiated key material in - * <b>key_out</b> by taking the first <b>key_out_len</b> bytes of - * H(K | [00]) | H(K | [01]) | .... - * - * This is the key expansion algorithm used in the "TAP" circuit extension - * mechanism; it shouldn't be used for new protocols. - * - * Return 0 on success, -1 on failure. - */ -int -crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, - uint8_t *key_out, size_t key_out_len) -{ - int i, r = -1; - uint8_t *cp, *tmp = tor_malloc(key_in_len+1); - uint8_t digest[DIGEST_LEN]; - - /* If we try to get more than this amount of key data, we'll repeat blocks.*/ - tor_assert(key_out_len <= DIGEST_LEN*256); - - memcpy(tmp, key_in, key_in_len); - for (cp = key_out, i=0; cp < key_out+key_out_len; - ++i, cp += DIGEST_LEN) { - tmp[key_in_len] = i; - if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0) - goto exit; - memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); - } - - r = 0; - exit: - memwipe(tmp, 0, key_in_len+1); - tor_free(tmp); - memwipe(digest, 0, sizeof(digest)); - return r; -} - -/** Expand some secret key material according to RFC5869, using SHA256 as the - * underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the - * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the - * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt" - * and "info" parameters respectively. On success, write <b>key_out_len</b> - * bytes to <b>key_out</b> and return 0. Assert on failure. - */ -int -crypto_expand_key_material_rfc5869_sha256( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len) -{ - uint8_t prk[DIGEST256_LEN]; - uint8_t tmp[DIGEST256_LEN + 128 + 1]; - uint8_t mac[DIGEST256_LEN]; - int i; - uint8_t *outp; - size_t tmp_len; - - crypto_hmac_sha256((char*)prk, - (const char*)salt_in, salt_in_len, - (const char*)key_in, key_in_len); - - /* If we try to get more than this amount of key data, we'll repeat blocks.*/ - tor_assert(key_out_len <= DIGEST256_LEN * 256); - tor_assert(info_in_len <= 128); - memset(tmp, 0, sizeof(tmp)); - outp = key_out; - i = 1; - - while (key_out_len) { - size_t n; - if (i > 1) { - memcpy(tmp, mac, DIGEST256_LEN); - memcpy(tmp+DIGEST256_LEN, info_in, info_in_len); - tmp[DIGEST256_LEN+info_in_len] = i; - tmp_len = DIGEST256_LEN + info_in_len + 1; - } else { - memcpy(tmp, info_in, info_in_len); - tmp[info_in_len] = i; - tmp_len = info_in_len + 1; - } - crypto_hmac_sha256((char*)mac, - (const char*)prk, DIGEST256_LEN, - (const char*)tmp, tmp_len); - n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN; - memcpy(outp, mac, n); - key_out_len -= n; - outp += n; - ++i; - } - - memwipe(tmp, 0, sizeof(tmp)); - memwipe(mac, 0, sizeof(mac)); - return 0; -} - -/** Free a DH key exchange object. - */ -void -crypto_dh_free_(crypto_dh_t *dh) -{ - if (!dh) - return; - tor_assert(dh->dh); - DH_free(dh->dh); - tor_free(dh); -} - -/** @{ */ -/** Uninitialize the crypto library. Return 0 on success. Does not detect - * failure. - */ -int -crypto_global_cleanup(void) -{ -#ifndef OPENSSL_1_1_API - EVP_cleanup(); -#endif -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif -#ifndef OPENSSL_1_1_API - ERR_free_strings(); -#endif - - if (dh_param_p) - BN_clear_free(dh_param_p); - if (dh_param_p_tls) - BN_clear_free(dh_param_p_tls); - if (dh_param_g) - BN_clear_free(dh_param_g); - - dh_param_p = dh_param_p_tls = dh_param_g = NULL; - -#ifndef DISABLE_ENGINES -#ifndef OPENSSL_1_1_API - ENGINE_cleanup(); -#endif -#endif - - CONF_modules_unload(1); -#ifndef OPENSSL_1_1_API - CRYPTO_cleanup_all_ex_data(); -#endif - - crypto_openssl_free_all(); - - crypto_early_initialized_ = 0; - crypto_global_initialized_ = 0; - have_seeded_siphash = 0; - siphash_unset_global_key(); - - return 0; -} - -/** @} */ - -#ifdef USE_DMALLOC -/** Tell the crypto library to use Tor's allocation functions rather than - * calling libc's allocation functions directly. Return 0 on success, -1 - * on failure. */ -int -crypto_use_tor_alloc_functions(void) -{ - int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_); - return r ? 0 : -1; -} -#endif /* defined(USE_DMALLOC) */ - diff --git a/src/common/crypto.h b/src/common/crypto.h deleted file mode 100644 index c773557310..0000000000 --- a/src/common/crypto.h +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto.h - * - * \brief Headers for crypto.c - **/ - -#ifndef TOR_CRYPTO_H -#define TOR_CRYPTO_H - -#include "orconfig.h" - -#include <stdio.h> -#include "torint.h" -#include "compat.h" -#include "util.h" -#include "crypto_rsa.h" - -/** Length of our symmetric cipher's keys of 128-bit. */ -#define CIPHER_KEY_LEN 16 -/** Length of our symmetric cipher's IV of 128-bit. */ -#define CIPHER_IV_LEN 16 -/** Length of our symmetric cipher's keys of 256-bit. */ -#define CIPHER256_KEY_LEN 32 -/** Length of our DH keys. */ -#define DH_BYTES (1024/8) - -/** Length of encoded public key fingerprints, including space; but not - * including terminating NUL. */ -#define FINGERPRINT_LEN 49 - -typedef struct aes_cnt_cipher crypto_cipher_t; -typedef struct crypto_dh_t crypto_dh_t; - -/* global state */ -int crypto_init_siphash_key(void); -int crypto_early_init(void) ATTR_WUR; -int crypto_global_init(int hardwareAccel, - const char *accelName, - const char *accelPath) ATTR_WUR; -#ifdef USE_DMALLOC -int crypto_use_tor_alloc_functions(void); -#endif - -void crypto_thread_cleanup(void); -int crypto_global_cleanup(void); - -/* environment setup */ -void crypto_set_tls_dh_prime(void); -crypto_cipher_t *crypto_cipher_new(const char *key); -crypto_cipher_t *crypto_cipher_new_with_bits(const char *key, int bits); -crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv); -crypto_cipher_t *crypto_cipher_new_with_iv_and_bits(const uint8_t *key, - const uint8_t *iv, - int bits); -void crypto_cipher_free_(crypto_cipher_t *env); -#define crypto_cipher_free(c) \ - FREE_AND_NULL(crypto_cipher_t, crypto_cipher_free_, (c)) - -/* symmetric crypto */ -const char *crypto_cipher_get_key(crypto_cipher_t *env); - -int crypto_cipher_encrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen); -int crypto_cipher_decrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen); -void crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *d, size_t len); - -int crypto_cipher_encrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen); -int crypto_cipher_decrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen); - -/* Key negotiation */ -#define DH_TYPE_CIRCUIT 1 -#define DH_TYPE_REND 2 -#define DH_TYPE_TLS 3 -crypto_dh_t *crypto_dh_new(int dh_type); -crypto_dh_t *crypto_dh_dup(const crypto_dh_t *dh); -int crypto_dh_get_bytes(crypto_dh_t *dh); -int crypto_dh_generate_public(crypto_dh_t *dh); -int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out, - size_t pubkey_out_len); -ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh, - const char *pubkey, size_t pubkey_len, - char *secret_out, size_t secret_out_len); -void crypto_dh_free_(crypto_dh_t *dh); -#define crypto_dh_free(dh) FREE_AND_NULL(crypto_dh_t, crypto_dh_free_, (dh)) - -int crypto_expand_key_material_TAP(const uint8_t *key_in, - size_t key_in_len, - uint8_t *key_out, size_t key_out_len); -int crypto_expand_key_material_rfc5869_sha256( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len); - -/* Prototypes for private functions only used by tortls.c, crypto.c, and the - * unit tests. */ -struct dh_st; -struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh); - -void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in); - -#endif /* !defined(TOR_CRYPTO_H) */ - diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c deleted file mode 100644 index 996d94c6e2..0000000000 --- a/src/common/crypto_curve25519.c +++ /dev/null @@ -1,359 +0,0 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_curve25519.c - * - * \brief Wrapper code for a curve25519 implementation. - * - * Curve25519 is an Elliptic-Curve Diffie Hellman handshake, designed by - * Dan Bernstein. For more information, see https://cr.yp.to/ecdh.html - * - * Tor uses Curve25519 as the basis of its "ntor" circuit extension - * handshake, and in related code. The functions in this module are - * used to find the most suitable available Curve25519 implementation, - * to provide wrappers around it, and so on. - */ - -#define CRYPTO_CURVE25519_PRIVATE -#include "orconfig.h" -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#include "container.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_format.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "util.h" -#include "torlog.h" - -#include "ed25519/donna/ed25519_donna_tor.h" - -/* ============================== - Part 1: wrap a suitable curve25519 implementation as curve25519_impl - ============================== */ - -#ifdef USE_CURVE25519_DONNA -int curve25519_donna(uint8_t *mypublic, - const uint8_t *secret, const uint8_t *basepoint); -#endif -#ifdef USE_CURVE25519_NACL -#ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H -#include <crypto_scalarmult_curve25519.h> -#elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H) -#include <nacl/crypto_scalarmult_curve25519.h> -#endif -#endif /* defined(USE_CURVE25519_NACL) */ - -static void pick_curve25519_basepoint_impl(void); - -/** This is set to 1 if we have an optimized Ed25519-based - * implementation for multiplying a value by the basepoint; to 0 if we - * don't, and to -1 if we haven't checked. */ -static int curve25519_use_ed = -1; - -/** - * Helper function: call the most appropriate backend to compute the - * scalar "secret" times the point "point". Store the result in - * "output". Return 0 on success, negative on failure. - **/ -STATIC int -curve25519_impl(uint8_t *output, const uint8_t *secret, - const uint8_t *point) -{ - uint8_t bp[CURVE25519_PUBKEY_LEN]; - int r; - memcpy(bp, point, CURVE25519_PUBKEY_LEN); - /* Clear the high bit, in case our backend foolishly looks at it. */ - bp[31] &= 0x7f; -#ifdef USE_CURVE25519_DONNA - r = curve25519_donna(output, secret, bp); -#elif defined(USE_CURVE25519_NACL) - r = crypto_scalarmult_curve25519(output, secret, bp); -#else -#error "No implementation of curve25519 is available." -#endif /* defined(USE_CURVE25519_DONNA) || ... */ - memwipe(bp, 0, sizeof(bp)); - return r; -} - -/** - * Helper function: Multiply the scalar "secret" by the Curve25519 - * basepoint (X=9), and store the result in "output". Return 0 on - * success, -1 on failure. - */ -STATIC int -curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret) -{ - int r = 0; - if (BUG(curve25519_use_ed == -1)) { - /* LCOV_EXCL_START - Only reached if we forgot to call curve25519_init() */ - pick_curve25519_basepoint_impl(); - /* LCOV_EXCL_STOP */ - } - - /* TODO: Someone should benchmark curved25519_scalarmult_basepoint versus - * an optimized NaCl build to see which should be used when compiled with - * NaCl available. I suspected that the ed25519 optimization always wins. - */ - if (PREDICT_LIKELY(curve25519_use_ed == 1)) { - curved25519_scalarmult_basepoint_donna(output, secret); - r = 0; - } else { - static const uint8_t basepoint[32] = {9}; - r = curve25519_impl(output, secret, basepoint); - } - return r; -} - -/** - * Override the decision of whether to use the Ed25519-based basepoint - * multiply function. Used for testing. - */ -void -curve25519_set_impl_params(int use_ed) -{ - curve25519_use_ed = use_ed; -} - -/* ============================== - Part 2: Wrap curve25519_impl with some convenience types and functions. - ============================== */ - -/** - * Return true iff a curve25519_public_key_t seems valid. (It's not necessary - * to see if the point is on the curve, since the twist is also secure, but we - * do need to make sure that it isn't the point at infinity.) */ -int -curve25519_public_key_is_ok(const curve25519_public_key_t *key) -{ - return !safe_mem_is_zero(key->public_key, CURVE25519_PUBKEY_LEN); -} - -/** - * Generate CURVE25519_SECKEY_LEN random bytes in <b>out</b>. If - * <b>extra_strong</b> is true, this key is possibly going to get used more - * than once, so use a better-than-usual RNG. Return 0 on success, -1 on - * failure. - * - * This function does not adjust the output of the RNG at all; the will caller - * will need to clear or set the appropriate bits to make curve25519 work. - */ -int -curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong) -{ - if (extra_strong) - crypto_strongest_rand(out, CURVE25519_SECKEY_LEN); - else - crypto_rand((char*)out, CURVE25519_SECKEY_LEN); - - return 0; -} - -/** Generate a new keypair and return the secret key. If <b>extra_strong</b> - * is true, this key is possibly going to get used more than once, so - * use a better-than-usual RNG. Return 0 on success, -1 on failure. */ -int -curve25519_secret_key_generate(curve25519_secret_key_t *key_out, - int extra_strong) -{ - if (curve25519_rand_seckey_bytes(key_out->secret_key, extra_strong) < 0) - return -1; - - key_out->secret_key[0] &= 248; - key_out->secret_key[31] &= 127; - key_out->secret_key[31] |= 64; - - return 0; -} - -/** - * Given a secret key in <b>seckey</b>, create the corresponding public - * key in <b>key_out</b>. - */ -void -curve25519_public_key_generate(curve25519_public_key_t *key_out, - const curve25519_secret_key_t *seckey) -{ - curve25519_basepoint_impl(key_out->public_key, seckey->secret_key); -} - -/** - * Construct a new keypair in *<b>keypair_out</b>. If <b>extra_strong</b> - * is true, this key is possibly going to get used more than once, so - * use a better-than-usual RNG. Return 0 on success, -1 on failure. */ -int -curve25519_keypair_generate(curve25519_keypair_t *keypair_out, - int extra_strong) -{ - if (curve25519_secret_key_generate(&keypair_out->seckey, extra_strong) < 0) - return -1; - curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey); - return 0; -} - -/** Store the keypair <b>keypair</b>, including its secret and public - * parts, to the file <b>fname</b>. Use the string tag <b>tag</b> to - * distinguish this from other Curve25519 keypairs. Return 0 on success, - * -1 on failure. - * - * See crypto_write_tagged_contents_to_file() for more information on - * the metaformat used for these keys.*/ -int -curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair, - const char *fname, - const char *tag) -{ - uint8_t contents[CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN]; - int r; - - memcpy(contents, keypair->seckey.secret_key, CURVE25519_SECKEY_LEN); - memcpy(contents+CURVE25519_SECKEY_LEN, - keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN); - - r = crypto_write_tagged_contents_to_file(fname, - "c25519v1", - tag, - contents, - sizeof(contents)); - - memwipe(contents, 0, sizeof(contents)); - return r; -} - -/** Read a curve25519 keypair from a file named <b>fname</b> created by - * curve25519_keypair_write_to_file(). Store the keypair in - * <b>keypair_out</b>, and the associated tag string in <b>tag_out</b>. - * Return 0 on success, and -1 on failure. */ -int -curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out, - char **tag_out, - const char *fname) -{ - uint8_t content[CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN]; - ssize_t len; - int r = -1; - - len = crypto_read_tagged_contents_from_file(fname, "c25519v1", tag_out, - content, sizeof(content)); - if (len != sizeof(content)) - goto end; - - /* Make sure that the public key matches the secret key */ - memcpy(keypair_out->seckey.secret_key, content, CURVE25519_SECKEY_LEN); - curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey); - if (tor_memneq(keypair_out->pubkey.public_key, - content + CURVE25519_SECKEY_LEN, - CURVE25519_PUBKEY_LEN)) - goto end; - - r = 0; - - end: - memwipe(content, 0, sizeof(content)); - if (r != 0) { - memset(keypair_out, 0, sizeof(*keypair_out)); - tor_free(*tag_out); - } - return r; -} - -/** Perform the curve25519 ECDH handshake with <b>skey</b> and <b>pkey</b>, - * writing CURVE25519_OUTPUT_LEN bytes of output into <b>output</b>. */ -void -curve25519_handshake(uint8_t *output, - const curve25519_secret_key_t *skey, - const curve25519_public_key_t *pkey) -{ - curve25519_impl(output, skey->secret_key, pkey->public_key); -} - -/** Check whether the ed25519-based curve25519 basepoint optimization seems to - * be working. If so, return 0; otherwise return -1. */ -static int -curve25519_basepoint_spot_check(void) -{ - static const uint8_t alicesk[32] = { - 0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d, - 0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45, - 0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a, - 0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a - }; - static const uint8_t alicepk[32] = { - 0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54, - 0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a, - 0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4, - 0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a - }; - const int loop_max=200; - int save_use_ed = curve25519_use_ed; - unsigned char e1[32] = { 5 }; - unsigned char e2[32] = { 5 }; - unsigned char x[32],y[32]; - int i; - int r=0; - - /* Check the most basic possible sanity via the test secret/public key pair - * used in "Cryptography in NaCl - 2. Secret keys and public keys". This - * may catch catastrophic failures on systems where Curve25519 is expensive, - * without requiring a ton of key generation. - */ - curve25519_use_ed = 1; - r |= curve25519_basepoint_impl(x, alicesk); - if (fast_memneq(x, alicepk, 32)) - goto fail; - - /* Ok, the optimization appears to produce passable results, try a few more - * values, maybe there's something subtle wrong. - */ - for (i = 0; i < loop_max; ++i) { - curve25519_use_ed = 0; - r |= curve25519_basepoint_impl(x, e1); - curve25519_use_ed = 1; - r |= curve25519_basepoint_impl(y, e2); - if (fast_memneq(x,y,32)) - goto fail; - memcpy(e1, x, 32); - memcpy(e2, x, 32); - } - - goto end; - // LCOV_EXCL_START -- we can only hit this code if there is a bug in our - // curve25519-basepoint implementation. - fail: - r = -1; - // LCOV_EXCL_STOP - end: - curve25519_use_ed = save_use_ed; - return r; -} - -/** Choose whether to use the ed25519-based curve25519-basepoint - * implementation. */ -static void -pick_curve25519_basepoint_impl(void) -{ - curve25519_use_ed = 1; - - if (curve25519_basepoint_spot_check() == 0) - return; - - /* LCOV_EXCL_START - * only reachable if our basepoint implementation broken */ - log_warn(LD_BUG|LD_CRYPTO, "The ed25519-based curve25519 basepoint " - "multiplication seems broken; using the curve25519 " - "implementation."); - curve25519_use_ed = 0; - /* LCOV_EXCL_STOP */ -} - -/** Initialize the curve25519 implementations. This is necessary if you're - * going to use them in a multithreaded setting, and not otherwise. */ -void -curve25519_init(void) -{ - pick_curve25519_basepoint_impl(); -} - diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h deleted file mode 100644 index 4834fa0836..0000000000 --- a/src/common/crypto_curve25519.h +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CRYPTO_CURVE25519_H -#define TOR_CRYPTO_CURVE25519_H - -#include "testsupport.h" -#include "torint.h" -#include "crypto_digest.h" -#include "crypto_openssl_mgt.h" - -/** Length of a curve25519 public key when encoded. */ -#define CURVE25519_PUBKEY_LEN 32 -/** Length of a curve25519 secret key when encoded. */ -#define CURVE25519_SECKEY_LEN 32 -/** Length of the result of a curve25519 handshake. */ -#define CURVE25519_OUTPUT_LEN 32 - -/** Wrapper type for a curve25519 public key. - * - * (We define a separate type for these to make it less likely that we'll - * mistake them for secret keys.) - * */ -typedef struct curve25519_public_key_t { - uint8_t public_key[CURVE25519_PUBKEY_LEN]; -} curve25519_public_key_t; - -/** Wrapper type for a curve25519 secret key - * - * (We define a separate type for these to make it less likely that we'll - * mistake them for public keys.) - **/ -typedef struct curve25519_secret_key_t { - uint8_t secret_key[CURVE25519_SECKEY_LEN]; -} curve25519_secret_key_t; - -/** A paired public and private key for curve25519. **/ -typedef struct curve25519_keypair_t { - curve25519_public_key_t pubkey; - curve25519_secret_key_t seckey; -} curve25519_keypair_t; - -/* These functions require that we actually know how to use curve25519 keys. - * The other data structures and functions in this header let us parse them, - * store them, and move them around. - */ - -int curve25519_public_key_is_ok(const curve25519_public_key_t *); - -int curve25519_secret_key_generate(curve25519_secret_key_t *key_out, - int extra_strong); -void curve25519_public_key_generate(curve25519_public_key_t *key_out, - const curve25519_secret_key_t *seckey); -int curve25519_keypair_generate(curve25519_keypair_t *keypair_out, - int extra_strong); - -void curve25519_handshake(uint8_t *output, - const curve25519_secret_key_t *, - const curve25519_public_key_t *); - -int curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair, - const char *fname, - const char *tag); - -int curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out, - char **tag_out, - const char *fname); - -int curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong); - -#ifdef CRYPTO_CURVE25519_PRIVATE -STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret, - const uint8_t *basepoint); - -STATIC int curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret); -#endif /* defined(CRYPTO_CURVE25519_PRIVATE) */ - -#define CURVE25519_BASE64_PADDED_LEN 44 - -int curve25519_public_from_base64(curve25519_public_key_t *pkey, - const char *input); -int curve25519_public_to_base64(char *output, - const curve25519_public_key_t *pkey); - -void curve25519_set_impl_params(int use_ed); -void curve25519_init(void); - -#endif /* !defined(TOR_CRYPTO_CURVE25519_H) */ - diff --git a/src/common/crypto_digest.c b/src/common/crypto_digest.c deleted file mode 100644 index 9f9a1a1e2c..0000000000 --- a/src/common/crypto_digest.c +++ /dev/null @@ -1,583 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_digest.c - * \brief Block of functions related with digest and xof utilities and - * operations. - **/ - -#include "container.h" -#include "crypto_digest.h" -#include "crypto_openssl_mgt.h" -#include "crypto_util.h" -#include "torlog.h" - -#include "keccak-tiny/keccak-tiny.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/hmac.h> -#include <openssl/sha.h> - -ENABLE_GCC_WARNING(redundant-decls) - -/* Crypto digest functions */ - -/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in - * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>. - * Return 0 on success, -1 on failure. - */ -int -crypto_digest(char *digest, const char *m, size_t len) -{ - tor_assert(m); - tor_assert(digest); - if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) - return -1; - return 0; -} - -/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>, - * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result - * into <b>digest</b>. Return 0 on success, -1 on failure. */ -int -crypto_digest256(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm) -{ - tor_assert(m); - tor_assert(digest); - tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); - - int ret = 0; - if (algorithm == DIGEST_SHA256) - ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL); - else - ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) - > -1); - - if (!ret) - return -1; - return 0; -} - -/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>, - * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result - * into <b>digest</b>. Return 0 on success, -1 on failure. */ -int -crypto_digest512(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm) -{ - tor_assert(m); - tor_assert(digest); - tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); - - int ret = 0; - if (algorithm == DIGEST_SHA512) - ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest) - != NULL); - else - ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) - > -1); - - if (!ret) - return -1; - return 0; -} - -/** Set the common_digests_t in <b>ds_out</b> to contain every digest on the - * <b>len</b> bytes in <b>m</b> that we know how to compute. Return 0 on - * success, -1 on failure. */ -int -crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len) -{ - tor_assert(ds_out); - memset(ds_out, 0, sizeof(*ds_out)); - if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0) - return -1; - if (crypto_digest256(ds_out->d[DIGEST_SHA256], m, len, DIGEST_SHA256) < 0) - return -1; - - return 0; -} - -/** Return the name of an algorithm, as used in directory documents. */ -const char * -crypto_digest_algorithm_get_name(digest_algorithm_t alg) -{ - switch (alg) { - case DIGEST_SHA1: - return "sha1"; - case DIGEST_SHA256: - return "sha256"; - case DIGEST_SHA512: - return "sha512"; - case DIGEST_SHA3_256: - return "sha3-256"; - case DIGEST_SHA3_512: - return "sha3-512"; - // LCOV_EXCL_START - default: - tor_fragile_assert(); - return "??unknown_digest??"; - // LCOV_EXCL_STOP - } -} - -/** Given the name of a digest algorithm, return its integer value, or -1 if - * the name is not recognized. */ -int -crypto_digest_algorithm_parse_name(const char *name) -{ - if (!strcmp(name, "sha1")) - return DIGEST_SHA1; - else if (!strcmp(name, "sha256")) - return DIGEST_SHA256; - else if (!strcmp(name, "sha512")) - return DIGEST_SHA512; - else if (!strcmp(name, "sha3-256")) - return DIGEST_SHA3_256; - else if (!strcmp(name, "sha3-512")) - return DIGEST_SHA3_512; - else - return -1; -} - -/** Given an algorithm, return the digest length in bytes. */ -size_t -crypto_digest_algorithm_get_length(digest_algorithm_t alg) -{ - switch (alg) { - case DIGEST_SHA1: - return DIGEST_LEN; - case DIGEST_SHA256: - return DIGEST256_LEN; - case DIGEST_SHA512: - return DIGEST512_LEN; - case DIGEST_SHA3_256: - return DIGEST256_LEN; - case DIGEST_SHA3_512: - return DIGEST512_LEN; - default: - tor_assert(0); // LCOV_EXCL_LINE - return 0; /* Unreachable */ // LCOV_EXCL_LINE - } -} - -/** Intermediate information about the digest of a stream of data. */ -struct crypto_digest_t { - digest_algorithm_t algorithm; /**< Which algorithm is in use? */ - /** State for the digest we're using. Only one member of the - * union is usable, depending on the value of <b>algorithm</b>. Note also - * that space for other members might not even be allocated! - */ - union { - SHA_CTX sha1; /**< state for SHA1 */ - SHA256_CTX sha2; /**< state for SHA256 */ - SHA512_CTX sha512; /**< state for SHA512 */ - keccak_state sha3; /**< state for SHA3-[256,512] */ - } d; -}; - -#ifdef TOR_UNIT_TESTS - -digest_algorithm_t -crypto_digest_get_algorithm(crypto_digest_t *digest) -{ - tor_assert(digest); - - return digest->algorithm; -} - -#endif /* defined(TOR_UNIT_TESTS) */ - -/** - * Return the number of bytes we need to malloc in order to get a - * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe - * when we free one. - */ -static size_t -crypto_digest_alloc_bytes(digest_algorithm_t alg) -{ - /* Helper: returns the number of bytes in the 'f' field of 'st' */ -#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f )) - /* Gives the length of crypto_digest_t through the end of the field 'd' */ -#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \ - STRUCT_FIELD_SIZE(crypto_digest_t, f)) - switch (alg) { - case DIGEST_SHA1: - return END_OF_FIELD(d.sha1); - case DIGEST_SHA256: - return END_OF_FIELD(d.sha2); - case DIGEST_SHA512: - return END_OF_FIELD(d.sha512); - case DIGEST_SHA3_256: - case DIGEST_SHA3_512: - return END_OF_FIELD(d.sha3); - default: - tor_assert(0); // LCOV_EXCL_LINE - return 0; // LCOV_EXCL_LINE - } -#undef END_OF_FIELD -#undef STRUCT_FIELD_SIZE -} - -/** - * Internal function: create and return a new digest object for 'algorithm'. - * Does not typecheck the algorithm. - */ -static crypto_digest_t * -crypto_digest_new_internal(digest_algorithm_t algorithm) -{ - crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); - r->algorithm = algorithm; - - switch (algorithm) - { - case DIGEST_SHA1: - SHA1_Init(&r->d.sha1); - break; - case DIGEST_SHA256: - SHA256_Init(&r->d.sha2); - break; - case DIGEST_SHA512: - SHA512_Init(&r->d.sha512); - break; - case DIGEST_SHA3_256: - keccak_digest_init(&r->d.sha3, 256); - break; - case DIGEST_SHA3_512: - keccak_digest_init(&r->d.sha3, 512); - break; - default: - tor_assert_unreached(); - } - - return r; -} - -/** Allocate and return a new digest object to compute SHA1 digests. - */ -crypto_digest_t * -crypto_digest_new(void) -{ - return crypto_digest_new_internal(DIGEST_SHA1); -} - -/** Allocate and return a new digest object to compute 256-bit digests - * using <b>algorithm</b>. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new` - * C_RUST_COUPLED: `crypto::digest::Sha256::default` - */ -crypto_digest_t * -crypto_digest256_new(digest_algorithm_t algorithm) -{ - tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); - return crypto_digest_new_internal(algorithm); -} - -/** Allocate and return a new digest object to compute 512-bit digests - * using <b>algorithm</b>. */ -crypto_digest_t * -crypto_digest512_new(digest_algorithm_t algorithm) -{ - tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); - return crypto_digest_new_internal(algorithm); -} - -/** Deallocate a digest object. - */ -void -crypto_digest_free_(crypto_digest_t *digest) -{ - if (!digest) - return; - size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - memwipe(digest, 0, bytes); - tor_free(digest); -} - -/** Add <b>len</b> bytes from <b>data</b> to the digest object. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess` - * C_RUST_COUPLED: `crypto::digest::Sha256::process` - */ -void -crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, - size_t len) -{ - tor_assert(digest); - tor_assert(data); - /* Using the SHA*_*() calls directly means we don't support doing - * SHA in hardware. But so far the delay of getting the question - * to the hardware, and hearing the answer, is likely higher than - * just doing it ourselves. Hashes are fast. - */ - switch (digest->algorithm) { - case DIGEST_SHA1: - SHA1_Update(&digest->d.sha1, (void*)data, len); - break; - case DIGEST_SHA256: - SHA256_Update(&digest->d.sha2, (void*)data, len); - break; - case DIGEST_SHA512: - SHA512_Update(&digest->d.sha512, (void*)data, len); - break; - case DIGEST_SHA3_256: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: - keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len); - break; - default: - /* LCOV_EXCL_START */ - tor_fragile_assert(); - break; - /* LCOV_EXCL_STOP */ - } -} - -/** Compute the hash of the data that has been passed to the digest - * object; write the first out_len bytes of the result to <b>out</b>. - * <b>out_len</b> must be \<= DIGEST512_LEN. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest` - * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256` - */ -void -crypto_digest_get_digest(crypto_digest_t *digest, - char *out, size_t out_len) -{ - unsigned char r[DIGEST512_LEN]; - crypto_digest_t tmpenv; - tor_assert(digest); - tor_assert(out); - tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm)); - - /* The SHA-3 code handles copying into a temporary ctx, and also can handle - * short output buffers by truncating appropriately. */ - if (digest->algorithm == DIGEST_SHA3_256 || - digest->algorithm == DIGEST_SHA3_512) { - keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len); - return; - } - - const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); - /* memcpy into a temporary ctx, since SHA*_Final clears the context */ - memcpy(&tmpenv, digest, alloc_bytes); - switch (digest->algorithm) { - case DIGEST_SHA1: - SHA1_Final(r, &tmpenv.d.sha1); - break; - case DIGEST_SHA256: - SHA256_Final(r, &tmpenv.d.sha2); - break; - case DIGEST_SHA512: - SHA512_Final(r, &tmpenv.d.sha512); - break; -//LCOV_EXCL_START - case DIGEST_SHA3_256: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: - default: - log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm); - /* This is fatal, because it should never happen. */ - tor_assert_unreached(); - break; -//LCOV_EXCL_STOP - } - memcpy(out, r, out_len); - memwipe(r, 0, sizeof(r)); -} - -/** Allocate and return a new digest object with the same state as - * <b>digest</b> - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup` - * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256` - */ -crypto_digest_t * -crypto_digest_dup(const crypto_digest_t *digest) -{ - tor_assert(digest); - const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); - return tor_memdup(digest, alloc_bytes); -} - -/** Temporarily save the state of <b>digest</b> in <b>checkpoint</b>. - * Asserts that <b>digest</b> is a SHA1 digest object. - */ -void -crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, - const crypto_digest_t *digest) -{ - const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - tor_assert(bytes <= sizeof(checkpoint->mem)); - memcpy(checkpoint->mem, digest, bytes); -} - -/** Restore the state of <b>digest</b> from <b>checkpoint</b>. - * Asserts that <b>digest</b> is a SHA1 digest object. Requires that the - * state was previously stored with crypto_digest_checkpoint() */ -void -crypto_digest_restore(crypto_digest_t *digest, - const crypto_digest_checkpoint_t *checkpoint) -{ - const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - memcpy(digest, checkpoint->mem, bytes); -} - -/** Replace the state of the digest object <b>into</b> with the state - * of the digest object <b>from</b>. Requires that 'into' and 'from' - * have the same digest type. - */ -void -crypto_digest_assign(crypto_digest_t *into, - const crypto_digest_t *from) -{ - tor_assert(into); - tor_assert(from); - tor_assert(into->algorithm == from->algorithm); - const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm); - memcpy(into,from,alloc_bytes); -} - -/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest - * at <b>digest_out</b> to the hash of the concatenation of those strings, - * plus the optional string <b>append</b>, computed with the algorithm - * <b>alg</b>. - * <b>out_len</b> must be \<= DIGEST512_LEN. */ -void -crypto_digest_smartlist(char *digest_out, size_t len_out, - const smartlist_t *lst, - const char *append, - digest_algorithm_t alg) -{ - crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg); -} - -/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest - * at <b>digest_out</b> to the hash of the concatenation of: the - * optional string <b>prepend</b>, those strings, - * and the optional string <b>append</b>, computed with the algorithm - * <b>alg</b>. - * <b>len_out</b> must be \<= DIGEST512_LEN. */ -void -crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, - const char *prepend, - const smartlist_t *lst, - const char *append, - digest_algorithm_t alg) -{ - crypto_digest_t *d = crypto_digest_new_internal(alg); - if (prepend) - crypto_digest_add_bytes(d, prepend, strlen(prepend)); - SMARTLIST_FOREACH(lst, const char *, cp, - crypto_digest_add_bytes(d, cp, strlen(cp))); - if (append) - crypto_digest_add_bytes(d, append, strlen(append)); - crypto_digest_get_digest(d, digest_out, len_out); - crypto_digest_free(d); -} - -/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using - * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte - * result in <b>hmac_out</b>. Asserts on failure. - */ -void -crypto_hmac_sha256(char *hmac_out, - const char *key, size_t key_len, - const char *msg, size_t msg_len) -{ - unsigned char *rv = NULL; - /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ - tor_assert(key_len < INT_MAX); - tor_assert(msg_len < INT_MAX); - tor_assert(hmac_out); - rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, - (unsigned char*)hmac_out, NULL); - tor_assert(rv); -} - -/** Compute a MAC using SHA3-256 of <b>msg_len</b> bytes in <b>msg</b> using a - * <b>key</b> of length <b>key_len</b> and a <b>salt</b> of length - * <b>salt_len</b>. Store the result of <b>len_out</b> bytes in in - * <b>mac_out</b>. This function can't fail. */ -void -crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, - const uint8_t *key, size_t key_len, - const uint8_t *msg, size_t msg_len) -{ - crypto_digest_t *digest; - - const uint64_t key_len_netorder = tor_htonll(key_len); - - tor_assert(mac_out); - tor_assert(key); - tor_assert(msg); - - digest = crypto_digest256_new(DIGEST_SHA3_256); - - /* Order matters here that is any subsystem using this function should - * expect this very precise ordering in the MAC construction. */ - crypto_digest_add_bytes(digest, (const char *) &key_len_netorder, - sizeof(key_len_netorder)); - crypto_digest_add_bytes(digest, (const char *) key, key_len); - crypto_digest_add_bytes(digest, (const char *) msg, msg_len); - crypto_digest_get_digest(digest, (char *) mac_out, len_out); - crypto_digest_free(digest); -} - -/* xof functions */ - -/** Internal state for a eXtendable-Output Function (XOF). */ -struct crypto_xof_t { - keccak_state s; -}; - -/** Allocate a new XOF object backed by SHAKE-256. The security level - * provided is a function of the length of the output used. Read and - * understand FIPS-202 A.2 "Additional Consideration for Extendable-Output - * Functions" before using this construct. - */ -crypto_xof_t * -crypto_xof_new(void) -{ - crypto_xof_t *xof; - xof = tor_malloc(sizeof(crypto_xof_t)); - keccak_xof_init(&xof->s, 256); - return xof; -} - -/** Absorb bytes into a XOF object. Must not be called after a call to - * crypto_xof_squeeze_bytes() for the same instance, and will assert - * if attempted. - */ -void -crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len) -{ - int i = keccak_xof_absorb(&xof->s, data, len); - tor_assert(i == 0); -} - -/** Squeeze bytes out of a XOF object. Calling this routine will render - * the XOF instance ineligible to absorb further data. - */ -void -crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len) -{ - int i = keccak_xof_squeeze(&xof->s, out, len); - tor_assert(i == 0); -} - -/** Cleanse and deallocate a XOF object. */ -void -crypto_xof_free_(crypto_xof_t *xof) -{ - if (!xof) - return; - memwipe(xof, 0, sizeof(crypto_xof_t)); - tor_free(xof); -} - diff --git a/src/common/crypto_digest.h b/src/common/crypto_digest.h deleted file mode 100644 index 3bd74acdfa..0000000000 --- a/src/common/crypto_digest.h +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_digest.h - * - * \brief Headers for crypto_digest.c - **/ - -#ifndef TOR_CRYPTO_DIGEST_H -#define TOR_CRYPTO_DIGEST_H - -#include <stdio.h> - -#include "container.h" -#include "torint.h" - -/** Length of the output of our message digest. */ -#define DIGEST_LEN 20 -/** Length of the output of our second (improved) message digests. (For now - * this is just sha256, but it could be any other 256-bit digest.) */ -#define DIGEST256_LEN 32 -/** Length of the output of our 64-bit optimized message digests (SHA512). */ -#define DIGEST512_LEN 64 - -/** Length of a sha1 message digest when encoded in base32 with trailing = - * signs removed. */ -#define BASE32_DIGEST_LEN 32 -/** Length of a sha1 message digest when encoded in base64 with trailing = - * signs removed. */ -#define BASE64_DIGEST_LEN 27 -/** Length of a sha256 message digest when encoded in base64 with trailing = - * signs removed. */ -#define BASE64_DIGEST256_LEN 43 -/** Length of a sha512 message digest when encoded in base64 with trailing = - * signs removed. */ -#define BASE64_DIGEST512_LEN 86 - -/** Length of hex encoding of SHA1 digest, not including final NUL. */ -#define HEX_DIGEST_LEN 40 -/** Length of hex encoding of SHA256 digest, not including final NUL. */ -#define HEX_DIGEST256_LEN 64 -/** Length of hex encoding of SHA512 digest, not including final NUL. */ -#define HEX_DIGEST512_LEN 128 - -typedef enum { - DIGEST_SHA1 = 0, - DIGEST_SHA256 = 1, - DIGEST_SHA512 = 2, - DIGEST_SHA3_256 = 3, - DIGEST_SHA3_512 = 4, -} digest_algorithm_t; -#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+1) -#define N_COMMON_DIGEST_ALGORITHMS (DIGEST_SHA256+1) - -#define DIGEST_CHECKPOINT_BYTES (SIZEOF_VOID_P + 512) -/** Structure used to temporarily save the a digest object. Only implemented - * for SHA1 digest for now. */ -typedef struct crypto_digest_checkpoint_t { - uint8_t mem[DIGEST_CHECKPOINT_BYTES]; -} crypto_digest_checkpoint_t; - -/** A set of all the digests we commonly compute, taken on a single - * string. Any digests that are shorter than 512 bits are right-padded - * with 0 bits. - * - * Note that this representation wastes 44 bytes for the SHA1 case, so - * don't use it for anything where we need to allocate a whole bunch at - * once. - **/ -typedef struct { - char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN]; -} common_digests_t; - -typedef struct crypto_digest_t crypto_digest_t; -typedef struct crypto_xof_t crypto_xof_t; - -/* SHA-1 and other digests */ -int crypto_digest(char *digest, const char *m, size_t len); -int crypto_digest256(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm); -int crypto_digest512(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm); -int crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len); -void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, - const char *prepend, - const struct smartlist_t *lst, - const char *append, - digest_algorithm_t alg); -void crypto_digest_smartlist(char *digest_out, size_t len_out, - const struct smartlist_t *lst, const char *append, - digest_algorithm_t alg); -const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg); -size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg); -int crypto_digest_algorithm_parse_name(const char *name); -crypto_digest_t *crypto_digest_new(void); -crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm); -crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm); -void crypto_digest_free_(crypto_digest_t *digest); -#define crypto_digest_free(d) \ - FREE_AND_NULL(crypto_digest_t, crypto_digest_free_, (d)) -void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, - size_t len); -void crypto_digest_get_digest(crypto_digest_t *digest, - char *out, size_t out_len); -crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest); -void crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, - const crypto_digest_t *digest); -void crypto_digest_restore(crypto_digest_t *digest, - const crypto_digest_checkpoint_t *checkpoint); -void crypto_digest_assign(crypto_digest_t *into, - const crypto_digest_t *from); -void crypto_hmac_sha256(char *hmac_out, - const char *key, size_t key_len, - const char *msg, size_t msg_len); -void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, - const uint8_t *key, size_t key_len, - const uint8_t *msg, size_t msg_len); - -/* xof functions*/ -crypto_xof_t *crypto_xof_new(void); -void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len); -void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len); -void crypto_xof_free_(crypto_xof_t *xof); -#define crypto_xof_free(xof) \ - FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof)) - -#ifdef TOR_UNIT_TESTS -digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest); -#endif - -#endif /* !defined(TOR_CRYPTO_DIGEST_H) */ - diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c deleted file mode 100644 index 9c13e3bdf0..0000000000 --- a/src/common/crypto_ed25519.c +++ /dev/null @@ -1,817 +0,0 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_ed25519.c - * - * \brief Wrapper code for an ed25519 implementation. - * - * Ed25519 is a Schnorr signature on a Twisted Edwards curve, defined - * by Dan Bernstein. For more information, see https://ed25519.cr.yp.to/ - * - * This module wraps our choice of Ed25519 backend, and provides a few - * convenience functions for checking and generating signatures. It also - * provides Tor-specific tools for key blinding and for converting Ed25519 - * keys to and from the corresponding Curve25519 keys. - */ - -#define CRYPTO_ED25519_PRIVATE -#include "orconfig.h" -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif - -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_ed25519.h" -#include "crypto_format.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" - -#include "ed25519/ref10/ed25519_ref10.h" -#include "ed25519/donna/ed25519_donna_tor.h" - -static void pick_ed25519_impl(void); - -/** An Ed25519 implementation, as a set of function pointers. */ -typedef struct { - int (*selftest)(void); - - int (*seckey)(unsigned char *); - int (*seckey_expand)(unsigned char *, const unsigned char *); - int (*pubkey)(unsigned char *, const unsigned char *); - int (*keygen)(unsigned char *, unsigned char *); - - int (*open)(const unsigned char *, const unsigned char *, size_t, const - unsigned char *); - int (*sign)(unsigned char *, const unsigned char *, size_t, - const unsigned char *, const unsigned char *); - int (*open_batch)(const unsigned char **, size_t *, const unsigned char **, - const unsigned char **, size_t, int *); - - int (*blind_secret_key)(unsigned char *, const unsigned char *, - const unsigned char *); - int (*blind_public_key)(unsigned char *, const unsigned char *, - const unsigned char *); - - int (*pubkey_from_curve25519_pubkey)(unsigned char *, const unsigned char *, - int); - - int (*ed25519_scalarmult_with_group_order)(unsigned char *, - const unsigned char *); -} ed25519_impl_t; - -/** The Ref10 Ed25519 implementation. This one is pure C and lightly - * optimized. */ -static const ed25519_impl_t impl_ref10 = { - NULL, - - ed25519_ref10_seckey, - ed25519_ref10_seckey_expand, - ed25519_ref10_pubkey, - ed25519_ref10_keygen, - - ed25519_ref10_open, - ed25519_ref10_sign, - NULL, - - ed25519_ref10_blind_secret_key, - ed25519_ref10_blind_public_key, - - ed25519_ref10_pubkey_from_curve25519_pubkey, - ed25519_ref10_scalarmult_with_group_order, -}; - -/** The Ref10 Ed25519 implementation. This one is heavily optimized, but still - * mostly C. The C still tends to be heavily platform-specific. */ -static const ed25519_impl_t impl_donna = { - ed25519_donna_selftest, - - ed25519_donna_seckey, - ed25519_donna_seckey_expand, - ed25519_donna_pubkey, - ed25519_donna_keygen, - - ed25519_donna_open, - ed25519_donna_sign, - ed25519_sign_open_batch_donna, - - ed25519_donna_blind_secret_key, - ed25519_donna_blind_public_key, - - ed25519_donna_pubkey_from_curve25519_pubkey, - ed25519_donna_scalarmult_with_group_order, -}; - -/** Which Ed25519 implementation are we using? NULL if we haven't decided - * yet. */ -static const ed25519_impl_t *ed25519_impl = NULL; - -/** Helper: Return our chosen Ed25519 implementation. - * - * This should only be called after we've picked an implementation, but - * it _does_ recover if you forget this. - **/ -static inline const ed25519_impl_t * -get_ed_impl(void) -{ - if (BUG(ed25519_impl == NULL)) { - pick_ed25519_impl(); // LCOV_EXCL_LINE - We always call ed25519_init(). - } - return ed25519_impl; -} - -#ifdef TOR_UNIT_TESTS -/** For testing: used to remember our actual choice of Ed25519 - * implementation */ -static const ed25519_impl_t *saved_ed25519_impl = NULL; -/** For testing: Use the Ed25519 implementation called <b>name</b> until - * crypto_ed25519_testing_restore_impl is called. Recognized names are - * "donna" and "ref10". */ -void -crypto_ed25519_testing_force_impl(const char *name) -{ - tor_assert(saved_ed25519_impl == NULL); - saved_ed25519_impl = ed25519_impl; - if (! strcmp(name, "donna")) { - ed25519_impl = &impl_donna; - } else { - tor_assert(!strcmp(name, "ref10")); - ed25519_impl = &impl_ref10; - } -} -/** For testing: go back to whatever Ed25519 implementation we had picked - * before crypto_ed25519_testing_force_impl was called. - */ -void -crypto_ed25519_testing_restore_impl(void) -{ - ed25519_impl = saved_ed25519_impl; - saved_ed25519_impl = NULL; -} -#endif /* defined(TOR_UNIT_TESTS) */ - -/** - * Initialize a new ed25519 secret key in <b>seckey_out</b>. If - * <b>extra_strong</b>, take the RNG inputs directly from the operating - * system. Return 0 on success, -1 on failure. - */ -int -ed25519_secret_key_generate(ed25519_secret_key_t *seckey_out, - int extra_strong) -{ - int r; - uint8_t seed[32]; - if (extra_strong) - crypto_strongest_rand(seed, sizeof(seed)); - else - crypto_rand((char*)seed, sizeof(seed)); - - r = get_ed_impl()->seckey_expand(seckey_out->seckey, seed); - memwipe(seed, 0, sizeof(seed)); - - return r < 0 ? -1 : 0; -} - -/** - * Given a 32-byte random seed in <b>seed</b>, expand it into an ed25519 - * secret key in <b>seckey_out</b>. Return 0 on success, -1 on failure. - */ -int -ed25519_secret_key_from_seed(ed25519_secret_key_t *seckey_out, - const uint8_t *seed) -{ - if (get_ed_impl()->seckey_expand(seckey_out->seckey, seed) < 0) - return -1; - return 0; -} - -/** - * Given a secret key in <b>seckey</b>, expand it into an - * ed25519 public key. Return 0 on success, -1 on failure. - */ -int -ed25519_public_key_generate(ed25519_public_key_t *pubkey_out, - const ed25519_secret_key_t *seckey) -{ - if (get_ed_impl()->pubkey(pubkey_out->pubkey, seckey->seckey) < 0) - return -1; - return 0; -} - -/** Generate a new ed25519 keypair in <b>keypair_out</b>. If - * <b>extra_strong</b> is set, try to mix some system entropy into the key - * generation process. Return 0 on success, -1 on failure. */ -int -ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong) -{ - if (ed25519_secret_key_generate(&keypair_out->seckey, extra_strong) < 0) - return -1; - if (ed25519_public_key_generate(&keypair_out->pubkey, - &keypair_out->seckey)<0) - return -1; - return 0; -} - -/** Return true iff 'pubkey' is set to zero (eg to indicate that it is not - * set). */ -int -ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey) -{ - return tor_mem_is_zero((char*)pubkey->pubkey, ED25519_PUBKEY_LEN); -} - -/* Return a heap-allocated array that contains <b>msg</b> prefixed by the - * string <b>prefix_str</b>. Set <b>final_msg_len_out</b> to the size of the - * final array. If an error occurred, return NULL. It's the responsibility of - * the caller to free the returned array. */ -static uint8_t * -get_prefixed_msg(const uint8_t *msg, size_t msg_len, - const char *prefix_str, - size_t *final_msg_len_out) -{ - size_t prefixed_msg_len, prefix_len; - uint8_t *prefixed_msg; - - tor_assert(prefix_str); - tor_assert(final_msg_len_out); - - prefix_len = strlen(prefix_str); - - /* msg_len + strlen(prefix_str) must not overflow. */ - if (msg_len > SIZE_T_CEILING - prefix_len) { - return NULL; - } - - prefixed_msg_len = msg_len + prefix_len; - prefixed_msg = tor_malloc_zero(prefixed_msg_len); - - memcpy(prefixed_msg, prefix_str, prefix_len); - memcpy(prefixed_msg + prefix_len, msg, msg_len); - - *final_msg_len_out = prefixed_msg_len; - return prefixed_msg; -} - -/** - * Set <b>signature_out</b> to a signature of the <b>len</b>-byte message - * <b>msg</b>, using the secret and public key in <b>keypair</b>. - * - * Return 0 if we successfully signed the message, otherwise return -1. - */ -int -ed25519_sign(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t len, - const ed25519_keypair_t *keypair) -{ - if (get_ed_impl()->sign(signature_out->sig, msg, len, - keypair->seckey.seckey, - keypair->pubkey.pubkey) < 0) { - return -1; - } - - return 0; -} - -/** - * Like ed25519_sign(), but also prefix <b>msg</b> with <b>prefix_str</b> - * before signing. <b>prefix_str</b> must be a NUL-terminated string. - */ -MOCK_IMPL(int, -ed25519_sign_prefixed,(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t msg_len, - const char *prefix_str, - const ed25519_keypair_t *keypair)) -{ - int retval; - size_t prefixed_msg_len; - uint8_t *prefixed_msg; - - tor_assert(prefix_str); - - prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str, - &prefixed_msg_len); - if (BUG(!prefixed_msg)) { - /* LCOV_EXCL_START -- only possible when the message and prefix are - * ridiculously huge */ - log_warn(LD_GENERAL, "Failed to get prefixed msg."); - return -1; - /* LCOV_EXCL_STOP */ - } - - retval = ed25519_sign(signature_out, - prefixed_msg, prefixed_msg_len, - keypair); - tor_free(prefixed_msg); - - return retval; -} - -/** - * Check whether if <b>signature</b> is a valid signature for the - * <b>len</b>-byte message in <b>msg</b> made with the key <b>pubkey</b>. - * - * Return 0 if the signature is valid; -1 if it isn't. - */ -MOCK_IMPL(int, -ed25519_checksig,(const ed25519_signature_t *signature, - const uint8_t *msg, size_t len, - const ed25519_public_key_t *pubkey)) -{ - return - get_ed_impl()->open(signature->sig, msg, len, pubkey->pubkey) < 0 ? -1 : 0; -} - -/** - * Like ed2519_checksig(), but also prefix <b>msg</b> with <b>prefix_str</b> - * before verifying signature. <b>prefix_str</b> must be a NUL-terminated - * string. - */ -int -ed25519_checksig_prefixed(const ed25519_signature_t *signature, - const uint8_t *msg, size_t msg_len, - const char *prefix_str, - const ed25519_public_key_t *pubkey) -{ - int retval; - size_t prefixed_msg_len; - uint8_t *prefixed_msg; - - prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str, - &prefixed_msg_len); - if (BUG(!prefixed_msg)) { - /* LCOV_EXCL_START -- only possible when the message and prefix are - * ridiculously huge */ - log_warn(LD_GENERAL, "Failed to get prefixed msg."); - return -1; - /* LCOV_EXCL_STOP */ - } - - retval = ed25519_checksig(signature, - prefixed_msg, prefixed_msg_len, - pubkey); - tor_free(prefixed_msg); - - return retval; -} - -/** Validate every signature among those in <b>checkable</b>, which contains - * exactly <b>n_checkable</b> elements. If <b>okay_out</b> is non-NULL, set - * the i'th element of <b>okay_out</b> to 1 if the i'th element of - * <b>checkable</b> is valid, and to 0 otherwise. Return 0 if every signature - * was valid. Otherwise return -N, where N is the number of invalid - * signatures. - */ -MOCK_IMPL(int, -ed25519_checksig_batch,(int *okay_out, - const ed25519_checkable_t *checkable, - int n_checkable)) -{ - int i, res; - const ed25519_impl_t *impl = get_ed_impl(); - - if (impl->open_batch == NULL) { - /* No batch verification implementation available, fake it by checking the - * each signature individually. - */ - res = 0; - for (i = 0; i < n_checkable; ++i) { - const ed25519_checkable_t *ch = &checkable[i]; - int r = ed25519_checksig(&ch->signature, ch->msg, ch->len, ch->pubkey); - if (r < 0) - --res; - if (okay_out) - okay_out[i] = (r == 0); - } - } else { - /* ed25519-donna style batch verification available. - * - * Theoretically, this should only be called if n_checkable >= 3, since - * that's the threshold where the batch verification actually kicks in, - * but the only difference is a few mallocs/frees. - */ - const uint8_t **ms; - size_t *lens; - const uint8_t **pks; - const uint8_t **sigs; - int *oks; - int all_ok; - - ms = tor_calloc(n_checkable, sizeof(uint8_t*)); - lens = tor_calloc(n_checkable, sizeof(size_t)); - pks = tor_calloc(n_checkable, sizeof(uint8_t*)); - sigs = tor_calloc(n_checkable, sizeof(uint8_t*)); - oks = okay_out ? okay_out : tor_calloc(n_checkable, sizeof(int)); - - for (i = 0; i < n_checkable; ++i) { - ms[i] = checkable[i].msg; - lens[i] = checkable[i].len; - pks[i] = checkable[i].pubkey->pubkey; - sigs[i] = checkable[i].signature.sig; - oks[i] = 0; - } - - res = 0; - all_ok = impl->open_batch(ms, lens, pks, sigs, n_checkable, oks); - for (i = 0; i < n_checkable; ++i) { - if (!oks[i]) - --res; - } - /* XXX: For now sanity check oks with the return value. Once we have - * more confidence in the code, if `all_ok == 0` we can skip iterating - * over oks since all the signatures were found to be valid. - */ - tor_assert(((res == 0) && !all_ok) || ((res < 0) && all_ok)); - - tor_free(ms); - tor_free(lens); - tor_free(pks); - tor_free(sigs); - if (! okay_out) - tor_free(oks); - } - - return res; -} - -/** - * Given a curve25519 keypair in <b>inp</b>, generate a corresponding - * ed25519 keypair in <b>out</b>, and set <b>signbit_out</b> to the - * sign bit of the X coordinate of the ed25519 key. - * - * NOTE THAT IT IS PROBABLY NOT SAFE TO USE THE GENERATED KEY FOR ANYTHING - * OUTSIDE OF WHAT'S PRESENTED IN PROPOSAL 228. In particular, it's probably - * not a great idea to use it to sign attacker-supplied anything. - */ -int -ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out, - int *signbit_out, - const curve25519_keypair_t *inp) -{ - const char string[] = "Derive high part of ed25519 key from curve25519 key"; - ed25519_public_key_t pubkey_check; - crypto_digest_t *ctx; - uint8_t sha512_output[DIGEST512_LEN]; - - memcpy(out->seckey.seckey, inp->seckey.secret_key, 32); - - ctx = crypto_digest512_new(DIGEST_SHA512); - crypto_digest_add_bytes(ctx, (const char*)out->seckey.seckey, 32); - crypto_digest_add_bytes(ctx, (const char*)string, sizeof(string)); - crypto_digest_get_digest(ctx, (char *)sha512_output, sizeof(sha512_output)); - crypto_digest_free(ctx); - memcpy(out->seckey.seckey + 32, sha512_output, 32); - - ed25519_public_key_generate(&out->pubkey, &out->seckey); - - *signbit_out = out->pubkey.pubkey[31] >> 7; - - ed25519_public_key_from_curve25519_public_key(&pubkey_check, &inp->pubkey, - *signbit_out); - - tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32)); - - memwipe(&pubkey_check, 0, sizeof(pubkey_check)); - memwipe(sha512_output, 0, sizeof(sha512_output)); - - return 0; -} - -/** - * Given a curve25519 public key and sign bit of X coordinate of the ed25519 - * public key, generate the corresponding ed25519 public key. - */ -int -ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey, - const curve25519_public_key_t *pubkey_in, - int signbit) -{ - return get_ed_impl()->pubkey_from_curve25519_pubkey(pubkey->pubkey, - pubkey_in->public_key, - signbit); -} - -/** - * Given an ed25519 keypair in <b>inp</b>, generate a corresponding - * ed25519 keypair in <b>out</b>, blinded by the corresponding 32-byte input - * in 'param'. - * - * Tor uses key blinding for the "next-generation" hidden services design: - * service descriptors are encrypted with a key derived from the service's - * long-term public key, and then signed with (and stored at a position - * indexed by) a short-term key derived by blinding the long-term keys. - * - * Return 0 if blinding was successful, else return -1. */ -int -ed25519_keypair_blind(ed25519_keypair_t *out, - const ed25519_keypair_t *inp, - const uint8_t *param) -{ - ed25519_public_key_t pubkey_check; - - get_ed_impl()->blind_secret_key(out->seckey.seckey, - inp->seckey.seckey, param); - - if (ed25519_public_blind(&pubkey_check, &inp->pubkey, param) < 0) { - return -1; - } - ed25519_public_key_generate(&out->pubkey, &out->seckey); - - tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32)); - - memwipe(&pubkey_check, 0, sizeof(pubkey_check)); - - return 0; -} - -/** - * Given an ed25519 public key in <b>inp</b>, generate a corresponding blinded - * public key in <b>out</b>, blinded with the 32-byte parameter in - * <b>param</b>. Return 0 on success, -1 on railure. - */ -int -ed25519_public_blind(ed25519_public_key_t *out, - const ed25519_public_key_t *inp, - const uint8_t *param) -{ - return get_ed_impl()->blind_public_key(out->pubkey, inp->pubkey, param); -} - -/** - * Store seckey unencrypted to <b>filename</b>, marking it with <b>tag</b>. - * Return 0 on success, -1 on failure. - */ -int -ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey, - const char *filename, - const char *tag) -{ - return crypto_write_tagged_contents_to_file(filename, - "ed25519v1-secret", - tag, - seckey->seckey, - sizeof(seckey->seckey)); -} - -/** - * Read seckey unencrypted from <b>filename</b>, storing it into - * <b>seckey_out</b>. Set *<b>tag_out</b> to the tag it was marked with. - * Return 0 on success, -1 on failure. - */ -int -ed25519_seckey_read_from_file(ed25519_secret_key_t *seckey_out, - char **tag_out, - const char *filename) -{ - ssize_t len; - - len = crypto_read_tagged_contents_from_file(filename, "ed25519v1-secret", - tag_out, seckey_out->seckey, - sizeof(seckey_out->seckey)); - if (len == sizeof(seckey_out->seckey)) { - return 0; - } else if (len >= 0) { - errno = EINVAL; - } - - tor_free(*tag_out); - return -1; -} - -/** - * Store pubkey unencrypted to <b>filename</b>, marking it with <b>tag</b>. - * Return 0 on success, -1 on failure. - */ -int -ed25519_pubkey_write_to_file(const ed25519_public_key_t *pubkey, - const char *filename, - const char *tag) -{ - return crypto_write_tagged_contents_to_file(filename, - "ed25519v1-public", - tag, - pubkey->pubkey, - sizeof(pubkey->pubkey)); -} - -/** - * Store pubkey unencrypted to <b>filename</b>, marking it with <b>tag</b>. - * Return 0 on success, -1 on failure. - */ -int -ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out, - char **tag_out, - const char *filename) -{ - ssize_t len; - - len = crypto_read_tagged_contents_from_file(filename, "ed25519v1-public", - tag_out, pubkey_out->pubkey, - sizeof(pubkey_out->pubkey)); - if (len == sizeof(pubkey_out->pubkey)) { - return 0; - } else if (len >= 0) { - errno = EINVAL; - } - - tor_free(*tag_out); - return -1; -} - -/** Release all storage held for <b>kp</b>. */ -void -ed25519_keypair_free_(ed25519_keypair_t *kp) -{ - if (! kp) - return; - - memwipe(kp, 0, sizeof(*kp)); - tor_free(kp); -} - -/** Return true iff <b>key1</b> and <b>key2</b> are the same public key. */ -int -ed25519_pubkey_eq(const ed25519_public_key_t *key1, - const ed25519_public_key_t *key2) -{ - tor_assert(key1); - tor_assert(key2); - return tor_memeq(key1->pubkey, key2->pubkey, ED25519_PUBKEY_LEN); -} - -/** - * Set <b>dest</b> to contain the same key as <b>src</b>. - */ -void -ed25519_pubkey_copy(ed25519_public_key_t *dest, - const ed25519_public_key_t *src) -{ - tor_assert(dest); - tor_assert(src); - memcpy(dest, src, sizeof(ed25519_public_key_t)); -} - -/** Check whether the given Ed25519 implementation seems to be working. - * If so, return 0; otherwise return -1. */ -MOCK_IMPL(STATIC int, -ed25519_impl_spot_check,(void)) -{ - static const uint8_t alicesk[32] = { - 0xc5,0xaa,0x8d,0xf4,0x3f,0x9f,0x83,0x7b, - 0xed,0xb7,0x44,0x2f,0x31,0xdc,0xb7,0xb1, - 0x66,0xd3,0x85,0x35,0x07,0x6f,0x09,0x4b, - 0x85,0xce,0x3a,0x2e,0x0b,0x44,0x58,0xf7 - }; - static const uint8_t alicepk[32] = { - 0xfc,0x51,0xcd,0x8e,0x62,0x18,0xa1,0xa3, - 0x8d,0xa4,0x7e,0xd0,0x02,0x30,0xf0,0x58, - 0x08,0x16,0xed,0x13,0xba,0x33,0x03,0xac, - 0x5d,0xeb,0x91,0x15,0x48,0x90,0x80,0x25 - }; - static const uint8_t alicemsg[2] = { 0xaf, 0x82 }; - static const uint8_t alicesig[64] = { - 0x62,0x91,0xd6,0x57,0xde,0xec,0x24,0x02, - 0x48,0x27,0xe6,0x9c,0x3a,0xbe,0x01,0xa3, - 0x0c,0xe5,0x48,0xa2,0x84,0x74,0x3a,0x44, - 0x5e,0x36,0x80,0xd7,0xdb,0x5a,0xc3,0xac, - 0x18,0xff,0x9b,0x53,0x8d,0x16,0xf2,0x90, - 0xae,0x67,0xf7,0x60,0x98,0x4d,0xc6,0x59, - 0x4a,0x7c,0x15,0xe9,0x71,0x6e,0xd2,0x8d, - 0xc0,0x27,0xbe,0xce,0xea,0x1e,0xc4,0x0a - }; - const ed25519_impl_t *impl = get_ed_impl(); - uint8_t sk[ED25519_SECKEY_LEN]; - uint8_t pk[ED25519_PUBKEY_LEN]; - uint8_t sig[ED25519_SIG_LEN]; - int r = 0; - - /* Some implementations (eg: The modified Ed25519-donna) have handy self-test - * code that sanity-checks the internals. If present, use that to screen out - * catastrophic errors like massive compiler failure. - */ - if (impl->selftest && impl->selftest() != 0) - goto fail; - - /* Validate results versus known answer tests. People really should be - * running "make test" instead of relying on this, but it's better than - * nothing. - * - * Test vectors taken from "EdDSA & Ed25519 - 6. Test Vectors for Ed25519 - * (TEST3)" (draft-josefsson-eddsa-ed25519-03). - */ - - /* Key expansion, public key derivation. */ - if (impl->seckey_expand(sk, alicesk) < 0) - goto fail; - if (impl->pubkey(pk, sk) < 0) - goto fail; - if (fast_memneq(pk, alicepk, ED25519_PUBKEY_LEN)) - goto fail; - - /* Signing, verification. */ - if (impl->sign(sig, alicemsg, sizeof(alicemsg), sk, pk) < 0) - return -1; - if (fast_memneq(sig, alicesig, ED25519_SIG_LEN)) - return -1; - if (impl->open(sig, alicemsg, sizeof(alicemsg), pk) < 0) - return -1; - - /* XXX/yawning: Someone that's more paranoid than I am, can write "Assume - * ref0 is canonical, and fuzz impl against it" if they want, but I doubt - * that will catch anything that the known answer tests won't. - */ - goto end; - - // LCOV_EXCL_START -- We can only reach this if our ed25519 implementation is - // broken. - fail: - r = -1; - // LCOV_EXCL_STOP - end: - return r; -} - -/** Force the Ed25519 implementation to a given one, without sanity checking - * the output. Used for testing. - */ -void -ed25519_set_impl_params(int use_donna) -{ - if (use_donna) - ed25519_impl = &impl_donna; - else - ed25519_impl = &impl_ref10; -} - -/** Choose whether to use the Ed25519-donna implementation. */ -static void -pick_ed25519_impl(void) -{ - ed25519_impl = &impl_donna; - - if (ed25519_impl_spot_check() == 0) - return; - - /* LCOV_EXCL_START - * unreachable unless ed25519_donna is broken */ - log_warn(LD_CRYPTO, "The Ed25519-donna implementation seems broken; using " - "the ref10 implementation."); - ed25519_impl = &impl_ref10; - /* LCOV_EXCL_STOP */ -} - -/* Initialize the Ed25519 implementation. This is necessary if you're - * going to use them in a multithreaded setting, and not otherwise. */ -void -ed25519_init(void) -{ - pick_ed25519_impl(); -} - -/* Return true if <b>point</b> is the identity element of the ed25519 group. */ -static int -ed25519_point_is_identity_element(const uint8_t *point) -{ - /* The identity element in ed25159 is the point with coordinates (0,1). */ - static const uint8_t ed25519_identity[32] = { - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - tor_assert(sizeof(ed25519_identity) == ED25519_PUBKEY_LEN); - return tor_memeq(point, ed25519_identity, sizeof(ed25519_identity)); -} - -/** Validate <b>pubkey</b> to ensure that it has no torsion component. - * Return 0 if <b>pubkey</b> is valid, else return -1. */ -int -ed25519_validate_pubkey(const ed25519_public_key_t *pubkey) -{ - uint8_t result[32] = {9}; - - /* First check that we were not given the identity element */ - if (ed25519_point_is_identity_element(pubkey->pubkey)) { - log_warn(LD_CRYPTO, "ed25519 pubkey is the identity"); - return -1; - } - - /* For any point on the curve, doing l*point should give the identity element - * (where l is the group order). Do the computation and check that the - * identity element is returned. */ - if (get_ed_impl()->ed25519_scalarmult_with_group_order(result, - pubkey->pubkey) < 0) { - log_warn(LD_CRYPTO, "ed25519 group order scalarmult failed"); - return -1; - } - - if (!ed25519_point_is_identity_element(result)) { - log_warn(LD_CRYPTO, "ed25519 validation failed"); - return -1; - } - - return 0; -} - diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h deleted file mode 100644 index 74269ccffd..0000000000 --- a/src/common/crypto_ed25519.h +++ /dev/null @@ -1,145 +0,0 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CRYPTO_ED25519_H -#define TOR_CRYPTO_ED25519_H - -#include "testsupport.h" -#include "torint.h" -#include "crypto_curve25519.h" -#include "util.h" - -#define ED25519_PUBKEY_LEN 32 -#define ED25519_SECKEY_LEN 64 -#define ED25519_SECKEY_SEED_LEN 32 -#define ED25519_SIG_LEN 64 - -/** An Ed25519 signature. */ -typedef struct { - uint8_t sig[ED25519_SIG_LEN]; -} ed25519_signature_t; - -/** An Ed25519 public key */ -typedef struct { - uint8_t pubkey[ED25519_PUBKEY_LEN]; -} ed25519_public_key_t; - -/** An Ed25519 secret key */ -typedef struct { - /** Note that we store secret keys in an expanded format that doesn't match - * the format from standard ed25519. Ed25519 stores a 32-byte value k and - * expands it into a 64-byte H(k), using the first 32 bytes for a multiplier - * of the base point, and second 32 bytes as an input to a hash function - * for deriving r. But because we implement key blinding, we need to store - * keys in the 64-byte expanded form. */ - uint8_t seckey[ED25519_SECKEY_LEN]; -} ed25519_secret_key_t; - -/** An Ed25519 keypair. */ -typedef struct { - ed25519_public_key_t pubkey; - ed25519_secret_key_t seckey; -} ed25519_keypair_t; - -int ed25519_secret_key_generate(ed25519_secret_key_t *seckey_out, - int extra_strong); -int ed25519_secret_key_from_seed(ed25519_secret_key_t *seckey_out, - const uint8_t *seed); - -int ed25519_public_key_generate(ed25519_public_key_t *pubkey_out, - const ed25519_secret_key_t *seckey); -int ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong); -int ed25519_sign(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t len, - const ed25519_keypair_t *key); -MOCK_DECL(int,ed25519_checksig,(const ed25519_signature_t *signature, - const uint8_t *msg, size_t len, - const ed25519_public_key_t *pubkey)); - -MOCK_DECL(int, -ed25519_sign_prefixed,(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t len, - const char *prefix_str, - const ed25519_keypair_t *keypair)); - -int -ed25519_checksig_prefixed(const ed25519_signature_t *signature, - const uint8_t *msg, size_t len, - const char *prefix_str, - const ed25519_public_key_t *pubkey); - -int ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey); - -/** - * A collection of information necessary to check an Ed25519 signature. Used - * for batch verification. - */ -typedef struct { - /** The public key that supposedly generated the signature. */ - const ed25519_public_key_t *pubkey; - /** The signature to check. */ - ed25519_signature_t signature; - /** The message that the signature is supposed to have been applied to. */ - const uint8_t *msg; - /** The length of the message. */ - size_t len; -} ed25519_checkable_t; - -MOCK_DECL(int, ed25519_checksig_batch,(int *okay_out, - const ed25519_checkable_t *checkable, - int n_checkable)); - -int ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out, - int *signbit_out, - const curve25519_keypair_t *inp); - -int ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey, - const curve25519_public_key_t *pubkey_in, - int signbit); -int ed25519_keypair_blind(ed25519_keypair_t *out, - const ed25519_keypair_t *inp, - const uint8_t *param); -int ed25519_public_blind(ed25519_public_key_t *out, - const ed25519_public_key_t *inp, - const uint8_t *param); - -/* XXXX read encrypted, write encrypted. */ - -int ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey, - const char *filename, - const char *tag); -int ed25519_seckey_read_from_file(ed25519_secret_key_t *seckey_out, - char **tag_out, - const char *filename); -int ed25519_pubkey_write_to_file(const ed25519_public_key_t *pubkey, - const char *filename, - const char *tag); -int ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out, - char **tag_out, - const char *filename); - -void ed25519_keypair_free_(ed25519_keypair_t *kp); -#define ed25519_keypair_free(kp) \ - FREE_AND_NULL(ed25519_keypair_t, ed25519_keypair_free_, (kp)) - -int ed25519_pubkey_eq(const ed25519_public_key_t *key1, - const ed25519_public_key_t *key2); -void ed25519_pubkey_copy(ed25519_public_key_t *dest, - const ed25519_public_key_t *src); - -void ed25519_set_impl_params(int use_donna); -void ed25519_init(void); - -int ed25519_validate_pubkey(const ed25519_public_key_t *pubkey); - -#ifdef TOR_UNIT_TESTS -void crypto_ed25519_testing_force_impl(const char *name); -void crypto_ed25519_testing_restore_impl(void); -#endif - -#ifdef CRYPTO_ED25519_PRIVATE -MOCK_DECL(STATIC int, ed25519_impl_spot_check, (void)); -#endif - -#endif /* !defined(TOR_CRYPTO_ED25519_H) */ - diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c deleted file mode 100644 index 460e85bac1..0000000000 --- a/src/common/crypto_format.c +++ /dev/null @@ -1,299 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_format.c - * - * \brief Formatting and parsing code for crypto-related data structures. - */ - -#include "orconfig.h" -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#include "container.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_ed25519.h" -#include "crypto_format.h" -#include "crypto_util.h" -#include "util.h" -#include "util_format.h" -#include "torlog.h" - -/** Write the <b>datalen</b> bytes from <b>data</b> to the file named - * <b>fname</b> in the tagged-data format. This format contains a - * 32-byte header, followed by the data itself. The header is the - * NUL-padded string "== <b>typestring</b>: <b>tag</b> ==". The length - * of <b>typestring</b> and <b>tag</b> must therefore be no more than - * 24. - **/ -int -crypto_write_tagged_contents_to_file(const char *fname, - const char *typestring, - const char *tag, - const uint8_t *data, - size_t datalen) -{ - char header[32]; - smartlist_t *chunks = smartlist_new(); - sized_chunk_t ch0, ch1; - int r = -1; - - memset(header, 0, sizeof(header)); - if (tor_snprintf(header, sizeof(header), - "== %s: %s ==", typestring, tag) < 0) - goto end; - ch0.bytes = header; - ch0.len = 32; - ch1.bytes = (const char*) data; - ch1.len = datalen; - smartlist_add(chunks, &ch0); - smartlist_add(chunks, &ch1); - - r = write_chunks_to_file(fname, chunks, 1, 0); - - end: - smartlist_free(chunks); - return r; -} - -/** Read a tagged-data file from <b>fname</b> into the - * <b>data_out_len</b>-byte buffer in <b>data_out</b>. Check that the - * typestring matches <b>typestring</b>; store the tag into a newly allocated - * string in <b>tag_out</b>. Return -1 on failure, and the number of bytes of - * data on success. Preserves the errno from reading the file. */ -ssize_t -crypto_read_tagged_contents_from_file(const char *fname, - const char *typestring, - char **tag_out, - uint8_t *data_out, - ssize_t data_out_len) -{ - char prefix[33]; - char *content = NULL; - struct stat st; - ssize_t r = -1; - size_t st_size = 0; - int saved_errno = 0; - - *tag_out = NULL; - st.st_size = 0; - content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st); - if (! content) { - saved_errno = errno; - goto end; - } - if (st.st_size < 32 || st.st_size > 32 + data_out_len) { - saved_errno = EINVAL; - goto end; - } - st_size = (size_t)st.st_size; - - memcpy(prefix, content, 32); - prefix[32] = 0; - /* Check type, extract tag. */ - if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") || - ! tor_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) { - saved_errno = EINVAL; - goto end; - } - - if (strcmpstart(prefix+3, typestring) || - 3+strlen(typestring) >= 32 || - strcmpstart(prefix+3+strlen(typestring), ": ")) { - saved_errno = EINVAL; - goto end; - } - - *tag_out = tor_strndup(prefix+5+strlen(typestring), - strlen(prefix)-8-strlen(typestring)); - - memcpy(data_out, content+32, st_size-32); - r = st_size - 32; - - end: - if (content) - memwipe(content, 0, st_size); - tor_free(content); - if (saved_errno) - errno = saved_errno; - return r; -} - -/** Encode <b>pkey</b> as a base64-encoded string, without trailing "=" - * characters, in the buffer <b>output</b>, which must have at least - * CURVE25519_BASE64_PADDED_LEN+1 bytes available. Return 0 on success, -1 on - * failure. */ -int -curve25519_public_to_base64(char *output, - const curve25519_public_key_t *pkey) -{ - char buf[128]; - base64_encode(buf, sizeof(buf), - (const char*)pkey->public_key, CURVE25519_PUBKEY_LEN, 0); - buf[CURVE25519_BASE64_PADDED_LEN] = '\0'; - memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1); - return 0; -} - -/** Try to decode a base64-encoded curve25519 public key from <b>input</b> - * into the object at <b>pkey</b>. Return 0 on success, -1 on failure. - * Accepts keys with or without a trailing "=". */ -int -curve25519_public_from_base64(curve25519_public_key_t *pkey, - const char *input) -{ - size_t len = strlen(input); - if (len == CURVE25519_BASE64_PADDED_LEN - 1) { - /* not padded */ - return digest256_from_base64((char*)pkey->public_key, input); - } else if (len == CURVE25519_BASE64_PADDED_LEN) { - char buf[128]; - if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN) - return -1; - memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN); - return 0; - } else { - return -1; - } -} - -/** For logging convenience: Convert <b>pkey</b> to a statically allocated - * base64 string and return it. Not threadsafe. Format not meant to be - * computer-readable; it may change in the future. Subsequent calls invalidate - * previous returns. */ -const char * -ed25519_fmt(const ed25519_public_key_t *pkey) -{ - static char formatted[ED25519_BASE64_LEN+1]; - if (pkey) { - if (ed25519_public_key_is_zero(pkey)) { - strlcpy(formatted, "<unset>", sizeof(formatted)); - } else { - int r = ed25519_public_to_base64(formatted, pkey); - tor_assert(!r); - } - } else { - strlcpy(formatted, "<null>", sizeof(formatted)); - } - return formatted; -} - -/** Try to decode the string <b>input</b> into an ed25519 public key. On - * success, store the value in <b>pkey</b> and return 0. Otherwise return - * -1. */ -int -ed25519_public_from_base64(ed25519_public_key_t *pkey, - const char *input) -{ - return digest256_from_base64((char*)pkey->pubkey, input); -} - -/** Encode the public key <b>pkey</b> into the buffer at <b>output</b>, - * which must have space for ED25519_BASE64_LEN bytes of encoded key, - * plus one byte for a terminating NUL. Return 0 on success, -1 on failure. - */ -int -ed25519_public_to_base64(char *output, - const ed25519_public_key_t *pkey) -{ - return digest256_to_base64(output, (const char *)pkey->pubkey); -} - -/** Encode the signature <b>sig</b> into the buffer at <b>output</b>, - * which must have space for ED25519_SIG_BASE64_LEN bytes of encoded signature, - * plus one byte for a terminating NUL. Return 0 on success, -1 on failure. - */ -int -ed25519_signature_to_base64(char *output, - const ed25519_signature_t *sig) -{ - char buf[256]; - int n = base64_encode_nopad(buf, sizeof(buf), sig->sig, ED25519_SIG_LEN); - tor_assert(n == ED25519_SIG_BASE64_LEN); - memcpy(output, buf, ED25519_SIG_BASE64_LEN+1); - return 0; -} - -/** Try to decode the string <b>input</b> into an ed25519 signature. On - * success, store the value in <b>sig</b> and return 0. Otherwise return - * -1. */ -int -ed25519_signature_from_base64(ed25519_signature_t *sig, - const char *input) -{ - - if (strlen(input) != ED25519_SIG_BASE64_LEN) - return -1; - char buf[ED25519_SIG_BASE64_LEN+3]; - memcpy(buf, input, ED25519_SIG_BASE64_LEN); - buf[ED25519_SIG_BASE64_LEN+0] = '='; - buf[ED25519_SIG_BASE64_LEN+1] = '='; - buf[ED25519_SIG_BASE64_LEN+2] = 0; - char decoded[128]; - int n = base64_decode(decoded, sizeof(decoded), buf, strlen(buf)); - if (n < 0 || n != ED25519_SIG_LEN) - return -1; - memcpy(sig->sig, decoded, ED25519_SIG_LEN); - - return 0; -} - -/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing = - * characters, and store the nul-terminated result in the first - * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */ -/* XXXX unify with crypto_format.c code */ -int -digest_to_base64(char *d64, const char *digest) -{ - char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST_LEN, 0); - buf[BASE64_DIGEST_LEN] = '\0'; - memcpy(d64, buf, BASE64_DIGEST_LEN+1); - return 0; -} - -/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without - * trailing newline or = characters), decode it and store the result in the - * first DIGEST_LEN bytes at <b>digest</b>. */ -/* XXXX unify with crypto_format.c code */ -int -digest_from_base64(char *digest, const char *d64) -{ - if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN) - return 0; - else - return -1; -} - -/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the - * trailing = characters, and store the nul-terminated result in the first - * BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */ - /* XXXX unify with crypto_format.c code */ -int -digest256_to_base64(char *d64, const char *digest) -{ - char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN, 0); - buf[BASE64_DIGEST256_LEN] = '\0'; - memcpy(d64, buf, BASE64_DIGEST256_LEN+1); - return 0; -} - -/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without - * trailing newline or = characters), decode it and store the result in the - * first DIGEST256_LEN bytes at <b>digest</b>. */ -/* XXXX unify with crypto_format.c code */ -int -digest256_from_base64(char *digest, const char *d64) -{ - if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN) - return 0; - else - return -1; -} - diff --git a/src/common/crypto_format.h b/src/common/crypto_format.h deleted file mode 100644 index bbd85dc720..0000000000 --- a/src/common/crypto_format.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CRYPTO_FORMAT_H -#define TOR_CRYPTO_FORMAT_H - -#include "testsupport.h" -#include "torint.h" -#include "crypto_ed25519.h" - -int crypto_write_tagged_contents_to_file(const char *fname, - const char *typestring, - const char *tag, - const uint8_t *data, - size_t datalen); - -ssize_t crypto_read_tagged_contents_from_file(const char *fname, - const char *typestring, - char **tag_out, - uint8_t *data_out, - ssize_t data_out_len); - -#define ED25519_BASE64_LEN 43 -int ed25519_public_from_base64(ed25519_public_key_t *pkey, - const char *input); -int ed25519_public_to_base64(char *output, - const ed25519_public_key_t *pkey); -const char *ed25519_fmt(const ed25519_public_key_t *pkey); - -/* XXXX move these to crypto_format.h */ -#define ED25519_SIG_BASE64_LEN 86 - -int ed25519_signature_from_base64(ed25519_signature_t *sig, - const char *input); -int ed25519_signature_to_base64(char *output, - const ed25519_signature_t *sig); - -int digest_to_base64(char *d64, const char *digest); -int digest_from_base64(char *digest, const char *d64); -int digest256_to_base64(char *d64, const char *digest); -int digest256_from_base64(char *digest, const char *d64); - -#endif /* !defined(TOR_CRYPTO_FORMAT_H) */ - diff --git a/src/common/crypto_openssl_mgt.c b/src/common/crypto_openssl_mgt.c deleted file mode 100644 index ea3519efa2..0000000000 --- a/src/common/crypto_openssl_mgt.c +++ /dev/null @@ -1,161 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_openssl.c - * - * \brief Block of functions related to operations from OpenSSL. - **/ - -#include "compat_openssl.h" -#include "crypto_openssl_mgt.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/err.h> -#include <openssl/rsa.h> -#include <openssl/pem.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/rand.h> -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/conf.h> -#include <openssl/hmac.h> -#include <openssl/crypto.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#ifndef NEW_THREAD_API -/** A number of preallocated mutexes for use by OpenSSL. */ -static tor_mutex_t **openssl_mutexes_ = NULL; -/** How many mutexes have we allocated for use by OpenSSL? */ -static int n_openssl_mutexes_ = 0; -#endif /* !defined(NEW_THREAD_API) */ - -/** Declare STATIC functions */ -STATIC char * parse_openssl_version_str(const char *raw_version); -#ifndef NEW_THREAD_API -STATIC void openssl_locking_cb_(int mode, int n, const char *file, int line); -STATIC void tor_set_openssl_thread_id(CRYPTO_THREADID *threadid); -#endif - -/* Returns a trimmed and human-readable version of an openssl version string -* <b>raw_version</b>. They are usually in the form of 'OpenSSL 1.0.0b 10 -* May 2012' and this will parse them into a form similar to '1.0.0b' */ -STATIC char * -parse_openssl_version_str(const char *raw_version) -{ - const char *end_of_version = NULL; - /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's - trim that down. */ - if (!strcmpstart(raw_version, "OpenSSL ")) { - raw_version += strlen("OpenSSL "); - end_of_version = strchr(raw_version, ' '); - } - - if (end_of_version) - return tor_strndup(raw_version, - end_of_version-raw_version); - else - return tor_strdup(raw_version); -} - -static char *crypto_openssl_version_str = NULL; -/* Return a human-readable version of the run-time openssl version number. */ -const char * -crypto_openssl_get_version_str(void) -{ - if (crypto_openssl_version_str == NULL) { - const char *raw_version = OpenSSL_version(OPENSSL_VERSION); - crypto_openssl_version_str = parse_openssl_version_str(raw_version); - } - return crypto_openssl_version_str; -} - -static char *crypto_openssl_header_version_str = NULL; -/* Return a human-readable version of the compile-time openssl version -* number. */ -const char * -crypto_openssl_get_header_version_str(void) -{ - if (crypto_openssl_header_version_str == NULL) { - crypto_openssl_header_version_str = - parse_openssl_version_str(OPENSSL_VERSION_TEXT); - } - return crypto_openssl_header_version_str; -} - -#ifndef OPENSSL_THREADS -#error OpenSSL has been built without thread support. Tor requires an \ - OpenSSL library with thread support enabled. -#endif - -#ifndef NEW_THREAD_API -/** Helper: OpenSSL uses this callback to manipulate mutexes. */ -STATIC void -openssl_locking_cb_(int mode, int n, const char *file, int line) -{ - (void)file; - (void)line; - if (!openssl_mutexes_) - /* This is not a really good fix for the - * "release-freed-lock-from-separate-thread-on-shutdown" problem, but - * it can't hurt. */ - return; - if (mode & CRYPTO_LOCK) - tor_mutex_acquire(openssl_mutexes_[n]); - else - tor_mutex_release(openssl_mutexes_[n]); -} - -STATIC void -tor_set_openssl_thread_id(CRYPTO_THREADID *threadid) -{ - CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id()); -} -#endif /* !defined(NEW_THREAD_API) */ - -/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being - * multithreaded. Returns 0. */ -int -setup_openssl_threading(void) -{ -#ifndef NEW_THREAD_API - int i; - int n = CRYPTO_num_locks(); - n_openssl_mutexes_ = n; - openssl_mutexes_ = tor_calloc(n, sizeof(tor_mutex_t *)); - for (i=0; i < n; ++i) - openssl_mutexes_[i] = tor_mutex_new(); - CRYPTO_set_locking_callback(openssl_locking_cb_); - CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id); -#endif /* !defined(NEW_THREAD_API) */ - return 0; -} - -/** free OpenSSL variables */ -void -crypto_openssl_free_all(void) -{ - tor_free(crypto_openssl_version_str); - tor_free(crypto_openssl_header_version_str); - -#ifndef NEW_THREAD_API - if (n_openssl_mutexes_) { - int n = n_openssl_mutexes_; - tor_mutex_t **ms = openssl_mutexes_; - int i; - openssl_mutexes_ = NULL; - n_openssl_mutexes_ = 0; - for (i=0;i<n;++i) { - tor_mutex_free(ms[i]); - } - tor_free(ms); - } -#endif /* !defined(NEW_THREAD_API) */ -} - diff --git a/src/common/crypto_openssl_mgt.h b/src/common/crypto_openssl_mgt.h deleted file mode 100644 index 09b6737962..0000000000 --- a/src/common/crypto_openssl_mgt.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_openssl.h - * - * \brief Headers for crypto_openssl.c - **/ - -#ifndef TOR_CRYPTO_OPENSSL_H -#define TOR_CRYPTO_OPENSSL_H - -#include <stdio.h> -#include "util.h" - -#include <openssl/engine.h> - -/* - Macro to create an arbitrary OpenSSL version number as used by - OPENSSL_VERSION_NUMBER or SSLeay(), since the actual numbers are a bit hard - to read. - - Don't use this directly, instead use one of the other OPENSSL_V macros - below. - - The format is: 4 bits major, 8 bits minor, 8 bits fix, 8 bits patch, 4 bit - status. - */ -#define OPENSSL_VER(a,b,c,d,e) \ - (((a)<<28) | \ - ((b)<<20) | \ - ((c)<<12) | \ - ((d)<< 4) | \ - (e)) -/** An openssl release number. For example, OPENSSL_V(0,9,8,'j') is the - * version for the released version of 0.9.8j */ -#define OPENSSL_V(a,b,c,d) \ - OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf) -/** An openssl release number for the first release in the series. For - * example, OPENSSL_V_NOPATCH(1,0,0) is the first released version of OpenSSL - * 1.0.0. */ -#define OPENSSL_V_NOPATCH(a,b,c) \ - OPENSSL_VER((a),(b),(c),0,0xf) -/** The first version that would occur for any alpha or beta in an openssl - * series. For example, OPENSSL_V_SERIES(0,9,8) is greater than any released - * 0.9.7, and less than any released 0.9.8. */ -#define OPENSSL_V_SERIES(a,b,c) \ - OPENSSL_VER((a),(b),(c),0,0) - -#ifdef ANDROID -/* Android's OpenSSL seems to have removed all of its Engine support. */ -#define DISABLE_ENGINES -#endif - -#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && \ - !defined(LIBRESSL_VERSION_NUMBER) -/* OpenSSL as of 1.1.0pre4 has an "new" thread API, which doesn't require - * seting up various callbacks. - * - * OpenSSL 1.1.0pre4 has a messed up `ERR_remove_thread_state()` prototype, - * while the previous one was restored in pre5, and the function made a no-op - * (along with a deprecated annotation, which produces a compiler warning). - * - * While it is possible to support all three versions of the thread API, - * a version that existed only for one snapshot pre-release is kind of - * pointless, so let's not. - */ -#define NEW_THREAD_API -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && ... */ - -/* global openssl state */ -const char * crypto_openssl_get_version_str(void); -const char * crypto_openssl_get_header_version_str(void); - -/* OpenSSL threading setup function */ -int setup_openssl_threading(void); - -/* Tor OpenSSL utility functions */ -void crypto_openssl_free_all(void); - -#endif /* !defined(TOR_CRYPTO_OPENSSL_H) */ - diff --git a/src/common/crypto_pwbox.c b/src/common/crypto_pwbox.c deleted file mode 100644 index c2bd1d26cb..0000000000 --- a/src/common/crypto_pwbox.c +++ /dev/null @@ -1,215 +0,0 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_pwbox.c - * - * \brief Code for encrypting secrets in a password-protected form and saving - * them to disk. - */ - -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_pwbox.h" -#include "crypto_rand.h" -#include "crypto_s2k.h" -#include "crypto_util.h" -#include "di_ops.h" -#include "util.h" -#include "pwbox.h" - -/* 8 bytes "TORBOX00" - 1 byte: header len (H) - H bytes: header, denoting secret key algorithm. - 16 bytes: IV - Round up to multiple of 128 bytes, then encrypt: - 4 bytes: data len - data - zeros - 32 bytes: HMAC-SHA256 of all previous bytes. -*/ - -#define MAX_OVERHEAD (S2K_MAXLEN + 8 + 1 + 32 + CIPHER_IV_LEN) - -/** - * Make an authenticated passphrase-encrypted blob to encode the - * <b>input_len</b> bytes in <b>input</b> using the passphrase - * <b>secret</b> of <b>secret_len</b> bytes. Allocate a new chunk of memory - * to hold the encrypted data, and store a pointer to that memory in - * *<b>out</b>, and its size in <b>outlen_out</b>. Use <b>s2k_flags</b> as an - * argument to the passphrase-hashing function. - */ -int -crypto_pwbox(uint8_t **out, size_t *outlen_out, - const uint8_t *input, size_t input_len, - const char *secret, size_t secret_len, - unsigned s2k_flags) -{ - uint8_t *result = NULL, *encrypted_portion; - size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128); - ssize_t result_len; - int spec_len; - uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN]; - pwbox_encoded_t *enc = NULL; - ssize_t enc_len; - - crypto_cipher_t *cipher; - int rv; - - enc = pwbox_encoded_new(); - - pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN); - - spec_len = secret_to_key_make_specifier( - pwbox_encoded_getarray_skey_header(enc), - S2K_MAXLEN, - s2k_flags); - if (BUG(spec_len < 0 || spec_len > S2K_MAXLEN)) - goto err; - pwbox_encoded_setlen_skey_header(enc, spec_len); - enc->header_len = spec_len; - - crypto_rand((char*)enc->iv, sizeof(enc->iv)); - - pwbox_encoded_setlen_data(enc, encrypted_len); - encrypted_portion = pwbox_encoded_getarray_data(enc); - - set_uint32(encrypted_portion, htonl((uint32_t)input_len)); - memcpy(encrypted_portion+4, input, input_len); - - /* Now that all the data is in position, derive some keys, encrypt, and - * digest */ - const int s2k_rv = secret_to_key_derivekey(keys, sizeof(keys), - pwbox_encoded_getarray_skey_header(enc), - spec_len, - secret, secret_len); - if (BUG(s2k_rv < 0)) - goto err; - - cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); - crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len); - crypto_cipher_free(cipher); - - result_len = pwbox_encoded_encoded_len(enc); - if (BUG(result_len < 0)) - goto err; - result = tor_malloc(result_len); - enc_len = pwbox_encoded_encode(result, result_len, enc); - if (BUG(enc_len < 0)) - goto err; - tor_assert(enc_len == result_len); - - crypto_hmac_sha256((char*) result + result_len - 32, - (const char*)keys + CIPHER_KEY_LEN, - DIGEST256_LEN, - (const char*)result, - result_len - 32); - - *out = result; - *outlen_out = result_len; - rv = 0; - goto out; - - /* LCOV_EXCL_START - - This error case is often unreachable if we're correctly coded, unless - somebody adds a new error case somewhere, or unless you're building - without scrypto support. - - - make_specifier can't fail, unless S2K_MAX_LEN is too short. - - secret_to_key_derivekey can't really fail unless we're missing - scrypt, or the underlying function fails, or we pass it a bogus - algorithm or parameters. - - pwbox_encoded_encoded_len can't fail unless we're using trunnel - incorrectly. - - pwbox_encoded_encode can't fail unless we're using trunnel wrong, - or it's buggy. - */ - err: - tor_free(result); - rv = -1; - /* LCOV_EXCL_STOP */ - out: - pwbox_encoded_free(enc); - memwipe(keys, 0, sizeof(keys)); - return rv; -} - -/** - * Try to decrypt the passphrase-encrypted blob of <b>input_len</b> bytes in - * <b>input</b> using the passphrase <b>secret</b> of <b>secret_len</b> bytes. - * On success, return 0 and allocate a new chunk of memory to hold the - * decrypted data, and store a pointer to that memory in *<b>out</b>, and its - * size in <b>outlen_out</b>. On failure, return UNPWBOX_BAD_SECRET if - * the passphrase might have been wrong, and UNPWBOX_CORRUPT if the object is - * definitely corrupt. - */ -int -crypto_unpwbox(uint8_t **out, size_t *outlen_out, - const uint8_t *inp, size_t input_len, - const char *secret, size_t secret_len) -{ - uint8_t *result = NULL; - const uint8_t *encrypted; - uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN]; - uint8_t hmac[DIGEST256_LEN]; - uint32_t result_len; - size_t encrypted_len; - crypto_cipher_t *cipher = NULL; - int rv = UNPWBOX_CORRUPTED; - ssize_t got_len; - - pwbox_encoded_t *enc = NULL; - - got_len = pwbox_encoded_parse(&enc, inp, input_len); - if (got_len < 0 || (size_t)got_len != input_len) - goto err; - - /* Now derive the keys and check the hmac. */ - if (secret_to_key_derivekey(keys, sizeof(keys), - pwbox_encoded_getarray_skey_header(enc), - pwbox_encoded_getlen_skey_header(enc), - secret, secret_len) < 0) - goto err; - - crypto_hmac_sha256((char *)hmac, - (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN, - (const char*)inp, input_len - DIGEST256_LEN); - - if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) { - rv = UNPWBOX_BAD_SECRET; - goto err; - } - - /* How long is the plaintext? */ - encrypted = pwbox_encoded_getarray_data(enc); - encrypted_len = pwbox_encoded_getlen_data(enc); - if (encrypted_len < 4) - goto err; - - cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); - crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4); - result_len = ntohl(result_len); - if (encrypted_len < result_len + 4) - goto err; - - /* Allocate a buffer and decrypt */ - result = tor_malloc_zero(result_len); - crypto_cipher_decrypt(cipher, (char*)result, (char*)encrypted+4, result_len); - - *out = result; - *outlen_out = result_len; - - rv = UNPWBOX_OKAY; - goto out; - - err: - tor_free(result); - - out: - crypto_cipher_free(cipher); - pwbox_encoded_free(enc); - memwipe(keys, 0, sizeof(keys)); - return rv; -} - diff --git a/src/common/crypto_pwbox.h b/src/common/crypto_pwbox.h deleted file mode 100644 index a26b6d2c17..0000000000 --- a/src/common/crypto_pwbox.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef CRYPTO_PWBOX_H_INCLUDED_ -#define CRYPTO_PWBOX_H_INCLUDED_ - -#include "torint.h" - -#define UNPWBOX_OKAY 0 -#define UNPWBOX_BAD_SECRET -1 -#define UNPWBOX_CORRUPTED -2 - -int crypto_pwbox(uint8_t **out, size_t *outlen_out, - const uint8_t *inp, size_t input_len, - const char *secret, size_t secret_len, - unsigned s2k_flags); - -int crypto_unpwbox(uint8_t **out, size_t *outlen_out, - const uint8_t *inp, size_t input_len, - const char *secret, size_t secret_len); - -#endif /* !defined(CRYPTO_PWBOX_H_INCLUDED_) */ - diff --git a/src/common/crypto_rand.c b/src/common/crypto_rand.c deleted file mode 100644 index df2e2f65d3..0000000000 --- a/src/common/crypto_rand.c +++ /dev/null @@ -1,615 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_rand.c - * - * \brief Functions for initialising and seeding (pseudo-)random - * number generators, and working with randomness. - **/ - -#ifndef CRYPTO_RAND_PRIVATE -#define CRYPTO_RAND_PRIVATE - -#include "crypto_rand.h" - -#ifdef _WIN32 -#include <windows.h> -#include <wincrypt.h> -#endif /* defined(_WIN32) */ - -#include "container.h" -#include "compat.h" -#include "compat_openssl.h" -#include "crypto_util.h" -#include "sandbox.h" -#include "testsupport.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" - -DISABLE_GCC_WARNING(redundant-decls) -#include <openssl/rand.h> -ENABLE_GCC_WARNING(redundant-decls) - -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#else -#pragma GCC diagnostic warning "-Wredundant-decls" -#endif -#endif /* __GNUC__ && GCC_VERSION >= 402 */ - -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <sys/fcntl.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_SYSCALL_H -#include <sys/syscall.h> -#endif -#ifdef HAVE_SYS_RANDOM_H -#include <sys/random.h> -#endif - -/** - * How many bytes of entropy we add at once. - * - * This is how much entropy OpenSSL likes to add right now, so maybe it will - * work for us too. - **/ -#define ADD_ENTROPY 32 - -/** - * Longest recognized DNS query. - **/ -#define MAX_DNS_LABEL_SIZE 63 - -/** - * Largest strong entropy request permitted. - **/ -#define MAX_STRONGEST_RAND_SIZE 256 - -/** - * Set the seed of the weak RNG to a random value. - **/ -void -crypto_seed_weak_rng(tor_weak_rng_t *rng) -{ - unsigned seed; - crypto_rand((void*)&seed, sizeof(seed)); - tor_init_weak_random(rng, seed); -} - -#ifdef TOR_UNIT_TESTS -int break_strongest_rng_syscall = 0; -int break_strongest_rng_fallback = 0; -#endif - -/** - * Try to get <b>out_len</b> bytes of the strongest entropy we can generate, - * via system calls, storing it into <b>out</b>. Return 0 on success, -1 on - * failure. A maximum request size of 256 bytes is imposed. - **/ -static int -crypto_strongest_rand_syscall(uint8_t *out, size_t out_len) -{ - tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE); - - /* We only log at notice-level here because in the case that this function - * fails the crypto_strongest_rand_raw() caller will log with a warning-level - * message and let crypto_strongest_rand() error out and finally terminating - * Tor with an assertion error. - */ - -#ifdef TOR_UNIT_TESTS - if (break_strongest_rng_syscall) - return -1; -#endif - -#if defined(_WIN32) - static int provider_set = 0; - static HCRYPTPROV provider; - - if (!provider_set) { - if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { - log_notice(LD_CRYPTO, "Unable to set Windows CryptoAPI provider [1]."); - return -1; - } - provider_set = 1; - } - if (!CryptGenRandom(provider, out_len, out)) { - log_notice(LD_CRYPTO, "Unable get entropy from the Windows CryptoAPI."); - return -1; - } - - return 0; -#elif defined(__linux__) && defined(SYS_getrandom) - static int getrandom_works = 1; /* Be optimistic about our chances... */ - - /* getrandom() isn't as straightforward as getentropy(), and has - * no glibc wrapper. - * - * As far as I can tell from getrandom(2) and the source code, the - * requests we issue will always succeed (though it will block on the - * call if /dev/urandom isn't seeded yet), since we are NOT specifying - * GRND_NONBLOCK and the request is <= 256 bytes. - * - * The manpage is unclear on what happens if a signal interrupts the call - * while the request is blocked due to lack of entropy.... - * - * We optimistically assume that getrandom() is available and functional - * because it is the way of the future, and 2 branch mispredicts pale in - * comparison to the overheads involved with failing to open - * /dev/srandom followed by opening and reading from /dev/urandom. - */ - if (PREDICT_LIKELY(getrandom_works)) { - long ret; - /* A flag of '0' here means to read from '/dev/urandom', and to - * block if insufficient entropy is available to service the - * request. - */ - const unsigned int flags = 0; - do { - ret = syscall(SYS_getrandom, out, out_len, flags); - } while (ret == -1 && ((errno == EINTR) ||(errno == EAGAIN))); - - if (PREDICT_UNLIKELY(ret == -1)) { - /* LCOV_EXCL_START we can't actually make the syscall fail in testing. */ - tor_assert(errno != EAGAIN); - tor_assert(errno != EINTR); - - /* Useful log message for errno. */ - if (errno == ENOSYS) { - log_notice(LD_CRYPTO, "Can't get entropy from getrandom()." - " You are running a version of Tor built to support" - " getrandom(), but the kernel doesn't implement this" - " function--probably because it is too old?" - " Trying fallback method instead."); - } else { - log_notice(LD_CRYPTO, "Can't get entropy from getrandom(): %s." - " Trying fallback method instead.", - strerror(errno)); - } - - getrandom_works = 0; /* Don't bother trying again. */ - return -1; - /* LCOV_EXCL_STOP */ - } - - tor_assert(ret == (long)out_len); - return 0; - } - - return -1; /* getrandom() previously failed unexpectedly. */ -#elif defined(HAVE_GETENTROPY) - /* getentropy() is what Linux's getrandom() wants to be when it grows up. - * the only gotcha is that requests are limited to 256 bytes. - */ - return getentropy(out, out_len); -#else - (void) out; -#endif /* defined(_WIN32) || ... */ - - /* This platform doesn't have a supported syscall based random. */ - return -1; -} - -/** - * Try to get <b>out_len</b> bytes of the strongest entropy we can generate, - * via the per-platform fallback mechanism, storing it into <b>out</b>. - * Return 0 on success, -1 on failure. A maximum request size of 256 bytes - * is imposed. - **/ -static int -crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) -{ -#ifdef TOR_UNIT_TESTS - if (break_strongest_rng_fallback) - return -1; -#endif - -#ifdef _WIN32 - /* Windows exclusively uses crypto_strongest_rand_syscall(). */ - (void)out; - (void)out_len; - return -1; -#else /* !(defined(_WIN32)) */ - static const char *filenames[] = { - "/dev/srandom", "/dev/urandom", "/dev/random", NULL - }; - int fd, i; - size_t n; - - for (i = 0; filenames[i]; ++i) { - log_debug(LD_FS, "Considering %s as entropy source", filenames[i]); - fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0); - if (fd<0) continue; - log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]); - n = read_all(fd, (char*)out, out_len, 0); - close(fd); - if (n != out_len) { - /* LCOV_EXCL_START - * We can't make /dev/foorandom actually fail. */ - log_notice(LD_CRYPTO, - "Error reading from entropy source %s (read only %lu bytes).", - filenames[i], - (unsigned long)n); - return -1; - /* LCOV_EXCL_STOP */ - } - - return 0; - } - - return -1; -#endif /* defined(_WIN32) */ -} - -/** - * Try to get <b>out_len</b> bytes of the strongest entropy we can generate, - * storing it into <b>out</b>. Return 0 on success, -1 on failure. A maximum - * request size of 256 bytes is imposed. - **/ -STATIC int -crypto_strongest_rand_raw(uint8_t *out, size_t out_len) -{ - static const size_t sanity_min_size = 16; - static const int max_attempts = 3; - tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE); - - /* For buffers >= 16 bytes (128 bits), we sanity check the output by - * zero filling the buffer and ensuring that it actually was at least - * partially modified. - * - * Checking that any individual byte is non-zero seems like it would - * fail too often (p = out_len * 1/256) for comfort, but this is an - * "adjust according to taste" sort of check. - */ - memwipe(out, 0, out_len); - for (int i = 0; i < max_attempts; i++) { - /* Try to use the syscall/OS favored mechanism to get strong entropy. */ - if (crypto_strongest_rand_syscall(out, out_len) != 0) { - /* Try to use the less-favored mechanism to get strong entropy. */ - if (crypto_strongest_rand_fallback(out, out_len) != 0) { - /* Welp, we tried. Hopefully the calling code terminates the process - * since we're basically boned without good entropy. - */ - log_warn(LD_CRYPTO, - "Cannot get strong entropy: no entropy source found."); - return -1; - } - } - - if ((out_len < sanity_min_size) || !tor_mem_is_zero((char*)out, out_len)) - return 0; - } - - /* LCOV_EXCL_START - * - * We tried max_attempts times to fill a buffer >= 128 bits long, - * and each time it returned all '0's. Either the system entropy - * source is busted, or the user should go out and buy a ticket to - * every lottery on the planet. - */ - log_warn(LD_CRYPTO, "Strong OS entropy returned all zero buffer."); - - return -1; - /* LCOV_EXCL_STOP */ -} - -/** - * Try to get <b>out_len</b> bytes of the strongest entropy we can generate, - * storing it into <b>out</b>. - **/ -void -crypto_strongest_rand(uint8_t *out, size_t out_len) -{ -#define DLEN SHA512_DIGEST_LENGTH - /* We're going to hash DLEN bytes from the system RNG together with some - * bytes from the openssl PRNG, in order to yield DLEN bytes. - */ - uint8_t inp[DLEN*2]; - uint8_t tmp[DLEN]; - tor_assert(out); - while (out_len) { - crypto_rand((char*) inp, DLEN); - if (crypto_strongest_rand_raw(inp+DLEN, DLEN) < 0) { - // LCOV_EXCL_START - log_err(LD_CRYPTO, "Failed to load strong entropy when generating an " - "important key. Exiting."); - /* Die with an assertion so we get a stack trace. */ - tor_assert(0); - // LCOV_EXCL_STOP - } - if (out_len >= DLEN) { - SHA512(inp, sizeof(inp), out); - out += DLEN; - out_len -= DLEN; - } else { - SHA512(inp, sizeof(inp), tmp); - memcpy(out, tmp, out_len); - break; - } - } - memwipe(tmp, 0, sizeof(tmp)); - memwipe(inp, 0, sizeof(inp)); -#undef DLEN -} - -/** - * Seed OpenSSL's random number generator with bytes from the operating - * system. Return 0 on success, -1 on failure. - **/ -int -crypto_seed_rng(void) -{ - int rand_poll_ok = 0, load_entropy_ok = 0; - uint8_t buf[ADD_ENTROPY]; - - /* OpenSSL has a RAND_poll function that knows about more kinds of - * entropy than we do. We'll try calling that, *and* calling our own entropy - * functions. If one succeeds, we'll accept the RNG as seeded. */ - rand_poll_ok = RAND_poll(); - if (rand_poll_ok == 0) - log_warn(LD_CRYPTO, "RAND_poll() failed."); // LCOV_EXCL_LINE - - load_entropy_ok = !crypto_strongest_rand_raw(buf, sizeof(buf)); - if (load_entropy_ok) { - RAND_seed(buf, sizeof(buf)); - } - - memwipe(buf, 0, sizeof(buf)); - - if ((rand_poll_ok || load_entropy_ok) && RAND_status() == 1) - return 0; - else - return -1; -} - -/** - * Write <b>n</b> bytes of strong random data to <b>to</b>. Supports mocking - * for unit tests. - * - * This function is not allowed to fail; if it would fail to generate strong - * entropy, it must terminate the process instead. - **/ -MOCK_IMPL(void, -crypto_rand, (char *to, size_t n)) -{ - crypto_rand_unmocked(to, n); -} - -/** - * Write <b>n</b> bytes of strong random data to <b>to</b>. Most callers - * will want crypto_rand instead. - * - * This function is not allowed to fail; if it would fail to generate strong - * entropy, it must terminate the process instead. - **/ -void -crypto_rand_unmocked(char *to, size_t n) -{ - int r; - if (n == 0) - return; - - tor_assert(n < INT_MAX); - tor_assert(to); - r = RAND_bytes((unsigned char*)to, (int)n); - /* We consider a PRNG failure non-survivable. Let's assert so that we get a - * stack trace about where it happened. - */ - tor_assert(r >= 0); -} - -/** - * Return a pseudorandom integer, chosen uniformly from the values - * between 0 and <b>max</b>-1 inclusive. <b>max</b> must be between 1 and - * INT_MAX+1, inclusive. - */ -int -crypto_rand_int(unsigned int max) -{ - unsigned int val; - unsigned int cutoff; - tor_assert(max <= ((unsigned int)INT_MAX)+1); - tor_assert(max > 0); /* don't div by 0 */ - - /* We ignore any values that are >= 'cutoff,' to avoid biasing the - * distribution with clipping at the upper end of unsigned int's - * range. - */ - cutoff = UINT_MAX - (UINT_MAX%max); - while (1) { - crypto_rand((char*)&val, sizeof(val)); - if (val < cutoff) - return val % max; - } -} - -/** - * Return a pseudorandom integer, chosen uniformly from the values i such - * that min <= i < max. - * - * <b>min</b> MUST be in range [0, <b>max</b>). - * <b>max</b> MUST be in range (min, INT_MAX]. - **/ -int -crypto_rand_int_range(unsigned int min, unsigned int max) -{ - tor_assert(min < max); - tor_assert(max <= INT_MAX); - - /* The overflow is avoided here because crypto_rand_int() returns a value - * between 0 and (max - min) inclusive. */ - return min + crypto_rand_int(max - min); -} - -/** - * As crypto_rand_int_range, but supports uint64_t. - **/ -uint64_t -crypto_rand_uint64_range(uint64_t min, uint64_t max) -{ - tor_assert(min < max); - return min + crypto_rand_uint64(max - min); -} - -/** - * As crypto_rand_int_range, but supports time_t. - **/ -time_t -crypto_rand_time_range(time_t min, time_t max) -{ - tor_assert(min < max); - return min + (time_t)crypto_rand_uint64(max - min); -} - -/** - * Return a pseudorandom 64-bit integer, chosen uniformly from the values - * between 0 and <b>max</b>-1 inclusive. - **/ -uint64_t -crypto_rand_uint64(uint64_t max) -{ - uint64_t val; - uint64_t cutoff; - tor_assert(max < UINT64_MAX); - tor_assert(max > 0); /* don't div by 0 */ - - /* We ignore any values that are >= 'cutoff,' to avoid biasing the - * distribution with clipping at the upper end of unsigned int's - * range. - */ - cutoff = UINT64_MAX - (UINT64_MAX%max); - while (1) { - crypto_rand((char*)&val, sizeof(val)); - if (val < cutoff) - return val % max; - } -} - -/** - * Return a pseudorandom double d, chosen uniformly from the range - * 0.0 <= d < 1.0. - **/ -double -crypto_rand_double(void) -{ - /* We just use an unsigned int here; we don't really care about getting - * more than 32 bits of resolution */ - unsigned int u; - crypto_rand((char*)&u, sizeof(u)); -#if SIZEOF_INT == 4 -#define UINT_MAX_AS_DOUBLE 4294967296.0 -#elif SIZEOF_INT == 8 -#define UINT_MAX_AS_DOUBLE 1.8446744073709552e+19 -#else -#error SIZEOF_INT is neither 4 nor 8 -#endif /* SIZEOF_INT == 4 || ... */ - return ((double)u) / UINT_MAX_AS_DOUBLE; -} - -/** - * Generate and return a new random hostname starting with <b>prefix</b>, - * ending with <b>suffix</b>, and containing no fewer than - * <b>min_rand_len</b> and no more than <b>max_rand_len</b> random base32 - * characters. Does not check for failure. - * - * Clip <b>max_rand_len</b> to MAX_DNS_LABEL_SIZE. - **/ -char * -crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix, - const char *suffix) -{ - char *result, *rand_bytes; - int randlen, rand_bytes_len; - size_t resultlen, prefixlen; - - if (max_rand_len > MAX_DNS_LABEL_SIZE) - max_rand_len = MAX_DNS_LABEL_SIZE; - if (min_rand_len > max_rand_len) - min_rand_len = max_rand_len; - - randlen = crypto_rand_int_range(min_rand_len, max_rand_len+1); - - prefixlen = strlen(prefix); - resultlen = prefixlen + strlen(suffix) + randlen + 16; - - rand_bytes_len = ((randlen*5)+7)/8; - if (rand_bytes_len % 5) - rand_bytes_len += 5 - (rand_bytes_len%5); - rand_bytes = tor_malloc(rand_bytes_len); - crypto_rand(rand_bytes, rand_bytes_len); - - result = tor_malloc(resultlen); - memcpy(result, prefix, prefixlen); - base32_encode(result+prefixlen, resultlen-prefixlen, - rand_bytes, rand_bytes_len); - tor_free(rand_bytes); - strlcpy(result+prefixlen+randlen, suffix, resultlen-(prefixlen+randlen)); - - return result; -} - -/** - * Return a randomly chosen element of <b>sl</b>; or NULL if <b>sl</b> - * is empty. - **/ -void * -smartlist_choose(const smartlist_t *sl) -{ - int len = smartlist_len(sl); - if (len) - return smartlist_get(sl,crypto_rand_int(len)); - return NULL; /* no elements to choose from */ -} - -/** - * Scramble the elements of <b>sl</b> into a random order. - **/ -void -smartlist_shuffle(smartlist_t *sl) -{ - int i; - /* From the end of the list to the front, choose at random from the - positions we haven't looked at yet, and swap that position into the - current position. Remember to give "no swap" the same probability as - any other swap. */ - for (i = smartlist_len(sl)-1; i > 0; --i) { - int j = crypto_rand_int(i+1); - smartlist_swap(sl, i, j); - } -} - -/** Make sure that openssl is using its default PRNG. Return 1 if we had to - * adjust it; 0 otherwise. */ -int -crypto_force_rand_ssleay(void) -{ - RAND_METHOD *default_method; - default_method = RAND_OpenSSL(); - if (RAND_get_rand_method() != default_method) { - log_notice(LD_CRYPTO, "It appears that one of our engines has provided " - "a replacement the OpenSSL RNG. Resetting it to the default " - "implementation."); - RAND_set_rand_method(default_method); - return 1; - } - return 0; -} - -#endif /* !defined(CRYPTO_RAND_PRIVATE) */ - diff --git a/src/common/crypto_rand.h b/src/common/crypto_rand.h deleted file mode 100644 index bb02e51001..0000000000 --- a/src/common/crypto_rand.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_rand.h - * - * \brief Common functions for using (pseudo-)random number generators. - **/ - -#ifndef TOR_CRYPTO_RAND_H -#define TOR_CRYPTO_RAND_H - -#include "torint.h" -#include "util.h" - -/* random numbers */ -int crypto_seed_rng(void) ATTR_WUR; -MOCK_DECL(void,crypto_rand,(char *to, size_t n)); -void crypto_rand_unmocked(char *to, size_t n); -void crypto_strongest_rand(uint8_t *out, size_t out_len); -int crypto_rand_int(unsigned int max); -int crypto_rand_int_range(unsigned int min, unsigned int max); -uint64_t crypto_rand_uint64_range(uint64_t min, uint64_t max); -time_t crypto_rand_time_range(time_t min, time_t max); -uint64_t crypto_rand_uint64(uint64_t max); -double crypto_rand_double(void); -struct tor_weak_rng_t; -void crypto_seed_weak_rng(struct tor_weak_rng_t *rng); - -char *crypto_random_hostname(int min_rand_len, int max_rand_len, - const char *prefix, const char *suffix); - -struct smartlist_t; -void *smartlist_choose(const struct smartlist_t *sl); -void smartlist_shuffle(struct smartlist_t *sl); -int crypto_force_rand_ssleay(void); - -#ifdef CRYPTO_RAND_PRIVATE - -STATIC int crypto_strongest_rand_raw(uint8_t *out, size_t out_len); - -#ifdef TOR_UNIT_TESTS -extern int break_strongest_rng_syscall; -extern int break_strongest_rng_fallback; -#endif -#endif /* defined(CRYPTO_RAND_PRIVATE) */ - -#endif /* !defined(TOR_CRYPTO_RAND_H) */ - diff --git a/src/common/crypto_rsa.c b/src/common/crypto_rsa.c deleted file mode 100644 index f66cdef3c5..0000000000 --- a/src/common/crypto_rsa.c +++ /dev/null @@ -1,1183 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_rsa.c - * \brief Block of functions related with RSA utilities and operations. - **/ - -#include "crypto.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_format.h" -#include "compat_openssl.h" -#include "crypto_rand.h" -#include "crypto_rsa.h" -#include "crypto_util.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/err.h> -#include <openssl/rsa.h> -#include <openssl/pem.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/rand.h> -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/conf.h> -#include <openssl/hmac.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#include "torlog.h" -#include "util.h" -#include "util_format.h" - -/** Declaration for crypto_pk_t structure. */ -struct crypto_pk_t -{ - int refs; /**< reference count, so we don't have to copy keys */ - RSA *key; /**< The key itself */ -}; - -/** Log all pending crypto errors at level <b>severity</b>. Use - * <b>doing</b> to describe our current activities. - */ -static void -crypto_log_errors(int severity, const char *doing) -{ - unsigned long err; - const char *msg, *lib, *func; - while ((err = ERR_get_error()) != 0) { - msg = (const char*)ERR_reason_error_string(err); - lib = (const char*)ERR_lib_error_string(err); - func = (const char*)ERR_func_error_string(err); - if (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (BUG(!doing)) doing = "(null)"; - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); - } -} - -/** Return the number of bytes added by padding method <b>padding</b>. - */ -int -crypto_get_rsa_padding_overhead(int padding) -{ - switch (padding) - { - case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD; - default: tor_assert(0); return -1; // LCOV_EXCL_LINE - } -} - -/** Given a padding method <b>padding</b>, return the correct OpenSSL constant. - */ -int -crypto_get_rsa_padding(int padding) -{ - switch (padding) - { - case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING; - default: tor_assert(0); return -1; // LCOV_EXCL_LINE - } -} - -/** used internally: quicly validate a crypto_pk_t object as a private key. - * Return 1 iff the public key is valid, 0 if obviously invalid. - */ -static int -crypto_pk_private_ok(const crypto_pk_t *k) -{ -#ifdef OPENSSL_1_1_API - if (!k || !k->key) - return 0; - - const BIGNUM *p, *q; - RSA_get0_factors(k->key, &p, &q); - return p != NULL; /* XXX/yawning: Should we check q? */ -#else /* !(defined(OPENSSL_1_1_API)) */ - return k && k->key && k->key->p; -#endif /* defined(OPENSSL_1_1_API) */ -} - -/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */ -crypto_pk_t * -crypto_new_pk_from_rsa_(RSA *rsa) -{ - crypto_pk_t *env; - tor_assert(rsa); - env = tor_malloc(sizeof(crypto_pk_t)); - env->refs = 1; - env->key = rsa; - return env; -} - -/** Helper, used by tor-gencert.c. Return the RSA from a - * crypto_pk_t. */ -RSA * -crypto_pk_get_rsa_(crypto_pk_t *env) -{ - return env->key; -} - -/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff - * private is set, include the private-key portion of the key. Return a valid - * pointer on success, and NULL on failure. */ -MOCK_IMPL(EVP_PKEY *, -crypto_pk_get_evp_pkey_,(crypto_pk_t *env, int private)) -{ - RSA *key = NULL; - EVP_PKEY *pkey = NULL; - tor_assert(env->key); - if (private) { - if (!(key = RSAPrivateKey_dup(env->key))) - goto error; - } else { - if (!(key = RSAPublicKey_dup(env->key))) - goto error; - } - if (!(pkey = EVP_PKEY_new())) - goto error; - if (!(EVP_PKEY_assign_RSA(pkey, key))) - goto error; - return pkey; - error: - if (pkey) - EVP_PKEY_free(pkey); - if (key) - RSA_free(key); - return NULL; -} - -/** Allocate and return storage for a public key. The key itself will not yet - * be set. - */ -MOCK_IMPL(crypto_pk_t *, -crypto_pk_new,(void)) -{ - RSA *rsa; - - rsa = RSA_new(); - tor_assert(rsa); - return crypto_new_pk_from_rsa_(rsa); -} - -/** Release a reference to an asymmetric key; when all the references - * are released, free the key. - */ -void -crypto_pk_free_(crypto_pk_t *env) -{ - if (!env) - return; - - if (--env->refs > 0) - return; - tor_assert(env->refs == 0); - - if (env->key) - RSA_free(env->key); - - tor_free(env); -} - -/** Generate a <b>bits</b>-bit new public/private keypair in <b>env</b>. - * Return 0 on success, -1 on failure. - */ -MOCK_IMPL(int, -crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits)) -{ - tor_assert(env); - - if (env->key) { - RSA_free(env->key); - env->key = NULL; - } - - { - BIGNUM *e = BN_new(); - RSA *r = NULL; - if (!e) - goto done; - if (! BN_set_word(e, 65537)) - goto done; - r = RSA_new(); - if (!r) - goto done; - if (RSA_generate_key_ex(r, bits, e, NULL) == -1) - goto done; - - env->key = r; - r = NULL; - done: - if (e) - BN_clear_free(e); - if (r) - RSA_free(r); - } - - if (!env->key) { - crypto_log_errors(LOG_WARN, "generating RSA key"); - return -1; - } - - return 0; -} - -/** A PEM callback that always reports a failure to get a password */ -static int -pem_no_password_cb(char *buf, int size, int rwflag, void *u) -{ - (void)buf; - (void)size; - (void)rwflag; - (void)u; - return -1; -} - -/** Read a PEM-encoded private key from the <b>len</b>-byte string <b>s</b> - * into <b>env</b>. Return 0 on success, -1 on failure. If len is -1, - * the string is nul-terminated. - */ -int -crypto_pk_read_private_key_from_string(crypto_pk_t *env, - const char *s, ssize_t len) -{ - BIO *b; - - tor_assert(env); - tor_assert(s); - tor_assert(len < INT_MAX && len < SSIZE_T_CEILING); - - /* Create a read-only memory BIO, backed by the string 's' */ - b = BIO_new_mem_buf((char*)s, (int)len); - if (!b) - return -1; - - if (env->key) - RSA_free(env->key); - - env->key = PEM_read_bio_RSAPrivateKey(b,NULL,pem_no_password_cb,NULL); - - BIO_free(b); - - if (!env->key) { - crypto_log_errors(LOG_WARN, "Error parsing private key"); - return -1; - } - return 0; -} - -/** Read a PEM-encoded private key from the file named by - * <b>keyfile</b> into <b>env</b>. Return 0 on success, -1 on failure. - */ -int -crypto_pk_read_private_key_from_filename(crypto_pk_t *env, - const char *keyfile) -{ - char *contents; - int r; - - /* Read the file into a string. */ - contents = read_file_to_str(keyfile, 0, NULL); - if (!contents) { - log_warn(LD_CRYPTO, "Error reading private key from \"%s\"", keyfile); - return -1; - } - - /* Try to parse it. */ - r = crypto_pk_read_private_key_from_string(env, contents, -1); - memwipe(contents, 0, strlen(contents)); - tor_free(contents); - if (r) - return -1; /* read_private_key_from_string already warned, so we don't.*/ - - /* Make sure it's valid. */ - if (crypto_pk_check_key(env) <= 0) - return -1; - - return 0; -} - -/** Helper function to implement crypto_pk_write_*_key_to_string. Return 0 on - * success, -1 on failure. */ -static int -crypto_pk_write_key_to_string_impl(crypto_pk_t *env, char **dest, - size_t *len, int is_public) -{ - BUF_MEM *buf; - BIO *b; - int r; - - tor_assert(env); - tor_assert(env->key); - tor_assert(dest); - - b = BIO_new(BIO_s_mem()); /* Create a memory BIO */ - if (!b) - return -1; - - /* Now you can treat b as if it were a file. Just use the - * PEM_*_bio_* functions instead of the non-bio variants. - */ - if (is_public) - r = PEM_write_bio_RSAPublicKey(b, env->key); - else - r = PEM_write_bio_RSAPrivateKey(b, env->key, NULL,NULL,0,NULL,NULL); - - if (!r) { - crypto_log_errors(LOG_WARN, "writing RSA key to string"); - BIO_free(b); - return -1; - } - - BIO_get_mem_ptr(b, &buf); - - *dest = tor_malloc(buf->length+1); - memcpy(*dest, buf->data, buf->length); - (*dest)[buf->length] = 0; /* nul terminate it */ - *len = buf->length; - - BIO_free(b); - - return 0; -} - -/** PEM-encode the public key portion of <b>env</b> and write it to a - * newly allocated string. On success, set *<b>dest</b> to the new - * string, *<b>len</b> to the string's length, and return 0. On - * failure, return -1. - */ -int -crypto_pk_write_public_key_to_string(crypto_pk_t *env, char **dest, - size_t *len) -{ - return crypto_pk_write_key_to_string_impl(env, dest, len, 1); -} - -/** PEM-encode the private key portion of <b>env</b> and write it to a - * newly allocated string. On success, set *<b>dest</b> to the new - * string, *<b>len</b> to the string's length, and return 0. On - * failure, return -1. - */ -int -crypto_pk_write_private_key_to_string(crypto_pk_t *env, char **dest, - size_t *len) -{ - return crypto_pk_write_key_to_string_impl(env, dest, len, 0); -} - -/** Read a PEM-encoded public key from the first <b>len</b> characters of - * <b>src</b>, and store the result in <b>env</b>. Return 0 on success, -1 on - * failure. - */ -int -crypto_pk_read_public_key_from_string(crypto_pk_t *env, const char *src, - size_t len) -{ - BIO *b; - - tor_assert(env); - tor_assert(src); - tor_assert(len<INT_MAX); - - b = BIO_new(BIO_s_mem()); /* Create a memory BIO */ - if (!b) - return -1; - - BIO_write(b, src, (int)len); - - if (env->key) - RSA_free(env->key); - env->key = PEM_read_bio_RSAPublicKey(b, NULL, pem_no_password_cb, NULL); - BIO_free(b); - if (!env->key) { - crypto_log_errors(LOG_WARN, "reading public key from string"); - return -1; - } - - return 0; -} - -/** Write the private key from <b>env</b> into the file named by <b>fname</b>, - * PEM-encoded. Return 0 on success, -1 on failure. - */ -int -crypto_pk_write_private_key_to_filename(crypto_pk_t *env, - const char *fname) -{ - BIO *bio; - char *cp; - long len; - char *s; - int r; - - tor_assert(crypto_pk_private_ok(env)); - - if (!(bio = BIO_new(BIO_s_mem()))) - return -1; - if (PEM_write_bio_RSAPrivateKey(bio, env->key, NULL,NULL,0,NULL,NULL) - == 0) { - crypto_log_errors(LOG_WARN, "writing private key"); - BIO_free(bio); - return -1; - } - len = BIO_get_mem_data(bio, &cp); - tor_assert(len >= 0); - s = tor_malloc(len+1); - memcpy(s, cp, len); - s[len]='\0'; - r = write_str_to_file(fname, s, 0); - BIO_free(bio); - memwipe(s, 0, strlen(s)); - tor_free(s); - return r; -} - -/** Return true iff <b>env</b> has a valid key. - */ -int -crypto_pk_check_key(crypto_pk_t *env) -{ - int r; - tor_assert(env); - - r = RSA_check_key(env->key); - if (r <= 0) - crypto_log_errors(LOG_WARN,"checking RSA key"); - return r; -} - -/** Return true iff <b>key</b> contains the private-key portion of the RSA - * key. */ -int -crypto_pk_key_is_private(const crypto_pk_t *key) -{ - tor_assert(key); - return crypto_pk_private_ok(key); -} - -/** Return true iff <b>env</b> contains a public key whose public exponent - * equals 65537. - */ -int -crypto_pk_public_exponent_ok(crypto_pk_t *env) -{ - tor_assert(env); - tor_assert(env->key); - - const BIGNUM *e; - -#ifdef OPENSSL_1_1_API - const BIGNUM *n, *d; - RSA_get0_key(env->key, &n, &e, &d); -#else - e = env->key->e; -#endif /* defined(OPENSSL_1_1_API) */ - return BN_is_word(e, 65537); -} - -/** Compare the public-key components of a and b. Return less than 0 - * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is - * considered to be less than all non-NULL keys, and equal to itself. - * - * Note that this may leak information about the keys through timing. - */ -int -crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b) -{ - int result; - char a_is_non_null = (a != NULL) && (a->key != NULL); - char b_is_non_null = (b != NULL) && (b->key != NULL); - char an_argument_is_null = !a_is_non_null | !b_is_non_null; - - result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null)); - if (an_argument_is_null) - return result; - - const BIGNUM *a_n, *a_e; - const BIGNUM *b_n, *b_e; - -#ifdef OPENSSL_1_1_API - const BIGNUM *a_d, *b_d; - RSA_get0_key(a->key, &a_n, &a_e, &a_d); - RSA_get0_key(b->key, &b_n, &b_e, &b_d); -#else - a_n = a->key->n; - a_e = a->key->e; - b_n = b->key->n; - b_e = b->key->e; -#endif /* defined(OPENSSL_1_1_API) */ - - tor_assert(a_n != NULL && a_e != NULL); - tor_assert(b_n != NULL && b_e != NULL); - - result = BN_cmp(a_n, b_n); - if (result) - return result; - return BN_cmp(a_e, b_e); -} - -/** Compare the public-key components of a and b. Return non-zero iff - * a==b. A NULL key is considered to be distinct from all non-NULL - * keys, and equal to itself. - * - * Note that this may leak information about the keys through timing. - */ -int -crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b) -{ - return (crypto_pk_cmp_keys(a, b) == 0); -} - -/** Return the size of the public key modulus in <b>env</b>, in bytes. */ -size_t -crypto_pk_keysize(const crypto_pk_t *env) -{ - tor_assert(env); - tor_assert(env->key); - - return (size_t) RSA_size((RSA*)env->key); -} - -/** Return the size of the public key modulus of <b>env</b>, in bits. */ -int -crypto_pk_num_bits(crypto_pk_t *env) -{ - tor_assert(env); - tor_assert(env->key); - -#ifdef OPENSSL_1_1_API - /* It's so stupid that there's no other way to check that n is valid - * before calling RSA_bits(). - */ - const BIGNUM *n, *e, *d; - RSA_get0_key(env->key, &n, &e, &d); - tor_assert(n != NULL); - - return RSA_bits(env->key); -#else /* !(defined(OPENSSL_1_1_API)) */ - tor_assert(env->key->n); - return BN_num_bits(env->key->n); -#endif /* defined(OPENSSL_1_1_API) */ -} - -/** Increase the reference count of <b>env</b>, and return it. - */ -crypto_pk_t * -crypto_pk_dup_key(crypto_pk_t *env) -{ - tor_assert(env); - tor_assert(env->key); - - env->refs++; - return env; -} - -#ifdef TOR_UNIT_TESTS -/** For testing: replace dest with src. (Dest must have a refcount - * of 1) */ -void -crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src) -{ - tor_assert(dest); - tor_assert(dest->refs == 1); - tor_assert(src); - RSA_free(dest->key); - dest->key = RSAPrivateKey_dup(src->key); -} -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Make a real honest-to-goodness copy of <b>env</b>, and return it. - * Returns NULL on failure. */ -crypto_pk_t * -crypto_pk_copy_full(crypto_pk_t *env) -{ - RSA *new_key; - int privatekey = 0; - tor_assert(env); - tor_assert(env->key); - - if (crypto_pk_private_ok(env)) { - new_key = RSAPrivateKey_dup(env->key); - privatekey = 1; - } else { - new_key = RSAPublicKey_dup(env->key); - } - if (!new_key) { - /* LCOV_EXCL_START - * - * We can't cause RSA*Key_dup() to fail, so we can't really test this. - */ - log_err(LD_CRYPTO, "Unable to duplicate a %s key: openssl failed.", - privatekey?"private":"public"); - crypto_log_errors(LOG_ERR, - privatekey ? "Duplicating a private key" : - "Duplicating a public key"); - tor_fragile_assert(); - return NULL; - /* LCOV_EXCL_STOP */ - } - - return crypto_new_pk_from_rsa_(new_key); -} - -/** Perform a hybrid (public/secret) encryption on <b>fromlen</b> - * bytes of data from <b>from</b>, with padding type 'padding', - * storing the results on <b>to</b>. - * - * Returns the number of bytes written on success, -1 on failure. - * - * The encrypted data consists of: - * - The source data, padded and encrypted with the public key, if the - * padded source data is no longer than the public key, and <b>force</b> - * is false, OR - * - The beginning of the source data prefixed with a 16-byte symmetric key, - * padded and encrypted with the public key; followed by the rest of - * the source data encrypted in AES-CTR mode with the symmetric key. - * - * NOTE that this format does not authenticate the symmetrically encrypted - * part of the data, and SHOULD NOT BE USED for new protocols. - */ -int -crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, - char *to, size_t tolen, - const char *from, - size_t fromlen, - int padding, int force) -{ - int overhead, outlen, r; - size_t pkeylen, symlen; - crypto_cipher_t *cipher = NULL; - char *buf = NULL; - - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - overhead = crypto_get_rsa_padding_overhead(crypto_get_rsa_padding(padding)); - pkeylen = crypto_pk_keysize(env); - - if (!force && fromlen+overhead <= pkeylen) { - /* It all fits in a single encrypt. */ - return crypto_pk_public_encrypt(env,to, - tolen, - from,fromlen,padding); - } - tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN); - tor_assert(tolen >= pkeylen); - - char key[CIPHER_KEY_LEN]; - crypto_rand(key, sizeof(key)); /* generate a new key. */ - cipher = crypto_cipher_new(key); - - buf = tor_malloc(pkeylen+1); - memcpy(buf, key, CIPHER_KEY_LEN); - memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN); - - /* Length of symmetrically encrypted data. */ - symlen = fromlen-(pkeylen-overhead-CIPHER_KEY_LEN); - - outlen = crypto_pk_public_encrypt(env,to,tolen,buf,pkeylen-overhead,padding); - if (outlen!=(int)pkeylen) { - goto err; - } - r = crypto_cipher_encrypt(cipher, to+outlen, - from+pkeylen-overhead-CIPHER_KEY_LEN, symlen); - - if (r<0) goto err; - memwipe(buf, 0, pkeylen); - memwipe(key, 0, sizeof(key)); - tor_free(buf); - crypto_cipher_free(cipher); - tor_assert(outlen+symlen < INT_MAX); - return (int)(outlen + symlen); - err: - - memwipe(buf, 0, pkeylen); - memwipe(key, 0, sizeof(key)); - tor_free(buf); - crypto_cipher_free(cipher); - return -1; -} - -/** Invert crypto_pk_obsolete_public_hybrid_encrypt. Returns the number of - * bytes written on success, -1 on failure. - * - * NOTE that this format does not authenticate the symmetrically encrypted - * part of the data, and SHOULD NOT BE USED for new protocols. - */ -int -crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, - char *to, - size_t tolen, - const char *from, - size_t fromlen, - int padding, int warnOnFailure) -{ - int outlen, r; - size_t pkeylen; - crypto_cipher_t *cipher = NULL; - char *buf = NULL; - - tor_assert(fromlen < SIZE_T_CEILING); - pkeylen = crypto_pk_keysize(env); - - if (fromlen <= pkeylen) { - return crypto_pk_private_decrypt(env,to,tolen,from,fromlen,padding, - warnOnFailure); - } - - buf = tor_malloc(pkeylen); - outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding, - warnOnFailure); - if (outlen<0) { - log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO, - "Error decrypting public-key data"); - goto err; - } - if (outlen < CIPHER_KEY_LEN) { - log_fn(warnOnFailure?LOG_WARN:LOG_INFO, LD_CRYPTO, - "No room for a symmetric key"); - goto err; - } - cipher = crypto_cipher_new(buf); - if (!cipher) { - goto err; - } - memcpy(to,buf+CIPHER_KEY_LEN,outlen-CIPHER_KEY_LEN); - outlen -= CIPHER_KEY_LEN; - tor_assert(tolen - outlen >= fromlen - pkeylen); - r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen); - if (r<0) - goto err; - memwipe(buf,0,pkeylen); - tor_free(buf); - crypto_cipher_free(cipher); - tor_assert(outlen + fromlen < INT_MAX); - return (int)(outlen + (fromlen-pkeylen)); - err: - memwipe(buf,0,pkeylen); - tor_free(buf); - crypto_cipher_free(cipher); - return -1; -} - -/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key - * in <b>env</b>, using the padding method <b>padding</b>. On success, - * write the result to <b>to</b>, and return the number of bytes - * written. On failure, return -1. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -int -crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen, int padding) -{ - int r; - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen<INT_MAX); - tor_assert(tolen >= crypto_pk_keysize(env)); - - r = RSA_public_encrypt((int)fromlen, - (unsigned char*)from, (unsigned char*)to, - env->key, crypto_get_rsa_padding(padding)); - if (r<0) { - crypto_log_errors(LOG_WARN, "performing RSA encryption"); - return -1; - } - return r; -} - -/** Decrypt <b>fromlen</b> bytes from <b>from</b> with the private key - * in <b>env</b>, using the padding method <b>padding</b>. On success, - * write the result to <b>to</b>, and return the number of bytes - * written. On failure, return -1. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -int -crypto_pk_private_decrypt(crypto_pk_t *env, char *to, - size_t tolen, - const char *from, size_t fromlen, - int padding, int warnOnFailure) -{ - int r; - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(env->key); - tor_assert(fromlen<INT_MAX); - tor_assert(tolen >= crypto_pk_keysize(env)); - if (!crypto_pk_key_is_private(env)) - /* Not a private key */ - return -1; - - r = RSA_private_decrypt((int)fromlen, - (unsigned char*)from, (unsigned char*)to, - env->key, crypto_get_rsa_padding(padding)); - - if (r<0) { - crypto_log_errors(warnOnFailure?LOG_WARN:LOG_DEBUG, - "performing RSA decryption"); - return -1; - } - return r; -} - -/** Check the signature in <b>from</b> (<b>fromlen</b> bytes long) with the - * public key in <b>env</b>, using PKCS1 padding. On success, write the - * signed data to <b>to</b>, and return the number of bytes written. - * On failure, return -1. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -MOCK_IMPL(int, -crypto_pk_public_checksig,(const crypto_pk_t *env, char *to, - size_t tolen, - const char *from, size_t fromlen)) -{ - int r; - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - tor_assert(tolen >= crypto_pk_keysize(env)); - r = RSA_public_decrypt((int)fromlen, - (unsigned char*)from, (unsigned char*)to, - env->key, RSA_PKCS1_PADDING); - - if (r<0) { - crypto_log_errors(LOG_INFO, "checking RSA signature"); - return -1; - } - return r; -} - -/** Sign <b>fromlen</b> bytes of data from <b>from</b> with the private key in - * <b>env</b>, using PKCS1 padding. On success, write the signature to - * <b>to</b>, and return the number of bytes written. On failure, return - * -1. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -int -crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen) -{ - int r; - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - tor_assert(tolen >= crypto_pk_keysize(env)); - if (!crypto_pk_key_is_private(env)) - /* Not a private key */ - return -1; - - r = RSA_private_encrypt((int)fromlen, - (unsigned char*)from, (unsigned char*)to, - (RSA*)env->key, RSA_PKCS1_PADDING); - if (r<0) { - crypto_log_errors(LOG_WARN, "generating RSA signature"); - return -1; - } - return r; -} - -/** ASN.1-encode the public portion of <b>pk</b> into <b>dest</b>. - * Return -1 on error, or the number of characters used on success. - */ -int -crypto_pk_asn1_encode(const crypto_pk_t *pk, char *dest, size_t dest_len) -{ - int len; - unsigned char *buf = NULL; - - len = i2d_RSAPublicKey(pk->key, &buf); - if (len < 0 || buf == NULL) - return -1; - - if ((size_t)len > dest_len || dest_len > SIZE_T_CEILING) { - OPENSSL_free(buf); - return -1; - } - /* We don't encode directly into 'dest', because that would be illegal - * type-punning. (C99 is smarter than me, C99 is smarter than me...) - */ - memcpy(dest,buf,len); - OPENSSL_free(buf); - return len; -} - -/** Decode an ASN.1-encoded public key from <b>str</b>; return the result on - * success and NULL on failure. - */ -crypto_pk_t * -crypto_pk_asn1_decode(const char *str, size_t len) -{ - RSA *rsa; - unsigned char *buf; - const unsigned char *cp; - cp = buf = tor_malloc(len); - memcpy(buf,str,len); - rsa = d2i_RSAPublicKey(NULL, &cp, len); - tor_free(buf); - if (!rsa) { - crypto_log_errors(LOG_WARN,"decoding public key"); - return NULL; - } - return crypto_new_pk_from_rsa_(rsa); -} - -/** Given a private or public key <b>pk</b>, put a fingerprint of the - * public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1 bytes of - * space). Return 0 on success, -1 on failure. - * - * Fingerprints are computed as the SHA1 digest of the ASN.1 encoding - * of the public key, converted to hexadecimal, in upper case, with a - * space after every four digits. - * - * If <b>add_space</b> is false, omit the spaces. - */ -int -crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space) -{ - char digest[DIGEST_LEN]; - char hexdigest[HEX_DIGEST_LEN+1]; - if (crypto_pk_get_digest(pk, digest)) { - return -1; - } - base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN); - if (add_space) { - crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest); - } else { - strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1); - } - return 0; -} - -/** Given a private or public key <b>pk</b>, put a hashed fingerprint of - * the public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1 - * bytes of space). Return 0 on success, -1 on failure. - * - * Hashed fingerprints are computed as the SHA1 digest of the SHA1 digest - * of the ASN.1 encoding of the public key, converted to hexadecimal, in - * upper case. - */ -int -crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out) -{ - char digest[DIGEST_LEN], hashed_digest[DIGEST_LEN]; - if (crypto_pk_get_digest(pk, digest)) { - return -1; - } - if (crypto_digest(hashed_digest, digest, DIGEST_LEN) < 0) { - return -1; - } - base16_encode(fp_out, FINGERPRINT_LEN + 1, hashed_digest, DIGEST_LEN); - return 0; -} - -/** Check a siglen-byte long signature at <b>sig</b> against - * <b>datalen</b> bytes of data at <b>data</b>, using the public key - * in <b>env</b>. Return 0 if <b>sig</b> is a correct signature for - * SHA1(data). Else return -1. - */ -MOCK_IMPL(int, -crypto_pk_public_checksig_digest,(crypto_pk_t *env, const char *data, - size_t datalen, const char *sig, - size_t siglen)) -{ - char digest[DIGEST_LEN]; - char *buf; - size_t buflen; - int r; - - tor_assert(env); - tor_assert(data); - tor_assert(sig); - tor_assert(datalen < SIZE_T_CEILING); - tor_assert(siglen < SIZE_T_CEILING); - - if (crypto_digest(digest,data,datalen)<0) { - log_warn(LD_BUG, "couldn't compute digest"); - return -1; - } - buflen = crypto_pk_keysize(env); - buf = tor_malloc(buflen); - r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen); - if (r != DIGEST_LEN) { - log_warn(LD_CRYPTO, "Invalid signature"); - tor_free(buf); - return -1; - } - if (tor_memneq(buf, digest, DIGEST_LEN)) { - log_warn(LD_CRYPTO, "Signature mismatched with digest."); - tor_free(buf); - return -1; - } - tor_free(buf); - - return 0; -} - -/** Compute a SHA1 digest of <b>fromlen</b> bytes of data stored at - * <b>from</b>; sign the data with the private key in <b>env</b>, and - * store it in <b>to</b>. Return the number of bytes written on - * success, and -1 on failure. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -int -crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen) -{ - int r; - char digest[DIGEST_LEN]; - if (crypto_digest(digest,from,fromlen)<0) - return -1; - r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN); - memwipe(digest, 0, sizeof(digest)); - return r; -} - -/** Given a private or public key <b>pk</b>, put a SHA1 hash of the - * public key into <b>digest_out</b> (must have DIGEST_LEN bytes of space). - * Return 0 on success, -1 on failure. - */ -int -crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out) -{ - char *buf; - size_t buflen; - int len; - int rv = -1; - - buflen = crypto_pk_keysize(pk)*2; - buf = tor_malloc(buflen); - len = crypto_pk_asn1_encode(pk, buf, buflen); - if (len < 0) - goto done; - - if (crypto_digest(digest_out, buf, len) < 0) - goto done; - - rv = 0; - done: - tor_free(buf); - return rv; -} - -/** Compute all digests of the DER encoding of <b>pk</b>, and store them - * in <b>digests_out</b>. Return 0 on success, -1 on failure. */ -int -crypto_pk_get_common_digests(crypto_pk_t *pk, common_digests_t *digests_out) -{ - char *buf; - size_t buflen; - int len; - int rv = -1; - - buflen = crypto_pk_keysize(pk)*2; - buf = tor_malloc(buflen); - len = crypto_pk_asn1_encode(pk, buf, buflen); - if (len < 0) - goto done; - - if (crypto_common_digests(digests_out, (char*)buf, len) < 0) - goto done; - - rv = 0; - done: - tor_free(buf); - return rv; -} - -/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the - * Base64 encoding of the DER representation of the private key as a NUL - * terminated string, and return it via <b>priv_out</b>. Return 0 on - * success, -1 on failure. - * - * It is the caller's responsibility to sanitize and free the resulting buffer. - */ -int -crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out) -{ - unsigned char *der = NULL; - int der_len; - int ret = -1; - - *priv_out = NULL; - - der_len = i2d_RSAPrivateKey(pk->key, &der); - if (der_len < 0 || der == NULL) - return ret; - - size_t priv_len = base64_encode_size(der_len, 0) + 1; - char *priv = tor_malloc_zero(priv_len); - if (base64_encode(priv, priv_len, (char *)der, der_len, 0) >= 0) { - *priv_out = priv; - ret = 0; - } else { - tor_free(priv); - } - - memwipe(der, 0, der_len); - OPENSSL_free(der); - return ret; -} - -/** Given a string containing the Base64 encoded DER representation of the - * private key <b>str</b>, decode and return the result on success, or NULL - * on failure. - */ -crypto_pk_t * -crypto_pk_base64_decode(const char *str, size_t len) -{ - crypto_pk_t *pk = NULL; - - char *der = tor_malloc_zero(len + 1); - int der_len = base64_decode(der, len, str, len); - if (der_len <= 0) { - log_warn(LD_CRYPTO, "Stored RSA private key seems corrupted (base64)."); - goto out; - } - - const unsigned char *dp = (unsigned char*)der; /* Shut the compiler up. */ - RSA *rsa = d2i_RSAPrivateKey(NULL, &dp, der_len); - if (!rsa) { - crypto_log_errors(LOG_WARN, "decoding private key"); - goto out; - } - - pk = crypto_new_pk_from_rsa_(rsa); - - /* Make sure it's valid. */ - if (crypto_pk_check_key(pk) <= 0) { - crypto_pk_free(pk); - pk = NULL; - goto out; - } - - out: - memwipe(der, 0, len + 1); - tor_free(der); - return pk; -} - diff --git a/src/common/crypto_rsa.h b/src/common/crypto_rsa.h deleted file mode 100644 index e952089318..0000000000 --- a/src/common/crypto_rsa.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_rsa.h - * - * \brief Headers for crypto_rsa.c - **/ - -#ifndef TOR_CRYPTO_RSA_H -#define TOR_CRYPTO_RSA_H - -#include "orconfig.h" - -#include "crypto_digest.h" -#include <stdio.h> -#include "torint.h" -#include "testsupport.h" -#include "compat.h" -#include "util.h" -#include "torlog.h" - -/** Length of our public keys. */ -#define PK_BYTES (1024/8) - -/** Constant used to indicate OAEP padding for public-key encryption */ -#define PK_PKCS1_OAEP_PADDING 60002 - -/** Number of bytes added for PKCS1-OAEP padding. */ -#define PKCS1_OAEP_PADDING_OVERHEAD 42 - -/** A public key, or a public/private key-pair. */ -typedef struct crypto_pk_t crypto_pk_t; - -/* RSA environment setup */ -MOCK_DECL(crypto_pk_t *,crypto_pk_new,(void)); -void crypto_pk_free_(crypto_pk_t *env); -#define crypto_pk_free(pk) FREE_AND_NULL(crypto_pk_t, crypto_pk_free_, (pk)) -int crypto_get_rsa_padding_overhead(int padding); -int crypto_get_rsa_padding(int padding); - -/* public key crypto */ -MOCK_DECL(int, crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits)); -#define crypto_pk_generate_key(env) \ - crypto_pk_generate_key_with_bits((env), (PK_BYTES*8)) - -int crypto_pk_read_private_key_from_filename(crypto_pk_t *env, - const char *keyfile); -int crypto_pk_write_public_key_to_string(crypto_pk_t *env, - char **dest, size_t *len); -int crypto_pk_write_private_key_to_string(crypto_pk_t *env, - char **dest, size_t *len); -int crypto_pk_read_public_key_from_string(crypto_pk_t *env, - const char *src, size_t len); -int crypto_pk_read_private_key_from_string(crypto_pk_t *env, - const char *s, ssize_t len); -int crypto_pk_write_private_key_to_filename(crypto_pk_t *env, - const char *fname); - -int crypto_pk_check_key(crypto_pk_t *env); -int crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b); -int crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b); -size_t crypto_pk_keysize(const crypto_pk_t *env); -int crypto_pk_num_bits(crypto_pk_t *env); -crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig); -crypto_pk_t *crypto_pk_copy_full(crypto_pk_t *orig); -int crypto_pk_key_is_private(const crypto_pk_t *key); -int crypto_pk_public_exponent_ok(crypto_pk_t *env); -int crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, char *to, - size_t tolen, - const char *from, size_t fromlen, - int padding, int force); -int crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, char *to, - size_t tolen, - const char *from, size_t fromlen, - int padding, int warnOnFailure); -int crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen, int padding); -int crypto_pk_private_decrypt(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen, - int padding, int warnOnFailure); -MOCK_DECL(int, crypto_pk_public_checksig,(const crypto_pk_t *env, - char *to, size_t tolen, - const char *from, size_t fromlen)); -int crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen); -int crypto_pk_asn1_encode(const crypto_pk_t *pk, char *dest, size_t dest_len); -crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len); -int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space); -int crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out); - -MOCK_DECL(int, crypto_pk_public_checksig_digest,(crypto_pk_t *env, - const char *data, size_t datalen, const char *sig, size_t siglen)); -int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen); -int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out); -int crypto_pk_get_common_digests(crypto_pk_t *pk, - common_digests_t *digests_out); -int crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out); -crypto_pk_t *crypto_pk_base64_decode(const char *str, size_t len); - -/* Prototypes for private functions only used by tortls.c, crypto.c, and the - * unit tests. */ -struct rsa_st; -struct rsa_st *crypto_pk_get_rsa_(crypto_pk_t *env); -crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa); -MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_evp_pkey_,(crypto_pk_t *env, - int private)); -struct evp_pkey_st; - -#ifdef TOR_UNIT_TESTS -void crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src); -#endif - -#endif - diff --git a/src/common/crypto_s2k.c b/src/common/crypto_s2k.c deleted file mode 100644 index 8543760ec5..0000000000 --- a/src/common/crypto_s2k.c +++ /dev/null @@ -1,475 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_s2k.c - * - * \brief Functions for deriving keys from human-readable passphrases. - */ - -#define CRYPTO_S2K_PRIVATE - -#include "compat.h" -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_rand.h" -#include "crypto_s2k.h" -#include "crypto_util.h" -#include "util.h" - -#include <openssl/evp.h> - -#if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT) -#define HAVE_SCRYPT -#include <libscrypt.h> -#endif - -/* Encoded secrets take the form: - - u8 type; - u8 salt_and_parameters[depends on type]; - u8 key[depends on type]; - - As a special case, if the encoded secret is exactly 29 bytes long, - type 0 is understood. - - Recognized types are: - 00 -- RFC2440. salt_and_parameters is 9 bytes. key is 20 bytes. - salt_and_parameters is 8 bytes random salt, - 1 byte iteration info. - 01 -- PKBDF2_SHA1. salt_and_parameters is 17 bytes. key is 20 bytes. - salt_and_parameters is 16 bytes random salt, - 1 byte iteration info. - 02 -- SCRYPT_SALSA208_SHA256. salt_and_parameters is 18 bytes. key is - 32 bytes. - salt_and_parameters is 18 bytes random salt, 2 bytes iteration - info. -*/ - -#define S2K_TYPE_RFC2440 0 -#define S2K_TYPE_PBKDF2 1 -#define S2K_TYPE_SCRYPT 2 - -#define PBKDF2_SPEC_LEN 17 -#define PBKDF2_KEY_LEN 20 - -#define SCRYPT_SPEC_LEN 18 -#define SCRYPT_KEY_LEN 32 - -/** Given an algorithm ID (one of S2K_TYPE_*), return the length of the - * specifier part of it, without the prefix type byte. Return -1 if it is not - * a valid algorithm ID. */ -static int -secret_to_key_spec_len(uint8_t type) -{ - switch (type) { - case S2K_TYPE_RFC2440: - return S2K_RFC2440_SPECIFIER_LEN; - case S2K_TYPE_PBKDF2: - return PBKDF2_SPEC_LEN; - case S2K_TYPE_SCRYPT: - return SCRYPT_SPEC_LEN; - default: - return -1; - } -} - -/** Given an algorithm ID (one of S2K_TYPE_*), return the length of the - * its preferred output. */ -static int -secret_to_key_key_len(uint8_t type) -{ - switch (type) { - case S2K_TYPE_RFC2440: - return DIGEST_LEN; - case S2K_TYPE_PBKDF2: - return DIGEST_LEN; - case S2K_TYPE_SCRYPT: - return DIGEST256_LEN; - // LCOV_EXCL_START - default: - tor_fragile_assert(); - return -1; - // LCOV_EXCL_STOP - } -} - -/** Given a specifier in <b>spec_and_key</b> of length - * <b>spec_and_key_len</b>, along with its prefix algorithm ID byte, and along - * with a key if <b>key_included</b> is true, check whether the whole - * specifier-and-key is of valid length, and return the algorithm type if it - * is. Set *<b>legacy_out</b> to 1 iff this is a legacy password hash or - * legacy specifier. Return an error code on failure. - */ -static int -secret_to_key_get_type(const uint8_t *spec_and_key, size_t spec_and_key_len, - int key_included, int *legacy_out) -{ - size_t legacy_len = S2K_RFC2440_SPECIFIER_LEN; - uint8_t type; - int total_len; - - if (key_included) - legacy_len += DIGEST_LEN; - - if (spec_and_key_len == legacy_len) { - *legacy_out = 1; - return S2K_TYPE_RFC2440; - } - - *legacy_out = 0; - if (spec_and_key_len == 0) - return S2K_BAD_LEN; - - type = spec_and_key[0]; - total_len = secret_to_key_spec_len(type); - if (total_len < 0) - return S2K_BAD_ALGORITHM; - if (key_included) { - int keylen = secret_to_key_key_len(type); - if (keylen < 0) - return S2K_BAD_ALGORITHM; - total_len += keylen; - } - - if ((size_t)total_len + 1 == spec_and_key_len) - return type; - else - return S2K_BAD_LEN; -} - -/** - * Write a new random s2k specifier of type <b>type</b>, without prefixing - * type byte, to <b>spec_out</b>, which must have enough room. May adjust - * parameter choice based on <b>flags</b>. - */ -static int -make_specifier(uint8_t *spec_out, uint8_t type, unsigned flags) -{ - int speclen = secret_to_key_spec_len(type); - if (speclen < 0) - return S2K_BAD_ALGORITHM; - - crypto_rand((char*)spec_out, speclen); - switch (type) { - case S2K_TYPE_RFC2440: - /* Hash 64 k of data. */ - spec_out[S2K_RFC2440_SPECIFIER_LEN-1] = 96; - break; - case S2K_TYPE_PBKDF2: - /* 131 K iterations */ - spec_out[PBKDF2_SPEC_LEN-1] = 17; - break; - case S2K_TYPE_SCRYPT: - if (flags & S2K_FLAG_LOW_MEM) { - /* N = 1<<12 */ - spec_out[SCRYPT_SPEC_LEN-2] = 12; - } else { - /* N = 1<<15 */ - spec_out[SCRYPT_SPEC_LEN-2] = 15; - } - /* r = 8; p = 2. */ - spec_out[SCRYPT_SPEC_LEN-1] = (3u << 4) | (1u << 0); - break; - // LCOV_EXCL_START - we should have returned above. - default: - tor_fragile_assert(); - return S2K_BAD_ALGORITHM; - // LCOV_EXCL_STOP - } - - return speclen; -} - -/** Implement RFC2440-style iterated-salted S2K conversion: convert the - * <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte - * <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier - * are a salt; the 9th byte describes how much iteration to do. - * If <b>key_out_len</b> > DIGEST_LEN, use HDKF to expand the result. - */ -void -secret_to_key_rfc2440(char *key_out, size_t key_out_len, const char *secret, - size_t secret_len, const char *s2k_specifier) -{ - crypto_digest_t *d; - uint8_t c; - size_t count, tmplen; - char *tmp; - uint8_t buf[DIGEST_LEN]; - tor_assert(key_out_len < SIZE_T_CEILING); - -#define EXPBIAS 6 - c = s2k_specifier[8]; - count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS); -#undef EXPBIAS - - d = crypto_digest_new(); - tmplen = 8+secret_len; - tmp = tor_malloc(tmplen); - memcpy(tmp,s2k_specifier,8); - memcpy(tmp+8,secret,secret_len); - secret_len += 8; - while (count) { - if (count >= secret_len) { - crypto_digest_add_bytes(d, tmp, secret_len); - count -= secret_len; - } else { - crypto_digest_add_bytes(d, tmp, count); - count = 0; - } - } - crypto_digest_get_digest(d, (char*)buf, sizeof(buf)); - - if (key_out_len <= sizeof(buf)) { - memcpy(key_out, buf, key_out_len); - } else { - crypto_expand_key_material_rfc5869_sha256(buf, DIGEST_LEN, - (const uint8_t*)s2k_specifier, 8, - (const uint8_t*)"EXPAND", 6, - (uint8_t*)key_out, key_out_len); - } - memwipe(tmp, 0, tmplen); - memwipe(buf, 0, sizeof(buf)); - tor_free(tmp); - crypto_digest_free(d); -} - -/** - * Helper: given a valid specifier without prefix type byte in <b>spec</b>, - * whose length must be correct, and given a secret passphrase <b>secret</b> - * of length <b>secret_len</b>, compute the key and store it into - * <b>key_out</b>, which must have enough room for secret_to_key_key_len(type) - * bytes. Return the number of bytes written on success and an error code - * on failure. - */ -STATIC int -secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len, - const uint8_t *spec, size_t spec_len, - const char *secret, size_t secret_len, - int type) -{ - int rv; - if (key_out_len > INT_MAX) - return S2K_BAD_LEN; - - switch (type) { - case S2K_TYPE_RFC2440: - secret_to_key_rfc2440((char*)key_out, key_out_len, secret, secret_len, - (const char*)spec); - return (int)key_out_len; - - case S2K_TYPE_PBKDF2: { - uint8_t log_iters; - if (spec_len < 1 || secret_len > INT_MAX || spec_len > INT_MAX) - return S2K_BAD_LEN; - log_iters = spec[spec_len-1]; - if (log_iters > 31) - return S2K_BAD_PARAMS; - rv = PKCS5_PBKDF2_HMAC_SHA1(secret, (int)secret_len, - spec, (int)spec_len-1, - (1<<log_iters), - (int)key_out_len, key_out); - if (rv < 0) - return S2K_FAILED; - return (int)key_out_len; - } - - case S2K_TYPE_SCRYPT: { -#ifdef HAVE_SCRYPT - uint8_t log_N, log_r, log_p; - uint64_t N; - uint32_t r, p; - if (spec_len < 2) - return S2K_BAD_LEN; - log_N = spec[spec_len-2]; - log_r = (spec[spec_len-1]) >> 4; - log_p = (spec[spec_len-1]) & 15; - if (log_N > 63) - return S2K_BAD_PARAMS; - N = ((uint64_t)1) << log_N; - r = 1u << log_r; - p = 1u << log_p; - rv = libscrypt_scrypt((const uint8_t*)secret, secret_len, - spec, spec_len-2, N, r, p, key_out, key_out_len); - if (rv != 0) - return S2K_FAILED; - return (int)key_out_len; -#else /* !(defined(HAVE_SCRYPT)) */ - return S2K_NO_SCRYPT_SUPPORT; -#endif /* defined(HAVE_SCRYPT) */ - } - default: - return S2K_BAD_ALGORITHM; - } -} - -/** - * Given a specifier previously constructed with secret_to_key_make_specifier - * in <b>spec</b> of length <b>spec_len</b>, and a secret password in - * <b>secret</b> of length <b>secret_len</b>, generate <b>key_out_len</b> - * bytes of cryptographic material in <b>key_out</b>. The native output of - * the secret-to-key function will be truncated if key_out_len is short, and - * expanded with HKDF if key_out_len is long. Returns S2K_OKAY on success, - * and an error code on failure. - */ -int -secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len, - const uint8_t *spec, size_t spec_len, - const char *secret, size_t secret_len) -{ - int legacy_format = 0; - int type = secret_to_key_get_type(spec, spec_len, 0, &legacy_format); - int r; - - if (type < 0) - return type; -#ifndef HAVE_SCRYPT - if (type == S2K_TYPE_SCRYPT) - return S2K_NO_SCRYPT_SUPPORT; - #endif - - if (! legacy_format) { - ++spec; - --spec_len; - } - - r = secret_to_key_compute_key(key_out, key_out_len, spec, spec_len, - secret, secret_len, type); - if (r < 0) - return r; - else - return S2K_OKAY; -} - -/** - * Construct a new s2k algorithm specifier and salt in <b>buf</b>, according - * to the bitwise-or of some S2K_FLAG_* options in <b>flags</b>. Up to - * <b>buf_len</b> bytes of storage may be used in <b>buf</b>. Return the - * number of bytes used on success and an error code on failure. - */ -int -secret_to_key_make_specifier(uint8_t *buf, size_t buf_len, unsigned flags) -{ - int rv; - int spec_len; -#ifdef HAVE_SCRYPT - uint8_t type = S2K_TYPE_SCRYPT; -#else - uint8_t type = S2K_TYPE_RFC2440; -#endif - - if (flags & S2K_FLAG_NO_SCRYPT) - type = S2K_TYPE_RFC2440; - if (flags & S2K_FLAG_USE_PBKDF2) - type = S2K_TYPE_PBKDF2; - - spec_len = secret_to_key_spec_len(type); - - if ((int)buf_len < spec_len + 1) - return S2K_TRUNCATED; - - buf[0] = type; - rv = make_specifier(buf+1, type, flags); - if (rv < 0) - return rv; - else - return rv + 1; -} - -/** - * Hash a passphrase from <b>secret</b> of length <b>secret_len</b>, according - * to the bitwise-or of some S2K_FLAG_* options in <b>flags</b>, and store the - * hash along with salt and hashing parameters into <b>buf</b>. Up to - * <b>buf_len</b> bytes of storage may be used in <b>buf</b>. Set - * *<b>len_out</b> to the number of bytes used and return S2K_OKAY on success; - * and return an error code on failure. - */ -int -secret_to_key_new(uint8_t *buf, - size_t buf_len, - size_t *len_out, - const char *secret, size_t secret_len, - unsigned flags) -{ - int key_len; - int spec_len; - int type; - int rv; - - spec_len = secret_to_key_make_specifier(buf, buf_len, flags); - - if (spec_len < 0) - return spec_len; - - type = buf[0]; - key_len = secret_to_key_key_len(type); - - if (key_len < 0) - return key_len; - - if ((int)buf_len < key_len + spec_len) - return S2K_TRUNCATED; - - rv = secret_to_key_compute_key(buf + spec_len, key_len, - buf + 1, spec_len-1, - secret, secret_len, type); - if (rv < 0) - return rv; - - *len_out = spec_len + key_len; - - return S2K_OKAY; -} - -/** - * Given a hashed passphrase in <b>spec_and_key</b> of length - * <b>spec_and_key_len</b> as generated by secret_to_key_new(), verify whether - * it is a hash of the passphrase <b>secret</b> of length <b>secret_len</b>. - * Return S2K_OKAY on a match, S2K_BAD_SECRET on a well-formed hash that - * doesn't match this secret, and another error code on other errors. - */ -int -secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len, - const char *secret, size_t secret_len) -{ - int is_legacy = 0; - int type = secret_to_key_get_type(spec_and_key, spec_and_key_len, - 1, &is_legacy); - uint8_t buf[32]; - int spec_len; - int key_len; - int rv; - - if (type < 0) - return type; - - if (! is_legacy) { - spec_and_key++; - spec_and_key_len--; - } - - spec_len = secret_to_key_spec_len(type); - key_len = secret_to_key_key_len(type); - tor_assert(spec_len > 0); - tor_assert(key_len > 0); - tor_assert(key_len <= (int) sizeof(buf)); - tor_assert((int)spec_and_key_len == spec_len + key_len); - rv = secret_to_key_compute_key(buf, key_len, - spec_and_key, spec_len, - secret, secret_len, type); - if (rv < 0) - goto done; - - if (tor_memeq(buf, spec_and_key + spec_len, key_len)) - rv = S2K_OKAY; - else - rv = S2K_BAD_SECRET; - - done: - memwipe(buf, 0, sizeof(buf)); - return rv; -} - diff --git a/src/common/crypto_s2k.h b/src/common/crypto_s2k.h deleted file mode 100644 index 849ff59ce8..0000000000 --- a/src/common/crypto_s2k.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CRYPTO_S2K_H_INCLUDED -#define TOR_CRYPTO_S2K_H_INCLUDED - -#include <stdio.h> -#include "torint.h" - -/** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the - * 9th describes how much iteration to do. */ -#define S2K_RFC2440_SPECIFIER_LEN 9 -void secret_to_key_rfc2440( - char *key_out, size_t key_out_len, const char *secret, - size_t secret_len, const char *s2k_specifier); - -/** Flag for secret-to-key function: do not use scrypt. */ -#define S2K_FLAG_NO_SCRYPT (1u<<0) -/** Flag for secret-to-key functions: if using a memory-tuned s2k function, - * assume that we have limited memory. */ -#define S2K_FLAG_LOW_MEM (1u<<1) -/** Flag for secret-to-key functions: force use of pbkdf2. Without this, we - * default to scrypt, then RFC2440. */ -#define S2K_FLAG_USE_PBKDF2 (1u<<2) - -/** Maximum possible output length from secret_to_key_new. */ -#define S2K_MAXLEN 64 - -/** Error code from secret-to-key functions: all is well */ -#define S2K_OKAY 0 -/** Error code from secret-to-key functions: generic failure */ -#define S2K_FAILED -1 -/** Error code from secret-to-key functions: provided secret didn't match */ -#define S2K_BAD_SECRET -2 -/** Error code from secret-to-key functions: didn't recognize the algorithm */ -#define S2K_BAD_ALGORITHM -3 -/** Error code from secret-to-key functions: specifier wasn't valid */ -#define S2K_BAD_PARAMS -4 -/** Error code from secret-to-key functions: compiled without scrypt */ -#define S2K_NO_SCRYPT_SUPPORT -5 -/** Error code from secret-to-key functions: not enough space to write output. - */ -#define S2K_TRUNCATED -6 -/** Error code from secret-to-key functions: Wrong length for specifier. */ -#define S2K_BAD_LEN -7 - -int secret_to_key_new(uint8_t *buf, - size_t buf_len, - size_t *len_out, - const char *secret, size_t secret_len, - unsigned flags); - -int secret_to_key_make_specifier(uint8_t *buf, size_t buf_len, unsigned flags); - -int secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len, - const char *secret, size_t secret_len); - -int secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len, - const uint8_t *spec, size_t spec_len, - const char *secret, size_t secret_len); - -#ifdef CRYPTO_S2K_PRIVATE -STATIC int secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len, - const uint8_t *spec, size_t spec_len, - const char *secret, size_t secret_len, - int type); -#endif /* defined(CRYPTO_S2K_PRIVATE) */ - -#endif /* !defined(TOR_CRYPTO_S2K_H_INCLUDED) */ - diff --git a/src/common/crypto_util.c b/src/common/crypto_util.c deleted file mode 100644 index b0d5b6b2f7..0000000000 --- a/src/common/crypto_util.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_util.c - * - * \brief Common cryptographic utilities. - **/ - -#ifndef CRYPTO_UTIL_PRIVATE -#define CRYPTO_UTIL_PRIVATE - -#include "crypto_util.h" - -#include <string.h> - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <wincrypt.h> -#endif /* defined(_WIN32) */ - -#include "util.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/crypto.h> - -ENABLE_GCC_WARNING(redundant-decls) - -/** - * Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to - * the value <b>byte</b>. - * If <b>mem</b> is NULL or <b>sz</b> is zero, nothing happens. - * - * This function is preferable to memset, since many compilers will happily - * optimize out memset() when they can convince themselves that the data being - * cleared will never be read. - * - * Right now, our convention is to use this function when we are wiping data - * that's about to become inaccessible, such as stack buffers that are about - * to go out of scope or structures that are about to get freed. (In - * practice, it appears that the compilers we're currently using will optimize - * out the memset()s for stack-allocated buffers, but not those for - * about-to-be-freed structures. That could change, though, so we're being - * wary.) If there are live reads for the data, then you can just use - * memset(). - */ -void -memwipe(void *mem, uint8_t byte, size_t sz) -{ - if (sz == 0) { - return; - } - /* If sz is nonzero, then mem must not be NULL. */ - tor_assert(mem != NULL); - - /* Data this large is likely to be an underflow. */ - tor_assert(sz < SIZE_T_CEILING); - - /* Because whole-program-optimization exists, we may not be able to just - * have this function call "memset". A smart compiler could inline it, then - * eliminate dead memsets, and declare itself to be clever. */ - -#if defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY) - /* Here's what you do on windows. */ - SecureZeroMemory(mem,sz); -#elif defined(HAVE_RTLSECUREZEROMEMORY) - RtlSecureZeroMemory(mem,sz); -#elif defined(HAVE_EXPLICIT_BZERO) - /* The BSDs provide this. */ - explicit_bzero(mem, sz); -#elif defined(HAVE_MEMSET_S) - /* This is in the C99 standard. */ - memset_s(mem, sz, 0, sz); -#else - /* This is a slow and ugly function from OpenSSL that fills 'mem' with junk - * based on the pointer value, then uses that junk to update a global - * variable. It's an elaborate ruse to trick the compiler into not - * optimizing out the "wipe this memory" code. Read it if you like zany - * programming tricks! In later versions of Tor, we should look for better - * not-optimized-out memory wiping stuff... - * - * ...or maybe not. In practice, there are pure-asm implementations of - * OPENSSL_cleanse() on most platforms, which ought to do the job. - **/ - - OPENSSL_cleanse(mem, sz); -#endif /* defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY) || ... */ - - /* Just in case some caller of memwipe() is relying on getting a buffer - * filled with a particular value, fill the buffer. - * - * If this function gets inlined, this memset might get eliminated, but - * that's okay: We only care about this particular memset in the case where - * the caller should have been using memset(), and the memset() wouldn't get - * eliminated. In other words, this is here so that we won't break anything - * if somebody accidentally calls memwipe() instead of memset(). - **/ - memset(mem, byte, sz); -} - -#endif /* !defined(CRYPTO_UTIL_PRIVATE) */ - diff --git a/src/common/crypto_util.h b/src/common/crypto_util.h deleted file mode 100644 index 922942b371..0000000000 --- a/src/common/crypto_util.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_util.h - * - * \brief Common functions for cryptographic routines. - **/ - -#ifndef TOR_CRYPTO_UTIL_H -#define TOR_CRYPTO_UTIL_H - -#include "torint.h" - -/** OpenSSL-based utility functions. */ -void memwipe(void *mem, uint8_t byte, size_t sz); - -#ifdef CRYPTO_UTIL_PRIVATE -#ifdef TOR_UNIT_TESTS -#endif /* defined(TOR_UNIT_TESTS) */ -#endif /* defined(CRYPTO_UTIL_PRIVATE) */ - -#endif /* !defined(TOR_CRYPTO_UTIL_H) */ - diff --git a/src/common/di_ops.c b/src/common/di_ops.c deleted file mode 100644 index 90e9357c8e..0000000000 --- a/src/common/di_ops.c +++ /dev/null @@ -1,274 +0,0 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file di_ops.c - * \brief Functions for data-independent operations. - **/ - -#include "orconfig.h" -#include "di_ops.h" -#include "torlog.h" -#include "util.h" - -/** - * Timing-safe version of memcmp. As memcmp, compare the <b>sz</b> bytes at - * <b>a</b> with the <b>sz</b> bytes at <b>b</b>, and return less than 0 if - * the bytes at <b>a</b> lexically precede those at <b>b</b>, 0 if the byte - * ranges are equal, and greater than zero if the bytes at <b>a</b> lexically - * follow those at <b>b</b>. - * - * This implementation differs from memcmp in that its timing behavior is not - * data-dependent: it should return in the same amount of time regardless of - * the contents of <b>a</b> and <b>b</b>. - */ -int -tor_memcmp(const void *a, const void *b, size_t len) -{ -#ifdef HAVE_TIMINGSAFE_MEMCMP - return timingsafe_memcmp(a, b, len); -#else - const uint8_t *x = a; - const uint8_t *y = b; - size_t i = len; - int retval = 0; - - /* This loop goes from the end of the arrays to the start. At the - * start of every iteration, before we decrement i, we have set - * "retval" equal to the result of memcmp(a+i,b+i,len-i). During the - * loop, we update retval by leaving it unchanged if x[i]==y[i] and - * setting it to x[i]-y[i] if x[i]!= y[i]. - * - * The following assumes we are on a system with two's-complement - * arithmetic. We check for this at configure-time with the check - * that sets USING_TWOS_COMPLEMENT. If we aren't two's complement, then - * torint.h will stop compilation with an error. - */ - while (i--) { - int v1 = x[i]; - int v2 = y[i]; - int equal_p = v1 ^ v2; - - /* The following sets bits 8 and above of equal_p to 'equal_p == - * 0', and thus to v1 == v2. (To see this, note that if v1 == - * v2, then v1^v2 == equal_p == 0, so equal_p-1 == -1, which is the - * same as ~0 on a two's-complement machine. Then note that if - * v1 != v2, then 0 < v1 ^ v2 < 256, so 0 <= equal_p - 1 < 255.) - */ - --equal_p; - - equal_p >>= 8; - /* Thanks to (sign-preserving) arithmetic shift, equal_p is now - * equal to -(v1 == v2), which is exactly what we need below. - * (Since we're assuming two's-complement arithmetic, -1 is the - * same as ~0 (all bits set).) - * - * (The result of an arithmetic shift on a negative value is - * actually implementation-defined in standard C. So how do we - * get away with assuming it? Easy. We check.) */ -#if ((-60 >> 8) != -1) -#error "According to cpp, right-shift doesn't perform sign-extension." -#endif -#ifndef RSHIFT_DOES_SIGN_EXTEND -#error "According to configure, right-shift doesn't perform sign-extension." -#endif - - /* If v1 == v2, equal_p is ~0, so this will leave retval - * unchanged; otherwise, equal_p is 0, so this will zero it. */ - retval &= equal_p; - - /* If v1 == v2, then this adds 0, and leaves retval unchanged. - * Otherwise, we just zeroed retval, so this sets it to v1 - v2. */ - retval += (v1 - v2); - - /* There. Now retval is equal to its previous value if v1 == v2, and - * equal to v1 - v2 if v1 != v2. */ - } - - return retval; -#endif /* defined(HAVE_TIMINGSAFE_MEMCMP) */ -} - -/** - * Timing-safe memory comparison. Return true if the <b>sz</b> bytes at - * <b>a</b> are the same as the <b>sz</b> bytes at <b>b</b>, and 0 otherwise. - * - * This implementation differs from !memcmp(a,b,sz) in that its timing - * behavior is not data-dependent: it should return in the same amount of time - * regardless of the contents of <b>a</b> and <b>b</b>. It differs from - * !tor_memcmp(a,b,sz) by being faster. - */ -int -tor_memeq(const void *a, const void *b, size_t sz) -{ - /* Treat a and b as byte ranges. */ - const uint8_t *ba = a, *bb = b; - uint32_t any_difference = 0; - while (sz--) { - /* Set byte_diff to all of those bits that are different in *ba and *bb, - * and advance both ba and bb. */ - const uint8_t byte_diff = *ba++ ^ *bb++; - - /* Set bits in any_difference if they are set in byte_diff. */ - any_difference |= byte_diff; - } - - /* Now any_difference is 0 if there are no bits different between - * a and b, and is nonzero if there are bits different between a - * and b. Now for paranoia's sake, let's convert it to 0 or 1. - * - * (If we say "!any_difference", the compiler might get smart enough - * to optimize-out our data-independence stuff above.) - * - * To unpack: - * - * If any_difference == 0: - * any_difference - 1 == ~0 - * (any_difference - 1) >> 8 == 0x00ffffff - * 1 & ((any_difference - 1) >> 8) == 1 - * - * If any_difference != 0: - * 0 < any_difference < 256, so - * 0 <= any_difference - 1 < 255 - * (any_difference - 1) >> 8 == 0 - * 1 & ((any_difference - 1) >> 8) == 0 - */ - - /*coverity[overflow]*/ - return 1 & ((any_difference - 1) >> 8); -} - -/* Implement di_digest256_map_t as a linked list of entries. */ -struct di_digest256_map_t { - struct di_digest256_map_t *next; - uint8_t key[32]; - void *val; -}; - -/** Release all storage held in <b>map</b>, calling free_fn on each value - * as we go. */ -void -dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn) -{ - while (map) { - di_digest256_map_t *victim = map; - map = map->next; - if (free_fn) - free_fn(victim->val); - tor_free(victim); - } -} - -/** Adjust the map at *<b>map</b>, adding an entry for <b>key</b> -> - * <b>val</b>, where <b>key</b> is a DIGEST256_LEN-byte key. - * - * The caller MUST NOT add a key that already appears in the map. - */ -void -dimap_add_entry(di_digest256_map_t **map, - const uint8_t *key, void *val) -{ - di_digest256_map_t *new_ent; - { - void *old_val = dimap_search(*map, key, NULL); - tor_assert(! old_val); - tor_assert(val); - } - new_ent = tor_malloc_zero(sizeof(di_digest256_map_t)); - new_ent->next = *map; - memcpy(new_ent->key, key, 32); - new_ent->val = val; - *map = new_ent; -} - -/** Search the map at <b>map</b> for an entry whose key is <b>key</b> (a - * DIGEST256_LEN-byte key) returning the corresponding value if we found one, - * and returning <b>dflt_val</b> if the key wasn't found. - * - * This operation takes an amount of time dependent only on the length of - * <b>map</b>, not on the position or presence of <b>key</b> within <b>map</b>. - */ -void * -dimap_search(const di_digest256_map_t *map, const uint8_t *key, - void *dflt_val) -{ - uintptr_t result = (uintptr_t)dflt_val; - - while (map) { - uintptr_t r = (uintptr_t) tor_memeq(map->key, key, 32); - r -= 1; /* Now r is (uintptr_t)-1 if memeq returned false, and - * 0 if memeq returned true. */ - - result &= r; - result |= ((uintptr_t)(map->val)) & ~r; - - map = map->next; - } - - return (void *)result; -} - -/** - * Return true iff the <b>sz</b> bytes at <b>mem</b> are all zero. Runs in - * time independent of the contents of <b>mem</b>. - */ -int -safe_mem_is_zero(const void *mem, size_t sz) -{ - uint32_t total = 0; - const uint8_t *ptr = mem; - - while (sz--) { - total |= *ptr++; - } - - /*coverity[overflow]*/ - return 1 & ((total - 1) >> 8); -} - -/** Time-invariant 64-bit greater-than; works on two integers in the range - * (0,INT64_MAX). */ -#if SIZEOF_VOID_P == 8 -#define gt_i64_timei(a,b) ((a) > (b)) -#else -static inline int -gt_i64_timei(uint64_t a, uint64_t b) -{ - int64_t diff = (int64_t) (b - a); - int res = diff >> 63; - return res & 1; -} -#endif /* SIZEOF_VOID_P == 8 */ - -/** - * Given an array of list of <b>n_entries</b> uint64_t values, whose sum is - * <b>total</b>, find the first i such that the total of all elements 0...i is - * greater than rand_val. - * - * Try to perform this operation in a constant-time way. - */ -int -select_array_member_cumulative_timei(const uint64_t *entries, int n_entries, - uint64_t total, uint64_t rand_val) -{ - int i, i_chosen=-1, n_chosen=0; - uint64_t total_so_far = 0; - - for (i = 0; i < n_entries; ++i) { - total_so_far += entries[i]; - if (gt_i64_timei(total_so_far, rand_val)) { - i_chosen = i; - n_chosen++; - /* Set rand_val to INT64_MAX rather than stopping the loop. This way, - * the time we spend in the loop does not leak which element we chose. */ - rand_val = INT64_MAX; - } - } - tor_assert(total_so_far == total); - tor_assert(n_chosen == 1); - tor_assert(i_chosen >= 0); - tor_assert(i_chosen < n_entries); - - return i_chosen; -} - diff --git a/src/common/di_ops.h b/src/common/di_ops.h deleted file mode 100644 index 67d9c9f0df..0000000000 --- a/src/common/di_ops.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file di_ops.h - * \brief Headers for di_ops.c - **/ - -#ifndef TOR_DI_OPS_H -#define TOR_DI_OPS_H - -#include "orconfig.h" -#include "torint.h" - -int tor_memcmp(const void *a, const void *b, size_t sz); -int tor_memeq(const void *a, const void *b, size_t sz); -#define tor_memneq(a,b,sz) (!tor_memeq((a),(b),(sz))) - -/** Alias for the platform's memcmp() function. This function is - * <em>not</em> data-independent: we define this alias so that we can - * mark cases where we are deliberately using a data-dependent memcmp() - * implementation. - */ -#define fast_memcmp(a,b,c) (memcmp((a),(b),(c))) -#define fast_memeq(a,b,c) (0==memcmp((a),(b),(c))) -#define fast_memneq(a,b,c) (0!=memcmp((a),(b),(c))) - -int safe_mem_is_zero(const void *mem, size_t sz); - -/** A type for a map from DIGEST256_LEN-byte blobs to void*, such that - * data lookups take an amount of time proportional only to the size - * of the map, and not to the position or presence of the item in the map. - * - * Not efficient for large maps! */ -typedef struct di_digest256_map_t di_digest256_map_t; -typedef void (*dimap_free_fn)(void *); - -void dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn); -#define dimap_free(map, free_fn) \ - do { \ - dimap_free_((map), (free_fn)); \ - (map) = NULL; \ - } while (0) -void dimap_add_entry(di_digest256_map_t **map, - const uint8_t *key, void *val); -void *dimap_search(const di_digest256_map_t *map, const uint8_t *key, - void *dflt_val); -int select_array_member_cumulative_timei(const uint64_t *entries, - int n_entries, - uint64_t total, uint64_t rand_val); - -#endif /* !defined(TOR_DI_OPS_H) */ - diff --git a/src/common/handles.h b/src/common/handles.h deleted file mode 100644 index aef8cd89ef..0000000000 --- a/src/common/handles.h +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file handles.h - * \brief Macros for C weak-handle implementation. - * - * A 'handle' is a pointer to an object that is allowed to go away while - * the handle stays alive. When you dereference the handle, you might get - * the object, or you might get "NULL". - * - * Use this pattern when an object has a single obvious lifespan, so you don't - * want to use reference counting, but when other objects might need to refer - * to the first object without caring about its lifetime. - * - * To enable a type to have handles, add a HANDLE_ENTRY() field in its - * definition, as in: - * - * struct walrus { - * HANDLE_ENTRY(wlr, walrus); - * // ... - * }; - * - * And invoke HANDLE_DECL(wlr, walrus, [static]) to declare the handle - * manipulation functions (typically in a header): - * - * // opaque handle to walrus. - * typedef struct wlr_handle_t wlr_handle_t; - * - * // make a new handle - * struct wlr_handle_t *wlr_handle_new(struct walrus *); - * - * // release a handle - * void wlr_handle_free(wlr_handle_t *); - * - * // return the pointed-to walrus, or NULL. - * struct walrus *wlr_handle_get(wlr_handle_t *). - * - * // call this function when you're about to free the walrus; - * // it invalidates all handles. (IF YOU DON'T, YOU WILL HAVE - * // DANGLING REFERENCES) - * void wlr_handles_clear(struct walrus *); - * - * Finally, use HANDLE_IMPL() to define the above functions in some - * appropriate C file: HANDLE_IMPL(wlr, walrus, [static]) - * - **/ - -#ifndef TOR_HANDLE_H -#define TOR_HANDLE_H - -#include "orconfig.h" -#include "tor_queue.h" -#include "util.h" - -#define HANDLE_ENTRY(name, structname) \ - struct name ## _handle_head_t *handle_head - -#define HANDLE_DECL(name, structname, linkage) \ - typedef struct name ## _handle_t name ## _handle_t; \ - linkage name ## _handle_t *name ## _handle_new(struct structname *object); \ - linkage void name ## _handle_free_(name ## _handle_t *); \ - linkage struct structname *name ## _handle_get(name ## _handle_t *); \ - linkage void name ## _handles_clear(struct structname *object); - -/* - * Implementation notes: there are lots of possible implementations here. We - * could keep a linked list of handles, each with a backpointer to the object, - * and set all of their backpointers to NULL when the object is freed. Or we - * could have the clear function invalidate the object, but not actually let - * the object get freed until the all the handles went away. We could even - * have a hash-table mapping unique identifiers to objects, and have each - * handle be a copy of the unique identifier. (We'll want to build that last - * one eventually if we want cross-process handles.) - * - * But instead we're opting for a single independent 'head' that knows how - * many handles there are, and where the object is (or isn't). This makes - * all of our functions O(1), and most as fast as a single pointer access. - * - * The handles themselves are opaque structures holding a pointer to the head. - * We could instead have each foo_handle_t* be identical to foo_handle_head_t - * *, and save some allocations ... but doing so would make handle leaks - * harder to debug. As it stands, every handle leak is a memory leak, and - * existing memory debugging tools should help with those. We can revisit - * this decision if handles are too slow. - */ - -#define HANDLE_IMPL(name, structname, linkage) \ - /* The 'head' object for a handle-accessible type. This object */ \ - /* persists for as long as the object, or any handles, exist. */ \ - typedef struct name ## _handle_head_t { \ - struct structname *object; /* pointed-to object, or NULL */ \ - unsigned int references; /* number of existing handles */ \ - } name ## _handle_head_t; \ - \ - struct name ## _handle_t { \ - struct name ## _handle_head_t *head; /* reference to the 'head'. */ \ - }; \ - \ - linkage struct name ## _handle_t * \ - name ## _handle_new(struct structname *object) \ - { \ - tor_assert(object); \ - name ## _handle_head_t *head = object->handle_head; \ - if (PREDICT_UNLIKELY(head == NULL)) { \ - head = object->handle_head = tor_malloc_zero(sizeof(*head)); \ - head->object = object; \ - } \ - name ## _handle_t *new_ref = tor_malloc_zero(sizeof(*new_ref)); \ - new_ref->head = head; \ - ++head->references; \ - return new_ref; \ - } \ - \ - linkage void \ - name ## _handle_free_(struct name ## _handle_t *ref) \ - { \ - if (! ref) return; \ - name ## _handle_head_t *head = ref->head; \ - tor_assert(head); \ - --head->references; \ - tor_free(ref); \ - if (head->object == NULL && head->references == 0) { \ - tor_free(head); \ - return; \ - } \ - } \ - \ - linkage struct structname * \ - name ## _handle_get(struct name ## _handle_t *ref) \ - { \ - tor_assert(ref); \ - name ## _handle_head_t *head = ref->head; \ - tor_assert(head); \ - return head->object; \ - } \ - \ - linkage void \ - name ## _handles_clear(struct structname *object) \ - { \ - tor_assert(object); \ - name ## _handle_head_t *head = object->handle_head; \ - if (! head) \ - return; \ - object->handle_head = NULL; \ - head->object = NULL; \ - if (head->references == 0) { \ - tor_free(head); \ - } \ - } - -#endif /* !defined(TOR_HANDLE_H) */ - diff --git a/src/common/include.am b/src/common/include.am deleted file mode 100644 index cfaf993674..0000000000 --- a/src/common/include.am +++ /dev/null @@ -1,213 +0,0 @@ - -noinst_LIBRARIES += \ - src/common/libor.a \ - src/common/libor-ctime.a \ - src/common/libor-crypto.a \ - src/common/libor-event.a - -if UNITTESTS_ENABLED -noinst_LIBRARIES += \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-crypto-testing.a \ - src/common/libor-event-testing.a -endif - -EXTRA_DIST += src/common/Makefile.nmake - -#CFLAGS = -Wall -Wpointer-arith -O2 -AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel - -if USE_OPENBSD_MALLOC -libor_extra_source=src/ext/OpenBSD_malloc_Linux.c -else -libor_extra_source= -endif - -src_common_libcurve25519_donna_a_CFLAGS= - -if BUILD_CURVE25519_DONNA -src_common_libcurve25519_donna_a_SOURCES=\ - src/ext/curve25519_donna/curve25519-donna.c -# See bug 13538 -- this code is known to have signed overflow issues. -src_common_libcurve25519_donna_a_CFLAGS+=\ - @F_OMIT_FRAME_POINTER@ @CFLAGS_CONSTTIME@ -noinst_LIBRARIES+=src/common/libcurve25519_donna.a -LIBDONNA=src/common/libcurve25519_donna.a -else -if BUILD_CURVE25519_DONNA_C64 -src_common_libcurve25519_donna_a_CFLAGS+=@CFLAGS_CONSTTIME@ -src_common_libcurve25519_donna_a_SOURCES=\ - src/ext/curve25519_donna/curve25519-donna-c64.c -noinst_LIBRARIES+=src/common/libcurve25519_donna.a -LIBDONNA=src/common/libcurve25519_donna.a -else -LIBDONNA= -endif -endif - -LIBDONNA += $(LIBED25519_REF10) -LIBDONNA += $(LIBED25519_DONNA) - -if THREADS_PTHREADS -threads_impl_source=src/common/compat_pthreads.c -endif -if THREADS_WIN32 -threads_impl_source=src/common/compat_winthreads.c -endif - -if BUILD_READPASSPHRASE_C -readpassphrase_source=src/ext/readpassphrase.c -else -readpassphrase_source= -endif - -if ADD_MULODI4 -mulodi4_source=src/ext/mulodi/mulodi4.c -else -mulodi4_source= -endif - -LIBOR_CTIME_A_SRC = \ - $(mulodi4_source) \ - src/ext/csiphash.c \ - src/common/di_ops.c - -src_common_libor_ctime_a_SOURCES = $(LIBOR_CTIME_A_SRC) -if UNITTESTS_ENABLED -src_common_libor_ctime_testing_a_SOURCES = $(LIBOR_CTIME_A_SRC) -else -src_common_libor_ctime_testing_a_SOURCES = -endif -src_common_libor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@ -src_common_libor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS) - -LIBOR_A_SRC = \ - src/common/address.c \ - src/common/address_set.c \ - src/common/backtrace.c \ - src/common/buffers.c \ - src/common/compat.c \ - src/common/compat_threads.c \ - src/common/compat_time.c \ - src/common/confline.c \ - src/common/container.c \ - src/common/log.c \ - src/common/memarea.c \ - src/common/pubsub.c \ - src/common/util.c \ - src/common/util_bug.c \ - src/common/util_format.c \ - src/common/util_process.c \ - src/common/sandbox.c \ - src/common/storagedir.c \ - src/common/token_bucket.c \ - src/common/workqueue.c \ - $(libor_extra_source) \ - $(threads_impl_source) \ - $(readpassphrase_source) - -src/common/src_common_libor_testing_a-log.$(OBJEXT) \ - src/common/log.$(OBJEXT): micro-revision.i - -LIBOR_CRYPTO_A_SRC = \ - src/common/aes.c \ - src/common/buffers_tls.c \ - src/common/compress.c \ - src/common/compress_lzma.c \ - src/common/compress_none.c \ - src/common/compress_zlib.c \ - src/common/compress_zstd.c \ - src/common/crypto.c \ - src/common/crypto_digest.c \ - src/common/crypto_format.c \ - src/common/crypto_openssl_mgt.c \ - src/common/crypto_pwbox.c \ - src/common/crypto_rand.c \ - src/common/crypto_rsa.c \ - src/common/crypto_s2k.c \ - src/common/crypto_util.c \ - src/common/tortls.c \ - src/common/crypto_curve25519.c \ - src/common/crypto_ed25519.c - -LIBOR_EVENT_A_SRC = \ - src/common/compat_libevent.c \ - src/common/procmon.c \ - src/common/timers.c \ - src/ext/timeouts/timeout.c - -src_common_libor_a_SOURCES = $(LIBOR_A_SRC) -src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) -src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SRC) - -if UNITTESTS_ENABLED -src_common_libor_testing_a_SOURCES = $(LIBOR_A_SRC) -src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) -src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SRC) -else -src_common_libor_testing_a_SOURCES = -src_common_libor_crypto_testing_a_SOURCES = -src_common_libor_event_testing_a_SOURCES = -endif - -src_common_libor_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_common_libor_crypto_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_common_libor_event_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) -src_common_libor_crypto_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) -src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) - -COMMONHEADERS = \ - src/common/address.h \ - src/common/address_set.h \ - src/common/backtrace.h \ - src/common/buffers.h \ - src/common/buffers_tls.h \ - src/common/aes.h \ - src/common/ciphers.inc \ - src/common/compat.h \ - src/common/compat_libevent.h \ - src/common/compat_openssl.h \ - src/common/compat_threads.h \ - src/common/compat_time.h \ - src/common/compress.h \ - src/common/compress_lzma.h \ - src/common/compress_none.h \ - src/common/compress_zlib.h \ - src/common/compress_zstd.h \ - src/common/confline.h \ - src/common/container.h \ - src/common/crypto.h \ - src/common/crypto_digest.h \ - src/common/crypto_curve25519.h \ - src/common/crypto_ed25519.h \ - src/common/crypto_format.h \ - src/common/crypto_openssl_mgt.h \ - src/common/crypto_pwbox.h \ - src/common/crypto_rand.h \ - src/common/crypto_rsa.h \ - src/common/crypto_s2k.h \ - src/common/crypto_util.h \ - src/common/di_ops.h \ - src/common/handles.h \ - src/common/memarea.h \ - src/common/linux_syscalls.inc \ - src/common/procmon.h \ - src/common/pubsub.h \ - src/common/sandbox.h \ - src/common/storagedir.h \ - src/common/testsupport.h \ - src/common/timers.h \ - src/common/token_bucket.h \ - src/common/torint.h \ - src/common/torlog.h \ - src/common/tortls.h \ - src/common/util.h \ - src/common/util_bug.h \ - src/common/util_format.h \ - src/common/util_process.h \ - src/common/workqueue.h - -noinst_HEADERS+= $(COMMONHEADERS) - diff --git a/src/common/linux_syscalls.inc b/src/common/linux_syscalls.inc deleted file mode 100644 index cf47c73809..0000000000 --- a/src/common/linux_syscalls.inc +++ /dev/null @@ -1,1153 +0,0 @@ -/* Automatically generated with - gen_linux_syscalls.pl /usr/include/asm/unistd*.h - Do not edit. - */ -static const struct { - int syscall_num; const char *syscall_name; -} SYSCALLS_BY_NUMBER[] = { -#ifdef __NR__llseek - { __NR__llseek, "_llseek" }, -#endif -#ifdef __NR__newselect - { __NR__newselect, "_newselect" }, -#endif -#ifdef __NR__sysctl - { __NR__sysctl, "_sysctl" }, -#endif -#ifdef __NR_accept - { __NR_accept, "accept" }, -#endif -#ifdef __NR_accept4 - { __NR_accept4, "accept4" }, -#endif -#ifdef __NR_access - { __NR_access, "access" }, -#endif -#ifdef __NR_acct - { __NR_acct, "acct" }, -#endif -#ifdef __NR_add_key - { __NR_add_key, "add_key" }, -#endif -#ifdef __NR_adjtimex - { __NR_adjtimex, "adjtimex" }, -#endif -#ifdef __NR_afs_syscall - { __NR_afs_syscall, "afs_syscall" }, -#endif -#ifdef __NR_alarm - { __NR_alarm, "alarm" }, -#endif -#ifdef __NR_arch_prctl - { __NR_arch_prctl, "arch_prctl" }, -#endif -#ifdef __NR_bdflush - { __NR_bdflush, "bdflush" }, -#endif -#ifdef __NR_bind - { __NR_bind, "bind" }, -#endif -#ifdef __NR_break - { __NR_break, "break" }, -#endif -#ifdef __NR_brk - { __NR_brk, "brk" }, -#endif -#ifdef __NR_capget - { __NR_capget, "capget" }, -#endif -#ifdef __NR_capset - { __NR_capset, "capset" }, -#endif -#ifdef __NR_chdir - { __NR_chdir, "chdir" }, -#endif -#ifdef __NR_chmod - { __NR_chmod, "chmod" }, -#endif -#ifdef __NR_chown - { __NR_chown, "chown" }, -#endif -#ifdef __NR_chown32 - { __NR_chown32, "chown32" }, -#endif -#ifdef __NR_chroot - { __NR_chroot, "chroot" }, -#endif -#ifdef __NR_clock_adjtime - { __NR_clock_adjtime, "clock_adjtime" }, -#endif -#ifdef __NR_clock_getres - { __NR_clock_getres, "clock_getres" }, -#endif -#ifdef __NR_clock_gettime - { __NR_clock_gettime, "clock_gettime" }, -#endif -#ifdef __NR_clock_nanosleep - { __NR_clock_nanosleep, "clock_nanosleep" }, -#endif -#ifdef __NR_clock_settime - { __NR_clock_settime, "clock_settime" }, -#endif -#ifdef __NR_clone - { __NR_clone, "clone" }, -#endif -#ifdef __NR_close - { __NR_close, "close" }, -#endif -#ifdef __NR_connect - { __NR_connect, "connect" }, -#endif -#ifdef __NR_creat - { __NR_creat, "creat" }, -#endif -#ifdef __NR_create_module - { __NR_create_module, "create_module" }, -#endif -#ifdef __NR_delete_module - { __NR_delete_module, "delete_module" }, -#endif -#ifdef __NR_dup - { __NR_dup, "dup" }, -#endif -#ifdef __NR_dup2 - { __NR_dup2, "dup2" }, -#endif -#ifdef __NR_dup3 - { __NR_dup3, "dup3" }, -#endif -#ifdef __NR_epoll_create - { __NR_epoll_create, "epoll_create" }, -#endif -#ifdef __NR_epoll_create1 - { __NR_epoll_create1, "epoll_create1" }, -#endif -#ifdef __NR_epoll_ctl - { __NR_epoll_ctl, "epoll_ctl" }, -#endif -#ifdef __NR_epoll_ctl_old - { __NR_epoll_ctl_old, "epoll_ctl_old" }, -#endif -#ifdef __NR_epoll_pwait - { __NR_epoll_pwait, "epoll_pwait" }, -#endif -#ifdef __NR_epoll_wait - { __NR_epoll_wait, "epoll_wait" }, -#endif -#ifdef __NR_epoll_wait_old - { __NR_epoll_wait_old, "epoll_wait_old" }, -#endif -#ifdef __NR_eventfd - { __NR_eventfd, "eventfd" }, -#endif -#ifdef __NR_eventfd2 - { __NR_eventfd2, "eventfd2" }, -#endif -#ifdef __NR_execve - { __NR_execve, "execve" }, -#endif -#ifdef __NR_exit - { __NR_exit, "exit" }, -#endif -#ifdef __NR_exit_group - { __NR_exit_group, "exit_group" }, -#endif -#ifdef __NR_faccessat - { __NR_faccessat, "faccessat" }, -#endif -#ifdef __NR_fadvise64 - { __NR_fadvise64, "fadvise64" }, -#endif -#ifdef __NR_fadvise64_64 - { __NR_fadvise64_64, "fadvise64_64" }, -#endif -#ifdef __NR_fallocate - { __NR_fallocate, "fallocate" }, -#endif -#ifdef __NR_fanotify_init - { __NR_fanotify_init, "fanotify_init" }, -#endif -#ifdef __NR_fanotify_mark - { __NR_fanotify_mark, "fanotify_mark" }, -#endif -#ifdef __NR_fchdir - { __NR_fchdir, "fchdir" }, -#endif -#ifdef __NR_fchmod - { __NR_fchmod, "fchmod" }, -#endif -#ifdef __NR_fchmodat - { __NR_fchmodat, "fchmodat" }, -#endif -#ifdef __NR_fchown - { __NR_fchown, "fchown" }, -#endif -#ifdef __NR_fchown32 - { __NR_fchown32, "fchown32" }, -#endif -#ifdef __NR_fchownat - { __NR_fchownat, "fchownat" }, -#endif -#ifdef __NR_fcntl - { __NR_fcntl, "fcntl" }, -#endif -#ifdef __NR_fcntl64 - { __NR_fcntl64, "fcntl64" }, -#endif -#ifdef __NR_fdatasync - { __NR_fdatasync, "fdatasync" }, -#endif -#ifdef __NR_fgetxattr - { __NR_fgetxattr, "fgetxattr" }, -#endif -#ifdef __NR_finit_module - { __NR_finit_module, "finit_module" }, -#endif -#ifdef __NR_flistxattr - { __NR_flistxattr, "flistxattr" }, -#endif -#ifdef __NR_flock - { __NR_flock, "flock" }, -#endif -#ifdef __NR_fork - { __NR_fork, "fork" }, -#endif -#ifdef __NR_fremovexattr - { __NR_fremovexattr, "fremovexattr" }, -#endif -#ifdef __NR_fsetxattr - { __NR_fsetxattr, "fsetxattr" }, -#endif -#ifdef __NR_fstat - { __NR_fstat, "fstat" }, -#endif -#ifdef __NR_fstat64 - { __NR_fstat64, "fstat64" }, -#endif -#ifdef __NR_fstatat64 - { __NR_fstatat64, "fstatat64" }, -#endif -#ifdef __NR_fstatfs - { __NR_fstatfs, "fstatfs" }, -#endif -#ifdef __NR_fstatfs64 - { __NR_fstatfs64, "fstatfs64" }, -#endif -#ifdef __NR_fsync - { __NR_fsync, "fsync" }, -#endif -#ifdef __NR_ftime - { __NR_ftime, "ftime" }, -#endif -#ifdef __NR_ftruncate - { __NR_ftruncate, "ftruncate" }, -#endif -#ifdef __NR_ftruncate64 - { __NR_ftruncate64, "ftruncate64" }, -#endif -#ifdef __NR_futex - { __NR_futex, "futex" }, -#endif -#ifdef __NR_futimesat - { __NR_futimesat, "futimesat" }, -#endif -#ifdef __NR_get_kernel_syms - { __NR_get_kernel_syms, "get_kernel_syms" }, -#endif -#ifdef __NR_get_mempolicy - { __NR_get_mempolicy, "get_mempolicy" }, -#endif -#ifdef __NR_get_robust_list - { __NR_get_robust_list, "get_robust_list" }, -#endif -#ifdef __NR_get_thread_area - { __NR_get_thread_area, "get_thread_area" }, -#endif -#ifdef __NR_getcpu - { __NR_getcpu, "getcpu" }, -#endif -#ifdef __NR_getcwd - { __NR_getcwd, "getcwd" }, -#endif -#ifdef __NR_getdents - { __NR_getdents, "getdents" }, -#endif -#ifdef __NR_getdents64 - { __NR_getdents64, "getdents64" }, -#endif -#ifdef __NR_getegid - { __NR_getegid, "getegid" }, -#endif -#ifdef __NR_getegid32 - { __NR_getegid32, "getegid32" }, -#endif -#ifdef __NR_geteuid - { __NR_geteuid, "geteuid" }, -#endif -#ifdef __NR_geteuid32 - { __NR_geteuid32, "geteuid32" }, -#endif -#ifdef __NR_getgid - { __NR_getgid, "getgid" }, -#endif -#ifdef __NR_getgid32 - { __NR_getgid32, "getgid32" }, -#endif -#ifdef __NR_getgroups - { __NR_getgroups, "getgroups" }, -#endif -#ifdef __NR_getgroups32 - { __NR_getgroups32, "getgroups32" }, -#endif -#ifdef __NR_getitimer - { __NR_getitimer, "getitimer" }, -#endif -#ifdef __NR_getpeername - { __NR_getpeername, "getpeername" }, -#endif -#ifdef __NR_getpgid - { __NR_getpgid, "getpgid" }, -#endif -#ifdef __NR_getpgrp - { __NR_getpgrp, "getpgrp" }, -#endif -#ifdef __NR_getpid - { __NR_getpid, "getpid" }, -#endif -#ifdef __NR_getpmsg - { __NR_getpmsg, "getpmsg" }, -#endif -#ifdef __NR_getppid - { __NR_getppid, "getppid" }, -#endif -#ifdef __NR_getpriority - { __NR_getpriority, "getpriority" }, -#endif -#ifdef __NR_getresgid - { __NR_getresgid, "getresgid" }, -#endif -#ifdef __NR_getresgid32 - { __NR_getresgid32, "getresgid32" }, -#endif -#ifdef __NR_getresuid - { __NR_getresuid, "getresuid" }, -#endif -#ifdef __NR_getresuid32 - { __NR_getresuid32, "getresuid32" }, -#endif -#ifdef __NR_getrlimit - { __NR_getrlimit, "getrlimit" }, -#endif -#ifdef __NR_getrusage - { __NR_getrusage, "getrusage" }, -#endif -#ifdef __NR_getsid - { __NR_getsid, "getsid" }, -#endif -#ifdef __NR_getsockname - { __NR_getsockname, "getsockname" }, -#endif -#ifdef __NR_getsockopt - { __NR_getsockopt, "getsockopt" }, -#endif -#ifdef __NR_gettid - { __NR_gettid, "gettid" }, -#endif -#ifdef __NR_gettimeofday - { __NR_gettimeofday, "gettimeofday" }, -#endif -#ifdef __NR_getuid - { __NR_getuid, "getuid" }, -#endif -#ifdef __NR_getuid32 - { __NR_getuid32, "getuid32" }, -#endif -#ifdef __NR_getxattr - { __NR_getxattr, "getxattr" }, -#endif -#ifdef __NR_gtty - { __NR_gtty, "gtty" }, -#endif -#ifdef __NR_idle - { __NR_idle, "idle" }, -#endif -#ifdef __NR_init_module - { __NR_init_module, "init_module" }, -#endif -#ifdef __NR_inotify_add_watch - { __NR_inotify_add_watch, "inotify_add_watch" }, -#endif -#ifdef __NR_inotify_init - { __NR_inotify_init, "inotify_init" }, -#endif -#ifdef __NR_inotify_init1 - { __NR_inotify_init1, "inotify_init1" }, -#endif -#ifdef __NR_inotify_rm_watch - { __NR_inotify_rm_watch, "inotify_rm_watch" }, -#endif -#ifdef __NR_io_cancel - { __NR_io_cancel, "io_cancel" }, -#endif -#ifdef __NR_io_destroy - { __NR_io_destroy, "io_destroy" }, -#endif -#ifdef __NR_io_getevents - { __NR_io_getevents, "io_getevents" }, -#endif -#ifdef __NR_io_setup - { __NR_io_setup, "io_setup" }, -#endif -#ifdef __NR_io_submit - { __NR_io_submit, "io_submit" }, -#endif -#ifdef __NR_ioctl - { __NR_ioctl, "ioctl" }, -#endif -#ifdef __NR_ioperm - { __NR_ioperm, "ioperm" }, -#endif -#ifdef __NR_iopl - { __NR_iopl, "iopl" }, -#endif -#ifdef __NR_ioprio_get - { __NR_ioprio_get, "ioprio_get" }, -#endif -#ifdef __NR_ioprio_set - { __NR_ioprio_set, "ioprio_set" }, -#endif -#ifdef __NR_ipc - { __NR_ipc, "ipc" }, -#endif -#ifdef __NR_kcmp - { __NR_kcmp, "kcmp" }, -#endif -#ifdef __NR_kexec_load - { __NR_kexec_load, "kexec_load" }, -#endif -#ifdef __NR_keyctl - { __NR_keyctl, "keyctl" }, -#endif -#ifdef __NR_kill - { __NR_kill, "kill" }, -#endif -#ifdef __NR_lchown - { __NR_lchown, "lchown" }, -#endif -#ifdef __NR_lchown32 - { __NR_lchown32, "lchown32" }, -#endif -#ifdef __NR_lgetxattr - { __NR_lgetxattr, "lgetxattr" }, -#endif -#ifdef __NR_link - { __NR_link, "link" }, -#endif -#ifdef __NR_linkat - { __NR_linkat, "linkat" }, -#endif -#ifdef __NR_listen - { __NR_listen, "listen" }, -#endif -#ifdef __NR_listxattr - { __NR_listxattr, "listxattr" }, -#endif -#ifdef __NR_llistxattr - { __NR_llistxattr, "llistxattr" }, -#endif -#ifdef __NR_lock - { __NR_lock, "lock" }, -#endif -#ifdef __NR_lookup_dcookie - { __NR_lookup_dcookie, "lookup_dcookie" }, -#endif -#ifdef __NR_lremovexattr - { __NR_lremovexattr, "lremovexattr" }, -#endif -#ifdef __NR_lseek - { __NR_lseek, "lseek" }, -#endif -#ifdef __NR_lsetxattr - { __NR_lsetxattr, "lsetxattr" }, -#endif -#ifdef __NR_lstat - { __NR_lstat, "lstat" }, -#endif -#ifdef __NR_lstat64 - { __NR_lstat64, "lstat64" }, -#endif -#ifdef __NR_madvise - { __NR_madvise, "madvise" }, -#endif -#ifdef __NR_mbind - { __NR_mbind, "mbind" }, -#endif -#ifdef __NR_migrate_pages - { __NR_migrate_pages, "migrate_pages" }, -#endif -#ifdef __NR_mincore - { __NR_mincore, "mincore" }, -#endif -#ifdef __NR_mkdir - { __NR_mkdir, "mkdir" }, -#endif -#ifdef __NR_mkdirat - { __NR_mkdirat, "mkdirat" }, -#endif -#ifdef __NR_mknod - { __NR_mknod, "mknod" }, -#endif -#ifdef __NR_mknodat - { __NR_mknodat, "mknodat" }, -#endif -#ifdef __NR_mlock - { __NR_mlock, "mlock" }, -#endif -#ifdef __NR_mlockall - { __NR_mlockall, "mlockall" }, -#endif -#ifdef __NR_mmap - { __NR_mmap, "mmap" }, -#endif -#ifdef __NR_mmap2 - { __NR_mmap2, "mmap2" }, -#endif -#ifdef __NR_modify_ldt - { __NR_modify_ldt, "modify_ldt" }, -#endif -#ifdef __NR_mount - { __NR_mount, "mount" }, -#endif -#ifdef __NR_move_pages - { __NR_move_pages, "move_pages" }, -#endif -#ifdef __NR_mprotect - { __NR_mprotect, "mprotect" }, -#endif -#ifdef __NR_mpx - { __NR_mpx, "mpx" }, -#endif -#ifdef __NR_mq_getsetattr - { __NR_mq_getsetattr, "mq_getsetattr" }, -#endif -#ifdef __NR_mq_notify - { __NR_mq_notify, "mq_notify" }, -#endif -#ifdef __NR_mq_open - { __NR_mq_open, "mq_open" }, -#endif -#ifdef __NR_mq_timedreceive - { __NR_mq_timedreceive, "mq_timedreceive" }, -#endif -#ifdef __NR_mq_timedsend - { __NR_mq_timedsend, "mq_timedsend" }, -#endif -#ifdef __NR_mq_unlink - { __NR_mq_unlink, "mq_unlink" }, -#endif -#ifdef __NR_mremap - { __NR_mremap, "mremap" }, -#endif -#ifdef __NR_msgctl - { __NR_msgctl, "msgctl" }, -#endif -#ifdef __NR_msgget - { __NR_msgget, "msgget" }, -#endif -#ifdef __NR_msgrcv - { __NR_msgrcv, "msgrcv" }, -#endif -#ifdef __NR_msgsnd - { __NR_msgsnd, "msgsnd" }, -#endif -#ifdef __NR_msync - { __NR_msync, "msync" }, -#endif -#ifdef __NR_munlock - { __NR_munlock, "munlock" }, -#endif -#ifdef __NR_munlockall - { __NR_munlockall, "munlockall" }, -#endif -#ifdef __NR_munmap - { __NR_munmap, "munmap" }, -#endif -#ifdef __NR_name_to_handle_at - { __NR_name_to_handle_at, "name_to_handle_at" }, -#endif -#ifdef __NR_nanosleep - { __NR_nanosleep, "nanosleep" }, -#endif -#ifdef __NR_newfstatat - { __NR_newfstatat, "newfstatat" }, -#endif -#ifdef __NR_nfsservctl - { __NR_nfsservctl, "nfsservctl" }, -#endif -#ifdef __NR_nice - { __NR_nice, "nice" }, -#endif -#ifdef __NR_oldfstat - { __NR_oldfstat, "oldfstat" }, -#endif -#ifdef __NR_oldlstat - { __NR_oldlstat, "oldlstat" }, -#endif -#ifdef __NR_oldolduname - { __NR_oldolduname, "oldolduname" }, -#endif -#ifdef __NR_oldstat - { __NR_oldstat, "oldstat" }, -#endif -#ifdef __NR_olduname - { __NR_olduname, "olduname" }, -#endif -#ifdef __NR_open - { __NR_open, "open" }, -#endif -#ifdef __NR_open_by_handle_at - { __NR_open_by_handle_at, "open_by_handle_at" }, -#endif -#ifdef __NR_openat - { __NR_openat, "openat" }, -#endif -#ifdef __NR_pause - { __NR_pause, "pause" }, -#endif -#ifdef __NR_perf_event_open - { __NR_perf_event_open, "perf_event_open" }, -#endif -#ifdef __NR_personality - { __NR_personality, "personality" }, -#endif -#ifdef __NR_pipe - { __NR_pipe, "pipe" }, -#endif -#ifdef __NR_pipe2 - { __NR_pipe2, "pipe2" }, -#endif -#ifdef __NR_pivot_root - { __NR_pivot_root, "pivot_root" }, -#endif -#ifdef __NR_poll - { __NR_poll, "poll" }, -#endif -#ifdef __NR_ppoll - { __NR_ppoll, "ppoll" }, -#endif -#ifdef __NR_prctl - { __NR_prctl, "prctl" }, -#endif -#ifdef __NR_pread64 - { __NR_pread64, "pread64" }, -#endif -#ifdef __NR_preadv - { __NR_preadv, "preadv" }, -#endif -#ifdef __NR_prlimit64 - { __NR_prlimit64, "prlimit64" }, -#endif -#ifdef __NR_process_vm_readv - { __NR_process_vm_readv, "process_vm_readv" }, -#endif -#ifdef __NR_process_vm_writev - { __NR_process_vm_writev, "process_vm_writev" }, -#endif -#ifdef __NR_prof - { __NR_prof, "prof" }, -#endif -#ifdef __NR_profil - { __NR_profil, "profil" }, -#endif -#ifdef __NR_pselect6 - { __NR_pselect6, "pselect6" }, -#endif -#ifdef __NR_ptrace - { __NR_ptrace, "ptrace" }, -#endif -#ifdef __NR_putpmsg - { __NR_putpmsg, "putpmsg" }, -#endif -#ifdef __NR_pwrite64 - { __NR_pwrite64, "pwrite64" }, -#endif -#ifdef __NR_pwritev - { __NR_pwritev, "pwritev" }, -#endif -#ifdef __NR_query_module - { __NR_query_module, "query_module" }, -#endif -#ifdef __NR_quotactl - { __NR_quotactl, "quotactl" }, -#endif -#ifdef __NR_read - { __NR_read, "read" }, -#endif -#ifdef __NR_readahead - { __NR_readahead, "readahead" }, -#endif -#ifdef __NR_readdir - { __NR_readdir, "readdir" }, -#endif -#ifdef __NR_readlink - { __NR_readlink, "readlink" }, -#endif -#ifdef __NR_readlinkat - { __NR_readlinkat, "readlinkat" }, -#endif -#ifdef __NR_readv - { __NR_readv, "readv" }, -#endif -#ifdef __NR_reboot - { __NR_reboot, "reboot" }, -#endif -#ifdef __NR_recvfrom - { __NR_recvfrom, "recvfrom" }, -#endif -#ifdef __NR_recvmmsg - { __NR_recvmmsg, "recvmmsg" }, -#endif -#ifdef __NR_recvmsg - { __NR_recvmsg, "recvmsg" }, -#endif -#ifdef __NR_remap_file_pages - { __NR_remap_file_pages, "remap_file_pages" }, -#endif -#ifdef __NR_removexattr - { __NR_removexattr, "removexattr" }, -#endif -#ifdef __NR_rename - { __NR_rename, "rename" }, -#endif -#ifdef __NR_renameat - { __NR_renameat, "renameat" }, -#endif -#ifdef __NR_request_key - { __NR_request_key, "request_key" }, -#endif -#ifdef __NR_restart_syscall - { __NR_restart_syscall, "restart_syscall" }, -#endif -#ifdef __NR_rmdir - { __NR_rmdir, "rmdir" }, -#endif -#ifdef __NR_rt_sigaction - { __NR_rt_sigaction, "rt_sigaction" }, -#endif -#ifdef __NR_rt_sigpending - { __NR_rt_sigpending, "rt_sigpending" }, -#endif -#ifdef __NR_rt_sigprocmask - { __NR_rt_sigprocmask, "rt_sigprocmask" }, -#endif -#ifdef __NR_rt_sigqueueinfo - { __NR_rt_sigqueueinfo, "rt_sigqueueinfo" }, -#endif -#ifdef __NR_rt_sigreturn - { __NR_rt_sigreturn, "rt_sigreturn" }, -#endif -#ifdef __NR_rt_sigsuspend - { __NR_rt_sigsuspend, "rt_sigsuspend" }, -#endif -#ifdef __NR_rt_sigtimedwait - { __NR_rt_sigtimedwait, "rt_sigtimedwait" }, -#endif -#ifdef __NR_rt_tgsigqueueinfo - { __NR_rt_tgsigqueueinfo, "rt_tgsigqueueinfo" }, -#endif -#ifdef __NR_sched_get_priority_max - { __NR_sched_get_priority_max, "sched_get_priority_max" }, -#endif -#ifdef __NR_sched_get_priority_min - { __NR_sched_get_priority_min, "sched_get_priority_min" }, -#endif -#ifdef __NR_sched_getaffinity - { __NR_sched_getaffinity, "sched_getaffinity" }, -#endif -#ifdef __NR_sched_getparam - { __NR_sched_getparam, "sched_getparam" }, -#endif -#ifdef __NR_sched_getscheduler - { __NR_sched_getscheduler, "sched_getscheduler" }, -#endif -#ifdef __NR_sched_rr_get_interval - { __NR_sched_rr_get_interval, "sched_rr_get_interval" }, -#endif -#ifdef __NR_sched_setaffinity - { __NR_sched_setaffinity, "sched_setaffinity" }, -#endif -#ifdef __NR_sched_setparam - { __NR_sched_setparam, "sched_setparam" }, -#endif -#ifdef __NR_sched_setscheduler - { __NR_sched_setscheduler, "sched_setscheduler" }, -#endif -#ifdef __NR_sched_yield - { __NR_sched_yield, "sched_yield" }, -#endif -#ifdef __NR_security - { __NR_security, "security" }, -#endif -#ifdef __NR_select - { __NR_select, "select" }, -#endif -#ifdef __NR_semctl - { __NR_semctl, "semctl" }, -#endif -#ifdef __NR_semget - { __NR_semget, "semget" }, -#endif -#ifdef __NR_semop - { __NR_semop, "semop" }, -#endif -#ifdef __NR_semtimedop - { __NR_semtimedop, "semtimedop" }, -#endif -#ifdef __NR_sendfile - { __NR_sendfile, "sendfile" }, -#endif -#ifdef __NR_sendfile64 - { __NR_sendfile64, "sendfile64" }, -#endif -#ifdef __NR_sendmmsg - { __NR_sendmmsg, "sendmmsg" }, -#endif -#ifdef __NR_sendmsg - { __NR_sendmsg, "sendmsg" }, -#endif -#ifdef __NR_sendto - { __NR_sendto, "sendto" }, -#endif -#ifdef __NR_set_mempolicy - { __NR_set_mempolicy, "set_mempolicy" }, -#endif -#ifdef __NR_set_robust_list - { __NR_set_robust_list, "set_robust_list" }, -#endif -#ifdef __NR_set_thread_area - { __NR_set_thread_area, "set_thread_area" }, -#endif -#ifdef __NR_set_tid_address - { __NR_set_tid_address, "set_tid_address" }, -#endif -#ifdef __NR_setdomainname - { __NR_setdomainname, "setdomainname" }, -#endif -#ifdef __NR_setfsgid - { __NR_setfsgid, "setfsgid" }, -#endif -#ifdef __NR_setfsgid32 - { __NR_setfsgid32, "setfsgid32" }, -#endif -#ifdef __NR_setfsuid - { __NR_setfsuid, "setfsuid" }, -#endif -#ifdef __NR_setfsuid32 - { __NR_setfsuid32, "setfsuid32" }, -#endif -#ifdef __NR_setgid - { __NR_setgid, "setgid" }, -#endif -#ifdef __NR_setgid32 - { __NR_setgid32, "setgid32" }, -#endif -#ifdef __NR_setgroups - { __NR_setgroups, "setgroups" }, -#endif -#ifdef __NR_setgroups32 - { __NR_setgroups32, "setgroups32" }, -#endif -#ifdef __NR_sethostname - { __NR_sethostname, "sethostname" }, -#endif -#ifdef __NR_setitimer - { __NR_setitimer, "setitimer" }, -#endif -#ifdef __NR_setns - { __NR_setns, "setns" }, -#endif -#ifdef __NR_setpgid - { __NR_setpgid, "setpgid" }, -#endif -#ifdef __NR_setpriority - { __NR_setpriority, "setpriority" }, -#endif -#ifdef __NR_setregid - { __NR_setregid, "setregid" }, -#endif -#ifdef __NR_setregid32 - { __NR_setregid32, "setregid32" }, -#endif -#ifdef __NR_setresgid - { __NR_setresgid, "setresgid" }, -#endif -#ifdef __NR_setresgid32 - { __NR_setresgid32, "setresgid32" }, -#endif -#ifdef __NR_setresuid - { __NR_setresuid, "setresuid" }, -#endif -#ifdef __NR_setresuid32 - { __NR_setresuid32, "setresuid32" }, -#endif -#ifdef __NR_setreuid - { __NR_setreuid, "setreuid" }, -#endif -#ifdef __NR_setreuid32 - { __NR_setreuid32, "setreuid32" }, -#endif -#ifdef __NR_setrlimit - { __NR_setrlimit, "setrlimit" }, -#endif -#ifdef __NR_setsid - { __NR_setsid, "setsid" }, -#endif -#ifdef __NR_setsockopt - { __NR_setsockopt, "setsockopt" }, -#endif -#ifdef __NR_settimeofday - { __NR_settimeofday, "settimeofday" }, -#endif -#ifdef __NR_setuid - { __NR_setuid, "setuid" }, -#endif -#ifdef __NR_setuid32 - { __NR_setuid32, "setuid32" }, -#endif -#ifdef __NR_setxattr - { __NR_setxattr, "setxattr" }, -#endif -#ifdef __NR_sgetmask - { __NR_sgetmask, "sgetmask" }, -#endif -#ifdef __NR_shmat - { __NR_shmat, "shmat" }, -#endif -#ifdef __NR_shmctl - { __NR_shmctl, "shmctl" }, -#endif -#ifdef __NR_shmdt - { __NR_shmdt, "shmdt" }, -#endif -#ifdef __NR_shmget - { __NR_shmget, "shmget" }, -#endif -#ifdef __NR_shutdown - { __NR_shutdown, "shutdown" }, -#endif -#ifdef __NR_sigaction - { __NR_sigaction, "sigaction" }, -#endif -#ifdef __NR_sigaltstack - { __NR_sigaltstack, "sigaltstack" }, -#endif -#ifdef __NR_signal - { __NR_signal, "signal" }, -#endif -#ifdef __NR_signalfd - { __NR_signalfd, "signalfd" }, -#endif -#ifdef __NR_signalfd4 - { __NR_signalfd4, "signalfd4" }, -#endif -#ifdef __NR_sigpending - { __NR_sigpending, "sigpending" }, -#endif -#ifdef __NR_sigprocmask - { __NR_sigprocmask, "sigprocmask" }, -#endif -#ifdef __NR_sigreturn - { __NR_sigreturn, "sigreturn" }, -#endif -#ifdef __NR_sigsuspend - { __NR_sigsuspend, "sigsuspend" }, -#endif -#ifdef __NR_socket - { __NR_socket, "socket" }, -#endif -#ifdef __NR_socketcall - { __NR_socketcall, "socketcall" }, -#endif -#ifdef __NR_socketpair - { __NR_socketpair, "socketpair" }, -#endif -#ifdef __NR_splice - { __NR_splice, "splice" }, -#endif -#ifdef __NR_ssetmask - { __NR_ssetmask, "ssetmask" }, -#endif -#ifdef __NR_stat - { __NR_stat, "stat" }, -#endif -#ifdef __NR_stat64 - { __NR_stat64, "stat64" }, -#endif -#ifdef __NR_statfs - { __NR_statfs, "statfs" }, -#endif -#ifdef __NR_statfs64 - { __NR_statfs64, "statfs64" }, -#endif -#ifdef __NR_stime - { __NR_stime, "stime" }, -#endif -#ifdef __NR_stty - { __NR_stty, "stty" }, -#endif -#ifdef __NR_swapoff - { __NR_swapoff, "swapoff" }, -#endif -#ifdef __NR_swapon - { __NR_swapon, "swapon" }, -#endif -#ifdef __NR_symlink - { __NR_symlink, "symlink" }, -#endif -#ifdef __NR_symlinkat - { __NR_symlinkat, "symlinkat" }, -#endif -#ifdef __NR_sync - { __NR_sync, "sync" }, -#endif -#ifdef __NR_sync_file_range - { __NR_sync_file_range, "sync_file_range" }, -#endif -#ifdef __NR_syncfs - { __NR_syncfs, "syncfs" }, -#endif -#ifdef __NR_sysfs - { __NR_sysfs, "sysfs" }, -#endif -#ifdef __NR_sysinfo - { __NR_sysinfo, "sysinfo" }, -#endif -#ifdef __NR_syslog - { __NR_syslog, "syslog" }, -#endif -#ifdef __NR_tee - { __NR_tee, "tee" }, -#endif -#ifdef __NR_tgkill - { __NR_tgkill, "tgkill" }, -#endif -#ifdef __NR_time - { __NR_time, "time" }, -#endif -#ifdef __NR_timer_create - { __NR_timer_create, "timer_create" }, -#endif -#ifdef __NR_timer_delete - { __NR_timer_delete, "timer_delete" }, -#endif -#ifdef __NR_timer_getoverrun - { __NR_timer_getoverrun, "timer_getoverrun" }, -#endif -#ifdef __NR_timer_gettime - { __NR_timer_gettime, "timer_gettime" }, -#endif -#ifdef __NR_timer_settime - { __NR_timer_settime, "timer_settime" }, -#endif -#ifdef __NR_timerfd_create - { __NR_timerfd_create, "timerfd_create" }, -#endif -#ifdef __NR_timerfd_gettime - { __NR_timerfd_gettime, "timerfd_gettime" }, -#endif -#ifdef __NR_timerfd_settime - { __NR_timerfd_settime, "timerfd_settime" }, -#endif -#ifdef __NR_times - { __NR_times, "times" }, -#endif -#ifdef __NR_tkill - { __NR_tkill, "tkill" }, -#endif -#ifdef __NR_truncate - { __NR_truncate, "truncate" }, -#endif -#ifdef __NR_truncate64 - { __NR_truncate64, "truncate64" }, -#endif -#ifdef __NR_tuxcall - { __NR_tuxcall, "tuxcall" }, -#endif -#ifdef __NR_ugetrlimit - { __NR_ugetrlimit, "ugetrlimit" }, -#endif -#ifdef __NR_ulimit - { __NR_ulimit, "ulimit" }, -#endif -#ifdef __NR_umask - { __NR_umask, "umask" }, -#endif -#ifdef __NR_umount - { __NR_umount, "umount" }, -#endif -#ifdef __NR_umount2 - { __NR_umount2, "umount2" }, -#endif -#ifdef __NR_uname - { __NR_uname, "uname" }, -#endif -#ifdef __NR_unlink - { __NR_unlink, "unlink" }, -#endif -#ifdef __NR_unlinkat - { __NR_unlinkat, "unlinkat" }, -#endif -#ifdef __NR_unshare - { __NR_unshare, "unshare" }, -#endif -#ifdef __NR_uselib - { __NR_uselib, "uselib" }, -#endif -#ifdef __NR_ustat - { __NR_ustat, "ustat" }, -#endif -#ifdef __NR_utime - { __NR_utime, "utime" }, -#endif -#ifdef __NR_utimensat - { __NR_utimensat, "utimensat" }, -#endif -#ifdef __NR_utimes - { __NR_utimes, "utimes" }, -#endif -#ifdef __NR_vfork - { __NR_vfork, "vfork" }, -#endif -#ifdef __NR_vhangup - { __NR_vhangup, "vhangup" }, -#endif -#ifdef __NR_vm86 - { __NR_vm86, "vm86" }, -#endif -#ifdef __NR_vm86old - { __NR_vm86old, "vm86old" }, -#endif -#ifdef __NR_vmsplice - { __NR_vmsplice, "vmsplice" }, -#endif -#ifdef __NR_vserver - { __NR_vserver, "vserver" }, -#endif -#ifdef __NR_wait4 - { __NR_wait4, "wait4" }, -#endif -#ifdef __NR_waitid - { __NR_waitid, "waitid" }, -#endif -#ifdef __NR_waitpid - { __NR_waitpid, "waitpid" }, -#endif -#ifdef __NR_write - { __NR_write, "write" }, -#endif -#ifdef __NR_writev - { __NR_writev, "writev" }, -#endif - {0, NULL} -}; - diff --git a/src/common/log.c b/src/common/log.c deleted file mode 100644 index ebd50f62d3..0000000000 --- a/src/common/log.c +++ /dev/null @@ -1,1539 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file log.c - * \brief Functions to send messages to log files or the console. - **/ - -#include "orconfig.h" -#include <stdarg.h> -#include <assert.h> -// #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#include "compat.h" -#include "util.h" -#define LOG_PRIVATE -#include "torlog.h" -#include "container.h" -#ifdef HAVE_ANDROID_LOG_H -#include <android/log.h> -#endif // HAVE_ANDROID_LOG_H. - -/** Given a severity, yields an index into log_severity_list_t.masks to use - * for that severity. */ -#define SEVERITY_MASK_IDX(sev) ((sev) - LOG_ERR) - -/** @{ */ -/** The string we stick at the end of a log message when it is too long, - * and its length. */ -#define TRUNCATED_STR "[...truncated]" -#define TRUNCATED_STR_LEN 14 -/** @} */ - -#define raw_assert(x) assert(x) // assert OK - -/** Defining compile-time constants for Tor log levels (used by the Rust - * log wrapper at src/rust/tor_log) */ -const int LOG_WARN_ = LOG_WARN; -const int LOG_NOTICE_ = LOG_NOTICE; -const log_domain_mask_t LD_GENERAL_ = LD_GENERAL; -const log_domain_mask_t LD_NET_ = LD_NET; - -/** Information for a single logfile; only used in log.c */ -typedef struct logfile_t { - struct logfile_t *next; /**< Next logfile_t in the linked list. */ - char *filename; /**< Filename to open. */ - int fd; /**< fd to receive log messages, or -1 for none. */ - int seems_dead; /**< Boolean: true if the stream seems to be kaput. */ - int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */ - int is_temporary; /**< Boolean: close after initializing logging subsystem.*/ - int is_syslog; /**< Boolean: send messages to syslog. */ - int is_android; /**< Boolean: send messages to Android's log subsystem. */ - char *android_tag; /**< Identity Tag used in Android's log subsystem. */ - log_callback callback; /**< If not NULL, send messages to this function. */ - log_severity_list_t *severities; /**< Which severity of messages should we - * log for each log domain? */ -} logfile_t; - -static void log_free_(logfile_t *victim); -#define log_free(lg) \ - FREE_AND_NULL(logfile_t, log_free_, (lg)) - -/** Helper: map a log severity to descriptive string. */ -static inline const char * -sev_to_string(int severity) -{ - switch (severity) { - case LOG_DEBUG: return "debug"; - case LOG_INFO: return "info"; - case LOG_NOTICE: return "notice"; - case LOG_WARN: return "warn"; - case LOG_ERR: return "err"; - default: /* Call assert, not tor_assert, since tor_assert - * calls log on failure. */ - raw_assert(0); return "UNKNOWN"; // LCOV_EXCL_LINE - } -} - -/** Helper: decide whether to include the function name in the log message. */ -static inline int -should_log_function_name(log_domain_mask_t domain, int severity) -{ - switch (severity) { - case LOG_DEBUG: - case LOG_INFO: - /* All debugging messages occur in interesting places. */ - return (domain & LD_NOFUNCNAME) == 0; - case LOG_NOTICE: - case LOG_WARN: - case LOG_ERR: - /* We care about places where bugs occur. */ - return (domain & (LD_BUG|LD_NOFUNCNAME)) == LD_BUG; - default: - /* Call assert, not tor_assert, since tor_assert calls log on failure. */ - raw_assert(0); return 0; // LCOV_EXCL_LINE - } -} - -#ifdef HAVE_ANDROID_LOG_H -/** Helper function to convert Tor's log severity into the matching - * Android log priority. - */ -static int -severity_to_android_log_priority(int severity) -{ - switch (severity) { - case LOG_DEBUG: - return ANDROID_LOG_VERBOSE; - case LOG_INFO: - return ANDROID_LOG_DEBUG; - case LOG_NOTICE: - return ANDROID_LOG_INFO; - case LOG_WARN: - return ANDROID_LOG_WARN; - case LOG_ERR: - return ANDROID_LOG_ERROR; - default: - // LCOV_EXCL_START - raw_assert(0); - return 0; - // LCOV_EXCL_STOP - } -} -#endif // HAVE_ANDROID_LOG_H. - -/** A mutex to guard changes to logfiles and logging. */ -static tor_mutex_t log_mutex; -/** True iff we have initialized log_mutex */ -static int log_mutex_initialized = 0; - -/** Linked list of logfile_t. */ -static logfile_t *logfiles = NULL; -/** Boolean: do we report logging domains? */ -static int log_domains_are_logged = 0; - -#ifdef HAVE_SYSLOG_H -/** The number of open syslog log handlers that we have. When this reaches 0, - * we can close our connection to the syslog facility. */ -static int syslog_count = 0; -#endif - -/** Represents a log message that we are going to send to callback-driven - * loggers once we can do so in a non-reentrant way. */ -typedef struct pending_log_message_t { - int severity; /**< The severity of the message */ - log_domain_mask_t domain; /**< The domain of the message */ - char *fullmsg; /**< The message, with all decorations */ - char *msg; /**< The content of the message */ -} pending_log_message_t; - -/** Log messages waiting to be replayed onto callback-based logs */ -static smartlist_t *pending_cb_messages = NULL; - -/** Callback to invoke when pending_cb_messages becomes nonempty. */ -static pending_callback_callback pending_cb_cb = NULL; - -/** Log messages waiting to be replayed once the logging system is initialized. - */ -static smartlist_t *pending_startup_messages = NULL; - -/** Number of bytes of messages queued in pending_startup_messages. (This is - * the length of the messages, not the number of bytes used to store - * them.) */ -static size_t pending_startup_messages_len; - -/** True iff we should store messages while waiting for the logs to get - * configured. */ -static int queue_startup_messages = 1; - -/** True iff __PRETTY_FUNCTION__ includes parenthesized arguments. */ -static int pretty_fn_has_parens = 0; - -/** Don't store more than this many bytes of messages while waiting for the - * logs to get configured. */ -#define MAX_STARTUP_MSG_LEN (1<<16) - -/** Lock the log_mutex to prevent others from changing the logfile_t list */ -#define LOCK_LOGS() STMT_BEGIN \ - tor_assert(log_mutex_initialized); \ - tor_mutex_acquire(&log_mutex); \ - STMT_END -/** Unlock the log_mutex */ -#define UNLOCK_LOGS() STMT_BEGIN \ - tor_assert(log_mutex_initialized); \ - tor_mutex_release(&log_mutex); \ - STMT_END - -/** What's the lowest log level anybody cares about? Checking this lets us - * bail out early from log_debug if we aren't debugging. */ -int log_global_min_severity_ = LOG_NOTICE; - -static void delete_log(logfile_t *victim); -static void close_log(logfile_t *victim); - -static char *domain_to_string(log_domain_mask_t domain, - char *buf, size_t buflen); -static inline char *format_msg(char *buf, size_t buf_len, - log_domain_mask_t domain, int severity, const char *funcname, - const char *suffix, - const char *format, va_list ap, size_t *msg_len_out) - CHECK_PRINTF(7,0); - -/** Name of the application: used to generate the message we write at the - * start of each new log. */ -static char *appname = NULL; - -/** Set the "application name" for the logs to <b>name</b>: we'll use this - * name in the message we write when starting up, and at the start of each new - * log. - * - * Tor uses this string to write the version number to the log file. */ -void -log_set_application_name(const char *name) -{ - tor_free(appname); - appname = name ? tor_strdup(name) : NULL; -} - -/** Return true if some of the running logs might be interested in a log - * message of the given severity in the given domains. If this function - * returns true, the log message might be ignored anyway, but if it returns - * false, it is definitely_ safe not to log the message. */ -int -log_message_is_interesting(int severity, log_domain_mask_t domain) -{ - (void) domain; - return (severity <= log_global_min_severity_); -} - -/** - * As tor_log, but takes an optional function name, and does not treat its - * <b>string</b> as a printf format. - * - * For use by Rust integration. - */ -void -tor_log_string(int severity, log_domain_mask_t domain, - const char *function, const char *string) -{ - log_fn_(severity, domain, function, "%s", string); -} - -/** Log time granularity in milliseconds. */ -static int log_time_granularity = 1; - -/** Define log time granularity for all logs to be <b>granularity_msec</b> - * milliseconds. */ -void -set_log_time_granularity(int granularity_msec) -{ - log_time_granularity = granularity_msec; -} - -/** Helper: Write the standard prefix for log lines to a - * <b>buf_len</b> character buffer in <b>buf</b>. - */ -static inline size_t -log_prefix_(char *buf, size_t buf_len, int severity) -{ - time_t t; - struct timeval now; - struct tm tm; - size_t n; - int r, ms; - - tor_gettimeofday(&now); - t = (time_t)now.tv_sec; - ms = (int)now.tv_usec / 1000; - if (log_time_granularity >= 1000) { - t -= t % (log_time_granularity / 1000); - ms = 0; - } else { - ms -= ((int)now.tv_usec / 1000) % log_time_granularity; - } - - n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm)); - r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ", ms, - sev_to_string(severity)); - - if (r<0) - return buf_len-1; - else - return n+r; -} - -/** If lf refers to an actual file that we have just opened, and the file - * contains no data, log an "opening new logfile" message at the top. - * - * Return -1 if the log is broken and needs to be deleted, else return 0. - */ -static int -log_tor_version(logfile_t *lf, int reset) -{ - char buf[256]; - size_t n; - int is_new; - - if (!lf->needs_close) - /* If it doesn't get closed, it isn't really a file. */ - return 0; - if (lf->is_temporary) - /* If it's temporary, it isn't really a file. */ - return 0; - - is_new = lf->fd >= 0 && tor_fd_getpos(lf->fd) == 0; - - if (reset && !is_new) - /* We are resetting, but we aren't at the start of the file; no - * need to log again. */ - return 0; - n = log_prefix_(buf, sizeof(buf), LOG_NOTICE); - if (appname) { - tor_snprintf(buf+n, sizeof(buf)-n, - "%s opening %slog file.\n", appname, is_new?"new ":""); - } else { - tor_snprintf(buf+n, sizeof(buf)-n, - "Tor %s opening %slog file.\n", VERSION, is_new?"new ":""); - } - if (write_all(lf->fd, buf, strlen(buf), 0) < 0) /* error */ - return -1; /* failed */ - return 0; -} - -static const char bug_suffix[] = " (on Tor " VERSION -#ifndef _MSC_VER - " " -#include "micro-revision.i" -#endif - ")"; - -/** Helper: Format a log message into a fixed-sized buffer. (This is - * factored out of <b>logv</b> so that we never format a message more - * than once.) Return a pointer to the first character of the message - * portion of the formatted string. - */ -static inline char * -format_msg(char *buf, size_t buf_len, - log_domain_mask_t domain, int severity, const char *funcname, - const char *suffix, - const char *format, va_list ap, size_t *msg_len_out) -{ - size_t n; - int r; - char *end_of_prefix; - char *buf_end; - - raw_assert(buf_len >= 16); /* prevent integer underflow and stupidity */ - buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */ - buf_end = buf+buf_len; /* point *after* the last char we can write to */ - - n = log_prefix_(buf, buf_len, severity); - end_of_prefix = buf+n; - - if (log_domains_are_logged) { - char *cp = buf+n; - if (cp == buf_end) goto format_msg_no_room_for_domains; - *cp++ = '{'; - if (cp == buf_end) goto format_msg_no_room_for_domains; - cp = domain_to_string(domain, cp, (buf+buf_len-cp)); - if (cp == buf_end) goto format_msg_no_room_for_domains; - *cp++ = '}'; - if (cp == buf_end) goto format_msg_no_room_for_domains; - *cp++ = ' '; - if (cp == buf_end) goto format_msg_no_room_for_domains; - end_of_prefix = cp; - n = cp-buf; - format_msg_no_room_for_domains: - /* This will leave end_of_prefix and n unchanged, and thus cause - * whatever log domain string we had written to be clobbered. */ - ; - } - - if (funcname && should_log_function_name(domain, severity)) { - r = tor_snprintf(buf+n, buf_len-n, - pretty_fn_has_parens ? "%s: " : "%s(): ", - funcname); - if (r<0) - n = strlen(buf); - else - n += r; - } - - if (domain == LD_BUG && buf_len-n > 6) { - memcpy(buf+n, "Bug: ", 6); - n += 5; - } - - r = tor_vsnprintf(buf+n,buf_len-n,format,ap); - if (r < 0) { - /* The message was too long; overwrite the end of the buffer with - * "[...truncated]" */ - if (buf_len >= TRUNCATED_STR_LEN) { - size_t offset = buf_len-TRUNCATED_STR_LEN; - /* We have an extra 2 characters after buf_len to hold the \n\0, - * so it's safe to add 1 to the size here. */ - strlcpy(buf+offset, TRUNCATED_STR, buf_len-offset+1); - } - /* Set 'n' to the end of the buffer, where we'll be writing \n\0. - * Since we already subtracted 2 from buf_len, this is safe.*/ - n = buf_len; - } else { - n += r; - if (suffix) { - size_t suffix_len = strlen(suffix); - if (buf_len-n >= suffix_len) { - memcpy(buf+n, suffix, suffix_len); - n += suffix_len; - } - } - } - - if (domain == LD_BUG && - buf_len - n > strlen(bug_suffix)+1) { - memcpy(buf+n, bug_suffix, strlen(bug_suffix)); - n += strlen(bug_suffix); - } - - buf[n]='\n'; - buf[n+1]='\0'; - *msg_len_out = n+1; - return end_of_prefix; -} - -/* Create a new pending_log_message_t with appropriate values */ -static pending_log_message_t * -pending_log_message_new(int severity, log_domain_mask_t domain, - const char *fullmsg, const char *shortmsg) -{ - pending_log_message_t *m = tor_malloc(sizeof(pending_log_message_t)); - m->severity = severity; - m->domain = domain; - m->fullmsg = fullmsg ? tor_strdup(fullmsg) : NULL; - m->msg = tor_strdup(shortmsg); - return m; -} - -#define pending_log_message_free(msg) \ - FREE_AND_NULL(pending_log_message_t, pending_log_message_free_, (msg)) - -/** Release all storage held by <b>msg</b>. */ -static void -pending_log_message_free_(pending_log_message_t *msg) -{ - if (!msg) - return; - tor_free(msg->msg); - tor_free(msg->fullmsg); - tor_free(msg); -} - -/** Helper function: returns true iff the log file, given in <b>lf</b>, is - * handled externally via the system log API, the Android logging API, or is an - * external callback function. */ -static inline int -logfile_is_external(const logfile_t *lf) -{ - raw_assert(lf); - return lf->is_syslog || lf->is_android || lf->callback; -} - -/** Return true iff <b>lf</b> would like to receive a message with the - * specified <b>severity</b> in the specified <b>domain</b>. - */ -static inline int -logfile_wants_message(const logfile_t *lf, int severity, - log_domain_mask_t domain) -{ - if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { - return 0; - } - if (! (lf->fd >= 0 || logfile_is_external(lf))) { - return 0; - } - if (lf->seems_dead) { - return 0; - } - - return 1; -} - -/** Send a message to <b>lf</b>. The full message, with time prefix and - * severity, is in <b>buf</b>. The message itself is in - * <b>msg_after_prefix</b>. If <b>callbacks_deferred</b> points to true, then - * we already deferred this message for pending callbacks and don't need to do - * it again. Otherwise, if we need to do it, do it, and set - * <b>callbacks_deferred</b> to 1. */ -static inline void -logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len, - const char *msg_after_prefix, log_domain_mask_t domain, - int severity, int *callbacks_deferred) -{ - - if (lf->is_syslog) { -#ifdef HAVE_SYSLOG_H -#ifdef MAXLINE - /* Some syslog implementations have limits on the length of what you can - * pass them, and some very old ones do not detect overflow so well. - * Regrettably, they call their maximum line length MAXLINE. */ -#if MAXLINE < 64 -#warn "MAXLINE is a very low number; it might not be from syslog.h after all" -#endif - char *m = msg_after_prefix; - if (msg_len >= MAXLINE) - m = tor_strndup(msg_after_prefix, MAXLINE-1); - syslog(severity, "%s", m); - if (m != msg_after_prefix) { - tor_free(m); - } -#else /* !(defined(MAXLINE)) */ - /* We have syslog but not MAXLINE. That's promising! */ - syslog(severity, "%s", msg_after_prefix); -#endif /* defined(MAXLINE) */ -#endif /* defined(HAVE_SYSLOG_H) */ - } else if (lf->is_android) { -#ifdef HAVE_ANDROID_LOG_H - int priority = severity_to_android_log_priority(severity); - __android_log_write(priority, lf->android_tag, msg_after_prefix); -#endif // HAVE_ANDROID_LOG_H. - } else if (lf->callback) { - if (domain & LD_NOCB) { - if (!*callbacks_deferred && pending_cb_messages) { - smartlist_add(pending_cb_messages, - pending_log_message_new(severity,domain,NULL,msg_after_prefix)); - *callbacks_deferred = 1; - if (smartlist_len(pending_cb_messages) == 1 && pending_cb_cb) { - pending_cb_cb(); - } - } - } else { - lf->callback(severity, domain, msg_after_prefix); - } - } else { - if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */ - /* don't log the error! mark this log entry to be blown away, and - * continue. */ - lf->seems_dead = 1; - } - } -} - -/** Helper: sends a message to the appropriate logfiles, at loglevel - * <b>severity</b>. If provided, <b>funcname</b> is prepended to the - * message. The actual message is derived as from tor_snprintf(format,ap). - */ -MOCK_IMPL(STATIC void, -logv,(int severity, log_domain_mask_t domain, const char *funcname, - const char *suffix, const char *format, va_list ap)) -{ - char buf[10240]; - size_t msg_len = 0; - int formatted = 0; - logfile_t *lf; - char *end_of_prefix=NULL; - int callbacks_deferred = 0; - - /* Call assert, not tor_assert, since tor_assert calls log on failure. */ - raw_assert(format); - /* check that severity is sane. Overrunning the masks array leads to - * interesting and hard to diagnose effects */ - raw_assert(severity >= LOG_ERR && severity <= LOG_DEBUG); - /* check that we've initialised the log mutex before we try to lock it */ - raw_assert(log_mutex_initialized); - LOCK_LOGS(); - - if ((! (domain & LD_NOCB)) && pending_cb_messages - && smartlist_len(pending_cb_messages)) - flush_pending_log_callbacks(); - - if (queue_startup_messages && - pending_startup_messages_len < MAX_STARTUP_MSG_LEN) { - end_of_prefix = - format_msg(buf, sizeof(buf), domain, severity, funcname, suffix, - format, ap, &msg_len); - formatted = 1; - - smartlist_add(pending_startup_messages, - pending_log_message_new(severity,domain,buf,end_of_prefix)); - pending_startup_messages_len += msg_len; - } - - for (lf = logfiles; lf; lf = lf->next) { - if (! logfile_wants_message(lf, severity, domain)) - continue; - - if (!formatted) { - end_of_prefix = - format_msg(buf, sizeof(buf), domain, severity, funcname, suffix, - format, ap, &msg_len); - formatted = 1; - } - - logfile_deliver(lf, buf, msg_len, end_of_prefix, domain, severity, - &callbacks_deferred); - } - UNLOCK_LOGS(); -} - -/** Output a message to the log. It gets logged to all logfiles that - * care about messages with <b>severity</b> in <b>domain</b>. The content - * is formatted printf-style based on <b>format</b> and extra arguments. - * */ -void -tor_log(int severity, log_domain_mask_t domain, const char *format, ...) -{ - va_list ap; - if (severity > log_global_min_severity_) - return; - va_start(ap,format); -#ifdef TOR_UNIT_TESTS - if (domain & LD_NO_MOCK) - logv__real(severity, domain, NULL, NULL, format, ap); - else -#endif - logv(severity, domain, NULL, NULL, format, ap); - va_end(ap); -} - -/** Maximum number of fds that will get notifications if we crash */ -#define MAX_SIGSAFE_FDS 8 -/** Array of fds to log crash-style warnings to. */ -static int sigsafe_log_fds[MAX_SIGSAFE_FDS] = { STDERR_FILENO }; -/** The number of elements used in sigsafe_log_fds */ -static int n_sigsafe_log_fds = 1; - -/** Write <b>s</b> to each element of sigsafe_log_fds. Return 0 on success, -1 - * on failure. */ -static int -tor_log_err_sigsafe_write(const char *s) -{ - int i; - ssize_t r; - size_t len = strlen(s); - int err = 0; - for (i=0; i < n_sigsafe_log_fds; ++i) { - r = write(sigsafe_log_fds[i], s, len); - err += (r != (ssize_t)len); - } - return err ? -1 : 0; -} - -/** Given a list of string arguments ending with a NULL, writes them - * to our logs and to stderr (if possible). This function is safe to call - * from within a signal handler. */ -void -tor_log_err_sigsafe(const char *m, ...) -{ - va_list ap; - const char *x; - char timebuf[33]; - time_t now = time(NULL); - - if (!m) - return; - if (log_time_granularity >= 2000) { - int g = log_time_granularity / 1000; - now -= now % g; - } - timebuf[0] = now < 0 ? '-' : ' '; - if (now < 0) now = -now; - timebuf[1] = '\0'; - format_dec_number_sigsafe(now, timebuf+1, sizeof(timebuf)-1); - tor_log_err_sigsafe_write("\n==========================================" - "================== T="); - tor_log_err_sigsafe_write(timebuf); - tor_log_err_sigsafe_write("\n"); - tor_log_err_sigsafe_write(m); - va_start(ap, m); - while ((x = va_arg(ap, const char*))) { - tor_log_err_sigsafe_write(x); - } - va_end(ap); -} - -/** Set *<b>out</b> to a pointer to an array of the fds to log errors to from - * inside a signal handler. Return the number of elements in the array. */ -int -tor_log_get_sigsafe_err_fds(const int **out) -{ - *out = sigsafe_log_fds; - return n_sigsafe_log_fds; -} - -/** Helper function; return true iff the <b>n</b>-element array <b>array</b> - * contains <b>item</b>. */ -static int -int_array_contains(const int *array, int n, int item) -{ - int j; - for (j = 0; j < n; ++j) { - if (array[j] == item) - return 1; - } - return 0; -} - -/** Function to call whenever the list of logs changes to get ready to log - * from signal handlers. */ -void -tor_log_update_sigsafe_err_fds(void) -{ - const logfile_t *lf; - int found_real_stderr = 0; - - LOCK_LOGS(); - /* Reserve the first one for stderr. This is safe because when we daemonize, - * we dup2 /dev/null to stderr, */ - sigsafe_log_fds[0] = STDERR_FILENO; - n_sigsafe_log_fds = 1; - - for (lf = logfiles; lf; lf = lf->next) { - /* Don't try callback to the control port, or syslogs: We can't - * do them from a signal handler. Don't try stdout: we always do stderr. - */ - if (lf->is_temporary || logfile_is_external(lf) - || lf->seems_dead || lf->fd < 0) - continue; - if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] & - (LD_BUG|LD_GENERAL)) { - if (lf->fd == STDERR_FILENO) - found_real_stderr = 1; - /* Avoid duplicates */ - if (int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, lf->fd)) - continue; - sigsafe_log_fds[n_sigsafe_log_fds++] = lf->fd; - if (n_sigsafe_log_fds == MAX_SIGSAFE_FDS) - break; - } - } - - if (!found_real_stderr && - int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, STDOUT_FILENO)) { - /* Don't use a virtual stderr when we're also logging to stdout. */ - raw_assert(n_sigsafe_log_fds >= 2); /* Don't tor_assert inside log fns */ - sigsafe_log_fds[0] = sigsafe_log_fds[--n_sigsafe_log_fds]; - } - - UNLOCK_LOGS(); -} - -/** Add to <b>out</b> a copy of every currently configured log file name. Used - * to enable access to these filenames with the sandbox code. */ -void -tor_log_get_logfile_names(smartlist_t *out) -{ - logfile_t *lf; - tor_assert(out); - - LOCK_LOGS(); - - for (lf = logfiles; lf; lf = lf->next) { - if (lf->is_temporary || logfile_is_external(lf)) - continue; - if (lf->filename == NULL) - continue; - smartlist_add_strdup(out, lf->filename); - } - - UNLOCK_LOGS(); -} - -/** Implementation of the log_fn backend, used when we have - * variadic macros. All arguments are as for log_fn, except for - * <b>fn</b>, which is the name of the calling functions. */ -void -log_fn_(int severity, log_domain_mask_t domain, const char *fn, - const char *format, ...) -{ - va_list ap; - if (severity > log_global_min_severity_) - return; - va_start(ap,format); - logv(severity, domain, fn, NULL, format, ap); - va_end(ap); -} -void -log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain, - const char *fn, const char *format, ...) -{ - va_list ap; - char *m; - if (severity > log_global_min_severity_) - return; - m = rate_limit_log(ratelim, approx_time()); - if (m == NULL) - return; - va_start(ap, format); - logv(severity, domain, fn, m, format, ap); - va_end(ap); - tor_free(m); -} - -/** Free all storage held by <b>victim</b>. */ -static void -log_free_(logfile_t *victim) -{ - if (!victim) - return; - tor_free(victim->severities); - tor_free(victim->filename); - tor_free(victim->android_tag); - tor_free(victim); -} - -/** Close all open log files, and free other static memory. */ -void -logs_free_all(void) -{ - logfile_t *victim, *next; - smartlist_t *messages, *messages2; - LOCK_LOGS(); - next = logfiles; - logfiles = NULL; - messages = pending_cb_messages; - pending_cb_messages = NULL; - pending_cb_cb = NULL; - messages2 = pending_startup_messages; - pending_startup_messages = NULL; - UNLOCK_LOGS(); - while (next) { - victim = next; - next = next->next; - close_log(victim); - log_free(victim); - } - tor_free(appname); - - SMARTLIST_FOREACH(messages, pending_log_message_t *, msg, { - pending_log_message_free(msg); - }); - smartlist_free(messages); - - if (messages2) { - SMARTLIST_FOREACH(messages2, pending_log_message_t *, msg, { - pending_log_message_free(msg); - }); - smartlist_free(messages2); - } - - /* We _could_ destroy the log mutex here, but that would screw up any logs - * that happened between here and the end of execution. */ -} - -/** Remove and free the log entry <b>victim</b> from the linked-list - * logfiles (it is probably present, but it might not be due to thread - * racing issues). After this function is called, the caller shouldn't - * refer to <b>victim</b> anymore. - * - * Long-term, we need to do something about races in the log subsystem - * in general. See bug 222 for more details. - */ -static void -delete_log(logfile_t *victim) -{ - logfile_t *tmpl; - if (victim == logfiles) - logfiles = victim->next; - else { - for (tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ; -// tor_assert(tmpl); -// tor_assert(tmpl->next == victim); - if (!tmpl) - return; - tmpl->next = victim->next; - } - log_free(victim); -} - -/** Helper: release system resources (but not memory) held by a single - * logfile_t. */ -static void -close_log(logfile_t *victim) -{ - if (victim->needs_close && victim->fd >= 0) { - close(victim->fd); - victim->fd = -1; - } else if (victim->is_syslog) { -#ifdef HAVE_SYSLOG_H - if (--syslog_count == 0) { - /* There are no other syslogs; close the logging facility. */ - closelog(); - } -#endif /* defined(HAVE_SYSLOG_H) */ - } -} - -/** Adjust a log severity configuration in <b>severity_out</b> to contain - * every domain between <b>loglevelMin</b> and <b>loglevelMax</b>, inclusive. - */ -void -set_log_severity_config(int loglevelMin, int loglevelMax, - log_severity_list_t *severity_out) -{ - int i; - tor_assert(loglevelMin >= loglevelMax); - tor_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG); - tor_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG); - memset(severity_out, 0, sizeof(log_severity_list_t)); - for (i = loglevelMin; i >= loglevelMax; --i) { - severity_out->masks[SEVERITY_MASK_IDX(i)] = ~0u; - } -} - -/** Add a log handler named <b>name</b> to send all messages in <b>severity</b> - * to <b>fd</b>. Copies <b>severity</b>. Helper: does no locking. */ -static void -add_stream_log_impl(const log_severity_list_t *severity, - const char *name, int fd) -{ - logfile_t *lf; - lf = tor_malloc_zero(sizeof(logfile_t)); - lf->fd = fd; - lf->filename = tor_strdup(name); - lf->severities = tor_memdup(severity, sizeof(log_severity_list_t)); - lf->next = logfiles; - - logfiles = lf; - log_global_min_severity_ = get_min_log_level(); -} - -/** Add a log handler named <b>name</b> to send all messages in <b>severity</b> - * to <b>fd</b>. Steals a reference to <b>severity</b>; the caller must - * not use it after calling this function. */ -void -add_stream_log(const log_severity_list_t *severity, const char *name, int fd) -{ - LOCK_LOGS(); - add_stream_log_impl(severity, name, fd); - UNLOCK_LOGS(); -} - -/** Initialize the global logging facility */ -void -init_logging(int disable_startup_queue) -{ - if (!log_mutex_initialized) { - tor_mutex_init(&log_mutex); - log_mutex_initialized = 1; - } -#ifdef __GNUC__ - if (strchr(__PRETTY_FUNCTION__, '(')) { - pretty_fn_has_parens = 1; - } -#endif - if (pending_cb_messages == NULL) - pending_cb_messages = smartlist_new(); - if (disable_startup_queue) - queue_startup_messages = 0; - if (pending_startup_messages == NULL && queue_startup_messages) { - pending_startup_messages = smartlist_new(); - } -} - -/** Set whether we report logging domains as a part of our log messages. - */ -void -logs_set_domain_logging(int enabled) -{ - LOCK_LOGS(); - log_domains_are_logged = enabled; - UNLOCK_LOGS(); -} - -/** Add a log handler to receive messages during startup (before the real - * logs are initialized). - */ -void -add_temp_log(int min_severity) -{ - log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t)); - set_log_severity_config(min_severity, LOG_ERR, s); - LOCK_LOGS(); - add_stream_log_impl(s, "<temp>", fileno(stdout)); - tor_free(s); - logfiles->is_temporary = 1; - UNLOCK_LOGS(); -} - -/** - * Register "cb" as the callback to call when there are new pending log - * callbacks to be flushed with flush_pending_log_callbacks(). - * - * Note that this callback, if present, can be invoked from any thread. - * - * This callback must not log. - * - * It is intentional that this function contains the name "callback" twice: it - * sets a "callback" to be called on the condition that there is a "pending - * callback". - **/ -void -logs_set_pending_callback_callback(pending_callback_callback cb) -{ - pending_cb_cb = cb; -} - -/** - * Add a log handler to send messages in <b>severity</b> - * to the function <b>cb</b>. - */ -int -add_callback_log(const log_severity_list_t *severity, log_callback cb) -{ - logfile_t *lf; - lf = tor_malloc_zero(sizeof(logfile_t)); - lf->fd = -1; - lf->severities = tor_memdup(severity, sizeof(log_severity_list_t)); - lf->filename = tor_strdup("<callback>"); - lf->callback = cb; - lf->next = logfiles; - - LOCK_LOGS(); - logfiles = lf; - log_global_min_severity_ = get_min_log_level(); - UNLOCK_LOGS(); - return 0; -} - -/** Adjust the configured severity of any logs whose callback function is - * <b>cb</b>. */ -void -change_callback_log_severity(int loglevelMin, int loglevelMax, - log_callback cb) -{ - logfile_t *lf; - log_severity_list_t severities; - set_log_severity_config(loglevelMin, loglevelMax, &severities); - LOCK_LOGS(); - for (lf = logfiles; lf; lf = lf->next) { - if (lf->callback == cb) { - memcpy(lf->severities, &severities, sizeof(severities)); - } - } - log_global_min_severity_ = get_min_log_level(); - UNLOCK_LOGS(); -} - -/** If there are any log messages that were generated with LD_NOCB waiting to - * be sent to callback-based loggers, send them now. */ -void -flush_pending_log_callbacks(void) -{ - logfile_t *lf; - smartlist_t *messages, *messages_tmp; - - LOCK_LOGS(); - if (!pending_cb_messages || 0 == smartlist_len(pending_cb_messages)) { - UNLOCK_LOGS(); - return; - } - - messages = pending_cb_messages; - pending_cb_messages = smartlist_new(); - do { - SMARTLIST_FOREACH_BEGIN(messages, pending_log_message_t *, msg) { - const int severity = msg->severity; - const int domain = msg->domain; - for (lf = logfiles; lf; lf = lf->next) { - if (! lf->callback || lf->seems_dead || - ! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { - continue; - } - lf->callback(severity, domain, msg->msg); - } - pending_log_message_free(msg); - } SMARTLIST_FOREACH_END(msg); - smartlist_clear(messages); - - messages_tmp = pending_cb_messages; - pending_cb_messages = messages; - messages = messages_tmp; - } while (smartlist_len(messages)); - - smartlist_free(messages); - - UNLOCK_LOGS(); -} - -/** Flush all the messages we stored from startup while waiting for log - * initialization. - */ -void -flush_log_messages_from_startup(void) -{ - logfile_t *lf; - - LOCK_LOGS(); - queue_startup_messages = 0; - pending_startup_messages_len = 0; - if (! pending_startup_messages) - goto out; - - SMARTLIST_FOREACH_BEGIN(pending_startup_messages, pending_log_message_t *, - msg) { - int callbacks_deferred = 0; - for (lf = logfiles; lf; lf = lf->next) { - if (! logfile_wants_message(lf, msg->severity, msg->domain)) - continue; - - /* We configure a temporary startup log that goes to stdout, so we - * shouldn't replay to stdout/stderr*/ - if (lf->fd == STDOUT_FILENO || lf->fd == STDERR_FILENO) { - continue; - } - - logfile_deliver(lf, msg->fullmsg, strlen(msg->fullmsg), msg->msg, - msg->domain, msg->severity, &callbacks_deferred); - } - pending_log_message_free(msg); - } SMARTLIST_FOREACH_END(msg); - smartlist_free(pending_startup_messages); - pending_startup_messages = NULL; - - out: - UNLOCK_LOGS(); -} - -/** Close any log handlers added by add_temp_log() or marked by - * mark_logs_temp(). */ -void -close_temp_logs(void) -{ - logfile_t *lf, **p; - - LOCK_LOGS(); - for (p = &logfiles; *p; ) { - if ((*p)->is_temporary) { - lf = *p; - /* we use *p here to handle the edge case of the head of the list */ - *p = (*p)->next; - close_log(lf); - log_free(lf); - } else { - p = &((*p)->next); - } - } - - log_global_min_severity_ = get_min_log_level(); - UNLOCK_LOGS(); -} - -/** Make all currently temporary logs (set to be closed by close_temp_logs) - * live again, and close all non-temporary logs. */ -void -rollback_log_changes(void) -{ - logfile_t *lf; - LOCK_LOGS(); - for (lf = logfiles; lf; lf = lf->next) - lf->is_temporary = ! lf->is_temporary; - UNLOCK_LOGS(); - close_temp_logs(); -} - -/** Configure all log handles to be closed by close_temp_logs(). */ -void -mark_logs_temp(void) -{ - logfile_t *lf; - LOCK_LOGS(); - for (lf = logfiles; lf; lf = lf->next) - lf->is_temporary = 1; - UNLOCK_LOGS(); -} - -/** - * Add a log handler to send messages to <b>filename</b>. If opening the - * logfile fails, -1 is returned and errno is set appropriately (by open(2)). - */ -int -add_file_log(const log_severity_list_t *severity, const char *filename, - const int truncate_log) -{ - int fd; - logfile_t *lf; - - int open_flags = O_WRONLY|O_CREAT; - open_flags |= truncate_log ? O_TRUNC : O_APPEND; - - fd = tor_open_cloexec(filename, open_flags, 0640); - if (fd<0) - return -1; - if (tor_fd_seekend(fd)<0) { - close(fd); - return -1; - } - - LOCK_LOGS(); - add_stream_log_impl(severity, filename, fd); - logfiles->needs_close = 1; - lf = logfiles; - log_global_min_severity_ = get_min_log_level(); - - if (log_tor_version(lf, 0) < 0) { - delete_log(lf); - } - UNLOCK_LOGS(); - - return 0; -} - -#ifdef HAVE_SYSLOG_H -/** - * Add a log handler to send messages to they system log facility. - * - * If this is the first log handler, opens syslog with ident Tor or - * Tor-<syslog_identity_tag> if that is not NULL. - */ -int -add_syslog_log(const log_severity_list_t *severity, - const char* syslog_identity_tag) -{ - logfile_t *lf; - if (syslog_count++ == 0) { - /* This is the first syslog. */ - static char buf[256]; - if (syslog_identity_tag) { - tor_snprintf(buf, sizeof(buf), "Tor-%s", syslog_identity_tag); - } else { - tor_snprintf(buf, sizeof(buf), "Tor"); - } - openlog(buf, LOG_PID | LOG_NDELAY, LOGFACILITY); - } - - lf = tor_malloc_zero(sizeof(logfile_t)); - lf->fd = -1; - lf->severities = tor_memdup(severity, sizeof(log_severity_list_t)); - lf->filename = tor_strdup("<syslog>"); - lf->is_syslog = 1; - - LOCK_LOGS(); - lf->next = logfiles; - logfiles = lf; - log_global_min_severity_ = get_min_log_level(); - UNLOCK_LOGS(); - return 0; -} -#endif /* defined(HAVE_SYSLOG_H) */ - -#ifdef HAVE_ANDROID_LOG_H -/** - * Add a log handler to send messages to the Android platform log facility. - */ -int -add_android_log(const log_severity_list_t *severity, - const char *android_tag) -{ - logfile_t *lf = NULL; - - lf = tor_malloc_zero(sizeof(logfile_t)); - lf->fd = -1; - lf->severities = tor_memdup(severity, sizeof(log_severity_list_t)); - lf->filename = tor_strdup("<android>"); - lf->is_android = 1; - - if (android_tag == NULL) - lf->android_tag = tor_strdup("Tor"); - else { - char buf[256]; - tor_snprintf(buf, sizeof(buf), "Tor-%s", android_tag); - lf->android_tag = tor_strdup(buf); - } - - LOCK_LOGS(); - lf->next = logfiles; - logfiles = lf; - log_global_min_severity_ = get_min_log_level(); - UNLOCK_LOGS(); - return 0; -} -#endif // HAVE_ANDROID_LOG_H. - -/** If <b>level</b> is a valid log severity, return the corresponding - * numeric value. Otherwise, return -1. */ -int -parse_log_level(const char *level) -{ - if (!strcasecmp(level, "err")) - return LOG_ERR; - if (!strcasecmp(level, "warn")) - return LOG_WARN; - if (!strcasecmp(level, "notice")) - return LOG_NOTICE; - if (!strcasecmp(level, "info")) - return LOG_INFO; - if (!strcasecmp(level, "debug")) - return LOG_DEBUG; - return -1; -} - -/** Return the string equivalent of a given log level. */ -const char * -log_level_to_string(int level) -{ - return sev_to_string(level); -} - -/** NULL-terminated array of names for log domains such that domain_list[dom] - * is a description of <b>dom</b>. - * - * Remember to update doc/tor.1.txt if you modify this list. - * */ -static const char *domain_list[] = { - "GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM", - "HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV", - "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL", - "SCHED", "GUARD", "CONSDIFF", "DOS", NULL -}; - -/** Return a bitmask for the log domain for which <b>domain</b> is the name, - * or 0 if there is no such name. */ -static log_domain_mask_t -parse_log_domain(const char *domain) -{ - int i; - for (i=0; domain_list[i]; ++i) { - if (!strcasecmp(domain, domain_list[i])) - return (1u<<i); - } - return 0; -} - -/** Translate a bitmask of log domains to a string. */ -static char * -domain_to_string(log_domain_mask_t domain, char *buf, size_t buflen) -{ - char *cp = buf; - char *eos = buf+buflen; - - buf[0] = '\0'; - if (! domain) - return buf; - while (1) { - const char *d; - int bit = tor_log2(domain); - size_t n; - if ((unsigned)bit >= ARRAY_LENGTH(domain_list)-1 || - bit >= N_LOGGING_DOMAINS) { - tor_snprintf(buf, buflen, "<BUG:Unknown domain %lx>", (long)domain); - return buf+strlen(buf); - } - d = domain_list[bit]; - n = strlcpy(cp, d, eos-cp); - if (n >= buflen) { - tor_snprintf(buf, buflen, "<BUG:Truncating domain %lx>", (long)domain); - return buf+strlen(buf); - } - cp += n; - domain &= ~(1<<bit); - - if (domain == 0 || (eos-cp) < 2) - return cp; - - memcpy(cp, ",", 2); /*Nul-terminated ,"*/ - cp++; - } -} - -/** Parse a log severity pattern in *<b>cfg_ptr</b>. Advance cfg_ptr after - * the end of the severityPattern. Set the value of <b>severity_out</b> to - * the parsed pattern. Return 0 on success, -1 on failure. - * - * The syntax for a SeverityPattern is: - * <pre> - * SeverityPattern = *(DomainSeverity SP)* DomainSeverity - * DomainSeverity = (DomainList SP)? SeverityRange - * SeverityRange = MinSeverity ("-" MaxSeverity )? - * DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]" - * DomainSpec = "*" | Domain | "~" Domain - * </pre> - * A missing MaxSeverity defaults to ERR. Severities and domains are - * case-insensitive. "~" indicates negation for a domain; negation happens - * last inside a DomainList. Only one SeverityRange without a DomainList is - * allowed per line. - */ -int -parse_log_severity_config(const char **cfg_ptr, - log_severity_list_t *severity_out) -{ - const char *cfg = *cfg_ptr; - int got_anything = 0; - int got_an_unqualified_range = 0; - memset(severity_out, 0, sizeof(*severity_out)); - - cfg = eat_whitespace(cfg); - while (*cfg) { - const char *dash, *space; - char *sev_lo, *sev_hi; - int low, high, i; - log_domain_mask_t domains = ~0u; - - if (*cfg == '[') { - int err = 0; - char *domains_str; - smartlist_t *domains_list; - log_domain_mask_t neg_domains = 0; - const char *closebracket = strchr(cfg, ']'); - if (!closebracket) - return -1; - domains = 0; - domains_str = tor_strndup(cfg+1, closebracket-cfg-1); - domains_list = smartlist_new(); - smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE, - -1); - tor_free(domains_str); - SMARTLIST_FOREACH_BEGIN(domains_list, const char *, domain) { - if (!strcmp(domain, "*")) { - domains = ~0u; - } else { - int d; - int negate=0; - if (*domain == '~') { - negate = 1; - ++domain; - } - d = parse_log_domain(domain); - if (!d) { - log_warn(LD_CONFIG, "No such logging domain as %s", domain); - err = 1; - } else { - if (negate) - neg_domains |= d; - else - domains |= d; - } - } - } SMARTLIST_FOREACH_END(domain); - SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d)); - smartlist_free(domains_list); - if (err) - return -1; - if (domains == 0 && neg_domains) - domains = ~neg_domains; - else - domains &= ~neg_domains; - cfg = eat_whitespace(closebracket+1); - } else { - ++got_an_unqualified_range; - } - if (!strcasecmpstart(cfg, "file") || - !strcasecmpstart(cfg, "stderr") || - !strcasecmpstart(cfg, "stdout") || - !strcasecmpstart(cfg, "syslog") || - !strcasecmpstart(cfg, "android")) { - goto done; - } - if (got_an_unqualified_range > 1) - return -1; - - space = find_whitespace(cfg); - dash = strchr(cfg, '-'); - if (dash && dash < space) { - sev_lo = tor_strndup(cfg, dash-cfg); - sev_hi = tor_strndup(dash+1, space-(dash+1)); - } else { - sev_lo = tor_strndup(cfg, space-cfg); - sev_hi = tor_strdup("ERR"); - } - low = parse_log_level(sev_lo); - high = parse_log_level(sev_hi); - tor_free(sev_lo); - tor_free(sev_hi); - if (low == -1) - return -1; - if (high == -1) - return -1; - - got_anything = 1; - for (i=low; i >= high; --i) - severity_out->masks[SEVERITY_MASK_IDX(i)] |= domains; - - cfg = eat_whitespace(space); - } - - done: - *cfg_ptr = cfg; - return got_anything ? 0 : -1; -} - -/** Return the least severe log level that any current log is interested in. */ -int -get_min_log_level(void) -{ - logfile_t *lf; - int i; - int min = LOG_ERR; - for (lf = logfiles; lf; lf = lf->next) { - for (i = LOG_DEBUG; i > min; --i) - if (lf->severities->masks[SEVERITY_MASK_IDX(i)]) - min = i; - } - return min; -} - -/** Switch all logs to output at most verbose level. */ -void -switch_logs_debug(void) -{ - logfile_t *lf; - int i; - LOCK_LOGS(); - for (lf = logfiles; lf; lf=lf->next) { - for (i = LOG_DEBUG; i >= LOG_ERR; --i) - lf->severities->masks[SEVERITY_MASK_IDX(i)] = ~0u; - } - log_global_min_severity_ = get_min_log_level(); - UNLOCK_LOGS(); -} - -/** Truncate all the log files. */ -void -truncate_logs(void) -{ - logfile_t *lf; - for (lf = logfiles; lf; lf = lf->next) { - if (lf->fd >= 0) { - tor_ftruncate(lf->fd); - } - } -} - diff --git a/src/common/memarea.c b/src/common/memarea.c deleted file mode 100644 index 68c1625fe4..0000000000 --- a/src/common/memarea.c +++ /dev/null @@ -1,398 +0,0 @@ -/* Copyright (c) 2008-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** \file memarea.c - * \brief Implementation for memarea_t, an allocator for allocating lots of - * small objects that will be freed all at once. - */ - -#include "orconfig.h" -#include <stddef.h> -#include <stdlib.h> -#include "memarea.h" -#include "util.h" -#include "compat.h" -#include "torlog.h" -#include "container.h" - -#ifndef DISABLE_MEMORY_SENTINELS - -/** If true, we try to detect any attempts to write beyond the length of a - * memarea. */ -#define USE_SENTINELS - -/** All returned pointers should be aligned to the nearest multiple of this - * value. */ -#define MEMAREA_ALIGN SIZEOF_VOID_P - -/** A value which, when masked out of a pointer, produces a maximally aligned - * pointer. */ -#if MEMAREA_ALIGN == 4 -#define MEMAREA_ALIGN_MASK ((uintptr_t)3) -#elif MEMAREA_ALIGN == 8 -#define MEMAREA_ALIGN_MASK ((uintptr_t)7) -#else -#error "void* is neither 4 nor 8 bytes long. I don't know how to align stuff." -#endif /* MEMAREA_ALIGN == 4 || ... */ - -#if defined(__GNUC__) && defined(FLEXIBLE_ARRAY_MEMBER) -#define USE_ALIGNED_ATTRIBUTE -/** Name for the 'memory' member of a memory chunk. */ -#define U_MEM mem -#else -#define U_MEM u.mem -#endif /* defined(__GNUC__) && defined(FLEXIBLE_ARRAY_MEMBER) */ - -#ifdef USE_SENTINELS -/** Magic value that we stick at the end of a memarea so we can make sure - * there are no run-off-the-end bugs. */ -#define SENTINEL_VAL 0x90806622u -/** How many bytes per area do we devote to the sentinel? */ -#define SENTINEL_LEN sizeof(uint32_t) -/** Given a mem_area_chunk_t with SENTINEL_LEN extra bytes allocated at the - * end, set those bytes. */ -#define SET_SENTINEL(chunk) \ - STMT_BEGIN \ - set_uint32( &(chunk)->U_MEM[chunk->mem_size], SENTINEL_VAL ); \ - STMT_END -/** Assert that the sentinel on a memarea is set correctly. */ -#define CHECK_SENTINEL(chunk) \ - STMT_BEGIN \ - uint32_t sent_val = get_uint32(&(chunk)->U_MEM[chunk->mem_size]); \ - tor_assert(sent_val == SENTINEL_VAL); \ - STMT_END -#else /* !(defined(USE_SENTINELS)) */ -#define SENTINEL_LEN 0 -#define SET_SENTINEL(chunk) STMT_NIL -#define CHECK_SENTINEL(chunk) STMT_NIL -#endif /* defined(USE_SENTINELS) */ - -/** Increment <b>ptr</b> until it is aligned to MEMAREA_ALIGN. */ -static inline void * -realign_pointer(void *ptr) -{ - uintptr_t x = (uintptr_t)ptr; - x = (x+MEMAREA_ALIGN_MASK) & ~MEMAREA_ALIGN_MASK; - /* Reinstate this if bug 930 ever reappears - tor_assert(((void*)x) >= ptr); - */ - return (void*)x; -} - -/** Implements part of a memarea. New memory is carved off from chunk->mem in - * increasing order until a request is too big, at which point a new chunk is - * allocated. */ -typedef struct memarea_chunk_t { - /** Next chunk in this area. Only kept around so we can free it. */ - struct memarea_chunk_t *next_chunk; - size_t mem_size; /**< How much RAM is available in mem, total? */ - char *next_mem; /**< Next position in mem to allocate data at. If it's - * equal to mem+mem_size, this chunk is full. */ -#ifdef USE_ALIGNED_ATTRIBUTE - /** Actual content of the memory chunk. */ - char mem[FLEXIBLE_ARRAY_MEMBER] __attribute__((aligned(MEMAREA_ALIGN))); -#else - union { - char mem[1]; /**< Memory space in this chunk. */ - void *void_for_alignment_; /**< Dummy; used to make sure mem is aligned. */ - } u; /**< Union used to enforce alignment when we don't have support for - * doing it right. */ -#endif /* defined(USE_ALIGNED_ATTRIBUTE) */ -} memarea_chunk_t; - -/** How many bytes are needed for overhead before we get to the memory part - * of a chunk? */ -#define CHUNK_HEADER_SIZE offsetof(memarea_chunk_t, U_MEM) - -/** What's the smallest that we'll allocate a chunk? */ -#define CHUNK_SIZE 4096 - -/** A memarea_t is an allocation region for a set of small memory requests - * that will all be freed at once. */ -struct memarea_t { - memarea_chunk_t *first; /**< Top of the chunk stack: never NULL. */ -}; - -/** Helper: allocate a new memarea chunk of around <b>chunk_size</b> bytes. */ -static memarea_chunk_t * -alloc_chunk(size_t sz) -{ - tor_assert(sz < SIZE_T_CEILING); - - size_t chunk_size = sz < CHUNK_SIZE ? CHUNK_SIZE : sz; - memarea_chunk_t *res; - chunk_size += SENTINEL_LEN; - res = tor_malloc(chunk_size); - res->next_chunk = NULL; - res->mem_size = chunk_size - CHUNK_HEADER_SIZE - SENTINEL_LEN; - res->next_mem = res->U_MEM; - tor_assert(res->next_mem+res->mem_size+SENTINEL_LEN == - ((char*)res)+chunk_size); - tor_assert(realign_pointer(res->next_mem) == res->next_mem); - SET_SENTINEL(res); - return res; -} - -/** Release <b>chunk</b> from a memarea. */ -static void -memarea_chunk_free_unchecked(memarea_chunk_t *chunk) -{ - CHECK_SENTINEL(chunk); - tor_free(chunk); -} - -/** Allocate and return new memarea. */ -memarea_t * -memarea_new(void) -{ - memarea_t *head = tor_malloc(sizeof(memarea_t)); - head->first = alloc_chunk(CHUNK_SIZE); - return head; -} - -/** Free <b>area</b>, invalidating all pointers returned from memarea_alloc() - * and friends for this area */ -void -memarea_drop_all_(memarea_t *area) -{ - memarea_chunk_t *chunk, *next; - for (chunk = area->first; chunk; chunk = next) { - next = chunk->next_chunk; - memarea_chunk_free_unchecked(chunk); - } - area->first = NULL; /*fail fast on */ - tor_free(area); -} - -/** Forget about having allocated anything in <b>area</b>, and free some of - * the backing storage associated with it, as appropriate. Invalidates all - * pointers returned from memarea_alloc() for this area. */ -void -memarea_clear(memarea_t *area) -{ - memarea_chunk_t *chunk, *next; - if (area->first->next_chunk) { - for (chunk = area->first->next_chunk; chunk; chunk = next) { - next = chunk->next_chunk; - memarea_chunk_free_unchecked(chunk); - } - area->first->next_chunk = NULL; - } - area->first->next_mem = area->first->U_MEM; -} - -/** Return true iff <b>p</b> is in a range that has been returned by an - * allocation from <b>area</b>. */ -int -memarea_owns_ptr(const memarea_t *area, const void *p) -{ - memarea_chunk_t *chunk; - const char *ptr = p; - for (chunk = area->first; chunk; chunk = chunk->next_chunk) { - if (ptr >= chunk->U_MEM && ptr < chunk->next_mem) - return 1; - } - return 0; -} - -/** Return a pointer to a chunk of memory in <b>area</b> of at least <b>sz</b> - * bytes. <b>sz</b> should be significantly smaller than the area's chunk - * size, though we can deal if it isn't. */ -void * -memarea_alloc(memarea_t *area, size_t sz) -{ - memarea_chunk_t *chunk = area->first; - char *result; - tor_assert(chunk); - CHECK_SENTINEL(chunk); - tor_assert(sz < SIZE_T_CEILING); - if (sz == 0) - sz = 1; - tor_assert(chunk->next_mem <= chunk->U_MEM + chunk->mem_size); - const size_t space_remaining = - (chunk->U_MEM + chunk->mem_size) - chunk->next_mem; - if (sz > space_remaining) { - if (sz+CHUNK_HEADER_SIZE >= CHUNK_SIZE) { - /* This allocation is too big. Stick it in a special chunk, and put - * that chunk second in the list. */ - memarea_chunk_t *new_chunk = alloc_chunk(sz+CHUNK_HEADER_SIZE); - new_chunk->next_chunk = chunk->next_chunk; - chunk->next_chunk = new_chunk; - chunk = new_chunk; - } else { - memarea_chunk_t *new_chunk = alloc_chunk(CHUNK_SIZE); - new_chunk->next_chunk = chunk; - area->first = chunk = new_chunk; - } - tor_assert(chunk->mem_size >= sz); - } - result = chunk->next_mem; - chunk->next_mem = chunk->next_mem + sz; - /* Reinstate these if bug 930 ever comes back - tor_assert(chunk->next_mem >= chunk->U_MEM); - tor_assert(chunk->next_mem <= chunk->U_MEM+chunk->mem_size); - */ - chunk->next_mem = realign_pointer(chunk->next_mem); - return result; -} - -/** As memarea_alloc(), but clears the memory it returns. */ -void * -memarea_alloc_zero(memarea_t *area, size_t sz) -{ - void *result = memarea_alloc(area, sz); - memset(result, 0, sz); - return result; -} - -/** As memdup, but returns the memory from <b>area</b>. */ -void * -memarea_memdup(memarea_t *area, const void *s, size_t n) -{ - char *result = memarea_alloc(area, n); - memcpy(result, s, n); - return result; -} - -/** As strdup, but returns the memory from <b>area</b>. */ -char * -memarea_strdup(memarea_t *area, const char *s) -{ - return memarea_memdup(area, s, strlen(s)+1); -} - -/** As strndup, but returns the memory from <b>area</b>. */ -char * -memarea_strndup(memarea_t *area, const char *s, size_t n) -{ - size_t ln = 0; - char *result; - tor_assert(n < SIZE_T_CEILING); - for (ln = 0; ln < n && s[ln]; ++ln) - ; - result = memarea_alloc(area, ln+1); - memcpy(result, s, ln); - result[ln]='\0'; - return result; -} - -/** Set <b>allocated_out</b> to the number of bytes allocated in <b>area</b>, - * and <b>used_out</b> to the number of bytes currently used. */ -void -memarea_get_stats(memarea_t *area, size_t *allocated_out, size_t *used_out) -{ - size_t a = 0, u = 0; - memarea_chunk_t *chunk; - for (chunk = area->first; chunk; chunk = chunk->next_chunk) { - CHECK_SENTINEL(chunk); - a += CHUNK_HEADER_SIZE + chunk->mem_size; - tor_assert(chunk->next_mem >= chunk->U_MEM); - u += CHUNK_HEADER_SIZE + (chunk->next_mem - chunk->U_MEM); - } - *allocated_out = a; - *used_out = u; -} - -/** Assert that <b>area</b> is okay. */ -void -memarea_assert_ok(memarea_t *area) -{ - memarea_chunk_t *chunk; - tor_assert(area->first); - - for (chunk = area->first; chunk; chunk = chunk->next_chunk) { - CHECK_SENTINEL(chunk); - tor_assert(chunk->next_mem >= chunk->U_MEM); - tor_assert(chunk->next_mem <= - (char*) realign_pointer(chunk->U_MEM+chunk->mem_size)); - } -} - -#else /* !(!defined(DISABLE_MEMORY_SENTINELS)) */ - -struct memarea_t { - smartlist_t *pieces; -}; - -memarea_t * -memarea_new(void) -{ - memarea_t *ma = tor_malloc_zero(sizeof(memarea_t)); - ma->pieces = smartlist_new(); - return ma; -} -void -memarea_drop_all_(memarea_t *area) -{ - memarea_clear(area); - smartlist_free(area->pieces); - tor_free(area); -} -void -memarea_clear(memarea_t *area) -{ - SMARTLIST_FOREACH(area->pieces, void *, p, tor_free_(p)); - smartlist_clear(area->pieces); -} -int -memarea_owns_ptr(const memarea_t *area, const void *ptr) -{ - SMARTLIST_FOREACH(area->pieces, const void *, p, if (ptr == p) return 1;); - return 0; -} - -void * -memarea_alloc(memarea_t *area, size_t sz) -{ - void *result = tor_malloc(sz); - smartlist_add(area->pieces, result); - return result; -} - -void * -memarea_alloc_zero(memarea_t *area, size_t sz) -{ - void *result = tor_malloc_zero(sz); - smartlist_add(area->pieces, result); - return result; -} -void * -memarea_memdup(memarea_t *area, const void *s, size_t n) -{ - void *r = memarea_alloc(area, n); - memcpy(r, s, n); - return r; -} -char * -memarea_strdup(memarea_t *area, const char *s) -{ - size_t n = strlen(s); - char *r = memarea_alloc(area, n+1); - memcpy(r, s, n); - r[n] = 0; - return r; -} -char * -memarea_strndup(memarea_t *area, const char *s, size_t n) -{ - size_t ln = strnlen(s, n); - char *r = memarea_alloc(area, ln+1); - memcpy(r, s, ln); - r[ln] = 0; - return r; -} -void -memarea_get_stats(memarea_t *area, - size_t *allocated_out, size_t *used_out) -{ - (void)area; - *allocated_out = *used_out = 128; -} -void -memarea_assert_ok(memarea_t *area) -{ - (void)area; -} - -#endif /* !defined(DISABLE_MEMORY_SENTINELS) */ - diff --git a/src/common/memarea.h b/src/common/memarea.h deleted file mode 100644 index 5207e8a5bd..0000000000 --- a/src/common/memarea.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2008-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ -/* Tor dependencies */ - -#ifndef TOR_MEMAREA_H -#define TOR_MEMAREA_H - -typedef struct memarea_t memarea_t; - -memarea_t *memarea_new(void); -void memarea_drop_all_(memarea_t *area); -#define memarea_drop_all(area) \ - do { \ - memarea_drop_all_(area); \ - (area) = NULL; \ - } while (0) -void memarea_clear(memarea_t *area); -int memarea_owns_ptr(const memarea_t *area, const void *ptr); -void *memarea_alloc(memarea_t *area, size_t sz); -void *memarea_alloc_zero(memarea_t *area, size_t sz); -void *memarea_memdup(memarea_t *area, const void *s, size_t n); -char *memarea_strdup(memarea_t *area, const char *s); -char *memarea_strndup(memarea_t *area, const char *s, size_t n); -void memarea_get_stats(memarea_t *area, - size_t *allocated_out, size_t *used_out); -void memarea_assert_ok(memarea_t *area); - -#endif /* !defined(TOR_MEMAREA_H) */ - diff --git a/src/common/procmon.c b/src/common/procmon.c deleted file mode 100644 index 73c14cd584..0000000000 --- a/src/common/procmon.c +++ /dev/null @@ -1,332 +0,0 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file procmon.c - * \brief Process-termination monitor functions - **/ - -#include "procmon.h" - -#include "util.h" - -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif - -#ifdef _WIN32 -#include <windows.h> -#endif - -#if (0 == SIZEOF_PID_T) && defined(_WIN32) -/* Windows does not define pid_t sometimes, but _getpid() returns an int. - * Everybody else needs to have a pid_t. */ -typedef int pid_t; -#define PID_T_FORMAT "%d" -#elif (SIZEOF_PID_T == SIZEOF_INT) || (SIZEOF_PID_T == SIZEOF_SHORT) -#define PID_T_FORMAT "%d" -#elif (SIZEOF_PID_T == SIZEOF_LONG) -#define PID_T_FORMAT "%ld" -#elif (SIZEOF_PID_T == SIZEOF_INT64_T) -#define PID_T_FORMAT I64_FORMAT -#else -#error Unknown: SIZEOF_PID_T -#endif /* (0 == SIZEOF_PID_T) && defined(_WIN32) || ... */ - -/* Define to 1 if process-termination monitors on this OS and Libevent - version must poll for process termination themselves. */ -#define PROCMON_POLLS 1 -/* Currently we need to poll in some way on all systems. */ - -#ifdef PROCMON_POLLS -static void tor_process_monitor_poll_cb(periodic_timer_t *ev, - void *procmon_); -#endif - -/* This struct may contain pointers into the original process - * specifier string, but it should *never* contain anything which - * needs to be freed. */ -/* DOCDOC parsed_process_specifier_t */ -struct parsed_process_specifier_t { - pid_t pid; -}; - -/** Parse the process specifier given in <b>process_spec</b> into - * *<b>ppspec</b>. Return 0 on success; return -1 and store an error - * message into *<b>msg</b> on failure. The caller must not free the - * returned error message. */ -static int -parse_process_specifier(const char *process_spec, - struct parsed_process_specifier_t *ppspec, - const char **msg) -{ - long pid_l; - int pid_ok = 0; - char *pspec_next; - - /* If we're lucky, long will turn out to be large enough to hold a - * PID everywhere that Tor runs. */ - pid_l = tor_parse_long(process_spec, 10, 1, LONG_MAX, &pid_ok, &pspec_next); - - /* Reserve room in the ‘process specifier’ for additional - * (platform-specific) identifying information beyond the PID, to - * make our process-existence checks a bit less racy in a future - * version. */ - if ((*pspec_next != 0) && (*pspec_next != ' ') && (*pspec_next != ':')) { - pid_ok = 0; - } - - ppspec->pid = (pid_t)(pid_l); - if (!pid_ok || (pid_l != (long)(ppspec->pid))) { - *msg = "invalid PID"; - goto err; - } - - return 0; - err: - return -1; -} - -/* DOCDOC tor_process_monitor_t */ -struct tor_process_monitor_t { - /** Log domain for warning messages. */ - log_domain_mask_t log_domain; - - /** All systems: The best we can do in general is poll for the - * process's existence by PID periodically, and hope that the kernel - * doesn't reassign the same PID to another process between our - * polls. */ - pid_t pid; - -#ifdef _WIN32 - /** Windows-only: Should we poll hproc? If false, poll pid - * instead. */ - int poll_hproc; - - /** Windows-only: Get a handle to the process (if possible) and - * periodically check whether the process we have a handle to has - * ended. */ - HANDLE hproc; - /* XXXX We should have Libevent watch hproc for us, - * if/when some version of Libevent can be told to do so. */ -#endif /* defined(_WIN32) */ - - /* XXXX On Linux, we can and should receive the 22nd - * (space-delimited) field (‘starttime’) of /proc/$PID/stat from the - * owning controller and store it, and poll once in a while to see - * whether it has changed -- if so, the kernel has *definitely* - * reassigned the owning controller's PID and we should exit. On - * FreeBSD, we can do the same trick using either the 8th - * space-delimited field of /proc/$PID/status on the seven FBSD - * systems whose admins have mounted procfs, or the start-time field - * of the process-information structure returned by kvmgetprocs() on - * any system. The latter is ickier. */ - - /* XXXX On FreeBSD (and possibly other kqueue systems), we can and - * should arrange to receive EVFILT_PROC NOTE_EXIT notifications for - * pid, so we don't have to do such a heavyweight poll operation in - * order to avoid the PID-reassignment race condition. (We would - * still need to poll our own kqueue periodically until some version - * of Libevent 2.x learns to receive these events for us.) */ - - /** A Libevent event structure, to either poll for the process's - * existence or receive a notification when the process ends. */ - periodic_timer_t *e; - - /** A callback to be called when the process ends. */ - tor_procmon_callback_t cb; - void *cb_arg; /**< A user-specified pointer to be passed to cb. */ -}; - -/** Verify that the process specifier given in <b>process_spec</b> is - * syntactically valid. Return 0 on success; return -1 and store an - * error message into *<b>msg</b> on failure. The caller must not - * free the returned error message. */ -int -tor_validate_process_specifier(const char *process_spec, - const char **msg) -{ - struct parsed_process_specifier_t ppspec; - - tor_assert(msg != NULL); - *msg = NULL; - - return parse_process_specifier(process_spec, &ppspec, msg); -} - -/* DOCDOC poll_interval_tv */ -static const struct timeval poll_interval_tv = {15, 0}; - -/** Create a process-termination monitor for the process specifier - * given in <b>process_spec</b>. Return a newly allocated - * tor_process_monitor_t on success; return NULL and store an error - * message into *<b>msg</b> on failure. The caller must not free - * the returned error message. - * - * When the monitored process terminates, call - * <b>cb</b>(<b>cb_arg</b>). - */ -tor_process_monitor_t * -tor_process_monitor_new(struct event_base *base, - const char *process_spec, - log_domain_mask_t log_domain, - tor_procmon_callback_t cb, void *cb_arg, - const char **msg) -{ - tor_process_monitor_t *procmon = tor_malloc_zero( - sizeof(tor_process_monitor_t)); - struct parsed_process_specifier_t ppspec; - - tor_assert(msg != NULL); - *msg = NULL; - - if (procmon == NULL) { - *msg = "out of memory"; - goto err; - } - - procmon->log_domain = log_domain; - - if (parse_process_specifier(process_spec, &ppspec, msg)) - goto err; - - procmon->pid = ppspec.pid; - -#ifdef _WIN32 - procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, - FALSE, - procmon->pid); - - if (procmon->hproc != NULL) { - procmon->poll_hproc = 1; - log_info(procmon->log_domain, "Successfully opened handle to process " - PID_T_FORMAT"; " - "monitoring it.", - procmon->pid); - } else { - /* If we couldn't get a handle to the process, we'll try again the - * first time we poll. */ - log_info(procmon->log_domain, "Failed to open handle to process " - PID_T_FORMAT"; will " - "try again later.", - procmon->pid); - } -#endif /* defined(_WIN32) */ - - procmon->cb = cb; - procmon->cb_arg = cb_arg; - -#ifdef PROCMON_POLLS - procmon->e = periodic_timer_new(base, - &poll_interval_tv, - tor_process_monitor_poll_cb, procmon); -#else /* !(defined(PROCMON_POLLS)) */ -#error OOPS? -#endif /* defined(PROCMON_POLLS) */ - - return procmon; - err: - tor_process_monitor_free(procmon); - return NULL; -} - -#ifdef PROCMON_POLLS -/** Libevent callback to poll for the existence of the process - * monitored by <b>procmon_</b>. */ -static void -tor_process_monitor_poll_cb(periodic_timer_t *event, void *procmon_) -{ - (void)event; - tor_process_monitor_t *procmon = (tor_process_monitor_t *)(procmon_); - int its_dead_jim; - - tor_assert(procmon != NULL); - -#ifdef _WIN32 - if (procmon->poll_hproc) { - DWORD exit_code; - if (!GetExitCodeProcess(procmon->hproc, &exit_code)) { - char *errmsg = format_win32_error(GetLastError()); - log_warn(procmon->log_domain, "Error \"%s\" occurred while polling " - "handle for monitored process "PID_T_FORMAT"; assuming " - "it's dead.", - errmsg, procmon->pid); - tor_free(errmsg); - its_dead_jim = 1; - } else { - its_dead_jim = (exit_code != STILL_ACTIVE); - } - } else { - /* All we can do is try to open the process, and look at the error - * code if it fails again. */ - procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, - FALSE, - procmon->pid); - - if (procmon->hproc != NULL) { - log_info(procmon->log_domain, "Successfully opened handle to monitored " - "process "PID_T_FORMAT".", - procmon->pid); - its_dead_jim = 0; - procmon->poll_hproc = 1; - } else { - DWORD err_code = GetLastError(); - char *errmsg = format_win32_error(err_code); - - /* When I tested OpenProcess's error codes on Windows 7, I - * received error code 5 (ERROR_ACCESS_DENIED) for PIDs of - * existing processes that I could not open and error code 87 - * (ERROR_INVALID_PARAMETER) for PIDs that were not in use. - * Since the nonexistent-process error code is sane, I'm going - * to assume that all errors other than ERROR_INVALID_PARAMETER - * mean that the process we are monitoring is still alive. */ - its_dead_jim = (err_code == ERROR_INVALID_PARAMETER); - - if (!its_dead_jim) - log_info(procmon->log_domain, "Failed to open handle to monitored " - "process "PID_T_FORMAT", and error code %lu (%s) is not " - "'invalid parameter' -- assuming the process is still alive.", - procmon->pid, - err_code, errmsg); - - tor_free(errmsg); - } - } -#else /* !(defined(_WIN32)) */ - /* Unix makes this part easy, if a bit racy. */ - its_dead_jim = kill(procmon->pid, 0); - its_dead_jim = its_dead_jim && (errno == ESRCH); -#endif /* defined(_WIN32) */ - - tor_log(its_dead_jim ? LOG_NOTICE : LOG_INFO, - procmon->log_domain, "Monitored process "PID_T_FORMAT" is %s.", - procmon->pid, - its_dead_jim ? "dead" : "still alive"); - - if (its_dead_jim) { - procmon->cb(procmon->cb_arg); - } -} -#endif /* defined(PROCMON_POLLS) */ - -/** Free the process-termination monitor <b>procmon</b>. */ -void -tor_process_monitor_free_(tor_process_monitor_t *procmon) -{ - if (procmon == NULL) - return; - -#ifdef _WIN32 - if (procmon->hproc != NULL) - CloseHandle(procmon->hproc); -#endif - - if (procmon->e != NULL) - periodic_timer_free(procmon->e); - - tor_free(procmon); -} - diff --git a/src/common/procmon.h b/src/common/procmon.h deleted file mode 100644 index 63777e4111..0000000000 --- a/src/common/procmon.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file procmon.h - * \brief Headers for procmon.c - **/ - -#ifndef TOR_PROCMON_H -#define TOR_PROCMON_H - -#include "compat.h" -#include "compat_libevent.h" - -#include "torlog.h" - -typedef struct tor_process_monitor_t tor_process_monitor_t; - -/* DOCDOC tor_procmon_callback_t */ -typedef void (*tor_procmon_callback_t)(void *); - -int tor_validate_process_specifier(const char *process_spec, - const char **msg); -tor_process_monitor_t *tor_process_monitor_new(struct event_base *base, - const char *process_spec, - log_domain_mask_t log_domain, - tor_procmon_callback_t cb, - void *cb_arg, - const char **msg); -void tor_process_monitor_free_(tor_process_monitor_t *procmon); -#define tor_process_monitor_free(procmon) \ - FREE_AND_NULL(tor_process_monitor_t, tor_process_monitor_free_, (procmon)) - -#endif /* !defined(TOR_PROCMON_H) */ - diff --git a/src/common/pubsub.c b/src/common/pubsub.c deleted file mode 100644 index 336e8a6e7f..0000000000 --- a/src/common/pubsub.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file pubsub.c - * - * \brief DOCDOC - */ - -#include "orconfig.h" -#include "pubsub.h" -#include "container.h" - -/** Helper: insert <b>s</b> into <b>topic's</b> list of subscribers, keeping - * them sorted in priority order. */ -static void -subscriber_insert(pubsub_topic_t *topic, pubsub_subscriber_t *s) -{ - int i; - smartlist_t *sl = topic->subscribers; - for (i = 0; i < smartlist_len(sl); ++i) { - pubsub_subscriber_t *other = smartlist_get(sl, i); - if (s->priority < other->priority) { - break; - } - } - smartlist_insert(sl, i, s); -} - -/** - * Add a new subscriber to <b>topic</b>, where (when an event is triggered), - * we'll notify the function <b>fn</b> by passing it <b>subscriber_data</b>. - * Return a handle to the subscribe which can later be passed to - * pubsub_unsubscribe_(). - * - * Functions are called in priority order, from lowest to highest. - * - * See pubsub.h for <b>subscribe_flags</b>. - */ -const pubsub_subscriber_t * -pubsub_subscribe_(pubsub_topic_t *topic, - pubsub_subscriber_fn_t fn, - void *subscriber_data, - unsigned subscribe_flags, - unsigned priority) -{ - tor_assert(! topic->locked); - if (subscribe_flags & SUBSCRIBE_ATSTART) { - tor_assert(topic->n_events_fired == 0); - } - pubsub_subscriber_t *r = tor_malloc_zero(sizeof(*r)); - r->priority = priority; - r->subscriber_flags = subscribe_flags; - r->fn = fn; - r->subscriber_data = subscriber_data; - if (topic->subscribers == NULL) { - topic->subscribers = smartlist_new(); - } - subscriber_insert(topic, r); - return r; -} - -/** - * Remove the subscriber <b>s</b> from <b>topic</b>. After calling this - * function, <b>s</b> may no longer be used. - */ -int -pubsub_unsubscribe_(pubsub_topic_t *topic, - const pubsub_subscriber_t *s) -{ - tor_assert(! topic->locked); - smartlist_t *sl = topic->subscribers; - if (sl == NULL) - return -1; - int i = smartlist_pos(sl, s); - if (i == -1) - return -1; - pubsub_subscriber_t *tmp = smartlist_get(sl, i); - tor_assert(tmp == s); - smartlist_del_keeporder(sl, i); - tor_free(tmp); - return 0; -} - -/** - * For every subscriber s in <b>topic</b>, invoke notify_fn on s and - * event_data. Return 0 if there were no nonzero return values, and -1 if - * there were any. - */ -int -pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn, - void *event_data, unsigned notify_flags) -{ - tor_assert(! topic->locked); - (void) notify_flags; - smartlist_t *sl = topic->subscribers; - int n_bad = 0; - ++topic->n_events_fired; - if (sl == NULL) - return -1; - topic->locked = 1; - SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) { - int r = notify_fn(s, event_data); - if (r != 0) - ++n_bad; - } SMARTLIST_FOREACH_END(s); - topic->locked = 0; - return (n_bad == 0) ? 0 : -1; -} - -/** - * Release all storage held by <b>topic</b>. - */ -void -pubsub_clear_(pubsub_topic_t *topic) -{ - tor_assert(! topic->locked); - - smartlist_t *sl = topic->subscribers; - if (sl == NULL) - return; - SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) { - tor_free(s); - } SMARTLIST_FOREACH_END(s); - smartlist_free(sl); - topic->subscribers = NULL; - topic->n_events_fired = 0; -} - diff --git a/src/common/pubsub.h b/src/common/pubsub.h deleted file mode 100644 index 2bee3af085..0000000000 --- a/src/common/pubsub.h +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file pubsub.h - * \brief Macros to implement publish/subscribe abstractions. - * - * To use these macros, call DECLARE_PUBSUB_TOPIC() with an identifier to use - * as your topic. Below, I'm going to assume you say DECLARE_PUBSUB_TOPIC(T). - * - * Doing this will declare the following types: - * typedef struct T_event_data_t T_event_data_t; // you define this struct - * typedef struct T_subscriber_data_t T_subscriber_data_t; // this one too. - * typedef struct T_subscriber_t T_subscriber_t; // opaque - * typedef int (*T_subscriber_fn_t)(T_event_data_t*, T_subscriber_data_t*); - * - * and it will declare the following functions: - * const T_subscriber_t *T_subscribe(T_subscriber_fn_t, - * T_subscriber_data_t *, - * unsigned flags, - * unsigned priority); - * int T_unsubscribe(const T_subscriber_t *) - * - * Elsewhere you can say DECLARE_NOTIFY_PUBSUB_TOPIC(static, T), which - * declares: - * - * static int T_notify(T_event_data_t *, unsigned notify_flags); - * static void T_clear(void); - * - * And in some C file, you would define these functions with: - * IMPLEMENT_PUBSUB_TOPIC(static, T). - * - * The implementations will be small typesafe wrappers over generic versions - * of the above functions. - * - * To use the typesafe functions, you add any number of subscribers with - * T_subscribe(). Each has an associated function pointer, data pointer, - * and priority. Later, you can invoke T_notify() to declare that the - * event has occurred. Each of the subscribers will be invoked once. - **/ - -#ifndef TOR_PUBSUB_H -#define TOR_PUBSUB_H - -#include "torint.h" - -/** - * Flag for T_subscribe: die with an assertion failure if the event - * have ever been published before. Used when a subscriber must absolutely - * never have missed an event. - */ -#define SUBSCRIBE_ATSTART (1u<<0) - -#define DECLARE_PUBSUB_STRUCT_TYPES(name) \ - /* You define this type. */ \ - typedef struct name ## _event_data_t name ## _event_data_t; \ - /* You define this type. */ \ - typedef struct name ## _subscriber_data_t name ## _subscriber_data_t; - -#define DECLARE_PUBSUB_TOPIC(name) \ - /* This type is opaque. */ \ - typedef struct name ## _subscriber_t name ## _subscriber_t; \ - /* You declare functions matching this type. */ \ - typedef int (*name ## _subscriber_fn_t)( \ - name ## _event_data_t *data, \ - name ## _subscriber_data_t *extra); \ - /* Call this function to subscribe to a topic. */ \ - const name ## _subscriber_t *name ## _subscribe( \ - name##_subscriber_fn_t subscriber, \ - name##_subscriber_data_t *extra_data, \ - unsigned flags, \ - unsigned priority); \ - /* Call this function to unsubscribe from a topic. */ \ - int name ## _unsubscribe(const name##_subscriber_t *s); - -#define DECLARE_NOTIFY_PUBSUB_TOPIC(linkage, name) \ - /* Call this function to notify all subscribers. Flags not yet used. */ \ - linkage int name ## _notify(name ## _event_data_t *data, unsigned flags); \ - /* Call this function to release storage held by the topic. */ \ - linkage void name ## _clear(void); - -/** - * Type used to hold a generic function for a subscriber. - * - * [Yes, it is safe to cast to this, so long as we cast back to the original - * type before calling. From C99: "A pointer to a function of one type may be - * converted to a pointer to a function of another type and back again; the - * result shall compare equal to the original pointer."] -*/ -typedef int (*pubsub_subscriber_fn_t)(void *, void *); - -/** - * Helper type to implement pubsub abstraction. Don't use this directly. - * It represents a subscriber. - */ -typedef struct pubsub_subscriber_t { - /** Function to invoke when the event triggers. */ - pubsub_subscriber_fn_t fn; - /** Data associated with this subscriber. */ - void *subscriber_data; - /** Priority for this subscriber. Low priorities happen first. */ - unsigned priority; - /** Flags set on this subscriber. Not yet used.*/ - unsigned subscriber_flags; -} pubsub_subscriber_t; - -/** - * Helper type to implement pubsub abstraction. Don't use this directly. - * It represents a topic, and keeps a record of subscribers. - */ -typedef struct pubsub_topic_t { - /** List of subscribers to this topic. May be NULL. */ - struct smartlist_t *subscribers; - /** Total number of times that pubsub_notify_() has ever been called on this - * topic. */ - uint64_t n_events_fired; - /** True iff we're running 'notify' on this topic, and shouldn't allow - * any concurrent modifications or events. */ - unsigned locked; -} pubsub_topic_t; - -const pubsub_subscriber_t *pubsub_subscribe_(pubsub_topic_t *topic, - pubsub_subscriber_fn_t fn, - void *subscriber_data, - unsigned subscribe_flags, - unsigned priority); -int pubsub_unsubscribe_(pubsub_topic_t *topic, const pubsub_subscriber_t *sub); -void pubsub_clear_(pubsub_topic_t *topic); -typedef int (*pubsub_notify_fn_t)(pubsub_subscriber_t *subscriber, - void *notify_data); -int pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn, - void *notify_data, unsigned notify_flags); - -#define IMPLEMENT_PUBSUB_TOPIC(notify_linkage, name) \ - static pubsub_topic_t name ## _topic_ = { NULL, 0, 0 }; \ - const name ## _subscriber_t * \ - name ## _subscribe(name##_subscriber_fn_t subscriber, \ - name##_subscriber_data_t *extra_data, \ - unsigned flags, \ - unsigned priority) \ - { \ - const pubsub_subscriber_t *s; \ - s = pubsub_subscribe_(&name##_topic_, \ - (pubsub_subscriber_fn_t)subscriber, \ - extra_data, \ - flags, \ - priority); \ - return (const name##_subscriber_t *)s; \ - } \ - int \ - name ## _unsubscribe(const name##_subscriber_t *subscriber) \ - { \ - return pubsub_unsubscribe_(&name##_topic_, \ - (const pubsub_subscriber_t *)subscriber); \ - } \ - static int \ - name##_call_the_notify_fn_(pubsub_subscriber_t *subscriber, \ - void *notify_data) \ - { \ - name ## _subscriber_fn_t fn; \ - fn = (name ## _subscriber_fn_t) subscriber->fn; \ - return fn(notify_data, subscriber->subscriber_data); \ - } \ - notify_linkage int \ - name ## _notify(name ## _event_data_t *event_data, unsigned flags) \ - { \ - return pubsub_notify_(&name##_topic_, \ - name##_call_the_notify_fn_, \ - event_data, \ - flags); \ - } \ - notify_linkage void \ - name ## _clear(void) \ - { \ - pubsub_clear_(&name##_topic_); \ - } - -#endif /* !defined(TOR_PUBSUB_H) */ - diff --git a/src/common/sandbox.c b/src/common/sandbox.c deleted file mode 100644 index ca7803ac9c..0000000000 --- a/src/common/sandbox.c +++ /dev/null @@ -1,1977 +0,0 @@ - /* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file sandbox.c - * \brief Code to enable sandboxing. - **/ - -#include "orconfig.h" - -#ifndef _LARGEFILE64_SOURCE -/** - * Temporarily required for O_LARGEFILE flag. Needs to be removed - * with the libevent fix. - */ -#define _LARGEFILE64_SOURCE -#endif /* !defined(_LARGEFILE64_SOURCE) */ - -/** Malloc mprotect limit in bytes. - * - * 28/06/2017: This value was increased from 16 MB to 20 MB after we introduced - * LZMA support in Tor (0.3.1.1-alpha). We limit our LZMA coder to 16 MB, but - * liblzma have a small overhead that we need to compensate for to avoid being - * killed by the sandbox. - */ -#define MALLOC_MP_LIM (20*1024*1024) - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#include "sandbox.h" -#include "container.h" -#include "torlog.h" -#include "torint.h" -#include "util.h" -#include "tor_queue.h" - -#include "ht.h" - -#define DEBUGGING_CLOSE - -#if defined(USE_LIBSECCOMP) - -#include <sys/mman.h> -#include <sys/syscall.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/epoll.h> -#include <sys/prctl.h> -#include <linux/futex.h> -#include <sys/file.h> - -#include <stdarg.h> -#include <seccomp.h> -#include <signal.h> -#include <unistd.h> -#include <fcntl.h> -#include <time.h> -#include <poll.h> - -#ifdef HAVE_GNU_LIBC_VERSION_H -#include <gnu/libc-version.h> -#endif -#ifdef HAVE_LINUX_NETFILTER_IPV4_H -#include <linux/netfilter_ipv4.h> -#endif -#ifdef HAVE_LINUX_IF_H -#include <linux/if.h> -#endif -#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H -#include <linux/netfilter_ipv6/ip6_tables.h> -#endif - -#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ - defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) -#define USE_BACKTRACE -#define EXPOSE_CLEAN_BACKTRACE -#include "backtrace.h" -#endif /* defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && ... */ - -#ifdef USE_BACKTRACE -#include <execinfo.h> -#endif - -/** - * Linux 32 bit definitions - */ -#if defined(__i386__) - -#define REG_SYSCALL REG_EAX -#define M_SYSCALL gregs[REG_SYSCALL] - -/** - * Linux 64 bit definitions - */ -#elif defined(__x86_64__) - -#define REG_SYSCALL REG_RAX -#define M_SYSCALL gregs[REG_SYSCALL] - -#elif defined(__arm__) - -#define M_SYSCALL arm_r7 - -#elif defined(__aarch64__) && defined(__LP64__) - -#define REG_SYSCALL 8 -#define M_SYSCALL regs[REG_SYSCALL] - -#endif /* defined(__i386__) || ... */ - -/**Determines if at least one sandbox is active.*/ -static int sandbox_active = 0; -/** Holds the parameter list configuration for the sandbox.*/ -static sandbox_cfg_t *filter_dynamic = NULL; - -#undef SCMP_CMP -#define SCMP_CMP(a,b,c) ((struct scmp_arg_cmp){(a),(b),(c),0}) -#define SCMP_CMP_STR(a,b,c) \ - ((struct scmp_arg_cmp) {(a),(b),(intptr_t)(void*)(c),0}) -#define SCMP_CMP4(a,b,c,d) ((struct scmp_arg_cmp){(a),(b),(c),(d)}) -/* We use a wrapper here because these masked comparisons seem to be pretty - * verbose. Also, it's important to cast to scmp_datum_t before negating the - * mask, since otherwise the negation might get applied to a 32 bit value, and - * the high bits of the value might get masked out improperly. */ -#define SCMP_CMP_MASKED(a,b,c) \ - SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, ~(scmp_datum_t)(b), (c)) - -/** Variable used for storing all syscall numbers that will be allowed with the - * stage 1 general Tor sandbox. - */ -static int filter_nopar_gen[] = { - SCMP_SYS(access), - SCMP_SYS(brk), - SCMP_SYS(clock_gettime), - SCMP_SYS(close), - SCMP_SYS(clone), - SCMP_SYS(epoll_create), - SCMP_SYS(epoll_wait), -#ifdef __NR_epoll_pwait - SCMP_SYS(epoll_pwait), -#endif -#ifdef HAVE_EVENTFD - SCMP_SYS(eventfd2), -#endif -#ifdef HAVE_PIPE2 - SCMP_SYS(pipe2), -#endif -#ifdef HAVE_PIPE - SCMP_SYS(pipe), -#endif -#ifdef __NR_fchmod - SCMP_SYS(fchmod), -#endif - SCMP_SYS(fcntl), - SCMP_SYS(fstat), -#ifdef __NR_fstat64 - SCMP_SYS(fstat64), -#endif - SCMP_SYS(futex), - SCMP_SYS(getdents), - SCMP_SYS(getdents64), - SCMP_SYS(getegid), -#ifdef __NR_getegid32 - SCMP_SYS(getegid32), -#endif - SCMP_SYS(geteuid), -#ifdef __NR_geteuid32 - SCMP_SYS(geteuid32), -#endif - SCMP_SYS(getgid), -#ifdef __NR_getgid32 - SCMP_SYS(getgid32), -#endif - SCMP_SYS(getpid), -#ifdef __NR_getrlimit - SCMP_SYS(getrlimit), -#endif - SCMP_SYS(gettimeofday), - SCMP_SYS(gettid), - SCMP_SYS(getuid), -#ifdef __NR_getuid32 - SCMP_SYS(getuid32), -#endif - SCMP_SYS(lseek), -#ifdef __NR__llseek - SCMP_SYS(_llseek), -#endif - SCMP_SYS(mkdir), - SCMP_SYS(mlockall), -#ifdef __NR_mmap - /* XXXX restrict this in the same ways as mmap2 */ - SCMP_SYS(mmap), -#endif - SCMP_SYS(munmap), -#ifdef __NR_nanosleep - SCMP_SYS(nanosleep), -#endif -#ifdef __NR_prlimit - SCMP_SYS(prlimit), -#endif -#ifdef __NR_prlimit64 - SCMP_SYS(prlimit64), -#endif - SCMP_SYS(read), - SCMP_SYS(rt_sigreturn), - SCMP_SYS(sched_getaffinity), -#ifdef __NR_sched_yield - SCMP_SYS(sched_yield), -#endif - SCMP_SYS(sendmsg), - SCMP_SYS(set_robust_list), -#ifdef __NR_setrlimit - SCMP_SYS(setrlimit), -#endif -#ifdef __NR_sigaltstack - SCMP_SYS(sigaltstack), -#endif -#ifdef __NR_sigreturn - SCMP_SYS(sigreturn), -#endif - SCMP_SYS(stat), - SCMP_SYS(uname), - SCMP_SYS(wait4), - SCMP_SYS(write), - SCMP_SYS(writev), - SCMP_SYS(exit_group), - SCMP_SYS(exit), - - SCMP_SYS(madvise), -#ifdef __NR_stat64 - // getaddrinfo uses this.. - SCMP_SYS(stat64), -#endif - -#ifdef __NR_getrandom - SCMP_SYS(getrandom), -#endif - -#ifdef __NR_sysinfo - // qsort uses this.. - SCMP_SYS(sysinfo), -#endif - /* - * These socket syscalls are not required on x86_64 and not supported with - * some libseccomp versions (eg: 1.0.1) - */ -#if defined(__i386) - SCMP_SYS(recv), - SCMP_SYS(send), -#endif - - // socket syscalls - SCMP_SYS(bind), - SCMP_SYS(listen), - SCMP_SYS(connect), - SCMP_SYS(getsockname), - SCMP_SYS(recvmsg), - SCMP_SYS(recvfrom), - SCMP_SYS(sendto), - SCMP_SYS(unlink), - SCMP_SYS(poll) -}; - -/* These macros help avoid the error where the number of filters we add on a - * single rule don't match the arg_cnt param. */ -#define seccomp_rule_add_0(ctx,act,call) \ - seccomp_rule_add((ctx),(act),(call),0) -#define seccomp_rule_add_1(ctx,act,call,f1) \ - seccomp_rule_add((ctx),(act),(call),1,(f1)) -#define seccomp_rule_add_2(ctx,act,call,f1,f2) \ - seccomp_rule_add((ctx),(act),(call),2,(f1),(f2)) -#define seccomp_rule_add_3(ctx,act,call,f1,f2,f3) \ - seccomp_rule_add((ctx),(act),(call),3,(f1),(f2),(f3)) -#define seccomp_rule_add_4(ctx,act,call,f1,f2,f3,f4) \ - seccomp_rule_add((ctx),(act),(call),4,(f1),(f2),(f3),(f4)) - -/** - * Function responsible for setting up the rt_sigaction syscall for - * the seccomp filter sandbox. - */ -static int -sb_rt_sigaction(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - unsigned i; - int rc; - int param[] = { SIGINT, SIGTERM, SIGPIPE, SIGUSR1, SIGUSR2, SIGHUP, SIGCHLD, -#ifdef SIGXFSZ - SIGXFSZ -#endif - }; - (void) filter; - - for (i = 0; i < ARRAY_LENGTH(param); i++) { - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), - SCMP_CMP(0, SCMP_CMP_EQ, param[i])); - if (rc) - break; - } - - return rc; -} - -/** - * Function responsible for setting up the time syscall for - * the seccomp filter sandbox. - */ -static int -sb_time(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - (void) filter; -#ifdef __NR_time - return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time), - SCMP_CMP(0, SCMP_CMP_EQ, 0)); -#else - return 0; -#endif /* defined(__NR_time) */ -} - -/** - * Function responsible for setting up the accept4 syscall for - * the seccomp filter sandbox. - */ -static int -sb_accept4(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void)filter; - -#ifdef __i386__ - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall), - SCMP_CMP(0, SCMP_CMP_EQ, 18)); - if (rc) { - return rc; - } -#endif /* defined(__i386__) */ - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4), - SCMP_CMP_MASKED(3, SOCK_CLOEXEC|SOCK_NONBLOCK, 0)); - if (rc) { - return rc; - } - - return 0; -} - -#ifdef __NR_mmap2 -/** - * Function responsible for setting up the mmap2 syscall for - * the seccomp filter sandbox. - */ -static int -sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void)filter; - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ), - SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE)); - if (rc) { - return rc; - } - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE), - SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE)); - if (rc) { - return rc; - } - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE), - SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS)); - if (rc) { - return rc; - } - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE), - SCMP_CMP(3, SCMP_CMP_EQ,MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK)); - if (rc) { - return rc; - } - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE), - SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE)); - if (rc) { - return rc; - } - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE), - SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS)); - if (rc) { - return rc; - } - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_EXEC), - SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_DENYWRITE)); - if (rc) { - return rc; - } - - return 0; -} -#endif /* defined(__NR_mmap2) */ - -#ifdef HAVE_GNU_LIBC_VERSION_H -#ifdef HAVE_GNU_GET_LIBC_VERSION -#define CHECK_LIBC_VERSION -#endif -#endif - -/* Return true if we think we're running with a libc that always uses - * openat on linux. */ -static int -libc_uses_openat_for_everything(void) -{ -#ifdef CHECK_LIBC_VERSION - const char *version = gnu_get_libc_version(); - if (version == NULL) - return 0; - - int major = -1; - int minor = -1; - - tor_sscanf(version, "%d.%d", &major, &minor); - if (major >= 3) - return 1; - else if (major == 2 && minor >= 26) - return 1; - else - return 0; -#else /* !(defined(CHECK_LIBC_VERSION)) */ - return 0; -#endif /* defined(CHECK_LIBC_VERSION) */ -} - -/** Allow a single file to be opened. If <b>use_openat</b> is true, - * we're using a libc that remaps all the opens into openats. */ -static int -allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file) -{ - if (use_openat) { - return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP(0, SCMP_CMP_EQ, (unsigned int)AT_FDCWD), - SCMP_CMP_STR(1, SCMP_CMP_EQ, file)); - } else { - return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), - SCMP_CMP_STR(0, SCMP_CMP_EQ, file)); - } -} - -/** - * Function responsible for setting up the open syscall for - * the seccomp filter sandbox. - */ -static int -sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc; - sandbox_cfg_t *elem = NULL; - - int use_openat = libc_uses_openat_for_everything(); - - // for each dynamic parameter filters - for (elem = filter; elem != NULL; elem = elem->next) { - smp_param_t *param = elem->param; - - if (param != NULL && param->prot == 1 && param->syscall - == SCMP_SYS(open)) { - rc = allow_file_open(ctx, use_openat, param->value); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add open syscall, received " - "libseccomp error %d", rc); - return rc; - } - } - } - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), - SCMP_CMP_MASKED(1, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_NOFOLLOW, - O_RDONLY)); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add open syscall, received libseccomp " - "error %d", rc); - return rc; - } - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(openat), - SCMP_CMP_MASKED(2, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_NOFOLLOW, - O_RDONLY)); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received " - "libseccomp error %d", rc); - return rc; - } - - return 0; -} - -static int -sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc; - sandbox_cfg_t *elem = NULL; - - // for each dynamic parameter filters - for (elem = filter; elem != NULL; elem = elem->next) { - smp_param_t *param = elem->param; - - if (param != NULL && param->prot == 1 && param->syscall - == SCMP_SYS(chmod)) { - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chmod), - SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add chmod syscall, received " - "libseccomp error %d", rc); - return rc; - } - } - } - - return 0; -} - -static int -sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc; - sandbox_cfg_t *elem = NULL; - - // for each dynamic parameter filters - for (elem = filter; elem != NULL; elem = elem->next) { - smp_param_t *param = elem->param; - - if (param != NULL && param->prot == 1 && param->syscall - == SCMP_SYS(chown)) { - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown), - SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add chown syscall, received " - "libseccomp error %d", rc); - return rc; - } - } - } - - return 0; -} - -static int -sb__sysctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc; - (void) filter; - (void) ctx; - - rc = seccomp_rule_add_0(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(_sysctl)); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add _sysctl syscall, " - "received libseccomp error %d", rc); - return rc; - } - - return 0; -} - -/** - * Function responsible for setting up the rename syscall for - * the seccomp filter sandbox. - */ -static int -sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc; - sandbox_cfg_t *elem = NULL; - - // for each dynamic parameter filters - for (elem = filter; elem != NULL; elem = elem->next) { - smp_param_t *param = elem->param; - - if (param != NULL && param->prot == 1 && - param->syscall == SCMP_SYS(rename)) { - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rename), - SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value), - SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value2)); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add rename syscall, received " - "libseccomp error %d", rc); - return rc; - } - } - } - - return 0; -} - -/** - * Function responsible for setting up the openat syscall for - * the seccomp filter sandbox. - */ -static int -sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc; - sandbox_cfg_t *elem = NULL; - - // for each dynamic parameter filters - for (elem = filter; elem != NULL; elem = elem->next) { - smp_param_t *param = elem->param; - - if (param != NULL && param->prot == 1 && param->syscall - == SCMP_SYS(openat)) { - rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP(0, SCMP_CMP_EQ, AT_FDCWD), - SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), - SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY| - O_CLOEXEC)); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received " - "libseccomp error %d", rc); - return rc; - } - } - } - - return 0; -} - -/** - * Function responsible for setting up the socket syscall for - * the seccomp filter sandbox. - */ -static int -sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - int i, j; - (void) filter; - -#ifdef __i386__ - rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket)); - if (rc) - return rc; -#endif - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), - SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE), - SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM)); - if (rc) - return rc; - - for (i = 0; i < 2; ++i) { - const int pf = i ? PF_INET : PF_INET6; - for (j=0; j < 3; ++j) { - const int type = (j == 0) ? SOCK_STREAM : - SOCK_DGRAM; - const int protocol = (j == 0) ? IPPROTO_TCP : - (j == 1) ? IPPROTO_IP : - IPPROTO_UDP; - rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), - SCMP_CMP(0, SCMP_CMP_EQ, pf), - SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, type), - SCMP_CMP(2, SCMP_CMP_EQ, protocol)); - if (rc) - return rc; - } - } - - rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), - SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX), - SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM), - SCMP_CMP(2, SCMP_CMP_EQ, 0)); - if (rc) - return rc; - - rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), - SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX), - SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_DGRAM), - SCMP_CMP(2, SCMP_CMP_EQ, 0)); - if (rc) - return rc; - - rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), - SCMP_CMP(0, SCMP_CMP_EQ, PF_NETLINK), - SCMP_CMP_MASKED(1, SOCK_CLOEXEC, SOCK_RAW), - SCMP_CMP(2, SCMP_CMP_EQ, 0)); - if (rc) - return rc; - - return 0; -} - -/** - * Function responsible for setting up the socketpair syscall for - * the seccomp filter sandbox. - */ -static int -sb_socketpair(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - -#ifdef __i386__ - rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair)); - if (rc) - return rc; -#endif - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketpair), - SCMP_CMP(0, SCMP_CMP_EQ, PF_FILE), - SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM|SOCK_CLOEXEC)); - if (rc) - return rc; - - return 0; -} - -#ifdef HAVE_KIST_SUPPORT - -#include <linux/sockios.h> - -static int -sb_ioctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc; - (void) filter; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), - SCMP_CMP(1, SCMP_CMP_EQ, SIOCOUTQNSD)); - if (rc) - return rc; - return 0; -} - -#endif /* defined(HAVE_KIST_SUPPORT) */ - -/** - * Function responsible for setting up the setsockopt syscall for - * the seccomp filter sandbox. - */ -static int -sb_setsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - -#ifdef __i386__ - rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt)); - if (rc) - return rc; -#endif - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET), - SCMP_CMP(2, SCMP_CMP_EQ, SO_REUSEADDR)); - if (rc) - return rc; - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET), - SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUF)); - if (rc) - return rc; - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET), - SCMP_CMP(2, SCMP_CMP_EQ, SO_RCVBUF)); - if (rc) - return rc; - -#ifdef HAVE_SYSTEMD - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET), - SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUFFORCE)); - if (rc) - return rc; -#endif /* defined(HAVE_SYSTEMD) */ - -#ifdef IP_TRANSPARENT - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP), - SCMP_CMP(2, SCMP_CMP_EQ, IP_TRANSPARENT)); - if (rc) - return rc; -#endif /* defined(IP_TRANSPARENT) */ - -#ifdef IPV6_V6ONLY - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, IPPROTO_IPV6), - SCMP_CMP(2, SCMP_CMP_EQ, IPV6_V6ONLY)); - if (rc) - return rc; -#endif /* defined(IPV6_V6ONLY) */ - - return 0; -} - -/** - * Function responsible for setting up the getsockopt syscall for - * the seccomp filter sandbox. - */ -static int -sb_getsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - -#ifdef __i386__ - rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt)); - if (rc) - return rc; -#endif - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET), - SCMP_CMP(2, SCMP_CMP_EQ, SO_ERROR)); - if (rc) - return rc; - -#ifdef HAVE_SYSTEMD - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_SOCKET), - SCMP_CMP(2, SCMP_CMP_EQ, SO_SNDBUF)); - if (rc) - return rc; -#endif /* defined(HAVE_SYSTEMD) */ - -#ifdef HAVE_LINUX_NETFILTER_IPV4_H - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP), - SCMP_CMP(2, SCMP_CMP_EQ, SO_ORIGINAL_DST)); - if (rc) - return rc; -#endif /* defined(HAVE_LINUX_NETFILTER_IPV4_H) */ - -#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_IPV6), - SCMP_CMP(2, SCMP_CMP_EQ, IP6T_SO_ORIGINAL_DST)); - if (rc) - return rc; -#endif /* defined(HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H) */ - -#ifdef HAVE_KIST_SUPPORT -#include <netinet/tcp.h> - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt), - SCMP_CMP(1, SCMP_CMP_EQ, SOL_TCP), - SCMP_CMP(2, SCMP_CMP_EQ, TCP_INFO)); - if (rc) - return rc; -#endif /* defined(HAVE_KIST_SUPPORT) */ - - return 0; -} - -#ifdef __NR_fcntl64 -/** - * Function responsible for setting up the fcntl64 syscall for - * the seccomp filter sandbox. - */ -static int -sb_fcntl64(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64), - SCMP_CMP(1, SCMP_CMP_EQ, F_GETFL)); - if (rc) - return rc; - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64), - SCMP_CMP(1, SCMP_CMP_EQ, F_SETFL), - SCMP_CMP(2, SCMP_CMP_EQ, O_RDWR|O_NONBLOCK)); - if (rc) - return rc; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64), - SCMP_CMP(1, SCMP_CMP_EQ, F_GETFD)); - if (rc) - return rc; - - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64), - SCMP_CMP(1, SCMP_CMP_EQ, F_SETFD), - SCMP_CMP(2, SCMP_CMP_EQ, FD_CLOEXEC)); - if (rc) - return rc; - - return 0; -} -#endif /* defined(__NR_fcntl64) */ - -/** - * Function responsible for setting up the epoll_ctl syscall for - * the seccomp filter sandbox. - * - * Note: basically allows everything but will keep for now.. - */ -static int -sb_epoll_ctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), - SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_ADD)); - if (rc) - return rc; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), - SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_MOD)); - if (rc) - return rc; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), - SCMP_CMP(1, SCMP_CMP_EQ, EPOLL_CTL_DEL)); - if (rc) - return rc; - - return 0; -} - -/** - * Function responsible for setting up the prctl syscall for - * the seccomp filter sandbox. - * - * NOTE: if multiple filters need to be added, the PR_SECCOMP parameter needs - * to be whitelisted in this function. - */ -static int -sb_prctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), - SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_DUMPABLE)); - if (rc) - return rc; - - return 0; -} - -/** - * Function responsible for setting up the mprotect syscall for - * the seccomp filter sandbox. - * - * NOTE: does not NEED to be here.. currently only occurs before filter; will - * keep just in case for the future. - */ -static int -sb_mprotect(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ)); - if (rc) - return rc; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE)); - if (rc) - return rc; - - return 0; -} - -/** - * Function responsible for setting up the rt_sigprocmask syscall for - * the seccomp filter sandbox. - */ -static int -sb_rt_sigprocmask(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), - SCMP_CMP(0, SCMP_CMP_EQ, SIG_UNBLOCK)); - if (rc) - return rc; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), - SCMP_CMP(0, SCMP_CMP_EQ, SIG_SETMASK)); - if (rc) - return rc; - - return 0; -} - -/** - * Function responsible for setting up the flock syscall for - * the seccomp filter sandbox. - * - * NOTE: does not need to be here, occurs before filter is applied. - */ -static int -sb_flock(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(flock), - SCMP_CMP(1, SCMP_CMP_EQ, LOCK_EX|LOCK_NB)); - if (rc) - return rc; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(flock), - SCMP_CMP(1, SCMP_CMP_EQ, LOCK_UN)); - if (rc) - return rc; - - return 0; -} - -/** - * Function responsible for setting up the futex syscall for - * the seccomp filter sandbox. - */ -static int -sb_futex(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - - // can remove - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), - SCMP_CMP(1, SCMP_CMP_EQ, - FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME)); - if (rc) - return rc; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), - SCMP_CMP(1, SCMP_CMP_EQ, FUTEX_WAKE_PRIVATE)); - if (rc) - return rc; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), - SCMP_CMP(1, SCMP_CMP_EQ, FUTEX_WAIT_PRIVATE)); - if (rc) - return rc; - - return 0; -} - -/** - * Function responsible for setting up the mremap syscall for - * the seccomp filter sandbox. - * - * NOTE: so far only occurs before filter is applied. - */ -static int -sb_mremap(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - (void) filter; - - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mremap), - SCMP_CMP(3, SCMP_CMP_EQ, MREMAP_MAYMOVE)); - if (rc) - return rc; - - return 0; -} - -#ifdef __NR_stat64 -/** - * Function responsible for setting up the stat64 syscall for - * the seccomp filter sandbox. - */ -static int -sb_stat64(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - int rc = 0; - sandbox_cfg_t *elem = NULL; - - // for each dynamic parameter filters - for (elem = filter; elem != NULL; elem = elem->next) { - smp_param_t *param = elem->param; - - if (param != NULL && param->prot == 1 && (param->syscall == SCMP_SYS(open) - || param->syscall == SCMP_SYS(stat64))) { - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat64), - SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add stat64 syscall, received " - "libseccomp error %d", rc); - return rc; - } - } - } - - return 0; -} -#endif /* defined(__NR_stat64) */ - -static int -sb_kill(scmp_filter_ctx ctx, sandbox_cfg_t *filter) -{ - (void) filter; -#ifdef __NR_kill - /* Allow killing anything with signal 0 -- it isn't really a kill. */ - return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(kill), - SCMP_CMP(1, SCMP_CMP_EQ, 0)); -#else - return 0; -#endif /* defined(__NR_kill) */ -} - -/** - * Array of function pointers responsible for filtering different syscalls at - * a parameter level. - */ -static sandbox_filter_func_t filter_func[] = { - sb_rt_sigaction, - sb_rt_sigprocmask, - sb_time, - sb_accept4, -#ifdef __NR_mmap2 - sb_mmap2, -#endif - sb_chown, - sb_chmod, - sb_open, - sb_openat, - sb__sysctl, - sb_rename, -#ifdef __NR_fcntl64 - sb_fcntl64, -#endif - sb_epoll_ctl, - sb_prctl, - sb_mprotect, - sb_flock, - sb_futex, - sb_mremap, -#ifdef __NR_stat64 - sb_stat64, -#endif - - sb_socket, - sb_setsockopt, - sb_getsockopt, - sb_socketpair, -#ifdef HAVE_KIST_SUPPORT - sb_ioctl, -#endif - sb_kill -}; - -const char * -sandbox_intern_string(const char *str) -{ - sandbox_cfg_t *elem; - - if (str == NULL) - return NULL; - - for (elem = filter_dynamic; elem != NULL; elem = elem->next) { - smp_param_t *param = elem->param; - - if (param->prot) { - if (!strcmp(str, (char*)(param->value))) { - return (char*)param->value; - } - if (param->value2 && !strcmp(str, (char*)param->value2)) { - return (char*)param->value2; - } - } - } - - if (sandbox_active) - log_warn(LD_BUG, "No interned sandbox parameter found for %s", str); - return str; -} - -/* DOCDOC */ -static int -prot_strings_helper(strmap_t *locations, - char **pr_mem_next_p, - size_t *pr_mem_left_p, - char **value_p) -{ - char *param_val; - size_t param_size; - void *location; - - if (*value_p == 0) - return 0; - - param_val = (char*) *value_p; - param_size = strlen(param_val) + 1; - location = strmap_get(locations, param_val); - - if (location) { - // We already interned this string. - tor_free(param_val); - *value_p = location; - return 0; - } else if (*pr_mem_left_p >= param_size) { - // copy to protected - location = *pr_mem_next_p; - memcpy(location, param_val, param_size); - - // re-point el parameter to protected - tor_free(param_val); - *value_p = location; - - strmap_set(locations, location, location); /* good real estate advice */ - - // move next available protected memory - *pr_mem_next_p += param_size; - *pr_mem_left_p -= param_size; - return 0; - } else { - log_err(LD_BUG,"(Sandbox) insufficient protected memory!"); - return -1; - } -} - -/** - * Protects all the strings in the sandbox's parameter list configuration. It - * works by calculating the total amount of memory required by the parameter - * list, allocating the memory using mmap, and protecting it from writes with - * mprotect(). - */ -static int -prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg) -{ - int ret = 0; - size_t pr_mem_size = 0, pr_mem_left = 0; - char *pr_mem_next = NULL, *pr_mem_base; - sandbox_cfg_t *el = NULL; - strmap_t *locations = NULL; - - // get total number of bytes required to mmap. (Overestimate.) - for (el = cfg; el != NULL; el = el->next) { - pr_mem_size += strlen((char*) el->param->value) + 1; - if (el->param->value2) - pr_mem_size += strlen((char*) el->param->value2) + 1; - } - - // allocate protected memory with MALLOC_MP_LIM canary - pr_mem_base = (char*) mmap(NULL, MALLOC_MP_LIM + pr_mem_size, - PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); - if (pr_mem_base == MAP_FAILED) { - log_err(LD_BUG,"(Sandbox) failed allocate protected memory! mmap: %s", - strerror(errno)); - ret = -1; - goto out; - } - - pr_mem_next = pr_mem_base + MALLOC_MP_LIM; - pr_mem_left = pr_mem_size; - - locations = strmap_new(); - - // change el value pointer to protected - for (el = cfg; el != NULL; el = el->next) { - if (prot_strings_helper(locations, &pr_mem_next, &pr_mem_left, - &el->param->value) < 0) { - ret = -2; - goto out; - } - if (prot_strings_helper(locations, &pr_mem_next, &pr_mem_left, - &el->param->value2) < 0) { - ret = -2; - goto out; - } - el->param->prot = 1; - } - - // protecting from writes - if (mprotect(pr_mem_base, MALLOC_MP_LIM + pr_mem_size, PROT_READ)) { - log_err(LD_BUG,"(Sandbox) failed to protect memory! mprotect: %s", - strerror(errno)); - ret = -3; - goto out; - } - - /* - * Setting sandbox restrictions so the string memory cannot be tampered with - */ - // no mremap of the protected base address - ret = seccomp_rule_add_1(ctx, SCMP_ACT_KILL, SCMP_SYS(mremap), - SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base)); - if (ret) { - log_err(LD_BUG,"(Sandbox) mremap protected memory filter fail!"); - goto out; - } - - // no munmap of the protected base address - ret = seccomp_rule_add_1(ctx, SCMP_ACT_KILL, SCMP_SYS(munmap), - SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base)); - if (ret) { - log_err(LD_BUG,"(Sandbox) munmap protected memory filter fail!"); - goto out; - } - - /* - * Allow mprotect with PROT_READ|PROT_WRITE because openssl uses it, but - * never over the memory region used by the protected strings. - * - * PROT_READ|PROT_WRITE was originally fully allowed in sb_mprotect(), but - * had to be removed due to limitation of libseccomp regarding intervals. - * - * There is a restriction on how much you can mprotect with R|W up to the - * size of the canary. - */ - ret = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), - SCMP_CMP(0, SCMP_CMP_LT, (intptr_t) pr_mem_base), - SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE)); - if (ret) { - log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (LT)!"); - goto out; - } - - ret = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), - SCMP_CMP(0, SCMP_CMP_GT, (intptr_t) pr_mem_base + pr_mem_size + - MALLOC_MP_LIM), - SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM), - SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE)); - if (ret) { - log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (GT)!"); - goto out; - } - - out: - strmap_free(locations, NULL); - return ret; -} - -/** - * Auxiliary function used in order to allocate a sandbox_cfg_t element and set - * its values according the parameter list. All elements are initialised - * with the 'prot' field set to false, as the pointer is not protected at this - * point. - */ -static sandbox_cfg_t* -new_element2(int syscall, char *value, char *value2) -{ - smp_param_t *param = NULL; - - sandbox_cfg_t *elem = tor_malloc_zero(sizeof(sandbox_cfg_t)); - param = elem->param = tor_malloc_zero(sizeof(smp_param_t)); - - param->syscall = syscall; - param->value = value; - param->value2 = value2; - param->prot = 0; - - return elem; -} - -static sandbox_cfg_t* -new_element(int syscall, char *value) -{ - return new_element2(syscall, value, NULL); -} - -#ifdef __NR_stat64 -#define SCMP_stat SCMP_SYS(stat64) -#else -#define SCMP_stat SCMP_SYS(stat) -#endif - -int -sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file) -{ - sandbox_cfg_t *elem = NULL; - - elem = new_element(SCMP_stat, file); - - elem->next = *cfg; - *cfg = elem; - - return 0; -} - -int -sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file) -{ - sandbox_cfg_t *elem = NULL; - - elem = new_element(SCMP_SYS(open), file); - - elem->next = *cfg; - *cfg = elem; - - return 0; -} - -int -sandbox_cfg_allow_chmod_filename(sandbox_cfg_t **cfg, char *file) -{ - sandbox_cfg_t *elem = NULL; - - elem = new_element(SCMP_SYS(chmod), file); - - elem->next = *cfg; - *cfg = elem; - - return 0; -} - -int -sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file) -{ - sandbox_cfg_t *elem = NULL; - - elem = new_element(SCMP_SYS(chown), file); - - elem->next = *cfg; - *cfg = elem; - - return 0; -} - -int -sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2) -{ - sandbox_cfg_t *elem = NULL; - - elem = new_element2(SCMP_SYS(rename), file1, file2); - - elem->next = *cfg; - *cfg = elem; - - return 0; -} - -int -sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) -{ - sandbox_cfg_t *elem = NULL; - - elem = new_element(SCMP_SYS(openat), file); - - elem->next = *cfg; - *cfg = elem; - - return 0; -} - -/** Cache entry for getaddrinfo results; used when sandboxing is implemented - * so that we can consult the cache when the sandbox prevents us from doing - * getaddrinfo. - * - * We support only a limited range of getaddrinfo calls, where servname is null - * and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC. - */ -typedef struct cached_getaddrinfo_item_t { - HT_ENTRY(cached_getaddrinfo_item_t) node; - char *name; - int family; - /** set if no error; otherwise NULL */ - struct addrinfo *res; - /** 0 for no error; otherwise an EAI_* value */ - int err; -} cached_getaddrinfo_item_t; - -static unsigned -cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item) -{ - return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family; -} - -static unsigned -cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a, - const cached_getaddrinfo_item_t *b) -{ - return (a->family == b->family) && 0 == strcmp(a->name, b->name); -} - -#define cached_getaddrinfo_item_free(item) \ - FREE_AND_NULL(cached_getaddrinfo_item_t, \ - cached_getaddrinfo_item_free_, (item)) - -static void -cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item) -{ - if (item == NULL) - return; - - tor_free(item->name); - if (item->res) - freeaddrinfo(item->res); - tor_free(item); -} - -static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t) - getaddrinfo_cache = HT_INITIALIZER(); - -HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node, - cached_getaddrinfo_item_hash, - cached_getaddrinfo_items_eq) -HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node, - cached_getaddrinfo_item_hash, - cached_getaddrinfo_items_eq, - 0.6, tor_reallocarray_, tor_free_) - -/** If true, don't try to cache getaddrinfo results. */ -static int sandbox_getaddrinfo_cache_disabled = 0; - -/** Tell the sandbox layer not to try to cache getaddrinfo results. Used as in - * tor-resolve, when we have no intention of initializing crypto or of - * installing the sandbox.*/ -void -sandbox_disable_getaddrinfo_cache(void) -{ - sandbox_getaddrinfo_cache_disabled = 1; -} - -void -sandbox_freeaddrinfo(struct addrinfo *ai) -{ - if (sandbox_getaddrinfo_cache_disabled) - freeaddrinfo(ai); -} - -int -sandbox_getaddrinfo(const char *name, const char *servname, - const struct addrinfo *hints, - struct addrinfo **res) -{ - int err; - struct cached_getaddrinfo_item_t search, *item; - - if (sandbox_getaddrinfo_cache_disabled) { - return getaddrinfo(name, NULL, hints, res); - } - - if (servname != NULL) { - log_warn(LD_BUG, "called with non-NULL servname"); - return EAI_NONAME; - } - if (name == NULL) { - log_warn(LD_BUG, "called with NULL name"); - return EAI_NONAME; - } - - *res = NULL; - - memset(&search, 0, sizeof(search)); - search.name = (char *) name; - search.family = hints ? hints->ai_family : AF_UNSPEC; - item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search); - - if (! sandbox_is_active()) { - /* If the sandbox is not turned on yet, then getaddrinfo and store the - result. */ - - err = getaddrinfo(name, NULL, hints, res); - log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded"); - - if (! item) { - item = tor_malloc_zero(sizeof(*item)); - item->name = tor_strdup(name); - item->family = hints ? hints->ai_family : AF_UNSPEC; - HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item); - } - - if (item->res) { - freeaddrinfo(item->res); - item->res = NULL; - } - item->res = *res; - item->err = err; - return err; - } - - /* Otherwise, the sandbox is on. If we have an item, yield its cached - result. */ - if (item) { - *res = item->res; - return item->err; - } - - /* getting here means something went wrong */ - log_err(LD_BUG,"(Sandbox) failed to get address %s!", name); - return EAI_NONAME; -} - -int -sandbox_add_addrinfo(const char *name) -{ - struct addrinfo *res; - struct addrinfo hints; - int i; - static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC }; - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - for (i = 0; i < 3; ++i) { - hints.ai_family = families[i]; - - res = NULL; - (void) sandbox_getaddrinfo(name, NULL, &hints, &res); - if (res) - sandbox_freeaddrinfo(res); - } - - return 0; -} - -void -sandbox_free_getaddrinfo_cache(void) -{ - cached_getaddrinfo_item_t **next, **item, *this; - - for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache); - item; - item = next) { - this = *item; - next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item); - cached_getaddrinfo_item_free(this); - } - - HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache); -} - -/** - * Function responsible for going through the parameter syscall filters and - * call each function pointer in the list. - */ -static int -add_param_filter(scmp_filter_ctx ctx, sandbox_cfg_t* cfg) -{ - unsigned i; - int rc = 0; - - // function pointer - for (i = 0; i < ARRAY_LENGTH(filter_func); i++) { - rc = filter_func[i](ctx, cfg); - if (rc) { - log_err(LD_BUG,"(Sandbox) failed to add syscall %d, received libseccomp " - "error %d", i, rc); - return rc; - } - } - - return 0; -} - -/** - * Function responsible of loading the libseccomp syscall filters which do not - * have parameter filtering. - */ -static int -add_noparam_filter(scmp_filter_ctx ctx) -{ - unsigned i; - int rc = 0; - - // add general filters - for (i = 0; i < ARRAY_LENGTH(filter_nopar_gen); i++) { - rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, filter_nopar_gen[i]); - if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add syscall index %d (NR=%d), " - "received libseccomp error %d", i, filter_nopar_gen[i], rc); - return rc; - } - } - - return 0; -} - -/** - * Function responsible for setting up and enabling a global syscall filter. - * The function is a prototype developed for stage 1 of sandboxing Tor. - * Returns 0 on success. - */ -static int -install_syscall_filter(sandbox_cfg_t* cfg) -{ - int rc = 0; - scmp_filter_ctx ctx; - - ctx = seccomp_init(SCMP_ACT_TRAP); - if (ctx == NULL) { - log_err(LD_BUG,"(Sandbox) failed to initialise libseccomp context"); - rc = -1; - goto end; - } - - // protectign sandbox parameter strings - if ((rc = prot_strings(ctx, cfg))) { - goto end; - } - - // add parameter filters - if ((rc = add_param_filter(ctx, cfg))) { - log_err(LD_BUG, "(Sandbox) failed to add param filters!"); - goto end; - } - - // adding filters with no parameters - if ((rc = add_noparam_filter(ctx))) { - log_err(LD_BUG, "(Sandbox) failed to add param filters!"); - goto end; - } - - // loading the seccomp2 filter - if ((rc = seccomp_load(ctx))) { - log_err(LD_BUG, "(Sandbox) failed to load: %d (%s)! " - "Are you sure that your kernel has seccomp2 support? The " - "sandbox won't work without it.", rc, - strerror(-rc)); - goto end; - } - - // marking the sandbox as active - sandbox_active = 1; - - end: - seccomp_release(ctx); - return (rc < 0 ? -rc : rc); -} - -#include "linux_syscalls.inc" -static const char * -get_syscall_name(int syscall_num) -{ - int i; - for (i = 0; SYSCALLS_BY_NUMBER[i].syscall_name; ++i) { - if (SYSCALLS_BY_NUMBER[i].syscall_num == syscall_num) - return SYSCALLS_BY_NUMBER[i].syscall_name; - } - - { - static char syscall_name_buf[64]; - format_dec_number_sigsafe(syscall_num, - syscall_name_buf, sizeof(syscall_name_buf)); - return syscall_name_buf; - } -} - -#ifdef USE_BACKTRACE -#define MAX_DEPTH 256 -static void *syscall_cb_buf[MAX_DEPTH]; -#endif - -/** - * Function called when a SIGSYS is caught by the application. It notifies the - * user that an error has occurred and either terminates or allows the - * application to continue execution, based on the DEBUGGING_CLOSE symbol. - */ -static void -sigsys_debugging(int nr, siginfo_t *info, void *void_context) -{ - ucontext_t *ctx = (ucontext_t *) (void_context); - const char *syscall_name; - int syscall; -#ifdef USE_BACKTRACE - size_t depth; - int n_fds, i; - const int *fds = NULL; -#endif - - (void) nr; - - if (info->si_code != SYS_SECCOMP) - return; - - if (!ctx) - return; - - syscall = (int) ctx->uc_mcontext.M_SYSCALL; - -#ifdef USE_BACKTRACE - depth = backtrace(syscall_cb_buf, MAX_DEPTH); - /* Clean up the top stack frame so we get the real function - * name for the most recently failing function. */ - clean_backtrace(syscall_cb_buf, depth, ctx); -#endif /* defined(USE_BACKTRACE) */ - - syscall_name = get_syscall_name(syscall); - - tor_log_err_sigsafe("(Sandbox) Caught a bad syscall attempt (syscall ", - syscall_name, - ")\n", - NULL); - -#ifdef USE_BACKTRACE - n_fds = tor_log_get_sigsafe_err_fds(&fds); - for (i=0; i < n_fds; ++i) - backtrace_symbols_fd(syscall_cb_buf, (int)depth, fds[i]); -#endif - -#if defined(DEBUGGING_CLOSE) - _exit(1); // exit ok: programming error has led to sandbox failure. -#endif // DEBUGGING_CLOSE -} - -/** - * Function that adds a handler for SIGSYS, which is the signal thrown - * when the application is issuing a syscall which is not allowed. The - * main purpose of this function is to help with debugging by identifying - * filtered syscalls. - */ -static int -install_sigsys_debugging(void) -{ - struct sigaction act; - sigset_t mask; - - memset(&act, 0, sizeof(act)); - sigemptyset(&mask); - sigaddset(&mask, SIGSYS); - - act.sa_sigaction = &sigsys_debugging; - act.sa_flags = SA_SIGINFO; - if (sigaction(SIGSYS, &act, NULL) < 0) { - log_err(LD_BUG,"(Sandbox) Failed to register SIGSYS signal handler"); - return -1; - } - - if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) { - log_err(LD_BUG,"(Sandbox) Failed call to sigprocmask()"); - return -2; - } - - return 0; -} - -/** - * Function responsible of registering the sandbox_cfg_t list of parameter - * syscall filters to the existing parameter list. This is used for incipient - * multiple-sandbox support. - */ -static int -register_cfg(sandbox_cfg_t* cfg) -{ - sandbox_cfg_t *elem = NULL; - - if (filter_dynamic == NULL) { - filter_dynamic = cfg; - return 0; - } - - for (elem = filter_dynamic; elem->next != NULL; elem = elem->next) - ; - - elem->next = cfg; - - return 0; -} - -#endif /* defined(USE_LIBSECCOMP) */ - -#ifdef USE_LIBSECCOMP -/** - * Initialises the syscall sandbox filter for any linux architecture, taking - * into account various available features for different linux flavours. - */ -static int -initialise_libseccomp_sandbox(sandbox_cfg_t* cfg) -{ - /* Prevent glibc from trying to open /dev/tty on fatal error */ - setenv("LIBC_FATAL_STDERR_", "1", 1); - - if (install_sigsys_debugging()) - return -1; - - if (install_syscall_filter(cfg)) - return -2; - - if (register_cfg(cfg)) - return -3; - - return 0; -} - -int -sandbox_is_active(void) -{ - return sandbox_active != 0; -} -#endif /* defined(USE_LIBSECCOMP) */ - -sandbox_cfg_t* -sandbox_cfg_new(void) -{ - return NULL; -} - -int -sandbox_init(sandbox_cfg_t *cfg) -{ -#if defined(USE_LIBSECCOMP) - return initialise_libseccomp_sandbox(cfg); - -#elif defined(__linux__) - (void)cfg; - log_warn(LD_GENERAL, - "This version of Tor was built without support for sandboxing. To " - "build with support for sandboxing on Linux, you must have " - "libseccomp and its necessary header files (e.g. seccomp.h)."); - return 0; - -#else - (void)cfg; - log_warn(LD_GENERAL, - "Currently, sandboxing is only implemented on Linux. The feature " - "is disabled on your platform."); - return 0; -#endif /* defined(USE_LIBSECCOMP) || ... */ -} - -#ifndef USE_LIBSECCOMP -int -sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file) -{ - (void)cfg; (void)file; - return 0; -} - -int -sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) -{ - (void)cfg; (void)file; - return 0; -} - -int -sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file) -{ - (void)cfg; (void)file; - return 0; -} - -int -sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file) -{ - (void)cfg; (void)file; - return 0; -} - -int -sandbox_cfg_allow_chmod_filename(sandbox_cfg_t **cfg, char *file) -{ - (void)cfg; (void)file; - return 0; -} - -int -sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2) -{ - (void)cfg; (void)file1; (void)file2; - return 0; -} - -int -sandbox_is_active(void) -{ - return 0; -} - -void -sandbox_disable_getaddrinfo_cache(void) -{ -} -#endif /* !defined(USE_LIBSECCOMP) */ - diff --git a/src/common/sandbox.h b/src/common/sandbox.h deleted file mode 100644 index d0f85570f4..0000000000 --- a/src/common/sandbox.h +++ /dev/null @@ -1,174 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file sandbox.h - * \brief Header file for sandbox.c. - **/ - -#ifndef SANDBOX_H_ -#define SANDBOX_H_ - -#include "orconfig.h" -#include "torint.h" - -#ifndef SYS_SECCOMP - -/** - * Used by SIGSYS signal handler to check if the signal was issued due to a - * seccomp2 filter violation. - */ -#define SYS_SECCOMP 1 - -#endif /* !defined(SYS_SECCOMP) */ - -#if defined(HAVE_SECCOMP_H) && defined(__linux__) -#define USE_LIBSECCOMP -#endif - -struct sandbox_cfg_elem; - -/** Typedef to structure used to manage a sandbox configuration. */ -typedef struct sandbox_cfg_elem sandbox_cfg_t; - -/** - * Linux definitions - */ -#ifdef USE_LIBSECCOMP - -#include <sys/ucontext.h> -#include <seccomp.h> -#include <netdb.h> - -#define PARAM_PTR 0 -#define PARAM_NUM 1 - -/** - * Enum used to manage the type of the implementation for general purpose. - */ -typedef enum { - /** Libseccomp implementation based on seccomp2*/ - LIBSECCOMP2 = 0 -} SB_IMPL; - -/** - * Configuration parameter structure associated with the LIBSECCOMP2 - * implementation. - */ -typedef struct smp_param { - /** syscall associated with parameter. */ - int syscall; - - /** parameter value. */ - char *value; - /** parameter value, second argument. */ - char *value2; - - /** parameter flag (0 = not protected, 1 = protected). */ - int prot; -} smp_param_t; - -/** - * Structure used to manage a sandbox configuration. - * - * It is implemented as a linked list of parameters. Currently only controls - * parameters for open, openat, execve, stat64. - */ -struct sandbox_cfg_elem { - /** Sandbox implementation which dictates the parameter type. */ - SB_IMPL implem; - - /** Configuration parameter. */ - smp_param_t *param; - - /** Next element of the configuration*/ - struct sandbox_cfg_elem *next; -}; - -/** Function pointer defining the prototype of a filter function.*/ -typedef int (*sandbox_filter_func_t)(scmp_filter_ctx ctx, - sandbox_cfg_t *filter); - -/** Type that will be used in step 3 in order to manage multiple sandboxes.*/ -typedef struct { - /** function pointers associated with the filter */ - sandbox_filter_func_t *filter_func; - - /** filter function pointer parameters */ - sandbox_cfg_t *filter_dynamic; -} sandbox_t; - -#endif /* defined(USE_LIBSECCOMP) */ - -#ifdef USE_LIBSECCOMP -/** Pre-calls getaddrinfo in order to pre-record result. */ -int sandbox_add_addrinfo(const char *addr); - -struct addrinfo; -/** Replacement for getaddrinfo(), using pre-recorded results. */ -int sandbox_getaddrinfo(const char *name, const char *servname, - const struct addrinfo *hints, - struct addrinfo **res); -void sandbox_freeaddrinfo(struct addrinfo *addrinfo); -void sandbox_free_getaddrinfo_cache(void); -#else /* !(defined(USE_LIBSECCOMP)) */ -#define sandbox_getaddrinfo(name, servname, hints, res) \ - getaddrinfo((name),(servname), (hints),(res)) -#define sandbox_add_addrinfo(name) \ - ((void)(name)) -#define sandbox_freeaddrinfo(addrinfo) \ - freeaddrinfo((addrinfo)) -#define sandbox_free_getaddrinfo_cache() -#endif /* defined(USE_LIBSECCOMP) */ - -#ifdef USE_LIBSECCOMP -/** Returns a registered protected string used with the sandbox, given that - * it matches the parameter. - */ -const char* sandbox_intern_string(const char *param); -#else /* !(defined(USE_LIBSECCOMP)) */ -#define sandbox_intern_string(s) (s) -#endif /* defined(USE_LIBSECCOMP) */ - -/** Creates an empty sandbox configuration file.*/ -sandbox_cfg_t * sandbox_cfg_new(void); - -/** - * Function used to add a open allowed filename to a supplied configuration. - * The (char*) specifies the path to the allowed file; we take ownership - * of the pointer. - */ -int sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file); - -int sandbox_cfg_allow_chmod_filename(sandbox_cfg_t **cfg, char *file); -int sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file); - -/* DOCDOC */ -int sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2); - -/** - * Function used to add a openat allowed filename to a supplied configuration. - * The (char*) specifies the path to the allowed file; we steal the pointer to - * that file. - */ -int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file); - -/** - * Function used to add a stat/stat64 allowed filename to a configuration. - * The (char*) specifies the path to the allowed file; that pointer is stolen. - */ -int sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file); - -/** Function used to initialise a sandbox configuration.*/ -int sandbox_init(sandbox_cfg_t* cfg); - -/** Return true iff the sandbox is turned on. */ -int sandbox_is_active(void); - -void sandbox_disable_getaddrinfo_cache(void); - -#endif /* !defined(SANDBOX_H_) */ - diff --git a/src/common/storagedir.c b/src/common/storagedir.c deleted file mode 100644 index e2c7b4bb87..0000000000 --- a/src/common/storagedir.c +++ /dev/null @@ -1,586 +0,0 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#include "container.h" -#include "compat.h" -#include "confline.h" -#include "memarea.h" -#include "sandbox.h" -#include "storagedir.h" -#include "torlog.h" -#include "util.h" - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#define FNAME_MIN_NUM 1000 - -/** A storage_dir_t represents a directory full of similar cached - * files. Filenames are decimal integers. Files can be cleaned as needed - * to limit total disk usage. */ -struct storage_dir_t { - /** Directory holding the files for this storagedir. */ - char *directory; - /** Either NULL, or a directory listing of the directory (as a smartlist - * of strings */ - smartlist_t *contents; - /** The largest number of non-temporary files we'll place in the - * directory. */ - int max_files; - /** If true, then 'usage' has been computed. */ - int usage_known; - /** The total number of bytes used in this directory */ - uint64_t usage; -}; - -/** Create or open a new storage directory at <b>dirname</b>, with - * capacity for up to <b>max_files</b> files. - */ -storage_dir_t * -storage_dir_new(const char *dirname, int max_files) -{ - if (check_private_dir(dirname, CPD_CREATE, NULL) < 0) - return NULL; - - storage_dir_t *d = tor_malloc_zero(sizeof(storage_dir_t)); - d->directory = tor_strdup(dirname); - d->max_files = max_files; - return d; -} - -/** - * Drop all in-RAM storage for <b>d</b>. Does not delete any files. - */ -void -storage_dir_free_(storage_dir_t *d) -{ - if (d == NULL) - return; - tor_free(d->directory); - if (d->contents) { - SMARTLIST_FOREACH(d->contents, char *, cp, tor_free(cp)); - smartlist_free(d->contents); - } - tor_free(d); -} - -/** - * Tell the sandbox (if any) configured by <b>cfg</b> to allow the - * operations that <b>d</b> will need. - * - * The presence of this function is why we need an upper limit on the - * number of files in a storage_dir_t: we need to approve file operations - * one by one. - */ -int -storage_dir_register_with_sandbox(storage_dir_t *d, sandbox_cfg_t **cfg) -{ - int problems = 0; - int idx; - for (idx = FNAME_MIN_NUM; idx < FNAME_MIN_NUM + d->max_files; ++idx) { - char *path = NULL, *tmppath = NULL; - tor_asprintf(&path, "%s/%d", d->directory, idx); - tor_asprintf(&tmppath, "%s/%d.tmp", d->directory, idx); - - problems += sandbox_cfg_allow_open_filename(cfg, tor_strdup(path)); - problems += sandbox_cfg_allow_open_filename(cfg, tor_strdup(tmppath)); - problems += sandbox_cfg_allow_stat_filename(cfg, tor_strdup(path)); - problems += sandbox_cfg_allow_stat_filename(cfg, tor_strdup(tmppath)); - problems += sandbox_cfg_allow_rename(cfg, - tor_strdup(tmppath), tor_strdup(path)); - - tor_free(path); - tor_free(tmppath); - } - - return problems ? -1 : 0; -} - -/** - * Remove all files in <b>d</b> whose names end with ".tmp". - * - * Requires that the contents field of <b>d</b> is set. - */ -static void -storage_dir_clean_tmpfiles(storage_dir_t *d) -{ - if (!d->contents) - return; - SMARTLIST_FOREACH_BEGIN(d->contents, char *, fname) { - if (strcmpend(fname, ".tmp")) - continue; - char *path = NULL; - tor_asprintf(&path, "%s/%s", d->directory, fname); - if (unlink(sandbox_intern_string(path))) { - log_warn(LD_FS, "Unable to unlink %s while cleaning " - "temporary files: %s", escaped(path), strerror(errno)); - tor_free(path); - continue; - } - tor_free(path); - SMARTLIST_DEL_CURRENT(d->contents, fname); - tor_free(fname); - } SMARTLIST_FOREACH_END(fname); - - d->usage_known = 0; -} - -/** - * Re-scan the directory <b>d</b> to learn its contents. - */ -static int -storage_dir_rescan(storage_dir_t *d) -{ - if (d->contents) { - SMARTLIST_FOREACH(d->contents, char *, cp, tor_free(cp)); - smartlist_free(d->contents); - } - d->usage = 0; - d->usage_known = 0; - if (NULL == (d->contents = tor_listdir(d->directory))) { - return -1; - } - storage_dir_clean_tmpfiles(d); - return 0; -} - -/** - * Return a smartlist containing the filenames within <b>d</b>. - */ -const smartlist_t * -storage_dir_list(storage_dir_t *d) -{ - if (! d->contents) - storage_dir_rescan(d); - return d->contents; -} - -/** - * Return the total number of bytes used for storage in <b>d</b>. - */ -uint64_t -storage_dir_get_usage(storage_dir_t *d) -{ - if (d->usage_known) - return d->usage; - - uint64_t total = 0; - SMARTLIST_FOREACH_BEGIN(storage_dir_list(d), const char *, cp) { - char *path = NULL; - struct stat st; - tor_asprintf(&path, "%s/%s", d->directory, cp); - if (stat(sandbox_intern_string(path), &st) == 0) { - total += st.st_size; - } - tor_free(path); - } SMARTLIST_FOREACH_END(cp); - - d->usage = total; - d->usage_known = 1; - return d->usage; -} - -/** Mmap a specified file within <b>d</b>. - * - * On failure, return NULL and set errno as for tor_mmap_file(). */ -tor_mmap_t * -storage_dir_map(storage_dir_t *d, const char *fname) -{ - char *path = NULL; - tor_asprintf(&path, "%s/%s", d->directory, fname); - tor_mmap_t *result = tor_mmap_file(path); - int errval = errno; - tor_free(path); - if (result == NULL) - errno = errval; - return result; -} - -/** Read a file within <b>d</b> into a newly allocated buffer. Set - * *<b>sz_out</b> to its size. */ -uint8_t * -storage_dir_read(storage_dir_t *d, const char *fname, int bin, size_t *sz_out) -{ - const int flags = bin ? RFTS_BIN : 0; - - char *path = NULL; - tor_asprintf(&path, "%s/%s", d->directory, fname); - struct stat st; - char *contents = read_file_to_str(path, flags, &st); - if (contents && sz_out) { - // it fits in RAM, so we know its size is less than SIZE_MAX -#if UINT64_MAX > SIZE_MAX - tor_assert((uint64_t)st.st_size <= SIZE_MAX); -#endif - *sz_out = (size_t) st.st_size; - } - - tor_free(path); - return (uint8_t *) contents; -} - -/** Helper: Find an unused filename within the directory */ -static char * -find_unused_fname(storage_dir_t *d) -{ - if (!d->contents) { - if (storage_dir_rescan(d) < 0) - return NULL; - } - - char buf[16]; - int i; - /* Yuck; this is quadratic. Fortunately, that shouldn't matter much, - * since disk writes are more expensive by a lot. */ - for (i = FNAME_MIN_NUM; i < FNAME_MIN_NUM + d->max_files; ++i) { - tor_snprintf(buf, sizeof(buf), "%d", i); - if (!smartlist_contains_string(d->contents, buf)) { - return tor_strdup(buf); - } - } - return NULL; -} - -/** Helper: As storage_dir_save_bytes_to_file, but store a smartlist of - * sized_chunk_t rather than a single byte array. */ -static int -storage_dir_save_chunks_to_file(storage_dir_t *d, - const smartlist_t *chunks, - int binary, - char **fname_out) -{ - uint64_t total_length = 0; - char *fname = find_unused_fname(d); - if (!fname) - return -1; - - SMARTLIST_FOREACH(chunks, const sized_chunk_t *, ch, - total_length += ch->len); - - char *path = NULL; - tor_asprintf(&path, "%s/%s", d->directory, fname); - - int r = write_chunks_to_file(path, chunks, binary, 0); - if (r == 0) { - if (d->usage_known) - d->usage += total_length; - if (fname_out) { - *fname_out = tor_strdup(fname); - } - if (d->contents) - smartlist_add(d->contents, tor_strdup(fname)); - } - tor_free(fname); - tor_free(path); - return r; -} - -/** Try to write the <b>length</b> bytes at <b>data</b> into a new file - * in <b>d</b>. On success, return 0 and set *<b>fname_out</b> to a - * newly allocated string containing the filename. On failure, return - * -1. */ -int -storage_dir_save_bytes_to_file(storage_dir_t *d, - const uint8_t *data, - size_t length, - int binary, - char **fname_out) -{ - smartlist_t *chunks = smartlist_new(); - sized_chunk_t chunk = { (const char *)data, length }; - smartlist_add(chunks, &chunk); - int r = storage_dir_save_chunks_to_file(d, chunks, binary, fname_out); - smartlist_free(chunks); - return r; -} - -/** - * As storage_dir_save_bytes_to_file, but saves a NUL-terminated string - * <b>str</b>. - */ -int -storage_dir_save_string_to_file(storage_dir_t *d, - const char *str, - int binary, - char **fname_out) -{ - return storage_dir_save_bytes_to_file(d, - (const uint8_t*)str, strlen(str), binary, fname_out); -} - -/** - * As storage_dir_save_bytes_to_file, but associates the data with the - * key-value pairs in <b>labels</b>. Files stored in this format can be - * recovered with storage_dir_map_labeled() or storage_dir_read_labeled(). - */ -int -storage_dir_save_labeled_to_file(storage_dir_t *d, - const config_line_t *labels, - const uint8_t *data, - size_t length, - char **fname_out) -{ - /* - * The storage format is to prefix the data with the key-value pairs in - * <b>labels</b>, and a single NUL separator. But code outside this module - * MUST NOT rely on that format. - */ - - smartlist_t *chunks = smartlist_new(); - memarea_t *area = memarea_new(); - const config_line_t *line; - for (line = labels; line; line = line->next) { - sized_chunk_t *sz = memarea_alloc(area, sizeof(sized_chunk_t)); - sz->len = strlen(line->key) + 1 + strlen(line->value) + 1; - const size_t allocated = sz->len + 1; - char *bytes = memarea_alloc(area, allocated); - tor_snprintf(bytes, allocated, "%s %s\n", line->key, line->value); - sz->bytes = bytes; - smartlist_add(chunks, sz); - } - - sized_chunk_t *nul = memarea_alloc(area, sizeof(sized_chunk_t)); - nul->len = 1; - nul->bytes = "\0"; - smartlist_add(chunks, nul); - - sized_chunk_t *datachunk = memarea_alloc(area, sizeof(sized_chunk_t)); - datachunk->bytes = (const char *)data; - datachunk->len = length; - smartlist_add(chunks, datachunk); - - int r = storage_dir_save_chunks_to_file(d, chunks, 1, fname_out); - smartlist_free(chunks); - memarea_drop_all(area); - return r; -} - -/** - * Map a file that was created with storage_dir_save_labeled_to_file(). On - * failure, return NULL. On success, write a set of newly allocated labels - * into *<b>labels_out</b>, a pointer to the data into *<b>data_out</b>, and - * the data's size into *<b>sz_out</b>. On success, also return a tor_mmap_t - * object whose contents should not be used -- it needs to be kept around, - * though, for as long as <b>data_out</b> is going to be valid. - * - * On failure, set errno as for tor_mmap_file() if the file was missing or - * empty, and set errno to EINVAL if the file was not in the labeled - * format expected. - */ -tor_mmap_t * -storage_dir_map_labeled(storage_dir_t *dir, - const char *fname, - config_line_t **labels_out, - const uint8_t **data_out, - size_t *sz_out) -{ - tor_mmap_t *m = storage_dir_map(dir, fname); - int errval; - if (! m) { - errval = errno; - goto err; - } - const char *nulp = memchr(m->data, '\0', m->size); - if (! nulp) { - errval = EINVAL; - goto err; - } - if (labels_out && config_get_lines(m->data, labels_out, 0) < 0) { - errval = EINVAL; - goto err; - } - size_t offset = nulp - m->data + 1; - tor_assert(offset <= m->size); - *data_out = (const uint8_t *)(m->data + offset); - *sz_out = m->size - offset; - - return m; - err: - tor_munmap_file(m); - errno = errval; - return NULL; -} - -/** As storage_dir_map_labeled, but return a new byte array containing the - * data. */ -uint8_t * -storage_dir_read_labeled(storage_dir_t *dir, - const char *fname, - config_line_t **labels_out, - size_t *sz_out) -{ - const uint8_t *data = NULL; - tor_mmap_t *m = storage_dir_map_labeled(dir, fname, labels_out, - &data, sz_out); - if (m == NULL) - return NULL; - uint8_t *result = tor_memdup(data, *sz_out); - tor_munmap_file(m); - return result; -} - -/* Reduce the cached usage amount in <b>d</b> by <b>removed_file_size</b>. - * This function is a no-op if <b>d->usage_known</b> is 0. */ -static void -storage_dir_reduce_usage(storage_dir_t *d, uint64_t removed_file_size) -{ - if (d->usage_known) { - if (! BUG(d->usage < removed_file_size)) { - /* This bug can also be triggered if an external process resized a file - * between the call to storage_dir_get_usage() that last checked - * actual usage (rather than relaying on cached usage), and the call to - * this function. */ - d->usage -= removed_file_size; - } else { - /* If we underflowed the cached directory size, re-check the sizes of all - * the files in the directory. This makes storage_dir_shrink() quadratic, - * but only if a process is continually changing file sizes in the - * storage directory (in which case, we have bigger issues). - * - * We can't just reset usage_known, because storage_dir_shrink() relies - * on knowing the usage. */ - storage_dir_rescan(d); - (void)storage_dir_get_usage(d); - } - } -} - -/** - * Remove the file called <b>fname</b> from <b>d</b>. - */ -void -storage_dir_remove_file(storage_dir_t *d, - const char *fname) -{ - char *path = NULL; - tor_asprintf(&path, "%s/%s", d->directory, fname); - const char *ipath = sandbox_intern_string(path); - - uint64_t size = 0; - if (d->usage_known) { - struct stat st; - if (stat(ipath, &st) == 0) { - size = st.st_size; - } - } - if (unlink(ipath) == 0) { - storage_dir_reduce_usage(d, size); - } else { - log_warn(LD_FS, "Unable to unlink %s while removing file: %s", - escaped(path), strerror(errno)); - tor_free(path); - return; - } - if (d->contents) { - smartlist_string_remove(d->contents, fname); - } - - tor_free(path); -} - -/** Helper type: used to sort the members of storage directory by mtime. */ -typedef struct shrinking_dir_entry_t { - time_t mtime; - uint64_t size; - char *path; -} shrinking_dir_entry_t; - -/** Helper: use with qsort to sort shrinking_dir_entry_t structs. */ -static int -shrinking_dir_entry_compare(const void *a_, const void *b_) -{ - const shrinking_dir_entry_t *a = a_; - const shrinking_dir_entry_t *b = b_; - - if (a->mtime < b->mtime) - return -1; - else if (a->mtime > b->mtime) - return 1; - else - return 0; -} - -/** - * Try to free space by removing the oldest files in <b>d</b>. Delete - * until no more than <b>target_size</b> bytes are left, and at least - * <b>min_to_remove</b> files have been removed... or until there is - * nothing left to remove. - * - * Return 0 on success; -1 on failure. - */ -int -storage_dir_shrink(storage_dir_t *d, - uint64_t target_size, - int min_to_remove) -{ - if (d->usage_known && d->usage <= target_size && !min_to_remove) { - /* Already small enough. */ - return 0; - } - - if (storage_dir_rescan(d) < 0) - return -1; - - const uint64_t orig_usage = storage_dir_get_usage(d); - if (orig_usage <= target_size && !min_to_remove) { - /* Okay, small enough after rescan! */ - return 0; - } - - const int n = smartlist_len(d->contents); - shrinking_dir_entry_t *ents = tor_calloc(n, sizeof(shrinking_dir_entry_t)); - SMARTLIST_FOREACH_BEGIN(d->contents, const char *, fname) { - shrinking_dir_entry_t *ent = &ents[fname_sl_idx]; - struct stat st; - tor_asprintf(&ent->path, "%s/%s", d->directory, fname); - if (stat(sandbox_intern_string(ent->path), &st) == 0) { - ent->mtime = st.st_mtime; - ent->size = st.st_size; - } - } SMARTLIST_FOREACH_END(fname); - - qsort(ents, n, sizeof(shrinking_dir_entry_t), shrinking_dir_entry_compare); - - int idx = 0; - while ((d->usage > target_size || min_to_remove > 0) && idx < n) { - if (unlink(sandbox_intern_string(ents[idx].path)) == 0) { - storage_dir_reduce_usage(d, ents[idx].size); - --min_to_remove; - } - ++idx; - } - - for (idx = 0; idx < n; ++idx) { - tor_free(ents[idx].path); - } - tor_free(ents); - - storage_dir_rescan(d); - - return 0; -} - -/** Remove all files in <b>d</b>. */ -int -storage_dir_remove_all(storage_dir_t *d) -{ - return storage_dir_shrink(d, 0, d->max_files); -} - -/** - * Return the largest number of non-temporary files we're willing to - * store in <b>d</b>. - */ -int -storage_dir_get_max_files(storage_dir_t *d) -{ - return d->max_files; -} - diff --git a/src/common/storagedir.h b/src/common/storagedir.h deleted file mode 100644 index d99bd7ec52..0000000000 --- a/src/common/storagedir.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_STORAGEDIR_H -#define TOR_STORAGEDIR_H - -typedef struct storage_dir_t storage_dir_t; -struct config_line_t; -struct sandbox_cfg_elem; - -storage_dir_t * storage_dir_new(const char *dirname, int n_files); -void storage_dir_free_(storage_dir_t *d); -#define storage_dir_free(d) \ - FREE_AND_NULL(storage_dir_t, storage_dir_free_, (d)) - -int storage_dir_register_with_sandbox(storage_dir_t *d, - struct sandbox_cfg_elem **cfg); -const smartlist_t *storage_dir_list(storage_dir_t *d); -uint64_t storage_dir_get_usage(storage_dir_t *d); -tor_mmap_t *storage_dir_map(storage_dir_t *d, const char *fname); -uint8_t *storage_dir_read(storage_dir_t *d, const char *fname, int bin, - size_t *sz_out); -int storage_dir_save_bytes_to_file(storage_dir_t *d, - const uint8_t *data, - size_t length, - int binary, - char **fname_out); -int storage_dir_save_string_to_file(storage_dir_t *d, - const char *data, - int binary, - char **fname_out); -int storage_dir_save_labeled_to_file(storage_dir_t *d, - const struct config_line_t *labels, - const uint8_t *data, - size_t length, - char **fname_out); -tor_mmap_t *storage_dir_map_labeled(storage_dir_t *dir, - const char *fname, - struct config_line_t **labels_out, - const uint8_t **data_out, - size_t *size_out); -uint8_t *storage_dir_read_labeled(storage_dir_t *d, const char *fname, - struct config_line_t **labels_out, - size_t *sz_out); -void storage_dir_remove_file(storage_dir_t *d, - const char *fname); -int storage_dir_shrink(storage_dir_t *d, - uint64_t target_size, - int min_to_remove); -int storage_dir_remove_all(storage_dir_t *d); -int storage_dir_get_max_files(storage_dir_t *d); - -#endif /* !defined(TOR_STORAGEDIR_H) */ - diff --git a/src/common/testsupport.h b/src/common/testsupport.h deleted file mode 100644 index a3f2ff91ed..0000000000 --- a/src/common/testsupport.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_TESTSUPPORT_H -#define TOR_TESTSUPPORT_H - -#ifdef TOR_UNIT_TESTS -#define STATIC -#define EXTERN(type, name) extern type name; -#else -#define STATIC static -#define EXTERN(type, name) -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Quick and dirty macros to implement test mocking. - * - * To use them, suppose that you have a function you'd like to mock - * with the signature "void writebuf(size_t n, char *buf)". You can then - * declare the function as: - * - * MOCK_DECL(void, writebuf, (size_t n, char *buf)); - * - * and implement it as: - * - * MOCK_IMPL(void, - * writebuf,(size_t n, char *buf)) - * { - * ... - * } - * - * For the non-testing build, this will expand simply into: - * - * void writebuf(size_t n, char *buf); - * void - * writebuf(size_t n, char *buf) - * { - * ... - * } - * - * But for the testing case, it will expand into: - * - * void writebuf__real(size_t n, char *buf); - * extern void (*writebuf)(size_t n, char *buf); - * - * void (*writebuf)(size_t n, char *buf) = writebuf__real; - * void - * writebuf__real(size_t n, char *buf) - * { - * ... - * } - * - * This is not a great mocking system! It is deliberately "the simplest - * thing that could work", and pays for its simplicity in its lack of - * features, and in its uglification of the Tor code. Replacing it with - * something clever would be a fine thing. - * - * @{ */ -#ifdef TOR_UNIT_TESTS -#define MOCK_DECL(rv, funcname, arglist) \ - rv funcname ##__real arglist; \ - extern rv(*funcname) arglist -#define MOCK_IMPL(rv, funcname, arglist) \ - rv(*funcname) arglist = funcname ##__real; \ - rv funcname ##__real arglist -#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \ - rv funcname ##__real arglist attr; \ - extern rv(*funcname) arglist -#define MOCK_IMPL(rv, funcname, arglist) \ - rv(*funcname) arglist = funcname ##__real; \ - rv funcname ##__real arglist -#define MOCK(func, replacement) \ - do { \ - (func) = (replacement); \ - } while (0) -#define UNMOCK(func) \ - do { \ - func = func ##__real; \ - } while (0) -#else /* !(defined(TOR_UNIT_TESTS)) */ -#define MOCK_DECL(rv, funcname, arglist) \ - rv funcname arglist -#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \ - rv funcname arglist attr -#define MOCK_IMPL(rv, funcname, arglist) \ - rv funcname arglist -#endif /* defined(TOR_UNIT_TESTS) */ -/** @} */ - -#endif /* !defined(TOR_TESTSUPPORT_H) */ - diff --git a/src/common/timers.c b/src/common/timers.c deleted file mode 100644 index 6f6236ed3b..0000000000 --- a/src/common/timers.c +++ /dev/null @@ -1,318 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file timers.c - * \brief Wrapper around William Ahern's fast hierarchical timer wheel - * implementation, to tie it in with a libevent backend. - * - * Only use these functions from the main thread. - * - * The main advantage of tor_timer_t over using libevent's timers is that - * they're way more efficient if we need to have thousands or millions of - * them. For more information, see - * http://www.25thandclement.com/~william/projects/timeout.c.html - * - * Periodic timers are available in the backend, but I've turned them off. - * We can turn them back on if needed. - */ - -/* Notes: - * - * Having a way to free all timers on shutdown would free people from the - * need to track them. Not sure if that's clever though. - * - * In an ideal world, Libevent would just switch to use this backend, and we - * could throw this file away. But even if Libevent does switch, we'll be - * stuck with legacy libevents for some time. - */ - -#include "orconfig.h" - -#define TOR_TIMERS_PRIVATE - -#include "compat.h" -#include "compat_libevent.h" -#include "timers.h" -#include "torlog.h" -#include "util.h" - -struct timeout_cb { - timer_cb_fn_t cb; - void *arg; -}; - -/* - * These definitions are for timeouts.c and timeouts.h. - */ -#ifdef __GNUC__ -/* We're not exposing any of the functions outside this file. */ -#define TIMEOUT_PUBLIC __attribute__((__unused__)) static -#else -/* We're not exposing any of the functions outside this file. */ -#define TIMEOUT_PUBLIC static -#endif /* defined(__GNUC__) */ -/* We're not using periodic events. */ -#define TIMEOUT_DISABLE_INTERVALS -/* We always know the global_timeouts object, so we don't need each timeout - * to keep a pointer to it. */ -#define TIMEOUT_DISABLE_RELATIVE_ACCESS -/* We're providing our own struct timeout_cb. */ -#define TIMEOUT_CB_OVERRIDE -/* We're going to support timers that are pretty far out in advance. Making - * this big can be inefficient, but having a significant number of timers - * above TIMEOUT_MAX can also be super-inefficient. Choosing 5 here sets - * timeout_max to 2^30 ticks, or 29 hours with our value for USEC_PER_TICK */ -#define WHEEL_NUM 5 -#if SIZEOF_VOID_P == 4 -/* On 32-bit platforms, we want to override wheel_bit, so that timeout.c will - * use 32-bit math. */ -#define WHEEL_BIT 5 -#endif -#include "src/ext/timeouts/timeout.c" - -static struct timeouts *global_timeouts = NULL; -static struct mainloop_event_t *global_timer_event = NULL; - -static monotime_t start_of_time; - -/** We need to choose this value carefully. Because we're using timer wheels, - * it actually costs us to have extra resolution we don't use. So for now, - * I'm going to define our resolution as .1 msec, and hope that's good enough. - * - * Note that two of the most popular libevent backends (epoll without timerfd, - * and windows select), simply can't support sub-millisecond resolution, - * do this is optimistic for a lot of users. - */ -#define USEC_PER_TICK 100 - -/** One million microseconds in a second */ -#define USEC_PER_SEC 1000000 - -/** Check at least once every N seconds. */ -#define MIN_CHECK_SECONDS 3600 - -/** Check at least once every N ticks. */ -#define MIN_CHECK_TICKS \ - (((timeout_t)MIN_CHECK_SECONDS) * (1000000 / USEC_PER_TICK)) - -/** - * Convert the timeval in <b>tv</b> to a timeout_t, and return it. - * - * The output resolution is set by USEC_PER_TICK. Only use this to convert - * delays to number of ticks; the time represented by 0 is undefined. - */ -static timeout_t -tv_to_timeout(const struct timeval *tv) -{ - uint64_t usec = tv->tv_usec; - usec += ((uint64_t)USEC_PER_SEC) * tv->tv_sec; - return usec / USEC_PER_TICK; -} - -/** - * Convert the timeout in <b>t</b> to a timeval in <b>tv_out</b>. Only - * use this for delays, not absolute times. - */ -static void -timeout_to_tv(timeout_t t, struct timeval *tv_out) -{ - t *= USEC_PER_TICK; - tv_out->tv_usec = (int)(t % USEC_PER_SEC); - tv_out->tv_sec = (time_t)(t / USEC_PER_SEC); -} - -/** - * Update the timer <b>tv</b> to the current time in <b>tv</b>. - */ -static void -timer_advance_to_cur_time(const monotime_t *now) -{ - timeout_t cur_tick = CEIL_DIV(monotime_diff_usec(&start_of_time, now), - USEC_PER_TICK); - timeouts_update(global_timeouts, cur_tick); -} - -/** - * Adjust the time at which the libevent timer should fire based on - * the next-expiring time in <b>global_timeouts</b> - */ -static void -libevent_timer_reschedule(void) -{ - monotime_t now; - monotime_get(&now); - timer_advance_to_cur_time(&now); - - timeout_t delay = timeouts_timeout(global_timeouts); - - struct timeval d; - if (delay > MIN_CHECK_TICKS) - delay = MIN_CHECK_TICKS; - timeout_to_tv(delay, &d); - mainloop_event_schedule(global_timer_event, &d); -} - -/** Run the callback of every timer that has expired, based on the current - * output of monotime_get(). */ -STATIC void -timers_run_pending(void) -{ - monotime_t now; - monotime_get(&now); - timer_advance_to_cur_time(&now); - - tor_timer_t *t; - while ((t = timeouts_get(global_timeouts))) { - t->callback.cb(t, t->callback.arg, &now); - } -} - -/** - * Invoked when the libevent timer has expired: see which tor_timer_t events - * have fired, activate their callbacks, and reschedule the libevent timer. - */ -static void -libevent_timer_callback(mainloop_event_t *ev, void *arg) -{ - (void)ev; - (void)arg; - - timers_run_pending(); - - libevent_timer_reschedule(); -} - -/** - * Initialize the timers subsystem. Requires that libevent has already been - * initialized. - */ -void -timers_initialize(void) -{ - if (BUG(global_timeouts)) - return; // LCOV_EXCL_LINE - - timeout_error_t err = 0; - global_timeouts = timeouts_open(0, &err); - if (!global_timeouts) { - // LCOV_EXCL_START -- this can only fail on malloc failure. - log_err(LD_BUG, "Unable to open timer backend: %s", strerror(err)); - tor_assert(0); - // LCOV_EXCL_STOP - } - - monotime_init(); - monotime_get(&start_of_time); - - mainloop_event_t *timer_event; - timer_event = mainloop_event_new(libevent_timer_callback, NULL); - tor_assert(timer_event); - global_timer_event = timer_event; - - libevent_timer_reschedule(); -} - -/** - * Release all storage held in the timers subsystem. Does not fire timers. - */ -void -timers_shutdown(void) -{ - if (global_timer_event) { - mainloop_event_free(global_timer_event); - global_timer_event = NULL; - } - if (global_timeouts) { - timeouts_close(global_timeouts); - global_timeouts = NULL; - } -} - -/** - * Allocate and return a new timer, with given callback and argument. - */ -tor_timer_t * -timer_new(timer_cb_fn_t cb, void *arg) -{ - tor_timer_t *t = tor_malloc(sizeof(tor_timer_t)); - timeout_init(t, 0); - timer_set_cb(t, cb, arg); - return t; -} - -/** - * Release all storage held by <b>t</b>, and unschedule it if was already - * scheduled. - */ -void -timer_free_(tor_timer_t *t) -{ - if (! t) - return; - - timeouts_del(global_timeouts, t); - tor_free(t); -} - -/** - * Change the callback and argument associated with a timer <b>t</b>. - */ -void -timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg) -{ - t->callback.cb = cb; - t->callback.arg = arg; -} - -/** - * Set *<b>cb_out</b> (if provided) to this timer's callback function, - * and *<b>arg_out</b> (if provided) to this timer's callback argument. - */ -void -timer_get_cb(const tor_timer_t *t, - timer_cb_fn_t *cb_out, void **arg_out) -{ - if (cb_out) - *cb_out = t->callback.cb; - if (arg_out) - *arg_out = t->callback.arg; -} - -/** - * Schedule the timer t to fire at the current time plus a delay of - * <b>delay</b> microseconds. All times are relative to monotime_get(). - */ -void -timer_schedule(tor_timer_t *t, const struct timeval *tv) -{ - const timeout_t delay = tv_to_timeout(tv); - - monotime_t now; - monotime_get(&now); - timer_advance_to_cur_time(&now); - - /* Take the old timeout value. */ - timeout_t to = timeouts_timeout(global_timeouts); - - timeouts_add(global_timeouts, t, delay); - - /* Should we update the libevent timer? */ - if (to <= delay) { - return; /* we're already going to fire before this timer would trigger. */ - } - libevent_timer_reschedule(); -} - -/** - * Cancel the timer <b>t</b> if it is currently scheduled. (It's okay to call - * this on an unscheduled timer. - */ -void -timer_disable(tor_timer_t *t) -{ - timeouts_del(global_timeouts, t); - /* We don't reschedule the libevent timer here, since it's okay if it fires - * early. */ -} - diff --git a/src/common/timers.h b/src/common/timers.h deleted file mode 100644 index 6d27f3e01e..0000000000 --- a/src/common/timers.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_TIMERS_H -#define TOR_TIMERS_H - -#include "orconfig.h" -#include "testsupport.h" - -struct monotime_t; -typedef struct timeout tor_timer_t; -typedef void (*timer_cb_fn_t)(tor_timer_t *, void *, - const struct monotime_t *); -tor_timer_t *timer_new(timer_cb_fn_t cb, void *arg); -void timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg); -void timer_get_cb(const tor_timer_t *t, - timer_cb_fn_t *cb_out, void **arg_out); -void timer_schedule(tor_timer_t *t, const struct timeval *delay); -void timer_disable(tor_timer_t *t); -void timer_free_(tor_timer_t *t); -#define timer_free(t) FREE_AND_NULL(tor_timer_t, timer_free_, (t)) - -void timers_initialize(void); -void timers_shutdown(void); - -#ifdef TOR_TIMERS_PRIVATE -STATIC void timers_run_pending(void); -#endif - -#endif /* !defined(TOR_TIMERS_H) */ - diff --git a/src/common/token_bucket.c b/src/common/token_bucket.c deleted file mode 100644 index f2396ec58a..0000000000 --- a/src/common/token_bucket.c +++ /dev/null @@ -1,255 +0,0 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file token_bucket.c - * \brief Functions to use and manipulate token buckets, used for - * rate-limiting on connections and globally. - * - * Tor uses these token buckets to keep track of bandwidth usage, and - * sometimes other things too. - * - * There are two layers of abstraction here: "raw" token buckets, in which all - * the pieces are decoupled, and "read-write" token buckets, which combine all - * the moving parts into one. - * - * Token buckets may become negative. - **/ - -#define TOKEN_BUCKET_PRIVATE - -#include "token_bucket.h" -#include "util_bug.h" - -/** - * Set the <b>rate</b> and <b>burst</b> value in a token_bucket_cfg. - * - * Note that the <b>rate</b> value is in arbitrary units, but those units will - * determine the units of token_bucket_raw_dec(), token_bucket_raw_refill, and - * so on. - */ -void -token_bucket_cfg_init(token_bucket_cfg_t *cfg, - uint32_t rate, - uint32_t burst) -{ - tor_assert_nonfatal(rate > 0); - tor_assert_nonfatal(burst > 0); - if (burst > TOKEN_BUCKET_MAX_BURST) - burst = TOKEN_BUCKET_MAX_BURST; - - cfg->rate = rate; - cfg->burst = burst; -} - -/** - * Initialize a raw token bucket and its associated timestamp to the "full" - * state, according to <b>cfg</b>. - */ -void -token_bucket_raw_reset(token_bucket_raw_t *bucket, - const token_bucket_cfg_t *cfg) -{ - bucket->bucket = cfg->burst; -} - -/** - * Adust a preexisting token bucket to respect the new configuration - * <b>cfg</b>, by decreasing its current level if needed. */ -void -token_bucket_raw_adjust(token_bucket_raw_t *bucket, - const token_bucket_cfg_t *cfg) -{ - bucket->bucket = MIN(bucket->bucket, cfg->burst); -} - -/** - * Given an amount of <b>elapsed</b> time units, and a bucket configuration - * <b>cfg</b>, refill the level of <b>bucket</b> accordingly. Note that the - * units of time in <b>elapsed</b> must correspond to those used to set the - * rate in <b>cfg</b>, or the result will be illogical. - */ -int -token_bucket_raw_refill_steps(token_bucket_raw_t *bucket, - const token_bucket_cfg_t *cfg, - const uint32_t elapsed) -{ - const int was_empty = (bucket->bucket <= 0); - /* The casts here prevent an underflow. - * - * Note that even if the bucket value is negative, subtracting it from - * "burst" will still produce a correct result. If this result is - * ridiculously high, then the "elapsed > gap / rate" check below - * should catch it. */ - const size_t gap = ((size_t)cfg->burst) - ((size_t)bucket->bucket); - - if (elapsed > gap / cfg->rate) { - bucket->bucket = cfg->burst; - } else { - bucket->bucket += cfg->rate * elapsed; - } - - return was_empty && bucket->bucket > 0; -} - -/** - * Decrement a provided bucket by <b>n</b> units. Note that <b>n</b> - * must be nonnegative. - */ -int -token_bucket_raw_dec(token_bucket_raw_t *bucket, - ssize_t n) -{ - if (BUG(n < 0)) - return 0; - const int becomes_empty = bucket->bucket > 0 && n >= bucket->bucket; - bucket->bucket -= n; - return becomes_empty; -} - -/** Convert a rate in bytes per second to a rate in bytes per step */ -STATIC uint32_t -rate_per_sec_to_rate_per_step(uint32_t rate) -{ - /* - The precise calculation we'd want to do is - - (rate / 1000) * to_approximate_msec(TICKS_PER_STEP). But to minimize - rounding error, we do it this way instead, and divide last. - */ - uint64_t units = (uint64_t) rate * TICKS_PER_STEP; - uint32_t val = (uint32_t) - (monotime_coarse_stamp_units_to_approx_msec(units) / 1000); - return val ? val : 1; -} - -/** - * Initialize a token bucket in *<b>bucket</b>, set up to allow <b>rate</b> - * bytes per second, with a maximum burst of <b>burst</b> bytes. The bucket - * is created such that <b>now_ts</b> is the current timestamp. The bucket - * starts out full. - */ -void -token_bucket_rw_init(token_bucket_rw_t *bucket, - uint32_t rate, - uint32_t burst, - uint32_t now_ts) -{ - memset(bucket, 0, sizeof(token_bucket_rw_t)); - token_bucket_rw_adjust(bucket, rate, burst); - token_bucket_rw_reset(bucket, now_ts); -} - -/** - * Change the configured rate (in bytes per second) and burst (in bytes) - * for the token bucket in *<b>bucket</b>. - */ -void -token_bucket_rw_adjust(token_bucket_rw_t *bucket, - uint32_t rate, - uint32_t burst) -{ - token_bucket_cfg_init(&bucket->cfg, - rate_per_sec_to_rate_per_step(rate), - burst); - token_bucket_raw_adjust(&bucket->read_bucket, &bucket->cfg); - token_bucket_raw_adjust(&bucket->write_bucket, &bucket->cfg); -} - -/** - * Reset <b>bucket</b> to be full, as of timestamp <b>now_ts</b>. - */ -void -token_bucket_rw_reset(token_bucket_rw_t *bucket, - uint32_t now_ts) -{ - token_bucket_raw_reset(&bucket->read_bucket, &bucket->cfg); - token_bucket_raw_reset(&bucket->write_bucket, &bucket->cfg); - bucket->last_refilled_at_timestamp = now_ts; -} - -/** - * Refill <b>bucket</b> as appropriate, given that the current timestamp - * is <b>now_ts</b>. - * - * Return a bitmask containing TB_READ iff read bucket was empty and became - * nonempty, and TB_WRITE iff the write bucket was empty and became nonempty. - */ -int -token_bucket_rw_refill(token_bucket_rw_t *bucket, - uint32_t now_ts) -{ - const uint32_t elapsed_ticks = - (now_ts - bucket->last_refilled_at_timestamp); - if (elapsed_ticks > UINT32_MAX-(300*1000)) { - /* Either about 48 days have passed since the last refill, or the - * monotonic clock has somehow moved backwards. (We're looking at you, - * Windows.). We accept up to a 5 minute jump backwards as - * "unremarkable". - */ - return 0; - } - const uint32_t elapsed_steps = elapsed_ticks / TICKS_PER_STEP; - - if (!elapsed_steps) { - /* Note that if less than one whole step elapsed, we don't advance the - * time in last_refilled_at. That's intentional: we want to make sure - * that we add some bytes to it eventually. */ - return 0; - } - - int flags = 0; - if (token_bucket_raw_refill_steps(&bucket->read_bucket, - &bucket->cfg, elapsed_steps)) - flags |= TB_READ; - if (token_bucket_raw_refill_steps(&bucket->write_bucket, - &bucket->cfg, elapsed_steps)) - flags |= TB_WRITE; - - bucket->last_refilled_at_timestamp = now_ts; - return flags; -} - -/** - * Decrement the read token bucket in <b>bucket</b> by <b>n</b> bytes. - * - * Return true if the bucket was nonempty and became empty; return false - * otherwise. - */ -int -token_bucket_rw_dec_read(token_bucket_rw_t *bucket, - ssize_t n) -{ - return token_bucket_raw_dec(&bucket->read_bucket, n); -} - -/** - * Decrement the write token bucket in <b>bucket</b> by <b>n</b> bytes. - * - * Return true if the bucket was nonempty and became empty; return false - * otherwise. - */ -int -token_bucket_rw_dec_write(token_bucket_rw_t *bucket, - ssize_t n) -{ - return token_bucket_raw_dec(&bucket->write_bucket, n); -} - -/** - * As token_bucket_rw_dec_read and token_bucket_rw_dec_write, in a single - * operation. Return a bitmask of TB_READ and TB_WRITE to indicate - * which buckets became empty. - */ -int -token_bucket_rw_dec(token_bucket_rw_t *bucket, - ssize_t n_read, ssize_t n_written) -{ - int flags = 0; - if (token_bucket_rw_dec_read(bucket, n_read)) - flags |= TB_READ; - if (token_bucket_rw_dec_write(bucket, n_written)) - flags |= TB_WRITE; - return flags; -} - diff --git a/src/common/token_bucket.h b/src/common/token_bucket.h deleted file mode 100644 index 0e7832e838..0000000000 --- a/src/common/token_bucket.h +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file token_bucket_rw.h - * \brief Headers for token_bucket_rw.c - **/ - -#ifndef TOR_TOKEN_BUCKET_H -#define TOR_TOKEN_BUCKET_H - -#include "torint.h" -#include "testsupport.h" - -/** Largest allowable burst value for a token buffer. */ -#define TOKEN_BUCKET_MAX_BURST INT32_MAX - -/** A generic token buffer configuration: determines the number of tokens - * added to the bucket in each time unit (the "rate"), and the maximum number - * of tokens in the bucket (the "burst") */ -typedef struct token_bucket_cfg_t { - uint32_t rate; - int32_t burst; -} token_bucket_cfg_t; - -/** A raw token bucket, decoupled from its configuration and timestamp. */ -typedef struct token_bucket_raw_t { - int32_t bucket; -} token_bucket_raw_t; - -void token_bucket_cfg_init(token_bucket_cfg_t *cfg, - uint32_t rate, - uint32_t burst); - -void token_bucket_raw_adjust(token_bucket_raw_t *bucket, - const token_bucket_cfg_t *cfg); - -void token_bucket_raw_reset(token_bucket_raw_t *bucket, - const token_bucket_cfg_t *cfg); - -int token_bucket_raw_dec(token_bucket_raw_t *bucket, - ssize_t n); - -int token_bucket_raw_refill_steps(token_bucket_raw_t *bucket, - const token_bucket_cfg_t *cfg, - const uint32_t elapsed_steps); - -static inline size_t token_bucket_raw_get(const token_bucket_raw_t *bucket); -/** Return the current number of bytes set in a token bucket. */ -static inline size_t -token_bucket_raw_get(const token_bucket_raw_t *bucket) -{ - return bucket->bucket >= 0 ? bucket->bucket : 0; -} - -/** A convenience type containing all the pieces needed for a coupled - * read-bucket and write-bucket that have the same rate limit, and which use - * "timestamp units" (see compat_time.h) for their time. */ -typedef struct token_bucket_rw_t { - token_bucket_cfg_t cfg; - token_bucket_raw_t read_bucket; - token_bucket_raw_t write_bucket; - uint32_t last_refilled_at_timestamp; -} token_bucket_rw_t; - -void token_bucket_rw_init(token_bucket_rw_t *bucket, - uint32_t rate, - uint32_t burst, - uint32_t now_ts); - -void token_bucket_rw_adjust(token_bucket_rw_t *bucket, - uint32_t rate, uint32_t burst); - -void token_bucket_rw_reset(token_bucket_rw_t *bucket, - uint32_t now_ts); - -#define TB_READ 1 -#define TB_WRITE 2 - -int token_bucket_rw_refill(token_bucket_rw_t *bucket, - uint32_t now_ts); - -int token_bucket_rw_dec_read(token_bucket_rw_t *bucket, - ssize_t n); -int token_bucket_rw_dec_write(token_bucket_rw_t *bucket, - ssize_t n); - -int token_bucket_rw_dec(token_bucket_rw_t *bucket, - ssize_t n_read, ssize_t n_written); - -static inline size_t token_bucket_rw_get_read(const token_bucket_rw_t *bucket); -static inline size_t -token_bucket_rw_get_read(const token_bucket_rw_t *bucket) -{ - return token_bucket_raw_get(&bucket->read_bucket); -} - -static inline size_t token_bucket_rw_get_write( - const token_bucket_rw_t *bucket); -static inline size_t -token_bucket_rw_get_write(const token_bucket_rw_t *bucket) -{ - return token_bucket_raw_get(&bucket->write_bucket); -} - -#ifdef TOKEN_BUCKET_PRIVATE - -/* To avoid making the rates too small, we consider units of "steps", - * where a "step" is defined as this many timestamp ticks. Keep this - * a power of two if you can. */ -#define TICKS_PER_STEP 16 - -STATIC uint32_t rate_per_sec_to_rate_per_step(uint32_t rate); - -#endif - -#endif /* TOR_TOKEN_BUCKET_H */ - diff --git a/src/common/torint.h b/src/common/torint.h deleted file mode 100644 index fc7818fe2c..0000000000 --- a/src/common/torint.h +++ /dev/null @@ -1,379 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file torint.h - * \brief Header file to define uint32_t and friends - **/ - -#ifndef TOR_TORINT_H -#define TOR_TORINT_H - -#include "orconfig.h" - -#ifdef HAVE_STDINT_H -#include <stdint.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_LIMITS_H -#include <limits.h> -#endif -#ifdef HAVE_SYS_LIMITS_H -#include <sys/limits.h> -#endif -#ifdef HAVE_MACHINE_LIMITS_H -#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) - /* FreeBSD has a bug where it complains that this file is obsolete, - and I should migrate to using sys/limits. It complains even when - I include both. - __FreeBSD_kernel__ is defined by Debian GNU/kFreeBSD which - does the same thing (but doesn't defined __FreeBSD__). - */ -#include <machine/limits.h> -#endif /* !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */ -#endif /* defined(HAVE_MACHINE_LIMITS_H) */ -#ifdef HAVE_INTTYPES_H -#include <inttypes.h> -#endif - -#include <stdbool.h> - -#if (SIZEOF_INT8_T != 0) -#define HAVE_INT8_T -#endif -#if (SIZEOF_INT16_T != 0) -#define HAVE_INT16_T -#endif -#if (SIZEOF_INT32_T != 0) -#define HAVE_INT32_T -#endif -#if (SIZEOF_INT64_T != 0) -#define HAVE_INT64_T -#endif -#if (SIZEOF_UINT8_T != 0) -#define HAVE_UINT8_T -#endif -#if (SIZEOF_UINT16_T != 0) -#define HAVE_UINT16_T -#endif -#if (SIZEOF_UINT32_T != 0) -#define HAVE_UINT32_T -#endif -#if (SIZEOF_UINT64_T != 0) -#define HAVE_UINT64_T -#endif -#if (SIZEOF_INTPTR_T != 0) -#define HAVE_INTPTR_T -#endif -#if (SIZEOF_UINTPTR_T != 0) -#define HAVE_UINTPTR_T -#endif - -#if (SIZEOF_CHAR == 1) -#ifndef HAVE_INT8_T -typedef signed char int8_t; -#define HAVE_INT8_T -#endif -#ifndef HAVE_UINT8_T -typedef unsigned char uint8_t; -#define HAVE_UINT8_T -#endif -#endif /* (SIZEOF_CHAR == 1) */ - -#if (SIZEOF_SHORT == 2) -#ifndef HAVE_INT16_T -typedef signed short int16_t; -#define HAVE_INT16_T -#endif -#ifndef HAVE_UINT16_T -typedef unsigned short uint16_t; -#define HAVE_UINT16_T -#endif -#endif /* (SIZEOF_SHORT == 2) */ - -#if (SIZEOF_INT == 2) -#ifndef HAVE_INT16_T -typedef signed int int16_t; -#define HAVE_INT16_T -#endif -#ifndef HAVE_UINT16_T -typedef unsigned int uint16_t; -#define HAVE_UINT16_T -#endif -#elif (SIZEOF_INT == 4) -#ifndef HAVE_INT32_T -typedef signed int int32_t; -#define HAVE_INT32_T -#endif -#ifndef HAVE_UINT32_T -typedef unsigned int uint32_t; -#define HAVE_UINT32_T -#endif -#ifndef UINT16_MAX -#define UINT16_MAX 0xffffu -#endif -#ifndef INT16_MAX -#define INT16_MAX 0x7fff -#endif -#ifndef INT16_MIN -#define INT16_MIN (-INT16_MAX-1) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX 0xffffffffu -#endif -#ifndef INT32_MAX -#define INT32_MAX 0x7fffffff -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#endif /* (SIZEOF_INT == 2) || ... */ - -#if (SIZEOF_LONG == 4) -#ifndef HAVE_INT32_T -typedef signed long int32_t; -#define HAVE_INT32_T -#endif -#ifndef HAVE_UINT32_T -typedef unsigned long uint32_t; -#define HAVE_UINT32_T -#ifndef UINT32_MAX -#define UINT32_MAX 0xfffffffful -#endif -#endif /* !defined(HAVE_UINT32_T) */ -#elif (SIZEOF_LONG == 8) -#ifndef HAVE_INT64_T -typedef signed long int64_t; -#define HAVE_INT64_T -#endif -#ifndef HAVE_UINT32_T -typedef unsigned long uint64_t; -#define HAVE_UINT32_T -#endif -#ifndef UINT64_MAX -#define UINT64_MAX 0xfffffffffffffffful -#endif -#endif /* (SIZEOF_LONG == 4) || ... */ - -#if (SIZEOF_LONG_LONG == 8) -#ifndef HAVE_INT64_T -typedef signed long long int64_t; -#define HAVE_INT64_T -#endif -#ifndef HAVE_UINT64_T -typedef unsigned long long uint64_t; -#define HAVE_UINT64_T -#endif -#ifndef UINT64_MAX -#define UINT64_MAX 0xffffffffffffffffull -#endif -#ifndef INT64_MAX -#define INT64_MAX 0x7fffffffffffffffll -#endif -#endif /* (SIZEOF_LONG_LONG == 8) */ - -#if (SIZEOF___INT64 == 8) -#ifndef HAVE_INT64_T -typedef signed __int64 int64_t; -#define HAVE_INT64_T -#endif -#ifndef HAVE_UINT64_T -typedef unsigned __int64 uint64_t; -#define HAVE_UINT64_T -#endif -#ifndef UINT64_MAX -#define UINT64_MAX 0xffffffffffffffffui64 -#endif -#ifndef INT64_MAX -#define INT64_MAX 0x7fffffffffffffffi64 -#endif -#endif /* (SIZEOF___INT64 == 8) */ - -#ifndef INT64_MIN -#define INT64_MIN ((- INT64_MAX) - 1) -#endif - -#ifndef SIZE_MAX -#if SIZEOF_SIZE_T == 8 -#define SIZE_MAX UINT64_MAX -#elif SIZEOF_SIZE_T == 4 -#define SIZE_MAX UINT32_MAX -#else -#error "Can't define SIZE_MAX" -#endif /* SIZEOF_SIZE_T == 8 || ... */ -#endif /* !defined(SIZE_MAX) */ - -#ifndef HAVE_SSIZE_T -#if SIZEOF_SIZE_T == 8 -typedef int64_t ssize_t; -#elif SIZEOF_SIZE_T == 4 -typedef int32_t ssize_t; -#else -#error "Can't define ssize_t." -#endif /* SIZEOF_SIZE_T == 8 || ... */ -#endif /* !defined(HAVE_SSIZE_T) */ - -#if (SIZEOF_VOID_P > 4 && SIZEOF_VOID_P <= 8) -#ifndef HAVE_INTPTR_T -typedef int64_t intptr_t; -#define SIZEOF_INTPTR_T 8 -#endif -#ifndef HAVE_UINTPTR_T -typedef uint64_t uintptr_t; -#define SIZEOF_UINTPTR_T 8 -#endif -#elif (SIZEOF_VOID_P > 2 && SIZEOF_VOID_P <= 4) -#ifndef HAVE_INTPTR_T -typedef int32_t intptr_t; -#define SIZEOF_INTPTR_T 4 -#endif -#ifndef HAVE_UINTPTR_T -typedef uint32_t uintptr_t; -#define SIZEOF_UINTPTR_T 4 -#endif -#else -#error "void * is either >8 bytes or <= 2. In either case, I am confused." -#endif /* (SIZEOF_VOID_P > 4 && SIZEOF_VOID_P <= 8) || ... */ - -#ifndef HAVE_INT8_T -#error "Missing type int8_t" -#endif -#ifndef HAVE_UINT8_T -#error "Missing type uint8_t" -#endif -#ifndef HAVE_INT16_T -#error "Missing type int16_t" -#endif -#ifndef HAVE_UINT16_T -#error "Missing type uint16_t" -#endif -#ifndef HAVE_INT32_T -#error "Missing type int32_t" -#endif -#ifndef HAVE_UINT32_T -#error "Missing type uint32_t" -#endif -#ifndef HAVE_INT64_T -#error "Missing type int64_t" -#endif -#ifndef HAVE_UINT64_T -#error "Missing type uint64_t" -#endif - -/* This assumes a sane (2's-complement) representation. But if you - * aren't 2's complement, and you don't define LONG_MAX, then you're so - * bizarre that I want nothing to do with you. */ -#ifndef USING_TWOS_COMPLEMENT -#error "Seems that your platform doesn't use 2's complement arithmetic. Argh." -#endif -#ifndef LONG_MAX -#if (SIZEOF_LONG == 4) -#define LONG_MAX 0x7fffffffL -#elif (SIZEOF_LONG == 8) -#define LONG_MAX 0x7fffffffffffffffL -#else -#error "Can't define LONG_MAX" -#endif /* (SIZEOF_LONG == 4) || ... */ -#endif /* !defined(LONG_MAX) */ - -#ifndef INT_MAX -#if (SIZEOF_INT == 4) -#define INT_MAX 0x7fffffffL -#elif (SIZEOF_INT == 8) -#define INT_MAX 0x7fffffffffffffffL -#else -#error "Can't define INT_MAX" -#endif /* (SIZEOF_INT == 4) || ... */ -#endif /* !defined(INT_MAX) */ - -#ifndef UINT_MAX -#if (SIZEOF_INT == 2) -#define UINT_MAX 0xffffu -#elif (SIZEOF_INT == 4) -#define UINT_MAX 0xffffffffu -#elif (SIZEOF_INT == 8) -#define UINT_MAX 0xffffffffffffffffu -#else -#error "Can't define UINT_MAX" -#endif /* (SIZEOF_INT == 2) || ... */ -#endif /* !defined(UINT_MAX) */ - -#ifndef SHORT_MAX -#if (SIZEOF_SHORT == 2) -#define SHORT_MAX 0x7fff -#elif (SIZEOF_SHORT == 4) -#define SHORT_MAX 0x7fffffff -#else -#error "Can't define SHORT_MAX" -#endif /* (SIZEOF_SHORT == 2) || ... */ -#endif /* !defined(SHORT_MAX) */ - -#ifndef TIME_MAX - -#if (SIZEOF_TIME_T == SIZEOF_INT) -#define TIME_MAX ((time_t)INT_MAX) -#elif (SIZEOF_TIME_T == SIZEOF_LONG) -#define TIME_MAX ((time_t)LONG_MAX) -#elif (SIZEOF_TIME_T == 8) -#define TIME_MAX ((time_t)INT64_MAX) -#else -#error "Can't define TIME_MAX" -#endif /* (SIZEOF_TIME_T == SIZEOF_INT) || ... */ - -#endif /* !defined(TIME_MAX) */ - -#ifndef TIME_MIN - -#if (SIZEOF_TIME_T == SIZEOF_INT) -#define TIME_MIN ((time_t)INT_MIN) -#elif (SIZEOF_TIME_T == SIZEOF_LONG) -#define TIME_MIN ((time_t)LONG_MIN) -#elif (SIZEOF_TIME_T == 8) -#define TIME_MIN ((time_t)INT64_MIN) -#else -#error "Can't define TIME_MIN" -#endif /* (SIZEOF_TIME_T == SIZEOF_INT) || ... */ - -#endif /* !defined(TIME_MIN) */ - -#ifndef SIZE_MAX -#if (SIZEOF_SIZE_T == 4) -#define SIZE_MAX UINT32_MAX -#elif (SIZEOF_SIZE_T == 8) -#define SIZE_MAX UINT64_MAX -#else -#error "Can't define SIZE_MAX" -#endif /* (SIZEOF_SIZE_T == 4) || ... */ -#endif /* !defined(SIZE_MAX) */ - -#ifdef _WIN32 -# ifdef _WIN64 -# define TOR_PRIuSZ PRIu64 -# else -# define TOR_PRIuSZ PRIu32 -# endif -#else -# define TOR_PRIuSZ "zu" -#endif - -#ifndef SSIZE_MAX -#if (SIZEOF_SIZE_T == 4) -#define SSIZE_MAX INT32_MAX -#elif (SIZEOF_SIZE_T == 8) -#define SSIZE_MAX INT64_MAX -#else -#error "Can't define SSIZE_MAX" -#endif /* (SIZEOF_SIZE_T == 4) || ... */ -#endif /* !defined(SSIZE_MAX) */ - -/** Any ssize_t larger than this amount is likely to be an underflow. */ -#define SSIZE_T_CEILING ((ssize_t)(SSIZE_MAX-16)) -/** Any size_t larger than this amount is likely to be an underflow. */ -#define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16)) - -#endif /* !defined(TOR_TORINT_H) */ - diff --git a/src/common/torlog.h b/src/common/torlog.h deleted file mode 100644 index de389883c0..0000000000 --- a/src/common/torlog.h +++ /dev/null @@ -1,275 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file torlog.h - * - * \brief Headers for log.c - **/ - -#ifndef TOR_TORLOG_H - -#include "compat.h" -#include "testsupport.h" - -#ifdef HAVE_SYSLOG_H -#include <syslog.h> -#define LOG_WARN LOG_WARNING -#if LOG_DEBUG < LOG_ERR -#error "Your syslog.h thinks high numbers are more important. " \ - "We aren't prepared to deal with that." -#endif -#else /* !(defined(HAVE_SYSLOG_H)) */ -/* Note: Syslog's logging code refers to priorities, with 0 being the most - * important. Thus, all our comparisons needed to be reversed when we added - * syslog support. - * - * The upshot of this is that comments about log levels may be messed up: for - * "maximum severity" read "most severe" and "numerically *lowest* severity". - */ - -/** Debug-level severity: for hyper-verbose messages of no interest to - * anybody but developers. */ -#define LOG_DEBUG 7 -/** Info-level severity: for messages that appear frequently during normal - * operation. */ -#define LOG_INFO 6 -/** Notice-level severity: for messages that appear infrequently - * during normal operation; that the user will probably care about; - * and that are not errors. - */ -#define LOG_NOTICE 5 -/** Warn-level severity: for messages that only appear when something has gone - * wrong. */ -#define LOG_WARN 4 -/** Error-level severity: for messages that only appear when something has gone - * very wrong, and the Tor process can no longer proceed. */ -#define LOG_ERR 3 -#endif /* defined(HAVE_SYSLOG_H) */ - -/* Logging domains */ - -/** Catch-all for miscellaneous events and fatal errors. */ -#define LD_GENERAL (1u<<0) -/** The cryptography subsystem. */ -#define LD_CRYPTO (1u<<1) -/** Networking. */ -#define LD_NET (1u<<2) -/** Parsing and acting on our configuration. */ -#define LD_CONFIG (1u<<3) -/** Reading and writing from the filesystem. */ -#define LD_FS (1u<<4) -/** Other servers' (non)compliance with the Tor protocol. */ -#define LD_PROTOCOL (1u<<5) -/** Memory management. */ -#define LD_MM (1u<<6) -/** HTTP implementation. */ -#define LD_HTTP (1u<<7) -/** Application (socks) requests. */ -#define LD_APP (1u<<8) -/** Communication via the controller protocol. */ -#define LD_CONTROL (1u<<9) -/** Building, using, and managing circuits. */ -#define LD_CIRC (1u<<10) -/** Hidden services. */ -#define LD_REND (1u<<11) -/** Internal errors in this Tor process. */ -#define LD_BUG (1u<<12) -/** Learning and using information about Tor servers. */ -#define LD_DIR (1u<<13) -/** Learning and using information about Tor servers. */ -#define LD_DIRSERV (1u<<14) -/** Onion routing protocol. */ -#define LD_OR (1u<<15) -/** Generic edge-connection functionality. */ -#define LD_EDGE (1u<<16) -#define LD_EXIT LD_EDGE -/** Bandwidth accounting. */ -#define LD_ACCT (1u<<17) -/** Router history */ -#define LD_HIST (1u<<18) -/** OR handshaking */ -#define LD_HANDSHAKE (1u<<19) -/** Heartbeat messages */ -#define LD_HEARTBEAT (1u<<20) -/** Abstract channel_t code */ -#define LD_CHANNEL (1u<<21) -/** Scheduler */ -#define LD_SCHED (1u<<22) -/** Guard nodes */ -#define LD_GUARD (1u<<23) -/** Generation and application of consensus diffs. */ -#define LD_CONSDIFF (1u<<24) -/** Denial of Service mitigation. */ -#define LD_DOS (1u<<25) -/** Number of logging domains in the code. */ -#define N_LOGGING_DOMAINS 26 - -/** This log message is not safe to send to a callback-based logger - * immediately. Used as a flag, not a log domain. */ -#define LD_NOCB (1u<<31) -/** This log message should not include a function name, even if it otherwise - * would. Used as a flag, not a log domain. */ -#define LD_NOFUNCNAME (1u<<30) - -#ifdef TOR_UNIT_TESTS -/** This log message should not be intercepted by mock_saving_logv */ -#define LD_NO_MOCK (1u<<29) -#endif - -/** Mask of zero or more log domains, OR'd together. */ -typedef uint32_t log_domain_mask_t; - -/** Configures which severities are logged for each logging domain for a given - * log target. */ -typedef struct log_severity_list_t { - /** For each log severity, a bitmask of which domains a given logger is - * logging. */ - log_domain_mask_t masks[LOG_DEBUG-LOG_ERR+1]; -} log_severity_list_t; - -/** Callback type used for add_callback_log. */ -typedef void (*log_callback)(int severity, uint32_t domain, const char *msg); - -void init_logging(int disable_startup_queue); -int parse_log_level(const char *level); -const char *log_level_to_string(int level); -int parse_log_severity_config(const char **cfg, - log_severity_list_t *severity_out); -void set_log_severity_config(int minSeverity, int maxSeverity, - log_severity_list_t *severity_out); -void add_stream_log(const log_severity_list_t *severity, const char *name, - int fd); -int add_file_log(const log_severity_list_t *severity, const char *filename, - const int truncate); -#ifdef HAVE_SYSLOG_H -int add_syslog_log(const log_severity_list_t *severity, - const char* syslog_identity_tag); -#endif // HAVE_SYSLOG_H. -#ifdef HAVE_ANDROID_LOG_H -int add_android_log(const log_severity_list_t *severity, - const char *android_identity_tag); -#endif // HAVE_ANDROID_LOG_H. -int add_callback_log(const log_severity_list_t *severity, log_callback cb); -typedef void (*pending_callback_callback)(void); -void logs_set_pending_callback_callback(pending_callback_callback cb); -void logs_set_domain_logging(int enabled); -int get_min_log_level(void); -void switch_logs_debug(void); -void logs_free_all(void); -void add_temp_log(int min_severity); -void close_temp_logs(void); -void rollback_log_changes(void); -void mark_logs_temp(void); -void change_callback_log_severity(int loglevelMin, int loglevelMax, - log_callback cb); -void flush_pending_log_callbacks(void); -void flush_log_messages_from_startup(void); -void log_set_application_name(const char *name); -void set_log_time_granularity(int granularity_msec); -void truncate_logs(void); - -void tor_log(int severity, log_domain_mask_t domain, const char *format, ...) - CHECK_PRINTF(3,4); - -void tor_log_err_sigsafe(const char *m, ...); -int tor_log_get_sigsafe_err_fds(const int **out); -void tor_log_update_sigsafe_err_fds(void); - -struct smartlist_t; -void tor_log_get_logfile_names(struct smartlist_t *out); - -extern int log_global_min_severity_; - -void log_fn_(int severity, log_domain_mask_t domain, - const char *funcname, const char *format, ...) - CHECK_PRINTF(4,5); -struct ratelim_t; -void log_fn_ratelim_(struct ratelim_t *ratelim, int severity, - log_domain_mask_t domain, const char *funcname, - const char *format, ...) - CHECK_PRINTF(5,6); - -int log_message_is_interesting(int severity, log_domain_mask_t domain); -void tor_log_string(int severity, log_domain_mask_t domain, - const char *function, const char *string); - -#if defined(__GNUC__) && __GNUC__ <= 3 - -/* These are the GCC varidaic macros, so that older versions of GCC don't - * break. */ - -/** Log a message at level <b>severity</b>, using a pretty-printed version - * of the current function name. */ -#define log_fn(severity, domain, args...) \ - log_fn_(severity, domain, __FUNCTION__, args) -/** As log_fn, but use <b>ratelim</b> (an instance of ratelim_t) to control - * the frequency at which messages can appear. - */ -#define log_fn_ratelim(ratelim, severity, domain, args...) \ - log_fn_ratelim_(ratelim, severity, domain, __FUNCTION__, args) -#define log_debug(domain, args...) \ - STMT_BEGIN \ - if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \ - log_fn_(LOG_DEBUG, domain, __FUNCTION__, args); \ - STMT_END -#define log_info(domain, args...) \ - log_fn_(LOG_INFO, domain, __FUNCTION__, args) -#define log_notice(domain, args...) \ - log_fn_(LOG_NOTICE, domain, __FUNCTION__, args) -#define log_warn(domain, args...) \ - log_fn_(LOG_WARN, domain, __FUNCTION__, args) -#define log_err(domain, args...) \ - log_fn_(LOG_ERR, domain, __FUNCTION__, args) - -#else /* !(defined(__GNUC__) && __GNUC__ <= 3) */ - -/* Here are the c99 variadic macros, to work with non-GCC compilers */ - -#define log_debug(domain, args, ...) \ - STMT_BEGIN \ - if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \ - log_fn_(LOG_DEBUG, domain, __FUNCTION__, args, ##__VA_ARGS__); \ - STMT_END -#define log_info(domain, args,...) \ - log_fn_(LOG_INFO, domain, __FUNCTION__, args, ##__VA_ARGS__) -#define log_notice(domain, args,...) \ - log_fn_(LOG_NOTICE, domain, __FUNCTION__, args, ##__VA_ARGS__) -#define log_warn(domain, args,...) \ - log_fn_(LOG_WARN, domain, __FUNCTION__, args, ##__VA_ARGS__) -#define log_err(domain, args,...) \ - log_fn_(LOG_ERR, domain, __FUNCTION__, args, ##__VA_ARGS__) -/** Log a message at level <b>severity</b>, using a pretty-printed version - * of the current function name. */ -#define log_fn(severity, domain, args,...) \ - log_fn_(severity, domain, __FUNCTION__, args, ##__VA_ARGS__) -/** As log_fn, but use <b>ratelim</b> (an instance of ratelim_t) to control - * the frequency at which messages can appear. - */ -#define log_fn_ratelim(ratelim, severity, domain, args,...) \ - log_fn_ratelim_(ratelim, severity, domain, __FUNCTION__, \ - args, ##__VA_ARGS__) -#endif /* defined(__GNUC__) && __GNUC__ <= 3 */ - -/** This defines log levels that are linked in the Rust log module, rather - * than re-defining these in both Rust and C. - * - * C_RUST_COUPLED src/rust/tor_log LogSeverity, LogDomain - */ -extern const int LOG_WARN_; -extern const int LOG_NOTICE_; -extern const log_domain_mask_t LD_NET_; -extern const log_domain_mask_t LD_GENERAL_; - -#ifdef LOG_PRIVATE -MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain, - const char *funcname, const char *suffix, const char *format, - va_list ap) CHECK_PRINTF(5,0)); -#endif - -# define TOR_TORLOG_H -#endif /* !defined(TOR_TORLOG_H) */ - diff --git a/src/common/tortls.c b/src/common/tortls.c deleted file mode 100644 index 08aa35a480..0000000000 --- a/src/common/tortls.c +++ /dev/null @@ -1,2670 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file tortls.c - * \brief Wrapper functions to present a consistent interface to - * TLS, SSL, and X.509 functions from OpenSSL. - **/ - -/* (Unlike other tor functions, these - * are prefixed with tor_ in order to avoid conflicting with OpenSSL - * functions and variables.) - */ - -#include "orconfig.h" - -#define TORTLS_PRIVATE -#define TORTLS_OPENSSL_PRIVATE - -#include <assert.h> -#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ - #include <winsock2.h> - #include <ws2tcpip.h> -#endif - -#include "crypto.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "compat.h" - -/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in - * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/opensslv.h> - -#ifdef OPENSSL_NO_EC -#error "We require OpenSSL with ECC support" -#endif - -#include <openssl/ssl.h> -#include <openssl/ssl3.h> -#include <openssl/err.h> -#include <openssl/tls1.h> -#include <openssl/asn1.h> -#include <openssl/bio.h> -#include <openssl/bn.h> -#include <openssl/rsa.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#define TORTLS_PRIVATE -#include "tortls.h" -#include "util.h" -#include "torlog.h" -#include "container.h" -#include <string.h> - -#ifdef OPENSSL_1_1_API -#define X509_get_notBefore_const(cert) \ - X509_get0_notBefore(cert) -#define X509_get_notAfter_const(cert) \ - X509_get0_notAfter(cert) -#ifndef X509_get_notBefore -#define X509_get_notBefore(cert) \ - X509_getm_notBefore(cert) -#endif -#ifndef X509_get_notAfter -#define X509_get_notAfter(cert) \ - X509_getm_notAfter(cert) -#endif -#else /* ! OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */ -#define X509_get_notBefore_const(cert) \ - ((const ASN1_TIME*) X509_get_notBefore((X509 *)cert)) -#define X509_get_notAfter_const(cert) \ - ((const ASN1_TIME*) X509_get_notAfter((X509 *)cert)) -#endif - -/* Copied from or.h */ -#define LEGAL_NICKNAME_CHARACTERS \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -/** How long do identity certificates live? (sec) */ -#define IDENTITY_CERT_LIFETIME (365*24*60*60) - -#define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer") - -#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f') -/* This is a version of OpenSSL before 1.0.0f. It does not have - * the CVE-2011-4576 fix, and as such it can't use RELEASE_BUFFERS and - * SSL3 safely at the same time. - */ -#define DISABLE_SSL3_HANDSHAKE -#endif /* OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f') */ - -/* We redefine these so that we can run correctly even if the vendor gives us - * a version of OpenSSL that does not match its header files. (Apple: I am - * looking at you.) - */ -#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION -#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L -#endif -#ifndef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION -#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010 -#endif - -/** Return values for tor_tls_classify_client_ciphers. - * - * @{ - */ -/** An error occurred when examining the client ciphers */ -#define CIPHERS_ERR -1 -/** The client cipher list indicates that a v1 handshake was in use. */ -#define CIPHERS_V1 1 -/** The client cipher list indicates that the client is using the v2 or the - * v3 handshake, but that it is (probably!) lying about what ciphers it - * supports */ -#define CIPHERS_V2 2 -/** The client cipher list indicates that the client is using the v2 or the - * v3 handshake, and that it is telling the truth about what ciphers it - * supports */ -#define CIPHERS_UNRESTRICTED 3 -/** @} */ - -/** The ex_data index in which we store a pointer to an SSL object's - * corresponding tor_tls_t object. */ -STATIC int tor_tls_object_ex_data_index = -1; - -/** Helper: Allocate tor_tls_object_ex_data_index. */ -STATIC void -tor_tls_allocate_tor_tls_object_ex_data_index(void) -{ - if (tor_tls_object_ex_data_index == -1) { - tor_tls_object_ex_data_index = - SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); - tor_assert(tor_tls_object_ex_data_index != -1); - } -} - -/** Helper: given a SSL* pointer, return the tor_tls_t object using that - * pointer. */ -STATIC tor_tls_t * -tor_tls_get_by_ssl(const SSL *ssl) -{ - tor_tls_t *result = SSL_get_ex_data(ssl, tor_tls_object_ex_data_index); - if (result) - tor_assert(result->magic == TOR_TLS_MAGIC); - return result; -} - -static void tor_tls_context_decref(tor_tls_context_t *ctx); -static void tor_tls_context_incref(tor_tls_context_t *ctx); - -static int check_cert_lifetime_internal(int severity, const X509 *cert, - time_t now, - int past_tolerance, int future_tolerance); - -/** Global TLS contexts. We keep them here because nobody else needs - * to touch them. - * - * @{ */ -STATIC tor_tls_context_t *server_tls_context = NULL; -STATIC tor_tls_context_t *client_tls_context = NULL; -/**@}*/ - -/** True iff tor_tls_init() has been called. */ -static int tls_library_is_initialized = 0; - -/* Module-internal error codes. */ -#define TOR_TLS_SYSCALL_ (MIN_TOR_TLS_ERROR_VAL_ - 2) -#define TOR_TLS_ZERORETURN_ (MIN_TOR_TLS_ERROR_VAL_ - 1) - -/** Write a description of the current state of <b>tls</b> into the - * <b>sz</b>-byte buffer at <b>buf</b>. */ -void -tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz) -{ - const char *ssl_state; - const char *tortls_state; - - if (PREDICT_UNLIKELY(!tls || !tls->ssl)) { - strlcpy(buf, "(No SSL object)", sz); - return; - } - - ssl_state = SSL_state_string_long(tls->ssl); - switch (tls->state) { -#define CASE(st) case TOR_TLS_ST_##st: tortls_state = " in "#st ; break - CASE(HANDSHAKE); - CASE(OPEN); - CASE(GOTCLOSE); - CASE(SENTCLOSE); - CASE(CLOSED); - CASE(RENEGOTIATE); -#undef CASE - case TOR_TLS_ST_BUFFEREVENT: - tortls_state = ""; - break; - default: - tortls_state = " in unknown TLS state"; - break; - } - - tor_snprintf(buf, sz, "%s%s", ssl_state, tortls_state); -} - -/** Log a single error <b>err</b> as returned by ERR_get_error(), which was - * received while performing an operation <b>doing</b> on <b>tls</b>. Log - * the message at <b>severity</b>, in log domain <b>domain</b>. */ -void -tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, - int severity, int domain, const char *doing) -{ - const char *state = NULL, *addr; - const char *msg, *lib, *func; - - state = (tls && tls->ssl)?SSL_state_string_long(tls->ssl):"---"; - - addr = tls ? tls->address : NULL; - - /* Some errors are known-benign, meaning they are the fault of the other - * side of the connection. The caller doesn't know this, so override the - * priority for those cases. */ - switch (ERR_GET_REASON(err)) { - case SSL_R_HTTP_REQUEST: - case SSL_R_HTTPS_PROXY_REQUEST: - case SSL_R_RECORD_LENGTH_MISMATCH: -#ifndef OPENSSL_1_1_API - case SSL_R_RECORD_TOO_LARGE: -#endif - case SSL_R_UNKNOWN_PROTOCOL: - case SSL_R_UNSUPPORTED_PROTOCOL: - severity = LOG_INFO; - break; - default: - break; - } - - msg = (const char*)ERR_reason_error_string(err); - lib = (const char*)ERR_lib_error_string(err); - func = (const char*)ERR_func_error_string(err); - if (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (doing) { - tor_log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)", - doing, addr?" with ":"", addr?addr:"", - msg, lib, func, state); - } else { - tor_log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)", - addr?" with ":"", addr?addr:"", - msg, lib, func, state); - } -} - -/** Log all pending tls errors at level <b>severity</b> in log domain - * <b>domain</b>. Use <b>doing</b> to describe our current activities. - */ -STATIC void -tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing) -{ - unsigned long err; - - while ((err = ERR_get_error()) != 0) { - tor_tls_log_one_error(tls, err, severity, domain, doing); - } -} - -/** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error - * code. */ -STATIC int -tor_errno_to_tls_error(int e) -{ - switch (e) { - case SOCK_ERRNO(ECONNRESET): // most common - return TOR_TLS_ERROR_CONNRESET; - case SOCK_ERRNO(ETIMEDOUT): - return TOR_TLS_ERROR_TIMEOUT; - case SOCK_ERRNO(EHOSTUNREACH): - case SOCK_ERRNO(ENETUNREACH): - return TOR_TLS_ERROR_NO_ROUTE; - case SOCK_ERRNO(ECONNREFUSED): - return TOR_TLS_ERROR_CONNREFUSED; // least common - default: - return TOR_TLS_ERROR_MISC; - } -} - -/** Given a TOR_TLS_* error code, return a string equivalent. */ -const char * -tor_tls_err_to_string(int err) -{ - if (err >= 0) - return "[Not an error.]"; - switch (err) { - case TOR_TLS_ERROR_MISC: return "misc error"; - case TOR_TLS_ERROR_IO: return "unexpected close"; - case TOR_TLS_ERROR_CONNREFUSED: return "connection refused"; - case TOR_TLS_ERROR_CONNRESET: return "connection reset"; - case TOR_TLS_ERROR_NO_ROUTE: return "host unreachable"; - case TOR_TLS_ERROR_TIMEOUT: return "connection timed out"; - case TOR_TLS_CLOSE: return "closed"; - case TOR_TLS_WANTREAD: return "want to read"; - case TOR_TLS_WANTWRITE: return "want to write"; - default: return "(unknown error code)"; - } -} - -#define CATCH_SYSCALL 1 -#define CATCH_ZERO 2 - -/** Given a TLS object and the result of an SSL_* call, use - * SSL_get_error to determine whether an error has occurred, and if so - * which one. Return one of TOR_TLS_{DONE|WANTREAD|WANTWRITE|ERROR}. - * If extra&CATCH_SYSCALL is true, return TOR_TLS_SYSCALL_ instead of - * reporting syscall errors. If extra&CATCH_ZERO is true, return - * TOR_TLS_ZERORETURN_ instead of reporting zero-return errors. - * - * If an error has occurred, log it at level <b>severity</b> and describe the - * current action as <b>doing</b>. - */ -STATIC int -tor_tls_get_error(tor_tls_t *tls, int r, int extra, - const char *doing, int severity, int domain) -{ - int err = SSL_get_error(tls->ssl, r); - int tor_error = TOR_TLS_ERROR_MISC; - switch (err) { - case SSL_ERROR_NONE: - return TOR_TLS_DONE; - case SSL_ERROR_WANT_READ: - return TOR_TLS_WANTREAD; - case SSL_ERROR_WANT_WRITE: - return TOR_TLS_WANTWRITE; - case SSL_ERROR_SYSCALL: - if (extra&CATCH_SYSCALL) - return TOR_TLS_SYSCALL_; - if (r == 0) { - tor_log(severity, LD_NET, "TLS error: unexpected close while %s (%s)", - doing, SSL_state_string_long(tls->ssl)); - tor_error = TOR_TLS_ERROR_IO; - } else { - int e = tor_socket_errno(tls->socket); - tor_log(severity, LD_NET, - "TLS error: <syscall error while %s> (errno=%d: %s; state=%s)", - doing, e, tor_socket_strerror(e), - SSL_state_string_long(tls->ssl)); - tor_error = tor_errno_to_tls_error(e); - } - tls_log_errors(tls, severity, domain, doing); - return tor_error; - case SSL_ERROR_ZERO_RETURN: - if (extra&CATCH_ZERO) - return TOR_TLS_ZERORETURN_; - tor_log(severity, LD_NET, "TLS connection closed while %s in state %s", - doing, SSL_state_string_long(tls->ssl)); - tls_log_errors(tls, severity, domain, doing); - return TOR_TLS_CLOSE; - default: - tls_log_errors(tls, severity, domain, doing); - return TOR_TLS_ERROR_MISC; - } -} - -/** Initialize OpenSSL, unless it has already been initialized. - */ -static void -tor_tls_init(void) -{ - check_no_tls_errors(); - - if (!tls_library_is_initialized) { -#ifdef OPENSSL_1_1_API - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); -#else - SSL_library_init(); - SSL_load_error_strings(); -#endif - -#if (SIZEOF_VOID_P >= 8 && \ - OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1)) - long version = OpenSSL_version_num(); - - /* LCOV_EXCL_START : we can't test these lines on the same machine */ - if (version >= OPENSSL_V_SERIES(1,0,1)) { - /* Warn if we could *almost* be running with much faster ECDH. - If we're built for a 64-bit target, using OpenSSL 1.0.1, but we - don't have one of the built-in __uint128-based speedups, we are - just one build operation away from an accelerated handshake. - - (We could be looking at OPENSSL_NO_EC_NISTP_64_GCC_128 instead of - doing this test, but that gives compile-time options, not runtime - behavior.) - */ - EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - const EC_GROUP *g = key ? EC_KEY_get0_group(key) : NULL; - const EC_METHOD *m = g ? EC_GROUP_method_of(g) : NULL; - const int warn = (m == EC_GFp_simple_method() || - m == EC_GFp_mont_method() || - m == EC_GFp_nist_method()); - EC_KEY_free(key); - - if (warn) - log_notice(LD_GENERAL, "We were built to run on a 64-bit CPU, with " - "OpenSSL 1.0.1 or later, but with a version of OpenSSL " - "that apparently lacks accelerated support for the NIST " - "P-224 and P-256 groups. Building openssl with such " - "support (using the enable-ec_nistp_64_gcc_128 option " - "when configuring it) would make ECDH much faster."); - } - /* LCOV_EXCL_STOP */ -#endif /* (SIZEOF_VOID_P >= 8 && ... */ - - tor_tls_allocate_tor_tls_object_ex_data_index(); - - tls_library_is_initialized = 1; - } -} - -/** Free all global TLS structures. */ -void -tor_tls_free_all(void) -{ - check_no_tls_errors(); - - if (server_tls_context) { - tor_tls_context_t *ctx = server_tls_context; - server_tls_context = NULL; - tor_tls_context_decref(ctx); - } - if (client_tls_context) { - tor_tls_context_t *ctx = client_tls_context; - client_tls_context = NULL; - tor_tls_context_decref(ctx); - } -} - -/** We need to give OpenSSL a callback to verify certificates. This is - * it: We always accept peer certs and complete the handshake. We - * don't validate them until later. - */ -STATIC int -always_accept_verify_cb(int preverify_ok, - X509_STORE_CTX *x509_ctx) -{ - (void) preverify_ok; - (void) x509_ctx; - return 1; -} - -/** Return a newly allocated X509 name with commonName <b>cname</b>. */ -static X509_NAME * -tor_x509_name_new(const char *cname) -{ - int nid; - X509_NAME *name; - /* LCOV_EXCL_BR_START : these branches will only fail on OOM errors */ - if (!(name = X509_NAME_new())) - return NULL; - if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error; - if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, - (unsigned char*)cname, -1, -1, 0))) - goto error; - /* LCOV_EXCL_BR_STOP */ - return name; - - /* LCOV_EXCL_START : these lines will only execute on out of memory errors*/ - error: - X509_NAME_free(name); - return NULL; - /* LCOV_EXCL_STOP */ -} - -/** Generate and sign an X509 certificate with the public key <b>rsa</b>, - * signed by the private key <b>rsa_sign</b>. The commonName of the - * certificate will be <b>cname</b>; the commonName of the issuer will be - * <b>cname_sign</b>. The cert will be valid for <b>cert_lifetime</b> - * seconds, starting from some time in the past. - * - * Return a certificate on success, NULL on failure. - */ -MOCK_IMPL(STATIC X509 *, -tor_tls_create_certificate,(crypto_pk_t *rsa, - crypto_pk_t *rsa_sign, - const char *cname, - const char *cname_sign, - unsigned int cert_lifetime)) -{ - /* OpenSSL generates self-signed certificates with random 64-bit serial - * numbers, so let's do that too. */ -#define SERIAL_NUMBER_SIZE 8 - - time_t start_time, end_time; - BIGNUM *serial_number = NULL; - unsigned char serial_tmp[SERIAL_NUMBER_SIZE]; - EVP_PKEY *sign_pkey = NULL, *pkey=NULL; - X509 *x509 = NULL; - X509_NAME *name = NULL, *name_issuer=NULL; - - tor_tls_init(); - - /* Make sure we're part-way through the certificate lifetime, rather - * than having it start right now. Don't choose quite uniformly, since - * then we might pick a time where we're about to expire. Lastly, be - * sure to start on a day boundary. */ - time_t now = time(NULL); - /* Our certificate lifetime will be cert_lifetime no matter what, but if we - * start cert_lifetime in the past, we'll have 0 real lifetime. instead we - * start up to (cert_lifetime - min_real_lifetime - start_granularity) in - * the past. */ - const time_t min_real_lifetime = 24*3600; - const time_t start_granularity = 24*3600; - time_t earliest_start_time; - /* Don't actually start in the future! */ - if (cert_lifetime <= min_real_lifetime + start_granularity) { - earliest_start_time = now - 1; - } else { - earliest_start_time = now + min_real_lifetime + start_granularity - - cert_lifetime; - } - start_time = crypto_rand_time_range(earliest_start_time, now); - /* Round the start time back to the start of a day. */ - start_time -= start_time % start_granularity; - - end_time = start_time + cert_lifetime; - - tor_assert(rsa); - tor_assert(cname); - tor_assert(rsa_sign); - tor_assert(cname_sign); - if (!(sign_pkey = crypto_pk_get_evp_pkey_(rsa_sign,1))) - goto error; - if (!(pkey = crypto_pk_get_evp_pkey_(rsa,0))) - goto error; - if (!(x509 = X509_new())) - goto error; - if (!(X509_set_version(x509, 2))) - goto error; - - { /* our serial number is 8 random bytes. */ - crypto_rand((char *)serial_tmp, sizeof(serial_tmp)); - if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL))) - goto error; - if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509)))) - goto error; - } - - if (!(name = tor_x509_name_new(cname))) - goto error; - if (!(X509_set_subject_name(x509, name))) - goto error; - if (!(name_issuer = tor_x509_name_new(cname_sign))) - goto error; - if (!(X509_set_issuer_name(x509, name_issuer))) - goto error; - - if (!X509_time_adj(X509_get_notBefore(x509),0,&start_time)) - goto error; - if (!X509_time_adj(X509_get_notAfter(x509),0,&end_time)) - goto error; - if (!X509_set_pubkey(x509, pkey)) - goto error; - - if (!X509_sign(x509, sign_pkey, EVP_sha256())) - goto error; - - goto done; - error: - if (x509) { - X509_free(x509); - x509 = NULL; - } - done: - tls_log_errors(NULL, LOG_WARN, LD_NET, "generating certificate"); - if (sign_pkey) - EVP_PKEY_free(sign_pkey); - if (pkey) - EVP_PKEY_free(pkey); - if (serial_number) - BN_clear_free(serial_number); - if (name) - X509_NAME_free(name); - if (name_issuer) - X509_NAME_free(name_issuer); - return x509; - -#undef SERIAL_NUMBER_SIZE -} - -/** List of ciphers that servers should select from when the client might be - * claiming extra unsupported ciphers in order to avoid fingerprinting. */ -static const char SERVER_CIPHER_LIST[] = -#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 - /* This one can never actually get selected, since if the client lists it, - * we will assume that the client is honest, and not use this list. - * Nonetheless we list it if it's available, so that the server doesn't - * conclude that it has no valid ciphers if it's running with TLS1.3. - */ - TLS1_3_TXT_AES_128_GCM_SHA256 ":" -#endif - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA; - -/** List of ciphers that servers should select from when we actually have - * our choice of what cipher to use. */ -static const char UNRESTRICTED_SERVER_CIPHER_LIST[] = - /* Here are the TLS 1.3 ciphers we like, in the order we prefer. */ -#ifdef TLS1_3_TXT_AES_256_GCM_SHA384 - TLS1_3_TXT_AES_256_GCM_SHA384 ":" -#endif -#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256 - TLS1_3_TXT_CHACHA20_POLY1305_SHA256 ":" -#endif -#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 - TLS1_3_TXT_AES_128_GCM_SHA256 ":" -#endif -#ifdef TLS1_3_TXT_AES_128_CCM_SHA256 - TLS1_3_TXT_AES_128_CCM_SHA256 ":" -#endif - - /* This list is autogenerated with the gen_server_ciphers.py script; - * don't hand-edit it. */ -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 - TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 - TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA - TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA - TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 - TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 - TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_CCM - TLS1_TXT_DHE_RSA_WITH_AES_256_CCM ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_CCM - TLS1_TXT_DHE_RSA_WITH_AES_128_CCM ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 ":" -#endif - /* Required */ - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" - /* Required */ - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" -#ifdef TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 - TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305 - TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305 -#endif - ; - -/* Note: to set up your own private testing network with link crypto - * disabled, set your Tors' cipher list to - * (SSL3_TXT_RSA_NULL_SHA). If you do this, you won't be able to communicate - * with any of the "real" Tors, though. */ - -#define CIPHER(id, name) name ":" -#define XCIPHER(id, name) -/** List of ciphers that clients should advertise, omitting items that - * our OpenSSL doesn't know about. */ -static const char CLIENT_CIPHER_LIST[] = -#include "ciphers.inc" - /* Tell it not to use SSLv2 ciphers, so that it can select an SSLv3 version - * of any cipher we say. */ - "!SSLv2" - ; -#undef CIPHER -#undef XCIPHER - -/** Free all storage held in <b>cert</b> */ -void -tor_x509_cert_free_(tor_x509_cert_t *cert) -{ - if (! cert) - return; - if (cert->cert) - X509_free(cert->cert); - tor_free(cert->encoded); - memwipe(cert, 0x03, sizeof(*cert)); - /* LCOV_EXCL_BR_START since cert will never be NULL here */ - tor_free(cert); - /* LCOV_EXCL_BR_STOP */ -} - -/** - * Allocate a new tor_x509_cert_t to hold the certificate "x509_cert". - * - * Steals a reference to x509_cert. - */ -MOCK_IMPL(STATIC tor_x509_cert_t *, -tor_x509_cert_new,(X509 *x509_cert)) -{ - tor_x509_cert_t *cert; - EVP_PKEY *pkey; - RSA *rsa; - int length; - unsigned char *buf = NULL; - - if (!x509_cert) - return NULL; - - length = i2d_X509(x509_cert, &buf); - cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); - if (length <= 0 || buf == NULL) { - goto err; - } - cert->encoded_len = (size_t) length; - cert->encoded = tor_malloc(length); - memcpy(cert->encoded, buf, length); - OPENSSL_free(buf); - - cert->cert = x509_cert; - - crypto_common_digests(&cert->cert_digests, - (char*)cert->encoded, cert->encoded_len); - - if ((pkey = X509_get_pubkey(x509_cert)) && - (rsa = EVP_PKEY_get1_RSA(pkey))) { - crypto_pk_t *pk = crypto_new_pk_from_rsa_(rsa); - if (crypto_pk_get_common_digests(pk, &cert->pkey_digests) < 0) { - crypto_pk_free(pk); - EVP_PKEY_free(pkey); - goto err; - } - - cert->pkey_digests_set = 1; - crypto_pk_free(pk); - EVP_PKEY_free(pkey); - } - - return cert; - err: - /* LCOV_EXCL_START for the same reason as the exclusion above */ - tor_free(cert); - log_err(LD_CRYPTO, "Couldn't wrap encoded X509 certificate."); - X509_free(x509_cert); - return NULL; - /* LCOV_EXCL_STOP */ -} - -/** Return a new copy of <b>cert</b>. */ -tor_x509_cert_t * -tor_x509_cert_dup(const tor_x509_cert_t *cert) -{ - tor_assert(cert); - X509 *x509 = cert->cert; - return tor_x509_cert_new(X509_dup(x509)); -} - -/** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>, - * from a <b>certificate</b>. Return a newly allocated tor_x509_cert_t on - * success and NULL on failure. */ -tor_x509_cert_t * -tor_x509_cert_decode(const uint8_t *certificate, size_t certificate_len) -{ - X509 *x509; - const unsigned char *cp = (const unsigned char *)certificate; - tor_x509_cert_t *newcert; - tor_assert(certificate); - check_no_tls_errors(); - - if (certificate_len > INT_MAX) - goto err; - - x509 = d2i_X509(NULL, &cp, (int)certificate_len); - - if (!x509) - goto err; /* Couldn't decode */ - if (cp - certificate != (int)certificate_len) { - X509_free(x509); - goto err; /* Didn't use all the bytes */ - } - newcert = tor_x509_cert_new(x509); - if (!newcert) { - goto err; - } - if (newcert->encoded_len != certificate_len || - fast_memneq(newcert->encoded, certificate, certificate_len)) { - /* Cert wasn't in DER */ - tor_x509_cert_free(newcert); - goto err; - } - return newcert; - err: - tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "decoding a certificate"); - return NULL; -} - -/** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER - * representation and length, respectively. */ -void -tor_x509_cert_get_der(const tor_x509_cert_t *cert, - const uint8_t **encoded_out, size_t *size_out) -{ - tor_assert(cert); - tor_assert(encoded_out); - tor_assert(size_out); - *encoded_out = cert->encoded; - *size_out = cert->encoded_len; -} - -/** Return a set of digests for the public key in <b>cert</b>, or NULL if this - * cert's public key is not one we know how to take the digest of. */ -const common_digests_t * -tor_x509_cert_get_id_digests(const tor_x509_cert_t *cert) -{ - if (cert->pkey_digests_set) - return &cert->pkey_digests; - else - return NULL; -} - -/** Return a set of digests for the public key in <b>cert</b>. */ -const common_digests_t * -tor_x509_cert_get_cert_digests(const tor_x509_cert_t *cert) -{ - return &cert->cert_digests; -} - -/** Remove a reference to <b>ctx</b>, and free it if it has no more - * references. */ -static void -tor_tls_context_decref(tor_tls_context_t *ctx) -{ - tor_assert(ctx); - if (--ctx->refcnt == 0) { - SSL_CTX_free(ctx->ctx); - tor_x509_cert_free(ctx->my_link_cert); - tor_x509_cert_free(ctx->my_id_cert); - tor_x509_cert_free(ctx->my_auth_cert); - crypto_pk_free(ctx->link_key); - crypto_pk_free(ctx->auth_key); - /* LCOV_EXCL_BR_START since ctx will never be NULL here */ - tor_free(ctx); - /* LCOV_EXCL_BR_STOP */ - } -} - -/** Set *<b>link_cert_out</b> and *<b>id_cert_out</b> to the link certificate - * and ID certificate that we're currently using for our V3 in-protocol - * handshake's certificate chain. If <b>server</b> is true, provide the certs - * that we use in server mode (auth, ID); otherwise, provide the certs that we - * use in client mode. (link, ID) */ -int -tor_tls_get_my_certs(int server, - const tor_x509_cert_t **link_cert_out, - const tor_x509_cert_t **id_cert_out) -{ - tor_tls_context_t *ctx = server ? server_tls_context : client_tls_context; - if (! ctx) - return -1; - if (link_cert_out) - *link_cert_out = server ? ctx->my_link_cert : ctx->my_auth_cert; - if (id_cert_out) - *id_cert_out = ctx->my_id_cert; - return 0; -} - -/** - * Return the authentication key that we use to authenticate ourselves as a - * client in the V3 in-protocol handshake. - */ -crypto_pk_t * -tor_tls_get_my_client_auth_key(void) -{ - if (! client_tls_context) - return NULL; - return client_tls_context->auth_key; -} - -/** - * Return a newly allocated copy of the public key that a certificate - * certifies. Watch out! This returns NULL if the cert's key is not RSA. - */ -crypto_pk_t * -tor_tls_cert_get_key(tor_x509_cert_t *cert) -{ - crypto_pk_t *result = NULL; - EVP_PKEY *pkey = X509_get_pubkey(cert->cert); - RSA *rsa; - if (!pkey) - return NULL; - rsa = EVP_PKEY_get1_RSA(pkey); - if (!rsa) { - EVP_PKEY_free(pkey); - return NULL; - } - result = crypto_new_pk_from_rsa_(rsa); - EVP_PKEY_free(pkey); - return result; -} - -/** Return true iff the other side of <b>tls</b> has authenticated to us, and - * the key certified in <b>cert</b> is the same as the key they used to do it. - */ -MOCK_IMPL(int, -tor_tls_cert_matches_key,(const tor_tls_t *tls, const tor_x509_cert_t *cert)) -{ - tor_x509_cert_t *peer = tor_tls_get_peer_cert((tor_tls_t *)tls); - if (!peer) - return 0; - - X509 *peercert = peer->cert; - EVP_PKEY *link_key = NULL, *cert_key = NULL; - int result; - - link_key = X509_get_pubkey(peercert); - cert_key = X509_get_pubkey(cert->cert); - - result = link_key && cert_key && EVP_PKEY_cmp(cert_key, link_key) == 1; - - tor_x509_cert_free(peer); - if (link_key) - EVP_PKEY_free(link_key); - if (cert_key) - EVP_PKEY_free(cert_key); - - return result; -} - -/** Check whether <b>cert</b> is well-formed, currently live, and correctly - * signed by the public key in <b>signing_cert</b>. If <b>check_rsa_1024</b>, - * make sure that it has an RSA key with 1024 bits; otherwise, just check that - * the key is long enough. Return 1 if the cert is good, and 0 if it's bad or - * we couldn't check it. */ -int -tor_tls_cert_is_valid(int severity, - const tor_x509_cert_t *cert, - const tor_x509_cert_t *signing_cert, - time_t now, - int check_rsa_1024) -{ - check_no_tls_errors(); - EVP_PKEY *cert_key; - int r, key_ok = 0; - - if (!signing_cert || !cert) - goto bad; - - EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert); - if (!signing_key) - goto bad; - r = X509_verify(cert->cert, signing_key); - EVP_PKEY_free(signing_key); - if (r <= 0) - goto bad; - - /* okay, the signature checked out right. Now let's check the check the - * lifetime. */ - if (check_cert_lifetime_internal(severity, cert->cert, now, - 48*60*60, 30*24*60*60) < 0) - goto bad; - - cert_key = X509_get_pubkey(cert->cert); - if (check_rsa_1024 && cert_key) { - RSA *rsa = EVP_PKEY_get1_RSA(cert_key); -#ifdef OPENSSL_1_1_API - if (rsa && RSA_bits(rsa) == 1024) -#else - if (rsa && BN_num_bits(rsa->n) == 1024) -#endif - key_ok = 1; - if (rsa) - RSA_free(rsa); - } else if (cert_key) { - int min_bits = 1024; -#ifdef EVP_PKEY_EC - if (EVP_PKEY_base_id(cert_key) == EVP_PKEY_EC) - min_bits = 128; -#endif - if (EVP_PKEY_bits(cert_key) >= min_bits) - key_ok = 1; - } - EVP_PKEY_free(cert_key); - if (!key_ok) - goto bad; - - /* XXXX compare DNs or anything? */ - - return 1; - bad: - tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "checking a certificate"); - return 0; -} - -/** Increase the reference count of <b>ctx</b>. */ -static void -tor_tls_context_incref(tor_tls_context_t *ctx) -{ - ++ctx->refcnt; -} - -/** Create new global client and server TLS contexts. - * - * If <b>server_identity</b> is NULL, this will not generate a server - * TLS context. If TOR_TLS_CTX_IS_PUBLIC_SERVER is set in <b>flags</b>, use - * the same TLS context for incoming and outgoing connections, and - * ignore <b>client_identity</b>. If one of TOR_TLS_CTX_USE_ECDHE_P{224,256} - * is set in <b>flags</b>, use that ECDHE group if possible; otherwise use - * the default ECDHE group. */ -int -tor_tls_context_init(unsigned flags, - crypto_pk_t *client_identity, - crypto_pk_t *server_identity, - unsigned int key_lifetime) -{ - int rv1 = 0; - int rv2 = 0; - const int is_public_server = flags & TOR_TLS_CTX_IS_PUBLIC_SERVER; - check_no_tls_errors(); - - if (is_public_server) { - tor_tls_context_t *new_ctx; - tor_tls_context_t *old_ctx; - - tor_assert(server_identity != NULL); - - rv1 = tor_tls_context_init_one(&server_tls_context, - server_identity, - key_lifetime, flags, 0); - - if (rv1 >= 0) { - new_ctx = server_tls_context; - tor_tls_context_incref(new_ctx); - old_ctx = client_tls_context; - client_tls_context = new_ctx; - - if (old_ctx != NULL) { - tor_tls_context_decref(old_ctx); - } - } - } else { - if (server_identity != NULL) { - rv1 = tor_tls_context_init_one(&server_tls_context, - server_identity, - key_lifetime, - flags, - 0); - } else { - tor_tls_context_t *old_ctx = server_tls_context; - server_tls_context = NULL; - - if (old_ctx != NULL) { - tor_tls_context_decref(old_ctx); - } - } - - rv2 = tor_tls_context_init_one(&client_tls_context, - client_identity, - key_lifetime, - flags, - 1); - } - - tls_log_errors(NULL, LOG_WARN, LD_CRYPTO, "constructing a TLS context"); - return MIN(rv1, rv2); -} - -/** Create a new global TLS context. - * - * You can call this function multiple times. Each time you call it, - * it generates new certificates; all new connections will use - * the new SSL context. - */ -STATIC int -tor_tls_context_init_one(tor_tls_context_t **ppcontext, - crypto_pk_t *identity, - unsigned int key_lifetime, - unsigned int flags, - int is_client) -{ - tor_tls_context_t *new_ctx = tor_tls_context_new(identity, - key_lifetime, - flags, - is_client); - tor_tls_context_t *old_ctx = *ppcontext; - - if (new_ctx != NULL) { - *ppcontext = new_ctx; - - /* Free the old context if one existed. */ - if (old_ctx != NULL) { - /* This is safe even if there are open connections: we reference- - * count tor_tls_context_t objects. */ - tor_tls_context_decref(old_ctx); - } - } - - return ((new_ctx != NULL) ? 0 : -1); -} - -/** The group we should use for ecdhe when none was selected. */ -#define NID_tor_default_ecdhe_group NID_X9_62_prime256v1 - -#define RSA_LINK_KEY_BITS 2048 - -/** Create a new TLS context for use with Tor TLS handshakes. - * <b>identity</b> should be set to the identity key used to sign the - * certificate. - */ -STATIC tor_tls_context_t * -tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, - unsigned flags, int is_client) -{ - crypto_pk_t *rsa = NULL, *rsa_auth = NULL; - EVP_PKEY *pkey = NULL; - tor_tls_context_t *result = NULL; - X509 *cert = NULL, *idcert = NULL, *authcert = NULL; - char *nickname = NULL, *nn2 = NULL; - - tor_tls_init(); - nickname = crypto_random_hostname(8, 20, "www.", ".net"); -#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE - nn2 = crypto_random_hostname(8, 20, "www.", ".net"); -#else - nn2 = crypto_random_hostname(8, 20, "www.", ".com"); -#endif - - /* Generate short-term RSA key for use with TLS. */ - if (!(rsa = crypto_pk_new())) - goto error; - if (crypto_pk_generate_key_with_bits(rsa, RSA_LINK_KEY_BITS)<0) - goto error; - if (!is_client) { - /* Generate short-term RSA key for use in the in-protocol ("v3") - * authentication handshake. */ - if (!(rsa_auth = crypto_pk_new())) - goto error; - if (crypto_pk_generate_key(rsa_auth)<0) - goto error; - /* Create a link certificate signed by identity key. */ - cert = tor_tls_create_certificate(rsa, identity, nickname, nn2, - key_lifetime); - /* Create self-signed certificate for identity key. */ - idcert = tor_tls_create_certificate(identity, identity, nn2, nn2, - IDENTITY_CERT_LIFETIME); - /* Create an authentication certificate signed by identity key. */ - authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2, - key_lifetime); - if (!cert || !idcert || !authcert) { - log_warn(LD_CRYPTO, "Error creating certificate"); - goto error; - } - } - - result = tor_malloc_zero(sizeof(tor_tls_context_t)); - result->refcnt = 1; - if (!is_client) { - result->my_link_cert = tor_x509_cert_new(X509_dup(cert)); - result->my_id_cert = tor_x509_cert_new(X509_dup(idcert)); - result->my_auth_cert = tor_x509_cert_new(X509_dup(authcert)); - if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert) - goto error; - result->link_key = crypto_pk_dup_key(rsa); - result->auth_key = crypto_pk_dup_key(rsa_auth); - } - -#if 0 - /* Tell OpenSSL to only use TLS1. This may have subtly different results - * from SSLv23_method() with SSLv2 and SSLv3 disabled, so we need to do some - * investigation before we consider adjusting it. It should be compatible - * with existing Tors. */ - if (!(result->ctx = SSL_CTX_new(TLSv1_method()))) - goto error; -#endif /* 0 */ - - /* Tell OpenSSL to use TLS 1.0 or later but not SSL2 or SSL3. */ -#ifdef HAVE_TLS_METHOD - if (!(result->ctx = SSL_CTX_new(TLS_method()))) - goto error; -#else - if (!(result->ctx = SSL_CTX_new(SSLv23_method()))) - goto error; -#endif /* defined(HAVE_TLS_METHOD) */ - -#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL - /* Level 1 re-enables RSA1024 and DH1024 for compatibility with old tors */ - SSL_CTX_set_security_level(result->ctx, 1); -#endif - - SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2); - SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3); - - /* Prefer the server's ordering of ciphers: the client's ordering has - * historically been chosen for fingerprinting resistance. */ - SSL_CTX_set_options(result->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - - /* Disable TLS tickets if they're supported. We never want to use them; - * using them can make our perfect forward secrecy a little worse, *and* - * create an opportunity to fingerprint us (since it's unusual to use them - * with TLS sessions turned off). - * - * In 0.2.4, clients advertise support for them though, to avoid a TLS - * distinguishability vector. This can give us worse PFS, though, if we - * get a server that doesn't set SSL_OP_NO_TICKET. With luck, there will - * be few such servers by the time 0.2.4 is more stable. - */ -#ifdef SSL_OP_NO_TICKET - if (! is_client) { - SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET); - } -#endif - - SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE); - SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_ECDH_USE); - -#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - SSL_CTX_set_options(result->ctx, - SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); -#endif - /* Yes, we know what we are doing here. No, we do not treat a renegotiation - * as authenticating any earlier-received data. - */ - { - SSL_CTX_set_options(result->ctx, - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); - } - - /* Don't actually allow compression; it uses RAM and time, it makes TLS - * vulnerable to CRIME-style attacks, and most of the data we transmit over - * TLS is encrypted (and therefore uncompressible) anyway. */ -#ifdef SSL_OP_NO_COMPRESSION - SSL_CTX_set_options(result->ctx, SSL_OP_NO_COMPRESSION); -#endif -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) -#ifndef OPENSSL_NO_COMP - if (result->ctx->comp_methods) - result->ctx->comp_methods = NULL; -#endif -#endif /* OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) */ - -#ifdef SSL_MODE_RELEASE_BUFFERS - SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS); -#endif - if (! is_client) { - if (cert && !SSL_CTX_use_certificate(result->ctx,cert)) - goto error; - X509_free(cert); /* We just added a reference to cert. */ - cert=NULL; - if (idcert) { - X509_STORE *s = SSL_CTX_get_cert_store(result->ctx); - tor_assert(s); - X509_STORE_add_cert(s, idcert); - X509_free(idcert); /* The context now owns the reference to idcert */ - idcert = NULL; - } - } - SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF); - if (!is_client) { - tor_assert(rsa); - if (!(pkey = crypto_pk_get_evp_pkey_(rsa,1))) - goto error; - if (!SSL_CTX_use_PrivateKey(result->ctx, pkey)) - goto error; - EVP_PKEY_free(pkey); - pkey = NULL; - if (!SSL_CTX_check_private_key(result->ctx)) - goto error; - } - { - crypto_dh_t *dh = crypto_dh_new(DH_TYPE_TLS); - tor_assert(dh); - SSL_CTX_set_tmp_dh(result->ctx, crypto_dh_get_dh_(dh)); - crypto_dh_free(dh); - } - if (! is_client) { - int nid; - EC_KEY *ec_key; - if (flags & TOR_TLS_CTX_USE_ECDHE_P224) - nid = NID_secp224r1; - else if (flags & TOR_TLS_CTX_USE_ECDHE_P256) - nid = NID_X9_62_prime256v1; - else - nid = NID_tor_default_ecdhe_group; - /* Use P-256 for ECDHE. */ - ec_key = EC_KEY_new_by_curve_name(nid); - if (ec_key != NULL) /*XXXX Handle errors? */ - SSL_CTX_set_tmp_ecdh(result->ctx, ec_key); - EC_KEY_free(ec_key); - } - SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, - always_accept_verify_cb); - /* let us realloc bufs that we're writing from */ - SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - - if (rsa) - crypto_pk_free(rsa); - if (rsa_auth) - crypto_pk_free(rsa_auth); - X509_free(authcert); - tor_free(nickname); - tor_free(nn2); - return result; - - error: - tls_log_errors(NULL, LOG_WARN, LD_NET, "creating TLS context"); - tor_free(nickname); - tor_free(nn2); - if (pkey) - EVP_PKEY_free(pkey); - if (rsa) - crypto_pk_free(rsa); - if (rsa_auth) - crypto_pk_free(rsa_auth); - if (result) - tor_tls_context_decref(result); - if (cert) - X509_free(cert); - if (idcert) - X509_free(idcert); - if (authcert) - X509_free(authcert); - return NULL; -} - -/** Invoked when a TLS state changes: log the change at severity 'debug' */ -STATIC void -tor_tls_debug_state_callback(const SSL *ssl, int type, int val) -{ - /* LCOV_EXCL_START since this depends on whether debug is captured or not */ - log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].", - ssl, SSL_state_string_long(ssl), type, val); - /* LCOV_EXCL_STOP */ -} - -/* Return the name of the negotiated ciphersuite in use on <b>tls</b> */ -const char * -tor_tls_get_ciphersuite_name(tor_tls_t *tls) -{ - return SSL_get_cipher(tls->ssl); -} - -/* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to - * 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers - * that it claims to support. We'll prune this list to remove the ciphers - * *we* don't recognize. */ -STATIC uint16_t v2_cipher_list[] = { - 0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */ - 0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */ - 0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */ - 0x0038, /* TLS1_TXT_DHE_DSS_WITH_AES_256_SHA */ - 0xc00f, /* TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA */ - 0xc005, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA */ - 0x0035, /* TLS1_TXT_RSA_WITH_AES_256_SHA */ - 0xc007, /* TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA */ - 0xc009, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */ - 0xc011, /* TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA */ - 0xc013, /* TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA */ - 0x0033, /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA */ - 0x0032, /* TLS1_TXT_DHE_DSS_WITH_AES_128_SHA */ - 0xc00c, /* TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA */ - 0xc00e, /* TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA */ - 0xc002, /* TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA */ - 0xc004, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA */ - 0x0004, /* SSL3_TXT_RSA_RC4_128_MD5 */ - 0x0005, /* SSL3_TXT_RSA_RC4_128_SHA */ - 0x002f, /* TLS1_TXT_RSA_WITH_AES_128_SHA */ - 0xc008, /* TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA */ - 0xc012, /* TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA */ - 0x0016, /* SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA */ - 0x0013, /* SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA */ - 0xc00d, /* TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA */ - 0xc003, /* TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA */ - 0xfeff, /* SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA */ - 0x000a, /* SSL3_TXT_RSA_DES_192_CBC3_SHA */ - 0 -}; -/** Have we removed the unrecognized ciphers from v2_cipher_list yet? */ -static int v2_cipher_list_pruned = 0; - -/** Return 0 if <b>m</b> does not support the cipher with ID <b>cipher</b>; - * return 1 if it does support it, or if we have no way to tell. */ -STATIC int -find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher) -{ - const SSL_CIPHER *c; -#ifdef HAVE_SSL_CIPHER_FIND - (void) m; - { - unsigned char cipherid[3]; - tor_assert(ssl); - set_uint16(cipherid, htons(cipher)); - cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting - * with a two-byte 'cipherid', it may look for a v2 - * cipher with the appropriate 3 bytes. */ - c = SSL_CIPHER_find((SSL*)ssl, cipherid); - if (c) - tor_assert((SSL_CIPHER_get_id(c) & 0xffff) == cipher); - return c != NULL; - } -#else /* !(defined(HAVE_SSL_CIPHER_FIND)) */ - -# if defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) - if (m && m->get_cipher_by_char) { - unsigned char cipherid[3]; - set_uint16(cipherid, htons(cipher)); - cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting - * with a two-byte 'cipherid', it may look for a v2 - * cipher with the appropriate 3 bytes. */ - c = m->get_cipher_by_char(cipherid); - if (c) - tor_assert((c->id & 0xffff) == cipher); - return c != NULL; - } -#endif /* defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) */ -# ifndef OPENSSL_1_1_API - if (m && m->get_cipher && m->num_ciphers) { - /* It would seem that some of the "let's-clean-up-openssl" forks have - * removed the get_cipher_by_char function. Okay, so now you get a - * quadratic search. - */ - int i; - for (i = 0; i < m->num_ciphers(); ++i) { - c = m->get_cipher(i); - if (c && (c->id & 0xffff) == cipher) { - return 1; - } - } - return 0; - } -#endif /* !defined(OPENSSL_1_1_API) */ - (void) ssl; - (void) m; - (void) cipher; - return 1; /* No way to search */ -#endif /* defined(HAVE_SSL_CIPHER_FIND) */ -} - -/** Remove from v2_cipher_list every cipher that we don't support, so that - * comparing v2_cipher_list to a client's cipher list will give a sensible - * result. */ -static void -prune_v2_cipher_list(const SSL *ssl) -{ - uint16_t *inp, *outp; -#ifdef HAVE_TLS_METHOD - const SSL_METHOD *m = TLS_method(); -#else - const SSL_METHOD *m = SSLv23_method(); -#endif - - inp = outp = v2_cipher_list; - while (*inp) { - if (find_cipher_by_id(ssl, m, *inp)) { - *outp++ = *inp++; - } else { - inp++; - } - } - *outp = 0; - - v2_cipher_list_pruned = 1; -} - -/** Examine the client cipher list in <b>ssl</b>, and determine what kind of - * client it is. Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2, - * CIPHERS_UNRESTRICTED. - **/ -STATIC int -tor_tls_classify_client_ciphers(const SSL *ssl, - STACK_OF(SSL_CIPHER) *peer_ciphers) -{ - int i, res; - tor_tls_t *tor_tls; - if (PREDICT_UNLIKELY(!v2_cipher_list_pruned)) - prune_v2_cipher_list(ssl); - - tor_tls = tor_tls_get_by_ssl(ssl); - if (tor_tls && tor_tls->client_cipher_list_type) - return tor_tls->client_cipher_list_type; - - /* If we reached this point, we just got a client hello. See if there is - * a cipher list. */ - if (!peer_ciphers) { - log_info(LD_NET, "No ciphers on session"); - res = CIPHERS_ERR; - goto done; - } - /* Now we need to see if there are any ciphers whose presence means we're - * dealing with an updated Tor. */ - for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - const char *ciphername = SSL_CIPHER_get_name(cipher); - if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) && - strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) && - strcmp(ciphername, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) && - strcmp(ciphername, "(NONE)")) { - log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername); - // return 1; - goto v2_or_higher; - } - } - res = CIPHERS_V1; - goto done; - v2_or_higher: - { - const uint16_t *v2_cipher = v2_cipher_list; - for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - uint16_t id = SSL_CIPHER_get_id(cipher) & 0xffff; - if (id == 0x00ff) /* extended renegotiation indicator. */ - continue; - if (!id || id != *v2_cipher) { - res = CIPHERS_UNRESTRICTED; - goto dump_ciphers; - } - ++v2_cipher; - } - if (*v2_cipher != 0) { - res = CIPHERS_UNRESTRICTED; - goto dump_ciphers; - } - res = CIPHERS_V2; - } - - dump_ciphers: - { - smartlist_t *elts = smartlist_new(); - char *s; - for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - const char *ciphername = SSL_CIPHER_get_name(cipher); - smartlist_add(elts, (char*)ciphername); - } - s = smartlist_join_strings(elts, ":", 0, NULL); - log_debug(LD_NET, "Got a %s V2/V3 cipher list from %s. It is: '%s'", - (res == CIPHERS_V2) ? "fictitious" : "real", ADDR(tor_tls), s); - tor_free(s); - smartlist_free(elts); - } - done: - if (tor_tls) - return tor_tls->client_cipher_list_type = res; - - return res; -} - -/** Return true iff the cipher list suggested by the client for <b>ssl</b> is - * a list that indicates that the client knows how to do the v2 TLS connection - * handshake. */ -STATIC int -tor_tls_client_is_using_v2_ciphers(const SSL *ssl) -{ - STACK_OF(SSL_CIPHER) *ciphers; -#ifdef HAVE_SSL_GET_CLIENT_CIPHERS - ciphers = SSL_get_client_ciphers(ssl); -#else - SSL_SESSION *session; - if (!(session = SSL_get_session((SSL *)ssl))) { - log_info(LD_NET, "No session on TLS?"); - return CIPHERS_ERR; - } - ciphers = session->ciphers; -#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */ - - return tor_tls_classify_client_ciphers(ssl, ciphers) >= CIPHERS_V2; -} - -/** Invoked when we're accepting a connection on <b>ssl</b>, and the connection - * changes state. We use this: - * <ul><li>To alter the state of the handshake partway through, so we - * do not send or request extra certificates in v2 handshakes.</li> - * <li>To detect renegotiation</li></ul> - */ -STATIC void -tor_tls_server_info_callback(const SSL *ssl, int type, int val) -{ - tor_tls_t *tls; - (void) val; - - IF_BUG_ONCE(ssl == NULL) { - return; // LCOV_EXCL_LINE - } - - tor_tls_debug_state_callback(ssl, type, val); - - if (type != SSL_CB_ACCEPT_LOOP) - return; - - OSSL_HANDSHAKE_STATE ssl_state = SSL_get_state(ssl); - if (! STATE_IS_SW_SERVER_HELLO(ssl_state)) - return; - tls = tor_tls_get_by_ssl(ssl); - if (tls) { - /* Check whether we're watching for renegotiates. If so, this is one! */ - if (tls->negotiated_callback) - tls->got_renegotiate = 1; - if (tls->server_handshake_count < 127) /*avoid any overflow possibility*/ - ++tls->server_handshake_count; - } else { - log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); - return; - } - - /* Now check the cipher list. */ - if (tor_tls_client_is_using_v2_ciphers(ssl)) { - if (tls->wasV2Handshake) - return; /* We already turned this stuff off for the first handshake; - * This is a renegotiation. */ - - /* Yes, we're casting away the const from ssl. This is very naughty of us. - * Let's hope openssl doesn't notice! */ - - /* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */ - SSL_set_mode((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN); - /* Don't send a hello request. */ - SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL); - - if (tls) { - tls->wasV2Handshake = 1; - } else { - /* LCOV_EXCL_START this line is not reachable */ - log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); - /* LCOV_EXCL_STOP */ - } - } -} - -/** Callback to get invoked on a server after we've read the list of ciphers - * the client supports, but before we pick our own ciphersuite. - * - * We can't abuse an info_cb for this, since by the time one of the - * client_hello info_cbs is called, we've already picked which ciphersuite to - * use. - * - * Technically, this function is an abuse of this callback, since the point of - * a session_secret_cb is to try to set up and/or verify a shared-secret for - * authentication on the fly. But as long as we return 0, we won't actually be - * setting up a shared secret, and all will be fine. - */ -STATIC int -tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len, - STACK_OF(SSL_CIPHER) *peer_ciphers, - CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher, - void *arg) -{ - (void) secret; - (void) secret_len; - (void) peer_ciphers; - (void) cipher; - (void) arg; - - if (tor_tls_classify_client_ciphers(ssl, peer_ciphers) == - CIPHERS_UNRESTRICTED) { - SSL_set_cipher_list(ssl, UNRESTRICTED_SERVER_CIPHER_LIST); - } - - SSL_set_session_secret_cb(ssl, NULL, NULL); - - return 0; -} -static void -tor_tls_setup_session_secret_cb(tor_tls_t *tls) -{ - SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL); -} - -/** Create a new TLS object from a file descriptor, and a flag to - * determine whether it is functioning as a server. - */ -tor_tls_t * -tor_tls_new(int sock, int isServer) -{ - BIO *bio = NULL; - tor_tls_t *result = tor_malloc_zero(sizeof(tor_tls_t)); - tor_tls_context_t *context = isServer ? server_tls_context : - client_tls_context; - result->magic = TOR_TLS_MAGIC; - - check_no_tls_errors(); - tor_assert(context); /* make sure somebody made it first */ - if (!(result->ssl = SSL_new(context->ctx))) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "creating SSL object"); - tor_free(result); - goto err; - } - -#ifdef SSL_set_tlsext_host_name - /* Browsers use the TLS hostname extension, so we should too. */ - if (!isServer) { - char *fake_hostname = crypto_random_hostname(4,25, "www.",".com"); - SSL_set_tlsext_host_name(result->ssl, fake_hostname); - tor_free(fake_hostname); - } -#endif /* defined(SSL_set_tlsext_host_name) */ - - if (!SSL_set_cipher_list(result->ssl, - isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "setting ciphers"); -#ifdef SSL_set_tlsext_host_name - SSL_set_tlsext_host_name(result->ssl, NULL); -#endif - SSL_free(result->ssl); - tor_free(result); - goto err; - } - result->socket = sock; - bio = BIO_new_socket(sock, BIO_NOCLOSE); - if (! bio) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "opening BIO"); -#ifdef SSL_set_tlsext_host_name - SSL_set_tlsext_host_name(result->ssl, NULL); -#endif - SSL_free(result->ssl); - tor_free(result); - goto err; - } - { - int set_worked = - SSL_set_ex_data(result->ssl, tor_tls_object_ex_data_index, result); - if (!set_worked) { - log_warn(LD_BUG, - "Couldn't set the tls for an SSL*; connection will fail"); - } - } - SSL_set_bio(result->ssl, bio, bio); - tor_tls_context_incref(context); - result->context = context; - result->state = TOR_TLS_ST_HANDSHAKE; - result->isServer = isServer; - result->wantwrite_n = 0; - result->last_write_count = (unsigned long) BIO_number_written(bio); - result->last_read_count = (unsigned long) BIO_number_read(bio); - if (result->last_write_count || result->last_read_count) { - log_warn(LD_NET, "Newly created BIO has read count %lu, write count %lu", - result->last_read_count, result->last_write_count); - } - if (isServer) { - SSL_set_info_callback(result->ssl, tor_tls_server_info_callback); - } else { - SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback); - } - - if (isServer) - tor_tls_setup_session_secret_cb(result); - - goto done; - err: - result = NULL; - done: - /* Not expected to get called. */ - tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object"); - return result; -} - -/** Make future log messages about <b>tls</b> display the address - * <b>address</b>. - */ -void -tor_tls_set_logged_address(tor_tls_t *tls, const char *address) -{ - tor_assert(tls); - tor_free(tls->address); - tls->address = tor_strdup(address); -} - -/** Set <b>cb</b> to be called with argument <b>arg</b> whenever <b>tls</b> - * next gets a client-side renegotiate in the middle of a read. Do not - * invoke this function until <em>after</em> initial handshaking is done! - */ -void -tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg) -{ - tls->negotiated_callback = cb; - tls->callback_arg = arg; - tls->got_renegotiate = 0; - if (cb) { - SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback); - } else { - SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback); - } -} - -/** If this version of openssl requires it, turn on renegotiation on - * <b>tls</b>. - */ -void -tor_tls_unblock_renegotiation(tor_tls_t *tls) -{ - /* Yes, we know what we are doing here. No, we do not treat a renegotiation - * as authenticating any earlier-received data. */ - SSL_set_options(tls->ssl, - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); -} - -/** If this version of openssl supports it, turn off renegotiation on - * <b>tls</b>. (Our protocol never requires this for security, but it's nice - * to use belt-and-suspenders here.) - */ -void -tor_tls_block_renegotiation(tor_tls_t *tls) -{ -#ifdef SUPPORT_UNSAFE_RENEGOTIATION_FLAG - tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; -#else - (void) tls; -#endif -} - -/** Assert that the flags that allow legacy renegotiation are still set */ -void -tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls) -{ -#if defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && \ - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION != 0 - long options = SSL_get_options(tls->ssl); - tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)); -#else - (void) tls; -#endif /* defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && ... */ -} - -/** Return whether this tls initiated the connect (client) or - * received it (server). */ -int -tor_tls_is_server(tor_tls_t *tls) -{ - tor_assert(tls); - return tls->isServer; -} - -/** Release resources associated with a TLS object. Does not close the - * underlying file descriptor. - */ -void -tor_tls_free_(tor_tls_t *tls) -{ - if (!tls) - return; - tor_assert(tls->ssl); - { - size_t r,w; - tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */ - } -#ifdef SSL_set_tlsext_host_name - SSL_set_tlsext_host_name(tls->ssl, NULL); -#endif - SSL_free(tls->ssl); - tls->ssl = NULL; - tls->negotiated_callback = NULL; - if (tls->context) - tor_tls_context_decref(tls->context); - tor_free(tls->address); - tls->magic = 0x99999999; - tor_free(tls); -} - -/** Underlying function for TLS reading. Reads up to <b>len</b> - * characters from <b>tls</b> into <b>cp</b>. On success, returns the - * number of characters read. On failure, returns TOR_TLS_ERROR, - * TOR_TLS_CLOSE, TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE. - */ -MOCK_IMPL(int, -tor_tls_read,(tor_tls_t *tls, char *cp, size_t len)) -{ - int r, err; - tor_assert(tls); - tor_assert(tls->ssl); - tor_assert(tls->state == TOR_TLS_ST_OPEN); - tor_assert(len<INT_MAX); - r = SSL_read(tls->ssl, cp, (int)len); - if (r > 0) { - if (tls->got_renegotiate) { - /* Renegotiation happened! */ - log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls)); - if (tls->negotiated_callback) - tls->negotiated_callback(tls, tls->callback_arg); - tls->got_renegotiate = 0; - } - return r; - } - err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET); - if (err == TOR_TLS_ZERORETURN_ || err == TOR_TLS_CLOSE) { - log_debug(LD_NET,"read returned r=%d; TLS is closed",r); - tls->state = TOR_TLS_ST_CLOSED; - return TOR_TLS_CLOSE; - } else { - tor_assert(err != TOR_TLS_DONE); - log_debug(LD_NET,"read returned r=%d, err=%d",r,err); - return err; - } -} - -/** Total number of bytes that we've used TLS to send. Used to track TLS - * overhead. */ -STATIC uint64_t total_bytes_written_over_tls = 0; -/** Total number of bytes that TLS has put on the network for us. Used to - * track TLS overhead. */ -STATIC uint64_t total_bytes_written_by_tls = 0; - -/** Underlying function for TLS writing. Write up to <b>n</b> - * characters from <b>cp</b> onto <b>tls</b>. On success, returns the - * number of characters written. On failure, returns TOR_TLS_ERROR, - * TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE. - */ -int -tor_tls_write(tor_tls_t *tls, const char *cp, size_t n) -{ - int r, err; - tor_assert(tls); - tor_assert(tls->ssl); - tor_assert(tls->state == TOR_TLS_ST_OPEN); - tor_assert(n < INT_MAX); - if (n == 0) - return 0; - if (tls->wantwrite_n) { - /* if WANTWRITE last time, we must use the _same_ n as before */ - tor_assert(n >= tls->wantwrite_n); - log_debug(LD_NET,"resuming pending-write, (%d to flush, reusing %d)", - (int)n, (int)tls->wantwrite_n); - n = tls->wantwrite_n; - tls->wantwrite_n = 0; - } - r = SSL_write(tls->ssl, cp, (int)n); - err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET); - if (err == TOR_TLS_DONE) { - total_bytes_written_over_tls += r; - return r; - } - if (err == TOR_TLS_WANTWRITE || err == TOR_TLS_WANTREAD) { - tls->wantwrite_n = n; - } - return err; -} - -/** Perform initial handshake on <b>tls</b>. When finished, returns - * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, - * or TOR_TLS_WANTWRITE. - */ -int -tor_tls_handshake(tor_tls_t *tls) -{ - int r; - tor_assert(tls); - tor_assert(tls->ssl); - tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE); - - check_no_tls_errors(); - - OSSL_HANDSHAKE_STATE oldstate = SSL_get_state(tls->ssl); - - if (tls->isServer) { - log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls, - SSL_state_string_long(tls->ssl)); - r = SSL_accept(tls->ssl); - } else { - log_debug(LD_HANDSHAKE, "About to call SSL_connect on %p (%s)", tls, - SSL_state_string_long(tls->ssl)); - r = SSL_connect(tls->ssl); - } - - OSSL_HANDSHAKE_STATE newstate = SSL_get_state(tls->ssl); - - if (oldstate != newstate) - log_debug(LD_HANDSHAKE, "After call, %p was in state %s", - tls, SSL_state_string_long(tls->ssl)); - /* We need to call this here and not earlier, since OpenSSL has a penchant - * for clearing its flags when you say accept or connect. */ - tor_tls_unblock_renegotiation(tls); - r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO, LD_HANDSHAKE); - if (ERR_peek_error() != 0) { - tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN, LD_HANDSHAKE, - "handshaking"); - return TOR_TLS_ERROR_MISC; - } - if (r == TOR_TLS_DONE) { - tls->state = TOR_TLS_ST_OPEN; - return tor_tls_finish_handshake(tls); - } - return r; -} - -/** Perform the final part of the initial TLS handshake on <b>tls</b>. This - * should be called for the first handshake only: it determines whether the v1 - * or the v2 handshake was used, and adjusts things for the renegotiation - * handshake as appropriate. - * - * tor_tls_handshake() calls this on its own; you only need to call this if - * bufferevent is doing the handshake for you. - */ -int -tor_tls_finish_handshake(tor_tls_t *tls) -{ - int r = TOR_TLS_DONE; - check_no_tls_errors(); - if (tls->isServer) { - SSL_set_info_callback(tls->ssl, NULL); - SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb); - SSL_clear_mode(tls->ssl, SSL_MODE_NO_AUTO_CHAIN); - if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) { - /* This check is redundant, but back when we did it in the callback, - * we might have not been able to look up the tor_tls_t if the code - * was buggy. Fixing that. */ - if (!tls->wasV2Handshake) { - log_warn(LD_BUG, "For some reason, wasV2Handshake didn't" - " get set. Fixing that."); - } - tls->wasV2Handshake = 1; - log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting" - " for renegotiation."); - } else { - tls->wasV2Handshake = 0; - } - } else { - /* Client-side */ - tls->wasV2Handshake = 1; - /* XXXX this can move, probably? -NM */ - if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) { - tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers"); - r = TOR_TLS_ERROR_MISC; - } - } - tls_log_errors(NULL, LOG_WARN, LD_NET, "finishing the handshake"); - return r; -} - -/** Shut down an open tls connection <b>tls</b>. When finished, returns - * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, - * or TOR_TLS_WANTWRITE. - */ -int -tor_tls_shutdown(tor_tls_t *tls) -{ - int r, err; - char buf[128]; - tor_assert(tls); - tor_assert(tls->ssl); - check_no_tls_errors(); - - while (1) { - if (tls->state == TOR_TLS_ST_SENTCLOSE) { - /* If we've already called shutdown once to send a close message, - * we read until the other side has closed too. - */ - do { - r = SSL_read(tls->ssl, buf, 128); - } while (r>0); - err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down", - LOG_INFO, LD_NET); - if (err == TOR_TLS_ZERORETURN_) { - tls->state = TOR_TLS_ST_GOTCLOSE; - /* fall through... */ - } else { - return err; - } - } - - r = SSL_shutdown(tls->ssl); - if (r == 1) { - /* If shutdown returns 1, the connection is entirely closed. */ - tls->state = TOR_TLS_ST_CLOSED; - return TOR_TLS_DONE; - } - err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down", - LOG_INFO, LD_NET); - if (err == TOR_TLS_SYSCALL_) { - /* The underlying TCP connection closed while we were shutting down. */ - tls->state = TOR_TLS_ST_CLOSED; - return TOR_TLS_DONE; - } else if (err == TOR_TLS_ZERORETURN_) { - /* The TLS connection says that it sent a shutdown record, but - * isn't done shutting down yet. Make sure that this hasn't - * happened before, then go back to the start of the function - * and try to read. - */ - if (tls->state == TOR_TLS_ST_GOTCLOSE || - tls->state == TOR_TLS_ST_SENTCLOSE) { - log_warn(LD_NET, - "TLS returned \"half-closed\" value while already half-closed"); - return TOR_TLS_ERROR_MISC; - } - tls->state = TOR_TLS_ST_SENTCLOSE; - /* fall through ... */ - } else { - return err; - } - } /* end loop */ -} - -/** Return true iff this TLS connection is authenticated. - */ -int -tor_tls_peer_has_cert(tor_tls_t *tls) -{ - X509 *cert; - cert = SSL_get_peer_certificate(tls->ssl); - tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate"); - if (!cert) - return 0; - X509_free(cert); - return 1; -} - -/** Return a newly allocated copy of the peer certificate, or NULL if there - * isn't one. */ -MOCK_IMPL(tor_x509_cert_t *, -tor_tls_get_peer_cert,(tor_tls_t *tls)) -{ - X509 *cert; - cert = SSL_get_peer_certificate(tls->ssl); - tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate"); - if (!cert) - return NULL; - return tor_x509_cert_new(cert); -} - -/** Return a newly allocated copy of the cerficate we used on the connection, - * or NULL if somehow we didn't use one. */ -MOCK_IMPL(tor_x509_cert_t *, -tor_tls_get_own_cert,(tor_tls_t *tls)) -{ - X509 *cert = SSL_get_certificate(tls->ssl); - tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, - "getting own-connection certificate"); - if (!cert) - return NULL; - /* Fun inconsistency: SSL_get_peer_certificate increments the reference - * count, but SSL_get_certificate does not. */ - X509 *duplicate = X509_dup(cert); - if (BUG(duplicate == NULL)) - return NULL; - return tor_x509_cert_new(duplicate); -} - -/** Warn that a certificate lifetime extends through a certain range. */ -static void -log_cert_lifetime(int severity, const X509 *cert, const char *problem, - time_t now) -{ - BIO *bio = NULL; - BUF_MEM *buf; - char *s1=NULL, *s2=NULL; - char mytime[33]; - struct tm tm; - size_t n; - - if (problem) - tor_log(severity, LD_GENERAL, - "Certificate %s. Either their clock is set wrong, or your clock " - "is wrong.", - problem); - - if (!(bio = BIO_new(BIO_s_mem()))) { - log_warn(LD_GENERAL, "Couldn't allocate BIO!"); goto end; - } - if (!(ASN1_TIME_print(bio, X509_get_notBefore_const(cert)))) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime"); - goto end; - } - BIO_get_mem_ptr(bio, &buf); - s1 = tor_strndup(buf->data, buf->length); - - (void)BIO_reset(bio); - if (!(ASN1_TIME_print(bio, X509_get_notAfter_const(cert)))) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime"); - goto end; - } - BIO_get_mem_ptr(bio, &buf); - s2 = tor_strndup(buf->data, buf->length); - - n = strftime(mytime, 32, "%b %d %H:%M:%S %Y UTC", tor_gmtime_r(&now, &tm)); - if (n > 0) { - tor_log(severity, LD_GENERAL, - "(certificate lifetime runs from %s through %s. Your time is %s.)", - s1,s2,mytime); - } else { - tor_log(severity, LD_GENERAL, - "(certificate lifetime runs from %s through %s. " - "Couldn't get your time.)", - s1, s2); - } - - end: - /* Not expected to get invoked */ - tls_log_errors(NULL, LOG_WARN, LD_NET, "getting certificate lifetime"); - if (bio) - BIO_free(bio); - tor_free(s1); - tor_free(s2); -} - -/** Helper function: try to extract a link certificate and an identity - * certificate from <b>tls</b>, and store them in *<b>cert_out</b> and - * *<b>id_cert_out</b> respectively. Log all messages at level - * <b>severity</b>. - * - * Note that a reference is added to cert_out, so it needs to be - * freed. id_cert_out doesn't. */ -MOCK_IMPL(STATIC void, -try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls, - X509 **cert_out, X509 **id_cert_out)) -{ - X509 *cert = NULL, *id_cert = NULL; - STACK_OF(X509) *chain = NULL; - int num_in_chain, i; - *cert_out = *id_cert_out = NULL; - if (!(cert = SSL_get_peer_certificate(tls->ssl))) - return; - *cert_out = cert; - if (!(chain = SSL_get_peer_cert_chain(tls->ssl))) - return; - num_in_chain = sk_X509_num(chain); - /* 1 means we're receiving (server-side), and it's just the id_cert. - * 2 means we're connecting (client-side), and it's both the link - * cert and the id_cert. - */ - if (num_in_chain < 1) { - log_fn(severity,LD_PROTOCOL, - "Unexpected number of certificates in chain (%d)", - num_in_chain); - return; - } - for (i=0; i<num_in_chain; ++i) { - id_cert = sk_X509_value(chain, i); - if (X509_cmp(id_cert, cert) != 0) - break; - } - *id_cert_out = id_cert; -} - -/** If the provided tls connection is authenticated and has a - * certificate chain that is currently valid and signed, then set - * *<b>identity_key</b> to the identity certificate's key and return - * 0. Else, return -1 and log complaints with log-level <b>severity</b>. - */ -int -tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key) -{ - X509 *cert = NULL, *id_cert = NULL; - EVP_PKEY *id_pkey = NULL; - RSA *rsa; - int r = -1; - - check_no_tls_errors(); - *identity_key = NULL; - - try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert); - if (!cert) - goto done; - if (!id_cert) { - log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found"); - goto done; - } - tls_log_errors(tls, severity, LD_HANDSHAKE, "before verifying certificate"); - - if (!(id_pkey = X509_get_pubkey(id_cert)) || - X509_verify(cert, id_pkey) <= 0) { - log_fn(severity,LD_PROTOCOL,"X509_verify on cert and pkey returned <= 0"); - tls_log_errors(tls, severity, LD_HANDSHAKE, "verifying certificate"); - goto done; - } - - rsa = EVP_PKEY_get1_RSA(id_pkey); - if (!rsa) - goto done; - *identity_key = crypto_new_pk_from_rsa_(rsa); - - r = 0; - - done: - if (cert) - X509_free(cert); - if (id_pkey) - EVP_PKEY_free(id_pkey); - - /* This should never get invoked, but let's make sure in case OpenSSL - * acts unexpectedly. */ - tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "finishing tor_tls_verify"); - - return r; -} - -/** Check whether the certificate set on the connection <b>tls</b> is expired - * give or take <b>past_tolerance</b> seconds, or not-yet-valid give or take - * <b>future_tolerance</b> seconds. Return 0 for valid, -1 for failure. - * - * NOTE: you should call tor_tls_verify before tor_tls_check_lifetime. - */ -int -tor_tls_check_lifetime(int severity, tor_tls_t *tls, - time_t now, - int past_tolerance, int future_tolerance) -{ - X509 *cert; - int r = -1; - - if (!(cert = SSL_get_peer_certificate(tls->ssl))) - goto done; - - if (check_cert_lifetime_internal(severity, cert, now, - past_tolerance, future_tolerance) < 0) - goto done; - - r = 0; - done: - if (cert) - X509_free(cert); - /* Not expected to get invoked */ - tls_log_errors(tls, LOG_WARN, LD_NET, "checking certificate lifetime"); - - return r; -} - -/** Helper: check whether <b>cert</b> is expired give or take - * <b>past_tolerance</b> seconds, or not-yet-valid give or take - * <b>future_tolerance</b> seconds. (Relative to the current time - * <b>now</b>.) If it is live, return 0. If it is not live, log a message - * and return -1. */ -static int -check_cert_lifetime_internal(int severity, const X509 *cert, - time_t now, - int past_tolerance, int future_tolerance) -{ - time_t t; - - t = now + future_tolerance; - if (X509_cmp_time(X509_get_notBefore_const(cert), &t) > 0) { - log_cert_lifetime(severity, cert, "not yet valid", now); - return -1; - } - t = now - past_tolerance; - if (X509_cmp_time(X509_get_notAfter_const(cert), &t) < 0) { - log_cert_lifetime(severity, cert, "already expired", now); - return -1; - } - - return 0; -} - -#ifdef TOR_UNIT_TESTS -/* Testing only: return a new x509 cert with the same contents as <b>inp</b>, - but with the expiration time <b>new_expiration_time</b>, signed with - <b>signing_key</b>. */ -STATIC tor_x509_cert_t * -tor_x509_cert_replace_expiration(const tor_x509_cert_t *inp, - time_t new_expiration_time, - crypto_pk_t *signing_key) -{ - X509 *newc = X509_dup(inp->cert); - X509_time_adj(X509_get_notAfter(newc), 0, &new_expiration_time); - EVP_PKEY *pk = crypto_pk_get_evp_pkey_(signing_key, 1); - tor_assert(X509_sign(newc, pk, EVP_sha256())); - EVP_PKEY_free(pk); - return tor_x509_cert_new(newc); -} -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Return the number of bytes available for reading from <b>tls</b>. - */ -int -tor_tls_get_pending_bytes(tor_tls_t *tls) -{ - tor_assert(tls); - return SSL_pending(tls->ssl); -} - -/** If <b>tls</b> requires that the next write be of a particular size, - * return that size. Otherwise, return 0. */ -size_t -tor_tls_get_forced_write_size(tor_tls_t *tls) -{ - return tls->wantwrite_n; -} - -/** Sets n_read and n_written to the number of bytes read and written, - * respectively, on the raw socket used by <b>tls</b> since the last time this - * function was called on <b>tls</b>. */ -void -tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written) -{ - BIO *wbio, *tmpbio; - unsigned long r, w; - r = (unsigned long) BIO_number_read(SSL_get_rbio(tls->ssl)); - /* We want the number of bytes actually for real written. Unfortunately, - * sometimes OpenSSL replaces the wbio on tls->ssl with a buffering bio, - * which makes the answer turn out wrong. Let's cope with that. Note - * that this approach will fail if we ever replace tls->ssl's BIOs with - * buffering bios for reasons of our own. As an alternative, we could - * save the original BIO for tls->ssl in the tor_tls_t structure, but - * that would be tempting fate. */ - wbio = SSL_get_wbio(tls->ssl); -#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) - /* BIO structure is opaque as of OpenSSL 1.1.0-pre5-dev. Again, not - * supposed to use this form of the version macro, but the OpenSSL developers - * introduced major API changes in the pre-release stage. - */ - if (BIO_method_type(wbio) == BIO_TYPE_BUFFER && - (tmpbio = BIO_next(wbio)) != NULL) - wbio = tmpbio; -#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5)) */ - if (wbio->method == BIO_f_buffer() && (tmpbio = BIO_next(wbio)) != NULL) - wbio = tmpbio; -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) */ - w = (unsigned long) BIO_number_written(wbio); - - /* We are ok with letting these unsigned ints go "negative" here: - * If we wrapped around, this should still give us the right answer, unless - * we wrapped around by more than ULONG_MAX since the last time we called - * this function. - */ - *n_read = (size_t)(r - tls->last_read_count); - *n_written = (size_t)(w - tls->last_write_count); - if (*n_read > INT_MAX || *n_written > INT_MAX) { - log_warn(LD_BUG, "Preposterously large value in tor_tls_get_n_raw_bytes. " - "r=%lu, last_read=%lu, w=%lu, last_written=%lu", - r, tls->last_read_count, w, tls->last_write_count); - } - total_bytes_written_by_tls += *n_written; - tls->last_read_count = r; - tls->last_write_count = w; -} - -/** Return a ratio of the bytes that TLS has sent to the bytes that we've told - * it to send. Used to track whether our TLS records are getting too tiny. */ -MOCK_IMPL(double, -tls_get_write_overhead_ratio,(void)) -{ - if (total_bytes_written_over_tls == 0) - return 1.0; - - return U64_TO_DBL(total_bytes_written_by_tls) / - U64_TO_DBL(total_bytes_written_over_tls); -} - -/** Implement check_no_tls_errors: If there are any pending OpenSSL - * errors, log an error message. */ -void -check_no_tls_errors_(const char *fname, int line) -{ - if (ERR_peek_error() == 0) - return; - log_warn(LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ", - tor_fix_source_file(fname), line); - tls_log_errors(NULL, LOG_WARN, LD_NET, NULL); -} - -/** Return true iff the initial TLS connection at <b>tls</b> did not use a v2 - * TLS handshake. Output is undefined if the handshake isn't finished. */ -int -tor_tls_used_v1_handshake(tor_tls_t *tls) -{ - return ! tls->wasV2Handshake; -} - -/** Return the number of server handshakes that we've noticed doing on - * <b>tls</b>. */ -int -tor_tls_get_num_server_handshakes(tor_tls_t *tls) -{ - return tls->server_handshake_count; -} - -/** Return true iff the server TLS connection <b>tls</b> got the renegotiation - * request it was waiting for. */ -int -tor_tls_server_got_renegotiate(tor_tls_t *tls) -{ - return tls->got_renegotiate; -} - -#ifndef HAVE_SSL_GET_CLIENT_RANDOM -static size_t -SSL_get_client_random(SSL *s, uint8_t *out, size_t len) -{ - if (len == 0) - return SSL3_RANDOM_SIZE; - tor_assert(len == SSL3_RANDOM_SIZE); - tor_assert(s->s3); - memcpy(out, s->s3->client_random, len); - return len; -} -#endif /* !defined(HAVE_SSL_GET_CLIENT_RANDOM) */ - -#ifndef HAVE_SSL_GET_SERVER_RANDOM -static size_t -SSL_get_server_random(SSL *s, uint8_t *out, size_t len) -{ - if (len == 0) - return SSL3_RANDOM_SIZE; - tor_assert(len == SSL3_RANDOM_SIZE); - tor_assert(s->s3); - memcpy(out, s->s3->server_random, len); - return len; -} -#endif /* !defined(HAVE_SSL_GET_SERVER_RANDOM) */ - -#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY -STATIC size_t -SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len) -{ - tor_assert(s); - if (len == 0) - return s->master_key_length; - tor_assert(len == (size_t)s->master_key_length); - tor_assert(out); - memcpy(out, s->master_key, len); - return len; -} -#endif /* !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) */ - -/** Set the DIGEST256_LEN buffer at <b>secrets_out</b> to the value used in - * the v3 handshake to prove that the client knows the TLS secrets for the - * connection <b>tls</b>. Return 0 on success, -1 on failure. - */ -MOCK_IMPL(int, -tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)) -{ -#define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification" - uint8_t buf[128]; - size_t len; - tor_assert(tls); - - SSL *const ssl = tls->ssl; - SSL_SESSION *const session = SSL_get_session(ssl); - - tor_assert(ssl); - tor_assert(session); - - const size_t server_random_len = SSL_get_server_random(ssl, NULL, 0); - const size_t client_random_len = SSL_get_client_random(ssl, NULL, 0); - const size_t master_key_len = SSL_SESSION_get_master_key(session, NULL, 0); - - tor_assert(server_random_len); - tor_assert(client_random_len); - tor_assert(master_key_len); - - len = client_random_len + server_random_len + strlen(TLSSECRET_MAGIC) + 1; - tor_assert(len <= sizeof(buf)); - - { - size_t r = SSL_get_client_random(ssl, buf, client_random_len); - tor_assert(r == client_random_len); - } - - { - size_t r = SSL_get_server_random(ssl, - buf+client_random_len, - server_random_len); - tor_assert(r == server_random_len); - } - - uint8_t *master_key = tor_malloc_zero(master_key_len); - { - size_t r = SSL_SESSION_get_master_key(session, master_key, master_key_len); - tor_assert(r == master_key_len); - } - - uint8_t *nextbuf = buf + client_random_len + server_random_len; - memcpy(nextbuf, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1); - - /* - The value is an HMAC, using the TLS master key as the HMAC key, of - client_random | server_random | TLSSECRET_MAGIC - */ - crypto_hmac_sha256((char*)secrets_out, - (char*)master_key, - master_key_len, - (char*)buf, len); - memwipe(buf, 0, sizeof(buf)); - memwipe(master_key, 0, master_key_len); - tor_free(master_key); - - return 0; -} - -/** Using the RFC5705 key material exporting construction, and the - * provided <b>context</b> (<b>context_len</b> bytes long) and - * <b>label</b> (a NUL-terminated string), compute a 32-byte secret in - * <b>secrets_out</b> that only the parties to this TLS session can - * compute. Return 0 on success and -1 on failure. - */ -MOCK_IMPL(int, -tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out, - const uint8_t *context, - size_t context_len, - const char *label)) -{ - tor_assert(tls); - tor_assert(tls->ssl); - - int r = SSL_export_keying_material(tls->ssl, - secrets_out, DIGEST256_LEN, - label, strlen(label), - context, context_len, 1); - return (r == 1) ? 0 : -1; -} - -/** Examine the amount of memory used and available for buffers in <b>tls</b>. - * Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read - * buffer and *<b>rbuf_bytes</b> to the amount actually used. - * Set *<b>wbuf_capacity</b> to the amount of storage allocated for the write - * buffer and *<b>wbuf_bytes</b> to the amount actually used. - * - * Return 0 on success, -1 on failure.*/ -int -tor_tls_get_buffer_sizes(tor_tls_t *tls, - size_t *rbuf_capacity, size_t *rbuf_bytes, - size_t *wbuf_capacity, size_t *wbuf_bytes) -{ -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) - (void)tls; - (void)rbuf_capacity; - (void)rbuf_bytes; - (void)wbuf_capacity; - (void)wbuf_bytes; - - return -1; -#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)) */ - if (tls->ssl->s3->rbuf.buf) - *rbuf_capacity = tls->ssl->s3->rbuf.len; - else - *rbuf_capacity = 0; - if (tls->ssl->s3->wbuf.buf) - *wbuf_capacity = tls->ssl->s3->wbuf.len; - else - *wbuf_capacity = 0; - *rbuf_bytes = tls->ssl->s3->rbuf.left; - *wbuf_bytes = tls->ssl->s3->wbuf.left; - return 0; -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */ -} - -/** Check whether the ECC group requested is supported by the current OpenSSL - * library instance. Return 1 if the group is supported, and 0 if not. - */ -int -evaluate_ecgroup_for_tls(const char *ecgroup) -{ - EC_KEY *ec_key; - int nid; - int ret; - - if (!ecgroup) - nid = NID_tor_default_ecdhe_group; - else if (!strcasecmp(ecgroup, "P256")) - nid = NID_X9_62_prime256v1; - else if (!strcasecmp(ecgroup, "P224")) - nid = NID_secp224r1; - else - return 0; - - ec_key = EC_KEY_new_by_curve_name(nid); - ret = (ec_key != NULL); - EC_KEY_free(ec_key); - - return ret; -} diff --git a/src/common/tortls.h b/src/common/tortls.h deleted file mode 100644 index 7c867bfff2..0000000000 --- a/src/common/tortls.h +++ /dev/null @@ -1,295 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_TORTLS_H -#define TOR_TORTLS_H - -/** - * \file tortls.h - * \brief Headers for tortls.c - **/ - -#include "crypto_rsa.h" -#include "compat_openssl.h" -#include "compat.h" -#include "testsupport.h" - -/* Opaque structure to hold a TLS connection. */ -typedef struct tor_tls_t tor_tls_t; - -/* Opaque structure to hold an X509 certificate. */ -typedef struct tor_x509_cert_t tor_x509_cert_t; - -/* Possible return values for most tor_tls_* functions. */ -#define MIN_TOR_TLS_ERROR_VAL_ -9 -#define TOR_TLS_ERROR_MISC -9 -/* Rename to unexpected close or something. XXXX */ -#define TOR_TLS_ERROR_IO -8 -#define TOR_TLS_ERROR_CONNREFUSED -7 -#define TOR_TLS_ERROR_CONNRESET -6 -#define TOR_TLS_ERROR_NO_ROUTE -5 -#define TOR_TLS_ERROR_TIMEOUT -4 -#define TOR_TLS_CLOSE -3 -#define TOR_TLS_WANTREAD -2 -#define TOR_TLS_WANTWRITE -1 -#define TOR_TLS_DONE 0 - -/** Collection of case statements for all TLS errors that are not due to - * underlying IO failure. */ -#define CASE_TOR_TLS_ERROR_ANY_NONIO \ - case TOR_TLS_ERROR_MISC: \ - case TOR_TLS_ERROR_CONNREFUSED: \ - case TOR_TLS_ERROR_CONNRESET: \ - case TOR_TLS_ERROR_NO_ROUTE: \ - case TOR_TLS_ERROR_TIMEOUT - -/** Use this macro in a switch statement to catch _any_ TLS error. That way, - * if more errors are added, your switches will still work. */ -#define CASE_TOR_TLS_ERROR_ANY \ - CASE_TOR_TLS_ERROR_ANY_NONIO: \ - case TOR_TLS_ERROR_IO - -#define TOR_TLS_IS_ERROR(rv) ((rv) < TOR_TLS_CLOSE) - -#ifdef TORTLS_PRIVATE -#define TOR_TLS_MAGIC 0x71571571 - -typedef enum { - TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE, - TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE, - TOR_TLS_ST_BUFFEREVENT -} tor_tls_state_t; -#define tor_tls_state_bitfield_t ENUM_BF(tor_tls_state_t) - -struct x509_st; -struct ssl_st; -struct ssl_ctx_st; -struct ssl_session_st; - -/** Holds a SSL_CTX object and related state used to configure TLS - * connections. - */ -typedef struct tor_tls_context_t { - int refcnt; - struct ssl_ctx_st *ctx; - tor_x509_cert_t *my_link_cert; - tor_x509_cert_t *my_id_cert; - tor_x509_cert_t *my_auth_cert; - crypto_pk_t *link_key; - crypto_pk_t *auth_key; -} tor_tls_context_t; - -/** Structure that we use for a single certificate. */ -struct tor_x509_cert_t { - struct x509_st *cert; - uint8_t *encoded; - size_t encoded_len; - unsigned pkey_digests_set : 1; - common_digests_t cert_digests; - common_digests_t pkey_digests; -}; - -/** Holds a SSL object and its associated data. Members are only - * accessed from within tortls.c. - */ -struct tor_tls_t { - uint32_t magic; - tor_tls_context_t *context; /** A link to the context object for this tls. */ - struct ssl_st *ssl; /**< An OpenSSL SSL object. */ - int socket; /**< The underlying file descriptor for this TLS connection. */ - char *address; /**< An address to log when describing this connection. */ - tor_tls_state_bitfield_t state : 3; /**< The current SSL state, - * depending on which operations - * have completed successfully. */ - unsigned int isServer:1; /**< True iff this is a server-side connection */ - unsigned int wasV2Handshake:1; /**< True iff the original handshake for - * this connection used the updated version - * of the connection protocol (client sends - * different cipher list, server sends only - * one certificate). */ - /** True iff we should call negotiated_callback when we're done reading. */ - unsigned int got_renegotiate:1; - /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't - * called that function yet. */ - int8_t client_cipher_list_type; - /** Incremented every time we start the server side of a handshake. */ - uint8_t server_handshake_count; - size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last - * time. */ - /** Last values retrieved from BIO_number_read()/write(); see - * tor_tls_get_n_raw_bytes() for usage. - */ - unsigned long last_write_count; - unsigned long last_read_count; - /** If set, a callback to invoke whenever the client tries to renegotiate - * the handshake. */ - void (*negotiated_callback)(tor_tls_t *tls, void *arg); - /** Argument to pass to negotiated_callback. */ - void *callback_arg; -}; - -STATIC int tor_errno_to_tls_error(int e); -STATIC int tor_tls_get_error(tor_tls_t *tls, int r, int extra, - const char *doing, int severity, int domain); -STATIC tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl); -STATIC void tor_tls_allocate_tor_tls_object_ex_data_index(void); -#ifdef TORTLS_OPENSSL_PRIVATE -STATIC int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx); -STATIC int tor_tls_classify_client_ciphers(const struct ssl_st *ssl, - STACK_OF(SSL_CIPHER) *peer_ciphers); -#endif -STATIC int tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl); -MOCK_DECL(STATIC void, try_to_extract_certs_from_tls, - (int severity, tor_tls_t *tls, struct x509_st **cert_out, - struct x509_st **id_cert_out)); -#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY -STATIC size_t SSL_SESSION_get_master_key(struct ssl_session_st *s, - uint8_t *out, - size_t len); -#endif -STATIC void tor_tls_debug_state_callback(const struct ssl_st *ssl, - int type, int val); -STATIC void tor_tls_server_info_callback(const struct ssl_st *ssl, - int type, int val); -#ifdef TORTLS_OPENSSL_PRIVATE -STATIC int tor_tls_session_secret_cb(struct ssl_st *ssl, void *secret, - int *secret_len, - STACK_OF(SSL_CIPHER) *peer_ciphers, - CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher, - void *arg); -STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, - uint16_t cipher); -#endif /* defined(TORTLS_OPENSSL_PRIVATE) */ -MOCK_DECL(STATIC struct x509_st *, tor_tls_create_certificate, - (crypto_pk_t *rsa, - crypto_pk_t *rsa_sign, - const char *cname, - const char *cname_sign, - unsigned int cert_lifetime)); -STATIC tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity, - unsigned int key_lifetime, unsigned flags, int is_client); -MOCK_DECL(STATIC tor_x509_cert_t *, tor_x509_cert_new, - (struct x509_st *x509_cert)); -STATIC int tor_tls_context_init_one(tor_tls_context_t **ppcontext, - crypto_pk_t *identity, - unsigned int key_lifetime, - unsigned int flags, - int is_client); -STATIC void tls_log_errors(tor_tls_t *tls, int severity, int domain, - const char *doing); - -#ifdef TOR_UNIT_TESTS -extern int tor_tls_object_ex_data_index; -extern tor_tls_context_t *server_tls_context; -extern tor_tls_context_t *client_tls_context; -extern uint16_t v2_cipher_list[]; -extern uint64_t total_bytes_written_over_tls; -extern uint64_t total_bytes_written_by_tls; - -STATIC tor_x509_cert_t *tor_x509_cert_replace_expiration( - const tor_x509_cert_t *inp, - time_t new_expiration_time, - crypto_pk_t *signing_key); -#endif /* defined(TOR_UNIT_TESTS) */ - -#endif /* defined(TORTLS_PRIVATE) */ - -tor_x509_cert_t *tor_x509_cert_dup(const tor_x509_cert_t *cert); -const char *tor_tls_err_to_string(int err); -void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz); - -void tor_tls_free_all(void); - -#define TOR_TLS_CTX_IS_PUBLIC_SERVER (1u<<0) -#define TOR_TLS_CTX_USE_ECDHE_P256 (1u<<1) -#define TOR_TLS_CTX_USE_ECDHE_P224 (1u<<2) - -int tor_tls_context_init(unsigned flags, - crypto_pk_t *client_identity, - crypto_pk_t *server_identity, - unsigned int key_lifetime); -tor_tls_t *tor_tls_new(int sock, int is_server); -void tor_tls_set_logged_address(tor_tls_t *tls, const char *address); -void tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg); -int tor_tls_is_server(tor_tls_t *tls); -void tor_tls_free_(tor_tls_t *tls); -#define tor_tls_free(tls) FREE_AND_NULL(tor_tls_t, tor_tls_free_, (tls)) -int tor_tls_peer_has_cert(tor_tls_t *tls); -MOCK_DECL(tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls)); -MOCK_DECL(tor_x509_cert_t *,tor_tls_get_own_cert,(tor_tls_t *tls)); -int tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity); -int tor_tls_check_lifetime(int severity, - tor_tls_t *tls, time_t now, - int past_tolerance, - int future_tolerance); -MOCK_DECL(int, tor_tls_read, (tor_tls_t *tls, char *cp, size_t len)); -int tor_tls_write(tor_tls_t *tls, const char *cp, size_t n); -int tor_tls_handshake(tor_tls_t *tls); -int tor_tls_finish_handshake(tor_tls_t *tls); -void tor_tls_unblock_renegotiation(tor_tls_t *tls); -void tor_tls_block_renegotiation(tor_tls_t *tls); -void tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls); -int tor_tls_shutdown(tor_tls_t *tls); -int tor_tls_get_pending_bytes(tor_tls_t *tls); -size_t tor_tls_get_forced_write_size(tor_tls_t *tls); - -void tor_tls_get_n_raw_bytes(tor_tls_t *tls, - size_t *n_read, size_t *n_written); - -int tor_tls_get_buffer_sizes(tor_tls_t *tls, - size_t *rbuf_capacity, size_t *rbuf_bytes, - size_t *wbuf_capacity, size_t *wbuf_bytes); - -MOCK_DECL(double, tls_get_write_overhead_ratio, (void)); - -int tor_tls_used_v1_handshake(tor_tls_t *tls); -int tor_tls_get_num_server_handshakes(tor_tls_t *tls); -int tor_tls_server_got_renegotiate(tor_tls_t *tls); -MOCK_DECL(int,tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)); -MOCK_DECL(int,tor_tls_export_key_material,( - tor_tls_t *tls, uint8_t *secrets_out, - const uint8_t *context, - size_t context_len, - const char *label)); - -/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack. - */ -#define check_no_tls_errors() check_no_tls_errors_(__FILE__,__LINE__) - -void check_no_tls_errors_(const char *fname, int line); -void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, - int severity, int domain, const char *doing); - -void tor_x509_cert_free_(tor_x509_cert_t *cert); -#define tor_x509_cert_free(c) \ - FREE_AND_NULL(tor_x509_cert_t, tor_x509_cert_free_, (c)) -tor_x509_cert_t *tor_x509_cert_decode(const uint8_t *certificate, - size_t certificate_len); -void tor_x509_cert_get_der(const tor_x509_cert_t *cert, - const uint8_t **encoded_out, size_t *size_out); -const common_digests_t *tor_x509_cert_get_id_digests( - const tor_x509_cert_t *cert); -const common_digests_t *tor_x509_cert_get_cert_digests( - const tor_x509_cert_t *cert); -int tor_tls_get_my_certs(int server, - const tor_x509_cert_t **link_cert_out, - const tor_x509_cert_t **id_cert_out); -crypto_pk_t *tor_tls_get_my_client_auth_key(void); -crypto_pk_t *tor_tls_cert_get_key(tor_x509_cert_t *cert); -MOCK_DECL(int,tor_tls_cert_matches_key,(const tor_tls_t *tls, - const tor_x509_cert_t *cert)); -int tor_tls_cert_is_valid(int severity, - const tor_x509_cert_t *cert, - const tor_x509_cert_t *signing_cert, - time_t now, - int check_rsa_1024); -const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls); - -int evaluate_ecgroup_for_tls(const char *ecgroup); - -#endif /* !defined(TOR_TORTLS_H) */ - diff --git a/src/common/util.c b/src/common/util.c deleted file mode 100644 index dece5877f1..0000000000 --- a/src/common/util.c +++ /dev/null @@ -1,5378 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util.c - * \brief Common functions for strings, IO, network, data structures, - * process control. - **/ - -#include "orconfig.h" -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#define UTIL_PRIVATE -#include "util.h" -#include "torlog.h" -#include "crypto_digest.h" -#include "torint.h" -#include "container.h" -#include "address.h" -#include "sandbox.h" -#include "backtrace.h" -#include "util_process.h" -#include "util_format.h" - -#ifdef _WIN32 -#include <io.h> -#include <direct.h> -#include <process.h> -#include <tchar.h> -#include <winbase.h> -#else /* !(defined(_WIN32)) */ -#include <dirent.h> -#include <pwd.h> -#include <grp.h> -#endif /* defined(_WIN32) */ - -/* math.h needs this on Linux */ -#ifndef _USE_ISOC99_ -#define _USE_ISOC99_ 1 -#endif -#include <math.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <signal.h> - -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <sys/fcntl.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_MALLOC_MALLOC_H -#include <malloc/malloc.h> -#endif -#ifdef HAVE_MALLOC_H -#if !defined(OpenBSD) && !defined(__FreeBSD__) -/* OpenBSD has a malloc.h, but for our purposes, it only exists in order to - * scold us for being so stupid as to autodetect its presence. To be fair, - * they've done this since 1996, when autoconf was only 5 years old. */ -#include <malloc.h> -#endif /* !defined(OpenBSD) && !defined(__FreeBSD__) */ -#endif /* defined(HAVE_MALLOC_H) */ -#ifdef HAVE_MALLOC_NP_H -#include <malloc_np.h> -#endif -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) -#include <sys/prctl.h> -#endif - -#ifdef __clang_analyzer__ -#undef MALLOC_ZERO_WORKS -#endif - -/* ===== - * Memory management - * ===== */ -#ifdef USE_DMALLOC - #undef strndup - #include <dmalloc.h> - /* Macro to pass the extra dmalloc args to another function. */ - #define DMALLOC_FN_ARGS , file, line - - #if defined(HAVE_DMALLOC_STRDUP) - /* the dmalloc_strdup should be fine as defined */ - #elif defined(HAVE_DMALLOC_STRNDUP) - #define dmalloc_strdup(file, line, string, xalloc_b) \ - dmalloc_strndup(file, line, (string), -1, xalloc_b) - #else - #error "No dmalloc_strdup or equivalent" -#endif /* defined(HAVE_DMALLOC_STRDUP) || ... */ - -#else /* !(defined(USE_DMALLOC)) */ - - #define DMALLOC_FN_ARGS -#endif /* defined(USE_DMALLOC) */ - -/** Allocate a chunk of <b>size</b> bytes of memory, and return a pointer to - * result. On error, log and terminate the process. (Same as malloc(size), - * but never returns NULL.) - * - * <b>file</b> and <b>line</b> are used if dmalloc is enabled, and - * ignored otherwise. - */ -void * -tor_malloc_(size_t size DMALLOC_PARAMS) -{ - void *result; - - tor_assert(size < SIZE_T_CEILING); - -#ifndef MALLOC_ZERO_WORKS - /* Some libc mallocs don't work when size==0. Override them. */ - if (size==0) { - size=1; - } -#endif /* !defined(MALLOC_ZERO_WORKS) */ - -#ifdef USE_DMALLOC - result = dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); -#else - result = raw_malloc(size); -#endif - - if (PREDICT_UNLIKELY(result == NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_MM,"Out of memory on malloc(). Dying."); - /* If these functions die within a worker process, they won't call - * spawn_exit, but that's ok, since the parent will run out of memory soon - * anyway. */ - exit(1); // exit ok: alloc failed. - /* LCOV_EXCL_STOP */ - } - return result; -} - -/** Allocate a chunk of <b>size</b> bytes of memory, fill the memory with - * zero bytes, and return a pointer to the result. Log and terminate - * the process on error. (Same as calloc(size,1), but never returns NULL.) - */ -void * -tor_malloc_zero_(size_t size DMALLOC_PARAMS) -{ - /* You may ask yourself, "wouldn't it be smart to use calloc instead of - * malloc+memset? Perhaps libc's calloc knows some nifty optimization trick - * we don't!" Indeed it does, but its optimizations are only a big win when - * we're allocating something very big (it knows if it just got the memory - * from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero - * for big stuff, so we don't bother with calloc. */ - void *result = tor_malloc_(size DMALLOC_FN_ARGS); - memset(result, 0, size); - return result; -} - -/* The square root of SIZE_MAX + 1. If a is less than this, and b is less - * than this, then a*b is less than SIZE_MAX. (For example, if size_t is - * 32 bits, then SIZE_MAX is 0xffffffff and this value is 0x10000. If a and - * b are less than this, then their product is at most (65535*65535) == - * 0xfffe0001. */ -#define SQRT_SIZE_MAX_P1 (((size_t)1) << (sizeof(size_t)*4)) - -/** Return non-zero if and only if the product of the arguments is exact, - * and cannot overflow. */ -int -size_mul_check(const size_t x, const size_t y) -{ - /* This first check is equivalent to - (x < SQRT_SIZE_MAX_P1 && y < SQRT_SIZE_MAX_P1) - - Rationale: if either one of x or y is >= SQRT_SIZE_MAX_P1, then it - will have some bit set in its most significant half. - */ - return ((x|y) < SQRT_SIZE_MAX_P1 || - y == 0 || - x <= SIZE_MAX / y); -} - -/** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill - * the memory with zero bytes, and return a pointer to the result. - * Log and terminate the process on error. (Same as - * calloc(<b>nmemb</b>,<b>size</b>), but never returns NULL.) - * The second argument (<b>size</b>) should preferably be non-zero - * and a compile-time constant. - */ -void * -tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) -{ - tor_assert(size_mul_check(nmemb, size)); - return tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS); -} - -/** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b> - * bytes long; return the new memory block. On error, log and - * terminate. (Like realloc(ptr,size), but never returns NULL.) - */ -void * -tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS) -{ - void *result; - - tor_assert(size < SIZE_T_CEILING); - -#ifndef MALLOC_ZERO_WORKS - /* Some libc mallocs don't work when size==0. Override them. */ - if (size==0) { - size=1; - } -#endif /* !defined(MALLOC_ZERO_WORKS) */ - -#ifdef USE_DMALLOC - result = dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); -#else - result = raw_realloc(ptr, size); -#endif - - if (PREDICT_UNLIKELY(result == NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_MM,"Out of memory on realloc(). Dying."); - exit(1); // exit ok: alloc failed. - /* LCOV_EXCL_STOP */ - } - return result; -} - -/** - * Try to realloc <b>ptr</b> so that it takes up sz1 * sz2 bytes. Check for - * overflow. Unlike other allocation functions, return NULL on overflow. - */ -void * -tor_reallocarray_(void *ptr, size_t sz1, size_t sz2 DMALLOC_PARAMS) -{ - /* XXXX we can make this return 0, but we would need to check all the - * reallocarray users. */ - tor_assert(size_mul_check(sz1, sz2)); - - return tor_realloc(ptr, (sz1 * sz2) DMALLOC_FN_ARGS); -} - -/** Return a newly allocated copy of the NUL-terminated string s. On - * error, log and terminate. (Like strdup(s), but never returns - * NULL.) - */ -char * -tor_strdup_(const char *s DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(s); - -#ifdef USE_DMALLOC - duplicate = dmalloc_strdup(file, line, s, 0); -#else - duplicate = raw_strdup(s); -#endif - if (PREDICT_UNLIKELY(duplicate == NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_MM,"Out of memory on strdup(). Dying."); - exit(1); // exit ok: alloc failed. - /* LCOV_EXCL_STOP */ - } - return duplicate; -} - -/** Allocate and return a new string containing the first <b>n</b> - * characters of <b>s</b>. If <b>s</b> is longer than <b>n</b> - * characters, only the first <b>n</b> are copied. The result is - * always NUL-terminated. (Like strndup(s,n), but never returns - * NULL.) - */ -char * -tor_strndup_(const char *s, size_t n DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(s); - tor_assert(n < SIZE_T_CEILING); - duplicate = tor_malloc_((n+1) DMALLOC_FN_ARGS); - /* Performance note: Ordinarily we prefer strlcpy to strncpy. But - * this function gets called a whole lot, and platform strncpy is - * much faster than strlcpy when strlen(s) is much longer than n. - */ - strncpy(duplicate, s, n); - duplicate[n]='\0'; - return duplicate; -} - -/** Allocate a chunk of <b>len</b> bytes, with the same contents as the - * <b>len</b> bytes starting at <b>mem</b>. */ -void * -tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(len < SIZE_T_CEILING); - tor_assert(mem); - duplicate = tor_malloc_(len DMALLOC_FN_ARGS); - memcpy(duplicate, mem, len); - return duplicate; -} - -/** As tor_memdup(), but add an extra 0 byte at the end of the resulting - * memory. */ -void * -tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(len < SIZE_T_CEILING+1); - tor_assert(mem); - duplicate = tor_malloc_(len+1 DMALLOC_FN_ARGS); - memcpy(duplicate, mem, len); - duplicate[len] = '\0'; - return duplicate; -} - -/** Helper for places that need to take a function pointer to the right - * spelling of "free()". */ -void -tor_free_(void *mem) -{ - tor_free(mem); -} - -DISABLE_GCC_WARNING(aggregate-return) -/** Call the platform malloc info function, and dump the results to the log at - * level <b>severity</b>. If no such function exists, do nothing. */ -void -tor_log_mallinfo(int severity) -{ -#ifdef HAVE_MALLINFO - struct mallinfo mi; - memset(&mi, 0, sizeof(mi)); - mi = mallinfo(); - tor_log(severity, LD_MM, - "mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, " - "hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, " - "keepcost=%d", - mi.arena, mi.ordblks, mi.smblks, mi.hblks, - mi.hblkhd, mi.usmblks, mi.fsmblks, mi.uordblks, mi.fordblks, - mi.keepcost); -#else /* !(defined(HAVE_MALLINFO)) */ - (void)severity; -#endif /* defined(HAVE_MALLINFO) */ -#ifdef USE_DMALLOC - dmalloc_log_changed(0, /* Since the program started. */ - 1, /* Log info about non-freed pointers. */ - 0, /* Do not log info about freed pointers. */ - 0 /* Do not log individual pointers. */ - ); -#endif /* defined(USE_DMALLOC) */ -} -ENABLE_GCC_WARNING(aggregate-return) - -/* ===== - * Math - * ===== */ - -/** - * Returns the natural logarithm of d base e. We defined this wrapper here so - * to avoid conflicts with old versions of tor_log(), which were named log(). - */ -double -tor_mathlog(double d) -{ - return log(d); -} - -/** Return the long integer closest to <b>d</b>. We define this wrapper - * here so that not all users of math.h need to use the right incantations - * to get the c99 functions. */ -long -tor_lround(double d) -{ -#if defined(HAVE_LROUND) - return lround(d); -#elif defined(HAVE_RINT) - return (long)rint(d); -#else - return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5)); -#endif /* defined(HAVE_LROUND) || ... */ -} - -/** Return the 64-bit integer closest to d. We define this wrapper here so - * that not all users of math.h need to use the right incantations to get the - * c99 functions. */ -int64_t -tor_llround(double d) -{ -#if defined(HAVE_LLROUND) - return (int64_t)llround(d); -#elif defined(HAVE_RINT) - return (int64_t)rint(d); -#else - return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5)); -#endif /* defined(HAVE_LLROUND) || ... */ -} - -/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */ -int -tor_log2(uint64_t u64) -{ - int r = 0; - if (u64 >= (U64_LITERAL(1)<<32)) { - u64 >>= 32; - r = 32; - } - if (u64 >= (U64_LITERAL(1)<<16)) { - u64 >>= 16; - r += 16; - } - if (u64 >= (U64_LITERAL(1)<<8)) { - u64 >>= 8; - r += 8; - } - if (u64 >= (U64_LITERAL(1)<<4)) { - u64 >>= 4; - r += 4; - } - if (u64 >= (U64_LITERAL(1)<<2)) { - u64 >>= 2; - r += 2; - } - if (u64 >= (U64_LITERAL(1)<<1)) { - // u64 >>= 1; // not using this any more. - r += 1; - } - return r; -} - -/** Return the power of 2 in range [1,UINT64_MAX] closest to <b>u64</b>. If - * there are two powers of 2 equally close, round down. */ -uint64_t -round_to_power_of_2(uint64_t u64) -{ - int lg2; - uint64_t low; - uint64_t high; - if (u64 == 0) - return 1; - - lg2 = tor_log2(u64); - low = U64_LITERAL(1) << lg2; - - if (lg2 == 63) - return low; - - high = U64_LITERAL(1) << (lg2+1); - if (high - u64 < u64 - low) - return high; - else - return low; -} - -/** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. If no such x can be expressed as an unsigned, return - * UINT_MAX. Asserts if divisor is zero. */ -unsigned -round_to_next_multiple_of(unsigned number, unsigned divisor) -{ - tor_assert(divisor > 0); - if (UINT_MAX - divisor + 1 < number) - return UINT_MAX; - number += divisor - 1; - number -= number % divisor; - return number; -} - -/** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. If no such x can be expressed as a uint32_t, return - * UINT32_MAX. Asserts if divisor is zero. */ -uint32_t -round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor) -{ - tor_assert(divisor > 0); - if (UINT32_MAX - divisor + 1 < number) - return UINT32_MAX; - - number += divisor - 1; - number -= number % divisor; - return number; -} - -/** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. If no such x can be expressed as a uint64_t, return - * UINT64_MAX. Asserts if divisor is zero. */ -uint64_t -round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor) -{ - tor_assert(divisor > 0); - if (UINT64_MAX - divisor + 1 < number) - return UINT64_MAX; - number += divisor - 1; - number -= number % divisor; - return number; -} - -/** Transform a random value <b>p</b> from the uniform distribution in - * [0.0, 1.0[ into a Laplace distributed value with location parameter - * <b>mu</b> and scale parameter <b>b</b>. Truncate the final result - * to be an integer in [INT64_MIN, INT64_MAX]. */ -int64_t -sample_laplace_distribution(double mu, double b, double p) -{ - double result; - tor_assert(p >= 0.0 && p < 1.0); - - /* This is the "inverse cumulative distribution function" from: - * http://en.wikipedia.org/wiki/Laplace_distribution */ - if (p <= 0.0) { - /* Avoid taking log(0.0) == -INFINITY, as some processors or compiler - * options can cause the program to trap. */ - return INT64_MIN; - } - - result = mu - b * (p > 0.5 ? 1.0 : -1.0) - * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5)); - - return clamp_double_to_int64(result); -} - -/** Add random noise between INT64_MIN and INT64_MAX coming from a Laplace - * distribution with mu = 0 and b = <b>delta_f</b>/<b>epsilon</b> to - * <b>signal</b> based on the provided <b>random</b> value in [0.0, 1.0[. - * The epsilon value must be between ]0.0, 1.0]. delta_f must be greater - * than 0. */ -int64_t -add_laplace_noise(int64_t signal_, double random_, double delta_f, - double epsilon) -{ - int64_t noise; - - /* epsilon MUST be between ]0.0, 1.0] */ - tor_assert(epsilon > 0.0 && epsilon <= 1.0); - /* delta_f MUST be greater than 0. */ - tor_assert(delta_f > 0.0); - - /* Just add noise, no further signal */ - noise = sample_laplace_distribution(0.0, - delta_f / epsilon, - random_); - - /* Clip (signal + noise) to [INT64_MIN, INT64_MAX] */ - if (noise > 0 && INT64_MAX - noise < signal_) - return INT64_MAX; - else if (noise < 0 && INT64_MIN - noise > signal_) - return INT64_MIN; - else - return signal_ + noise; -} - -/* Helper: safely add two uint32_t's, capping at UINT32_MAX rather - * than overflow */ -uint32_t -tor_add_u32_nowrap(uint32_t a, uint32_t b) -{ - /* a+b > UINT32_MAX check, without overflow */ - if (PREDICT_UNLIKELY(a > UINT32_MAX - b)) { - return UINT32_MAX; - } else { - return a+b; - } -} - -/* Helper: return greatest common divisor of a,b */ -static uint64_t -gcd64(uint64_t a, uint64_t b) -{ - while (b) { - uint64_t t = b; - b = a % b; - a = t; - } - return a; -} - -/* Given a fraction *<b>numer</b> / *<b>denom</b>, simplify it. - * Requires that the denominator is greater than 0. */ -void -simplify_fraction64(uint64_t *numer, uint64_t *denom) -{ - tor_assert(denom); - uint64_t gcd = gcd64(*numer, *denom); - *numer /= gcd; - *denom /= gcd; -} - -/** Return the number of bits set in <b>v</b>. */ -int -n_bits_set_u8(uint8_t v) -{ - static const int nybble_table[] = { - 0, /* 0000 */ - 1, /* 0001 */ - 1, /* 0010 */ - 2, /* 0011 */ - 1, /* 0100 */ - 2, /* 0101 */ - 2, /* 0110 */ - 3, /* 0111 */ - 1, /* 1000 */ - 2, /* 1001 */ - 2, /* 1010 */ - 3, /* 1011 */ - 2, /* 1100 */ - 3, /* 1101 */ - 3, /* 1110 */ - 4, /* 1111 */ - }; - - return nybble_table[v & 15] + nybble_table[v>>4]; -} - -/* ===== - * String manipulation - * ===== */ - -/** Remove from the string <b>s</b> every character which appears in - * <b>strip</b>. */ -void -tor_strstrip(char *s, const char *strip) -{ - char *readp = s; - while (*readp) { - if (strchr(strip, *readp)) { - ++readp; - } else { - *s++ = *readp++; - } - } - *s = '\0'; -} - -/** Return a pointer to a NUL-terminated hexadecimal string encoding - * the first <b>fromlen</b> bytes of <b>from</b>. (fromlen must be \<= 32.) The - * result does not need to be deallocated, but repeated calls to - * hex_str will trash old results. - */ -const char * -hex_str(const char *from, size_t fromlen) -{ - static char buf[65]; - if (fromlen>(sizeof(buf)-1)/2) - fromlen = (sizeof(buf)-1)/2; - base16_encode(buf,sizeof(buf),from,fromlen); - return buf; -} - -/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to - * lowercase. */ -void -tor_strlower(char *s) -{ - while (*s) { - *s = TOR_TOLOWER(*s); - ++s; - } -} - -/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to - * lowercase. */ -void -tor_strupper(char *s) -{ - while (*s) { - *s = TOR_TOUPPER(*s); - ++s; - } -} - -/** Return 1 if every character in <b>s</b> is printable, else return 0. - */ -int -tor_strisprint(const char *s) -{ - while (*s) { - if (!TOR_ISPRINT(*s)) - return 0; - s++; - } - return 1; -} - -/** Return 1 if no character in <b>s</b> is uppercase, else return 0. - */ -int -tor_strisnonupper(const char *s) -{ - while (*s) { - if (TOR_ISUPPER(*s)) - return 0; - s++; - } - return 1; -} - -/** Return true iff every character in <b>s</b> is whitespace space; else - * return false. */ -int -tor_strisspace(const char *s) -{ - while (*s) { - if (!TOR_ISSPACE(*s)) - return 0; - s++; - } - return 1; -} - -/** As strcmp, except that either string may be NULL. The NULL string is - * considered to be before any non-NULL string. */ -int -strcmp_opt(const char *s1, const char *s2) -{ - if (!s1) { - if (!s2) - return 0; - else - return -1; - } else if (!s2) { - return 1; - } else { - return strcmp(s1, s2); - } -} - -/** Compares the first strlen(s2) characters of s1 with s2. Returns as for - * strcmp. - */ -int -strcmpstart(const char *s1, const char *s2) -{ - size_t n = strlen(s2); - return strncmp(s1, s2, n); -} - -/** Compare the s1_len-byte string <b>s1</b> with <b>s2</b>, - * without depending on a terminating nul in s1. Sorting order is first by - * length, then lexically; return values are as for strcmp. - */ -int -strcmp_len(const char *s1, const char *s2, size_t s1_len) -{ - size_t s2_len = strlen(s2); - if (s1_len < s2_len) - return -1; - if (s1_len > s2_len) - return 1; - return fast_memcmp(s1, s2, s2_len); -} - -/** Compares the first strlen(s2) characters of s1 with s2. Returns as for - * strcasecmp. - */ -int -strcasecmpstart(const char *s1, const char *s2) -{ - size_t n = strlen(s2); - return strncasecmp(s1, s2, n); -} - -/** Compares the last strlen(s2) characters of s1 with s2. Returns as for - * strcmp. - */ -int -strcmpend(const char *s1, const char *s2) -{ - size_t n1 = strlen(s1), n2 = strlen(s2); - if (n2>n1) - return strcmp(s1,s2); - else - return strncmp(s1+(n1-n2), s2, n2); -} - -/** Compares the last strlen(s2) characters of s1 with s2. Returns as for - * strcasecmp. - */ -int -strcasecmpend(const char *s1, const char *s2) -{ - size_t n1 = strlen(s1), n2 = strlen(s2); - if (n2>n1) /* then they can't be the same; figure out which is bigger */ - return strcasecmp(s1,s2); - else - return strncasecmp(s1+(n1-n2), s2, n2); -} - -/** Compare the value of the string <b>prefix</b> with the start of the - * <b>memlen</b>-byte memory chunk at <b>mem</b>. Return as for strcmp. - * - * [As fast_memcmp(mem, prefix, strlen(prefix)) but returns -1 if memlen is - * less than strlen(prefix).] - */ -int -fast_memcmpstart(const void *mem, size_t memlen, - const char *prefix) -{ - size_t plen = strlen(prefix); - if (memlen < plen) - return -1; - return fast_memcmp(mem, prefix, plen); -} - -/** Return a pointer to the first char of s that is not whitespace and - * not a comment, or to the terminating NUL if no such character exists. - */ -const char * -eat_whitespace(const char *s) -{ - tor_assert(s); - - while (1) { - switch (*s) { - case '\0': - default: - return s; - case ' ': - case '\t': - case '\n': - case '\r': - ++s; - break; - case '#': - ++s; - while (*s && *s != '\n') - ++s; - } - } -} - -/** Return a pointer to the first char of s that is not whitespace and - * not a comment, or to the terminating NUL if no such character exists. - */ -const char * -eat_whitespace_eos(const char *s, const char *eos) -{ - tor_assert(s); - tor_assert(eos && s <= eos); - - while (s < eos) { - switch (*s) { - case '\0': - default: - return s; - case ' ': - case '\t': - case '\n': - case '\r': - ++s; - break; - case '#': - ++s; - while (s < eos && *s && *s != '\n') - ++s; - } - } - return s; -} - -/** Return a pointer to the first char of s that is not a space or a tab - * or a \\r, or to the terminating NUL if no such character exists. */ -const char * -eat_whitespace_no_nl(const char *s) -{ - while (*s == ' ' || *s == '\t' || *s == '\r') - ++s; - return s; -} - -/** As eat_whitespace_no_nl, but stop at <b>eos</b> whether we have - * found a non-whitespace character or not. */ -const char * -eat_whitespace_eos_no_nl(const char *s, const char *eos) -{ - while (s < eos && (*s == ' ' || *s == '\t' || *s == '\r')) - ++s; - return s; -} - -/** Return a pointer to the first char of s that is whitespace or <b>#</b>, - * or to the terminating NUL if no such character exists. - */ -const char * -find_whitespace(const char *s) -{ - /* tor_assert(s); */ - while (1) { - switch (*s) - { - case '\0': - case '#': - case ' ': - case '\r': - case '\n': - case '\t': - return s; - default: - ++s; - } - } -} - -/** As find_whitespace, but stop at <b>eos</b> whether we have found a - * whitespace or not. */ -const char * -find_whitespace_eos(const char *s, const char *eos) -{ - /* tor_assert(s); */ - while (s < eos) { - switch (*s) - { - case '\0': - case '#': - case ' ': - case '\r': - case '\n': - case '\t': - return s; - default: - ++s; - } - } - return s; -} - -/** Return the first occurrence of <b>needle</b> in <b>haystack</b> that - * occurs at the start of a line (that is, at the beginning of <b>haystack</b> - * or immediately after a newline). Return NULL if no such string is found. - */ -const char * -find_str_at_start_of_line(const char *haystack, const char *needle) -{ - size_t needle_len = strlen(needle); - - do { - if (!strncmp(haystack, needle, needle_len)) - return haystack; - - haystack = strchr(haystack, '\n'); - if (!haystack) - return NULL; - else - ++haystack; - } while (*haystack); - - return NULL; -} - -/** Returns true if <b>string</b> could be a C identifier. - A C identifier must begin with a letter or an underscore and the - rest of its characters can be letters, numbers or underscores. No - length limit is imposed. */ -int -string_is_C_identifier(const char *string) -{ - size_t iter; - size_t length = strlen(string); - if (!length) - return 0; - - for (iter = 0; iter < length ; iter++) { - if (iter == 0) { - if (!(TOR_ISALPHA(string[iter]) || - string[iter] == '_')) - return 0; - } else { - if (!(TOR_ISALPHA(string[iter]) || - TOR_ISDIGIT(string[iter]) || - string[iter] == '_')) - return 0; - } - } - - return 1; -} - -/** Return true iff the 'len' bytes at 'mem' are all zero. */ -int -tor_mem_is_zero(const char *mem, size_t len) -{ - static const char ZERO[] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - }; - while (len >= sizeof(ZERO)) { - /* It's safe to use fast_memcmp here, since the very worst thing an - * attacker could learn is how many initial bytes of a secret were zero */ - if (fast_memcmp(mem, ZERO, sizeof(ZERO))) - return 0; - len -= sizeof(ZERO); - mem += sizeof(ZERO); - } - /* Deal with leftover bytes. */ - if (len) - return fast_memeq(mem, ZERO, len); - - return 1; -} - -/** Return true iff the DIGEST_LEN bytes in digest are all zero. */ -int -tor_digest_is_zero(const char *digest) -{ - static const uint8_t ZERO_DIGEST[] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 - }; - return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN); -} - -/** Return true if <b>string</b> is a valid 'key=[value]' string. - * "value" is optional, to indicate the empty string. Log at logging - * <b>severity</b> if something ugly happens. */ -int -string_is_key_value(int severity, const char *string) -{ - /* position of equal sign in string */ - const char *equal_sign_pos = NULL; - - tor_assert(string); - - if (strlen(string) < 2) { /* "x=" is shortest args string */ - tor_log(severity, LD_GENERAL, "'%s' is too short to be a k=v value.", - escaped(string)); - return 0; - } - - equal_sign_pos = strchr(string, '='); - if (!equal_sign_pos) { - tor_log(severity, LD_GENERAL, "'%s' is not a k=v value.", escaped(string)); - return 0; - } - - /* validate that the '=' is not in the beginning of the string. */ - if (equal_sign_pos == string) { - tor_log(severity, LD_GENERAL, "'%s' is not a valid k=v value.", - escaped(string)); - return 0; - } - - return 1; -} - -/** Return true if <b>string</b> represents a valid IPv4 adddress in - * 'a.b.c.d' form. - */ -int -string_is_valid_ipv4_address(const char *string) -{ - struct in_addr addr; - - return (tor_inet_pton(AF_INET,string,&addr) == 1); -} - -/** Return true if <b>string</b> represents a valid IPv6 address in - * a form that inet_pton() can parse. - */ -int -string_is_valid_ipv6_address(const char *string) -{ - struct in6_addr addr; - - return (tor_inet_pton(AF_INET6,string,&addr) == 1); -} - -/** Return true iff <b>string</b> is a valid destination address, - * i.e. either a DNS hostname or IPv4/IPv6 address string. - */ -int -string_is_valid_dest(const char *string) -{ - char *tmp = NULL; - int retval; - size_t len; - - if (string == NULL) - return 0; - - len = strlen(string); - - if (len == 0) - return 0; - - if (string[0] == '[' && string[len - 1] == ']') - string = tmp = tor_strndup(string + 1, len - 2); - - retval = string_is_valid_ipv4_address(string) || - string_is_valid_ipv6_address(string) || - string_is_valid_nonrfc_hostname(string); - - tor_free(tmp); - - return retval; -} - -/** Return true iff <b>string</b> matches a pattern of DNS names - * that we allow Tor clients to connect to. - * - * Note: This allows certain technically invalid characters ('_') to cope - * with misconfigured zones that have been encountered in the wild. - */ -int -string_is_valid_nonrfc_hostname(const char *string) -{ - int result = 1; - int has_trailing_dot; - char *last_label; - smartlist_t *components; - - if (!string || strlen(string) == 0) - return 0; - - if (string_is_valid_ipv4_address(string)) - return 0; - - components = smartlist_new(); - - smartlist_split_string(components,string,".",0,0); - - if (BUG(smartlist_len(components) == 0)) - return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks. - - /* Allow a single terminating '.' used rarely to indicate domains - * are FQDNs rather than relative. */ - last_label = (char *)smartlist_get(components, - smartlist_len(components) - 1); - has_trailing_dot = (last_label[0] == '\0'); - if (has_trailing_dot) { - smartlist_pop_last(components); - tor_free(last_label); - last_label = NULL; - } - - SMARTLIST_FOREACH_BEGIN(components, char *, c) { - if ((c[0] == '-') || (*c == '_')) { - result = 0; - break; - } - - do { - result = (TOR_ISALNUM(*c) || (*c == '-') || (*c == '_')); - c++; - } while (result && *c); - - if (result == 0) { - break; - } - } SMARTLIST_FOREACH_END(c); - - SMARTLIST_FOREACH_BEGIN(components, char *, c) { - tor_free(c); - } SMARTLIST_FOREACH_END(c); - - smartlist_free(components); - - return result; -} - -/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */ -int -tor_digest256_is_zero(const char *digest) -{ - return tor_mem_is_zero(digest, DIGEST256_LEN); -} - -/* Helper: common code to check whether the result of a strtol or strtoul or - * strtoll is correct. */ -#define CHECK_STRTOX_RESULT() \ - /* Did an overflow occur? */ \ - if (errno == ERANGE) \ - goto err; \ - /* Was at least one character converted? */ \ - if (endptr == s) \ - goto err; \ - /* Were there unexpected unconverted characters? */ \ - if (!next && *endptr) \ - goto err; \ - /* Illogical (max, min) inputs? */ \ - if (BUG(max < min)) \ - goto err; \ - /* Is r within limits? */ \ - if (r < min || r > max) \ - goto err; \ - if (ok) *ok = 1; \ - if (next) *next = endptr; \ - return r; \ - err: \ - if (ok) *ok = 0; \ - if (next) *next = endptr; \ - return 0 - -/** Extract a long from the start of <b>s</b>, in the given numeric - * <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal, - * octal, or hex number in the syntax of a C integer literal. If - * there is unconverted data and <b>next</b> is provided, set - * *<b>next</b> to the first unconverted character. An error has - * occurred if no characters are converted; or if there are - * unconverted characters and <b>next</b> is NULL; or if the parsed - * value is not between <b>min</b> and <b>max</b>. When no error - * occurs, return the parsed value and set *<b>ok</b> (if provided) to - * 1. When an error occurs, return 0 and set *<b>ok</b> (if provided) - * to 0. - */ -long -tor_parse_long(const char *s, int base, long min, long max, - int *ok, char **next) -{ - char *endptr; - long r; - - if (BUG(base < 0)) { - if (ok) - *ok = 0; - return 0; - } - - errno = 0; - r = strtol(s, &endptr, base); - CHECK_STRTOX_RESULT(); -} - -/** As tor_parse_long(), but return an unsigned long. */ -unsigned long -tor_parse_ulong(const char *s, int base, unsigned long min, - unsigned long max, int *ok, char **next) -{ - char *endptr; - unsigned long r; - - if (BUG(base < 0)) { - if (ok) - *ok = 0; - return 0; - } - - errno = 0; - r = strtoul(s, &endptr, base); - CHECK_STRTOX_RESULT(); -} - -/** As tor_parse_long(), but return a double. */ -double -tor_parse_double(const char *s, double min, double max, int *ok, char **next) -{ - char *endptr; - double r; - - errno = 0; - r = strtod(s, &endptr); - CHECK_STRTOX_RESULT(); -} - -/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to - * work for now. */ -uint64_t -tor_parse_uint64(const char *s, int base, uint64_t min, - uint64_t max, int *ok, char **next) -{ - char *endptr; - uint64_t r; - - if (BUG(base < 0)) { - if (ok) - *ok = 0; - return 0; - } - - errno = 0; -#ifdef HAVE_STRTOULL - r = (uint64_t)strtoull(s, &endptr, base); -#elif defined(_WIN32) - r = (uint64_t)_strtoui64(s, &endptr, base); -#elif SIZEOF_LONG == 8 - r = (uint64_t)strtoul(s, &endptr, base); -#else -#error "I don't know how to parse 64-bit numbers." -#endif /* defined(HAVE_STRTOULL) || ... */ - - CHECK_STRTOX_RESULT(); -} - -/** Allocate and return a new string representing the contents of <b>s</b>, - * surrounded by quotes and using standard C escapes. - * - * Generally, we use this for logging values that come in over the network to - * keep them from tricking users, and for sending certain values to the - * controller. - * - * We trust values from the resolver, OS, configuration file, and command line - * to not be maliciously ill-formed. We validate incoming routerdescs and - * SOCKS requests and addresses from BEGIN cells as they're parsed; - * afterwards, we trust them as non-malicious. - */ -char * -esc_for_log(const char *s) -{ - const char *cp; - char *result, *outp; - size_t len = 3; - if (!s) { - return tor_strdup("(null)"); - } - - for (cp = s; *cp; ++cp) { - switch (*cp) { - case '\\': - case '\"': - case '\'': - case '\r': - case '\n': - case '\t': - len += 2; - break; - default: - if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) - ++len; - else - len += 4; - break; - } - } - - tor_assert(len <= SSIZE_MAX); - - result = outp = tor_malloc(len); - *outp++ = '\"'; - for (cp = s; *cp; ++cp) { - /* This assertion should always succeed, since we will write at least - * one char here, and two chars for closing quote and nul later */ - tor_assert((outp-result) < (ssize_t)len-2); - switch (*cp) { - case '\\': - case '\"': - case '\'': - *outp++ = '\\'; - *outp++ = *cp; - break; - case '\n': - *outp++ = '\\'; - *outp++ = 'n'; - break; - case '\t': - *outp++ = '\\'; - *outp++ = 't'; - break; - case '\r': - *outp++ = '\\'; - *outp++ = 'r'; - break; - default: - if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) { - *outp++ = *cp; - } else { - tor_assert((outp-result) < (ssize_t)len-4); - tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp); - outp += 4; - } - break; - } - } - - tor_assert((outp-result) <= (ssize_t)len-2); - *outp++ = '\"'; - *outp++ = 0; - - return result; -} - -/** Similar to esc_for_log. Allocate and return a new string representing - * the first n characters in <b>chars</b>, surround by quotes and using - * standard C escapes. If a NUL character is encountered in <b>chars</b>, - * the resulting string will be terminated there. - */ -char * -esc_for_log_len(const char *chars, size_t n) -{ - char *string = tor_strndup(chars, n); - char *string_escaped = esc_for_log(string); - tor_free(string); - return string_escaped; -} - -/** Allocate and return a new string representing the contents of <b>s</b>, - * surrounded by quotes and using standard C escapes. - * - * THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main - * thread. Also, each call invalidates the last-returned value, so don't - * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b)); - */ -const char * -escaped(const char *s) -{ - static char *escaped_val_ = NULL; - tor_free(escaped_val_); - - if (s) - escaped_val_ = esc_for_log(s); - else - escaped_val_ = NULL; - - return escaped_val_; -} - -/** Return a newly allocated string equal to <b>string</b>, except that every - * character in <b>chars_to_escape</b> is preceded by a backslash. */ -char * -tor_escape_str_for_pt_args(const char *string, const char *chars_to_escape) -{ - char *new_string = NULL; - char *new_cp = NULL; - size_t length, new_length; - - tor_assert(string); - - length = strlen(string); - - if (!length) /* If we were given the empty string, return the same. */ - return tor_strdup(""); - /* (new_length > SIZE_MAX) => ((length * 2) + 1 > SIZE_MAX) => - (length*2 > SIZE_MAX - 1) => (length > (SIZE_MAX - 1)/2) */ - if (length > (SIZE_MAX - 1)/2) /* check for overflow */ - return NULL; - - /* this should be enough even if all characters must be escaped */ - new_length = (length * 2) + 1; - - new_string = new_cp = tor_malloc(new_length); - - while (*string) { - if (strchr(chars_to_escape, *string)) - *new_cp++ = '\\'; - - *new_cp++ = *string++; - } - - *new_cp = '\0'; /* NUL-terminate the new string */ - - return new_string; -} - -/* ===== - * Time - * ===== */ - -#define TOR_USEC_PER_SEC 1000000 - -/** Return the difference between start->tv_sec and end->tv_sec. - * Returns INT64_MAX on overflow and underflow. - */ -static int64_t -tv_secdiff_impl(const struct timeval *start, const struct timeval *end) -{ - const int64_t s = (int64_t)start->tv_sec; - const int64_t e = (int64_t)end->tv_sec; - - /* This may not be the most efficient way of implemeting this check, - * but it's easy to see that it's correct and doesn't overflow */ - - if (s > 0 && e < INT64_MIN + s) { - /* s is positive: equivalent to e - s < INT64_MIN, but without any - * overflow */ - return INT64_MAX; - } else if (s < 0 && e > INT64_MAX + s) { - /* s is negative: equivalent to e - s > INT64_MAX, but without any - * overflow */ - return INT64_MAX; - } - - return e - s; -} - -/** Return the number of microseconds elapsed between *start and *end. - * Returns LONG_MAX on overflow and underflow. - */ -long -tv_udiff(const struct timeval *start, const struct timeval *end) -{ - /* Sanity check tv_usec */ - if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " - "start tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(start->tv_usec)); - return LONG_MAX; - } - - if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " - "end tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(end->tv_usec)); - return LONG_MAX; - } - - /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit - */ - int64_t udiff; - const int64_t secdiff = tv_secdiff_impl(start, end); - - /* end->tv_usec - start->tv_usec can be up to 1 second either way */ - if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) || - secdiff < (int64_t)(LONG_MIN/1000000 + 1)) { - log_warn(LD_GENERAL, "comparing times on microsecond detail too far " - "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); - return LONG_MAX; - } - - /* we'll never get an overflow here, because we check that both usecs are - * between 0 and TV_USEC_PER_SEC. */ - udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec); - - /* Some compilers are smart enough to work out this is a no-op on L64 */ -#if SIZEOF_LONG < 8 - if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) { - return LONG_MAX; - } -#endif - - return (long)udiff; -} - -/** Return the number of milliseconds elapsed between *start and *end. - * If the tv_usec difference is 500, rounds away from zero. - * Returns LONG_MAX on overflow and underflow. - */ -long -tv_mdiff(const struct timeval *start, const struct timeval *end) -{ - /* Sanity check tv_usec */ - if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " - "start tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(start->tv_usec)); - return LONG_MAX; - } - - if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " - "end tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(end->tv_usec)); - return LONG_MAX; - } - - /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit - */ - int64_t mdiff; - const int64_t secdiff = tv_secdiff_impl(start, end); - - /* end->tv_usec - start->tv_usec can be up to 1 second either way, but the - * mdiff calculation may add another temporary second for rounding. - * Whether this actually causes overflow depends on the compiler's constant - * folding and order of operations. */ - if (secdiff > (int64_t)(LONG_MAX/1000 - 2) || - secdiff < (int64_t)(LONG_MIN/1000 + 1)) { - log_warn(LD_GENERAL, "comparing times on millisecond detail too far " - "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); - return LONG_MAX; - } - - /* Subtract and round */ - mdiff = secdiff*1000 + - /* We add a million usec here to ensure that the result is positive, - * so that the round-towards-zero behavior of the division will give - * the right result for rounding to the nearest msec. Later we subtract - * 1000 in order to get the correct result. - * We'll never get an overflow here, because we check that both usecs are - * between 0 and TV_USEC_PER_SEC. */ - ((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000 - - 1000; - - /* Some compilers are smart enough to work out this is a no-op on L64 */ -#if SIZEOF_LONG < 8 - if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) { - return LONG_MAX; - } -#endif - - return (long)mdiff; -} - -/** - * Converts timeval to milliseconds. - */ -int64_t -tv_to_msec(const struct timeval *tv) -{ - int64_t conv = ((int64_t)tv->tv_sec)*1000L; - /* Round ghetto-style */ - conv += ((int64_t)tv->tv_usec+500)/1000L; - return conv; -} - -/** Yield true iff <b>y</b> is a leap-year. */ -#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400))) -/** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */ -static int -n_leapdays(int year1, int year2) -{ - --year1; - --year2; - return (year2/4 - year1/4) - (year2/100 - year1/100) - + (year2/400 - year1/400); -} -/** Number of days per month in non-leap year; used by tor_timegm and - * parse_rfc1123_time. */ -static const int days_per_month[] = - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -/** Compute a time_t given a struct tm. The result is given in UTC, and - * does not account for leap seconds. Return 0 on success, -1 on failure. - */ -int -tor_timegm(const struct tm *tm, time_t *time_out) -{ - /* This is a pretty ironclad timegm implementation, snarfed from Python2.2. - * It's way more brute-force than fiddling with tzset(). - * - * We use int64_t rather than time_t to avoid overflow on multiplication on - * platforms with 32-bit time_t. Since year is clipped to INT32_MAX, and - * since 365 * 24 * 60 * 60 is approximately 31 million, it's not possible - * for INT32_MAX years to overflow int64_t when converted to seconds. */ - int64_t year, days, hours, minutes, seconds; - int i, invalid_year, dpm; - - /* Initialize time_out to 0 for now, to avoid bad usage in case this function - fails and the caller ignores the return value. */ - tor_assert(time_out); - *time_out = 0; - - /* avoid int overflow on addition */ - if (tm->tm_year < INT32_MAX-1900) { - year = tm->tm_year + 1900; - } else { - /* clamp year */ - year = INT32_MAX; - } - invalid_year = (year < 1970 || tm->tm_year >= INT32_MAX-1900); - - if (tm->tm_mon >= 0 && tm->tm_mon <= 11) { - dpm = days_per_month[tm->tm_mon]; - if (tm->tm_mon == 1 && !invalid_year && IS_LEAPYEAR(tm->tm_year)) { - dpm = 29; - } - } else { - /* invalid month - default to 0 days per month */ - dpm = 0; - } - - if (invalid_year || - tm->tm_mon < 0 || tm->tm_mon > 11 || - tm->tm_mday < 1 || tm->tm_mday > dpm || - tm->tm_hour < 0 || tm->tm_hour > 23 || - tm->tm_min < 0 || tm->tm_min > 59 || - tm->tm_sec < 0 || tm->tm_sec > 60) { - log_warn(LD_BUG, "Out-of-range argument to tor_timegm"); - return -1; - } - days = 365 * (year-1970) + n_leapdays(1970,(int)year); - for (i = 0; i < tm->tm_mon; ++i) - days += days_per_month[i]; - if (tm->tm_mon > 1 && IS_LEAPYEAR(year)) - ++days; - days += tm->tm_mday - 1; - hours = days*24 + tm->tm_hour; - - minutes = hours*60 + tm->tm_min; - seconds = minutes*60 + tm->tm_sec; - /* Check that "seconds" will fit in a time_t. On platforms where time_t is - * 32-bit, this check will fail for dates in and after 2038. - * - * We already know that "seconds" can't be negative because "year" >= 1970 */ -#if SIZEOF_TIME_T < 8 - if (seconds < TIME_MIN || seconds > TIME_MAX) { - log_warn(LD_BUG, "Result does not fit in tor_timegm"); - return -1; - } -#endif /* SIZEOF_TIME_T < 8 */ - *time_out = (time_t)seconds; - return 0; -} - -/* strftime is locale-specific, so we need to replace those parts */ - -/** A c-locale array of 3-letter names of weekdays, starting with Sun. */ -static const char *WEEKDAY_NAMES[] = - { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -/** A c-locale array of 3-letter names of months, starting with Jan. */ -static const char *MONTH_NAMES[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - -/** Set <b>buf</b> to the RFC1123 encoding of the UTC value of <b>t</b>. - * The buffer must be at least RFC1123_TIME_LEN+1 bytes long. - * - * (RFC1123 format is "Fri, 29 Sep 2006 15:54:20 GMT". Note the "GMT" - * rather than "UTC".) - */ -void -format_rfc1123_time(char *buf, time_t t) -{ - struct tm tm; - - tor_gmtime_r(&t, &tm); - - strftime(buf, RFC1123_TIME_LEN+1, "___, %d ___ %Y %H:%M:%S GMT", &tm); - tor_assert(tm.tm_wday >= 0); - tor_assert(tm.tm_wday <= 6); - memcpy(buf, WEEKDAY_NAMES[tm.tm_wday], 3); - tor_assert(tm.tm_mon >= 0); - tor_assert(tm.tm_mon <= 11); - memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3); -} - -/** Parse the (a subset of) the RFC1123 encoding of some time (in UTC) from - * <b>buf</b>, and store the result in *<b>t</b>. - * - * Note that we only accept the subset generated by format_rfc1123_time above, - * not the full range of formats suggested by RFC 1123. - * - * Return 0 on success, -1 on failure. -*/ -int -parse_rfc1123_time(const char *buf, time_t *t) -{ - struct tm tm; - char month[4]; - char weekday[4]; - int i, m, invalid_year; - unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; - unsigned dpm; - - if (strlen(buf) != RFC1123_TIME_LEN) - return -1; - memset(&tm, 0, sizeof(tm)); - if (tor_sscanf(buf, "%3s, %2u %3s %u %2u:%2u:%2u GMT", weekday, - &tm_mday, month, &tm_year, &tm_hour, - &tm_min, &tm_sec) < 7) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); - tor_free(esc); - return -1; - } - - m = -1; - for (i = 0; i < 12; ++i) { - if (!strcmp(month, MONTH_NAMES[i])) { - m = i; - break; - } - } - if (m<0) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s: No such month", esc); - tor_free(esc); - return -1; - } - tm.tm_mon = m; - - invalid_year = (tm_year >= INT32_MAX || tm_year < 1970); - tor_assert(m >= 0 && m <= 11); - dpm = days_per_month[m]; - if (m == 1 && !invalid_year && IS_LEAPYEAR(tm_year)) { - dpm = 29; - } - - if (invalid_year || tm_mday < 1 || tm_mday > dpm || - tm_hour > 23 || tm_min > 59 || tm_sec > 60) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); - tor_free(esc); - return -1; - } - tm.tm_mday = (int)tm_mday; - tm.tm_year = (int)tm_year; - tm.tm_hour = (int)tm_hour; - tm.tm_min = (int)tm_min; - tm.tm_sec = (int)tm_sec; - - if (tm.tm_year < 1970) { - /* LCOV_EXCL_START - * XXXX I think this is dead code; we already checked for - * invalid_year above. */ - tor_assert_nonfatal_unreached(); - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, - "Got invalid RFC1123 time %s. (Before 1970)", esc); - tor_free(esc); - return -1; - /* LCOV_EXCL_STOP */ - } - tm.tm_year -= 1900; - - return tor_timegm(&tm, t); -} - -/** Set <b>buf</b> to the ISO8601 encoding of the local value of <b>t</b>. - * The buffer must be at least ISO_TIME_LEN+1 bytes long. - * - * (ISO8601 format is 2006-10-29 10:57:20) - */ -void -format_local_iso_time(char *buf, time_t t) -{ - struct tm tm; - strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_localtime_r(&t, &tm)); -} - -/** Set <b>buf</b> to the ISO8601 encoding of the GMT value of <b>t</b>. - * The buffer must be at least ISO_TIME_LEN+1 bytes long. - */ -void -format_iso_time(char *buf, time_t t) -{ - struct tm tm; - strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_gmtime_r(&t, &tm)); -} - -/** As format_local_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid - * embedding an internal space. */ -void -format_local_iso_time_nospace(char *buf, time_t t) -{ - format_local_iso_time(buf, t); - buf[10] = 'T'; -} - -/** As format_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid - * embedding an internal space. */ -void -format_iso_time_nospace(char *buf, time_t t) -{ - format_iso_time(buf, t); - buf[10] = 'T'; -} - -/** As format_iso_time_nospace, but include microseconds in decimal - * fixed-point format. Requires that buf be at least ISO_TIME_USEC_LEN+1 - * bytes long. */ -void -format_iso_time_nospace_usec(char *buf, const struct timeval *tv) -{ - tor_assert(tv); - format_iso_time_nospace(buf, (time_t)tv->tv_sec); - tor_snprintf(buf+ISO_TIME_LEN, 8, ".%06d", (int)tv->tv_usec); -} - -/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, - * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on - * failure. Ignore extraneous stuff in <b>cp</b> after the end of the time - * string, unless <b>strict</b> is set. If <b>nospace</b> is set, - * expect the YYYY-MM-DDTHH:MM:SS format. */ -int -parse_iso_time_(const char *cp, time_t *t, int strict, int nospace) -{ - struct tm st_tm; - unsigned int year=0, month=0, day=0, hour=0, minute=0, second=0; - int n_fields; - char extra_char, separator_char; - n_fields = tor_sscanf(cp, "%u-%2u-%2u%c%2u:%2u:%2u%c", - &year, &month, &day, - &separator_char, - &hour, &minute, &second, &extra_char); - if (strict ? (n_fields != 7) : (n_fields < 7)) { - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); - tor_free(esc); - return -1; - } - if (separator_char != (nospace ? 'T' : ' ')) { - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); - tor_free(esc); - return -1; - } - if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || - hour > 23 || minute > 59 || second > 60 || year >= INT32_MAX) { - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "ISO time %s was nonsensical", esc); - tor_free(esc); - return -1; - } - st_tm.tm_year = (int)year-1900; - st_tm.tm_mon = month-1; - st_tm.tm_mday = day; - st_tm.tm_hour = hour; - st_tm.tm_min = minute; - st_tm.tm_sec = second; - st_tm.tm_wday = 0; /* Should be ignored. */ - - if (st_tm.tm_year < 70) { - /* LCOV_EXCL_START - * XXXX I think this is dead code; we already checked for - * year < 1970 above. */ - tor_assert_nonfatal_unreached(); - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "Got invalid ISO time %s. (Before 1970)", esc); - tor_free(esc); - return -1; - /* LCOV_EXCL_STOP */ - } - return tor_timegm(&st_tm, t); -} - -/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, - * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on - * failure. Reject the string if any characters are present after the time. - */ -int -parse_iso_time(const char *cp, time_t *t) -{ - return parse_iso_time_(cp, t, 1, 0); -} - -/** - * As parse_iso_time, but parses a time encoded by format_iso_time_nospace(). - */ -int -parse_iso_time_nospace(const char *cp, time_t *t) -{ - return parse_iso_time_(cp, t, 1, 1); -} - -/** Given a <b>date</b> in one of the three formats allowed by HTTP (ugh), - * parse it into <b>tm</b>. Return 0 on success, negative on failure. */ -int -parse_http_time(const char *date, struct tm *tm) -{ - const char *cp; - char month[4]; - char wkday[4]; - int i; - unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; - - tor_assert(tm); - memset(tm, 0, sizeof(*tm)); - - /* First, try RFC1123 or RFC850 format: skip the weekday. */ - if ((cp = strchr(date, ','))) { - ++cp; - if (*cp != ' ') - return -1; - ++cp; - if (tor_sscanf(cp, "%2u %3s %4u %2u:%2u:%2u GMT", - &tm_mday, month, &tm_year, - &tm_hour, &tm_min, &tm_sec) == 6) { - /* rfc1123-date */ - tm_year -= 1900; - } else if (tor_sscanf(cp, "%2u-%3s-%2u %2u:%2u:%2u GMT", - &tm_mday, month, &tm_year, - &tm_hour, &tm_min, &tm_sec) == 6) { - /* rfc850-date */ - } else { - return -1; - } - } else { - /* No comma; possibly asctime() format. */ - if (tor_sscanf(date, "%3s %3s %2u %2u:%2u:%2u %4u", - wkday, month, &tm_mday, - &tm_hour, &tm_min, &tm_sec, &tm_year) == 7) { - tm_year -= 1900; - } else { - return -1; - } - } - tm->tm_mday = (int)tm_mday; - tm->tm_year = (int)tm_year; - tm->tm_hour = (int)tm_hour; - tm->tm_min = (int)tm_min; - tm->tm_sec = (int)tm_sec; - tm->tm_wday = 0; /* Leave this unset. */ - - month[3] = '\0'; - /* Okay, now decode the month. */ - /* set tm->tm_mon to dummy value so the check below fails. */ - tm->tm_mon = -1; - for (i = 0; i < 12; ++i) { - if (!strcasecmp(MONTH_NAMES[i], month)) { - tm->tm_mon = i; - } - } - - if (tm->tm_year < 0 || - tm->tm_mon < 0 || tm->tm_mon > 11 || - tm->tm_mday < 1 || tm->tm_mday > 31 || - tm->tm_hour < 0 || tm->tm_hour > 23 || - tm->tm_min < 0 || tm->tm_min > 59 || - tm->tm_sec < 0 || tm->tm_sec > 60) - return -1; /* Out of range, or bad month. */ - - return 0; -} - -/** Given an <b>interval</b> in seconds, try to write it to the - * <b>out_len</b>-byte buffer in <b>out</b> in a human-readable form. - * Returns a non-negative integer on success, -1 on failure. - */ -int -format_time_interval(char *out, size_t out_len, long interval) -{ - /* We only report seconds if there's no hours. */ - long sec = 0, min = 0, hour = 0, day = 0; - - /* -LONG_MIN is LONG_MAX + 1, which causes signed overflow */ - if (interval < -LONG_MAX) - interval = LONG_MAX; - else if (interval < 0) - interval = -interval; - - if (interval >= 86400) { - day = interval / 86400; - interval %= 86400; - } - if (interval >= 3600) { - hour = interval / 3600; - interval %= 3600; - } - if (interval >= 60) { - min = interval / 60; - interval %= 60; - } - sec = interval; - - if (day) { - return tor_snprintf(out, out_len, "%ld days, %ld hours, %ld minutes", - day, hour, min); - } else if (hour) { - return tor_snprintf(out, out_len, "%ld hours, %ld minutes", hour, min); - } else if (min) { - return tor_snprintf(out, out_len, "%ld minutes, %ld seconds", min, sec); - } else { - return tor_snprintf(out, out_len, "%ld seconds", sec); - } -} - -/* ===== - * Cached time - * ===== */ - -#ifndef TIME_IS_FAST -/** Cached estimate of the current time. Updated around once per second; - * may be a few seconds off if we are really busy. This is a hack to avoid - * calling time(NULL) (which not everybody has optimized) on critical paths. - */ -static time_t cached_approx_time = 0; - -/** Return a cached estimate of the current time from when - * update_approx_time() was last called. This is a hack to avoid calling - * time(NULL) on critical paths: please do not even think of calling it - * anywhere else. */ -time_t -approx_time(void) -{ - return cached_approx_time; -} - -/** Update the cached estimate of the current time. This function SHOULD be - * called once per second, and MUST be called before the first call to - * get_approx_time. */ -void -update_approx_time(time_t now) -{ - cached_approx_time = now; -} -#endif /* !defined(TIME_IS_FAST) */ - -/* ===== - * Rate limiting - * ===== */ - -/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number - * of calls to rate_limit_is_ready (including this one!) since the last time - * rate_limit_is_ready returned nonzero. Otherwise return 0. - * If the call number hits <b>RATELIM_TOOMANY</b> limit, drop a warning - * about this event and stop counting. */ -static int -rate_limit_is_ready(ratelim_t *lim, time_t now) -{ - if (lim->rate + lim->last_allowed <= now) { - int res = lim->n_calls_since_last_time + 1; - lim->last_allowed = now; - lim->n_calls_since_last_time = 0; - return res; - } else { - if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { - ++lim->n_calls_since_last_time; - } - - return 0; - } -} - -/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly - * allocated string indicating how many messages were suppressed, suitable to - * append to a log message. Otherwise return NULL. */ -char * -rate_limit_log(ratelim_t *lim, time_t now) -{ - int n; - if ((n = rate_limit_is_ready(lim, now))) { - if (n == 1) { - return tor_strdup(""); - } else { - char *cp=NULL; - const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; - /* XXXX this is not exactly correct: the messages could have occurred - * any time between the old value of lim->allowed and now. */ - tor_asprintf(&cp, - " [%s%d similar message(s) suppressed in last %d seconds]", - opt_over, n-1, lim->rate); - return cp; - } - } else { - return NULL; - } -} - -/* ===== - * File helpers - * ===== */ - -/** Write <b>count</b> bytes from <b>buf</b> to <b>fd</b>. <b>isSocket</b> - * must be 1 if fd was returned by socket() or accept(), and 0 if fd - * was returned by open(). Return the number of bytes written, or -1 - * on error. Only use if fd is a blocking fd. */ -ssize_t -write_all(tor_socket_t fd, const char *buf, size_t count, int isSocket) -{ - size_t written = 0; - ssize_t result; - tor_assert(count < SSIZE_MAX); - - while (written != count) { - if (isSocket) - result = tor_socket_send(fd, buf+written, count-written, 0); - else - result = write((int)fd, buf+written, count-written); - if (result<0) - return -1; - written += result; - } - return (ssize_t)count; -} - -/** Read from <b>fd</b> to <b>buf</b>, until we get <b>count</b> bytes - * or reach the end of the file. <b>isSocket</b> must be 1 if fd - * was returned by socket() or accept(), and 0 if fd was returned by - * open(). Return the number of bytes read, or -1 on error. Only use - * if fd is a blocking fd. */ -ssize_t -read_all(tor_socket_t fd, char *buf, size_t count, int isSocket) -{ - size_t numread = 0; - ssize_t result; - - if (count > SIZE_T_CEILING || count > SSIZE_MAX) { - errno = EINVAL; - return -1; - } - - while (numread < count) { - if (isSocket) - result = tor_socket_recv(fd, buf+numread, count-numread, 0); - else - result = read((int)fd, buf+numread, count-numread); - if (result<0) - return -1; - else if (result == 0) - break; - numread += result; - } - return (ssize_t)numread; -} - -/* - * Filesystem operations. - */ - -/** Clean up <b>name</b> so that we can use it in a call to "stat". On Unix, - * we do nothing. On Windows, we remove a trailing slash, unless the path is - * the root of a disk. */ -static void -clean_name_for_stat(char *name) -{ -#ifdef _WIN32 - size_t len = strlen(name); - if (!len) - return; - if (name[len-1]=='\\' || name[len-1]=='/') { - if (len == 1 || (len==3 && name[1]==':')) - return; - name[len-1]='\0'; - } -#else /* !(defined(_WIN32)) */ - (void)name; -#endif /* defined(_WIN32) */ -} - -/** Wrapper for unlink() to make it mockable for the test suite; returns 0 - * if unlinking the file succeeded, -1 and sets errno if unlinking fails. - */ - -MOCK_IMPL(int, -tor_unlink,(const char *pathname)) -{ - return unlink(pathname); -} - -/** Return: - * FN_ERROR if filename can't be read, is NULL, or is zero-length, - * FN_NOENT if it doesn't exist, - * FN_FILE if it is a non-empty regular file, or a FIFO on unix-like systems, - * FN_EMPTY for zero-byte regular files, - * FN_DIR if it's a directory, and - * FN_ERROR for any other file type. - * On FN_ERROR and FN_NOENT, sets errno. (errno is not set when FN_ERROR - * is returned due to an unhandled file type.) */ -file_status_t -file_status(const char *fname) -{ - struct stat st; - char *f; - int r; - if (!fname || strlen(fname) == 0) { - return FN_ERROR; - } - f = tor_strdup(fname); - clean_name_for_stat(f); - log_debug(LD_FS, "stat()ing %s", f); - r = stat(sandbox_intern_string(f), &st); - tor_free(f); - if (r) { - if (errno == ENOENT) { - return FN_NOENT; - } - return FN_ERROR; - } - if (st.st_mode & S_IFDIR) { - return FN_DIR; - } else if (st.st_mode & S_IFREG) { - if (st.st_size > 0) { - return FN_FILE; - } else if (st.st_size == 0) { - return FN_EMPTY; - } else { - return FN_ERROR; - } -#ifndef _WIN32 - } else if (st.st_mode & S_IFIFO) { - return FN_FILE; -#endif - } else { - return FN_ERROR; - } -} - -/** Check whether <b>dirname</b> exists and is private. If yes return 0. - * If <b>dirname</b> does not exist: - * - if <b>check</b>&CPD_CREATE, try to create it and return 0 on success. - * - if <b>check</b>&CPD_CHECK, and we think we can create it, return 0. - * - if <b>check</b>&CPD_CHECK is false, and the directory exists, return 0. - * - otherwise, return -1. - * If CPD_GROUP_OK is set, then it's okay if the directory - * is group-readable, but in all cases we create the directory mode 0700. - * If CPD_GROUP_READ is set, existing directory behaves as CPD_GROUP_OK and - * if the directory is created it will use mode 0750 with group read - * permission. Group read privileges also assume execute permission - * as norm for directories. If CPD_CHECK_MODE_ONLY is set, then we don't - * alter the directory permissions if they are too permissive: - * we just return -1. - * When effective_user is not NULL, check permissions against the given user - * and its primary group. - */ -MOCK_IMPL(int, -check_private_dir,(const char *dirname, cpd_check_t check, - const char *effective_user)) -{ - int r; - struct stat st; - - tor_assert(dirname); - -#ifndef _WIN32 - int fd; - const struct passwd *pw = NULL; - uid_t running_uid; - gid_t running_gid; - - /* - * Goal is to harden the implementation by removing any - * potential for race between stat() and chmod(). - * chmod() accepts filename as argument. If an attacker can move - * the file between stat() and chmod(), a potential race exists. - * - * Several suggestions taken from: - * https://developer.apple.com/library/mac/documentation/ - * Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html - */ - - /* Open directory. - * O_NOFOLLOW to ensure that it does not follow symbolic links */ - fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); - - /* Was there an error? Maybe the directory does not exist? */ - if (fd == -1) { - - if (errno != ENOENT) { - /* Other directory error */ - log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, - strerror(errno)); - return -1; - } - - /* Received ENOENT: Directory does not exist */ - - /* Should we create the directory? */ - if (check & CPD_CREATE) { - log_info(LD_GENERAL, "Creating directory %s", dirname); - if (check & CPD_GROUP_READ) { - r = mkdir(dirname, 0750); - } else { - r = mkdir(dirname, 0700); - } - - /* check for mkdir() error */ - if (r) { - log_warn(LD_FS, "Error creating directory %s: %s", dirname, - strerror(errno)); - return -1; - } - - /* we just created the directory. try to open it again. - * permissions on the directory will be checked again below.*/ - fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); - - if (fd == -1) { - log_warn(LD_FS, "Could not reopen recently created directory %s: %s", - dirname, - strerror(errno)); - return -1; - } else { - close(fd); - } - - } else if (!(check & CPD_CHECK)) { - log_warn(LD_FS, "Directory %s does not exist.", dirname); - return -1; - } - - /* XXXX In the case where check==CPD_CHECK, we should look at the - * parent directory a little harder. */ - return 0; - } - - tor_assert(fd >= 0); - - //f = tor_strdup(dirname); - //clean_name_for_stat(f); - log_debug(LD_FS, "stat()ing %s", dirname); - //r = stat(sandbox_intern_string(f), &st); - r = fstat(fd, &st); - if (r == -1) { - log_warn(LD_FS, "fstat() on directory %s failed.", dirname); - close(fd); - return -1; - } - //tor_free(f); - - /* check that dirname is a directory */ - if (!(st.st_mode & S_IFDIR)) { - log_warn(LD_FS, "%s is not a directory", dirname); - close(fd); - return -1; - } - - if (effective_user) { - /* Look up the user and group information. - * If we have a problem, bail out. */ - pw = tor_getpwnam(effective_user); - if (pw == NULL) { - log_warn(LD_CONFIG, "Error setting configured user: %s not found", - effective_user); - close(fd); - return -1; - } - running_uid = pw->pw_uid; - running_gid = pw->pw_gid; - } else { - running_uid = getuid(); - running_gid = getgid(); - } - if (st.st_uid != running_uid) { - char *process_ownername = NULL, *file_ownername = NULL; - - { - const struct passwd *pw_running = tor_getpwuid(running_uid); - process_ownername = pw_running ? tor_strdup(pw_running->pw_name) : - tor_strdup("<unknown>"); - } - - { - const struct passwd *pw_stat = tor_getpwuid(st.st_uid); - file_ownername = pw_stat ? tor_strdup(pw_stat->pw_name) : - tor_strdup("<unknown>"); - } - - log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by " - "%s (%d). Perhaps you are running Tor as the wrong user?", - dirname, process_ownername, (int)running_uid, - file_ownername, (int)st.st_uid); - - tor_free(process_ownername); - tor_free(file_ownername); - close(fd); - return -1; - } - if ( (check & (CPD_GROUP_OK|CPD_GROUP_READ)) - && (st.st_gid != running_gid) && (st.st_gid != 0)) { - struct group *gr; - char *process_groupname = NULL; - gr = getgrgid(running_gid); - process_groupname = gr ? tor_strdup(gr->gr_name) : tor_strdup("<unknown>"); - gr = getgrgid(st.st_gid); - - log_warn(LD_FS, "%s is not owned by this group (%s, %d) but by group " - "%s (%d). Are you running Tor as the wrong user?", - dirname, process_groupname, (int)running_gid, - gr ? gr->gr_name : "<unknown>", (int)st.st_gid); - - tor_free(process_groupname); - close(fd); - return -1; - } - unsigned unwanted_bits = 0; - if (check & (CPD_GROUP_OK|CPD_GROUP_READ)) { - unwanted_bits = 0027; - } else { - unwanted_bits = 0077; - } - unsigned check_bits_filter = ~0; - if (check & CPD_RELAX_DIRMODE_CHECK) { - check_bits_filter = 0022; - } - if ((st.st_mode & unwanted_bits & check_bits_filter) != 0) { - unsigned new_mode; - if (check & CPD_CHECK_MODE_ONLY) { - log_warn(LD_FS, "Permissions on directory %s are too permissive.", - dirname); - close(fd); - return -1; - } - log_warn(LD_FS, "Fixing permissions on directory %s", dirname); - new_mode = st.st_mode; - new_mode |= 0700; /* Owner should have rwx */ - if (check & CPD_GROUP_READ) { - new_mode |= 0050; /* Group should have rx */ - } - new_mode &= ~unwanted_bits; /* Clear the bits that we didn't want set...*/ - if (fchmod(fd, new_mode)) { - log_warn(LD_FS, "Could not chmod directory %s: %s", dirname, - strerror(errno)); - close(fd); - return -1; - } else { - close(fd); - return 0; - } - } - close(fd); -#else /* !(!defined(_WIN32)) */ - /* Win32 case: we can't open() a directory. */ - (void)effective_user; - - char *f = tor_strdup(dirname); - clean_name_for_stat(f); - log_debug(LD_FS, "stat()ing %s", f); - r = stat(sandbox_intern_string(f), &st); - tor_free(f); - if (r) { - if (errno != ENOENT) { - log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, - strerror(errno)); - return -1; - } - if (check & CPD_CREATE) { - log_info(LD_GENERAL, "Creating directory %s", dirname); - r = mkdir(dirname); - if (r) { - log_warn(LD_FS, "Error creating directory %s: %s", dirname, - strerror(errno)); - return -1; - } - } else if (!(check & CPD_CHECK)) { - log_warn(LD_FS, "Directory %s does not exist.", dirname); - return -1; - } - return 0; - } - if (!(st.st_mode & S_IFDIR)) { - log_warn(LD_FS, "%s is not a directory", dirname); - return -1; - } - -#endif /* !defined(_WIN32) */ - return 0; -} - -/** Create a file named <b>fname</b> with the contents <b>str</b>. Overwrite - * the previous <b>fname</b> if possible. Return 0 on success, -1 on failure. - * - * This function replaces the old file atomically, if possible. This - * function, and all other functions in util.c that create files, create them - * with mode 0600. - */ -MOCK_IMPL(int, -write_str_to_file,(const char *fname, const char *str, int bin)) -{ -#ifdef _WIN32 - if (!bin && strchr(str, '\r')) { - log_warn(LD_BUG, - "We're writing a text string that already contains a CR to %s", - escaped(fname)); - } -#endif /* defined(_WIN32) */ - return write_bytes_to_file(fname, str, strlen(str), bin); -} - -/** Represents a file that we're writing to, with support for atomic commit: - * we can write into a temporary file, and either remove the file on - * failure, or replace the original file on success. */ -struct open_file_t { - char *tempname; /**< Name of the temporary file. */ - char *filename; /**< Name of the original file. */ - unsigned rename_on_close:1; /**< Are we using the temporary file or not? */ - unsigned binary:1; /**< Did we open in binary mode? */ - int fd; /**< fd for the open file. */ - FILE *stdio_file; /**< stdio wrapper for <b>fd</b>. */ -}; - -/** Try to start writing to the file in <b>fname</b>, passing the flags - * <b>open_flags</b> to the open() syscall, creating the file (if needed) with - * access value <b>mode</b>. If the O_APPEND flag is set, we append to the - * original file. Otherwise, we open a new temporary file in the same - * directory, and either replace the original or remove the temporary file - * when we're done. - * - * Return the fd for the newly opened file, and store working data in - * *<b>data_out</b>. The caller should not close the fd manually: - * instead, call finish_writing_to_file() or abort_writing_to_file(). - * Returns -1 on failure. - * - * NOTE: When not appending, the flags O_CREAT and O_TRUNC are treated - * as true and the flag O_EXCL is treated as false. - * - * NOTE: Ordinarily, O_APPEND means "seek to the end of the file before each - * write()". We don't do that. - */ -int -start_writing_to_file(const char *fname, int open_flags, int mode, - open_file_t **data_out) -{ - open_file_t *new_file = tor_malloc_zero(sizeof(open_file_t)); - const char *open_name; - int append = 0; - - tor_assert(fname); - tor_assert(data_out); -#if (O_BINARY != 0 && O_TEXT != 0) - tor_assert((open_flags & (O_BINARY|O_TEXT)) != 0); -#endif - new_file->fd = -1; - new_file->filename = tor_strdup(fname); - if (open_flags & O_APPEND) { - open_name = fname; - new_file->rename_on_close = 0; - append = 1; - open_flags &= ~O_APPEND; - } else { - tor_asprintf(&new_file->tempname, "%s.tmp", fname); - open_name = new_file->tempname; - /* We always replace an existing temporary file if there is one. */ - open_flags |= O_CREAT|O_TRUNC; - open_flags &= ~O_EXCL; - new_file->rename_on_close = 1; - } -#if O_BINARY != 0 - if (open_flags & O_BINARY) - new_file->binary = 1; -#endif - - new_file->fd = tor_open_cloexec(open_name, open_flags, mode); - if (new_file->fd < 0) { - log_warn(LD_FS, "Couldn't open \"%s\" (%s) for writing: %s", - open_name, fname, strerror(errno)); - goto err; - } - if (append) { - if (tor_fd_seekend(new_file->fd) < 0) { - log_warn(LD_FS, "Couldn't seek to end of file \"%s\": %s", open_name, - strerror(errno)); - goto err; - } - } - - *data_out = new_file; - - return new_file->fd; - - err: - if (new_file->fd >= 0) - close(new_file->fd); - *data_out = NULL; - tor_free(new_file->filename); - tor_free(new_file->tempname); - tor_free(new_file); - return -1; -} - -/** Given <b>file_data</b> from start_writing_to_file(), return a stdio FILE* - * that can be used to write to the same file. The caller should not mix - * stdio calls with non-stdio calls. */ -FILE * -fdopen_file(open_file_t *file_data) -{ - tor_assert(file_data); - if (file_data->stdio_file) - return file_data->stdio_file; - tor_assert(file_data->fd >= 0); - if (!(file_data->stdio_file = fdopen(file_data->fd, - file_data->binary?"ab":"a"))) { - log_warn(LD_FS, "Couldn't fdopen \"%s\" [%d]: %s", file_data->filename, - file_data->fd, strerror(errno)); - } - return file_data->stdio_file; -} - -/** Combines start_writing_to_file with fdopen_file(): arguments are as - * for start_writing_to_file, but */ -FILE * -start_writing_to_stdio_file(const char *fname, int open_flags, int mode, - open_file_t **data_out) -{ - FILE *res; - if (start_writing_to_file(fname, open_flags, mode, data_out)<0) - return NULL; - if (!(res = fdopen_file(*data_out))) { - abort_writing_to_file(*data_out); - *data_out = NULL; - } - return res; -} - -/** Helper function: close and free the underlying file and memory in - * <b>file_data</b>. If we were writing into a temporary file, then delete - * that file (if abort_write is true) or replaces the target file with - * the temporary file (if abort_write is false). */ -static int -finish_writing_to_file_impl(open_file_t *file_data, int abort_write) -{ - int r = 0; - - tor_assert(file_data && file_data->filename); - if (file_data->stdio_file) { - if (fclose(file_data->stdio_file)) { - log_warn(LD_FS, "Error closing \"%s\": %s", file_data->filename, - strerror(errno)); - abort_write = r = -1; - } - } else if (file_data->fd >= 0 && close(file_data->fd) < 0) { - log_warn(LD_FS, "Error flushing \"%s\": %s", file_data->filename, - strerror(errno)); - abort_write = r = -1; - } - - if (file_data->rename_on_close) { - tor_assert(file_data->tempname && file_data->filename); - if (!abort_write) { - tor_assert(strcmp(file_data->filename, file_data->tempname)); - if (replace_file(file_data->tempname, file_data->filename)) { - log_warn(LD_FS, "Error replacing \"%s\": %s", file_data->filename, - strerror(errno)); - abort_write = r = -1; - } - } - if (abort_write) { - int res = unlink(file_data->tempname); - if (res != 0) { - /* We couldn't unlink and we'll leave a mess behind */ - log_warn(LD_FS, "Failed to unlink %s: %s", - file_data->tempname, strerror(errno)); - r = -1; - } - } - } - - tor_free(file_data->filename); - tor_free(file_data->tempname); - tor_free(file_data); - - return r; -} - -/** Finish writing to <b>file_data</b>: close the file handle, free memory as - * needed, and if using a temporary file, replace the original file with - * the temporary file. */ -int -finish_writing_to_file(open_file_t *file_data) -{ - return finish_writing_to_file_impl(file_data, 0); -} - -/** Finish writing to <b>file_data</b>: close the file handle, free memory as - * needed, and if using a temporary file, delete it. */ -int -abort_writing_to_file(open_file_t *file_data) -{ - return finish_writing_to_file_impl(file_data, 1); -} - -/** Helper: given a set of flags as passed to open(2), open the file - * <b>fname</b> and write all the sized_chunk_t structs in <b>chunks</b> to - * the file. Do so as atomically as possible e.g. by opening temp files and - * renaming. */ -static int -write_chunks_to_file_impl(const char *fname, const smartlist_t *chunks, - int open_flags) -{ - open_file_t *file = NULL; - int fd; - ssize_t result; - fd = start_writing_to_file(fname, open_flags, 0600, &file); - if (fd<0) - return -1; - SMARTLIST_FOREACH(chunks, sized_chunk_t *, chunk, - { - result = write_all(fd, chunk->bytes, chunk->len, 0); - if (result < 0) { - log_warn(LD_FS, "Error writing to \"%s\": %s", fname, - strerror(errno)); - goto err; - } - tor_assert((size_t)result == chunk->len); - }); - - return finish_writing_to_file(file); - err: - abort_writing_to_file(file); - return -1; -} - -/** Given a smartlist of sized_chunk_t, write them to a file - * <b>fname</b>, overwriting or creating the file as necessary. - * If <b>no_tempfile</b> is 0 then the file will be written - * atomically. */ -int -write_chunks_to_file(const char *fname, const smartlist_t *chunks, int bin, - int no_tempfile) -{ - int flags = OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT); - - if (no_tempfile) { - /* O_APPEND stops write_chunks_to_file from using tempfiles */ - flags |= O_APPEND; - } - return write_chunks_to_file_impl(fname, chunks, flags); -} - -/** Write <b>len</b> bytes, starting at <b>str</b>, to <b>fname</b> - using the open() flags passed in <b>flags</b>. */ -static int -write_bytes_to_file_impl(const char *fname, const char *str, size_t len, - int flags) -{ - int r; - sized_chunk_t c = { str, len }; - smartlist_t *chunks = smartlist_new(); - smartlist_add(chunks, &c); - r = write_chunks_to_file_impl(fname, chunks, flags); - smartlist_free(chunks); - return r; -} - -/** As write_str_to_file, but does not assume a NUL-terminated - * string. Instead, we write <b>len</b> bytes, starting at <b>str</b>. */ -MOCK_IMPL(int, -write_bytes_to_file,(const char *fname, const char *str, size_t len, - int bin)) -{ - return write_bytes_to_file_impl(fname, str, len, - OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT)); -} - -/** As write_bytes_to_file, but if the file already exists, append the bytes - * to the end of the file instead of overwriting it. */ -int -append_bytes_to_file(const char *fname, const char *str, size_t len, - int bin) -{ - return write_bytes_to_file_impl(fname, str, len, - OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT)); -} - -/** Like write_str_to_file(), but also return -1 if there was a file - already residing in <b>fname</b>. */ -int -write_bytes_to_new_file(const char *fname, const char *str, size_t len, - int bin) -{ - return write_bytes_to_file_impl(fname, str, len, - OPEN_FLAGS_DONT_REPLACE| - (bin?O_BINARY:O_TEXT)); -} - -/** - * Read the contents of the open file <b>fd</b> presuming it is a FIFO - * (or similar) file descriptor for which the size of the file isn't - * known ahead of time. Return NULL on failure, and a NUL-terminated - * string on success. On success, set <b>sz_out</b> to the number of - * bytes read. - */ -char * -read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) -{ - ssize_t r; - size_t pos = 0; - char *string = NULL; - size_t string_max = 0; - - if (max_bytes_to_read+1 >= SIZE_T_CEILING) { - errno = EINVAL; - return NULL; - } - - do { - /* XXXX This "add 1K" approach is a little goofy; if we care about - * performance here, we should be doubling. But in practice we shouldn't - * be using this function on big files anyway. */ - string_max = pos + 1024; - if (string_max > max_bytes_to_read) - string_max = max_bytes_to_read + 1; - string = tor_realloc(string, string_max); - r = read(fd, string + pos, string_max - pos - 1); - if (r < 0) { - int save_errno = errno; - tor_free(string); - errno = save_errno; - return NULL; - } - - pos += r; - } while (r > 0 && pos < max_bytes_to_read); - - tor_assert(pos < string_max); - *sz_out = pos; - string[pos] = '\0'; - return string; -} - -/** Read the contents of <b>filename</b> into a newly allocated - * string; return the string on success or NULL on failure. - * - * If <b>stat_out</b> is provided, store the result of stat()ing the - * file into <b>stat_out</b>. - * - * If <b>flags</b> & RFTS_BIN, open the file in binary mode. - * If <b>flags</b> & RFTS_IGNORE_MISSING, don't warn if the file - * doesn't exist. - */ -/* - * This function <em>may</em> return an erroneous result if the file - * is modified while it is running, but must not crash or overflow. - * Right now, the error case occurs when the file length grows between - * the call to stat and the call to read_all: the resulting string will - * be truncated. - */ -MOCK_IMPL(char *, -read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) -{ - int fd; /* router file */ - struct stat statbuf; - char *string; - ssize_t r; - int bin = flags & RFTS_BIN; - - tor_assert(filename); - - fd = tor_open_cloexec(filename,O_RDONLY|(bin?O_BINARY:O_TEXT),0); - if (fd<0) { - int severity = LOG_WARN; - int save_errno = errno; - if (errno == ENOENT && (flags & RFTS_IGNORE_MISSING)) - severity = LOG_INFO; - log_fn(severity, LD_FS,"Could not open \"%s\": %s",filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - if (fstat(fd, &statbuf)<0) { - int save_errno = errno; - close(fd); - log_warn(LD_FS,"Could not fstat \"%s\".",filename); - errno = save_errno; - return NULL; - } - -#ifndef _WIN32 -/** When we detect that we're reading from a FIFO, don't read more than - * this many bytes. It's insane overkill for most uses. */ -#define FIFO_READ_MAX (1024*1024) - if (S_ISFIFO(statbuf.st_mode)) { - size_t sz = 0; - string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz); - int save_errno = errno; - if (string && stat_out) { - statbuf.st_size = sz; - memcpy(stat_out, &statbuf, sizeof(struct stat)); - } - close(fd); - if (!string) - errno = save_errno; - return string; - } -#endif /* !defined(_WIN32) */ - - if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING) { - close(fd); - errno = EINVAL; - return NULL; - } - - string = tor_malloc((size_t)(statbuf.st_size+1)); - - r = read_all(fd,string,(size_t)statbuf.st_size,0); - if (r<0) { - int save_errno = errno; - log_warn(LD_FS,"Error reading from file \"%s\": %s", filename, - strerror(errno)); - tor_free(string); - close(fd); - errno = save_errno; - return NULL; - } - string[r] = '\0'; /* NUL-terminate the result. */ - -#if defined(_WIN32) || defined(__CYGWIN__) - if (!bin && strchr(string, '\r')) { - log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped " - "when reading %s. Coping.", - filename); - tor_strstrip(string, "\r"); - r = strlen(string); - } - if (!bin) { - statbuf.st_size = (size_t) r; - } else -#endif /* defined(_WIN32) || defined(__CYGWIN__) */ - if (r != statbuf.st_size) { - /* Unless we're using text mode on win32, we'd better have an exact - * match for size. */ - int save_errno = errno; - log_warn(LD_FS,"Could read only %d of %ld bytes of file \"%s\".", - (int)r, (long)statbuf.st_size,filename); - tor_free(string); - close(fd); - errno = save_errno; - return NULL; - } - close(fd); - if (stat_out) { - memcpy(stat_out, &statbuf, sizeof(struct stat)); - } - - return string; -} - -#define TOR_ISODIGIT(c) ('0' <= (c) && (c) <= '7') - -/** Given a c-style double-quoted escaped string in <b>s</b>, extract and - * decode its contents into a newly allocated string. On success, assign this - * string to *<b>result</b>, assign its length to <b>size_out</b> (if - * provided), and return a pointer to the position in <b>s</b> immediately - * after the string. On failure, return NULL. - */ -const char * -unescape_string(const char *s, char **result, size_t *size_out) -{ - const char *cp; - char *out; - if (s[0] != '\"') - return NULL; - cp = s+1; - while (1) { - switch (*cp) { - case '\0': - case '\n': - return NULL; - case '\"': - goto end_of_loop; - case '\\': - if (cp[1] == 'x' || cp[1] == 'X') { - if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3]))) - return NULL; - cp += 4; - } else if (TOR_ISODIGIT(cp[1])) { - cp += 2; - if (TOR_ISODIGIT(*cp)) ++cp; - if (TOR_ISODIGIT(*cp)) ++cp; - } else if (cp[1] == 'n' || cp[1] == 'r' || cp[1] == 't' || cp[1] == '"' - || cp[1] == '\\' || cp[1] == '\'') { - cp += 2; - } else { - return NULL; - } - break; - default: - ++cp; - break; - } - } - end_of_loop: - out = *result = tor_malloc(cp-s + 1); - cp = s+1; - while (1) { - switch (*cp) - { - case '\"': - *out = '\0'; - if (size_out) *size_out = out - *result; - return cp+1; - - /* LCOV_EXCL_START -- we caught this in parse_config_from_line. */ - case '\0': - tor_fragile_assert(); - tor_free(*result); - return NULL; - /* LCOV_EXCL_STOP */ - case '\\': - switch (cp[1]) - { - case 'n': *out++ = '\n'; cp += 2; break; - case 'r': *out++ = '\r'; cp += 2; break; - case 't': *out++ = '\t'; cp += 2; break; - case 'x': case 'X': - { - int x1, x2; - - x1 = hex_decode_digit(cp[2]); - x2 = hex_decode_digit(cp[3]); - if (x1 == -1 || x2 == -1) { - /* LCOV_EXCL_START */ - /* we caught this above in the initial loop. */ - tor_assert_nonfatal_unreached(); - tor_free(*result); - return NULL; - /* LCOV_EXCL_STOP */ - } - - *out++ = ((x1<<4) + x2); - cp += 4; - } - break; - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': - { - int n = cp[1]-'0'; - cp += 2; - if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } - if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } - if (n > 255) { tor_free(*result); return NULL; } - *out++ = (char)n; - } - break; - case '\'': - case '\"': - case '\\': - case '\?': - *out++ = cp[1]; - cp += 2; - break; - - /* LCOV_EXCL_START */ - default: - /* we caught this above in the initial loop. */ - tor_assert_nonfatal_unreached(); - tor_free(*result); return NULL; - /* LCOV_EXCL_STOP */ - } - break; - default: - *out++ = *cp++; - } - } -} - -/** Removes enclosing quotes from <b>path</b> and unescapes quotes between the - * enclosing quotes. Backslashes are not unescaped. Return the unquoted - * <b>path</b> on success or 0 if <b>path</b> is not quoted correctly. */ -char * -get_unquoted_path(const char *path) -{ - size_t len = strlen(path); - - if (len == 0) { - return tor_strdup(""); - } - - int has_start_quote = (path[0] == '\"'); - int has_end_quote = (len > 0 && path[len-1] == '\"'); - if (has_start_quote != has_end_quote || (len == 1 && has_start_quote)) { - return NULL; - } - - char *unquoted_path = tor_malloc(len - has_start_quote - has_end_quote + 1); - char *s = unquoted_path; - size_t i; - for (i = has_start_quote; i < len - has_end_quote; i++) { - if (path[i] == '\"' && (i > 0 && path[i-1] == '\\')) { - *(s-1) = path[i]; - } else if (path[i] != '\"') { - *s++ = path[i]; - } else { /* unescaped quote */ - tor_free(unquoted_path); - return NULL; - } - } - *s = '\0'; - return unquoted_path; -} - -/** Expand any homedir prefix on <b>filename</b>; return a newly allocated - * string. */ -char * -expand_filename(const char *filename) -{ - tor_assert(filename); -#ifdef _WIN32 - /* Might consider using GetFullPathName() as described here: - * http://etutorials.org/Programming/secure+programming/ - * Chapter+3.+Input+Validation/3.7+Validating+Filenames+and+Paths/ - */ - return tor_strdup(filename); -#else /* !(defined(_WIN32)) */ - if (*filename == '~') { - char *home, *result=NULL; - const char *rest; - - if (filename[1] == '/' || filename[1] == '\0') { - home = getenv("HOME"); - if (!home) { - log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while " - "expanding \"%s\"; defaulting to \"\".", filename); - home = tor_strdup(""); - } else { - home = tor_strdup(home); - } - rest = strlen(filename)>=2?(filename+2):""; - } else { -#ifdef HAVE_PWD_H - char *username, *slash; - slash = strchr(filename, '/'); - if (slash) - username = tor_strndup(filename+1,slash-filename-1); - else - username = tor_strdup(filename+1); - if (!(home = get_user_homedir(username))) { - log_warn(LD_CONFIG,"Couldn't get homedir for \"%s\"",username); - tor_free(username); - return NULL; - } - tor_free(username); - rest = slash ? (slash+1) : ""; -#else /* !(defined(HAVE_PWD_H)) */ - log_warn(LD_CONFIG, "Couldn't expand homedir on system without pwd.h"); - return tor_strdup(filename); -#endif /* defined(HAVE_PWD_H) */ - } - tor_assert(home); - /* Remove trailing slash. */ - if (strlen(home)>1 && !strcmpend(home,PATH_SEPARATOR)) { - home[strlen(home)-1] = '\0'; - } - tor_asprintf(&result,"%s"PATH_SEPARATOR"%s",home,rest); - tor_free(home); - return result; - } else { - return tor_strdup(filename); - } -#endif /* defined(_WIN32) */ -} - -#define MAX_SCANF_WIDTH 9999 - -/** Helper: given an ASCII-encoded decimal digit, return its numeric value. - * NOTE: requires that its input be in-bounds. */ -static int -digit_to_num(char d) -{ - int num = ((int)d) - (int)'0'; - tor_assert(num <= 9 && num >= 0); - return num; -} - -/** Helper: Read an unsigned int from *<b>bufp</b> of up to <b>width</b> - * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On - * success, store the result in <b>out</b>, advance bufp to the next - * character, and return 0. On failure, return -1. */ -static int -scan_unsigned(const char **bufp, unsigned long *out, int width, unsigned base) -{ - unsigned long result = 0; - int scanned_so_far = 0; - const int hex = base==16; - tor_assert(base == 10 || base == 16); - if (!bufp || !*bufp || !out) - return -1; - if (width<0) - width=MAX_SCANF_WIDTH; - - while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp)) - && scanned_so_far < width) { - unsigned digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++); - // Check for overflow beforehand, without actually causing any overflow - // This preserves functionality on compilers that don't wrap overflow - // (i.e. that trap or optimise away overflow) - // result * base + digit > ULONG_MAX - // result * base > ULONG_MAX - digit - if (result > (ULONG_MAX - digit)/base) - return -1; /* Processing this digit would overflow */ - result = result * base + digit; - ++scanned_so_far; - } - - if (!scanned_so_far) /* No actual digits scanned */ - return -1; - - *out = result; - return 0; -} - -/** Helper: Read an signed int from *<b>bufp</b> of up to <b>width</b> - * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On - * success, store the result in <b>out</b>, advance bufp to the next - * character, and return 0. On failure, return -1. */ -static int -scan_signed(const char **bufp, long *out, int width) -{ - int neg = 0; - unsigned long result = 0; - - if (!bufp || !*bufp || !out) - return -1; - if (width<0) - width=MAX_SCANF_WIDTH; - - if (**bufp == '-') { - neg = 1; - ++*bufp; - --width; - } - - if (scan_unsigned(bufp, &result, width, 10) < 0) - return -1; - - if (neg && result > 0) { - if (result > ((unsigned long)LONG_MAX) + 1) - return -1; /* Underflow */ - else if (result == ((unsigned long)LONG_MAX) + 1) - *out = LONG_MIN; - else { - /* We once had a far more clever no-overflow conversion here, but - * some versions of GCC apparently ran it into the ground. Now - * we just check for LONG_MIN explicitly. - */ - *out = -(long)result; - } - } else { - if (result > LONG_MAX) - return -1; /* Overflow */ - *out = (long)result; - } - - return 0; -} - -/** Helper: Read a decimal-formatted double from *<b>bufp</b> of up to - * <b>width</b> characters. (Handle arbitrary width if <b>width</b> is less - * than 0.) On success, store the result in <b>out</b>, advance bufp to the - * next character, and return 0. On failure, return -1. */ -static int -scan_double(const char **bufp, double *out, int width) -{ - int neg = 0; - double result = 0; - int scanned_so_far = 0; - - if (!bufp || !*bufp || !out) - return -1; - if (width<0) - width=MAX_SCANF_WIDTH; - - if (**bufp == '-') { - neg = 1; - ++*bufp; - } - - while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { - const int digit = digit_to_num(*(*bufp)++); - result = result * 10 + digit; - ++scanned_so_far; - } - if (**bufp == '.') { - double fracval = 0, denominator = 1; - ++*bufp; - ++scanned_so_far; - while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { - const int digit = digit_to_num(*(*bufp)++); - fracval = fracval * 10 + digit; - denominator *= 10; - ++scanned_so_far; - } - result += fracval / denominator; - } - - if (!scanned_so_far) /* No actual digits scanned */ - return -1; - - *out = neg ? -result : result; - return 0; -} - -/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to - * <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b> - * to the next non-space character or the EOS. */ -static int -scan_string(const char **bufp, char *out, int width) -{ - int scanned_so_far = 0; - if (!bufp || !out || width < 0) - return -1; - while (**bufp && ! TOR_ISSPACE(**bufp) && scanned_so_far < width) { - *out++ = *(*bufp)++; - ++scanned_so_far; - } - *out = '\0'; - return 0; -} - -/** Locale-independent, minimal, no-surprises scanf variant, accepting only a - * restricted pattern format. For more info on what it supports, see - * tor_sscanf() documentation. */ -int -tor_vsscanf(const char *buf, const char *pattern, va_list ap) -{ - int n_matched = 0; - - while (*pattern) { - if (*pattern != '%') { - if (*buf == *pattern) { - ++buf; - ++pattern; - continue; - } else { - return n_matched; - } - } else { - int width = -1; - int longmod = 0; - ++pattern; - if (TOR_ISDIGIT(*pattern)) { - width = digit_to_num(*pattern++); - while (TOR_ISDIGIT(*pattern)) { - width *= 10; - width += digit_to_num(*pattern++); - if (width > MAX_SCANF_WIDTH) - return -1; - } - if (!width) /* No zero-width things. */ - return -1; - } - if (*pattern == 'l') { - longmod = 1; - ++pattern; - } - if (*pattern == 'u' || *pattern == 'x') { - unsigned long u; - const int base = (*pattern == 'u') ? 10 : 16; - if (!*buf) - return n_matched; - if (scan_unsigned(&buf, &u, width, base)<0) - return n_matched; - if (longmod) { - unsigned long *out = va_arg(ap, unsigned long *); - *out = u; - } else { - unsigned *out = va_arg(ap, unsigned *); - if (u > UINT_MAX) - return n_matched; - *out = (unsigned) u; - } - ++pattern; - ++n_matched; - } else if (*pattern == 'f') { - double *d = va_arg(ap, double *); - if (!longmod) - return -1; /* float not supported */ - if (!*buf) - return n_matched; - if (scan_double(&buf, d, width)<0) - return n_matched; - ++pattern; - ++n_matched; - } else if (*pattern == 'd') { - long lng=0; - if (scan_signed(&buf, &lng, width)<0) - return n_matched; - if (longmod) { - long *out = va_arg(ap, long *); - *out = lng; - } else { - int *out = va_arg(ap, int *); -#if LONG_MAX > INT_MAX - if (lng < INT_MIN || lng > INT_MAX) - return n_matched; -#endif - *out = (int)lng; - } - ++pattern; - ++n_matched; - } else if (*pattern == 's') { - char *s = va_arg(ap, char *); - if (longmod) - return -1; - if (width < 0) - return -1; - if (scan_string(&buf, s, width)<0) - return n_matched; - ++pattern; - ++n_matched; - } else if (*pattern == 'c') { - char *ch = va_arg(ap, char *); - if (longmod) - return -1; - if (width != -1) - return -1; - if (!*buf) - return n_matched; - *ch = *buf++; - ++pattern; - ++n_matched; - } else if (*pattern == '%') { - if (*buf != '%') - return n_matched; - if (longmod) - return -1; - ++buf; - ++pattern; - } else { - return -1; /* Unrecognized pattern component. */ - } - } - } - - return n_matched; -} - -/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b> - * and store the results in the corresponding argument fields. Differs from - * sscanf in that: - * <ul><li>It only handles %u, %lu, %x, %lx, %[NUM]s, %d, %ld, %lf, and %c. - * <li>It only handles decimal inputs for %lf. (12.3, not 1.23e1) - * <li>It does not handle arbitrarily long widths. - * <li>Numbers do not consume any space characters. - * <li>It is locale-independent. - * <li>%u and %x do not consume any space. - * <li>It returns -1 on malformed patterns.</ul> - * - * (As with other locale-independent functions, we need this to parse data that - * is in ASCII without worrying that the C library's locale-handling will make - * miscellaneous characters look like numbers, spaces, and so on.) - */ -int -tor_sscanf(const char *buf, const char *pattern, ...) -{ - int r; - va_list ap; - va_start(ap, pattern); - r = tor_vsscanf(buf, pattern, ap); - va_end(ap); - return r; -} - -/** Append the string produced by tor_asprintf(<b>pattern</b>, <b>...</b>) - * to <b>sl</b>. */ -void -smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) -{ - va_list ap; - va_start(ap, pattern); - smartlist_add_vasprintf(sl, pattern, ap); - va_end(ap); -} - -/** va_list-based backend of smartlist_add_asprintf. */ -void -smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, - va_list args) -{ - char *str = NULL; - - tor_vasprintf(&str, pattern, args); - tor_assert(str != NULL); - - smartlist_add(sl, str); -} - -/** Append a copy of string to sl */ -void -smartlist_add_strdup(struct smartlist_t *sl, const char *string) -{ - char *copy; - - copy = tor_strdup(string); - - smartlist_add(sl, copy); -} - -/** Return a new list containing the filenames in the directory <b>dirname</b>. - * Return NULL on error or if <b>dirname</b> is not a directory. - */ -MOCK_IMPL(smartlist_t *, -tor_listdir, (const char *dirname)) -{ - smartlist_t *result; -#ifdef _WIN32 - char *pattern=NULL; - TCHAR tpattern[MAX_PATH] = {0}; - char name[MAX_PATH*2+1] = {0}; - HANDLE handle; - WIN32_FIND_DATA findData; - tor_asprintf(&pattern, "%s\\*", dirname); -#ifdef UNICODE - mbstowcs(tpattern,pattern,MAX_PATH); -#else - strlcpy(tpattern, pattern, MAX_PATH); -#endif - if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(tpattern, &findData))) { - tor_free(pattern); - return NULL; - } - result = smartlist_new(); - while (1) { -#ifdef UNICODE - wcstombs(name,findData.cFileName,MAX_PATH); - name[sizeof(name)-1] = '\0'; -#else - strlcpy(name,findData.cFileName,sizeof(name)); -#endif /* defined(UNICODE) */ - if (strcmp(name, ".") && - strcmp(name, "..")) { - smartlist_add_strdup(result, name); - } - if (!FindNextFile(handle, &findData)) { - DWORD err; - if ((err = GetLastError()) != ERROR_NO_MORE_FILES) { - char *errstr = format_win32_error(err); - log_warn(LD_FS, "Error reading directory '%s': %s", dirname, errstr); - tor_free(errstr); - } - break; - } - } - FindClose(handle); - tor_free(pattern); -#else /* !(defined(_WIN32)) */ - const char *prot_dname = sandbox_intern_string(dirname); - DIR *d; - struct dirent *de; - if (!(d = opendir(prot_dname))) - return NULL; - - result = smartlist_new(); - while ((de = readdir(d))) { - if (!strcmp(de->d_name, ".") || - !strcmp(de->d_name, "..")) - continue; - smartlist_add_strdup(result, de->d_name); - } - closedir(d); -#endif /* defined(_WIN32) */ - return result; -} - -/** Return true iff <b>filename</b> is a relative path. */ -int -path_is_relative(const char *filename) -{ - if (filename && filename[0] == '/') - return 0; -#ifdef _WIN32 - else if (filename && filename[0] == '\\') - return 0; - else if (filename && strlen(filename)>3 && TOR_ISALPHA(filename[0]) && - filename[1] == ':' && filename[2] == '\\') - return 0; -#endif /* defined(_WIN32) */ - else - return 1; -} - -/* ===== - * Process helpers - * ===== */ - -#ifndef _WIN32 -/* Based on code contributed by christian grothoff */ -/** True iff we've called start_daemon(). */ -static int start_daemon_called = 0; -/** True iff we've called finish_daemon(). */ -static int finish_daemon_called = 0; -/** Socketpair used to communicate between parent and child process while - * daemonizing. */ -static int daemon_filedes[2]; -/** Start putting the process into daemon mode: fork and drop all resources - * except standard fds. The parent process never returns, but stays around - * until finish_daemon is called. (Note: it's safe to call this more - * than once: calls after the first are ignored.) - */ -void -start_daemon(void) -{ - pid_t pid; - - if (start_daemon_called) - return; - start_daemon_called = 1; - - if (pipe(daemon_filedes)) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno)); - exit(1); // exit ok: during daemonize, pipe failed. - /* LCOV_EXCL_STOP */ - } - pid = fork(); - if (pid < 0) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"fork failed. Exiting."); - exit(1); // exit ok: during daemonize, fork failed - /* LCOV_EXCL_STOP */ - } - if (pid) { /* Parent */ - int ok; - char c; - - close(daemon_filedes[1]); /* we only read */ - ok = -1; - while (0 < read(daemon_filedes[0], &c, sizeof(char))) { - if (c == '.') - ok = 1; - } - fflush(stdout); - if (ok == 1) - exit(0); // exit ok: during daemonize, daemonizing. - else - exit(1); /* child reported error. exit ok: daemonize failed. */ - } else { /* Child */ - close(daemon_filedes[0]); /* we only write */ - - (void) setsid(); /* Detach from controlling terminal */ - /* - * Fork one more time, so the parent (the session group leader) can exit. - * This means that we, as a non-session group leader, can never regain a - * controlling terminal. This part is recommended by Stevens's - * _Advanced Programming in the Unix Environment_. - */ - if (fork() != 0) { - exit(0); // exit ok: during daemonize, fork failed (2) - } - set_main_thread(); /* We are now the main thread. */ - - return; - } -} - -/** Finish putting the process into daemon mode: drop standard fds, and tell - * the parent process to exit. (Note: it's safe to call this more than once: - * calls after the first are ignored. Calls start_daemon first if it hasn't - * been called already.) - */ -void -finish_daemon(const char *desired_cwd) -{ - int nullfd; - char c = '.'; - if (finish_daemon_called) - return; - if (!start_daemon_called) - start_daemon(); - finish_daemon_called = 1; - - if (!desired_cwd) - desired_cwd = "/"; - /* Don't hold the wrong FS mounted */ - if (chdir(desired_cwd) < 0) { - log_err(LD_GENERAL,"chdir to \"%s\" failed. Exiting.",desired_cwd); - exit(1); // exit ok: during daemonize, chdir failed. - } - - nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0); - if (nullfd < 0) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"/dev/null can't be opened. Exiting."); - exit(1); // exit ok: during daemonize, couldn't open /dev/null - /* LCOV_EXCL_STOP */ - } - /* close fds linking to invoking terminal, but - * close usual incoming fds, but redirect them somewhere - * useful so the fds don't get reallocated elsewhere. - */ - if (dup2(nullfd,0) < 0 || - dup2(nullfd,1) < 0 || - dup2(nullfd,2) < 0) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"dup2 failed. Exiting."); - exit(1); // exit ok: during daemonize, dup2 failed. - /* LCOV_EXCL_STOP */ - } - if (nullfd > 2) - close(nullfd); - /* signal success */ - if (write(daemon_filedes[1], &c, sizeof(char)) != sizeof(char)) { - log_err(LD_GENERAL,"write failed. Exiting."); - } - close(daemon_filedes[1]); -} -#else /* !(!defined(_WIN32)) */ -/* defined(_WIN32) */ -void -start_daemon(void) -{ -} -void -finish_daemon(const char *cp) -{ - (void)cp; -} -#endif /* !defined(_WIN32) */ - -/** Write the current process ID, followed by NL, into <b>filename</b>. - * Return 0 on success, -1 on failure. - */ -int -write_pidfile(const char *filename) -{ - FILE *pidfile; - - if ((pidfile = fopen(filename, "w")) == NULL) { - log_warn(LD_FS, "Unable to open \"%s\" for writing: %s", filename, - strerror(errno)); - return -1; - } else { -#ifdef _WIN32 - int pid = (int)_getpid(); -#else - int pid = (int)getpid(); -#endif - int rv = 0; - if (fprintf(pidfile, "%d\n", pid) < 0) - rv = -1; - if (fclose(pidfile) < 0) - rv = -1; - return rv; - } -} - -#ifdef _WIN32 -HANDLE -load_windows_system_library(const TCHAR *library_name) -{ - TCHAR path[MAX_PATH]; - unsigned n; - n = GetSystemDirectory(path, MAX_PATH); - if (n == 0 || n + _tcslen(library_name) + 2 >= MAX_PATH) - return 0; - _tcscat(path, TEXT("\\")); - _tcscat(path, library_name); - return LoadLibrary(path); -} -#endif /* defined(_WIN32) */ - -/** Format a single argument for being put on a Windows command line. - * Returns a newly allocated string */ -static char * -format_win_cmdline_argument(const char *arg) -{ - char *formatted_arg; - char need_quotes; - const char *c; - int i; - int bs_counter = 0; - /* Backslash we can point to when one is inserted into the string */ - const char backslash = '\\'; - - /* Smartlist of *char */ - smartlist_t *arg_chars; - arg_chars = smartlist_new(); - - /* Quote string if it contains whitespace or is empty */ - need_quotes = (strchr(arg, ' ') || strchr(arg, '\t') || '\0' == arg[0]); - - /* Build up smartlist of *chars */ - for (c=arg; *c != '\0'; c++) { - if ('"' == *c) { - /* Double up backslashes preceding a quote */ - for (i=0; i<(bs_counter*2); i++) - smartlist_add(arg_chars, (void*)&backslash); - bs_counter = 0; - /* Escape the quote */ - smartlist_add(arg_chars, (void*)&backslash); - smartlist_add(arg_chars, (void*)c); - } else if ('\\' == *c) { - /* Count backslashes until we know whether to double up */ - bs_counter++; - } else { - /* Don't double up slashes preceding a non-quote */ - for (i=0; i<bs_counter; i++) - smartlist_add(arg_chars, (void*)&backslash); - bs_counter = 0; - smartlist_add(arg_chars, (void*)c); - } - } - /* Don't double up trailing backslashes */ - for (i=0; i<bs_counter; i++) - smartlist_add(arg_chars, (void*)&backslash); - - /* Allocate space for argument, quotes (if needed), and terminator */ - const size_t formatted_arg_len = smartlist_len(arg_chars) + - (need_quotes ? 2 : 0) + 1; - formatted_arg = tor_malloc_zero(formatted_arg_len); - - /* Add leading quote */ - i=0; - if (need_quotes) - formatted_arg[i++] = '"'; - - /* Add characters */ - SMARTLIST_FOREACH(arg_chars, char*, ch, - { - formatted_arg[i++] = *ch; - }); - - /* Add trailing quote */ - if (need_quotes) - formatted_arg[i++] = '"'; - formatted_arg[i] = '\0'; - - smartlist_free(arg_chars); - return formatted_arg; -} - -/** Format a command line for use on Windows, which takes the command as a - * string rather than string array. Follows the rules from "Parsing C++ - * Command-Line Arguments" in MSDN. Algorithm based on list2cmdline in the - * Python subprocess module. Returns a newly allocated string */ -char * -tor_join_win_cmdline(const char *argv[]) -{ - smartlist_t *argv_list; - char *joined_argv; - int i; - - /* Format each argument and put the result in a smartlist */ - argv_list = smartlist_new(); - for (i=0; argv[i] != NULL; i++) { - smartlist_add(argv_list, (void *)format_win_cmdline_argument(argv[i])); - } - - /* Join the arguments with whitespace */ - joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL); - - /* Free the newly allocated arguments, and the smartlist */ - SMARTLIST_FOREACH(argv_list, char *, arg, - { - tor_free(arg); - }); - smartlist_free(argv_list); - - return joined_argv; -} - -/* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument - * in range 2..16 inclusive. */ -static int -format_number_sigsafe(unsigned long x, char *buf, int buf_len, - unsigned int radix) -{ - unsigned long tmp; - int len; - char *cp; - - /* NOT tor_assert. This needs to be safe to run from within a signal handler, - * and from within the 'tor_assert() has failed' code. */ - if (radix < 2 || radix > 16) - return 0; - - /* Count how many digits we need. */ - tmp = x; - len = 1; - while (tmp >= radix) { - tmp /= radix; - ++len; - } - - /* Not long enough */ - if (!buf || len >= buf_len) - return 0; - - cp = buf + len; - *cp = '\0'; - do { - unsigned digit = (unsigned) (x % radix); - tor_assert(cp > buf); - --cp; - *cp = "0123456789ABCDEF"[digit]; - x /= radix; - } while (x); - - /* NOT tor_assert; see above. */ - if (cp != buf) { - abort(); // LCOV_EXCL_LINE - } - - return len; -} - -/** - * Helper function to output hex numbers from within a signal handler. - * - * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer - * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits - * written, not counting the terminal NUL. - * - * If there is insufficient space, write nothing and return 0. - * - * This accepts an unsigned int because format_helper_exit_status() needs to - * call it with a signed int and an unsigned char, and since the C standard - * does not guarantee that an int is wider than a char (an int must be at - * least 16 bits but it is permitted for a char to be that wide as well), we - * can't assume a signed int is sufficient to accommodate an unsigned char. - * Thus, format_helper_exit_status() will still need to emit any require '-' - * on its own. - * - * For most purposes, you'd want to use tor_snprintf("%x") instead of this - * function; it's designed to be used in code paths where you can't call - * arbitrary C functions. - */ -int -format_hex_number_sigsafe(unsigned long x, char *buf, int buf_len) -{ - return format_number_sigsafe(x, buf, buf_len, 16); -} - -/** As format_hex_number_sigsafe, but format the number in base 10. */ -int -format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len) -{ - return format_number_sigsafe(x, buf, buf_len, 10); -} - -#ifndef _WIN32 -/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in - * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler - * safe. - * - * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE+1 bytes available. - * - * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded - * with spaces. CHILD_STATE indicates where - * in the process of starting the child process did the failure occur (see - * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of - * errno when the failure occurred. - * - * On success return the number of characters added to hex_errno, not counting - * the terminating NUL; return -1 on error. - */ -STATIC int -format_helper_exit_status(unsigned char child_state, int saved_errno, - char *hex_errno) -{ - unsigned int unsigned_errno; - int written, left; - char *cur; - size_t i; - int res = -1; - - /* Fill hex_errno with spaces, and a trailing newline (memset may - not be signal handler safe, so we can't use it) */ - for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++) - hex_errno[i] = ' '; - hex_errno[HEX_ERRNO_SIZE - 1] = '\n'; - - /* Convert errno to be unsigned for hex conversion */ - if (saved_errno < 0) { - // Avoid overflow on the cast to unsigned int when result is INT_MIN - // by adding 1 to the signed int negative value, - // then, after it has been negated and cast to unsigned, - // adding the original 1 back (the double-addition is intentional). - // Otherwise, the cast to signed could cause a temporary int - // to equal INT_MAX + 1, which is undefined. - unsigned_errno = ((unsigned int) -(saved_errno + 1)) + 1; - } else { - unsigned_errno = (unsigned int) saved_errno; - } - - /* - * Count how many chars of space we have left, and keep a pointer into the - * current point in the buffer. - */ - left = HEX_ERRNO_SIZE+1; - cur = hex_errno; - - /* Emit child_state */ - written = format_hex_number_sigsafe(child_state, cur, left); - - if (written <= 0) - goto err; - - /* Adjust left and cur */ - left -= written; - cur += written; - if (left <= 0) - goto err; - - /* Now the '/' */ - *cur = '/'; - - /* Adjust left and cur */ - ++cur; - --left; - if (left <= 0) - goto err; - - /* Need minus? */ - if (saved_errno < 0) { - *cur = '-'; - ++cur; - --left; - if (left <= 0) - goto err; - } - - /* Emit unsigned_errno */ - written = format_hex_number_sigsafe(unsigned_errno, cur, left); - - if (written <= 0) - goto err; - - /* Adjust left and cur */ - left -= written; - cur += written; - - /* Check that we have enough space left for a newline and a NUL */ - if (left <= 1) - goto err; - - /* Emit the newline and NUL */ - *cur++ = '\n'; - *cur++ = '\0'; - - res = (int)(cur - hex_errno - 1); - - goto done; - - err: - /* - * In error exit, just write a '\0' in the first char so whatever called - * this at least won't fall off the end. - */ - *hex_errno = '\0'; - - done: - return res; -} -#endif /* !defined(_WIN32) */ - -/* Maximum number of file descriptors, if we cannot get it via sysconf() */ -#define DEFAULT_MAX_FD 256 - -/** Terminate the process of <b>process_handle</b>, if that process has not - * already exited. - * - * Return 0 if we succeeded in terminating the process (or if the process - * already exited), and -1 if we tried to kill the process but failed. - * - * Based on code originally borrowed from Python's os.kill. */ -int -tor_terminate_process(process_handle_t *process_handle) -{ -#ifdef _WIN32 - if (tor_get_exit_code(process_handle, 0, NULL) == PROCESS_EXIT_RUNNING) { - HANDLE handle = process_handle->pid.hProcess; - - if (!TerminateProcess(handle, 0)) - return -1; - else - return 0; - } -#else /* !(defined(_WIN32)) */ - if (process_handle->waitpid_cb) { - /* We haven't got a waitpid yet, so we can just kill off the process. */ - return kill(process_handle->pid, SIGTERM); - } -#endif /* defined(_WIN32) */ - - return 0; /* We didn't need to kill the process, so report success */ -} - -/** Return the Process ID of <b>process_handle</b>. */ -int -tor_process_get_pid(process_handle_t *process_handle) -{ -#ifdef _WIN32 - return (int) process_handle->pid.dwProcessId; -#else - return (int) process_handle->pid; -#endif -} - -#ifdef _WIN32 -HANDLE -tor_process_get_stdout_pipe(process_handle_t *process_handle) -{ - return process_handle->stdout_pipe; -} -#else /* !(defined(_WIN32)) */ -/* DOCDOC tor_process_get_stdout_pipe */ -int -tor_process_get_stdout_pipe(process_handle_t *process_handle) -{ - return process_handle->stdout_pipe; -} -#endif /* defined(_WIN32) */ - -/* DOCDOC process_handle_new */ -static process_handle_t * -process_handle_new(void) -{ - process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t)); - -#ifdef _WIN32 - out->stdin_pipe = INVALID_HANDLE_VALUE; - out->stdout_pipe = INVALID_HANDLE_VALUE; - out->stderr_pipe = INVALID_HANDLE_VALUE; -#else - out->stdin_pipe = -1; - out->stdout_pipe = -1; - out->stderr_pipe = -1; -#endif /* defined(_WIN32) */ - - return out; -} - -#ifndef _WIN32 -/** Invoked when a process that we've launched via tor_spawn_background() has - * been found to have terminated. - */ -static void -process_handle_waitpid_cb(int status, void *arg) -{ - process_handle_t *process_handle = arg; - - process_handle->waitpid_exit_status = status; - clear_waitpid_callback(process_handle->waitpid_cb); - if (process_handle->status == PROCESS_STATUS_RUNNING) - process_handle->status = PROCESS_STATUS_NOTRUNNING; - process_handle->waitpid_cb = 0; -} -#endif /* !defined(_WIN32) */ - -/** - * @name child-process states - * - * Each of these values represents a possible state that a child process can - * be in. They're used to determine what to say when telling the parent how - * far along we were before failure. - * - * @{ - */ -#define CHILD_STATE_INIT 0 -#define CHILD_STATE_PIPE 1 -#define CHILD_STATE_MAXFD 2 -#define CHILD_STATE_FORK 3 -#define CHILD_STATE_DUPOUT 4 -#define CHILD_STATE_DUPERR 5 -#define CHILD_STATE_DUPIN 6 -#define CHILD_STATE_CLOSEFD 7 -#define CHILD_STATE_EXEC 8 -#define CHILD_STATE_FAILEXEC 9 -/** @} */ -/** - * Boolean. If true, then Tor may call execve or CreateProcess via - * tor_spawn_background. - **/ -static int may_spawn_background_process = 1; -/** - * Turn off may_spawn_background_process, so that all future calls to - * tor_spawn_background are guaranteed to fail. - **/ -void -tor_disable_spawning_background_processes(void) -{ - may_spawn_background_process = 0; -} -/** Start a program in the background. If <b>filename</b> contains a '/', then - * it will be treated as an absolute or relative path. Otherwise, on - * non-Windows systems, the system path will be searched for <b>filename</b>. - * On Windows, only the current directory will be searched. Here, to search the - * system path (as well as the application directory, current working - * directory, and system directories), set filename to NULL. - * - * The strings in <b>argv</b> will be passed as the command line arguments of - * the child program (following convention, argv[0] should normally be the - * filename of the executable, and this must be the case if <b>filename</b> is - * NULL). The last element of argv must be NULL. A handle to the child process - * will be returned in process_handle (which must be non-NULL). Read - * process_handle.status to find out if the process was successfully launched. - * For convenience, process_handle.status is returned by this function. - * - * Some parts of this code are based on the POSIX subprocess module from - * Python, and example code from - * http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx. - */ -int -tor_spawn_background(const char *const filename, const char **argv, - process_environment_t *env, - process_handle_t **process_handle_out) -{ - if (BUG(may_spawn_background_process == 0)) { - /* We should never reach this point if we're forbidden to spawn - * processes. Instead we should have caught the attempt earlier. */ - return PROCESS_STATUS_ERROR; - } - -#ifdef _WIN32 - HANDLE stdout_pipe_read = NULL; - HANDLE stdout_pipe_write = NULL; - HANDLE stderr_pipe_read = NULL; - HANDLE stderr_pipe_write = NULL; - HANDLE stdin_pipe_read = NULL; - HANDLE stdin_pipe_write = NULL; - process_handle_t *process_handle; - int status; - - STARTUPINFOA siStartInfo; - BOOL retval = FALSE; - - SECURITY_ATTRIBUTES saAttr; - char *joined_argv; - - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - /* TODO: should we set explicit security attributes? (#2046, comment 5) */ - saAttr.lpSecurityDescriptor = NULL; - - /* Assume failure to start process */ - status = PROCESS_STATUS_ERROR; - - /* Set up pipe for stdout */ - if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &saAttr, 0)) { - log_warn(LD_GENERAL, - "Failed to create pipe for stdout communication with child process: %s", - format_win32_error(GetLastError())); - return status; - } - if (!SetHandleInformation(stdout_pipe_read, HANDLE_FLAG_INHERIT, 0)) { - log_warn(LD_GENERAL, - "Failed to configure pipe for stdout communication with child " - "process: %s", format_win32_error(GetLastError())); - return status; - } - - /* Set up pipe for stderr */ - if (!CreatePipe(&stderr_pipe_read, &stderr_pipe_write, &saAttr, 0)) { - log_warn(LD_GENERAL, - "Failed to create pipe for stderr communication with child process: %s", - format_win32_error(GetLastError())); - return status; - } - if (!SetHandleInformation(stderr_pipe_read, HANDLE_FLAG_INHERIT, 0)) { - log_warn(LD_GENERAL, - "Failed to configure pipe for stderr communication with child " - "process: %s", format_win32_error(GetLastError())); - return status; - } - - /* Set up pipe for stdin */ - if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, &saAttr, 0)) { - log_warn(LD_GENERAL, - "Failed to create pipe for stdin communication with child process: %s", - format_win32_error(GetLastError())); - return status; - } - if (!SetHandleInformation(stdin_pipe_write, HANDLE_FLAG_INHERIT, 0)) { - log_warn(LD_GENERAL, - "Failed to configure pipe for stdin communication with child " - "process: %s", format_win32_error(GetLastError())); - return status; - } - - /* Create the child process */ - - /* Windows expects argv to be a whitespace delimited string, so join argv up - */ - joined_argv = tor_join_win_cmdline(argv); - - process_handle = process_handle_new(); - process_handle->status = status; - - ZeroMemory(&(process_handle->pid), sizeof(PROCESS_INFORMATION)); - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - siStartInfo.cb = sizeof(STARTUPINFO); - siStartInfo.hStdError = stderr_pipe_write; - siStartInfo.hStdOutput = stdout_pipe_write; - siStartInfo.hStdInput = stdin_pipe_read; - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - /* Create the child process */ - - retval = CreateProcessA(filename, // module name - joined_argv, // command line - /* TODO: should we set explicit security attributes? (#2046, comment 5) */ - NULL, // process security attributes - NULL, // primary thread security attributes - TRUE, // handles are inherited - /*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess() - * work?) */ - CREATE_NO_WINDOW, // creation flags - (env==NULL) ? NULL : env->windows_environment_block, - NULL, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer - &(process_handle->pid)); // receives PROCESS_INFORMATION - - tor_free(joined_argv); - - if (!retval) { - log_warn(LD_GENERAL, - "Failed to create child process %s: %s", filename?filename:argv[0], - format_win32_error(GetLastError())); - tor_free(process_handle); - } else { - /* TODO: Close hProcess and hThread in process_handle->pid? */ - process_handle->stdout_pipe = stdout_pipe_read; - process_handle->stderr_pipe = stderr_pipe_read; - process_handle->stdin_pipe = stdin_pipe_write; - status = process_handle->status = PROCESS_STATUS_RUNNING; - } - - /* TODO: Close pipes on exit */ - *process_handle_out = process_handle; - return status; -#else /* !(defined(_WIN32)) */ - pid_t pid; - int stdout_pipe[2]; - int stderr_pipe[2]; - int stdin_pipe[2]; - int fd, retval; - process_handle_t *process_handle; - int status; - - const char *error_message = SPAWN_ERROR_MESSAGE; - size_t error_message_length; - - /* Represents where in the process of spawning the program is; - this is used for printing out the error message */ - unsigned char child_state = CHILD_STATE_INIT; - - char hex_errno[HEX_ERRNO_SIZE + 2]; /* + 1 should be sufficient actually */ - - static int max_fd = -1; - - status = PROCESS_STATUS_ERROR; - - /* We do the strlen here because strlen() is not signal handler safe, - and we are not allowed to use unsafe functions between fork and exec */ - error_message_length = strlen(error_message); - - // child_state = CHILD_STATE_PIPE; - - /* Set up pipe for redirecting stdout, stderr, and stdin of child */ - retval = pipe(stdout_pipe); - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to set up pipe for stdout communication with child process: %s", - strerror(errno)); - return status; - } - - retval = pipe(stderr_pipe); - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to set up pipe for stderr communication with child process: %s", - strerror(errno)); - - close(stdout_pipe[0]); - close(stdout_pipe[1]); - - return status; - } - - retval = pipe(stdin_pipe); - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to set up pipe for stdin communication with child process: %s", - strerror(errno)); - - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stderr_pipe[0]); - close(stderr_pipe[1]); - - return status; - } - - // child_state = CHILD_STATE_MAXFD; - -#ifdef _SC_OPEN_MAX - if (-1 == max_fd) { - max_fd = (int) sysconf(_SC_OPEN_MAX); - if (max_fd == -1) { - max_fd = DEFAULT_MAX_FD; - log_warn(LD_GENERAL, - "Cannot find maximum file descriptor, assuming %d", max_fd); - } - } -#else /* !(defined(_SC_OPEN_MAX)) */ - max_fd = DEFAULT_MAX_FD; -#endif /* defined(_SC_OPEN_MAX) */ - - // child_state = CHILD_STATE_FORK; - - pid = fork(); - if (0 == pid) { - /* In child */ - -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) - /* Attempt to have the kernel issue a SIGTERM if the parent - * goes away. Certain attributes of the binary being execve()ed - * will clear this during the execve() call, but it's better - * than nothing. - */ - prctl(PR_SET_PDEATHSIG, SIGTERM); -#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) */ - - child_state = CHILD_STATE_DUPOUT; - - /* Link child stdout to the write end of the pipe */ - retval = dup2(stdout_pipe[1], STDOUT_FILENO); - if (-1 == retval) - goto error; - - child_state = CHILD_STATE_DUPERR; - - /* Link child stderr to the write end of the pipe */ - retval = dup2(stderr_pipe[1], STDERR_FILENO); - if (-1 == retval) - goto error; - - child_state = CHILD_STATE_DUPIN; - - /* Link child stdin to the read end of the pipe */ - retval = dup2(stdin_pipe[0], STDIN_FILENO); - if (-1 == retval) - goto error; - - // child_state = CHILD_STATE_CLOSEFD; - - close(stderr_pipe[0]); - close(stderr_pipe[1]); - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stdin_pipe[0]); - close(stdin_pipe[1]); - - /* Close all other fds, including the read end of the pipe */ - /* XXX: We should now be doing enough FD_CLOEXEC setting to make - * this needless. */ - for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) { - close(fd); - } - - // child_state = CHILD_STATE_EXEC; - - /* Call the requested program. We need the cast because - execvp doesn't define argv as const, even though it - does not modify the arguments */ - if (env) - execve(filename, (char *const *) argv, env->unixoid_environment_block); - else { - static char *new_env[] = { NULL }; - execve(filename, (char *const *) argv, new_env); - } - - /* If we got here, the exec or open(/dev/null) failed */ - - child_state = CHILD_STATE_FAILEXEC; - - error: - { - /* XXX: are we leaking fds from the pipe? */ - int n, err=0; - ssize_t nbytes; - - n = format_helper_exit_status(child_state, errno, hex_errno); - - if (n >= 0) { - /* Write the error message. GCC requires that we check the return - value, but there is nothing we can do if it fails */ - /* TODO: Don't use STDOUT, use a pipe set up just for this purpose */ - nbytes = write(STDOUT_FILENO, error_message, error_message_length); - err = (nbytes < 0); - nbytes = write(STDOUT_FILENO, hex_errno, n); - err += (nbytes < 0); - } - - _exit(err?254:255); // exit ok: in child. - } - - /* Never reached, but avoids compiler warning */ - return status; // LCOV_EXCL_LINE - } - - /* In parent */ - - if (-1 == pid) { - log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno)); - close(stdin_pipe[0]); - close(stdin_pipe[1]); - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stderr_pipe[0]); - close(stderr_pipe[1]); - return status; - } - - process_handle = process_handle_new(); - process_handle->status = status; - process_handle->pid = pid; - - /* TODO: If the child process forked but failed to exec, waitpid it */ - - /* Return read end of the pipes to caller, and close write end */ - process_handle->stdout_pipe = stdout_pipe[0]; - retval = close(stdout_pipe[1]); - - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to close write end of stdout pipe in parent process: %s", - strerror(errno)); - } - - process_handle->waitpid_cb = set_waitpid_callback(pid, - process_handle_waitpid_cb, - process_handle); - - process_handle->stderr_pipe = stderr_pipe[0]; - retval = close(stderr_pipe[1]); - - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to close write end of stderr pipe in parent process: %s", - strerror(errno)); - } - - /* Return write end of the stdin pipe to caller, and close the read end */ - process_handle->stdin_pipe = stdin_pipe[1]; - retval = close(stdin_pipe[0]); - - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to close read end of stdin pipe in parent process: %s", - strerror(errno)); - } - - status = process_handle->status = PROCESS_STATUS_RUNNING; - /* Set stdin/stdout/stderr pipes to be non-blocking */ - if (fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK) < 0 || - fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0 || - fcntl(process_handle->stdin_pipe, F_SETFL, O_NONBLOCK) < 0) { - log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes " - "nonblocking in parent process: %s", strerror(errno)); - } - - *process_handle_out = process_handle; - return status; -#endif /* defined(_WIN32) */ -} - -/** Destroy all resources allocated by the process handle in - * <b>process_handle</b>. - * If <b>also_terminate_process</b> is true, also terminate the - * process of the process handle. */ -MOCK_IMPL(void, -tor_process_handle_destroy,(process_handle_t *process_handle, - int also_terminate_process)) -{ - if (!process_handle) - return; - - if (also_terminate_process) { - if (tor_terminate_process(process_handle) < 0) { - const char *errstr = -#ifdef _WIN32 - format_win32_error(GetLastError()); -#else - strerror(errno); -#endif - log_notice(LD_GENERAL, "Failed to terminate process with " - "PID '%d' ('%s').", tor_process_get_pid(process_handle), - errstr); - } else { - log_info(LD_GENERAL, "Terminated process with PID '%d'.", - tor_process_get_pid(process_handle)); - } - } - - process_handle->status = PROCESS_STATUS_NOTRUNNING; - -#ifdef _WIN32 - if (process_handle->stdout_pipe) - CloseHandle(process_handle->stdout_pipe); - - if (process_handle->stderr_pipe) - CloseHandle(process_handle->stderr_pipe); - - if (process_handle->stdin_pipe) - CloseHandle(process_handle->stdin_pipe); -#else /* !(defined(_WIN32)) */ - close(process_handle->stdout_pipe); - close(process_handle->stderr_pipe); - close(process_handle->stdin_pipe); - - clear_waitpid_callback(process_handle->waitpid_cb); -#endif /* defined(_WIN32) */ - - memset(process_handle, 0x0f, sizeof(process_handle_t)); - tor_free(process_handle); -} - -/** Get the exit code of a process specified by <b>process_handle</b> and store - * it in <b>exit_code</b>, if set to a non-NULL value. If <b>block</b> is set - * to true, the call will block until the process has exited. Otherwise if - * the process is still running, the function will return - * PROCESS_EXIT_RUNNING, and exit_code will be left unchanged. Returns - * PROCESS_EXIT_EXITED if the process did exit. If there is a failure, - * PROCESS_EXIT_ERROR will be returned and the contents of exit_code (if - * non-NULL) will be undefined. N.B. Under *nix operating systems, this will - * probably not work in Tor, because waitpid() is called in main.c to reap any - * terminated child processes.*/ -int -tor_get_exit_code(process_handle_t *process_handle, - int block, int *exit_code) -{ -#ifdef _WIN32 - DWORD retval; - BOOL success; - - if (block) { - /* Wait for the process to exit */ - retval = WaitForSingleObject(process_handle->pid.hProcess, INFINITE); - if (retval != WAIT_OBJECT_0) { - log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", - (int)retval, format_win32_error(GetLastError())); - return PROCESS_EXIT_ERROR; - } - } else { - retval = WaitForSingleObject(process_handle->pid.hProcess, 0); - if (WAIT_TIMEOUT == retval) { - /* Process has not exited */ - return PROCESS_EXIT_RUNNING; - } else if (retval != WAIT_OBJECT_0) { - log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", - (int)retval, format_win32_error(GetLastError())); - return PROCESS_EXIT_ERROR; - } - } - - if (exit_code != NULL) { - success = GetExitCodeProcess(process_handle->pid.hProcess, - (PDWORD)exit_code); - if (!success) { - log_warn(LD_GENERAL, "GetExitCodeProcess() failed: %s", - format_win32_error(GetLastError())); - return PROCESS_EXIT_ERROR; - } - } -#else /* !(defined(_WIN32)) */ - int stat_loc; - int retval; - - if (process_handle->waitpid_cb) { - /* We haven't processed a SIGCHLD yet. */ - retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG); - if (retval == process_handle->pid) { - clear_waitpid_callback(process_handle->waitpid_cb); - process_handle->waitpid_cb = NULL; - process_handle->waitpid_exit_status = stat_loc; - } - } else { - /* We already got a SIGCHLD for this process, and handled it. */ - retval = process_handle->pid; - stat_loc = process_handle->waitpid_exit_status; - } - - if (!block && 0 == retval) { - /* Process has not exited */ - return PROCESS_EXIT_RUNNING; - } else if (retval != process_handle->pid) { - log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s", - (int)process_handle->pid, strerror(errno)); - return PROCESS_EXIT_ERROR; - } - - if (!WIFEXITED(stat_loc)) { - log_warn(LD_GENERAL, "Process %d did not exit normally", - (int)process_handle->pid); - return PROCESS_EXIT_ERROR; - } - - if (exit_code != NULL) - *exit_code = WEXITSTATUS(stat_loc); -#endif /* defined(_WIN32) */ - - return PROCESS_EXIT_EXITED; -} - -/** Helper: return the number of characters in <b>s</b> preceding the first - * occurrence of <b>ch</b>. If <b>ch</b> does not occur in <b>s</b>, return - * the length of <b>s</b>. Should be equivalent to strspn(s, "ch"). */ -static inline size_t -str_num_before(const char *s, char ch) -{ - const char *cp = strchr(s, ch); - if (cp) - return cp - s; - else - return strlen(s); -} - -/** Return non-zero iff getenv would consider <b>s1</b> and <b>s2</b> - * to have the same name as strings in a process's environment. */ -int -environment_variable_names_equal(const char *s1, const char *s2) -{ - size_t s1_name_len = str_num_before(s1, '='); - size_t s2_name_len = str_num_before(s2, '='); - - return (s1_name_len == s2_name_len && - tor_memeq(s1, s2, s1_name_len)); -} - -/** Free <b>env</b> (assuming it was produced by - * process_environment_make). */ -void -process_environment_free_(process_environment_t *env) -{ - if (env == NULL) return; - - /* As both an optimization hack to reduce consing on Unixoid systems - * and a nice way to ensure that some otherwise-Windows-specific - * code will always get tested before changes to it get merged, the - * strings which env->unixoid_environment_block points to are packed - * into env->windows_environment_block. */ - tor_free(env->unixoid_environment_block); - tor_free(env->windows_environment_block); - - tor_free(env); -} - -/** Make a process_environment_t containing the environment variables - * specified in <b>env_vars</b> (as C strings of the form - * "NAME=VALUE"). */ -process_environment_t * -process_environment_make(struct smartlist_t *env_vars) -{ - process_environment_t *env = tor_malloc_zero(sizeof(process_environment_t)); - int n_env_vars = smartlist_len(env_vars); - int i; - size_t total_env_length; - smartlist_t *env_vars_sorted; - - tor_assert(n_env_vars + 1 != 0); - env->unixoid_environment_block = tor_calloc(n_env_vars + 1, sizeof(char *)); - /* env->unixoid_environment_block is already NULL-terminated, - * because we assume that NULL == 0 (and check that during compilation). */ - - total_env_length = 1; /* terminating NUL of terminating empty string */ - for (i = 0; i < n_env_vars; ++i) { - const char *s = smartlist_get(env_vars, i); - size_t slen = strlen(s); - - tor_assert(slen + 1 != 0); - tor_assert(slen + 1 < SIZE_MAX - total_env_length); - total_env_length += slen + 1; - } - - env->windows_environment_block = tor_malloc_zero(total_env_length); - /* env->windows_environment_block is already - * (NUL-terminated-empty-string)-terminated. */ - - /* Some versions of Windows supposedly require that environment - * blocks be sorted. Or maybe some Windows programs (or their - * runtime libraries) fail to look up strings in non-sorted - * environment blocks. - * - * Also, sorting strings makes it easy to find duplicate environment - * variables and environment-variable strings without an '=' on all - * OSes, and they can cause badness. Let's complain about those. */ - env_vars_sorted = smartlist_new(); - smartlist_add_all(env_vars_sorted, env_vars); - smartlist_sort_strings(env_vars_sorted); - - /* Now copy the strings into the environment blocks. */ - { - char *cp = env->windows_environment_block; - const char *prev_env_var = NULL; - - for (i = 0; i < n_env_vars; ++i) { - const char *s = smartlist_get(env_vars_sorted, i); - size_t slen = strlen(s); - size_t s_name_len = str_num_before(s, '='); - - if (s_name_len == slen) { - log_warn(LD_GENERAL, - "Preparing an environment containing a variable " - "without a value: %s", - s); - } - if (prev_env_var != NULL && - environment_variable_names_equal(s, prev_env_var)) { - log_warn(LD_GENERAL, - "Preparing an environment containing two variables " - "with the same name: %s and %s", - prev_env_var, s); - } - - prev_env_var = s; - - /* Actually copy the string into the environment. */ - memcpy(cp, s, slen+1); - env->unixoid_environment_block[i] = cp; - cp += slen+1; - } - - tor_assert(cp == env->windows_environment_block + total_env_length - 1); - } - - smartlist_free(env_vars_sorted); - - return env; -} - -/** Return a newly allocated smartlist containing every variable in - * this process's environment, as a NUL-terminated string of the form - * "NAME=VALUE". Note that on some/many/most/all OSes, the parent - * process can put strings not of that form in our environment; - * callers should try to not get crashed by that. - * - * The returned strings are heap-allocated, and must be freed by the - * caller. */ -struct smartlist_t * -get_current_process_environment_variables(void) -{ - smartlist_t *sl = smartlist_new(); - - char **environ_tmp; /* Not const char ** ? Really? */ - for (environ_tmp = get_environment(); *environ_tmp; ++environ_tmp) { - smartlist_add_strdup(sl, *environ_tmp); - } - - return sl; -} - -/** For each string s in <b>env_vars</b> such that - * environment_variable_names_equal(s, <b>new_var</b>), remove it; if - * <b>free_p</b> is non-zero, call <b>free_old</b>(s). If - * <b>new_var</b> contains '=', insert it into <b>env_vars</b>. */ -void -set_environment_variable_in_smartlist(struct smartlist_t *env_vars, - const char *new_var, - void (*free_old)(void*), - int free_p) -{ - SMARTLIST_FOREACH_BEGIN(env_vars, const char *, s) { - if (environment_variable_names_equal(s, new_var)) { - SMARTLIST_DEL_CURRENT(env_vars, s); - if (free_p) { - free_old((void *)s); - } - } - } SMARTLIST_FOREACH_END(s); - - if (strchr(new_var, '=') != NULL) { - smartlist_add(env_vars, (void *)new_var); - } -} - -#ifdef _WIN32 -/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If - * <b>hProcess</b> is NULL, the function will return immediately if there is - * nothing more to read. Otherwise <b>hProcess</b> should be set to the handle - * to the process owning the <b>h</b>. In this case, the function will exit - * only once the process has exited, or <b>count</b> bytes are read. Returns - * the number of bytes read, or -1 on error. */ -ssize_t -tor_read_all_handle(HANDLE h, char *buf, size_t count, - const process_handle_t *process) -{ - size_t numread = 0; - BOOL retval; - DWORD byte_count; - BOOL process_exited = FALSE; - - if (count > SIZE_T_CEILING || count > SSIZE_MAX) - return -1; - - while (numread < count) { - /* Check if there is anything to read */ - retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL); - if (!retval) { - log_warn(LD_GENERAL, - "Failed to peek from handle: %s", - format_win32_error(GetLastError())); - return -1; - } else if (0 == byte_count) { - /* Nothing available: process exited or it is busy */ - - /* Exit if we don't know whether the process is running */ - if (NULL == process) - break; - - /* The process exited and there's nothing left to read from it */ - if (process_exited) - break; - - /* If process is not running, check for output one more time in case - it wrote something after the peek was performed. Otherwise keep on - waiting for output */ - tor_assert(process != NULL); - byte_count = WaitForSingleObject(process->pid.hProcess, 0); - if (WAIT_TIMEOUT != byte_count) - process_exited = TRUE; - - continue; - } - - /* There is data to read; read it */ - retval = ReadFile(h, buf+numread, count-numread, &byte_count, NULL); - tor_assert(byte_count + numread <= count); - if (!retval) { - log_warn(LD_GENERAL, "Failed to read from handle: %s", - format_win32_error(GetLastError())); - return -1; - } else if (0 == byte_count) { - /* End of file */ - break; - } - numread += byte_count; - } - return (ssize_t)numread; -} -#else /* !(defined(_WIN32)) */ -/** Read from a handle <b>fd</b> into <b>buf</b>, up to <b>count</b> bytes. If - * <b>process</b> is NULL, the function will return immediately if there is - * nothing more to read. Otherwise data will be read until end of file, or - * <b>count</b> bytes are read. Returns the number of bytes read, or -1 on - * error. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the - * file has been reached. */ -ssize_t -tor_read_all_handle(int fd, char *buf, size_t count, - const process_handle_t *process, - int *eof) -{ - size_t numread = 0; - ssize_t result; - - if (eof) - *eof = 0; - - if (count > SIZE_T_CEILING || count > SSIZE_MAX) - return -1; - - while (numread < count) { - result = read(fd, buf+numread, count-numread); - - if (result == 0) { - log_debug(LD_GENERAL, "read() reached end of file"); - if (eof) - *eof = 1; - break; - } else if (result < 0 && errno == EAGAIN) { - if (process) - continue; - else - break; - } else if (result < 0) { - log_warn(LD_GENERAL, "read() failed: %s", strerror(errno)); - return -1; - } - - numread += result; - } - - log_debug(LD_GENERAL, "read() read %d bytes from handle", (int)numread); - return (ssize_t)numread; -} -#endif /* defined(_WIN32) */ - -/** Read from stdout of a process until the process exits. */ -ssize_t -tor_read_all_from_process_stdout(const process_handle_t *process_handle, - char *buf, size_t count) -{ -#ifdef _WIN32 - return tor_read_all_handle(process_handle->stdout_pipe, buf, count, - process_handle); -#else - return tor_read_all_handle(process_handle->stdout_pipe, buf, count, - process_handle, NULL); -#endif /* defined(_WIN32) */ -} - -/** Read from stdout of a process until the process exits. */ -ssize_t -tor_read_all_from_process_stderr(const process_handle_t *process_handle, - char *buf, size_t count) -{ -#ifdef _WIN32 - return tor_read_all_handle(process_handle->stderr_pipe, buf, count, - process_handle); -#else - return tor_read_all_handle(process_handle->stderr_pipe, buf, count, - process_handle, NULL); -#endif /* defined(_WIN32) */ -} - -/** Split buf into lines, and add to smartlist. The buffer <b>buf</b> will be - * modified. The resulting smartlist will consist of pointers to buf, so there - * is no need to free the contents of sl. <b>buf</b> must be a NUL-terminated - * string. <b>len</b> should be set to the length of the buffer excluding the - * NUL. Non-printable characters (including NUL) will be replaced with "." */ -int -tor_split_lines(smartlist_t *sl, char *buf, int len) -{ - /* Index in buf of the start of the current line */ - int start = 0; - /* Index in buf of the current character being processed */ - int cur = 0; - /* Are we currently in a line */ - char in_line = 0; - - /* Loop over string */ - while (cur < len) { - /* Loop until end of line or end of string */ - for (; cur < len; cur++) { - if (in_line) { - if ('\r' == buf[cur] || '\n' == buf[cur]) { - /* End of line */ - buf[cur] = '\0'; - /* Point cur to the next line */ - cur++; - /* Line starts at start and ends with a nul */ - break; - } else { - if (!TOR_ISPRINT(buf[cur])) - buf[cur] = '.'; - } - } else { - if ('\r' == buf[cur] || '\n' == buf[cur]) { - /* Skip leading vertical space */ - ; - } else { - in_line = 1; - start = cur; - if (!TOR_ISPRINT(buf[cur])) - buf[cur] = '.'; - } - } - } - /* We are at the end of the line or end of string. If in_line is true there - * is a line which starts at buf+start and ends at a NUL. cur points to - * the character after the NUL. */ - if (in_line) - smartlist_add(sl, (void *)(buf+start)); - in_line = 0; - } - return smartlist_len(sl); -} - -/** Return a string corresponding to <b>stream_status</b>. */ -const char * -stream_status_to_string(enum stream_status stream_status) -{ - switch (stream_status) { - case IO_STREAM_OKAY: - return "okay"; - case IO_STREAM_EAGAIN: - return "temporarily unavailable"; - case IO_STREAM_TERM: - return "terminated"; - case IO_STREAM_CLOSED: - return "closed"; - default: - tor_fragile_assert(); - return "unknown"; - } -} - -#ifdef _WIN32 - -/** Return a smartlist containing lines outputted from - * <b>handle</b>. Return NULL on error, and set - * <b>stream_status_out</b> appropriately. */ -MOCK_IMPL(smartlist_t *, -tor_get_lines_from_handle, (HANDLE *handle, - enum stream_status *stream_status_out)) -{ - int pos; - char stdout_buf[600] = {0}; - smartlist_t *lines = NULL; - - tor_assert(stream_status_out); - - *stream_status_out = IO_STREAM_TERM; - - pos = tor_read_all_handle(handle, stdout_buf, sizeof(stdout_buf) - 1, NULL); - if (pos < 0) { - *stream_status_out = IO_STREAM_TERM; - return NULL; - } - if (pos == 0) { - *stream_status_out = IO_STREAM_EAGAIN; - return NULL; - } - - /* End with a null even if there isn't a \r\n at the end */ - /* TODO: What if this is a partial line? */ - stdout_buf[pos] = '\0'; - - /* Split up the buffer */ - lines = smartlist_new(); - tor_split_lines(lines, stdout_buf, pos); - - /* Currently 'lines' is populated with strings residing on the - stack. Replace them with their exact copies on the heap: */ - SMARTLIST_FOREACH(lines, char *, line, - SMARTLIST_REPLACE_CURRENT(lines, line, tor_strdup(line))); - - *stream_status_out = IO_STREAM_OKAY; - - return lines; -} - -#else /* !(defined(_WIN32)) */ - -/** Return a smartlist containing lines outputted from - * <b>fd</b>. Return NULL on error, and set - * <b>stream_status_out</b> appropriately. */ -MOCK_IMPL(smartlist_t *, -tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out)) -{ - enum stream_status stream_status; - char stdout_buf[400]; - smartlist_t *lines = NULL; - - while (1) { - memset(stdout_buf, 0, sizeof(stdout_buf)); - - stream_status = get_string_from_pipe(fd, - stdout_buf, sizeof(stdout_buf) - 1); - if (stream_status != IO_STREAM_OKAY) - goto done; - - if (!lines) lines = smartlist_new(); - smartlist_split_string(lines, stdout_buf, "\n", 0, 0); - } - - done: - *stream_status_out = stream_status; - return lines; -} - -#endif /* defined(_WIN32) */ - -/** Reads from <b>fd</b> and stores input in <b>buf_out</b> making - * sure it's below <b>count</b> bytes. - * If the string has a trailing newline, we strip it off. - * - * This function is specifically created to handle input from managed - * proxies, according to the pluggable transports spec. Make sure it - * fits your needs before using it. - * - * Returns: - * IO_STREAM_CLOSED: If the stream is closed. - * IO_STREAM_EAGAIN: If there is nothing to read and we should check back - * later. - * IO_STREAM_TERM: If something is wrong with the stream. - * IO_STREAM_OKAY: If everything went okay and we got a string - * in <b>buf_out</b>. */ -enum stream_status -get_string_from_pipe(int fd, char *buf_out, size_t count) -{ - ssize_t ret; - - tor_assert(count <= INT_MAX); - - ret = read(fd, buf_out, count); - - if (ret == 0) - return IO_STREAM_CLOSED; - else if (ret < 0 && errno == EAGAIN) - return IO_STREAM_EAGAIN; - else if (ret < 0) - return IO_STREAM_TERM; - - if (buf_out[ret - 1] == '\n') { - /* Remove the trailing newline */ - buf_out[ret - 1] = '\0'; - } else - buf_out[ret] = '\0'; - - return IO_STREAM_OKAY; -} - -/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */ -void -tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed) -{ - rng->state = (uint32_t)(seed & 0x7fffffff); -} - -/** Return a randomly chosen value in the range 0..TOR_WEAK_RANDOM_MAX based - * on the RNG state of <b>rng</b>. This entropy will not be cryptographically - * strong; do not rely on it for anything an adversary should not be able to - * predict. */ -int32_t -tor_weak_random(tor_weak_rng_t *rng) -{ - /* Here's a linear congruential generator. OpenBSD and glibc use these - * parameters; they aren't too bad, and should have maximal period over the - * range 0..INT32_MAX. We don't want to use the platform rand() or random(), - * since some platforms have bad weak RNGs that only return values in the - * range 0..INT16_MAX, which just isn't enough. */ - rng->state = (rng->state * 1103515245 + 12345) & 0x7fffffff; - return (int32_t) rng->state; -} - -/** Return a random number in the range [0 , <b>top</b>). {That is, the range - * of integers i such that 0 <= i < top.} Chooses uniformly. Requires that - * top is greater than 0. This randomness is not cryptographically strong; do - * not rely on it for anything an adversary should not be able to predict. */ -int32_t -tor_weak_random_range(tor_weak_rng_t *rng, int32_t top) -{ - /* We don't want to just do tor_weak_random() % top, since random() is often - * implemented with an LCG whose modulus is a power of 2, and those are - * cyclic in their low-order bits. */ - int divisor, result; - tor_assert(top > 0); - divisor = TOR_WEAK_RANDOM_MAX / top; - do { - result = (int32_t)(tor_weak_random(rng) / divisor); - } while (result >= top); - return result; -} - -/** Cast a given double value to a int64_t. Return 0 if number is NaN. - * Returns either INT64_MIN or INT64_MAX if number is outside of the int64_t - * range. */ -int64_t -clamp_double_to_int64(double number) -{ - int exponent; - -#if defined(MINGW_ANY) && GCC_VERSION >= 409 -/* - Mingw's math.h uses gcc's __builtin_choose_expr() facility to declare - isnan, isfinite, and signbit. But as implemented in at least some - versions of gcc, __builtin_choose_expr() can generate type warnings - even from branches that are not taken. So, suppress those warnings. -*/ -#define PROBLEMATIC_FLOAT_CONVERSION_WARNING -DISABLE_GCC_WARNING(float-conversion) -#endif /* defined(MINGW_ANY) && GCC_VERSION >= 409 */ - -/* - With clang 4.0 we apparently run into "double promotion" warnings here, - since clang thinks we're promoting a double to a long double. - */ -#if defined(__clang__) -#if __has_warning("-Wdouble-promotion") -#define PROBLEMATIC_DOUBLE_PROMOTION_WARNING -DISABLE_GCC_WARNING(double-promotion) -#endif -#endif /* defined(__clang__) */ - - /* NaN is a special case that can't be used with the logic below. */ - if (isnan(number)) { - return 0; - } - - /* Time to validate if result can overflows a int64_t value. Fun with - * float! Find that exponent exp such that - * number == x * 2^exp - * for some x with abs(x) in [0.5, 1.0). Note that this implies that the - * magnitude of number is strictly less than 2^exp. - * - * If number is infinite, the call to frexp is legal but the contents of - * are exponent unspecified. */ - frexp(number, &exponent); - - /* If the magnitude of number is strictly less than 2^63, the truncated - * version of number is guaranteed to be representable. The only - * representable integer for which this is not the case is INT64_MIN, but - * it is covered by the logic below. */ - if (isfinite(number) && exponent <= 63) { - return (int64_t)number; - } - - /* Handle infinities and finite numbers with magnitude >= 2^63. */ - return signbit(number) ? INT64_MIN : INT64_MAX; - -#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING -ENABLE_GCC_WARNING(double-promotion) -#endif -#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING -ENABLE_GCC_WARNING(float-conversion) -#endif -} - -/** Return a uint64_t value from <b>a</b> in network byte order. */ -uint64_t -tor_htonll(uint64_t a) -{ -#ifdef WORDS_BIGENDIAN - /* Big endian. */ - return a; -#else /* WORDS_BIGENDIAN */ - /* Little endian. The worst... */ - return htonl((uint32_t)(a>>32)) | - (((uint64_t)htonl((uint32_t)a))<<32); -#endif /* defined(WORDS_BIGENDIAN) */ -} - -/** Return a uint64_t value from <b>a</b> in host byte order. */ -uint64_t -tor_ntohll(uint64_t a) -{ - return tor_htonll(a); -} - diff --git a/src/common/util.h b/src/common/util.h deleted file mode 100644 index 7172b7da08..0000000000 --- a/src/common/util.h +++ /dev/null @@ -1,572 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util.h - * \brief Headers for util.c - **/ - -#ifndef TOR_UTIL_H -#define TOR_UTIL_H - -#include "orconfig.h" -#include "torint.h" -#include "compat.h" -#include "di_ops.h" -#include "testsupport.h" -#include <stdio.h> -#include <stdlib.h> -#ifdef _WIN32 -/* for the correct alias to struct stat */ -#include <sys/stat.h> -#endif -#include "util_bug.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef O_TEXT -#define O_TEXT 0 -#endif -#ifndef O_NOFOLLOW -#define O_NOFOLLOW 0 -#endif - -/* If we're building with dmalloc, we want all of our memory allocation - * functions to take an extra file/line pair of arguments. If not, not. - * We define DMALLOC_PARAMS to the extra parameters to insert in the - * function prototypes, and DMALLOC_ARGS to the extra arguments to add - * to calls. */ -#ifdef USE_DMALLOC -#define DMALLOC_PARAMS , const char *file, const int line -#define DMALLOC_ARGS , SHORT_FILE__, __LINE__ -#else -#define DMALLOC_PARAMS -#define DMALLOC_ARGS -#endif /* defined(USE_DMALLOC) */ - -/* Memory management */ -void *tor_malloc_(size_t size DMALLOC_PARAMS) ATTR_MALLOC; -void *tor_malloc_zero_(size_t size DMALLOC_PARAMS) ATTR_MALLOC; -void *tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC; -void *tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS); -void *tor_reallocarray_(void *ptr, size_t size1, size_t size2 DMALLOC_PARAMS); -char *tor_strdup_(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1)); -char *tor_strndup_(const char *s, size_t n DMALLOC_PARAMS) - ATTR_MALLOC ATTR_NONNULL((1)); -void *tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS) - ATTR_MALLOC ATTR_NONNULL((1)); -void *tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS) - ATTR_MALLOC ATTR_NONNULL((1)); -void tor_free_(void *mem); -uint64_t tor_htonll(uint64_t a); -uint64_t tor_ntohll(uint64_t a); -#ifdef USE_DMALLOC -extern int dmalloc_free(const char *file, const int line, void *pnt, - const int func_id); -#define tor_free(p) STMT_BEGIN \ - if (PREDICT_LIKELY((p)!=NULL)) { \ - dmalloc_free(SHORT_FILE__, __LINE__, (p), 0); \ - (p)=NULL; \ - } \ - STMT_END -#else /* !(defined(USE_DMALLOC)) */ -/** Release memory allocated by tor_malloc, tor_realloc, tor_strdup, - * etc. Unlike the free() function, the tor_free() macro sets the - * pointer value to NULL after freeing it. - * - * This is a macro. If you need a function pointer to release memory from - * tor_malloc(), use tor_free_(). - * - * Note that this macro takes the address of the pointer it is going to - * free and clear. If that pointer is stored with a nonstandard - * alignment (eg because of a "packed" pragma) it is not correct to use - * tor_free(). - */ -#ifdef __GNUC__ -#define tor_free(p) STMT_BEGIN \ - typeof(&(p)) tor_free__tmpvar = &(p); \ - raw_free(*tor_free__tmpvar); \ - *tor_free__tmpvar=NULL; \ - STMT_END -#else -#define tor_free(p) STMT_BEGIN \ - raw_free(p); \ - (p)=NULL; \ - STMT_END -#endif -#endif /* defined(USE_DMALLOC) */ - -#define tor_malloc(size) tor_malloc_(size DMALLOC_ARGS) -#define tor_malloc_zero(size) tor_malloc_zero_(size DMALLOC_ARGS) -#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size DMALLOC_ARGS) -#define tor_realloc(ptr, size) tor_realloc_(ptr, size DMALLOC_ARGS) -#define tor_reallocarray(ptr, sz1, sz2) \ - tor_reallocarray_((ptr), (sz1), (sz2) DMALLOC_ARGS) -#define tor_strdup(s) tor_strdup_(s DMALLOC_ARGS) -#define tor_strndup(s, n) tor_strndup_(s, n DMALLOC_ARGS) -#define tor_memdup(s, n) tor_memdup_(s, n DMALLOC_ARGS) -#define tor_memdup_nulterm(s, n) tor_memdup_nulterm_(s, n DMALLOC_ARGS) - -/* Aliases for the underlying system malloc/realloc/free. Only use - * them to indicate "I really want the underlying system function, I know - * what I'm doing." */ -#define raw_malloc malloc -#define raw_realloc realloc -#define raw_free free -#define raw_strdup strdup - -void tor_log_mallinfo(int severity); - -/* Helper macro: free a variable of type 'typename' using freefn, and - * set the variable to NULL. - */ -#define FREE_AND_NULL(typename, freefn, var) \ - do { \ - /* only evaluate (var) once. */ \ - typename **tmp__free__ptr ## freefn = &(var); \ - freefn(*tmp__free__ptr ## freefn); \ - (*tmp__free__ptr ## freefn) = NULL; \ - } while (0) - -/** Macro: yield a pointer to the field at position <b>off</b> within the - * structure <b>st</b>. Example: - * <pre> - * struct a { int foo; int bar; } x; - * off_t bar_offset = offsetof(struct a, bar); - * int *bar_p = STRUCT_VAR_P(&x, bar_offset); - * *bar_p = 3; - * </pre> - */ -#define STRUCT_VAR_P(st, off) ((void*) ( ((char*)(st)) + (off) ) ) - -/** Macro: yield a pointer to an enclosing structure given a pointer to - * a substructure at offset <b>off</b>. Example: - * <pre> - * struct base { ... }; - * struct subtype { int x; struct base b; } x; - * struct base *bp = &x.base; - * struct *sp = SUBTYPE_P(bp, struct subtype, b); - * </pre> - */ -#define SUBTYPE_P(p, subtype, basemember) \ - ((void*) ( ((char*)(p)) - offsetof(subtype, basemember) )) - -/* Logic */ -/** Macro: true if two values have the same boolean value. */ -#define bool_eq(a,b) (!(a)==!(b)) -/** Macro: true if two values have different boolean values. */ -#define bool_neq(a,b) (!(a)!=!(b)) - -/* Math functions */ -double tor_mathlog(double d) ATTR_CONST; -long tor_lround(double d) ATTR_CONST; -int64_t tor_llround(double d) ATTR_CONST; -int tor_log2(uint64_t u64) ATTR_CONST; -uint64_t round_to_power_of_2(uint64_t u64); -unsigned round_to_next_multiple_of(unsigned number, unsigned divisor); -uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor); -uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor); -int64_t sample_laplace_distribution(double mu, double b, double p); -int64_t add_laplace_noise(int64_t signal, double random, double delta_f, - double epsilon); -int n_bits_set_u8(uint8_t v); -int64_t clamp_double_to_int64(double number); -void simplify_fraction64(uint64_t *numer, uint64_t *denom); - -uint32_t tor_add_u32_nowrap(uint32_t a, uint32_t b); - -/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b> - * and positive <b>b</b>. Works on integer types only. Not defined if a+(b-1) - * can overflow. */ -#define CEIL_DIV(a,b) (((a)+((b)-1))/(b)) - -/* Return <b>v</b> if it's between <b>min</b> and <b>max</b>. Otherwise - * return <b>min</b> if <b>v</b> is smaller than <b>min</b>, or <b>max</b> if - * <b>b</b> is larger than <b>max</b>. - * - * Requires that <b>min</b> is no more than <b>max</b>. May evaluate any of - * its arguments more than once! */ -#define CLAMP(min,v,max) \ - ( ((v) < (min)) ? (min) : \ - ((v) > (max)) ? (max) : \ - (v) ) - -/* String manipulation */ - -/** Allowable characters in a hexadecimal string. */ -#define HEX_CHARACTERS "0123456789ABCDEFabcdef" -void tor_strlower(char *s) ATTR_NONNULL((1)); -void tor_strupper(char *s) ATTR_NONNULL((1)); -int tor_strisprint(const char *s) ATTR_NONNULL((1)); -int tor_strisnonupper(const char *s) ATTR_NONNULL((1)); -int tor_strisspace(const char *s); -int strcmp_opt(const char *s1, const char *s2); -int strcmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int strcmp_len(const char *s1, const char *s2, size_t len) ATTR_NONNULL((1,2)); -int strcasecmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int strcmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int strcasecmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix); - -void tor_strstrip(char *s, const char *strip) ATTR_NONNULL((1,2)); -long tor_parse_long(const char *s, int base, long min, - long max, int *ok, char **next); -unsigned long tor_parse_ulong(const char *s, int base, unsigned long min, - unsigned long max, int *ok, char **next); -double tor_parse_double(const char *s, double min, double max, int *ok, - char **next); -uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, - uint64_t max, int *ok, char **next); -const char *hex_str(const char *from, size_t fromlen) ATTR_NONNULL((1)); -const char *eat_whitespace(const char *s); -const char *eat_whitespace_eos(const char *s, const char *eos); -const char *eat_whitespace_no_nl(const char *s); -const char *eat_whitespace_eos_no_nl(const char *s, const char *eos); -const char *find_whitespace(const char *s); -const char *find_whitespace_eos(const char *s, const char *eos); -const char *find_str_at_start_of_line(const char *haystack, - const char *needle); -int string_is_C_identifier(const char *string); -int string_is_key_value(int severity, const char *string); -int string_is_valid_dest(const char *string); -int string_is_valid_nonrfc_hostname(const char *string); -int string_is_valid_ipv4_address(const char *string); -int string_is_valid_ipv6_address(const char *string); - -int tor_mem_is_zero(const char *mem, size_t len); -int tor_digest_is_zero(const char *digest); -int tor_digest256_is_zero(const char *digest); -char *esc_for_log(const char *string) ATTR_MALLOC; -char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC; -const char *escaped(const char *string); - -char *tor_escape_str_for_pt_args(const char *string, - const char *chars_to_escape); - -struct smartlist_t; -int tor_vsscanf(const char *buf, const char *pattern, va_list ap) \ - CHECK_SCANF(2, 0); -int tor_sscanf(const char *buf, const char *pattern, ...) - CHECK_SCANF(2, 3); - -void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) - CHECK_PRINTF(2, 3); -void smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, - va_list args) - CHECK_PRINTF(2, 0); -void smartlist_add_strdup(struct smartlist_t *sl, const char *string); - -/* Time helpers */ -long tv_udiff(const struct timeval *start, const struct timeval *end); -long tv_mdiff(const struct timeval *start, const struct timeval *end); -int64_t tv_to_msec(const struct timeval *tv); -int tor_timegm(const struct tm *tm, time_t *time_out); -#define RFC1123_TIME_LEN 29 -void format_rfc1123_time(char *buf, time_t t); -int parse_rfc1123_time(const char *buf, time_t *t); -#define ISO_TIME_LEN 19 -#define ISO_TIME_USEC_LEN (ISO_TIME_LEN+7) -void format_local_iso_time(char *buf, time_t t); -void format_iso_time(char *buf, time_t t); -void format_local_iso_time_nospace(char *buf, time_t t); -void format_iso_time_nospace(char *buf, time_t t); -void format_iso_time_nospace_usec(char *buf, const struct timeval *tv); -int parse_iso_time_(const char *cp, time_t *t, int strict, int nospace); -int parse_iso_time(const char *buf, time_t *t); -int parse_iso_time_nospace(const char *cp, time_t *t); -int parse_http_time(const char *buf, struct tm *tm); -int format_time_interval(char *out, size_t out_len, long interval); - -/* Cached time */ -#ifdef TIME_IS_FAST -#define approx_time() time(NULL) -#define update_approx_time(t) STMT_NIL -#else -time_t approx_time(void); -void update_approx_time(time_t now); -#endif /* defined(TIME_IS_FAST) */ - -/* Rate-limiter */ - -/** A ratelim_t remembers how often an event is occurring, and how often - * it's allowed to occur. Typical usage is something like: - * - <pre> - if (possibly_very_frequent_event()) { - const int INTERVAL = 300; - static ratelim_t warning_limit = RATELIM_INIT(INTERVAL); - char *m; - if ((m = rate_limit_log(&warning_limit, approx_time()))) { - log_warn(LD_GENERAL, "The event occurred!%s", m); - tor_free(m); - } - } - </pre> - - As a convenience wrapper for logging, you can replace the above with: - <pre> - if (possibly_very_frequent_event()) { - static ratelim_t warning_limit = RATELIM_INIT(300); - log_fn_ratelim(&warning_limit, LOG_WARN, LD_GENERAL, - "The event occurred!"); - } - </pre> - */ -typedef struct ratelim_t { - int rate; - time_t last_allowed; - int n_calls_since_last_time; -} ratelim_t; - -#define RATELIM_INIT(r) { (r), 0, 0 } -#define RATELIM_TOOMANY (16*1000*1000) - -char *rate_limit_log(ratelim_t *lim, time_t now); - -/* File helpers */ -ssize_t write_all(tor_socket_t fd, const char *buf, size_t count,int isSocket); -ssize_t read_all(tor_socket_t fd, char *buf, size_t count, int isSocket); - -/** Status of an I/O stream. */ -enum stream_status { - IO_STREAM_OKAY, - IO_STREAM_EAGAIN, - IO_STREAM_TERM, - IO_STREAM_CLOSED -}; - -const char *stream_status_to_string(enum stream_status stream_status); - -enum stream_status get_string_from_pipe(int fd, char *buf, size_t count); - -MOCK_DECL(int,tor_unlink,(const char *pathname)); - -/** Return values from file_status(); see that function's documentation - * for details. */ -typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t; -file_status_t file_status(const char *filename); - -/** Possible behaviors for check_private_dir() on encountering a nonexistent - * directory; see that function's documentation for details. */ -typedef unsigned int cpd_check_t; -#define CPD_NONE 0 -#define CPD_CREATE (1u << 0) -#define CPD_CHECK (1u << 1) -#define CPD_GROUP_OK (1u << 2) -#define CPD_GROUP_READ (1u << 3) -#define CPD_CHECK_MODE_ONLY (1u << 4) -#define CPD_RELAX_DIRMODE_CHECK (1u << 5) -MOCK_DECL(int, check_private_dir, - (const char *dirname, cpd_check_t check, - const char *effective_user)); - -#define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC) -#define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND) -#define OPEN_FLAGS_DONT_REPLACE (O_CREAT|O_EXCL|O_APPEND|O_WRONLY) -typedef struct open_file_t open_file_t; -int start_writing_to_file(const char *fname, int open_flags, int mode, - open_file_t **data_out); -FILE *start_writing_to_stdio_file(const char *fname, int open_flags, int mode, - open_file_t **data_out); -FILE *fdopen_file(open_file_t *file_data); -int finish_writing_to_file(open_file_t *file_data); -int abort_writing_to_file(open_file_t *file_data); -MOCK_DECL(int, -write_str_to_file,(const char *fname, const char *str, int bin)); -MOCK_DECL(int, -write_bytes_to_file,(const char *fname, const char *str, size_t len, - int bin)); -/** An ad-hoc type to hold a string of characters and a count; used by - * write_chunks_to_file. */ -typedef struct sized_chunk_t { - const char *bytes; - size_t len; -} sized_chunk_t; -int write_chunks_to_file(const char *fname, const struct smartlist_t *chunks, - int bin, int no_tempfile); -int append_bytes_to_file(const char *fname, const char *str, size_t len, - int bin); -int write_bytes_to_new_file(const char *fname, const char *str, size_t len, - int bin); - -/** Flag for read_file_to_str: open the file in binary mode. */ -#define RFTS_BIN 1 -/** Flag for read_file_to_str: it's okay if the file doesn't exist. */ -#define RFTS_IGNORE_MISSING 2 - -#ifndef _WIN32 -struct stat; -#endif -MOCK_DECL_ATTR(char *, read_file_to_str, - (const char *filename, int flags, struct stat *stat_out), - ATTR_MALLOC); -char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, - size_t *sz_out) - ATTR_MALLOC; -const char *unescape_string(const char *s, char **result, size_t *size_out); -char *get_unquoted_path(const char *path); -char *expand_filename(const char *filename); -MOCK_DECL(struct smartlist_t *, tor_listdir, (const char *dirname)); -int path_is_relative(const char *filename); - -/* Process helpers */ -void start_daemon(void); -void finish_daemon(const char *desired_cwd); -int write_pidfile(const char *filename); - -void tor_disable_spawning_background_processes(void); - -typedef struct process_handle_t process_handle_t; -typedef struct process_environment_t process_environment_t; -int tor_spawn_background(const char *const filename, const char **argv, - process_environment_t *env, - process_handle_t **process_handle_out); - -#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code " - -#ifdef _WIN32 -HANDLE load_windows_system_library(const TCHAR *library_name); -#endif - -int environment_variable_names_equal(const char *s1, const char *s2); - -/* DOCDOC process_environment_t */ -struct process_environment_t { - /** A pointer to a sorted empty-string-terminated sequence of - * NUL-terminated strings of the form "NAME=VALUE". */ - char *windows_environment_block; - /** A pointer to a NULL-terminated array of pointers to - * NUL-terminated strings of the form "NAME=VALUE". */ - char **unixoid_environment_block; -}; - -process_environment_t *process_environment_make(struct smartlist_t *env_vars); -void process_environment_free_(process_environment_t *env); -#define process_environment_free(env) \ - FREE_AND_NULL(process_environment_t, process_environment_free_, (env)) - -struct smartlist_t *get_current_process_environment_variables(void); - -void set_environment_variable_in_smartlist(struct smartlist_t *env_vars, - const char *new_var, - void (*free_old)(void*), - int free_p); - -/* Values of process_handle_t.status. */ -#define PROCESS_STATUS_NOTRUNNING 0 -#define PROCESS_STATUS_RUNNING 1 -#define PROCESS_STATUS_ERROR -1 - -#ifdef UTIL_PRIVATE -struct waitpid_callback_t; -/** Structure to represent the state of a process with which Tor is - * communicating. The contents of this structure are private to util.c */ -struct process_handle_t { - /** One of the PROCESS_STATUS_* values */ - int status; -#ifdef _WIN32 - HANDLE stdin_pipe; - HANDLE stdout_pipe; - HANDLE stderr_pipe; - PROCESS_INFORMATION pid; -#else /* !(defined(_WIN32)) */ - int stdin_pipe; - int stdout_pipe; - int stderr_pipe; - pid_t pid; - /** If the process has not given us a SIGCHLD yet, this has the - * waitpid_callback_t that gets invoked once it has. Otherwise this - * contains NULL. */ - struct waitpid_callback_t *waitpid_cb; - /** The exit status reported by waitpid. */ - int waitpid_exit_status; -#endif /* defined(_WIN32) */ -}; -#endif /* defined(UTIL_PRIVATE) */ - -/* Return values of tor_get_exit_code() */ -#define PROCESS_EXIT_RUNNING 1 -#define PROCESS_EXIT_EXITED 0 -#define PROCESS_EXIT_ERROR -1 -int tor_get_exit_code(process_handle_t *process_handle, - int block, int *exit_code); -int tor_split_lines(struct smartlist_t *sl, char *buf, int len); -#ifdef _WIN32 -ssize_t tor_read_all_handle(HANDLE h, char *buf, size_t count, - const process_handle_t *process); -#else -ssize_t tor_read_all_handle(int fd, char *buf, size_t count, - const process_handle_t *process, - int *eof); -#endif /* defined(_WIN32) */ -ssize_t tor_read_all_from_process_stdout( - const process_handle_t *process_handle, char *buf, size_t count); -ssize_t tor_read_all_from_process_stderr( - const process_handle_t *process_handle, char *buf, size_t count); -char *tor_join_win_cmdline(const char *argv[]); - -int tor_process_get_pid(process_handle_t *process_handle); -#ifdef _WIN32 -HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle); -#else -int tor_process_get_stdout_pipe(process_handle_t *process_handle); -#endif - -#ifdef _WIN32 -MOCK_DECL(struct smartlist_t *, -tor_get_lines_from_handle,(HANDLE *handle, - enum stream_status *stream_status)); -#else -MOCK_DECL(struct smartlist_t *, -tor_get_lines_from_handle,(int fd, - enum stream_status *stream_status)); -#endif /* defined(_WIN32) */ - -int -tor_terminate_process(process_handle_t *process_handle); - -MOCK_DECL(void, -tor_process_handle_destroy,(process_handle_t *process_handle, - int also_terminate_process)); - -/* ===== Insecure rng */ -typedef struct tor_weak_rng_t { - uint32_t state; -} tor_weak_rng_t; - -#define TOR_WEAK_RNG_INIT {383745623} -#define TOR_WEAK_RANDOM_MAX (INT_MAX) -void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed); -int32_t tor_weak_random(tor_weak_rng_t *weak_rng); -int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top); -/** Randomly return true according to <b>rng</b> with probability 1 in - * <b>n</b> */ -#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n))) - -int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len); -int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len); - -#ifdef UTIL_PRIVATE -/* Prototypes for private functions only used by util.c (and unit tests) */ - -#ifndef _WIN32 -STATIC int format_helper_exit_status(unsigned char child_state, - int saved_errno, char *hex_errno); - -/* Space for hex values of child state, a slash, saved_errno (with - leading minus) and newline (no null) */ -#define HEX_ERRNO_SIZE (sizeof(char) * 2 + 1 + \ - 1 + sizeof(int) * 2 + 1) -#endif /* !defined(_WIN32) */ - -#endif /* defined(UTIL_PRIVATE) */ - -int size_mul_check(const size_t x, const size_t y); - -#define ARRAY_LENGTH(x) ((sizeof(x)) / sizeof(x[0])) - -#endif /* !defined(TOR_UTIL_H) */ - diff --git a/src/common/util_bug.c b/src/common/util_bug.c deleted file mode 100644 index 126e843866..0000000000 --- a/src/common/util_bug.c +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util_bug.c - **/ - -#include "orconfig.h" -#include "util_bug.h" -#include "torlog.h" -#include "backtrace.h" -#include "container.h" - -#ifdef __COVERITY__ -int bug_macro_deadcode_dummy__ = 0; -#endif - -#ifdef TOR_UNIT_TESTS -static void (*failed_assertion_cb)(void) = NULL; -static int n_bugs_to_capture = 0; -static smartlist_t *bug_messages = NULL; -#define capturing_bugs() (bug_messages != NULL && n_bugs_to_capture) -void -tor_capture_bugs_(int n) -{ - tor_end_capture_bugs_(); - bug_messages = smartlist_new(); - n_bugs_to_capture = n; -} -void -tor_end_capture_bugs_(void) -{ - n_bugs_to_capture = 0; - if (!bug_messages) - return; - SMARTLIST_FOREACH(bug_messages, char *, cp, tor_free(cp)); - smartlist_free(bug_messages); - bug_messages = NULL; -} -const smartlist_t * -tor_get_captured_bug_log_(void) -{ - return bug_messages; -} -static void -add_captured_bug(const char *s) -{ - --n_bugs_to_capture; - smartlist_add_strdup(bug_messages, s); -} -/** Set a callback to be invoked when we get any tor_bug_occurred_ - * invocation. We use this in the unit tests so that a nonfatal - * assertion failure can also count as a test failure. - */ -void -tor_set_failed_assertion_callback(void (*fn)(void)) -{ - failed_assertion_cb = fn; -} -#else /* !(defined(TOR_UNIT_TESTS)) */ -#define capturing_bugs() (0) -#define add_captured_bug(s) do { } while (0) -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Helper for tor_assert: report the assertion failure. */ -void -tor_assertion_failed_(const char *fname, unsigned int line, - const char *func, const char *expr) -{ - char buf[256]; - log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.", - fname, line, func, expr); - tor_snprintf(buf, sizeof(buf), - "Assertion %s failed in %s at %s:%u", - expr, func, fname, line); - log_backtrace(LOG_ERR, LD_BUG, buf); -} - -/** Helper for tor_assert_nonfatal: report the assertion failure. */ -void -tor_bug_occurred_(const char *fname, unsigned int line, - const char *func, const char *expr, - int once) -{ - char buf[256]; - const char *once_str = once ? - " (Future instances of this warning will be silenced.)": ""; - if (! expr) { - if (capturing_bugs()) { - add_captured_bug("This line should not have been reached."); - return; - } - log_warn(LD_BUG, "%s:%u: %s: This line should not have been reached.%s", - fname, line, func, once_str); - tor_snprintf(buf, sizeof(buf), - "Line unexpectedly reached at %s at %s:%u", - func, fname, line); - } else { - if (capturing_bugs()) { - add_captured_bug(expr); - return; - } - log_warn(LD_BUG, "%s:%u: %s: Non-fatal assertion %s failed.%s", - fname, line, func, expr, once_str); - tor_snprintf(buf, sizeof(buf), - "Non-fatal assertion %s failed in %s at %s:%u", - expr, func, fname, line); - } - log_backtrace(LOG_WARN, LD_BUG, buf); - -#ifdef TOR_UNIT_TESTS - if (failed_assertion_cb) { - failed_assertion_cb(); - } -#endif -} - diff --git a/src/common/util_bug.h b/src/common/util_bug.h deleted file mode 100644 index 50becd0c33..0000000000 --- a/src/common/util_bug.h +++ /dev/null @@ -1,238 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util_bug.h - * - * \brief Macros to manage assertions, fatal and non-fatal. - * - * Guidelines: All the different kinds of assertion in this file are for - * bug-checking only. Don't write code that can assert based on bad inputs. - * - * We provide two kinds of assertion here: "fatal" and "nonfatal". Use - * nonfatal assertions for any bug you can reasonably recover from -- and - * please, try to recover! Many severe bugs in Tor have been caused by using - * a regular assertion when a nonfatal assertion would have been better. - * - * If you need to check a condition with a nonfatal assertion, AND recover - * from that same condition, consider using the BUG() macro inside a - * conditional. For example: - * - * <code> - * // wrong -- use tor_assert_nonfatal() if you just want an assertion. - * BUG(ptr == NULL); - * - * // okay, but needlessly verbose - * tor_assert_nonfatal(ptr != NULL); - * if (ptr == NULL) { ... } - * - * // this is how we do it: - * if (BUG(ptr == NULL)) { ... } - * </code> - **/ - -#ifndef TOR_UTIL_BUG_H -#define TOR_UTIL_BUG_H - -#include "orconfig.h" -#include "compat.h" -#include "testsupport.h" - -/* Replace assert() with a variant that sends failures to the log before - * calling assert() normally. - */ -#ifdef NDEBUG -/* Nobody should ever want to build with NDEBUG set. 99% of our asserts will - * be outside the critical path anyway, so it's silly to disable bug-checking - * throughout the entire program just because a few asserts are slowing you - * down. Profile, optimize the critical path, and keep debugging on. - * - * And I'm not just saying that because some of our asserts check - * security-critical properties. - */ -#error "Sorry; we don't support building with NDEBUG." -#endif /* defined(NDEBUG) */ - -#if defined(TOR_UNIT_TESTS) && defined(__GNUC__) -/* We define this GCC macro as a replacement for PREDICT_UNLIKELY() in this - * header, so that in our unit test builds, we'll get compiler warnings about - * stuff like tor_assert(n = 5). - * - * The key here is that (e) is wrapped in exactly one layer of parentheses, - * and then passed right to a conditional. If you do anything else to the - * expression here, or introduce any more parentheses, the compiler won't - * help you. - * - * We only do this for the unit-test build case because it interferes with - * the likely-branch labeling. Note below that in the other case, we define - * these macros to just be synonyms for PREDICT_(UN)LIKELY. - */ -#define ASSERT_PREDICT_UNLIKELY_(e) \ - ( { \ - int tor__assert_tmp_value__; \ - if (e) \ - tor__assert_tmp_value__ = 1; \ - else \ - tor__assert_tmp_value__ = 0; \ - tor__assert_tmp_value__; \ - } ) -#define ASSERT_PREDICT_LIKELY_(e) ASSERT_PREDICT_UNLIKELY_(e) -#else -#define ASSERT_PREDICT_UNLIKELY_(e) PREDICT_UNLIKELY(e) -#define ASSERT_PREDICT_LIKELY_(e) PREDICT_LIKELY(e) -#endif - -/* Sometimes we don't want to use assertions during branch coverage tests; it - * leads to tons of unreached branches which in reality are only assertions we - * didn't hit. */ -#if defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) -#define tor_assert(a) STMT_BEGIN \ - (void)(a); \ - STMT_END -#else -/** Like assert(3), but send assertion failures to the log as well as to - * stderr. */ -#define tor_assert(expr) STMT_BEGIN \ - if (ASSERT_PREDICT_LIKELY_(expr)) { \ - } else { \ - tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr); \ - abort(); \ - } STMT_END -#endif /* defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) */ - -#define tor_assert_unreached() \ - STMT_BEGIN { \ - tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, \ - "line should be unreached"); \ - abort(); \ - } STMT_END - -/* Non-fatal bug assertions. The "unreached" variants mean "this line should - * never be reached." The "once" variants mean "Don't log a warning more than - * once". - * - * The 'BUG' macro checks a boolean condition and logs an error message if it - * is true. Example usage: - * if (BUG(x == NULL)) - * return -1; - */ - -#ifdef __COVERITY__ -extern int bug_macro_deadcode_dummy__; -#undef BUG -// Coverity defines this in global headers; let's override it. This is a -// magic coverity-only preprocessor thing. -// We use this "deadcode_dummy__" trick to prevent coverity from -// complaining about unreachable bug cases. -#nodef BUG(x) ((x)?(__coverity_panic__(),1):(0+bug_macro_deadcode_dummy__)) -#endif /* defined(__COVERITY__) */ - -#if defined(__COVERITY__) || defined(__clang_analyzer__) -// We're running with a static analysis tool: let's treat even nonfatal -// assertion failures as something that we need to avoid. -#define ALL_BUGS_ARE_FATAL -#endif - -#ifdef ALL_BUGS_ARE_FATAL -#define tor_assert_nonfatal_unreached() tor_assert(0) -#define tor_assert_nonfatal(cond) tor_assert((cond)) -#define tor_assert_nonfatal_unreached_once() tor_assert(0) -#define tor_assert_nonfatal_once(cond) tor_assert((cond)) -#define BUG(cond) \ - (ASSERT_PREDICT_UNLIKELY_(cond) ? \ - (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")"), \ - abort(), 1) \ - : 0) -#elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) -#define tor_assert_nonfatal_unreached() STMT_NIL -#define tor_assert_nonfatal(cond) ((void)(cond)) -#define tor_assert_nonfatal_unreached_once() STMT_NIL -#define tor_assert_nonfatal_once(cond) ((void)(cond)) -#define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0) -#else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */ -#define tor_assert_nonfatal_unreached() STMT_BEGIN \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0); \ - STMT_END -#define tor_assert_nonfatal(cond) STMT_BEGIN \ - if (ASSERT_PREDICT_LIKELY_(cond)) { \ - } else { \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0); \ - } \ - STMT_END -#define tor_assert_nonfatal_unreached_once() STMT_BEGIN \ - static int warning_logged__ = 0; \ - if (!warning_logged__) { \ - warning_logged__ = 1; \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1); \ - } \ - STMT_END -#define tor_assert_nonfatal_once(cond) STMT_BEGIN \ - static int warning_logged__ = 0; \ - if (ASSERT_PREDICT_LIKELY_(cond)) { \ - } else if (!warning_logged__) { \ - warning_logged__ = 1; \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1); \ - } \ - STMT_END -#define BUG(cond) \ - (ASSERT_PREDICT_UNLIKELY_(cond) ? \ - (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0), 1) \ - : 0) -#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */ - -#ifdef __GNUC__ -#define IF_BUG_ONCE__(cond,var) \ - if (( { \ - static int var = 0; \ - int bool_result = !!(cond); \ - if (bool_result && !var) { \ - var = 1; \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ - "!("#cond")", 1); \ - } \ - bool_result; } )) -#else /* !(defined(__GNUC__)) */ -#define IF_BUG_ONCE__(cond,var) \ - static int var = 0; \ - if ((cond) ? \ - (var ? 1 : \ - (var=1, \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ - "!("#cond")", 1), \ - 1)) \ - : 0) -#endif /* defined(__GNUC__) */ -#define IF_BUG_ONCE_VARNAME_(a) \ - warning_logged_on_ ## a ## __ -#define IF_BUG_ONCE_VARNAME__(a) \ - IF_BUG_ONCE_VARNAME_(a) - -/** This macro behaves as 'if (bug(x))', except that it only logs its - * warning once, no matter how many times it triggers. - */ - -#define IF_BUG_ONCE(cond) \ - IF_BUG_ONCE__(ASSERT_PREDICT_UNLIKELY_(cond), \ - IF_BUG_ONCE_VARNAME__(__LINE__)) - -/** Define this if you want Tor to crash when any problem comes up, - * so you can get a coredump and track things down. */ -// #define tor_fragile_assert() tor_assert_unreached(0) -#define tor_fragile_assert() tor_assert_nonfatal_unreached_once() - -void tor_assertion_failed_(const char *fname, unsigned int line, - const char *func, const char *expr); -void tor_bug_occurred_(const char *fname, unsigned int line, - const char *func, const char *expr, - int once); - -#ifdef TOR_UNIT_TESTS -void tor_capture_bugs_(int n); -void tor_end_capture_bugs_(void); -const struct smartlist_t *tor_get_captured_bug_log_(void); -void tor_set_failed_assertion_callback(void (*fn)(void)); -#endif /* defined(TOR_UNIT_TESTS) */ - -#endif /* !defined(TOR_UTIL_BUG_H) */ diff --git a/src/common/util_format.c b/src/common/util_format.c deleted file mode 100644 index e51757a4e8..0000000000 --- a/src/common/util_format.c +++ /dev/null @@ -1,535 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util_format.c - * - * \brief Miscellaneous functions for encoding and decoding various things - * in base{16,32,64}. - */ - -#include "orconfig.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" -#include "torint.h" - -#include <stddef.h> -#include <string.h> -#include <stdlib.h> - -/* Return the base32 encoded size in bytes using the source length srclen. - * - * (WATCH OUT: This API counts the terminating NUL byte, but - * base64_encode_size does not.) - */ -size_t -base32_encoded_size(size_t srclen) -{ - size_t enclen; - tor_assert(srclen < SIZE_T_CEILING / 8); - enclen = BASE32_NOPAD_BUFSIZE(srclen); - tor_assert(enclen < INT_MAX && enclen > srclen); - return enclen; -} - -/** Implements base32 encoding as in RFC 4648. */ -void -base32_encode(char *dest, size_t destlen, const char *src, size_t srclen) -{ - unsigned int i, v, u; - size_t nbits = srclen * 8; - size_t bit; - - /* We need enough space for the encoded data and the extra NUL byte. */ - tor_assert(base32_encoded_size(srclen) <= destlen); - tor_assert(destlen < SIZE_T_CEILING); - - /* Make sure we leave no uninitialized data in the destination buffer. */ - memset(dest, 0, destlen); - - for (i=0,bit=0; bit < nbits; ++i, bit+=5) { - /* set v to the 16-bit value starting at src[bits/8], 0-padded. */ - size_t idx = bit / 8; - v = ((uint8_t)src[idx]) << 8; - if (idx+1 < srclen) - v += (uint8_t)src[idx+1]; - /* set u to the 5-bit value at the bit'th bit of buf. */ - u = (v >> (11-(bit%8))) & 0x1F; - dest[i] = BASE32_CHARS[u]; - } - dest[i] = '\0'; -} - -/** Implements base32 decoding as in RFC 4648. - * Returns 0 if successful, -1 otherwise. - */ -int -base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) -{ - /* XXXX we might want to rewrite this along the lines of base64_decode, if - * it ever shows up in the profile. */ - unsigned int i; - size_t nbits, j, bit; - char *tmp; - nbits = ((srclen * 5) / 8) * 8; - - tor_assert(srclen < SIZE_T_CEILING / 5); - tor_assert((nbits/8) <= destlen); /* We need enough space. */ - tor_assert(destlen < SIZE_T_CEILING); - - /* Make sure we leave no uninitialized data in the destination buffer. */ - memset(dest, 0, destlen); - - /* Convert base32 encoded chars to the 5-bit values that they represent. */ - tmp = tor_malloc_zero(srclen); - for (j = 0; j < srclen; ++j) { - if (src[j] > 0x60 && src[j] < 0x7B) tmp[j] = src[j] - 0x61; - else if (src[j] > 0x31 && src[j] < 0x38) tmp[j] = src[j] - 0x18; - else if (src[j] > 0x40 && src[j] < 0x5B) tmp[j] = src[j] - 0x41; - else { - log_warn(LD_GENERAL, "illegal character in base32 encoded string"); - tor_free(tmp); - return -1; - } - } - - /* Assemble result byte-wise by applying five possible cases. */ - for (i = 0, bit = 0; bit < nbits; ++i, bit += 8) { - switch (bit % 40) { - case 0: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 3) + - (((uint8_t)tmp[(bit/5)+1]) >> 2); - break; - case 8: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 6) + - (((uint8_t)tmp[(bit/5)+1]) << 1) + - (((uint8_t)tmp[(bit/5)+2]) >> 4); - break; - case 16: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 4) + - (((uint8_t)tmp[(bit/5)+1]) >> 1); - break; - case 24: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 7) + - (((uint8_t)tmp[(bit/5)+1]) << 2) + - (((uint8_t)tmp[(bit/5)+2]) >> 3); - break; - case 32: - dest[i] = (((uint8_t)tmp[(bit/5)]) << 5) + - ((uint8_t)tmp[(bit/5)+1]); - break; - } - } - - memset(tmp, 0, srclen); /* on the heap, this should be safe */ - tor_free(tmp); - tmp = NULL; - return 0; -} - -#define BASE64_OPENSSL_LINELEN 64 - -/** Return the Base64 encoded size of <b>srclen</b> bytes of data in - * bytes. - * - * (WATCH OUT: This API <em>does not</em> count the terminating NUL byte, - * but base32_encoded_size does.) - * - * If <b>flags</b>&BASE64_ENCODE_MULTILINE is true, return the size - * of the encoded output as multiline output (64 character, `\n' terminated - * lines). - */ -size_t -base64_encode_size(size_t srclen, int flags) -{ - size_t enclen; - - /* Use INT_MAX for overflow checking because base64_encode() returns int. */ - tor_assert(srclen < INT_MAX); - tor_assert(CEIL_DIV(srclen, 3) < INT_MAX / 4); - - enclen = BASE64_LEN(srclen); - if (flags & BASE64_ENCODE_MULTILINE) - enclen += CEIL_DIV(enclen, BASE64_OPENSSL_LINELEN); - - tor_assert(enclen < INT_MAX && (enclen == 0 || enclen > srclen)); - return enclen; -} - -/** Internal table mapping 6 bit values to the Base64 alphabet. */ -static const char base64_encode_table[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/' -}; - -/** Base64 encode <b>srclen</b> bytes of data from <b>src</b>. Write - * the result into <b>dest</b>, if it will fit within <b>destlen</b> - * bytes. Return the number of bytes written on success; -1 if - * destlen is too short, or other failure. - * - * If <b>flags</b>&BASE64_ENCODE_MULTILINE is true, return encoded - * output in multiline format (64 character, `\n' terminated lines). - */ -int -base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, - int flags) -{ - const unsigned char *usrc = (unsigned char *)src; - const unsigned char *eous = usrc + srclen; - char *d = dest; - uint32_t n = 0; - size_t linelen = 0; - size_t enclen; - int n_idx = 0; - - if (!src || !dest) - return -1; - - /* Ensure that there is sufficient space, including the NUL. */ - enclen = base64_encode_size(srclen, flags); - if (destlen < enclen + 1) - return -1; - if (destlen > SIZE_T_CEILING) - return -1; - if (enclen > INT_MAX) - return -1; - - /* Make sure we leave no uninitialized data in the destination buffer. */ - memset(dest, 0, destlen); - - /* XXX/Yawning: If this ends up being too slow, this can be sped up - * by separating the multiline format case and the normal case, and - * processing 48 bytes of input at a time when newlines are desired. - */ -#define ENCODE_CHAR(ch) \ - STMT_BEGIN \ - *d++ = ch; \ - if (flags & BASE64_ENCODE_MULTILINE) { \ - if (++linelen % BASE64_OPENSSL_LINELEN == 0) { \ - linelen = 0; \ - *d++ = '\n'; \ - } \ - } \ - STMT_END - -#define ENCODE_N(idx) \ - ENCODE_CHAR(base64_encode_table[(n >> ((3 - idx) * 6)) & 0x3f]) - -#define ENCODE_PAD() ENCODE_CHAR('=') - - /* Iterate over all the bytes in src. Each one will add 8 bits to the - * value we're encoding. Accumulate bits in <b>n</b>, and whenever we - * have 24 bits, batch them into 4 bytes and flush those bytes to dest. - */ - for ( ; usrc < eous; ++usrc) { - n = (n << 8) | *usrc; - if ((++n_idx) == 3) { - ENCODE_N(0); - ENCODE_N(1); - ENCODE_N(2); - ENCODE_N(3); - n_idx = 0; - n = 0; - } - } - switch (n_idx) { - case 0: - /* 0 leftover bits, no pading to add. */ - break; - case 1: - /* 8 leftover bits, pad to 12 bits, write the 2 6-bit values followed - * by 2 padding characters. - */ - n <<= 4; - ENCODE_N(2); - ENCODE_N(3); - ENCODE_PAD(); - ENCODE_PAD(); - break; - case 2: - /* 16 leftover bits, pad to 18 bits, write the 3 6-bit values followed - * by 1 padding character. - */ - n <<= 2; - ENCODE_N(1); - ENCODE_N(2); - ENCODE_N(3); - ENCODE_PAD(); - break; - // LCOV_EXCL_START -- we can't reach this point, because we enforce - // 0 <= ncov_idx < 3 in the loop above. - default: - /* Something went catastrophically wrong. */ - tor_fragile_assert(); - return -1; - // LCOV_EXCL_STOP - } - -#undef ENCODE_N -#undef ENCODE_PAD -#undef ENCODE_CHAR - - /* Multiline output always includes at least one newline. */ - if (flags & BASE64_ENCODE_MULTILINE && linelen != 0) - *d++ = '\n'; - - tor_assert(d - dest == (ptrdiff_t)enclen); - - *d++ = '\0'; /* NUL terminate the output. */ - - return (int) enclen; -} - -/** As base64_encode, but do not add any internal spaces or external padding - * to the output stream. */ -int -base64_encode_nopad(char *dest, size_t destlen, - const uint8_t *src, size_t srclen) -{ - int n = base64_encode(dest, destlen, (const char*) src, srclen, 0); - if (n <= 0) - return n; - tor_assert((size_t)n < destlen && dest[n] == 0); - char *in, *out; - in = out = dest; - while (*in) { - if (*in == '=' || *in == '\n') { - ++in; - } else { - *out++ = *in++; - } - } - *out = 0; - - tor_assert(out - dest <= INT_MAX); - - return (int)(out - dest); -} - -#undef BASE64_OPENSSL_LINELEN - -/** @{ */ -/** Special values used for the base64_decode_table */ -#define X 255 -#define SP 64 -#define PAD 65 -/** @} */ -/** Internal table mapping byte values to what they represent in base64. - * Numbers 0..63 are 6-bit integers. SPs are spaces, and should be - * skipped. Xs are invalid and must not appear in base64. PAD indicates - * end-of-string. */ -static const uint8_t base64_decode_table[256] = { - X, X, X, X, X, X, X, X, X, SP, SP, SP, X, SP, X, X, /* */ - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - SP, X, X, X, X, X, X, X, X, X, X, 62, X, X, X, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, X, X, X, PAD, X, X, - X, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, X, X, X, X, X, - X, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, -}; - -/** Base64 decode <b>srclen</b> bytes of data from <b>src</b>. Write - * the result into <b>dest</b>, if it will fit within <b>destlen</b> - * bytes. Return the number of bytes written on success; -1 if - * destlen is too short, or other failure. - * - * NOTE 1: destlen is checked conservatively, as though srclen contained no - * spaces or padding. - * - * NOTE 2: This implementation does not check for the correct number of - * padding "=" characters at the end of the string, and does not check - * for internal padding characters. - */ -int -base64_decode(char *dest, size_t destlen, const char *src, size_t srclen) -{ - const char *eos = src+srclen; - uint32_t n=0; - int n_idx=0; - size_t di = 0; - - if (destlen > INT_MAX) - return -1; - - /* Make sure we leave no uninitialized data in the destination buffer. */ - memset(dest, 0, destlen); - - /* Iterate over all the bytes in src. Each one will add 0 or 6 bits to the - * value we're decoding. Accumulate bits in <b>n</b>, and whenever we have - * 24 bits, batch them into 3 bytes and flush those bytes to dest. - */ - for ( ; src < eos; ++src) { - unsigned char c = (unsigned char) *src; - uint8_t v = base64_decode_table[c]; - switch (v) { - case X: - /* This character isn't allowed in base64. */ - return -1; - case SP: - /* This character is whitespace, and has no effect. */ - continue; - case PAD: - /* We've hit an = character: the data is over. */ - goto end_of_loop; - default: - /* We have an actual 6-bit value. Append it to the bits in n. */ - n = (n<<6) | v; - if ((++n_idx) == 4) { - /* We've accumulated 24 bits in n. Flush them. */ - if (destlen < 3 || di > destlen - 3) - return -1; - dest[di++] = (n>>16); - dest[di++] = (n>>8) & 0xff; - dest[di++] = (n) & 0xff; - n_idx = 0; - n = 0; - } - } - } - end_of_loop: - /* If we have leftover bits, we need to cope. */ - switch (n_idx) { - case 0: - default: - /* No leftover bits. We win. */ - break; - case 1: - /* 6 leftover bits. That's invalid; we can't form a byte out of that. */ - return -1; - case 2: - /* 12 leftover bits: The last 4 are padding and the first 8 are data. */ - if (destlen < 1 || di > destlen - 1) - return -1; - dest[di++] = n >> 4; - break; - case 3: - /* 18 leftover bits: The last 2 are padding and the first 16 are data. */ - if (destlen < 2 || di > destlen - 2) - return -1; - dest[di++] = n >> 10; - dest[di++] = n >> 2; - } - - tor_assert(di <= destlen); - - return (int)di; -} -#undef X -#undef SP -#undef PAD - -/** Encode the <b>srclen</b> bytes at <b>src</b> in a NUL-terminated, - * uppercase hexadecimal string; store it in the <b>destlen</b>-byte buffer - * <b>dest</b>. - */ -void -base16_encode(char *dest, size_t destlen, const char *src, size_t srclen) -{ - const char *end; - char *cp; - - tor_assert(srclen < SIZE_T_CEILING / 2 - 1); - tor_assert(destlen >= BASE16_BUFSIZE(srclen)); - tor_assert(destlen < SIZE_T_CEILING); - - /* Make sure we leave no uninitialized data in the destination buffer. */ - memset(dest, 0, destlen); - - cp = dest; - end = src+srclen; - while (src<end) { - *cp++ = "0123456789ABCDEF"[ (*(const uint8_t*)src) >> 4 ]; - *cp++ = "0123456789ABCDEF"[ (*(const uint8_t*)src) & 0xf ]; - ++src; - } - *cp = '\0'; -} - -/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */ -static inline int -hex_decode_digit_(char c) -{ - switch (c) { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case 'A': case 'a': return 10; - case 'B': case 'b': return 11; - case 'C': case 'c': return 12; - case 'D': case 'd': return 13; - case 'E': case 'e': return 14; - case 'F': case 'f': return 15; - default: - return -1; - } -} - -/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */ -int -hex_decode_digit(char c) -{ - return hex_decode_digit_(c); -} - -/** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode - * it and store the result in the <b>destlen</b>-byte buffer at <b>dest</b>. - * Return the number of bytes decoded on success, -1 on failure. If - * <b>destlen</b> is greater than INT_MAX or less than half of - * <b>srclen</b>, -1 is returned. */ -int -base16_decode(char *dest, size_t destlen, const char *src, size_t srclen) -{ - const char *end; - char *dest_orig = dest; - int v1,v2; - - if ((srclen % 2) != 0) - return -1; - if (destlen < srclen/2 || destlen > INT_MAX) - return -1; - - /* Make sure we leave no uninitialized data in the destination buffer. */ - memset(dest, 0, destlen); - - end = src+srclen; - while (src<end) { - v1 = hex_decode_digit_(*src); - v2 = hex_decode_digit_(*(src+1)); - if (v1<0||v2<0) - return -1; - *(uint8_t*)dest = (v1<<4)|v2; - ++dest; - src+=2; - } - - tor_assert((dest-dest_orig) <= (ptrdiff_t) destlen); - - return (int) (dest-dest_orig); -} - diff --git a/src/common/util_format.h b/src/common/util_format.h deleted file mode 100644 index 0aefe3a44e..0000000000 --- a/src/common/util_format.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_UTIL_FORMAT_H -#define TOR_UTIL_FORMAT_H - -#include "testsupport.h" -#include "torint.h" - -/** @{ */ -/** These macros don't check for overflow. Use them only for constant inputs - * (like array declarations). The *_LEN macros are the raw encoding lengths - * (without terminating NUL), while the *_BUFSIZE macros count the terminating - * NUL. */ -#define BASE64_LEN(n) (CEIL_DIV((n), 3) * 4) -#define BASE32_LEN(n) (CEIL_DIV((n), 5) * 8) -#define BASE16_LEN(n) ((n) * 2) - -#define BASE64_BUFSIZE(n) (BASE64_LEN(n) + 1) -#define BASE32_BUFSIZE(n) (BASE32_LEN(n) + 1) -#define BASE16_BUFSIZE(n) (BASE16_LEN(n) + 1) - -#define BASE64_NOPAD_LEN(n) (CEIL_DIV((n) * 4, 3)) -#define BASE32_NOPAD_LEN(n) (CEIL_DIV((n) * 8, 5)) - -#define BASE64_NOPAD_BUFSIZE(n) (BASE64_NOPAD_LEN(n) + 1) -#define BASE32_NOPAD_BUFSIZE(n) (BASE32_NOPAD_LEN(n) + 1) -/** @} */ - -#define BASE64_ENCODE_MULTILINE 1 -size_t base64_encode_size(size_t srclen, int flags); -int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, - int flags); -int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen); -int base64_encode_nopad(char *dest, size_t destlen, - const uint8_t *src, size_t srclen); - -/** Characters that can appear (case-insensitively) in a base32 encoding. */ -#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567" -void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen); -int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen); -size_t base32_encoded_size(size_t srclen); - -int hex_decode_digit(char c); -void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen); -int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen); - -#endif /* !defined(TOR_UTIL_FORMAT_H) */ - diff --git a/src/common/util_process.c b/src/common/util_process.c deleted file mode 100644 index c2826152e9..0000000000 --- a/src/common/util_process.c +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util_process.c - * \brief utility functions for launching processes and checking their - * status. These functions are kept separately from procmon so that they - * won't require linking against libevent. - **/ - -#include "orconfig.h" - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif - -#include "compat.h" -#include "util.h" -#include "torlog.h" -#include "util_process.h" -#include "ht.h" - -/* ================================================== */ -/* Convenience structures for handlers for waitpid(). - * - * The tor_process_monitor*() code above doesn't use them, since it is for - * monitoring a non-child process. - */ - -#ifndef _WIN32 - -/** Mapping from a PID to a userfn/userdata pair. */ -struct waitpid_callback_t { - HT_ENTRY(waitpid_callback_t) node; - pid_t pid; - - void (*userfn)(int, void *userdata); - void *userdata; - - unsigned running; -}; - -static inline unsigned int -process_map_entry_hash_(const waitpid_callback_t *ent) -{ - return (unsigned) ent->pid; -} - -static inline unsigned int -process_map_entries_eq_(const waitpid_callback_t *a, - const waitpid_callback_t *b) -{ - return a->pid == b->pid; -} - -static HT_HEAD(process_map, waitpid_callback_t) process_map = HT_INITIALIZER(); - -HT_PROTOTYPE(process_map, waitpid_callback_t, node, process_map_entry_hash_, - process_map_entries_eq_) -HT_GENERATE2(process_map, waitpid_callback_t, node, process_map_entry_hash_, - process_map_entries_eq_, 0.6, tor_reallocarray_, tor_free_) - -/** - * Begin monitoring the child pid <b>pid</b> to see if we get a SIGCHLD for - * it. If we eventually do, call <b>fn</b>, passing it the exit status (as - * yielded by waitpid) and the pointer <b>arg</b>. - * - * To cancel this, or clean up after it has triggered, call - * clear_waitpid_callback(). - */ -waitpid_callback_t * -set_waitpid_callback(pid_t pid, void (*fn)(int, void *), void *arg) -{ - waitpid_callback_t *old_ent; - waitpid_callback_t *ent = tor_malloc_zero(sizeof(waitpid_callback_t)); - ent->pid = pid; - ent->userfn = fn; - ent->userdata = arg; - ent->running = 1; - - old_ent = HT_REPLACE(process_map, &process_map, ent); - if (old_ent) { - log_warn(LD_BUG, "Replaced a waitpid monitor on pid %u. That should be " - "impossible.", (unsigned) pid); - old_ent->running = 0; - } - - return ent; -} - -/** - * Cancel a waitpid_callback_t, or clean up after one has triggered. Releases - * all storage held by <b>ent</b>. - */ -void -clear_waitpid_callback(waitpid_callback_t *ent) -{ - waitpid_callback_t *old_ent; - if (ent == NULL) - return; - - if (ent->running) { - old_ent = HT_REMOVE(process_map, &process_map, ent); - if (old_ent != ent) { - log_warn(LD_BUG, "Couldn't remove waitpid monitor for pid %u.", - (unsigned) ent->pid); - return; - } - } - - tor_free(ent); -} - -/** Helper: find the callack for <b>pid</b>; if there is one, run it, - * reporting the exit status as <b>status</b>. */ -static void -notify_waitpid_callback_by_pid(pid_t pid, int status) -{ - waitpid_callback_t search, *ent; - - search.pid = pid; - ent = HT_REMOVE(process_map, &process_map, &search); - if (!ent || !ent->running) { - log_info(LD_GENERAL, "Child process %u has exited; no callback was " - "registered", (unsigned)pid); - return; - } - - log_info(LD_GENERAL, "Child process %u has exited; running callback.", - (unsigned)pid); - - ent->running = 0; - ent->userfn(status, ent->userdata); -} - -/** Use waitpid() to wait for all children that have exited, and invoke any - * callbacks registered for them. */ -void -notify_pending_waitpid_callbacks(void) -{ - /* I was going to call this function reap_zombie_children(), but - * that makes it sound way more exciting than it really is. */ - pid_t child; - int status = 0; - - while ((child = waitpid(-1, &status, WNOHANG)) > 0) { - notify_waitpid_callback_by_pid(child, status); - status = 0; /* should be needless */ - } -} - -#endif /* !defined(_WIN32) */ - diff --git a/src/common/util_process.h b/src/common/util_process.h deleted file mode 100644 index c9aa771b77..0000000000 --- a/src/common/util_process.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util_process.h - * \brief Headers for util_process.c - **/ - -#ifndef TOR_UTIL_PROCESS_H -#define TOR_UTIL_PROCESS_H - -#ifndef _WIN32 -/** A callback structure waiting for us to get a SIGCHLD informing us that a - * PID has been closed. Created by set_waitpid_callback. Cancelled or cleaned- - * up from clear_waitpid_callback(). Do not access outside of the main thread; - * do not access from inside a signal handler. */ -typedef struct waitpid_callback_t waitpid_callback_t; - -waitpid_callback_t *set_waitpid_callback(pid_t pid, - void (*fn)(int, void *), void *arg); -void clear_waitpid_callback(waitpid_callback_t *ent); -void notify_pending_waitpid_callbacks(void); -#endif /* !defined(_WIN32) */ - -#endif /* !defined(TOR_UTIL_PROCESS_H) */ - diff --git a/src/common/workqueue.c b/src/common/workqueue.c deleted file mode 100644 index 563a98af96..0000000000 --- a/src/common/workqueue.c +++ /dev/null @@ -1,678 +0,0 @@ - -/* copyright (c) 2013-2015, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file workqueue.c - * - * \brief Implements worker threads, queues of work for them, and mechanisms - * for them to send answers back to the main thread. - * - * The main structure here is a threadpool_t : it manages a set of worker - * threads, a queue of pending work, and a reply queue. Every piece of work - * is a workqueue_entry_t, containing data to process and a function to - * process it with. - * - * The main thread informs the worker threads of pending work by using a - * condition variable. The workers inform the main process of completed work - * by using an alert_sockets_t object, as implemented in compat_threads.c. - * - * The main thread can also queue an "update" that will be handled by all the - * workers. This is useful for updating state that all the workers share. - * - * In Tor today, there is currently only one thread pool, used in cpuworker.c. - */ - -#include "orconfig.h" -#include "compat.h" -#include "compat_libevent.h" -#include "compat_threads.h" -#include "crypto_rand.h" -#include "util.h" -#include "workqueue.h" -#include "tor_queue.h" -#include "torlog.h" - -#include <event2/event.h> - -#define WORKQUEUE_PRIORITY_FIRST WQ_PRI_HIGH -#define WORKQUEUE_PRIORITY_LAST WQ_PRI_LOW -#define WORKQUEUE_N_PRIORITIES (((int) WORKQUEUE_PRIORITY_LAST)+1) - -TOR_TAILQ_HEAD(work_tailq_t, workqueue_entry_s); -typedef struct work_tailq_t work_tailq_t; - -struct threadpool_s { - /** An array of pointers to workerthread_t: one for each running worker - * thread. */ - struct workerthread_s **threads; - - /** Condition variable that we wait on when we have no work, and which - * gets signaled when our queue becomes nonempty. */ - tor_cond_t condition; - /** Queues of pending work that we have to do. The queue with priority - * <b>p</b> is work[p]. */ - work_tailq_t work[WORKQUEUE_N_PRIORITIES]; - - /** Weak RNG, used to decide when to ignore priority. */ - tor_weak_rng_t weak_rng; - - /** The current 'update generation' of the threadpool. Any thread that is - * at an earlier generation needs to run the update function. */ - unsigned generation; - - /** Function that should be run for updates on each thread. */ - workqueue_reply_t (*update_fn)(void *, void *); - /** Function to free update arguments if they can't be run. */ - void (*free_update_arg_fn)(void *); - /** Array of n_threads update arguments. */ - void **update_args; - /** Event to notice when another thread has sent a reply. */ - struct event *reply_event; - void (*reply_cb)(threadpool_t *); - - /** Number of elements in threads. */ - int n_threads; - /** Mutex to protect all the above fields. */ - tor_mutex_t lock; - - /** A reply queue to use when constructing new threads. */ - replyqueue_t *reply_queue; - - /** Functions used to allocate and free thread state. */ - void *(*new_thread_state_fn)(void*); - void (*free_thread_state_fn)(void*); - void *new_thread_state_arg; -}; - -/** Used to put a workqueue_priority_t value into a bitfield. */ -#define workqueue_priority_bitfield_t ENUM_BF(workqueue_priority_t) -/** Number of bits needed to hold all legal values of workqueue_priority_t */ -#define WORKQUEUE_PRIORITY_BITS 2 - -struct workqueue_entry_s { - /** The next workqueue_entry_t that's pending on the same thread or - * reply queue. */ - TOR_TAILQ_ENTRY(workqueue_entry_s) next_work; - /** The threadpool to which this workqueue_entry_t was assigned. This field - * is set when the workqueue_entry_t is created, and won't be cleared until - * after it's handled in the main thread. */ - struct threadpool_s *on_pool; - /** True iff this entry is waiting for a worker to start processing it. */ - uint8_t pending; - /** Priority of this entry. */ - workqueue_priority_bitfield_t priority : WORKQUEUE_PRIORITY_BITS; - /** Function to run in the worker thread. */ - workqueue_reply_t (*fn)(void *state, void *arg); - /** Function to run while processing the reply queue. */ - void (*reply_fn)(void *arg); - /** Argument for the above functions. */ - void *arg; -}; - -struct replyqueue_s { - /** Mutex to protect the answers field */ - tor_mutex_t lock; - /** Doubly-linked list of answers that the reply queue needs to handle. */ - TOR_TAILQ_HEAD(, workqueue_entry_s) answers; - - /** Mechanism to wake up the main thread when it is receiving answers. */ - alert_sockets_t alert; -}; - -/** A worker thread represents a single thread in a thread pool. */ -typedef struct workerthread_s { - /** Which thread it this? In range 0..in_pool->n_threads-1 */ - int index; - /** The pool this thread is a part of. */ - struct threadpool_s *in_pool; - /** User-supplied state field that we pass to the worker functions of each - * work item. */ - void *state; - /** Reply queue to which we pass our results. */ - replyqueue_t *reply_queue; - /** The current update generation of this thread */ - unsigned generation; - /** One over the probability of taking work from a lower-priority queue. */ - int32_t lower_priority_chance; -} workerthread_t; - -static void queue_reply(replyqueue_t *queue, workqueue_entry_t *work); - -/** Allocate and return a new workqueue_entry_t, set up to run the function - * <b>fn</b> in the worker thread, and <b>reply_fn</b> in the main - * thread. See threadpool_queue_work() for full documentation. */ -static workqueue_entry_t * -workqueue_entry_new(workqueue_reply_t (*fn)(void*, void*), - void (*reply_fn)(void*), - void *arg) -{ - workqueue_entry_t *ent = tor_malloc_zero(sizeof(workqueue_entry_t)); - ent->fn = fn; - ent->reply_fn = reply_fn; - ent->arg = arg; - ent->priority = WQ_PRI_HIGH; - return ent; -} - -#define workqueue_entry_free(ent) \ - FREE_AND_NULL(workqueue_entry_t, workqueue_entry_free_, (ent)) - -/** - * Release all storage held in <b>ent</b>. Call only when <b>ent</b> is not on - * any queue. - */ -static void -workqueue_entry_free_(workqueue_entry_t *ent) -{ - if (!ent) - return; - memset(ent, 0xf0, sizeof(*ent)); - tor_free(ent); -} - -/** - * Cancel a workqueue_entry_t that has been returned from - * threadpool_queue_work. - * - * You must not call this function on any work whose reply function has been - * executed in the main thread; that will cause undefined behavior (probably, - * a crash). - * - * If the work is cancelled, this function return the argument passed to the - * work function. It is the caller's responsibility to free this storage. - * - * This function will have no effect if the worker thread has already executed - * or begun to execute the work item. In that case, it will return NULL. - */ -void * -workqueue_entry_cancel(workqueue_entry_t *ent) -{ - int cancelled = 0; - void *result = NULL; - tor_mutex_acquire(&ent->on_pool->lock); - workqueue_priority_t prio = ent->priority; - if (ent->pending) { - TOR_TAILQ_REMOVE(&ent->on_pool->work[prio], ent, next_work); - cancelled = 1; - result = ent->arg; - } - tor_mutex_release(&ent->on_pool->lock); - - if (cancelled) { - workqueue_entry_free(ent); - } - return result; -} - -/**DOCDOC - - must hold lock */ -static int -worker_thread_has_work(workerthread_t *thread) -{ - unsigned i; - for (i = WORKQUEUE_PRIORITY_FIRST; i <= WORKQUEUE_PRIORITY_LAST; ++i) { - if (!TOR_TAILQ_EMPTY(&thread->in_pool->work[i])) - return 1; - } - return thread->generation != thread->in_pool->generation; -} - -/** Extract the next workqueue_entry_t from the the thread's pool, removing - * it from the relevant queues and marking it as non-pending. - * - * The caller must hold the lock. */ -static workqueue_entry_t * -worker_thread_extract_next_work(workerthread_t *thread) -{ - threadpool_t *pool = thread->in_pool; - work_tailq_t *queue = NULL, *this_queue; - unsigned i; - for (i = WORKQUEUE_PRIORITY_FIRST; i <= WORKQUEUE_PRIORITY_LAST; ++i) { - this_queue = &pool->work[i]; - if (!TOR_TAILQ_EMPTY(this_queue)) { - queue = this_queue; - if (! tor_weak_random_one_in_n(&pool->weak_rng, - thread->lower_priority_chance)) { - /* Usually we'll just break now, so that we can get out of the loop - * and use the queue where we found work. But with a small - * probability, we'll keep looking for lower priority work, so that - * we don't ignore our low-priority queues entirely. */ - break; - } - } - } - - if (queue == NULL) - return NULL; - - workqueue_entry_t *work = TOR_TAILQ_FIRST(queue); - TOR_TAILQ_REMOVE(queue, work, next_work); - work->pending = 0; - return work; -} - -/** - * Main function for the worker thread. - */ -static void -worker_thread_main(void *thread_) -{ - workerthread_t *thread = thread_; - threadpool_t *pool = thread->in_pool; - workqueue_entry_t *work; - workqueue_reply_t result; - - tor_mutex_acquire(&pool->lock); - while (1) { - /* lock must be held at this point. */ - while (worker_thread_has_work(thread)) { - /* lock must be held at this point. */ - if (thread->in_pool->generation != thread->generation) { - void *arg = thread->in_pool->update_args[thread->index]; - thread->in_pool->update_args[thread->index] = NULL; - workqueue_reply_t (*update_fn)(void*,void*) = - thread->in_pool->update_fn; - thread->generation = thread->in_pool->generation; - tor_mutex_release(&pool->lock); - - workqueue_reply_t r = update_fn(thread->state, arg); - - if (r != WQ_RPL_REPLY) { - return; - } - - tor_mutex_acquire(&pool->lock); - continue; - } - work = worker_thread_extract_next_work(thread); - if (BUG(work == NULL)) - break; - tor_mutex_release(&pool->lock); - - /* We run the work function without holding the thread lock. This - * is the main thread's first opportunity to give us more work. */ - result = work->fn(thread->state, work->arg); - - /* Queue the reply for the main thread. */ - queue_reply(thread->reply_queue, work); - - /* We may need to exit the thread. */ - if (result != WQ_RPL_REPLY) { - return; - } - tor_mutex_acquire(&pool->lock); - } - /* At this point the lock is held, and there is no work in this thread's - * queue. */ - - /* TODO: support an idle-function */ - - /* Okay. Now, wait till somebody has work for us. */ - if (tor_cond_wait(&pool->condition, &pool->lock, NULL) < 0) { - log_warn(LD_GENERAL, "Fail tor_cond_wait."); - } - } -} - -/** Put a reply on the reply queue. The reply must not currently be on - * any thread's work queue. */ -static void -queue_reply(replyqueue_t *queue, workqueue_entry_t *work) -{ - int was_empty; - tor_mutex_acquire(&queue->lock); - was_empty = TOR_TAILQ_EMPTY(&queue->answers); - TOR_TAILQ_INSERT_TAIL(&queue->answers, work, next_work); - tor_mutex_release(&queue->lock); - - if (was_empty) { - if (queue->alert.alert_fn(queue->alert.write_fd) < 0) { - /* XXXX complain! */ - } - } -} - -/** Allocate and start a new worker thread to use state object <b>state</b>, - * and send responses to <b>replyqueue</b>. */ -static workerthread_t * -workerthread_new(int32_t lower_priority_chance, - void *state, threadpool_t *pool, replyqueue_t *replyqueue) -{ - workerthread_t *thr = tor_malloc_zero(sizeof(workerthread_t)); - thr->state = state; - thr->reply_queue = replyqueue; - thr->in_pool = pool; - thr->lower_priority_chance = lower_priority_chance; - - if (spawn_func(worker_thread_main, thr) < 0) { - //LCOV_EXCL_START - tor_assert_nonfatal_unreached(); - log_err(LD_GENERAL, "Can't launch worker thread."); - tor_free(thr); - return NULL; - //LCOV_EXCL_STOP - } - - return thr; -} - -/** - * Queue an item of work for a thread in a thread pool. The function - * <b>fn</b> will be run in a worker thread, and will receive as arguments the - * thread's state object, and the provided object <b>arg</b>. It must return - * one of WQ_RPL_REPLY, WQ_RPL_ERROR, or WQ_RPL_SHUTDOWN. - * - * Regardless of its return value, the function <b>reply_fn</b> will later be - * run in the main thread when it invokes replyqueue_process(), and will - * receive as its argument the same <b>arg</b> object. It's the reply - * function's responsibility to free the work object. - * - * On success, return a workqueue_entry_t object that can be passed to - * workqueue_entry_cancel(). On failure, return NULL. (Failure is not - * currently possible, but callers should check anyway.) - * - * Items are executed in a loose priority order -- each thread will usually - * take from the queued work with the highest prioirity, but will occasionally - * visit lower-priority queues to keep them from starving completely. - * - * Note that because of priorities and thread behavior, work items may not - * be executed strictly in order. - */ -workqueue_entry_t * -threadpool_queue_work_priority(threadpool_t *pool, - workqueue_priority_t prio, - workqueue_reply_t (*fn)(void *, void *), - void (*reply_fn)(void *), - void *arg) -{ - tor_assert(((int)prio) >= WORKQUEUE_PRIORITY_FIRST && - ((int)prio) <= WORKQUEUE_PRIORITY_LAST); - - workqueue_entry_t *ent = workqueue_entry_new(fn, reply_fn, arg); - ent->on_pool = pool; - ent->pending = 1; - ent->priority = prio; - - tor_mutex_acquire(&pool->lock); - - TOR_TAILQ_INSERT_TAIL(&pool->work[prio], ent, next_work); - - tor_cond_signal_one(&pool->condition); - - tor_mutex_release(&pool->lock); - - return ent; -} - -/** As threadpool_queue_work_priority(), but assumes WQ_PRI_HIGH */ -workqueue_entry_t * -threadpool_queue_work(threadpool_t *pool, - workqueue_reply_t (*fn)(void *, void *), - void (*reply_fn)(void *), - void *arg) -{ - return threadpool_queue_work_priority(pool, WQ_PRI_HIGH, fn, reply_fn, arg); -} - -/** - * Queue a copy of a work item for every thread in a pool. This can be used, - * for example, to tell the threads to update some parameter in their states. - * - * Arguments are as for <b>threadpool_queue_work</b>, except that the - * <b>arg</b> value is passed to <b>dup_fn</b> once per each thread to - * make a copy of it. - * - * UPDATE FUNCTIONS MUST BE IDEMPOTENT. We do not guarantee that every update - * will be run. If a new update is scheduled before the old update finishes - * running, then the new will replace the old in any threads that haven't run - * it yet. - * - * Return 0 on success, -1 on failure. - */ -int -threadpool_queue_update(threadpool_t *pool, - void *(*dup_fn)(void *), - workqueue_reply_t (*fn)(void *, void *), - void (*free_fn)(void *), - void *arg) -{ - int i, n_threads; - void (*old_args_free_fn)(void *arg); - void **old_args; - void **new_args; - - tor_mutex_acquire(&pool->lock); - n_threads = pool->n_threads; - old_args = pool->update_args; - old_args_free_fn = pool->free_update_arg_fn; - - new_args = tor_calloc(n_threads, sizeof(void*)); - for (i = 0; i < n_threads; ++i) { - if (dup_fn) - new_args[i] = dup_fn(arg); - else - new_args[i] = arg; - } - - pool->update_args = new_args; - pool->free_update_arg_fn = free_fn; - pool->update_fn = fn; - ++pool->generation; - - tor_cond_signal_all(&pool->condition); - - tor_mutex_release(&pool->lock); - - if (old_args) { - for (i = 0; i < n_threads; ++i) { - if (old_args[i] && old_args_free_fn) - old_args_free_fn(old_args[i]); - } - tor_free(old_args); - } - - return 0; -} - -/** Don't have more than this many threads per pool. */ -#define MAX_THREADS 1024 - -/** For half of our threads, choose lower priority queues with probability - * 1/N for each of these values. Both are chosen somewhat arbitrarily. If - * CHANCE_PERMISSIVE is too low, then we have a risk of low-priority tasks - * stalling forever. If it's too high, we have a risk of low-priority tasks - * grabbing half of the threads. */ -#define CHANCE_PERMISSIVE 37 -#define CHANCE_STRICT INT32_MAX - -/** Launch threads until we have <b>n</b>. */ -static int -threadpool_start_threads(threadpool_t *pool, int n) -{ - if (BUG(n < 0)) - return -1; // LCOV_EXCL_LINE - if (n > MAX_THREADS) - n = MAX_THREADS; - - tor_mutex_acquire(&pool->lock); - - if (pool->n_threads < n) - pool->threads = tor_reallocarray(pool->threads, - sizeof(workerthread_t*), n); - - while (pool->n_threads < n) { - /* For half of our threads, we'll choose lower priorities permissively; - * for the other half, we'll stick more strictly to higher priorities. - * This keeps slow low-priority tasks from taking over completely. */ - int32_t chance = (pool->n_threads & 1) ? CHANCE_STRICT : CHANCE_PERMISSIVE; - - void *state = pool->new_thread_state_fn(pool->new_thread_state_arg); - workerthread_t *thr = workerthread_new(chance, - state, pool, pool->reply_queue); - - if (!thr) { - //LCOV_EXCL_START - tor_assert_nonfatal_unreached(); - pool->free_thread_state_fn(state); - tor_mutex_release(&pool->lock); - return -1; - //LCOV_EXCL_STOP - } - thr->index = pool->n_threads; - pool->threads[pool->n_threads++] = thr; - } - tor_mutex_release(&pool->lock); - - return 0; -} - -/** - * Construct a new thread pool with <b>n</b> worker threads, configured to - * send their output to <b>replyqueue</b>. The threads' states will be - * constructed with the <b>new_thread_state_fn</b> call, receiving <b>arg</b> - * as its argument. When the threads close, they will call - * <b>free_thread_state_fn</b> on their states. - */ -threadpool_t * -threadpool_new(int n_threads, - replyqueue_t *replyqueue, - void *(*new_thread_state_fn)(void*), - void (*free_thread_state_fn)(void*), - void *arg) -{ - threadpool_t *pool; - pool = tor_malloc_zero(sizeof(threadpool_t)); - tor_mutex_init_nonrecursive(&pool->lock); - tor_cond_init(&pool->condition); - unsigned i; - for (i = WORKQUEUE_PRIORITY_FIRST; i <= WORKQUEUE_PRIORITY_LAST; ++i) { - TOR_TAILQ_INIT(&pool->work[i]); - } - { - unsigned seed; - crypto_rand((void*)&seed, sizeof(seed)); - tor_init_weak_random(&pool->weak_rng, seed); - } - - pool->new_thread_state_fn = new_thread_state_fn; - pool->new_thread_state_arg = arg; - pool->free_thread_state_fn = free_thread_state_fn; - pool->reply_queue = replyqueue; - - if (threadpool_start_threads(pool, n_threads) < 0) { - //LCOV_EXCL_START - tor_assert_nonfatal_unreached(); - tor_cond_uninit(&pool->condition); - tor_mutex_uninit(&pool->lock); - tor_free(pool); - return NULL; - //LCOV_EXCL_STOP - } - - return pool; -} - -/** Return the reply queue associated with a given thread pool. */ -replyqueue_t * -threadpool_get_replyqueue(threadpool_t *tp) -{ - return tp->reply_queue; -} - -/** Allocate a new reply queue. Reply queues are used to pass results from - * worker threads to the main thread. Since the main thread is running an - * IO-centric event loop, it needs to get woken up with means other than a - * condition variable. */ -replyqueue_t * -replyqueue_new(uint32_t alertsocks_flags) -{ - replyqueue_t *rq; - - rq = tor_malloc_zero(sizeof(replyqueue_t)); - if (alert_sockets_create(&rq->alert, alertsocks_flags) < 0) { - //LCOV_EXCL_START - tor_free(rq); - return NULL; - //LCOV_EXCL_STOP - } - - tor_mutex_init(&rq->lock); - TOR_TAILQ_INIT(&rq->answers); - - return rq; -} - -/** Internal: Run from the libevent mainloop when there is work to handle in - * the reply queue handler. */ -static void -reply_event_cb(evutil_socket_t sock, short events, void *arg) -{ - threadpool_t *tp = arg; - (void) sock; - (void) events; - replyqueue_process(tp->reply_queue); - if (tp->reply_cb) - tp->reply_cb(tp); -} - -/** Register the threadpool <b>tp</b>'s reply queue with the libevent - * mainloop of <b>base</b>. If <b>tp</b> is provided, it is run after - * each time there is work to process from the reply queue. Return 0 on - * success, -1 on failure. - */ -int -threadpool_register_reply_event(threadpool_t *tp, - void (*cb)(threadpool_t *tp)) -{ - struct event_base *base = tor_libevent_get_base(); - - if (tp->reply_event) { - tor_event_free(tp->reply_event); - } - tp->reply_event = tor_event_new(base, - tp->reply_queue->alert.read_fd, - EV_READ|EV_PERSIST, - reply_event_cb, - tp); - tor_assert(tp->reply_event); - tp->reply_cb = cb; - return event_add(tp->reply_event, NULL); -} - -/** - * Process all pending replies on a reply queue. The main thread should call - * this function every time the socket returned by replyqueue_get_socket() is - * readable. - */ -void -replyqueue_process(replyqueue_t *queue) -{ - int r = queue->alert.drain_fn(queue->alert.read_fd); - if (r < 0) { - //LCOV_EXCL_START - static ratelim_t warn_limit = RATELIM_INIT(7200); - log_fn_ratelim(&warn_limit, LOG_WARN, LD_GENERAL, - "Failure from drain_fd: %s", - tor_socket_strerror(-r)); - //LCOV_EXCL_STOP - } - - tor_mutex_acquire(&queue->lock); - while (!TOR_TAILQ_EMPTY(&queue->answers)) { - /* lock must be held at this point.*/ - workqueue_entry_t *work = TOR_TAILQ_FIRST(&queue->answers); - TOR_TAILQ_REMOVE(&queue->answers, work, next_work); - tor_mutex_release(&queue->lock); - work->on_pool = NULL; - - work->reply_fn(work->arg); - workqueue_entry_free(work); - - tor_mutex_acquire(&queue->lock); - } - - tor_mutex_release(&queue->lock); -} - diff --git a/src/common/workqueue.h b/src/common/workqueue.h deleted file mode 100644 index e1fe612e2b..0000000000 --- a/src/common/workqueue.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_WORKQUEUE_H -#define TOR_WORKQUEUE_H - -#include "compat.h" - -/** A replyqueue is used to tell the main thread about the outcome of - * work that we queued for the workers. */ -typedef struct replyqueue_s replyqueue_t; -/** A thread-pool manages starting threads and passing work to them. */ -typedef struct threadpool_s threadpool_t; -/** A workqueue entry represents a request that has been passed to a thread - * pool. */ -typedef struct workqueue_entry_s workqueue_entry_t; - -/** Possible return value from a work function: */ -typedef enum workqueue_reply_t { - WQ_RPL_REPLY = 0, /** indicates success */ - WQ_RPL_ERROR = 1, /** indicates fatal error */ - WQ_RPL_SHUTDOWN = 2, /** indicates thread is shutting down */ -} workqueue_reply_t; - -/** Possible priorities for work. Lower numeric values are more important. */ -typedef enum workqueue_priority_t { - WQ_PRI_HIGH = 0, - WQ_PRI_MED = 1, - WQ_PRI_LOW = 2, -} workqueue_priority_t; - -workqueue_entry_t *threadpool_queue_work_priority(threadpool_t *pool, - workqueue_priority_t prio, - workqueue_reply_t (*fn)(void *, - void *), - void (*reply_fn)(void *), - void *arg); - -workqueue_entry_t *threadpool_queue_work(threadpool_t *pool, - workqueue_reply_t (*fn)(void *, - void *), - void (*reply_fn)(void *), - void *arg); - -int threadpool_queue_update(threadpool_t *pool, - void *(*dup_fn)(void *), - workqueue_reply_t (*fn)(void *, void *), - void (*free_fn)(void *), - void *arg); -void *workqueue_entry_cancel(workqueue_entry_t *pending_work); -threadpool_t *threadpool_new(int n_threads, - replyqueue_t *replyqueue, - void *(*new_thread_state_fn)(void*), - void (*free_thread_state_fn)(void*), - void *arg); -replyqueue_t *threadpool_get_replyqueue(threadpool_t *tp); - -replyqueue_t *replyqueue_new(uint32_t alertsocks_flags); -void replyqueue_process(replyqueue_t *queue); - -struct event_base; -int threadpool_register_reply_event(threadpool_t *tp, - void (*cb)(threadpool_t *tp)); - -#endif /* !defined(TOR_WORKQUEUE_H) */ - |