diff --git a/configure.ac b/configure.ac index d427988b..b8821ff6 100644 --- a/configure.ac +++ b/configure.ac @@ -145,6 +145,8 @@ AS_IF([test -d /sw/lib], [LIBS="$LIBS -L/sw/lib"]) dnl Compiler hardening flags dnl No -fstack-protector-all because it doesn't work on all platforms or architectures. +AX_CFLAGS_WARN_ALL(CFLAGS) + AC_ARG_ENABLE([hardening], AS_HELP_STRING([--disable-hardening], [disable compiler and linker hardening flags])) AS_IF([test "x$enable_hardening" != "xno"], diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4 new file mode 100644 index 00000000..08f2e07e --- /dev/null +++ b/m4/ax_append_flag.m4 @@ -0,0 +1,71 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 6 + +AC_DEFUN([AX_APPEND_FLAG], +[dnl +AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) +AS_VAR_SET_IF(FLAGS,[ + AS_CASE([" AS_VAR_GET(FLAGS) "], + [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], + [ + AS_VAR_APPEND(FLAGS,[" $1"]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) + ], + [ + AS_VAR_SET(FLAGS,[$1]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG diff --git a/m4/ax_cflags_warn_all.m4 b/m4/ax_cflags_warn_all.m4 new file mode 100644 index 00000000..1f077992 --- /dev/null +++ b/m4/ax_cflags_warn_all.m4 @@ -0,0 +1,122 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_CXXFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_FCFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# +# DESCRIPTION +# +# Try to find a compiler option that enables most reasonable warnings. +# +# For the GNU compiler it will be -Wall (and -ansi -pedantic) The result +# is added to the shellvar being CFLAGS, CXXFLAGS, or FCFLAGS by default. +# +# Currently this macro knows about the GCC, Solaris, Digital Unix, AIX, +# HP-UX, IRIX, NEC SX-5 (Super-UX 10), Cray J90 (Unicos 10.0.0.8), and +# Intel compilers. For a given compiler, the Fortran flags are much more +# experimental than their C equivalents. +# +# - $1 shell-variable-to-add-to : CFLAGS, CXXFLAGS, or FCFLAGS +# - $2 add-value-if-not-found : nothing +# - $3 action-if-found : add value to shellvariable +# - $4 action-if-not-found : nothing +# +# NOTE: These macros depend on AX_APPEND_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2010 Rhys Ulerich +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 15 + +AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl +AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings], +VAR,[VAR="no, unknown" +ac_save_[]FLAGS="$[]FLAGS" +for ac_arg dnl +in "-warn all % -warn all" dnl Intel + "-pedantic % -Wall" dnl GCC + "-xstrconst % -v" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix + "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + "-ansi -ansiE % -fullwarn" dnl IRIX + "+ESlit % +w1" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done +FLAGS="$ac_save_[]FLAGS" +]) +AS_VAR_POPDEF([FLAGS])dnl +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;; + *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +])dnl AX_FLAGS_WARN_ALL +dnl implementation tactics: +dnl the for-argument contains a list of options. The first part of +dnl these does only exist to detect the compiler - usually it is +dnl a global option to enable -ansi or -extrawarnings. All other +dnl compilers will fail about it. That was needed since a lot of +dnl compilers will give false positives for some option-syntax +dnl like -Woption or -Xoption as they think of it is a pass-through +dnl to later compile stages or something. The "%" is used as a +dnl delimiter. A non-option comment can be given after "%%" marks +dnl which will be shown but not added to the respective C/CXXFLAGS. + +AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C]) +]) + +AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C++]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C++]) +]) + +AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([Fortran]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([Fortran]) +]) diff --git a/m4/ax_require_defined.m4 b/m4/ax_require_defined.m4 new file mode 100644 index 00000000..cae11112 --- /dev/null +++ b/m4/ax_require_defined.m4 @@ -0,0 +1,37 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_require_defined.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_REQUIRE_DEFINED(MACRO) +# +# DESCRIPTION +# +# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have +# been defined and thus are available for use. This avoids random issues +# where a macro isn't expanded. Instead the configure script emits a +# non-fatal: +# +# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found +# +# It's like AC_REQUIRE except it doesn't expand the required macro. +# +# Here's an example: +# +# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +# +# LICENSE +# +# Copyright (c) 2014 Mike Frysinger +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_REQUIRE_DEFINED], [dnl + m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) +])dnl AX_REQUIRE_DEFINED diff --git a/m4/openssl.m4 b/m4/openssl.m4 index 26cbcbe8..4afcff2f 100644 --- a/m4/openssl.m4 +++ b/m4/openssl.m4 @@ -45,12 +45,14 @@ AC_DEFUN([tinc_OPENSSL], [AC_MSG_ERROR([LibreSSL/OpenSSL libraries not found.])] ) - AC_CHECK_FUNCS([RAND_status EVP_EncryptInit_ex], , + AC_CHECK_FUNCS([RAND_bytes EVP_EncryptInit_ex EVP_CIPHER_CTX_new], , [AC_MSG_ERROR([Missing LibreSSL/OpenSSL functionality, make sure you have installed the latest version.]); break], ) - AC_CHECK_DECLS([OpenSSL_add_all_algorithms], , + AC_CHECK_DECLS([OpenSSL_add_all_algorithms EVP_aes_256_cfb], , [AC_MSG_ERROR([Missing LibreSSL/OpenSSL functionality, make sure you have installed the latest version.]); break], [#include ] ) + + AC_CHECK_FUNCS([BN_GENCB_new ERR_remove_state RSA_set0_key], , , [#include ]) ]) diff --git a/src/Makefile.am b/src/Makefile.am index 3453d513..0dfa952a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,7 @@ ## Produce this file with automake to get Makefile.in -sbin_PROGRAMS = tincd tinc sptps_test sptps_keypair +sbin_PROGRAMS = tincd tinc +EXTRA_PROGRAMS = sptps_test sptps_keypair CLEANFILES = version_git.h @@ -18,7 +19,7 @@ version.c: ${srcdir}/version.c endif if LINUX -sbin_PROGRAMS += sptps_speed +EXTRA_PROGRAMS += sptps_speed endif ed25519_SOURCES = \ diff --git a/src/bsd/tunemu.c b/src/bsd/tunemu.c index 90873d7b..5ca88e3d 100644 --- a/src/bsd/tunemu.c +++ b/src/bsd/tunemu.c @@ -88,7 +88,7 @@ static void tun_error(char *format, ...) { va_list vl; va_start(vl, format); - vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, format, vl); + vsnprintf(tunemu_error, sizeof tunemu_error, format, vl); va_end(vl); } diff --git a/src/cipher.h b/src/cipher.h index 3f98c18f..44db40f8 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -1,6 +1,6 @@ /* cipher.h -- header file cipher.c - Copyright (C) 2007-2013 Guus Sliepen + Copyright (C) 2007-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,10 +30,10 @@ typedef struct cipher cipher_t; extern cipher_t *cipher_open_by_name(const char *) __attribute__ ((__malloc__)); extern cipher_t *cipher_open_by_nid(int) __attribute__ ((__malloc__)); -extern cipher_t *cipher_open_blowfish_ofb(void) __attribute__ ((__malloc__)); extern void cipher_close(cipher_t *); extern size_t cipher_keylength(const cipher_t *); extern size_t cipher_blocksize(const cipher_t *); +extern uint64_t cipher_budget(const cipher_t *); extern void cipher_get_key(const cipher_t *, void *); extern bool cipher_set_key(cipher_t *, void *, bool) __attribute__ ((__warn_unused_result__)); extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool) __attribute__ ((__warn_unused_result__)); diff --git a/src/connection.h b/src/connection.h index 02664d11..51a96e2a 100644 --- a/src/connection.h +++ b/src/connection.h @@ -81,6 +81,8 @@ typedef struct connection_t { cipher_t *outcipher; /* Cipher we will use to send data to him */ digest_t *indigest; digest_t *outdigest; + uint64_t inbudget; + uint64_t outbudget; #endif ecdsa_t *ecdsa; /* his public ECDSA key */ diff --git a/src/digest.h b/src/digest.h index 204048ad..a3691bf0 100644 --- a/src/digest.h +++ b/src/digest.h @@ -1,6 +1,6 @@ /* digest.h -- header file digest.c - Copyright (C) 2007-2013 Guus Sliepen + Copyright (C) 2007-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,6 @@ typedef struct digest digest_t; extern digest_t *digest_open_by_name(const char *name, int maclength) __attribute__ ((__malloc__)); extern digest_t *digest_open_by_nid(int nid, int maclength) __attribute__ ((__malloc__)); -extern digest_t *digest_open_sha1(int maclength) __attribute__ ((__malloc__)); extern void digest_close(digest_t *); extern bool digest_create(digest_t *, const void *indata, size_t inlen, void *outdata) __attribute__ ((__warn_unused_result__)); extern bool digest_verify(digest_t *, const void *indata, size_t inlen, const void *digestdata) __attribute__ ((__warn_unused_result__)); diff --git a/src/dropin.c b/src/dropin.c index fe3b7ef2..a4f7a65d 100644 --- a/src/dropin.c +++ b/src/dropin.c @@ -112,7 +112,7 @@ int vasprintf(char **buf, const char *fmt, va_list ap) { *buf = xrealloc(*buf, status + 1); if(status > len - 1) { - len = status; + len = status + 1; va_copy(aq, ap); status = vsnprintf(*buf, len, fmt, aq); va_end(aq); diff --git a/src/fsck.c b/src/fsck.c index a54dfdfd..569ff10e 100644 --- a/src/fsck.c +++ b/src/fsck.c @@ -298,9 +298,10 @@ int fsck(const char *argv0) { rsa_t *rsa_pub = NULL; f = fopen(fname, "r"); - if(f) + if(f) { rsa_pub = rsa_read_pem_public_key(f); - fclose(f); + fclose(f); + } if(rsa_priv) { if(!rsa_pub) { @@ -353,12 +354,12 @@ int fsck(const char *argv0) { f = fopen(fname, "r"); if(f) { ecdsa_pub = get_pubkey(f); - if(!f) { + if(!ecdsa_pub) { rewind(f); ecdsa_pub = ecdsa_read_pem_public_key(f); } + fclose(f); } - fclose(f); if(ecdsa_priv) { if(!ecdsa_pub) { diff --git a/src/logger.c b/src/logger.c index d9c912d4..6ab538d4 100644 --- a/src/logger.c +++ b/src/logger.c @@ -110,20 +110,22 @@ void logger(int level, int priority, const char *format, ...) { va_start(ap, format); int len = vsnprintf(message, sizeof message, format, ap); + message[sizeof message - 1] = 0; va_end(ap); - if(len > 0 && len < sizeof message && message[len - 1] == '\n') + if(len > 0 && len < sizeof message - 1 && message[len - 1] == '\n') message[len - 1] = 0; real_logger(level, priority, message); } static void sptps_logger(sptps_t *s, int s_errno, const char *format, va_list ap) { - char message[1024] = ""; + char message[1024]; size_t msglen = sizeof message; int len = vsnprintf(message, msglen, format, ap); - if(len > 0 && len < sizeof message) { + message[sizeof message - 1] = 0; + if(len > 0 && len < sizeof message - 1) { if(message[len - 1] == '\n') message[--len] = 0; diff --git a/src/meta.c b/src/meta.c index fd73476c..dcbe4293 100644 --- a/src/meta.c +++ b/src/meta.c @@ -66,6 +66,13 @@ bool send_meta(connection_t *c, const char *buffer, int length) { #ifdef DISABLE_LEGACY return false; #else + if(length > c->outbudget) { + logger(DEBUG_META, LOG_ERR, "Byte limit exceeded for encryption to %s (%s)", c->name, c->hostname); + return false; + } else { + c->outbudget -= length; + } + size_t outlen = length; if(!cipher_encrypt(c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) { @@ -224,6 +231,13 @@ bool receive_meta(connection_t *c) { #ifdef DISABLE_LEGACY return false; #else + if(inlen > c->inbudget) { + logger(DEBUG_META, LOG_ERR, "yte limit exceeded for decryption from %s (%s)", c->name, c->hostname); + return false; + } else { + c->inbudget -= inlen; + } + size_t outlen = inlen; if(!cipher_decrypt(c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || inlen != outlen) { diff --git a/src/net.c b/src/net.c index 8bb9b9aa..375fb5e2 100644 --- a/src/net.c +++ b/src/net.c @@ -95,28 +95,31 @@ void purge(void) { void terminate_connection(connection_t *c, bool report) { logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Closing connection with %s (%s)", c->name, c->hostname); - if(c->node && c->node->connection == c) - c->node->connection = NULL; + if(c->node) { + if(c->node->connection == c) + c->node->connection = NULL; - if(c->edge) { - if(report && !tunnelserver) - send_del_edge(everyone, c->edge); + if(c->edge) { + if(report && !tunnelserver) + send_del_edge(everyone, c->edge); - edge_del(c->edge); - c->edge = NULL; + edge_del(c->edge); + c->edge = NULL; - /* Run MST and SSSP algorithms */ - graph(); + /* Run MST and SSSP algorithms */ - /* If the node is not reachable anymore but we remember it had an edge to us, clean it up */ + graph(); - if(report && !c->node->status.reachable) { - edge_t *e; - e = lookup_edge(c->node, myself); - if(e) { - if(!tunnelserver) - send_del_edge(everyone, e); - edge_del(e); + /* If the node is not reachable anymore but we remember it had an edge to us, clean it up */ + + if(report && !c->node->status.reachable) { + edge_t *e; + e = lookup_edge(c->node, myself); + if(e) { + if(!tunnelserver) + send_del_edge(everyone, e); + edge_del(e); + } } } } diff --git a/src/net_packet.c b/src/net_packet.c index e46709a0..4bb08544 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -357,16 +357,16 @@ static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) { if(seqno != n->received_seqno + 1) { if(seqno >= n->received_seqno + replaywin * 8) { if(n->farfuture++ < replaywin >> 2) { - logger(DEBUG_ALWAYS, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)", + logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)", n->name, n->hostname, seqno - n->received_seqno - 1, n->farfuture); return false; } - logger(DEBUG_ALWAYS, LOG_WARNING, "Lost %d packets from %s (%s)", + logger(DEBUG_TRAFFIC, LOG_WARNING, "Lost %d packets from %s (%s)", seqno - n->received_seqno - 1, n->name, n->hostname); memset(n->late, 0, replaywin); } else if (seqno <= n->received_seqno) { if((n->received_seqno >= replaywin * 8 && seqno <= n->received_seqno - replaywin * 8) || !(n->late[(seqno / 8) % replaywin] & (1 << seqno % 8))) { - logger(DEBUG_ALWAYS, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d", + logger(DEBUG_TRAFFIC, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d", n->name, n->hostname, seqno, n->received_seqno); return false; } @@ -438,7 +438,7 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) { bool receive_tcppacket_sptps(connection_t *c, const char *data, int len) { if (len < sizeof(node_id_t) + sizeof(node_id_t)) { - logger(DEBUG_ALWAYS, LOG_ERR, "Got too short TCP SPTPS packet from %s (%s)", c->name, c->hostname); + logger(DEBUG_PROTOCOL, LOG_ERR, "Got too short TCP SPTPS packet from %s (%s)", c->name, c->hostname); return false; } @@ -773,7 +773,7 @@ bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_ char buf[len + sizeof to->id + sizeof from->id]; char* buf_ptr = buf; memcpy(buf_ptr, &to->id, sizeof to->id); buf_ptr += sizeof to->id; memcpy(buf_ptr, &from->id, sizeof from->id); buf_ptr += sizeof from->id; - memcpy(buf_ptr, data, len); buf_ptr += len; + memcpy(buf_ptr, data, len); logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s) (TCP)", from->name, from->hostname, to->name, to->hostname, to->nexthop->name, to->nexthop->hostname); return send_sptps_tcppacket(to->nexthop->connection, buf, sizeof buf); } diff --git a/src/net_setup.c b/src/net_setup.c index 75f9c87e..e9a8ca79 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -726,7 +726,7 @@ static bool add_listen_address(char *address, bool bindto) { int udp_fd = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); - if(tcp_fd < 0) { + if(udp_fd < 0) { close(tcp_fd); continue; } @@ -909,7 +909,7 @@ static bool setup_myself(void) { /* Generate packet encryption key */ if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher)) - cipher = xstrdup("blowfish"); + cipher = xstrdup("aes-256-cbc"); if(!strcasecmp(cipher, "none")) { myself->incipher = NULL; @@ -933,7 +933,7 @@ static bool setup_myself(void) { } if(!get_config_string(lookup_config(config_tree, "Digest"), &digest)) - digest = xstrdup("sha1"); + digest = xstrdup("sha256"); if(!strcasecmp(digest, "none")) { myself->indigest = NULL; diff --git a/src/net_socket.c b/src/net_socket.c index 094e2668..89330ac5 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -526,6 +526,8 @@ begin: } else if(proxytype == PROXY_EXEC) { result = 0; } else { + if(!proxyai) + abort(); result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen); freeaddrinfo(proxyai); } diff --git a/src/openssl/cipher.c b/src/openssl/cipher.c index 04aee27e..e362325a 100644 --- a/src/openssl/cipher.c +++ b/src/openssl/cipher.c @@ -1,6 +1,6 @@ /* cipher.c -- Symmetric block cipher handling - Copyright (C) 2007-2013 Guus Sliepen + Copyright (C) 2007-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,14 +28,16 @@ #include "../xalloc.h" struct cipher { - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx; const EVP_CIPHER *cipher; }; static cipher_t *cipher_open(const EVP_CIPHER *evp_cipher) { cipher_t *cipher = xzalloc(sizeof *cipher); cipher->cipher = evp_cipher; - EVP_CIPHER_CTX_init(&cipher->ctx); + cipher->ctx = EVP_CIPHER_CTX_new(); + if(!cipher->ctx) + abort(); return cipher; } @@ -60,15 +62,11 @@ cipher_t *cipher_open_by_nid(int nid) { return cipher_open(evp_cipher); } -cipher_t *cipher_open_blowfish_ofb(void) { - return cipher_open(EVP_bf_ofb()); -} - void cipher_close(cipher_t *cipher) { if(!cipher) return; - EVP_CIPHER_CTX_cleanup(&cipher->ctx); + EVP_CIPHER_CTX_free(cipher->ctx); free(cipher); } @@ -76,23 +74,41 @@ size_t cipher_keylength(const cipher_t *cipher) { if(!cipher || !cipher->cipher) return 0; - return cipher->cipher->key_len + cipher->cipher->iv_len; + return EVP_CIPHER_key_length(cipher->cipher) + EVP_CIPHER_iv_length(cipher->cipher); +} + +uint64_t cipher_budget(const cipher_t *cipher) { + /* Hopefully some failsafe way to calculate the maximum amount of bytes to + send/receive with a given cipher before we might run into birthday paradox + attacks. Because we might use different modes, the block size of the mode + might be 1 byte. In that case, use the IV length. Ensure the whole thing + is limited to what can be represented with a 64 bits integer. + */ + + if(!cipher || !cipher->cipher) + return UINT64_MAX; // NULL cipher + + int ivlen = EVP_CIPHER_iv_length(cipher->cipher); + int blklen = EVP_CIPHER_block_size(cipher->cipher); + int len = blklen > 1 ? blklen : ivlen > 1 ? ivlen : 8; + int bits = len * 4 - 1; + return bits < 64 ? UINT64_C(1) << bits : UINT64_MAX; } size_t cipher_blocksize(const cipher_t *cipher) { if(!cipher || !cipher->cipher) return 1; - return cipher->cipher->block_size; + return EVP_CIPHER_block_size(cipher->cipher); } bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) { bool result; if(encrypt) - result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + cipher->cipher->key_len); + result = EVP_EncryptInit_ex(cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + EVP_CIPHER_key_length(cipher->cipher)); else - result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + cipher->cipher->key_len); + result = EVP_DecryptInit_ex(cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + EVP_CIPHER_key_length(cipher->cipher)); if(result) return true; @@ -105,9 +121,9 @@ bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encry bool result; if(encrypt) - result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - cipher->cipher->key_len, (unsigned char *)key + len - cipher->cipher->iv_len - cipher->cipher->key_len); + result = EVP_EncryptInit_ex(cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - EVP_CIPHER_key_length(cipher->cipher), (unsigned char *)key + len - EVP_CIPHER_iv_length(cipher->cipher) - EVP_CIPHER_key_length(cipher->cipher)); else - result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - cipher->cipher->key_len, (unsigned char *)key + len - cipher->cipher->iv_len - cipher->cipher->key_len); + result = EVP_DecryptInit_ex(cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - EVP_CIPHER_key_length(cipher->cipher), (unsigned char *)key + len - EVP_CIPHER_iv_length(cipher->cipher) - EVP_CIPHER_key_length(cipher->cipher)); if(result) return true; @@ -119,15 +135,15 @@ bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encry bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) { if(oneshot) { int len, pad; - if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL) - && EVP_EncryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen) - && EVP_EncryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) { + if(EVP_EncryptInit_ex(cipher->ctx, NULL, NULL, NULL, NULL) + && EVP_EncryptUpdate(cipher->ctx, (unsigned char *)outdata, &len, indata, inlen) + && EVP_EncryptFinal(cipher->ctx, (unsigned char *)outdata + len, &pad)) { if(outlen) *outlen = len + pad; return true; } } else { int len; - if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) { + if(EVP_EncryptUpdate(cipher->ctx, outdata, &len, indata, inlen)) { if(outlen) *outlen = len; return true; } @@ -140,15 +156,15 @@ bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) { if(oneshot) { int len, pad; - if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL) - && EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen) - && EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) { + if(EVP_DecryptInit_ex(cipher->ctx, NULL, NULL, NULL, NULL) + && EVP_DecryptUpdate(cipher->ctx, (unsigned char *)outdata, &len, indata, inlen) + && EVP_DecryptFinal(cipher->ctx, (unsigned char *)outdata + len, &pad)) { if(outlen) *outlen = len + pad; return true; } } else { int len; - if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) { + if(EVP_EncryptUpdate(cipher->ctx, outdata, &len, indata, inlen)) { if(outlen) *outlen = len; return true; } @@ -162,9 +178,9 @@ int cipher_get_nid(const cipher_t *cipher) { if(!cipher || !cipher->cipher) return 0; - return cipher->cipher->nid; + return EVP_CIPHER_nid(cipher->cipher); } bool cipher_active(const cipher_t *cipher) { - return cipher && cipher->cipher && cipher->cipher->nid != 0; + return cipher && cipher->cipher && EVP_CIPHER_nid(cipher->cipher) != 0; } diff --git a/src/openssl/digest.c b/src/openssl/digest.c index 0e600b9d..58ca167f 100644 --- a/src/openssl/digest.c +++ b/src/openssl/digest.c @@ -1,6 +1,6 @@ /* digest.c -- Digest handling - Copyright (C) 2007-2013 Guus Sliepen + Copyright (C) 2007-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -64,10 +64,6 @@ digest_t *digest_open_by_nid(int nid, int maclength) { return digest_open(evp_md, maclength); } -digest_t *digest_open_sha1(int maclength) { - return digest_open(EVP_sha1(), maclength); -} - bool digest_set_key(digest_t *digest, const void *key, size_t len) { digest->key = xrealloc(digest->key, len); memcpy(digest->key, key, len); @@ -93,14 +89,19 @@ bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *out return false; } } else { - EVP_MD_CTX ctx; + EVP_MD_CTX *ctx = EVP_MD_CTX_create(); + if(!ctx) + abort(); - if(!EVP_DigestInit(&ctx, digest->digest) - || !EVP_DigestUpdate(&ctx, indata, inlen) - || !EVP_DigestFinal(&ctx, tmpdata, NULL)) { + if(!EVP_DigestInit(ctx, digest->digest) + || !EVP_DigestUpdate(ctx, indata, inlen) + || !EVP_DigestFinal(ctx, tmpdata, NULL)) { logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL)); + EVP_MD_CTX_destroy(ctx); return false; } + + EVP_MD_CTX_destroy(ctx); } memcpy(outdata, tmpdata, digest->maclength); @@ -118,14 +119,14 @@ int digest_get_nid(const digest_t *digest) { if(!digest || !digest->digest) return 0; - return digest->digest->type; + return EVP_MD_type(digest->digest); } size_t digest_keylength(const digest_t *digest) { if(!digest || !digest->digest) return 0; - return digest->digest->md_size; + return EVP_MD_size(digest->digest); } size_t digest_length(const digest_t *digest) { @@ -136,5 +137,5 @@ size_t digest_length(const digest_t *digest) { } bool digest_active(const digest_t *digest) { - return digest && digest->digest && digest->digest->type != 0; + return digest && digest->digest && EVP_MD_type(digest->digest) != 0; } diff --git a/src/openssl/rsa.c b/src/openssl/rsa.c index 9c1f4984..3033bcd7 100644 --- a/src/openssl/rsa.c +++ b/src/openssl/rsa.c @@ -30,28 +30,51 @@ typedef RSA rsa_t; // Set RSA keys +#ifndef HAVE_RSA_SET0_KEY +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { + BN_free(r->n); r->n = n; + BN_free(r->e); r->e = e; + BN_free(r->d); r->d = d; + return 1; +} +#endif + rsa_t *rsa_set_hex_public_key(char *n, char *e) { + BIGNUM *bn_n = NULL; + BIGNUM *bn_e = NULL; + + if(BN_hex2bn(&bn_n, n) != strlen(n) || BN_hex2bn(&bn_e, e) != strlen(e)) { + BN_free(bn_e); + BN_free(bn_n); + return false; + } + rsa_t *rsa = RSA_new(); if(!rsa) return NULL; - - if(BN_hex2bn(&rsa->n, n) != strlen(n) || BN_hex2bn(&rsa->e, e) != strlen(e)) { - RSA_free(rsa); - return false; - } + + RSA_set0_key(rsa, bn_n, bn_e, NULL); return rsa; } rsa_t *rsa_set_hex_private_key(char *n, char *e, char *d) { + BIGNUM *bn_n = NULL; + BIGNUM *bn_e = NULL; + BIGNUM *bn_d = NULL; + + if(BN_hex2bn(&bn_n, n) != strlen(n) || BN_hex2bn(&bn_e, e) != strlen(e) || BN_hex2bn(&bn_d, d) != strlen(d)) { + BN_free(bn_d); + BN_free(bn_e); + BN_free(bn_n); + return false; + } + rsa_t *rsa = RSA_new(); if(!rsa) return NULL; - if(BN_hex2bn(&rsa->n, n) != strlen(n) || BN_hex2bn(&rsa->e, e) != strlen(e) || BN_hex2bn(&rsa->d, d) != strlen(d)) { - RSA_free(rsa); - return false; - } + RSA_set0_key(rsa, bn_n, bn_e, bn_d); return rsa; } diff --git a/src/openssl/rsagen.c b/src/openssl/rsagen.c index a7e06656..a52dd24d 100644 --- a/src/openssl/rsagen.c +++ b/src/openssl/rsagen.c @@ -27,11 +27,10 @@ typedef RSA rsa_t; #include "../logger.h" #include "../rsagen.h" +#include "../xalloc.h" /* This function prettyprints the key generation process */ - -static void indicator(int a, int b, void *p) { - UNUSED(p); +static int indicator(int a, int b, BN_GENCB *cb) { switch (a) { case 0: fprintf(stderr, "."); @@ -63,12 +62,45 @@ static void indicator(int a, int b, void *p) { default: fprintf(stderr, "?"); } + + return 1; } // Generate RSA key +#ifndef HAVE_BN_GENCB_NEW +BN_GENCB *BN_GENCB_new(void) { + return xzalloc(sizeof(BN_GENCB)); +} + +void BN_GENCB_free(BN_GENCB *cb) { + free(cb); +} +#endif + rsa_t *rsa_generate(size_t bits, unsigned long exponent) { - return RSA_generate_key(bits, exponent, indicator, NULL); + BIGNUM *bn_e = BN_new(); + rsa_t *rsa = RSA_new(); + BN_GENCB *cb = BN_GENCB_new(); + + if(!bn_e || !rsa || !cb) + abort(); + + BN_set_word(bn_e, exponent); + BN_GENCB_set(cb, indicator, NULL); + + int result = RSA_generate_key_ex(rsa, bits, bn_e, cb); + + BN_GENCB_free(cb); + BN_free(bn_e); + + if(!result) { + fprintf(stderr, "Error during key generation!\n"); + RSA_free(rsa); + return NULL; + } + + return rsa; } // Write PEM RSA keys diff --git a/src/protocol.c b/src/protocol.c index ce9b79aa..76b96590 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -72,10 +72,11 @@ bool send_request(connection_t *c, const char *format, ...) { input buffer anyway */ va_start(args, format); - len = vsnprintf(request, MAXBUFSIZE, format, args); + len = vsnprintf(request, sizeof request, format, args); + request[sizeof request - 1] = 0; va_end(args); - if(len < 0 || len > MAXBUFSIZE - 1) { + if(len < 0 || len > sizeof request - 1) { logger(DEBUG_ALWAYS, LOG_ERR, "Output buffer overflow while sending request to %s (%s)", c->name, c->hostname); return false; diff --git a/src/protocol_auth.c b/src/protocol_auth.c index f937f5aa..3bbc2e42 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -1,7 +1,7 @@ /* protocol_auth.c -- handle the meta-protocol, authentication Copyright (C) 1999-2005 Ivo Timmermans, - 2000-2014 Guus Sliepen + 2000-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -425,10 +425,24 @@ bool send_metakey(connection_t *c) { if(!read_rsa_public_key(c)) return false; - if(!(c->outcipher = cipher_open_blowfish_ofb())) + /* We need to use a stream mode for the meta protocol. Use AES for this, + but try to match the key size with the one from the cipher selected + by Cipher. + */ + + int keylen = cipher_keylength(myself->incipher); + if(keylen <= 16) + c->outcipher = cipher_open_by_name("aes-128-cfb"); + else if(keylen <= 24) + c->outcipher = cipher_open_by_name("aes-192-cfb"); + else + c->outcipher = cipher_open_by_name("aes-256-cfb"); + if(!c) return false; - if(!(c->outdigest = digest_open_sha1(-1))) + c->outbudget = cipher_budget(c->outcipher); + + if(!(c->outdigest = digest_open_by_name("sha256", -1))) return false; const size_t len = rsa_size(c->rsa); @@ -540,6 +554,8 @@ bool metakey_h(connection_t *c, const char *request) { c->incipher = NULL; } + c->inbudget = cipher_budget(c->incipher); + if(digest) { if(!(c->indigest = digest_open_by_nid(digest, -1))) { logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of digest from %s (%s)", c->name, c->hostname); @@ -882,8 +898,10 @@ bool ack_h(connection_t *c, const char *request) { socklen_t local_salen = sizeof local_sa; if (getsockname(c->socket, &local_sa.sa, &local_salen) < 0) logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get local socket address for connection with %s", c->name); - else + else { sockaddr_setport(&local_sa, myport); + c->edge->local_address = local_sa; + } c->edge->weight = (weight + c->estimated_weight) / 2; c->edge->connection = c; c->edge->options = c->options; diff --git a/src/protocol_edge.c b/src/protocol_edge.c index f2073456..7ddad03b 100644 --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@ -135,69 +135,56 @@ bool add_edge_h(connection_t *c, const char *request) { e = lookup_edge(from, to); if(e) { - if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) { - if(from == myself) { - logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry", - "ADD_EDGE", c->name, c->hostname); - send_add_edge(c, e); - sockaddrfree(&local_address); - return true; - } else { - /* Update weight first */ - if(e->weight != weight){ - logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) with new weight %s -> %s %d -> %d", - "ADD_EDGE", c->name, c->hostname, e->from->name, e->to->name, e->weight, weight); - edge_update_weigth(e, weight); - } - if (e->options != options) { - logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) with new options %s -> %s %x -> %x", - "ADD_EDGE", c->name, c->hostname, e->from->name, e->to->name, e->options, options); - e->options = options; - } - if (sockaddrcmp(&e->address, &address)) { - logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) with new address %s -> %s", - "ADD_EDGE", c->name, c->hostname, e->from->name, e->to->name); - e->address = address; - } - goto done; - } - } else if(sockaddrcmp(&e->local_address, &local_address)) { - if(from == myself) { - if(e->local_address.sa.sa_family && local_address.sa.sa_family) { - // Someone has the wrong local address for ourself. Correct then. - logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry", - "ADD_EDGE", c->name, c->hostname); - send_add_edge(c, e); - sockaddrfree(&local_address); - return true; - } - // Otherwise, just ignore it. - sockaddrfree(&local_address); - return true; - } else if(local_address.sa.sa_family && local_address.sa.sa_family != AF_UNKNOWN) { - // We learned a new local address for this edge. - // local_address.sa.sa_family will be 0 if we got it from older tinc versions - // local_address.sa.sa_family will be 255 (AF_UNKNOWN) if we got it from newer versions - // but for edge which does not have local_address - sockaddrfree(&e->local_address); - e->local_address = local_address; - - // Tell others about it. - if(!tunnelserver) - forward_request(c, request); - - return true; - } else { - logger(DEBUG_PROTOCOL, LOG_WARNING, "%s:%d %s -> %s - got edge we know from older version? (%d.%d)", - __FUNCTION__, __LINE__, e->from->name, e->to->name, c->protocol_major, c->protocol_minor); - sockaddrfree(&local_address); - return true; - } - } else { + bool new_address = sockaddrcmp(&e->address, &address); + // local_address.sa.sa_family will be 0 if we got it from older tinc versions + // local_address.sa.sa_family will be 255 (AF_UNKNOWN) if we got it from newer versions + // but for edge which does not have local_address + bool new_local_address = local_address.sa.sa_family && local_address.sa.sa_family != AF_UNKNOWN && + sockaddrcmp(&e->local_address, &local_address); + if(e->weight == weight && e->options == options && !new_address && !new_local_address) { + sockaddrfree(&address); sockaddrfree(&local_address); return true; } + + if(from == myself) { + logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry", + "ADD_EDGE", c->name, c->hostname); + send_add_edge(c, e); + sockaddrfree(&address); + sockaddrfree(&local_address); + return true; + } + + logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) which does not match existing entry", + "ADD_EDGE", c->name, c->hostname); + + if (e->options != options) { + logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) with new options %s -> %s %x -> %x", + "ADD_EDGE", c->name, c->hostname, e->from->name, e->to->name, e->options, options); + e->options = options; + } + + if(new_address) { + sockaddrfree(&e->address); + e->address = address; + } else { + sockaddrfree(&address); + } + + if(new_local_address) { + sockaddrfree(&e->local_address); + e->local_address = local_address; + } else { + sockaddrfree(&local_address); + } + + if(e->weight != weight) { + logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) with new weight %s -> %s %d -> %d", + "ADD_EDGE", c->name, c->hostname, e->from->name, e->to->name, e->weight, weight); + edge_update_weigth(e, weight); + } } else if(from == myself) { logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist", "ADD_EDGE", c->name, c->hostname); @@ -207,21 +194,20 @@ bool add_edge_h(connection_t *c, const char *request) { e->to = to; send_del_edge(c, e); free_edge(e); + sockaddrfree(&address); sockaddrfree(&local_address); return true; + } else { + e = new_edge(); + e->from = from; + e->to = to; + e->address = address; + e->local_address = local_address; + e->options = options; + e->weight = weight; + edge_add(e); } - e = new_edge(); - e->from = from; - e->to = to; - e->address = address; - e->local_address = local_address; - e->options = options; - e->weight = weight; - e->avg_rtt = weight/10; - edge_add(e); - -done: /* Tell the rest about the new edge */ if(!tunnelserver) forward_request(c, request); diff --git a/src/sptps.c b/src/sptps.c index 65e11388..56e24397 100644 --- a/src/sptps.c +++ b/src/sptps.c @@ -603,8 +603,6 @@ size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) { memcpy(s->inbuf + s->buflen, data, toread); total_read += toread; s->buflen += toread; - len -= toread; - data += toread; // If we don't have a whole record, exit. if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL)) diff --git a/src/tincctl.c b/src/tincctl.c index 7d993a44..1e026832 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -445,11 +445,13 @@ static bool rsa_keygen(int bits, bool ask) { // Make sure the key size is a multiple of 8 bits. bits &= ~0x7; - // Force them to be between 1024 and 8192 bits long. - if(bits < 1024) - bits = 1024; - if(bits > 8192) - bits = 8192; + // Make sure that a valid key size is used. + if(bits < 1024 || bits > 8192) { + fprintf(stderr, "Invalid key size %d specified! It should be between 1024 and 8192 bits.\n", bits); + return false; + } else if(bits < 2048) { + fprintf(stderr, "WARNING: generating a weak %d bits RSA key! 2048 or more bits are recommended.\n", bits); + } fprintf(stderr, "Generating %d bits keys:\n", bits); @@ -559,6 +561,7 @@ bool sendline(int fd, char *format, ...) { va_start(ap, format); blen = vsnprintf(buffer, sizeof buffer, format, ap); + buffer[sizeof buffer - 1] = 0; va_end(ap); if(blen < 1 || blen >= sizeof buffer) @@ -884,7 +887,7 @@ static int cmd_start(int argc, char *argv[]) { if(!pid) { close(pfd[0]); - char buf[100] = ""; + char buf[100]; snprintf(buf, sizeof buf, "%d", pfd[1]); setenv("TINC_UMBILICAL", buf, true); exit(execvp(c, nargv)); @@ -2538,6 +2541,7 @@ static int cmd_verify(int argc, char *argv[]) { char *newline = memchr(data, '\n', len); if(!newline || (newline - data > MAX_STRING_SIZE - 1)) { fprintf(stderr, "Invalid input\n"); + free(data); return 1; } @@ -2550,11 +2554,13 @@ static int cmd_verify(int argc, char *argv[]) { if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) { fprintf(stderr, "Invalid input\n"); + free(data); return 1; } if(node && strcmp(node, signer)) { fprintf(stderr, "Signature is not made by %s\n", node); + free(data); return 1; } @@ -2851,8 +2857,10 @@ static int cmd_shell(int argc, char *argv[]) { if(nargc == argc) continue; - if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit")) + if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit")) { + free(nargv); return result; + } bool found = false; diff --git a/src/upnp.c b/src/upnp.c index abd2f92f..3bfc770f 100644 --- a/src/upnp.c +++ b/src/upnp.c @@ -57,7 +57,7 @@ static struct UPNPDev *upnp_discover(int delay, int *error) { #elif MINIUPNPC_API_VERSION <= 14 - return upnpDiscover(delay, NULL NULL, false, false, 2, error); + return upnpDiscover(delay, NULL, NULL, false, false, 2, error); #else