# HG changeset patch # User Matt Johnston # Date 1518838157 -28800 # Node ID eb4c7052f51d4bc8ad39e7beab0c80cee5d70dd1 # Parent 3520d7c2536315a0b24d7e871affabb190d3cb0b# Parent 47f36d8565cfb856f184acc128accfe7d451c17c merge coverity up to date diff -r 3520d7c25363 -r eb4c7052f51d .travis.yml diff -r 3520d7c25363 -r eb4c7052f51d INSTALL --- a/INSTALL Sat Feb 10 19:06:13 2018 +0800 +++ b/INSTALL Sat Feb 17 11:29:17 2018 +0800 @@ -1,20 +1,26 @@ Basic Dropbear build instructions: -- Edit options.h to set which features you want. -- Edit debug.h if you want any debug options (not usually required). +- Edit localoptions.h to set which features you want. Available options + are described in default_options.h.in, these will be overridden by + anything set in localoptions.h -(If using a non-tarball copy, "autoconf; autoheader") +- If using a Mercurial or Git checkout, "autoconf; autoheader" -./configure (optionally with --disable-zlib or --disable-syslog, +- Configure for your system: + ./configure (optionally with --disable-zlib or --disable-syslog, or --help for other options) -Now compile: +- Compile: -make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" + make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" + +- Optionally install, or copy the binaries another way -And install (/usr/local/bin is usual default): + make install (/usr/local/bin is usual default): -make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" install + or + + make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" install (you can leave items out of the PROGRAMS list to avoid compiling them. If you recompile after changing the PROGRAMS list, you *MUST* "make clean" before @@ -25,7 +31,7 @@ If you want to compile statically use ./configure --enable-static By default Dropbear adds various build flags that improve robustness -against programming bugs (good for security) - if these cause problems +against programming bugs (good for security). If these cause problems they can be disabled with ./configure --disable-harden Binaries can be stripped with "make strip" diff -r 3520d7c25363 -r eb4c7052f51d Makefile.in --- a/Makefile.in Sat Feb 10 19:06:13 2018 +0800 +++ b/Makefile.in Sat Feb 17 11:29:17 2018 +0800 @@ -20,11 +20,12 @@ ifeq (@BUNDLED_LIBTOM@, 1) LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM) CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/ -LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM) +LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM) endif ifneq ($(wildcard localoptions.h),) CFLAGS+=-DLOCALOPTIONS_H_EXISTS +LOCALOPTIONS_H=localoptions.h endif COMMONOBJS=dbutil.o buffer.o dbhelpers.o \ @@ -56,13 +57,6 @@ SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o -HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \ - dss.h bignum.h signkey.h rsa.h dbrandom.h service.h auth.h \ - debug.h channel.h chansession.h config.h queue.h sshpty.h \ - termcodes.h gendss.h genrsa.h runopts.h includes.h \ - loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \ - listener.h fake-rfc2553.h ecc.h ecdsa.h - dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS) @@ -97,7 +91,6 @@ # whether we're building client, server, or both for the common objects. # evilness so we detect 'dropbear' by itself as a word -space:= $(empty) $(empty) ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z)))) CFLAGS+= -DDROPBEAR_SERVER endif @@ -128,6 +121,10 @@ all: $(TARGETS) +# a bit lazy, but safer +HEADERS=$(wildcard $(srcdir)/*.h *.h) +*.o: $(HEADERS) + strip: $(TARGETS) $(STRIP) $(addsuffix $(EXEEXT), $(TARGETS)) @@ -200,10 +197,10 @@ -rm -f $*$(EXEEXT) -ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT) -$(STATIC_LTC): options.h +$(STATIC_LTC): $(MAKE) -C libtomcrypt -$(STATIC_LTM): options.h +$(STATIC_LTM): $(MAKE) -C libtommath .PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean @@ -234,7 +231,7 @@ # default_options.h is stored in version control, could not find a workaround # for parallel "make -j" and dependency rules. default_options.h: default_options.h.in - echo "# > > > Generated from $^, edit that file instead !" > $@.tmp - echo >> $@.tmp - $(srcdir)/ifndef_wrapper.sh < $^ > $@.tmp - mv $@.tmp $@ + @echo Creating $@ + @echo "/*\n > > > Do not edit this file (default_options.h) < < <\nGenerated from "$^"\nLocal customisation goes in localoptions.h\n*/\n\n" > $@.tmp + @$(srcdir)/ifndef_wrapper.sh < $^ >> $@.tmp + @mv $@.tmp $@ diff -r 3520d7c25363 -r eb4c7052f51d channel.h --- a/channel.h Sat Feb 10 19:06:13 2018 +0800 +++ b/channel.h Sat Feb 17 11:29:17 2018 +0800 @@ -94,9 +94,9 @@ struct ChanType { int sepfds; /* Whether this channel has separate pipes for in/out or not */ - char *name; + const char *name; int (*inithandler)(struct Channel*); - int (*check_close)(struct Channel*); + int (*check_close)(const struct Channel*); void (*reqhandler)(struct Channel*); void (*closehandler)(const struct Channel*); }; diff -r 3520d7c25363 -r eb4c7052f51d chansession.h --- a/chansession.h Sat Feb 10 19:06:13 2018 +0800 +++ b/chansession.h Sat Feb 17 11:29:17 2018 +0800 @@ -94,6 +94,7 @@ #endif void svr_chansessinitialise(void); +void svr_chansess_checksignal(void); extern const struct ChanType svrchansess; struct SigMap { diff -r 3520d7c25363 -r eb4c7052f51d cli-auth.c --- a/cli-auth.c Sat Feb 10 19:06:13 2018 +0800 +++ b/cli-auth.c Sat Feb 17 11:29:17 2018 +0800 @@ -60,9 +60,11 @@ */ if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) { ses.authstate.authtypes = AUTH_TYPE_PUBKEY; +#if DROPBEAR_USE_DROPBEAR_PASSWORD if (getenv(DROPBEAR_PASSWORD_ENV)) { ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT; } +#endif if (cli_auth_try() == DROPBEAR_SUCCESS) { TRACE(("skipped initial none auth query")) /* Note that there will be two auth responses in-flight */ @@ -335,7 +337,7 @@ { char* password = NULL; -#ifdef DROPBEAR_PASSWORD_ENV +#if DROPBEAR_USE_DROPBEAR_PASSWORD /* Password provided in an environment var */ password = getenv(DROPBEAR_PASSWORD_ENV); if (password) diff -r 3520d7c25363 -r eb4c7052f51d cli-main.c --- a/cli-main.c Sat Feb 10 19:06:13 2018 +0800 +++ b/cli-main.c Sat Feb 17 11:29:17 2018 +0800 @@ -108,7 +108,7 @@ vsnprintf(exitmsg, sizeof(exitmsg), format, param); /* Add the prefix depending on session/auth state */ - if (!sessinitdone) { + if (!ses.init_done) { snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg); } else { snprintf(fullmsg, sizeof(fullmsg), diff -r 3520d7c25363 -r eb4c7052f51d cli-runopts.c --- a/cli-runopts.c Sat Feb 10 19:06:13 2018 +0800 +++ b/cli-runopts.c Sat Feb 17 11:29:17 2018 +0800 @@ -306,10 +306,10 @@ case 'm': #endif case 'D': -#ifndef DROPBEAR_CLI_REMOTETCPFWD +#if !DROPBEAR_CLI_REMOTETCPFWD case 'R': #endif -#ifndef DROPBEAR_CLI_LOCALTCPFWD +#if !DROPBEAR_CLI_LOCALTCPFWD case 'L': #endif case 'V': diff -r 3520d7c25363 -r eb4c7052f51d cli-session.c --- a/cli-session.c Sat Feb 10 19:06:13 2018 +0800 +++ b/cli-session.c Sat Feb 17 11:29:17 2018 +0800 @@ -118,7 +118,7 @@ cli_session_init(proxy_cmd_pid); /* Ready to go */ - sessinitdone = 1; + ses.init_done = 1; /* Exchange identification */ send_session_identification(); @@ -338,7 +338,7 @@ static void cli_session_cleanup(void) { - if (!sessinitdone) { + if (!ses.init_done) { return; } diff -r 3520d7c25363 -r eb4c7052f51d common-session.c --- a/common-session.c Sat Feb 10 19:06:13 2018 +0800 +++ b/common-session.c Sat Feb 17 11:29:17 2018 +0800 @@ -43,13 +43,6 @@ struct sshsession ses; /* GLOBAL */ -/* need to know if the session struct has been initialised, this way isn't the - * cleanest, but works OK */ -int sessinitdone = 0; /* GLOBAL */ - -/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */ -int exitflag = 0; /* GLOBAL */ - /* called only at the start of a session, set up initial state */ void common_session_init(int sock_in, int sock_out) { time_t now; @@ -162,7 +155,6 @@ /* We get woken up when signal handlers write to this pipe. SIGCHLD in svr-chansession is the only one currently. */ FD_SET(ses.signal_pipe[0], &readfd); - ses.channel_signal_pending = 0; /* set up for channels which can be read/written */ setchannelfds(&readfd, &writefd, writequeue_has_space); @@ -190,7 +182,7 @@ val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout); - if (exitflag) { + if (ses.exitflag) { dropbear_exit("Terminated by signal"); } @@ -210,6 +202,7 @@ /* We'll just empty out the pipe if required. We don't do any thing with the data, since the pipe's purpose is purely to wake up the select() above. */ + ses.channel_signal_pending = 0; if (FD_ISSET(ses.signal_pipe[0], &readfd)) { char x; TRACE(("signal pipe set")) @@ -244,6 +237,10 @@ handle_connect_fds(&writefd); + /* loop handler prior to channelio, in case the server loophandler closes + channels on process exit */ + loophandler(); + /* process pipes etc for the channels, ses.dataallowed == 0 * during rekeying ) */ channelio(&readfd, &writefd); @@ -255,11 +252,6 @@ } } - - if (loophandler) { - loophandler(); - } - } /* for(;;) */ /* Not reached */ @@ -280,8 +272,8 @@ TRACE(("enter session_cleanup")) /* we can't cleanup if we don't know the session state */ - if (!sessinitdone) { - TRACE(("leave session_cleanup: !sessinitdone")) + if (!ses.init_done) { + TRACE(("leave session_cleanup: !ses.init_done")) return; } diff -r 3520d7c25363 -r eb4c7052f51d configure.ac --- a/configure.ac Sat Feb 10 19:06:13 2018 +0800 +++ b/configure.ac Sat Feb 17 11:29:17 2018 +0800 @@ -11,7 +11,6 @@ # Checks for programs. AC_PROG_CC -AC_PROG_MAKE_SET if test -z "$LD" ; then LD=$CC @@ -111,6 +110,11 @@ ) # FORTIFY_SOURCE DB_TRYADDCFLAGS([-D_FORTIFY_SOURCE=2]) + + # Spectre v2 mitigations + DB_TRYADDCFLAGS([-mfunction-return=thunk]) + DB_TRYADDCFLAGS([-mindirect-branch=thunk]) + fi # large file support is useful for scp diff -r 3520d7c25363 -r eb4c7052f51d dbrandom.c --- a/dbrandom.c Sat Feb 10 19:06:13 2018 +0800 +++ b/dbrandom.c Sat Feb 17 11:29:17 2018 +0800 @@ -59,7 +59,7 @@ unsigned int readcount; int ret = DROPBEAR_FAILURE; -#ifdef DROPBEAR_PRNGD_SOCKET +#if DROPBEAR_USE_PRNGD if (prngd) { readfd = connect_unix(filename); @@ -107,7 +107,7 @@ wantread = MIN(sizeof(readbuf), len-readcount); } -#ifdef DROPBEAR_PRNGD_SOCKET +#if DROPBEAR_USE_PRNGD if (prngd) { char egdcmd[2]; @@ -157,7 +157,7 @@ static void write_urandom() { -#ifndef DROPBEAR_PRNGD_SOCKET +#if !DROPBEAR_USE_PRNGD /* This is opportunistic, don't worry about failure */ unsigned char buf[INIT_SEED_SIZE]; FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w"); @@ -185,7 +185,7 @@ /* existing state */ sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); -#ifdef DROPBEAR_PRNGD_SOCKET +#if DROPBEAR_USE_PRNGD if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) != DROPBEAR_SUCCESS) { dropbear_exit("Failure reading random device %s", diff -r 3520d7c25363 -r eb4c7052f51d dbutil.c --- a/dbutil.c Sat Feb 10 19:06:13 2018 +0800 +++ b/dbutil.c Sat Feb 17 11:29:17 2018 +0800 @@ -214,7 +214,7 @@ #endif /* DEBUG_TRACE */ /* Connect to a given unix socket. The socket is blocking */ -#ifdef ENABLE_CONNECT_UNIX +#if ENABLE_CONNECT_UNIX int connect_unix(const char* path) { struct sockaddr_un addr; int fd = -1; diff -r 3520d7c25363 -r eb4c7052f51d dbutil.h --- a/dbutil.h Sat Feb 10 19:06:13 2018 +0800 +++ b/dbutil.h Sat Feb 17 11:29:17 2018 +0800 @@ -59,7 +59,7 @@ int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data, int *writefd, int *readfd, int *errfd, pid_t *pid); void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell); -#ifdef ENABLE_CONNECT_UNIX +#if ENABLE_CONNECT_UNIX int connect_unix(const char* addr); #endif int buf_readfile(buffer* buf, const char* filename); diff -r 3520d7c25363 -r eb4c7052f51d debug.h --- a/debug.h Sat Feb 10 19:06:13 2018 +0800 +++ b/debug.h Sat Feb 17 11:29:17 2018 +0800 @@ -33,16 +33,6 @@ * etc. Don't use this normally, it might cause problems */ /* #define DEBUG_VALGRIND */ -/* Define this to compile in trace debugging printf()s. - * You'll need to run programs with "-v" to turn this on. - * - * Caution: Don't use this in an unfriendly environment (ie unfirewalled), - * since the printing may not sanitise strings etc. This will add a reasonable - * amount to your executable size. */ -#ifndef DEBUG_TRACE -#define DEBUG_TRACE 0 -#endif - /* All functions writing to the cleartext payload buffer call * CHECKCLEARTOWRITE() before writing. This is only really useful if you're * attempting to track down a problem */ diff -r 3520d7c25363 -r eb4c7052f51d default_options.h --- a/default_options.h Sat Feb 10 19:06:13 2018 +0800 +++ b/default_options.h Sat Feb 17 11:29:17 2018 +0800 @@ -1,14 +1,20 @@ +/* + > > > Do not edit this file (default_options.h) < < < +Generated from ../default_options.h.in +Local customisation goes in localoptions.h +*/ + + #ifndef DROPBEAR_DEFAULT_OPTIONS_H_ #define DROPBEAR_DEFAULT_OPTIONS_H_ /* > > > Read This < < < -default_options.h.in (this file) documents compile-time options, and provides -default values. +default_options.h.in documents compile-time options, and provides default values. Local customisation should be added to localoptions.h which is used if it exists. Options defined there will override any options in this -file (#ifndef guards added by ifndef_wrapper.sh). +file. Options can also be defined with -DDROPBEAR_XXX in Makefile CFLAGS @@ -381,7 +387,7 @@ #endif /* Default maximum number of failed authentication tries (server option) */ -/* -T runtime option overrides */ +/* -T server option overrides */ #ifndef MAX_AUTH_TRIES #define MAX_AUTH_TRIES 10 #endif diff -r 3520d7c25363 -r eb4c7052f51d default_options.h.in --- a/default_options.h.in Sat Feb 10 19:06:13 2018 +0800 +++ b/default_options.h.in Sat Feb 17 11:29:17 2018 +0800 @@ -3,12 +3,11 @@ /* > > > Read This < < < -default_options.h.in (this file) documents compile-time options, and provides -default values. +default_options.h.in documents compile-time options, and provides default values. Local customisation should be added to localoptions.h which is used if it exists. Options defined there will override any options in this -file (#ifndef guards added by ifndef_wrapper.sh). +file. Options can also be defined with -DDROPBEAR_XXX in Makefile CFLAGS @@ -37,10 +36,9 @@ #define NON_INETD_MODE 1 #define INETD_MODE 1 -/* Setting this disables the fast exptmod bignum code. It saves ~5kB, but is - * perhaps 20% slower for pubkey operations (it is probably worth experimenting - * if you want to use this) */ -/*#define NO_FAST_EXPTMOD*/ +#if !(NON_INETD_MODE || INETD_MODE) + #error "NON_INETD_MODE or INETD_MODE (or both) must be enabled." +#endif /* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save several kB in binary size however will make the symmetrical ciphers and hashes @@ -78,7 +76,7 @@ #define DROPBEAR_CLI_NETCAT 1 /* Whether to support "-c" and "-m" flags to choose ciphers/MACs at runtime */ -#define ENABLE_USER_ALGO_LIST 1 +#define DROPBEAR_USER_ALGO_LIST 1 /* Encryption - at least one required. * Protocol RFC requires 3DES and recommends AES128 for interoperability. @@ -87,10 +85,15 @@ #define DROPBEAR_AES128 1 #define DROPBEAR_3DES 1 #define DROPBEAR_AES256 1 -/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */ -/*#define DROPBEAR_BLOWFISH*/ #define DROPBEAR_TWOFISH256 1 #define DROPBEAR_TWOFISH128 1 +/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */ +#define DROPBEAR_BLOWFISH 0 + +#if !(DROPBEAR_AES128 || DROPBEAR_3DES || DROPBEAR_AES256 || DROPBEAR_BLOWFISH \ + || DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128) + #error "At least one encryption algorithm must be enabled; 3DES and AES128 are recommended." +#endif /* Enable CBC mode for ciphers. This has security issues though * is the most compatible with older SSH implementations */ @@ -130,6 +133,10 @@ * on x86-64 */ #define DROPBEAR_ECDSA 1 +#if !(DROPBEAR_RSA || DROPBEAR_DSS || DROPBEAR_ECDSA) + #error "At least one hostkey or public-key algorithm must be enabled; RSA is recommended." +#endif + /* RSA must be >=1024 */ #define DROPBEAR_DEFAULT_RSA_SIZE 2048 /* DSS is always 1024 */ @@ -194,15 +201,38 @@ * PAM challenge/response. * You can't enable both PASSWORD and PAM. */ +/* PAM requires ./configure --enable-pam */ +#if defined(HAVE_LIBPAM) && !DROPBEAR_SVR_PASSWORD_AUTH + #define DROPBEAR_SVR_PAM_AUTH 1 +#else + #define DROPBEAR_SVR_PAM_AUTH 0 +#endif + /* This requires crypt() */ -#ifdef HAVE_CRYPT -#define DROPBEAR_SVR_PASSWORD_AUTH 1 +#if defined(HAVE_CRYPT) && !DROPBEAR_SVR_PAM_AUTH + #define DROPBEAR_SVR_PASSWORD_AUTH 1 #else -#define DROPBEAR_SVR_PASSWORD_AUTH 0 + #define DROPBEAR_SVR_PASSWORD_AUTH 0 +#endif + +#define DROPBEAR_SVR_PUBKEY_AUTH 1 + +#if !(DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH || DROPBEAR_SVR_PUBKEY_AUTH) + #error "At least one server authentication type must be enabled; PUBKEY and PASSWORD are recommended." #endif -/* PAM requires ./configure --enable-pam */ -#define DROPBEAR_SVR_PAM_AUTH 0 -#define DROPBEAR_SVR_PUBKEY_AUTH 1 + +#if DROPBEAR_SVR_PASSWORD_AUTH && !HAVE_CRYPT + #error "DROPBEAR_SVR_PASSWORD_AUTH requires `crypt()'." +#endif + +#if DROPBEAR_SVR_PAM_AUTH + #if DISABLE_PAM + #error "DROPBEAR_SVR_PAM_AUTH requires 'configure --enable-pam' to succeed." + #endif + #if DROPBEAR_SVR_PASSWORD_AUTH + #error "DROPBEAR_SVR_PASSWORD_AUTH cannot be enabled at the same time as DROPBEAR_SVR_PAM_AUTH." + #endif +#endif /* Whether to take public key options in * authorized_keys file into account */ @@ -210,11 +240,18 @@ /* This requires getpass. */ #ifdef HAVE_GETPASS -#define DROPBEAR_CLI_PASSWORD_AUTH 1 -#define DROPBEAR_CLI_INTERACT_AUTH 1 + #define DROPBEAR_CLI_PASSWORD_AUTH 1 + #define DROPBEAR_CLI_INTERACT_AUTH 1 +#else + #define DROPBEAR_CLI_PASSWORD_AUTH 0 + #define DROPBEAR_CLI_INTERACT_AUTH 0 #endif #define DROPBEAR_CLI_PUBKEY_AUTH 1 +#if !(DROPBEAR_CLI_PASSWORD_AUTH || DROPBEAR_CLI_PUBKEY_AUTH) + #error "At least one client authentication type must be enabled; PUBKEY and PASSWORD are recommended." +#endif + /* A default argument for dbclient -i . Homedir is prepended unless path begins with / */ #define DROPBEAR_DEFAULT_CLI_AUTHKEY ".ssh/id_dropbear" @@ -225,7 +262,7 @@ * note that it will be provided for all "hidden" client-interactive * style prompts - if you want something more sophisticated, use * SSH_ASKPASS instead. Comment out this var to remove this functionality.*/ -#define DROPBEAR_PASSWORD_ENV "DROPBEAR_PASSWORD" +#define DROPBEAR_USE_DROPBEAR_PASSWORD 1 /* Define this (as well as DROPBEAR_CLI_PASSWORD_AUTH) to allow the use of * a helper program for the ssh client. The helper program should be @@ -234,6 +271,10 @@ * return the password on standard output */ #define DROPBEAR_CLI_ASKPASS_HELPER 0 +#if DROPBEAR_CLI_ASKPASS_HELPER + #define DROPBEAR_CLI_PASSWORD_AUTH 1 +#endif + /* Save a network roundtrip by sendng a real auth request immediately after * sending a query for the available methods. It is at the expense of < 100 * bytes of extra network traffic. This is not yet enabled by default since it @@ -246,8 +287,8 @@ #define DROPBEAR_URANDOM_DEV "/dev/urandom" /* Set this to use PRNGD or EGD instead of /dev/urandom or /dev/random */ -/*#define DROPBEAR_PRNGD_SOCKET "/var/run/dropbear-rng"*/ - +#define DROPBEAR_USE_PRNGD 0 +#define DROPBEAR_PRNGD_SOCKET "/var/run/dropbear-rng" /* Specify the number of clients we will allow to be connected but * not yet authenticated. After this limit, connections are rejected */ @@ -270,6 +311,8 @@ * "-q" for quiet */ #define XAUTH_COMMAND "/usr/bin/xauth -q" +#define DROPBEAR_SFTPSERVER 1 + /* if you want to enable running an sftp server (such as the one included with * OpenSSH), set the path below. If the path isn't defined, sftp will not * be enabled */ @@ -315,4 +358,8 @@ /* The default path. This will often get replaced by the shell */ #define DEFAULT_PATH "/usr/bin:/bin" +/* Include verbose debug output, enabled with -v at runtime. + * This will add a reasonable amount to your executable size. */ +#define DEBUG_TRACE 0 + #endif /* DROPBEAR_DEFAULT_OPTIONS_H_ */ diff -r 3520d7c25363 -r eb4c7052f51d ecc.c --- a/ecc.c Sat Feb 10 19:06:13 2018 +0800 +++ b/ecc.c Sat Feb 17 11:29:17 2018 +0800 @@ -221,46 +221,41 @@ /* type valid? */ if (private_key->type != PK_PRIVATE) { - goto done; + goto out; } if (private_key->dp != public_key->dp) { - goto done; + goto out; } /* make new point */ result = ltc_ecc_new_point(); if (result == NULL) { - goto done; + goto out; } prime = m_malloc(sizeof(*prime)); m_mp_init(prime); if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) { - goto done; + goto out; } if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) { - goto done; + goto out; } + shared_secret = m_malloc(sizeof(*shared_secret)); + m_mp_init(shared_secret); + if (mp_copy(result->x, shared_secret) != CRYPT_OK) { + goto out; + } + + mp_clear(prime); + m_free(prime); + ltc_ecc_del_point(result); + err = DROPBEAR_SUCCESS; - done: - if (err == DROPBEAR_SUCCESS) { - shared_secret = m_malloc(sizeof(*shared_secret)); - m_mp_init(shared_secret); - mp_copy(result->x, shared_secret); - } - - if (prime) { - mp_clear(prime); - m_free(prime); - } - if (result) - { - ltc_ecc_del_point(result); - } - + out: if (err == DROPBEAR_FAILURE) { dropbear_exit("ECC error"); } diff -r 3520d7c25363 -r eb4c7052f51d keyimport.c --- a/keyimport.c Sat Feb 10 19:06:13 2018 +0800 +++ b/keyimport.c Sat Feb 17 11:29:17 2018 +0800 @@ -870,7 +870,7 @@ */ numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0'; - #ifdef DROPBEAR_RSA + #if DROPBEAR_RSA if (key->type == DROPBEAR_SIGNKEY_RSA) { if (key->rsakey->p == NULL || key->rsakey->q == NULL) { @@ -966,7 +966,7 @@ } #endif /* DROPBEAR_RSA */ - #ifdef DROPBEAR_DSS + #if DROPBEAR_DSS if (key->type == DROPBEAR_SIGNKEY_DSS) { /* p */ diff -r 3520d7c25363 -r eb4c7052f51d libtomcrypt/src/ciphers/aes/aes.c --- a/libtomcrypt/src/ciphers/aes/aes.c Sat Feb 10 19:06:13 2018 +0800 +++ b/libtomcrypt/src/ciphers/aes/aes.c Sat Feb 17 11:29:17 2018 +0800 @@ -124,7 +124,6 @@ int i; ulong32 temp, *rk; #ifndef ENCRYPT_ONLY - int j; ulong32 *rrk; #endif LTC_ARGCHK(key != NULL); diff -r 3520d7c25363 -r eb4c7052f51d libtomcrypt/src/headers/tomcrypt_custom.h --- a/libtomcrypt/src/headers/tomcrypt_custom.h Sat Feb 10 19:06:13 2018 +0800 +++ b/libtomcrypt/src/headers/tomcrypt_custom.h Sat Feb 17 11:29:17 2018 +0800 @@ -68,8 +68,8 @@ #define LTC_NO_MODES #define LTC_NO_HASHES #define LTC_NO_MACS - #define LTC_NO_PRNGS - #define LTC_NO_PK + #define LTC_NO_PRNGS + #define LTC_NO_PK #define LTC_NO_PKCS #define LTC_NO_MISC #endif /* LTC_NOTHING */ diff -r 3520d7c25363 -r eb4c7052f51d netio.c --- a/netio.c Sat Feb 10 19:06:13 2018 +0800 +++ b/netio.c Sat Feb 17 11:29:17 2018 +0800 @@ -488,7 +488,7 @@ * caller can do a get_socket_address to discover assigned-port * hence, use same port for all address families */ - u_int16_t *allocated_lport_p = 0; + u_int16_t *allocated_lport_p = NULL; int allocated_lport = 0; nsock = 0; @@ -613,7 +613,7 @@ int flags = NI_NUMERICSERV | NI_NUMERICHOST; -#ifndef DO_HOST_LOOKUP +#if !DO_HOST_LOOKUP host_lookup = 0; #endif diff -r 3520d7c25363 -r eb4c7052f51d packet.c --- a/packet.c Sat Feb 10 19:06:13 2018 +0800 +++ b/packet.c Sat Feb 17 11:29:17 2018 +0800 @@ -331,10 +331,6 @@ ses.payload = ses.readbuf; ses.payload_beginning = ses.payload->pos; buf_setlen(ses.payload, ses.payload->pos + len); - /* copy payload */ - //ses.payload = buf_new(len); - //memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len); - //buf_incrlen(ses.payload, len); } ses.readbuf = NULL; diff -r 3520d7c25363 -r eb4c7052f51d runopts.h --- a/runopts.h Sat Feb 10 19:06:13 2018 +0800 +++ b/runopts.h Sat Feb 17 11:29:17 2018 +0800 @@ -86,7 +86,7 @@ int ipv6; */ -#ifdef DO_MOTD +#if DO_MOTD /* whether to print the MOTD */ int domotd; #endif diff -r 3520d7c25363 -r eb4c7052f51d session.h --- a/session.h Sat Feb 10 19:06:13 2018 +0800 +++ b/session.h Sat Feb 17 11:29:17 2018 +0800 @@ -40,9 +40,6 @@ #include "dbutil.h" #include "netio.h" -extern int sessinitdone; /* Is set to 0 somewhere */ -extern int exitflag; - void common_session_init(int sock_in, int sock_out); void session_loop(void(*loophandler)()) ATTRIB_NORETURN; void session_cleanup(void); @@ -157,6 +154,7 @@ int signal_pipe[2]; /* stores endpoints of a self-pipe used for race-free signal handling */ + int channel_signal_pending; /* Flag set when the signal pipe is triggered */ m_list conn_pending; @@ -203,7 +201,6 @@ unsigned int chansize; /* the number of Channel*s allocated for channels */ unsigned int chancount; /* the number of Channel*s in use */ const struct ChanType **chantypes; /* The valid channel types */ - int channel_signal_pending; /* Flag set by sigchld handler */ /* TCP priority level for the main "port 22" tcp socket */ enum dropbear_prio socket_prio; @@ -216,6 +213,10 @@ * really belong here, but nowhere else fits nicely */ int allowprivport; + /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */ + volatile int exitflag; + /* set once the ses structure (and cli_ses/svr_ses) have been populated to their initial state */ + int init_done; }; struct serversession { @@ -283,7 +284,7 @@ /* for escape char handling */ int last_char; - int winchange; /* Set to 1 when a windowchange signal happens */ + volatile int winchange; /* Set to 1 when a windowchange signal happens */ int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD, for the last type of auth we tried */ diff -r 3520d7c25363 -r eb4c7052f51d signkey.c --- a/signkey.c Sat Feb 10 19:06:13 2018 +0800 +++ b/signkey.c Sat Feb 17 11:29:17 2018 +0800 @@ -78,13 +78,13 @@ #if DROPBEAR_ECDSA /* Some of the ECDSA key sizes are defined even if they're not compiled in */ if (0 -#ifndef DROPBEAR_ECC_256 +#if !DROPBEAR_ECC_256 || i == DROPBEAR_SIGNKEY_ECDSA_NISTP256 #endif -#ifndef DROPBEAR_ECC_384 +#if !DROPBEAR_ECC_384 || i == DROPBEAR_SIGNKEY_ECDSA_NISTP384 #endif -#ifndef DROPBEAR_ECC_521 +#if !DROPBEAR_ECC_521 || i == DROPBEAR_SIGNKEY_ECDSA_NISTP521 #endif ) { diff -r 3520d7c25363 -r eb4c7052f51d svr-authpubkey.c --- a/svr-authpubkey.c Sat Feb 10 19:06:13 2018 +0800 +++ b/svr-authpubkey.c Sat Feb 17 11:29:17 2018 +0800 @@ -473,12 +473,4 @@ return DROPBEAR_SUCCESS; } -#ifdef DROPBEAR_FUZZ -int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename, - const char* algo, unsigned int algolen, - const unsigned char* keyblob, unsigned int keybloblen) { - return checkpubkey_line(line, line_num, filename, algo, algolen, keyblob, keybloblen); -} #endif - -#endif diff -r 3520d7c25363 -r eb4c7052f51d svr-authpubkeyoptions.c --- a/svr-authpubkeyoptions.c Sat Feb 10 19:06:13 2018 +0800 +++ b/svr-authpubkeyoptions.c Sat Feb 17 11:29:17 2018 +0800 @@ -100,7 +100,7 @@ chansess->original_command = m_strdup(""); } chansess->cmd = m_strdup(ses.authstate.pubkey_options->forced_command); -#ifdef LOG_COMMANDS +#if LOG_COMMANDS dropbear_log(LOG_INFO, "Command forced to '%s'", chansess->original_command); #endif } diff -r 3520d7c25363 -r eb4c7052f51d svr-chansession.c --- a/svr-chansession.c Sat Feb 10 19:06:13 2018 +0800 +++ b/svr-chansession.c Sat Feb 17 11:29:17 2018 +0800 @@ -80,6 +80,55 @@ return chansess->exit.exitpid != -1; } +void svr_chansess_checksignal(void) { + int status; + pid_t pid; + + if (!ses.channel_signal_pending) { + return; + } + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + unsigned int i; + struct exitinfo *ex = NULL; + TRACE(("sigchld handler: pid %d", pid)) + + ex = NULL; + /* find the corresponding chansess */ + for (i = 0; i < svr_ses.childpidsize; i++) { + if (svr_ses.childpids[i].pid == pid) { + TRACE(("found match session")); + ex = &svr_ses.childpids[i].chansess->exit; + break; + } + } + + /* If the pid wasn't matched, then we might have hit the race mentioned + * above. So we just store the info for the parent to deal with */ + if (ex == NULL) { + TRACE(("using lastexit")); + ex = &svr_ses.lastexit; + } + + ex->exitpid = pid; + if (WIFEXITED(status)) { + ex->exitstatus = WEXITSTATUS(status); + } + if (WIFSIGNALED(status)) { + ex->exitsignal = WTERMSIG(status); +#if !defined(AIX) && defined(WCOREDUMP) + ex->exitcore = WCOREDUMP(status); +#else + ex->exitcore = 0; +#endif + } else { + /* we use this to determine how pid exited */ + ex->exitsignal = -1; + } + + } +} + /* Handler for childs exiting, store the state for return to the client */ /* There's a particular race we have to watch out for: if the forked child @@ -89,63 +138,19 @@ * the parent when it runs. This work correctly at least in the case of a * single shell spawned (ie the usual case) */ static void sesssigchild_handler(int UNUSED(dummy)) { - - int status; - pid_t pid; - unsigned int i; struct sigaction sa_chld; - struct exitinfo *exit = NULL; const int saved_errno = errno; - /* Make channel handling code look for closed channels */ - ses.channel_signal_pending = 1; - TRACE(("enter sigchld handler")) - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - TRACE(("sigchld handler: pid %d", pid)) - - exit = NULL; - /* find the corresponding chansess */ - for (i = 0; i < svr_ses.childpidsize; i++) { - if (svr_ses.childpids[i].pid == pid) { - TRACE(("found match session")); - exit = &svr_ses.childpids[i].chansess->exit; - break; - } - } - - /* If the pid wasn't matched, then we might have hit the race mentioned - * above. So we just store the info for the parent to deal with */ - if (exit == NULL) { - TRACE(("using lastexit")); - exit = &svr_ses.lastexit; - } - exit->exitpid = pid; - if (WIFEXITED(status)) { - exit->exitstatus = WEXITSTATUS(status); - } - if (WIFSIGNALED(status)) { - exit->exitsignal = WTERMSIG(status); -#if !defined(AIX) && defined(WCOREDUMP) - exit->exitcore = WCOREDUMP(status); -#else - exit->exitcore = 0; -#endif - } else { - /* we use this to determine how pid exited */ - exit->exitsignal = -1; - } - - /* Make sure that the main select() loop wakes up */ - while (1) { - /* isserver is just a random byte to write. We can't do anything - about an error so should just ignore it */ - if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 - || errno != EINTR) { - break; - } + /* Make sure that the main select() loop wakes up */ + while (1) { + /* isserver is just a random byte to write. We can't do anything + about an error so should just ignore it */ + if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 + || errno != EINTR) { + break; } } @@ -658,7 +663,7 @@ } } if (issubsys) { -#ifdef SFTPSERVER_PATH +#if DROPBEAR_SFTPSERVER if ((cmdlen == 4) && strncmp(chansess->cmd, "sftp", 4) == 0) { m_free(chansess->cmd); chansess->cmd = m_strdup(SFTPSERVER_PATH); @@ -682,7 +687,7 @@ } -#ifdef LOG_COMMANDS +#if LOG_COMMANDS if (chansess->cmd) { dropbear_log(LOG_INFO, "User %s executing '%s'", ses.authstate.pw_name, chansess->cmd); @@ -769,7 +774,7 @@ pid_t pid; struct logininfo *li = NULL; -#ifdef DO_MOTD +#if DO_MOTD buffer * motdbuf = NULL; int len; struct stat sb; @@ -821,7 +826,7 @@ login_login(li); login_free_entry(li); -#ifdef DO_MOTD +#if DO_MOTD if (svr_opts.domotd && !chansess->cmd) { /* don't show the motd if ~/.hushlogin exists */ @@ -899,7 +904,7 @@ /* Clean up, drop to user privileges, set up the environment and execute * the command/shell. This function does not return. */ static void execchild(const void *user_data) { - struct ChanSess *chansess = user_data; + const struct ChanSess *chansess = user_data; char *usershell = NULL; /* with uClinux we'll have vfork()ed, so don't want to overwrite the diff -r 3520d7c25363 -r eb4c7052f51d svr-main.c --- a/svr-main.c Sat Feb 10 19:06:13 2018 +0800 +++ b/svr-main.c Sat Feb 17 11:29:17 2018 +0800 @@ -35,10 +35,10 @@ static void sigchld_handler(int dummy); static void sigsegv_handler(int); static void sigintterm_handler(int fish); -#ifdef INETD_MODE +#if INETD_MODE static void main_inetd(void); #endif -#ifdef NON_INETD_MODE +#if NON_INETD_MODE static void main_noinetd(void); #endif static void commonsetup(void); @@ -58,7 +58,7 @@ /* get commandline options */ svr_getopts(argc, argv); -#ifdef INETD_MODE +#if INETD_MODE /* service program mode */ if (svr_opts.inetdmode) { main_inetd(); @@ -66,7 +66,7 @@ } #endif -#ifdef NON_INETD_MODE +#if NON_INETD_MODE main_noinetd(); /* notreached */ #endif @@ -76,13 +76,20 @@ } #endif -#ifdef INETD_MODE +#if INETD_MODE static void main_inetd() { char *host, *port = NULL; /* Set up handlers, syslog, seed random */ commonsetup(); +#if DEBUG_TRACE + if (debug_trace) { + /* -v output goes to stderr which would get sent over the inetd network socket */ + dropbear_exit("Dropbear inetd mode is incompatible with debug -v"); + } +#endif + /* In case our inetd was lax in logging source addresses */ get_socket_address(0, NULL, NULL, &host, &port, 0); dropbear_log(LOG_INFO, "Child connection from %s:%s", host, port); @@ -103,7 +110,7 @@ } #endif /* INETD_MODE */ -#ifdef NON_INETD_MODE +#if NON_INETD_MODE static void main_noinetd() { fd_set fds; unsigned int i, j; @@ -188,7 +195,7 @@ val = select(maxsock+1, &fds, NULL, NULL, NULL); - if (exitflag) { + if (ses.exitflag) { unlink(svr_opts.pidfile); dropbear_exit("Terminated by signal"); } @@ -359,7 +366,7 @@ /* catch ctrl-c or sigterm */ static void sigintterm_handler(int UNUSED(unused)) { - exitflag = 1; + ses.exitflag = 1; } /* Things used by inetd and non-inetd modes */ diff -r 3520d7c25363 -r eb4c7052f51d svr-runopts.c --- a/svr-runopts.c Sat Feb 10 19:06:13 2018 +0800 +++ b/svr-runopts.c Sat Feb 17 11:29:17 2018 +0800 @@ -64,7 +64,7 @@ #else "-E Log to stderr rather than syslog\n" #endif -#ifdef DO_MOTD +#if DO_MOTD "-m Don't display the motd on login\n" #endif "-w Disallow root logins\n" @@ -88,7 +88,7 @@ " (default port is %s if none specified)\n" "-P PidFile Create pid file PidFile\n" " (default %s)\n" -#ifdef INETD_MODE +#if INETD_MODE "-i Start for inetd\n" #endif "-W (default %d, larger may be faster, max 1MB)\n" @@ -156,7 +156,7 @@ opts.ipv4 = 1; opts.ipv6 = 1; */ -#ifdef DO_MOTD +#if DO_MOTD svr_opts.domotd = 1; #endif #ifndef DISABLE_SYSLOG @@ -210,7 +210,7 @@ opts.listen_fwd_all = 1; break; #endif -#ifdef INETD_MODE +#if INETD_MODE case 'i': svr_opts.inetdmode = 1; break; @@ -221,7 +221,7 @@ case 'P': next = &svr_opts.pidfile; break; -#ifdef DO_MOTD +#if DO_MOTD /* motd is displayed by default, -m turns it off */ case 'm': svr_opts.domotd = 0; diff -r 3520d7c25363 -r eb4c7052f51d svr-session.c --- a/svr-session.c Sat Feb 10 19:06:13 2018 +0800 +++ b/svr-session.c Sat Feb 17 11:29:17 2018 +0800 @@ -124,7 +124,7 @@ ses.isserver = 1; /* We're ready to go now */ - sessinitdone = 1; + ses.init_done = 1; /* exchange identification, version etc */ send_session_identification(); @@ -136,7 +136,7 @@ /* Run the main for loop. NULL is for the dispatcher - only the client * code makes use of it */ - session_loop(NULL); + session_loop(svr_chansess_checksignal); /* Not reached */ @@ -152,7 +152,7 @@ vsnprintf(exitmsg, sizeof(exitmsg), format, param); /* Add the prefix depending on session/auth state */ - if (!sessinitdone) { + if (!ses.init_done) { /* before session init */ snprintf(fullmsg, sizeof(fullmsg), "Early exit: %s", exitmsg); } else if (ses.authstate.authdone) { diff -r 3520d7c25363 -r eb4c7052f51d svr-tcpfwd.c --- a/svr-tcpfwd.c Sat Feb 10 19:06:13 2018 +0800 +++ b/svr-tcpfwd.c Sat Feb 17 11:29:17 2018 +0800 @@ -35,7 +35,7 @@ #include "auth.h" #include "netio.h" -#ifndef DROPBEAR_SVR_REMOTETCPFWD +#if !DROPBEAR_SVR_REMOTETCPFWD /* This is better than SSH_MSG_UNIMPLEMENTED */ void recv_msg_global_request_remotetcp() { @@ -95,7 +95,7 @@ buf_putint(ses.writepayload, allocated_listen_port); encrypt_packet(); wantreply = 0; //so out does not do so - } + } } else if (strcmp("cancel-tcpip-forward", reqname) == 0) { ret = svr_cancelremotetcp(); } else { diff -r 3520d7c25363 -r eb4c7052f51d sysoptions.h --- a/sysoptions.h Sat Feb 10 19:06:13 2018 +0800 +++ b/sysoptions.h Sat Feb 17 11:29:17 2018 +0800 @@ -192,7 +192,7 @@ #define DROPBEAR_CLI_MULTIHOP ((DROPBEAR_CLI_NETCAT) && (DROPBEAR_CLI_PROXYCMD)) -#define ENABLE_CONNECT_UNIX ((DROPBEAR_CLI_AGENTFWD) || (DROPBEAR_PRNGD_SOCKET)) +#define ENABLE_CONNECT_UNIX ((DROPBEAR_CLI_AGENTFWD) || (DROPBEAR_USE_PRNGD)) /* if we're using authorized_keys or known_hosts */ #define DROPBEAR_KEY_LINES ((DROPBEAR_CLIENT) || (DROPBEAR_SVR_PUBKEY_AUTH))