From a9f7f10f2001608263a684dfc691e65bd93f929a Mon Sep 17 00:00:00 2001 From: Shibby Date: Mon, 28 Sep 2015 14:29:24 +0200 Subject: [PATCH] dropbear: update to 2015.67 --- .../router/dropbear/.hg_archival.txt | 6 +- release/src-rt-6.x.4708/router/dropbear/.hgsigs | 5 + release/src-rt-6.x.4708/router/dropbear/.hgtags | 6 + .../src-rt-6.x.4708/router/dropbear/.travis.yml | 20 +++ release/src-rt-6.x.4708/router/dropbear/CHANGES | 131 +++++++++++++++++ release/src-rt-6.x.4708/router/dropbear/LICENSE | 2 +- .../src-rt-6.x.4708/router/dropbear/Makefile.in | 42 +++--- release/src-rt-6.x.4708/router/dropbear/README | 2 +- release/src-rt-6.x.4708/router/dropbear/algo.h | 1 + release/src-rt-6.x.4708/router/dropbear/auth.h | 2 +- release/src-rt-6.x.4708/router/dropbear/channel.h | 26 ++-- .../src-rt-6.x.4708/router/dropbear/chansession.h | 8 +- .../src-rt-6.x.4708/router/dropbear/cli-agentfwd.c | 15 +- release/src-rt-6.x.4708/router/dropbear/cli-auth.c | 80 ++++++---- .../router/dropbear/cli-chansession.c | 27 ++-- release/src-rt-6.x.4708/router/dropbear/cli-kex.c | 5 +- release/src-rt-6.x.4708/router/dropbear/cli-main.c | 8 +- .../src-rt-6.x.4708/router/dropbear/cli-runopts.c | 48 ++++-- .../src-rt-6.x.4708/router/dropbear/cli-session.c | 18 +++ .../src-rt-6.x.4708/router/dropbear/cli-tcpfwd.c | 28 +++- .../src-rt-6.x.4708/router/dropbear/common-algo.c | 29 ++-- .../router/dropbear/common-channel.c | 120 ++++++++++++--- .../src-rt-6.x.4708/router/dropbear/common-kex.c | 43 ++++-- .../router/dropbear/common-runopts.c | 5 + .../router/dropbear/common-session.c | 163 ++++++++++++++++----- .../src-rt-6.x.4708/router/dropbear/config.h.in | 12 +- release/src-rt-6.x.4708/router/dropbear/configure | 65 ++++---- .../src-rt-6.x.4708/router/dropbear/configure.ac | 20 ++- release/src-rt-6.x.4708/router/dropbear/dbclient.1 | 16 +- release/src-rt-6.x.4708/router/dropbear/dbutil.c | 102 ++++++++++++- release/src-rt-6.x.4708/router/dropbear/dbutil.h | 14 +- .../router/dropbear/debian/changelog | 30 ++++ release/src-rt-6.x.4708/router/dropbear/dropbear.8 | 9 +- .../router/dropbear/dropbearconvert.1 | 4 +- .../src-rt-6.x.4708/router/dropbear/dropbearkey.1 | 2 +- .../src-rt-6.x.4708/router/dropbear/dropbearkey.c | 3 +- release/src-rt-6.x.4708/router/dropbear/ecdsa.c | 1 + release/src-rt-6.x.4708/router/dropbear/genrsa.c | 26 ++-- .../src-rt-6.x.4708/router/dropbear/gensignkey.c | 5 +- .../src-rt-6.x.4708/router/dropbear/keyimport.c | 22 ++- release/src-rt-6.x.4708/router/dropbear/loginrec.h | 4 +- release/src-rt-6.x.4708/router/dropbear/options.h | 37 +++-- release/src-rt-6.x.4708/router/dropbear/packet.c | 93 +++++++----- .../router/dropbear/process-packet.c | 53 +++++-- release/src-rt-6.x.4708/router/dropbear/release.sh | 40 +++++ release/src-rt-6.x.4708/router/dropbear/rsa.c | 4 +- release/src-rt-6.x.4708/router/dropbear/runopts.h | 12 +- release/src-rt-6.x.4708/router/dropbear/scp.c | 2 +- release/src-rt-6.x.4708/router/dropbear/session.h | 35 +++-- release/src-rt-6.x.4708/router/dropbear/signkey.c | 2 + release/src-rt-6.x.4708/router/dropbear/svr-auth.c | 3 +- .../router/dropbear/svr-chansession.c | 60 +++++--- release/src-rt-6.x.4708/router/dropbear/svr-kex.c | 28 +++- release/src-rt-6.x.4708/router/dropbear/svr-main.c | 8 +- .../src-rt-6.x.4708/router/dropbear/svr-runopts.c | 19 ++- .../src-rt-6.x.4708/router/dropbear/svr-session.c | 18 ++- .../src-rt-6.x.4708/router/dropbear/svr-tcpfwd.c | 24 +-- .../src-rt-6.x.4708/router/dropbear/svr-x11fwd.c | 7 +- .../src-rt-6.x.4708/router/dropbear/sysoptions.h | 15 +- .../src-rt-6.x.4708/router/dropbear/tcp-accept.c | 8 + release/src-rt-6.x.4708/router/dropbear/tcpfwd.h | 4 + 61 files changed, 1250 insertions(+), 397 deletions(-) create mode 100644 release/src-rt-6.x.4708/router/dropbear/.travis.yml create mode 100644 release/src-rt-6.x.4708/router/dropbear/release.sh diff --git a/release/src-rt-6.x.4708/router/dropbear/.hg_archival.txt b/release/src-rt-6.x.4708/router/dropbear/.hg_archival.txt index 3eacbbc9ea..ada464d087 100644 --- a/release/src-rt-6.x.4708/router/dropbear/.hg_archival.txt +++ b/release/src-rt-6.x.4708/router/dropbear/.hg_archival.txt @@ -1,5 +1,5 @@ repo: d7da3b1e15401eb234ec866d5eac992fc4cd5878 -node: 3d1d7d151c0ce3a79da62e86463f5632fa2b144a +node: 48a0ba346de446e413433f93b731187fb4772508 branch: default -latesttag: DROPBEAR_2013.61test -latesttagdistance: 16 +latesttag: DROPBEAR_2015.67 +latesttagdistance: 2 diff --git a/release/src-rt-6.x.4708/router/dropbear/.hgsigs b/release/src-rt-6.x.4708/router/dropbear/.hgsigs index 6b70b75998..10bf8f5a14 100644 --- a/release/src-rt-6.x.4708/router/dropbear/.hgsigs +++ b/release/src-rt-6.x.4708/router/dropbear/.hgsigs @@ -8,3 +8,8 @@ deb211f75ca194e2fcf0d2e5f71c60474e42ec95 0 iEYEABECAAYFAlJO01cACgkQjPn4sExkf7yDq 025237c9f0a1a60a616f984d82fb2a9270d3b0ea 0 iEYEABECAAYFAlJeqDYACgkQjPn4sExkf7y5nQCfW6t+TJySBTTo+gCfDUBPRVxvNe8AoIn/15aWfqH/A2G9uikfoVtWK3pd a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVqACg6IP0fU29+Feh/TDeemDA+2XAzrIAoIdZfMDvVYlDoWotZD8ACFnf5H1P 9ec083a21adfcb099f21eb03704b66d14a4ba800 0 iEYEABECAAYFAlKE4JoACgkQjPn4sExkf7wLDgCghkVGwMjI138bEv+ORVzN7zIH7cEAoLckaxZc1k1aXlmlSCRlP8cuKH3o +3d1d7d151c0ce3a79da62e86463f5632fa2b144a 0 iEYEABECAAYFAlKd5AEACgkQjPn4sExkf7wzWgCfdvPEEIdlMPqcbOQMJ7b+eAyy164An2ip1lPh1eS5g26/gSfruvWBVym4 +277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn +96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m +caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq +2d421bc0545d1be6d59a4ebfe61606d94b124b0c 0 iEYEABECAAYFAlRJDCQACgkQjPn4sExkf7xUYACcCwVJkYWXJn5x/D5A+qMupy778lEAn0rg1oNiq96YU/4jOPsS5IMItihu diff --git a/release/src-rt-6.x.4708/router/dropbear/.hgtags b/release/src-rt-6.x.4708/router/dropbear/.hgtags index eaf691aaec..afd75ca938 100644 --- a/release/src-rt-6.x.4708/router/dropbear/.hgtags +++ b/release/src-rt-6.x.4708/router/dropbear/.hgtags @@ -41,3 +41,9 @@ e76614145aea67f66e4a4257685c771efba21aa1 DROPBEAR_2013.58 7b68e581985fd4ea50869f8608ab95cda5d17876 DROPBEAR_2013.59 a50a1dc743317fad9b3737bc68fbca640659bb6d DROPBEAR_2013.60 e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test +3d1d7d151c0ce3a79da62e86463f5632fa2b144a DROPBEAR_2013.62 +2351b2da8e0d08dcc6e64fcc328b53b9630bda68 DROPBEAR_2014.63 +0d2d39957c029adb7f4327d37fe6b4900f0736d9 DROPBEAR_2014.64 +e9579816f20ea85affc6135e87f8477992808948 DROPBEAR_2014.65 +735511a4c761141416ad0e6728989d2dafa55bc2 DROPBEAR_2014.66 +cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67 diff --git a/release/src-rt-6.x.4708/router/dropbear/.travis.yml b/release/src-rt-6.x.4708/router/dropbear/.travis.yml new file mode 100644 index 0000000000..7e5302abfa --- /dev/null +++ b/release/src-rt-6.x.4708/router/dropbear/.travis.yml @@ -0,0 +1,20 @@ +language: c +compiler: + - gcc + +script: + - autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst && make install + - ~/inst/bin/dropbearkey -t rsa -f testrsa + - ~/inst/bin/dropbearkey -t dss -f testdss + - ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256 + - ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384 + - ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521 + +before_install: + - sudo apt-get update -qq + - sudo apt-get install -qq libz-dev libtomcrypt-dev libtommath-dev + +env: + - BUNDLEDLIBTOM=--disable-bundled-libtom + - BUNDLEDLIBTOM=--enable-bundled-libtom + - MULTI=1 diff --git a/release/src-rt-6.x.4708/router/dropbear/CHANGES b/release/src-rt-6.x.4708/router/dropbear/CHANGES index b93a8df042..6621e8d506 100644 --- a/release/src-rt-6.x.4708/router/dropbear/CHANGES +++ b/release/src-rt-6.x.4708/router/dropbear/CHANGES @@ -1,3 +1,134 @@ +2015.67 - Wednesday 28 January 2015 + +- Call fsync() after generating private keys to ensure they aren't lost if a + reboot occurs. Thanks to Peter Korsgaard + +- Disable non-delayed zlib compression by default on the server. Can be + enabled if required for old clients with DROPBEAR_SERVER_DELAY_ZLIB + +- Default client key path ~/.ssh/id_dropbear + +- Prefer stronger algorithms by default, from Fedor Brunner. + AES256 over 3DES + Diffie-hellman group14 over group1 + +- Add option to disable CBC ciphers. + +- Disable twofish in default options.h + +- Enable sha2 HMAC algorithms by default, the code was already required + for ECC key exchange. sha1 is the first preference still for performance. + +- Fix installing dropbear.8 in a separate build directory, from Like Ma + +- Allow configure to succeed if libtomcrypt/libtommath are missing, from Elan Ruusamäe + +- Don't crash if ssh-agent provides an unknown type of key. From Catalin Patulea + +- Minor bug fixes, a few issues found by Coverity scan + +2014.66 - Thursday 23 October 2014 + +- Use the same keepalive handling behaviour as OpenSSH. This will work better + with some SSH implementations that have different behaviour with unknown + message types. + +- Don't reply with SSH_MSG_UNIMPLEMENTED when we receive a reply to our own + keepalive message + +- Set $SSH_CLIENT to keep bash happy, patch from Ryan Cleere + +- Fix wtmp which broke since 2013.62, patch from Whoopie + +2014.65 - Friday 8 August 2014 + +- Fix 2014.64 regression, server session hang on exit with scp (and probably + others), thanks to NiLuJe for tracking it down + +- Fix 2014.64 regression, clock_gettime() error handling which broke on older + Linux kernels, reported by NiLuJe + +- Fix 2014.64 regression, writev() could occassionally fail with EAGAIN which + wasn't caught + +- Avoid error message when trying to set QoS on proxycommand or multihop pipes + +- Use /usr/bin/xauth, thanks to Mike Frysinger + +- Don't exit the client if the local user entry can't be found, thanks to iquaba + +2014.64 - Sunday 27 July 2014 + +- Fix compiling with ECDSA and DSS disabled + +- Don't exit abruptly if too many outgoing packets are queued for writev(). Patch + thanks to Ronny Meeus + +- The -K keepalive option now behaves more like OpenSSH's "ServerAliveInterval". + If no response is received after 3 keepalives then the session is terminated. This + will close connections faster than waiting for a TCP timeout. + +- Rework TCP priority setting. New settings are + if (connecting || ptys || x11) tos = LOWDELAY + else if (tcp_forwards) tos = 0 + else tos = BULK + Thanks to Catalin Patulea for the suggestion. + +- Improve handling of many concurrent new TCP forwarded connections, should now + be able to handle as many as MAX_CHANNELS. Thanks to Eduardo Silva for reporting + and investigating it. + +- Make sure that exit messages from the client are printed, regression in 2013.57 + +- Use monotonic clock where available, timeouts won't be affected by system time + changes + +- Add -V for version + +2014.63 - Wednesday 19 February 2014 + +- Fix ~. to terminate a client interactive session after waking a laptop + from sleep. + +- Changed port separator syntax again, now using host^port. This is because + IPv6 link-local addresses use %. Reported by Gui Iribarren + +- Avoid constantly relinking dropbearmulti target, fix "make install" + for multi target, thanks to Mike Frysinger + +- Avoid getting stuck in a loop writing huge key files, reported by Bruno + Thomsen + +- Don't link dropbearkey or dropbearconvert to libz or libutil, + thanks to Nicolas Boos + +- Fix linking -lcrypt on systems without /usr/lib, thanks to Nicolas Boos + +- Avoid crash on exit due to cleaned up keys before last packets are sent, + debugged by Ronald Wahl + +- Fix a race condition in rekeying where Dropbear would exit if it received a + still-in-flight packet after initiating rekeying. Reported by Oliver Metz. + This is a longstanding bug but is triggered more easily since 2013.57 + +- Fix README for ecdsa keys, from Catalin Patulea + +- Ensure that generated RSA keys are always exactly the length + requested. Previously Dropbear always generated N+16 or N+15 bit keys. + Thanks to Unit 193 + +- Fix DROPBEAR_CLI_IMMEDIATE_AUTH mode which saves a network round trip if the + first public key succeeds. Still not enabled by default, needs more + compatibility testing with other implementations. + +- Fix for port 0 forwarding in the client and port forwarding with Apache MINA SSHD. Thanks to + +- Fix for bad system linux/pkt-sched.h header file with older Linux +kernels, from Steve Dover + +- Fix signal handlers so that errno is saved, thanks to Erik Ahlén for a patch + and Mark Wickham for independently spotting the same problem. + 2013.62 - Tuesday 3 December 2013 - Disable "interactive" QoS connection options when a connection doesn't diff --git a/release/src-rt-6.x.4708/router/dropbear/LICENSE b/release/src-rt-6.x.4708/router/dropbear/LICENSE index be9d5d8314..828b9af3f6 100644 --- a/release/src-rt-6.x.4708/router/dropbear/LICENSE +++ b/release/src-rt-6.x.4708/router/dropbear/LICENSE @@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below. Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the same license: -Copyright (c) 2002-2013 Matt Johnston +Copyright (c) 2002-2014 Matt Johnston Portions copyright (c) 2004 Mihnea Stoenescu All rights reserved. diff --git a/release/src-rt-6.x.4708/router/dropbear/Makefile.in b/release/src-rt-6.x.4708/router/dropbear/Makefile.in index daa4bb7a6f..8cde521819 100644 --- a/release/src-rt-6.x.4708/router/dropbear/Makefile.in +++ b/release/src-rt-6.x.4708/router/dropbear/Makefile.in @@ -13,13 +13,15 @@ ifndef PROGRAMS PROGRAMS=dropbear dbclient dropbearkey dropbearconvert endif -LTC=libtomcrypt/libtomcrypt.a -LTM=libtommath/libtommath.a +STATIC_LTC=libtomcrypt/libtomcrypt.a +STATIC_LTM=libtommath/libtommath.a + +LIBTOM_LIBS=@LIBTOM_LIBS@ ifeq (@BUNDLED_LIBTOM@, 1) -LIBTOM_DEPS=$(LTC) $(LTM) +LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM) CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/ -LIBS+=$(LTC) $(LTM) +LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM) endif COMMONOBJS=dbutil.o buffer.o \ @@ -58,7 +60,7 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.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) @CRYPTLIB@ +dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS) dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS) @@ -129,23 +131,23 @@ insmultidropbear: dropbearmulti -rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT) -ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT) $(INSTALL) -d $(DESTDIR)$(mandir)/man8 - $(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8 + $(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8 insmulti%: dropbearmulti $(INSTALL) -d $(DESTDIR)$(bindir) -rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT) -ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT) $(INSTALL) -d $(DESTDIR)$(mandir)/man1 - $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1 + if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi # dropbear should go in sbin, so it needs a seperate rule inst_dropbear: dropbear $(INSTALL) -d $(DESTDIR)$(sbindir) $(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir) $(INSTALL) -d $(DESTDIR)$(mandir)/man8 - $(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8 + $(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8 -inst_%: $* +inst_%: % $(INSTALL) -d $(DESTDIR)$(bindir) $(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir) $(INSTALL) -d $(DESTDIR)$(mandir)/man1 @@ -160,8 +162,14 @@ dbclient: $(dbclientobjs) dropbearkey: $(dropbearkeyobjs) dropbearconvert: $(dropbearconvertobjs) -dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile - $(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS) +dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile + $(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@ + +dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile + $(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) + +dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile + $(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) # scp doesn't use the libs so is special. scp: $(SCPOBJS) $(HEADERS) Makefile @@ -171,14 +179,14 @@ scp: $(SCPOBJS) $(HEADERS) Makefile # multi-binary compilation. MULTIOBJS= ifeq ($(MULTI),1) - MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) @CRYPTLIB@ + MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI endif -dropbearmulti: multilink +dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile + $(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@ -multibinary: $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile - $(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS) +multibinary: dropbearmulti$(EXEEXT) multilink: multibinary $(addprefix link, $(PROGRAMS)) @@ -186,10 +194,10 @@ link%: -rm -f $*$(EXEEXT) -ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT) -$(LTC): options.h +$(STATIC_LTC): options.h cd libtomcrypt && $(MAKE) -$(LTM): options.h +$(STATIC_LTM): options.h cd libtommath && $(MAKE) .PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean diff --git a/release/src-rt-6.x.4708/router/dropbear/README b/release/src-rt-6.x.4708/router/dropbear/README index 9ff8d4f054..60ab95c4ef 100644 --- a/release/src-rt-6.x.4708/router/dropbear/README +++ b/release/src-rt-6.x.4708/router/dropbear/README @@ -54,7 +54,7 @@ dropbearkey's '-y' option. To run the server, you need to server keys, this is one-off: ./dropbearkey -t rsa -f dropbear_rsa_host_key ./dropbearkey -t dss -f dropbear_dss_host_key -./dropbearkey -t ecdsa -f dropbear_dss_host_key +./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key or alternatively convert OpenSSH keys to Dropbear: ./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key diff --git a/release/src-rt-6.x.4708/router/dropbear/algo.h b/release/src-rt-6.x.4708/router/dropbear/algo.h index 955864bd57..1758c51ceb 100644 --- a/release/src-rt-6.x.4708/router/dropbear/algo.h +++ b/release/src-rt-6.x.4708/router/dropbear/algo.h @@ -51,6 +51,7 @@ extern algo_type sshhostkey[]; extern algo_type sshciphers[]; extern algo_type sshhashes[]; extern algo_type ssh_compress[]; +extern algo_type ssh_delaycompress[]; extern algo_type ssh_nocompress[]; extern const struct dropbear_cipher dropbear_nocipher; diff --git a/release/src-rt-6.x.4708/router/dropbear/auth.h b/release/src-rt-6.x.4708/router/dropbear/auth.h index 3aed57bb46..66f5b6a470 100644 --- a/release/src-rt-6.x.4708/router/dropbear/auth.h +++ b/release/src-rt-6.x.4708/router/dropbear/auth.h @@ -106,7 +106,7 @@ struct AuthState { valid */ unsigned int failcount; /* Number of (failed) authentication attempts.*/ unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for - client and server (though has differing [obvious] + client and server (though has differing meanings). */ unsigned perm_warn : 1; /* Server only, set if bad permissions on ~/.ssh/authorized_keys have already been diff --git a/release/src-rt-6.x.4708/router/dropbear/channel.h b/release/src-rt-6.x.4708/router/dropbear/channel.h index 714669723d..a310d44eac 100644 --- a/release/src-rt-6.x.4708/router/dropbear/channel.h +++ b/release/src-rt-6.x.4708/router/dropbear/channel.h @@ -29,14 +29,6 @@ #include "buffer.h" #include "circbuffer.h" -/* channel->type values */ -#define CHANNEL_ID_NONE 0 -#define CHANNEL_ID_SESSION 1 -#define CHANNEL_ID_X11 2 -#define CHANNEL_ID_AGENT 3 -#define CHANNEL_ID_TCPDIRECT 4 -#define CHANNEL_ID_TCPFORWARDED 5 - #define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1 #define SSH_OPEN_CONNECT_FAILED 2 #define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3 @@ -49,6 +41,13 @@ struct ChanType; +enum dropbear_channel_prio { + DROPBEAR_CHANNEL_PRIO_INTERACTIVE, /* pty shell, x11 */ + DROPBEAR_CHANNEL_PRIO_UNKNOWABLE, /* tcp - can't know what's being forwarded */ + DROPBEAR_CHANNEL_PRIO_BULK, /* the rest - probably scp or something */ + DROPBEAR_CHANNEL_PRIO_EARLY, /* channel is still being set up */ +}; + struct Channel { unsigned int index; /* the local channel index */ @@ -87,6 +86,8 @@ struct Channel { void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len); const struct ChanType* type; + + enum dropbear_channel_prio prio; }; struct ChanType { @@ -97,7 +98,6 @@ struct ChanType { int (*check_close)(struct Channel*); void (*reqhandler)(struct Channel*); void (*closehandler)(struct Channel*); - }; void chaninitialise(const struct ChanType *chantypes[]); @@ -105,6 +105,9 @@ void chancleanup(); void setchannelfds(fd_set *readfd, fd_set *writefd); void channelio(fd_set *readfd, fd_set *writefd); struct Channel* getchannel(); +/* Returns an arbitrary channel that is in a ready state - not +being initialised and no EOF in either direction. NULL if none. */ +struct Channel* get_any_ready_channel(); void recv_msg_channel_open(); void recv_msg_channel_request(); @@ -128,5 +131,10 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type); void recv_msg_channel_open_confirmation(); void recv_msg_channel_open_failure(); #endif +void start_send_channel_request(struct Channel *channel, unsigned char *type); + +void send_msg_request_success(); +void send_msg_request_failure(); + #endif /* _CHANNEL_H_ */ diff --git a/release/src-rt-6.x.4708/router/dropbear/chansession.h b/release/src-rt-6.x.4708/router/dropbear/chansession.h index ef252eaf7e..4078123c65 100644 --- a/release/src-rt-6.x.4708/router/dropbear/chansession.h +++ b/release/src-rt-6.x.4708/router/dropbear/chansession.h @@ -51,9 +51,12 @@ struct ChanSess { /* exit details */ struct exitinfo exit; - /* Used to set $SSH_CONNECTION in the child session. - Is only set temporarily before forking */ + + /* These are only set temporarily before forking */ + /* Used to set $SSH_CONNECTION in the child session. */ char *connection_string; + /* Used to set $SSH_CLIENT in the child session. */ + char *client_string; #ifndef DISABLE_X11FWD struct Listener * x11listener; @@ -89,7 +92,6 @@ void cli_chansess_winchange(); #ifdef ENABLE_CLI_NETCAT void cli_send_netcat_request(); #endif -void cli_start_send_channel_request(struct Channel *channel, unsigned char *type); void svr_chansessinitialise(); extern const struct ChanType svrchansess; diff --git a/release/src-rt-6.x.4708/router/dropbear/cli-agentfwd.c b/release/src-rt-6.x.4708/router/dropbear/cli-agentfwd.c index 4ec555b37b..aea5e647a8 100644 --- a/release/src-rt-6.x.4708/router/dropbear/cli-agentfwd.c +++ b/release/src-rt-6.x.4708/router/dropbear/cli-agentfwd.c @@ -210,13 +210,14 @@ static void agent_get_key_list(m_list * ret_list) ret = buf_get_pub_key(key_buf, pubkey, &key_type); buf_free(key_buf); if (ret != DROPBEAR_SUCCESS) { - /* This is slack, properly would cleanup vars etc */ - dropbear_exit("Bad pubkey received from agent"); - } - pubkey->type = key_type; - pubkey->source = SIGNKEY_SOURCE_AGENT; + TRACE(("Skipping bad/unknown type pubkey from agent")); + sign_key_free(pubkey); + } else { + pubkey->type = key_type; + pubkey->source = SIGNKEY_SOURCE_AGENT; - list_append(ret_list, pubkey); + list_append(ret_list, pubkey); + } /* We'll ignore the comment for now. might want it later.*/ buf_eatstring(inbuf); @@ -234,7 +235,7 @@ void cli_setup_agent(struct Channel *channel) { return; } - cli_start_send_channel_request(channel, "auth-agent-req@openssh.com"); + start_send_channel_request(channel, "auth-agent-req@openssh.com"); /* Don't want replies */ buf_putbyte(ses.writepayload, 0); encrypt_packet(); diff --git a/release/src-rt-6.x.4708/router/dropbear/cli-auth.c b/release/src-rt-6.x.4708/router/dropbear/cli-auth.c index efa9e9b273..70ace65861 100644 --- a/release/src-rt-6.x.4708/router/dropbear/cli-auth.c +++ b/release/src-rt-6.x.4708/router/dropbear/cli-auth.c @@ -41,16 +41,6 @@ void cli_authinitialise() { /* Send a "none" auth request to get available methods */ void cli_auth_getmethods() { TRACE(("enter cli_auth_getmethods")) -#ifdef CLI_IMMEDIATE_AUTH - ses.authstate.authtypes = AUTH_TYPE_PUBKEY; - if (getenv(DROPBEAR_PASSWORD_ENV)) { - ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT; - } - if (cli_auth_try() == DROPBEAR_SUCCESS) { - TRACE(("skipped initial none auth query")) - return; - } -#endif CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); buf_putstring(ses.writepayload, cli_opts.username, @@ -60,6 +50,26 @@ void cli_auth_getmethods() { buf_putstring(ses.writepayload, "none", 4); /* 'none' method */ encrypt_packet(); + +#ifdef DROPBEAR_CLI_IMMEDIATE_AUTH + /* We can't haven't two auth requests in-flight with delayed zlib mode + since if the first one succeeds then the remote side will + expect the second one to be compressed. + Race described at + http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/zlib-openssh.html + */ + if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) { + ses.authstate.authtypes = AUTH_TYPE_PUBKEY; + if (getenv(DROPBEAR_PASSWORD_ENV)) { + ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT; + } + if (cli_auth_try() == DROPBEAR_SUCCESS) { + TRACE(("skipped initial none auth query")) + /* Note that there will be two auth responses in-flight */ + cli_ses.ignore_next_auth_response = 1; + } + } +#endif TRACE(("leave cli_auth_getmethods")) } @@ -150,31 +160,46 @@ void recv_msg_userauth_failure() { TRACE(("<- MSG_USERAUTH_FAILURE")) TRACE(("enter recv_msg_userauth_failure")) + if (ses.authstate.authdone) { + TRACE(("leave recv_msg_userauth_failure, already authdone.")) + return; + } + if (cli_ses.state != USERAUTH_REQ_SENT) { /* Perhaps we should be more fatal? */ dropbear_exit("Unexpected userauth failure"); } + /* When DROPBEAR_CLI_IMMEDIATE_AUTH is set there will be an initial response for + the "none" auth request, and then a response to the immediate auth request. + We need to be careful handling them. */ + if (cli_ses.ignore_next_auth_response) { + cli_ses.state = USERAUTH_REQ_SENT; + cli_ses.ignore_next_auth_response = 0; + TRACE(("leave recv_msg_userauth_failure, ignored response, state set to USERAUTH_REQ_SENT")); + return; + } else { #ifdef ENABLE_CLI_PUBKEY_AUTH - /* If it was a pubkey auth request, we should cross that key - * off the list. */ - if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) { - cli_pubkeyfail(); - } + /* If it was a pubkey auth request, we should cross that key + * off the list. */ + if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) { + cli_pubkeyfail(); + } #endif #ifdef ENABLE_CLI_INTERACT_AUTH - /* If we get a failure message for keyboard interactive without - * receiving any request info packet, then we don't bother trying - * keyboard interactive again */ - if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT - && !cli_ses.interact_request_received) { - TRACE(("setting auth_interact_failed = 1")) - cli_ses.auth_interact_failed = 1; - } + /* If we get a failure message for keyboard interactive without + * receiving any request info packet, then we don't bother trying + * keyboard interactive again */ + if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT + && !cli_ses.interact_request_received) { + TRACE(("setting auth_interact_failed = 1")) + cli_ses.auth_interact_failed = 1; + } #endif - - cli_ses.lastauthtype = AUTH_TYPE_NONE; + cli_ses.state = USERAUTH_FAIL_RCVD; + cli_ses.lastauthtype = AUTH_TYPE_NONE; + } methods = buf_getstring(ses.payload, &methlen); @@ -227,13 +252,14 @@ void recv_msg_userauth_failure() { } m_free(methods); - - cli_ses.state = USERAUTH_FAIL_RCVD; TRACE(("leave recv_msg_userauth_failure")) } void recv_msg_userauth_success() { + /* This function can validly get called multiple times + if DROPBEAR_CLI_IMMEDIATE_AUTH is set */ + TRACE(("received msg_userauth_success")) /* Note: in delayed-zlib mode, setting authdone here * will enable compression in the transport layer */ diff --git a/release/src-rt-6.x.4708/router/dropbear/cli-chansession.c b/release/src-rt-6.x.4708/router/dropbear/cli-chansession.c index fa97a6a015..57457d2362 100644 --- a/release/src-rt-6.x.4708/router/dropbear/cli-chansession.c +++ b/release/src-rt-6.x.4708/router/dropbear/cli-chansession.c @@ -41,7 +41,7 @@ static void cli_chansessreq(struct Channel *channel); static void send_chansess_pty_req(struct Channel *channel); static void send_chansess_shell_req(struct Channel *channel); static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len); - +static int cli_init_netcat(struct Channel *channel); static void cli_tty_setup(); @@ -92,17 +92,6 @@ static void cli_closechansess(struct Channel *UNUSED(channel)) { } } -void cli_start_send_channel_request(struct Channel *channel, - unsigned char *type) { - - CHECKCLEARTOWRITE(); - buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST); - buf_putint(ses.writepayload, channel->remotechan); - - buf_putstring(ses.writepayload, type, strlen(type)); - -} - /* Taken from OpenSSH's sshtty.c: * RCSID("OpenBSD: sshtty.c,v 1.5 2003/09/19 17:43:35 markus Exp "); */ static void cli_tty_setup() { @@ -287,7 +276,7 @@ static void send_chansess_pty_req(struct Channel *channel) { TRACE(("enter send_chansess_pty_req")) - cli_start_send_channel_request(channel, "pty-req"); + start_send_channel_request(channel, "pty-req"); /* Don't want replies */ buf_putbyte(ses.writepayload, 0); @@ -330,7 +319,7 @@ static void send_chansess_shell_req(struct Channel *channel) { reqtype = "shell"; } - cli_start_send_channel_request(channel, reqtype); + start_send_channel_request(channel, reqtype); /* XXX TODO */ buf_putbyte(ses.writepayload, 0); /* Don't want replies */ @@ -357,6 +346,11 @@ static int cli_init_stdpipe_sess(struct Channel *channel) { return 0; } +static int cli_init_netcat(struct Channel *channel) { + channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; + return cli_init_stdpipe_sess(channel); +} + static int cli_initchansess(struct Channel *channel) { cli_init_stdpipe_sess(channel); @@ -369,8 +363,9 @@ static int cli_initchansess(struct Channel *channel) { if (cli_opts.wantpty) { send_chansess_pty_req(channel); + channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE; } else { - set_sock_priority(ses.sock_out, DROPBEAR_PRIO_BULK); + channel->prio = DROPBEAR_CHANNEL_PRIO_BULK; } send_chansess_shell_req(channel); @@ -389,7 +384,7 @@ static int cli_initchansess(struct Channel *channel) { static const struct ChanType cli_chan_netcat = { 0, /* sepfds */ "direct-tcpip", - cli_init_stdpipe_sess, /* inithandler */ + cli_init_netcat, /* inithandler */ NULL, NULL, cli_closechansess diff --git a/release/src-rt-6.x.4708/router/dropbear/cli-kex.c b/release/src-rt-6.x.4708/router/dropbear/cli-kex.c index 55b00415fc..a590157913 100644 --- a/release/src-rt-6.x.4708/router/dropbear/cli-kex.c +++ b/release/src-rt-6.x.4708/router/dropbear/cli-kex.c @@ -86,8 +86,6 @@ void send_msg_kexdh_init() { cli_ses.param_kex_algo = ses.newkeys->algo_kex; encrypt_packet(); - ses.requirenext[0] = SSH_MSG_KEXDH_REPLY; - ses.requirenext[1] = SSH_MSG_KEXINIT; } /* Handle a diffie-hellman key exchange reply. */ @@ -179,8 +177,7 @@ void recv_msg_kexdh_reply() { hostkey = NULL; send_msg_newkeys(); - ses.requirenext[0] = SSH_MSG_NEWKEYS; - ses.requirenext[1] = 0; + ses.requirenext = SSH_MSG_NEWKEYS; TRACE(("leave recv_msg_kexdh_init")) } diff --git a/release/src-rt-6.x.4708/router/dropbear/cli-main.c b/release/src-rt-6.x.4708/router/dropbear/cli-main.c index 3db8f2ff4d..0b4047c240 100644 --- a/release/src-rt-6.x.4708/router/dropbear/cli-main.c +++ b/release/src-rt-6.x.4708/router/dropbear/cli-main.c @@ -75,9 +75,6 @@ int main(int argc, char ** argv) { int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport, 0, &error); sock_in = sock_out = sock; - if (cli_opts.wantpty) { - set_sock_priority(sock, DROPBEAR_PRIO_LOWDELAY); - } } if (sock_in < 0) { @@ -107,9 +104,10 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) { /* Do the cleanup first, since then the terminal will be reset */ session_cleanup(); + /* Avoid printing onwards from terminal cruft */ + fprintf(stderr, "\n"); _dropbear_log(LOG_INFO, fmtbuf, param); - exit(exitcode); } @@ -121,7 +119,7 @@ static void cli_dropbear_log(int UNUSED(priority), vsnprintf(printbuf, sizeof(printbuf), format, param); fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf); - + fflush(stderr); } static void exec_proxy_cmd(void *user_data_cmd) { diff --git a/release/src-rt-6.x.4708/router/dropbear/cli-runopts.c b/release/src-rt-6.x.4708/router/dropbear/cli-runopts.c index 9877740e55..467776b5bc 100644 --- a/release/src-rt-6.x.4708/router/dropbear/cli-runopts.c +++ b/release/src-rt-6.x.4708/router/dropbear/cli-runopts.c @@ -38,7 +38,7 @@ static void parse_hostname(const char* orighostarg); static void parse_multihop_hostname(const char* orighostarg, const char* argv0); static void fill_own_user(); #ifdef ENABLE_CLI_PUBKEY_AUTH -static void loadidentityfile(const char* filename); +static void loadidentityfile(const char* filename, int warnfail); #endif #ifdef ENABLE_CLI_ANYTCPFWD static void addforward(const char* str, m_list *fwdlist); @@ -65,7 +65,7 @@ static void printhelp() { "-y -y Don't perform any remote host key checking (caution)\n" "-s Request a subsystem (use by external sftp)\n" #ifdef ENABLE_CLI_PUBKEY_AUTH - "-i (multiple allowed)\n" + "-i (multiple allowed, default %s)\n" #endif #ifdef ENABLE_CLI_AGENTFWD "-A Enable agent auth forwarding\n" @@ -90,10 +90,14 @@ static void printhelp() { "-c Specify preferred ciphers ('-c help' to list options)\n" "-m Specify preferred MACs for packet verification (or '-m help')\n" #endif + "-V Version\n" #ifdef DEBUG_TRACE "-v verbose (compiled with DEBUG_TRACE)\n" #endif ,DROPBEAR_VERSION, cli_opts.progname, +#ifdef ENABLE_CLI_PUBKEY_AUTH + DROPBEAR_DEFAULT_CLI_AUTHKEY, +#endif DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT); } @@ -152,7 +156,7 @@ void cli_getopts(int argc, char ** argv) { cli_opts.proxycmd = NULL; #endif #ifndef DISABLE_ZLIB - opts.enable_compress = 1; + opts.compress_mode = DROPBEAR_COMPRESS_ON; #endif #ifdef ENABLE_USER_ALGO_LIST opts.cipher_list = NULL; @@ -163,6 +167,8 @@ void cli_getopts(int argc, char ** argv) { opts.ipv6 = 1; */ opts.recv_window = DEFAULT_RECV_WINDOW; + opts.keepalive_secs = DEFAULT_KEEPALIVE; + opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT; fill_own_user(); @@ -171,7 +177,7 @@ void cli_getopts(int argc, char ** argv) { #ifdef ENABLE_CLI_PUBKEY_AUTH if (nextiskey) { /* Load a hostkey since the previous argument was "-i" */ - loadidentityfile(argv[i]); + loadidentityfile(argv[i], 1); nextiskey = 0; continue; } @@ -228,7 +234,7 @@ void cli_getopts(int argc, char ** argv) { case 'i': /* an identityfile */ /* Keep scp happy when it changes "-i file" to "-ifile" */ if (strlen(argv[i]) > 2) { - loadidentityfile(&argv[i][2]); + loadidentityfile(&argv[i][2], 1); } else { nextiskey = 1; } @@ -322,6 +328,10 @@ void cli_getopts(int argc, char ** argv) { #ifndef ENABLE_CLI_LOCALTCPFWD case 'L': #endif + case 'V': + print_version(); + exit(EXIT_SUCCESS); + break; case 'o': case 'b': next = &dummy; @@ -437,6 +447,14 @@ void cli_getopts(int argc, char ** argv) { } #endif +#ifdef DROPBEAR_DEFAULT_CLI_AUTHKEY + { + char *expand_path = expand_tilde(DROPBEAR_DEFAULT_CLI_AUTHKEY); + loadidentityfile(expand_path, 0); + m_free(expand_path); + } +#endif + /* The hostname gets set up last, since * in multi-hop mode it will require knowledge * of other flags such as -i */ @@ -448,14 +466,18 @@ void cli_getopts(int argc, char ** argv) { } #ifdef ENABLE_CLI_PUBKEY_AUTH -static void loadidentityfile(const char* filename) { +static void loadidentityfile(const char* filename, int warnfail) { sign_key *key; enum signkey_type keytype; + TRACE(("loadidentityfile %s", filename)) + key = new_sign_key(); keytype = DROPBEAR_SIGNKEY_ANY; if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) { - fprintf(stderr, "Failed loading keyfile '%s'\n", filename); + if (warnfail) { + fprintf(stderr, "Failed loading keyfile '%s'\n", filename); + } sign_key_free(key); } else { key->type = keytype; @@ -587,7 +609,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0) passthrough_args, remainder); #ifndef DISABLE_ZLIB /* The stream will be incompressible since it's encrypted. */ - opts.enable_compress = 0; + opts.compress_mode = DROPBEAR_COMPRESS_OFF; #endif m_free(passthrough_args); } @@ -617,7 +639,7 @@ static void parse_hostname(const char* orighostarg) { cli_opts.username = m_strdup(cli_opts.own_user); } - port = strchr(cli_opts.remotehost, '%'); + port = strchr(cli_opts.remotehost, '^'); if (!port) { /* legacy separator */ port = strchr(cli_opts.remotehost, '/'); @@ -676,11 +698,13 @@ static void fill_own_user() { uid = getuid(); pw = getpwuid(uid); - if (pw == NULL || pw->pw_name == NULL) { - dropbear_exit("Unknown own user"); + if (pw && pw->pw_name != NULL) { + cli_opts.own_user = m_strdup(pw->pw_name); + } else { + dropbear_log(LOG_INFO, "Warning: failed to identify current user. Trying anyway."); + cli_opts.own_user = m_strdup("unknown"); } - cli_opts.own_user = m_strdup(pw->pw_name); } #ifdef ENABLE_CLI_ANYTCPFWD diff --git a/release/src-rt-6.x.4708/router/dropbear/cli-session.c b/release/src-rt-6.x.4708/router/dropbear/cli-session.c index 2a335d43b2..a484bf731a 100644 --- a/release/src-rt-6.x.4708/router/dropbear/cli-session.c +++ b/release/src-rt-6.x.4708/router/dropbear/cli-session.c @@ -44,6 +44,7 @@ static void cli_session_init(); static void cli_finished(); static void recv_msg_service_accept(void); static void cli_session_cleanup(void); +static void recv_msg_global_request_cli(void); struct clientsession cli_ses; /* GLOBAL */ @@ -68,9 +69,16 @@ static const packettype cli_packettypes[] = { {SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure}, {SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */ {SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */ + {SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_cli}, + {SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response}, + {SSH_MSG_CHANNEL_FAILURE, ignore_recv_response}, #ifdef ENABLE_CLI_REMOTETCPFWD {SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */ {SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */ +#else + /* For keepalive */ + {SSH_MSG_REQUEST_SUCCESS, ignore_recv_response}, + {SSH_MSG_REQUEST_FAILURE, ignore_recv_response}, #endif {0, 0} /* End */ }; @@ -228,6 +236,10 @@ static void cli_sessionloop() { cli_ses.state = USERAUTH_REQ_SENT; TRACE(("leave cli_sessionloop: sent userauth methods req")) return; + + case USERAUTH_REQ_SENT: + TRACE(("leave cli_sessionloop: waiting, req_sent")) + return; case USERAUTH_FAIL_RCVD: if (cli_auth_try() == DROPBEAR_FAILURE) { @@ -362,3 +374,9 @@ void cleantext(unsigned char* dirtytext) { /* Null terminate */ dirtytext[j] = '\0'; } + +static void recv_msg_global_request_cli(void) { + TRACE(("recv_msg_global_request_cli")) + /* Send a proper rejection */ + send_msg_request_failure(); +} diff --git a/release/src-rt-6.x.4708/router/dropbear/cli-tcpfwd.c b/release/src-rt-6.x.4708/router/dropbear/cli-tcpfwd.c index 218a6ab431..fa61d13f88 100644 --- a/release/src-rt-6.x.4708/router/dropbear/cli-tcpfwd.c +++ b/release/src-rt-6.x.4708/router/dropbear/cli-tcpfwd.c @@ -52,7 +52,7 @@ static int cli_localtcp(const char* listenaddr, static const struct ChanType cli_chan_tcplocal = { 1, /* sepfds */ "direct-tcpip", - NULL, + tcp_prio_inithandler, NULL, NULL, NULL @@ -161,9 +161,10 @@ void cli_recv_msg_request_success() { if (!fwd->have_reply) { fwd->have_reply = 1; if (fwd->listenport == 0) { - /* The server should let us know which port was allocated if we requestd port 0 */ + /* The server should let us know which port was allocated if we requested port 0 */ int allocport = buf_getint(ses.payload); if (allocport > 0) { + fwd->listenport = allocport; dropbear_log(LOG_INFO, "Allocated port %d for remote forward to %s:%d", allocport, fwd->connectaddr, fwd->connectport); } @@ -220,18 +221,33 @@ static int newtcpforwarded(struct Channel * channel) { origaddr = buf_getstring(ses.payload, NULL); origport = buf_getint(ses.payload); - /* Find which port corresponds */ + /* Find which port corresponds. First try and match address as well as port, + in case they want to forward different ports separately ... */ for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) { fwd = (struct TCPFwdEntry*)iter->item; if (origport == fwd->listenport - && (strcmp(origaddr, fwd->listenaddr) == 0)) { + && strcmp(origaddr, fwd->listenaddr) == 0) { break; } } + if (!iter) + { + /* ... otherwise try to generically match the only forwarded port + without address (also handles ::1 vs 127.0.0.1 vs localhost case). + rfc4254 is vague about the definition of "address that was connected" */ + for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) { + fwd = (struct TCPFwdEntry*)iter->item; + if (origport == fwd->listenport) { + break; + } + } + } + + if (iter == NULL) { /* We didn't request forwarding on that port */ - cleantext(origaddr); + cleantext(origaddr); dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"", origaddr, origport); goto out; @@ -251,6 +267,8 @@ static int newtcpforwarded(struct Channel * channel) { * progress succeeds */ channel->writefd = sock; channel->initconn = 1; + + channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; err = SSH_OPEN_IN_PROGRESS; diff --git a/release/src-rt-6.x.4708/router/dropbear/common-algo.c b/release/src-rt-6.x.4708/router/dropbear/common-algo.c index e57f37cdc4..9abc330311 100644 --- a/release/src-rt-6.x.4708/router/dropbear/common-algo.c +++ b/release/src-rt-6.x.4708/router/dropbear/common-algo.c @@ -84,10 +84,14 @@ const struct dropbear_cipher dropbear_nocipher = /* A few void* s are required to silence warnings * about the symmetric_CBC vs symmetric_CTR cipher_state pointer */ +#ifdef DROPBEAR_ENABLE_CBC_MODE const struct dropbear_cipher_mode dropbear_mode_cbc = {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt}; +#endif // DROPBEAR_ENABLE_CBC_MODE + const struct dropbear_cipher_mode dropbear_mode_none = {void_start, void_cipher, void_cipher}; + #ifdef DROPBEAR_ENABLE_CTR_MODE /* a wrapper to make ctr_start and cbc_start look the same */ static int dropbear_big_endian_ctr_start(int cipher, @@ -98,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher, } const struct dropbear_cipher_mode dropbear_mode_ctr = {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt}; -#endif +#endif // DROPBEAR_ENABLE_CTR_MODE /* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc. {&hash_desc, keysize, hashsize} */ @@ -137,21 +141,15 @@ algo_type sshciphers[] = { #ifdef DROPBEAR_AES128 {"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr}, #endif -#ifdef DROPBEAR_3DES - {"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr}, -#endif #ifdef DROPBEAR_AES256 {"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr}, #endif #endif /* DROPBEAR_ENABLE_CTR_MODE */ -/* CBC modes are always enabled */ +#ifdef DROPBEAR_ENABLE_CBC_MODE #ifdef DROPBEAR_AES128 {"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc}, #endif -#ifdef DROPBEAR_3DES - {"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc}, -#endif #ifdef DROPBEAR_AES256 {"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc}, #endif @@ -162,9 +160,16 @@ algo_type sshciphers[] = { #ifdef DROPBEAR_TWOFISH128 {"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc}, #endif +#ifdef DROPBEAR_3DES + {"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr}, +#endif +#ifdef DROPBEAR_3DES + {"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc}, +#endif #ifdef DROPBEAR_BLOWFISH {"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc}, #endif +#endif /* DROPBEAR_ENABLE_CBC_MODE */ #ifdef DROPBEAR_NONE_CIPHER {"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none}, #endif @@ -195,7 +200,13 @@ algo_type sshhashes[] = { #ifndef DISABLE_ZLIB algo_type ssh_compress[] = { + {"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL}, {"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL}, + {"none", DROPBEAR_COMP_NONE, NULL, 1, NULL}, + {NULL, 0, NULL, 0, NULL} +}; + +algo_type ssh_delaycompress[] = { {"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL}, {"none", DROPBEAR_COMP_NONE, NULL, 1, NULL}, {NULL, 0, NULL, 0, NULL} @@ -265,8 +276,8 @@ algo_type sshkex[] = { {"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL}, #endif #endif - {"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL}, {"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL}, + {"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL}, #ifdef USE_KEXGUESS2 {KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL}, #endif diff --git a/release/src-rt-6.x.4708/router/dropbear/common-channel.c b/release/src-rt-6.x.4708/router/dropbear/common-channel.c index 206890461b..049658d929 100644 --- a/release/src-rt-6.x.4708/router/dropbear/common-channel.c +++ b/release/src-rt-6.x.4708/router/dropbear/common-channel.c @@ -59,6 +59,13 @@ static void close_chan_fd(struct Channel *channel, int fd, int how); #define ERRFD_IS_READ(channel) ((channel)->extrabuf == NULL) #define ERRFD_IS_WRITE(channel) (!ERRFD_IS_READ(channel)) +/* allow space for: + * 1 byte byte SSH_MSG_CHANNEL_DATA + * 4 bytes uint32 recipient channel + * 4 bytes string data + */ +#define RECV_MAX_CHANNEL_DATA_LEN (RECV_MAX_PAYLOAD_LEN-(1+4+4)) + /* Initialise all the channels */ void chaninitialise(const struct ChanType *chantypes[]) { @@ -165,7 +172,9 @@ static struct Channel* newchannel(unsigned int remotechan, newchan->extrabuf = NULL; /* The user code can set it up */ newchan->recvdonelen = 0; - newchan->recvmaxpacket = RECV_MAX_PAYLOAD_LEN; + newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN; + + newchan->prio = DROPBEAR_CHANNEL_PRIO_EARLY; /* inithandler sets it */ ses.channels[i] = newchan; ses.chancount++; @@ -201,11 +210,14 @@ struct Channel* getchannel() { /* Iterate through the channels, performing IO if available */ void channelio(fd_set *readfds, fd_set *writefds) { + /* Listeners such as TCP, X11, agent-auth */ struct Channel *channel; unsigned int i; /* foreach channel */ for (i = 0; i < ses.chansize; i++) { + /* Close checking only needs to occur for channels that had IO events */ + int do_check_close = 0; channel = ses.channels[i]; if (channel == NULL) { @@ -217,6 +229,7 @@ void channelio(fd_set *readfds, fd_set *writefds) { if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) { TRACE(("send normal readfd")) send_msg_channel_data(channel, 0); + do_check_close = 1; } /* read stderr data and send it over the wire */ @@ -224,6 +237,7 @@ void channelio(fd_set *readfds, fd_set *writefds) { && FD_ISSET(channel->errfd, readfds)) { TRACE(("send normal errfd")) send_msg_channel_data(channel, 1); + do_check_close = 1; } /* write to program/pipe stdin */ @@ -235,20 +249,28 @@ void channelio(fd_set *readfds, fd_set *writefds) { check_in_progress(), as it may be NULL */ } writechannel(channel, channel->writefd, channel->writebuf); + do_check_close = 1; } /* stderr for client mode */ if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { writechannel(channel, channel->errfd, channel->extrabuf); + do_check_close = 1; + } + + if (ses.channel_signal_pending) { + /* SIGCHLD can change channel state for server sessions */ + do_check_close = 1; + ses.channel_signal_pending = 0; } /* handle any channel closing etc */ - check_close(channel); - + if (do_check_close) { + check_close(channel); + } } - /* Listeners such as TCP, X11, agent-auth */ #ifdef USING_LISTENERS handle_listeners(readfds); #endif @@ -474,8 +496,13 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) { continue; } - /* Stuff to put over the wire */ - if (channel->transwindow > 0) { + /* Stuff to put over the wire. + Avoid queueing data to send if we're in the middle of a + key re-exchange (!dataallowed), but still read from the + FD if there's the possibility of "~."" to kill an + interactive session (the read_mangler) */ + if (channel->transwindow > 0 + && (ses.dataallowed || channel->read_mangler)) { if (channel->readfd >= 0) { FD_SET(channel->readfd, readfds); @@ -555,14 +582,16 @@ static void remove_channel(struct Channel * channel) { } - /* close the FDs in case they haven't been done - * yet (they might have been shutdown etc) */ - TRACE(("CLOSE writefd %d", channel->writefd)) - close(channel->writefd); - TRACE(("CLOSE readfd %d", channel->readfd)) - close(channel->readfd); - TRACE(("CLOSE errfd %d", channel->errfd)) - close(channel->errfd); + if (IS_DROPBEAR_SERVER || (channel->writefd != STDOUT_FILENO)) { + /* close the FDs in case they haven't been done + * yet (they might have been shutdown etc) */ + TRACE(("CLOSE writefd %d", channel->writefd)) + close(channel->writefd); + TRACE(("CLOSE readfd %d", channel->readfd)) + close(channel->readfd); + TRACE(("CLOSE errfd %d", channel->errfd)) + close(channel->errfd); + } if (!channel->close_handler_done && channel->type->closehandler) { @@ -574,6 +603,8 @@ static void remove_channel(struct Channel * channel) { m_free(channel); ses.chancount--; + update_channel_prio(); + TRACE(("leave remove_channel")) } @@ -596,7 +627,12 @@ void recv_msg_channel_request() { && !channel->close_handler_done) { channel->type->reqhandler(channel); } else { - send_msg_channel_failure(channel); + int wantreply; + buf_eatstring(ses.payload); + wantreply = buf_getbool(ses.payload); + if (wantreply) { + send_msg_channel_failure(channel); + } } TRACE(("leave recv_msg_channel_request")) @@ -864,6 +900,10 @@ void recv_msg_channel_open() { } } + if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) { + channel->prio = DROPBEAR_CHANNEL_PRIO_BULK; + } + chan_initwritebuf(channel); /* success */ @@ -877,6 +917,8 @@ failure: cleanup: m_free(type); + + update_channel_prio(); TRACE(("leave recv_msg_channel_open")) } @@ -992,7 +1034,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) { * for X11, agent, tcp forwarding, and should be filled with channel-specific * options, with the calling function calling encrypt_packet() after * completion. It is mandatory for the caller to encrypt_packet() if - * DROPBEAR_SUCCESS is returned */ + * a channel is returned. NULL is returned on failure. */ int send_msg_channel_open_init(int fd, const struct ChanType *type) { struct Channel* chan; @@ -1023,7 +1065,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) { buf_putstring(ses.writepayload, type->name, strlen(type->name)); buf_putint(ses.writepayload, chan->index); buf_putint(ses.writepayload, opts.recv_window); - buf_putint(ses.writepayload, RECV_MAX_PAYLOAD_LEN); + buf_putint(ses.writepayload, RECV_MAX_CHANNEL_DATA_LEN); TRACE(("leave send_msg_channel_open_init()")) return DROPBEAR_SUCCESS; @@ -1058,9 +1100,14 @@ void recv_msg_channel_open_confirmation() { if (ret > 0) { remove_channel(channel); TRACE(("inithandler returned failure %d", ret)) + return; } } + if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) { + channel->prio = DROPBEAR_CHANNEL_PRIO_BULK; + } + update_channel_prio(); TRACE(("leave recv_msg_channel_open_confirmation")) } @@ -1080,3 +1127,42 @@ void recv_msg_channel_open_failure() { remove_channel(channel); } #endif /* USING_LISTENERS */ + +void send_msg_request_success() { + CHECKCLEARTOWRITE(); + buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS); + encrypt_packet(); +} + +void send_msg_request_failure() { + CHECKCLEARTOWRITE(); + buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); + encrypt_packet(); +} + +struct Channel* get_any_ready_channel() { + if (ses.chancount == 0) { + return NULL; + } + size_t i; + for (i = 0; i < ses.chansize; i++) { + struct Channel *chan = ses.channels[i]; + if (chan + && !(chan->sent_eof || chan->recv_eof) + && !(chan->await_open || chan->initconn)) { + return chan; + } + } + return NULL; +} + +void start_send_channel_request(struct Channel *channel, + unsigned char *type) { + + CHECKCLEARTOWRITE(); + buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST); + buf_putint(ses.writepayload, channel->remotechan); + + buf_putstring(ses.writepayload, type, strlen(type)); + +} diff --git a/release/src-rt-6.x.4708/router/dropbear/common-kex.c b/release/src-rt-6.x.4708/router/dropbear/common-kex.c index 77a7aa6957..7d93708ef1 100644 --- a/release/src-rt-6.x.4708/router/dropbear/common-kex.c +++ b/release/src-rt-6.x.4708/router/dropbear/common-kex.c @@ -238,14 +238,24 @@ void recv_msg_newkeys() { void kexfirstinitialise() { ses.kexstate.donefirstkex = 0; -#ifndef DISABLE_ZLIB - if (opts.enable_compress) { - ses.compress_algos = ssh_compress; - } else -#endif +#ifdef DISABLE_ZLIB + ses.compress_algos = ssh_nocompress; +#else + switch (opts.compress_mode) { - ses.compress_algos = ssh_nocompress; + case DROPBEAR_COMPRESS_DELAYED: + ses.compress_algos = ssh_delaycompress; + break; + + case DROPBEAR_COMPRESS_ON: + ses.compress_algos = ssh_compress; + break; + + case DROPBEAR_COMPRESS_OFF: + ses.compress_algos = ssh_nocompress; + break; } +#endif kexinitialise(); } @@ -270,7 +280,7 @@ static void kexinitialise() { ses.kexstate.our_first_follows_matches = 0; - ses.kexstate.lastkextime = time(NULL); + ses.kexstate.lastkextime = monotonic_now(); } @@ -303,7 +313,7 @@ static void hashkeys(unsigned char *out, unsigned int outlen, hash_desc->done(&hs2, tmpout); memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize)); } - + m_burn(&hs2, sizeof(hash_state)); } /* Generate the actual encryption/integrity keys, using the results of the @@ -403,6 +413,7 @@ static void gen_new_keys() { m_burn(C2S_key, sizeof(C2S_key)); m_burn(S2C_IV, sizeof(S2C_IV)); m_burn(S2C_key, sizeof(S2C_key)); + m_burn(&hs, sizeof(hash_state)); TRACE(("leave gen_new_keys")) } @@ -483,9 +494,6 @@ static void gen_new_zstream_trans() { * and we calculate the first portion of the key-exchange-hash for used * later in the key exchange. No response is sent, as the client should * initiate the diffie-hellman key exchange */ - -/* Originally from kex.c, generalized for cli/svr mode --mihnea */ -/* Belongs in common_kex.c where it should be moved after review */ void recv_msg_kexinit() { unsigned int kexhashbuf_len = 0; @@ -528,7 +536,7 @@ void recv_msg_kexinit() { /* I_S, the payload of the server's SSH_MSG_KEXINIT */ buf_setpos(ses.payload, 0); buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len); - + ses.requirenext = SSH_MSG_KEXDH_REPLY; } else { /* SERVER */ @@ -548,7 +556,7 @@ void recv_msg_kexinit() { buf_putstring(ses.kexhashbuf, ses.transkexinit->data, ses.transkexinit->len); - ses.requirenext[0] = SSH_MSG_KEXDH_INIT; + ses.requirenext = SSH_MSG_KEXDH_INIT; } buf_free(ses.transkexinit); @@ -792,8 +800,16 @@ static void finish_kexhashbuf(void) { hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize)); buf_setlen(ses.hash, hash_desc->hashsize); +#if defined(DEBUG_KEXHASH) && defined(DEBUG_TRACE) + if (!debug_trace) { + printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len); + printhex("kexhash", ses.hash->data, ses.hash->len); + } +#endif + buf_burn(ses.kexhashbuf); buf_free(ses.kexhashbuf); + m_burn(&hs, sizeof(hash_state)); ses.kexhashbuf = NULL; /* first time around, we set the session_id to H */ @@ -801,7 +817,6 @@ static void finish_kexhashbuf(void) { /* create the session_id, this never needs freeing */ ses.session_id = buf_newcopy(ses.hash); } - } /* read the other side's algo list. buf_match_algo is a callback to match diff --git a/release/src-rt-6.x.4708/router/dropbear/common-runopts.c b/release/src-rt-6.x.4708/router/dropbear/common-runopts.c index 699ebdaac9..4c07e1f58a 100644 --- a/release/src-rt-6.x.4708/router/dropbear/common-runopts.c +++ b/release/src-rt-6.x.4708/router/dropbear/common-runopts.c @@ -106,3 +106,8 @@ parse_ciphers_macs() } #endif +void print_version() { + fprintf(stderr, "Dropbear v%s\n", DROPBEAR_VERSION); +} + + diff --git a/release/src-rt-6.x.4708/router/dropbear/common-session.c b/release/src-rt-6.x.4708/router/dropbear/common-session.c index f4016b593c..83fb7f41d6 100644 --- a/release/src-rt-6.x.4708/router/dropbear/common-session.c +++ b/release/src-rt-6.x.4708/router/dropbear/common-session.c @@ -51,6 +51,7 @@ 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; TRACE(("enter session_init")) @@ -58,9 +59,15 @@ void common_session_init(int sock_in, int sock_out) { ses.sock_out = sock_out; ses.maxfd = MAX(sock_in, sock_out); - ses.connect_time = 0; - ses.last_trx_packet_time = 0; - ses.last_packet_time = 0; + ses.socket_prio = DROPBEAR_PRIO_DEFAULT; + /* Sets it to lowdelay */ + update_channel_prio(); + + now = monotonic_now(); + ses.last_packet_time_keepalive_recv = now; + ses.last_packet_time_idle = now; + ses.last_packet_time_any_sent = 0; + ses.last_packet_time_keepalive_sent = 0; if (pipe(ses.signal_pipe) < 0) { dropbear_exit("Signal pipe failed"); @@ -82,7 +89,7 @@ void common_session_init(int sock_in, int sock_out) { initqueue(&ses.writequeue); - ses.requirenext[0] = SSH_MSG_KEXINIT; + ses.requirenext = SSH_MSG_KEXINIT; ses.dataallowed = 1; /* we can send data until we actually send the SSH_MSG_KEXINIT */ ses.ignorenext = 0; @@ -153,10 +160,9 @@ void session_loop(void(*loophandler)()) { SIGCHLD in svr-chansession is the only one currently. */ FD_SET(ses.signal_pipe[0], &readfd); - /* set up for channels which require reading/writing */ - if (ses.dataallowed) { - setchannelfds(&readfd, &writefd); - } + /* set up for channels which can be read/written */ + setchannelfds(&readfd, &writefd); + val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout); if (exitflag) { @@ -187,13 +193,7 @@ void session_loop(void(*loophandler)()) { /* check for auth timeout, rekeying required etc */ checktimeouts(); - /* process session socket's incoming/outgoing data */ - if (ses.sock_out != -1) { - if (FD_ISSET(ses.sock_out, &writefd) && !isempty(&ses.writequeue)) { - write_packet(); - } - } - + /* process session socket's incoming data */ if (ses.sock_in != -1) { if (FD_ISSET(ses.sock_in, &readfd)) { if (!ses.remoteident) { @@ -217,10 +217,16 @@ void session_loop(void(*loophandler)()) { /* process pipes etc for the channels, ses.dataallowed == 0 * during rekeying ) */ - if (ses.dataallowed) { - channelio(&readfd, &writefd); + channelio(&readfd, &writefd); + + /* process session socket's outgoing data */ + if (ses.sock_out != -1) { + if (!isempty(&ses.writequeue)) { + write_packet(); + } } + if (loophandler) { loophandler(); } @@ -244,7 +250,11 @@ void session_cleanup() { if (ses.extra_session_cleanup) { ses.extra_session_cleanup(); } + + chancleanup(); + /* Cleaning up keys must happen after other cleanup + functions which might queue packets */ if (ses.session_id) { buf_burn(ses.session_id); buf_free(ses.session_id); @@ -258,8 +268,6 @@ void session_cleanup() { m_burn(ses.keys, sizeof(struct key_context)); m_free(ses.keys); - chancleanup(); - TRACE(("leave session_cleanup")) } @@ -386,11 +394,37 @@ static int ident_readln(int fd, char* buf, int count) { return pos+1; } -void send_msg_ignore() { +void ignore_recv_response() { + // Do nothing + TRACE(("Ignored msg_request_response")) +} + +static void send_msg_keepalive() { CHECKCLEARTOWRITE(); - buf_putbyte(ses.writepayload, SSH_MSG_IGNORE); - buf_putstring(ses.writepayload, "", 0); + time_t old_time_idle = ses.last_packet_time_idle; + + struct Channel *chan = get_any_ready_channel(); + + if (chan) { + /* Channel requests are preferable, more implementations + handle them than SSH_MSG_GLOBAL_REQUEST */ + TRACE(("keepalive channel request %d", chan->index)) + start_send_channel_request(chan, DROPBEAR_KEEPALIVE_STRING); + } else { + TRACE(("keepalive global request")) + /* Some peers will reply with SSH_MSG_REQUEST_FAILURE, + some will reply with SSH_MSG_UNIMPLEMENTED, some will exit. */ + buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST); + buf_putstring(ses.writepayload, DROPBEAR_KEEPALIVE_STRING, + strlen(DROPBEAR_KEEPALIVE_STRING)); + } + buf_putbyte(ses.writepayload, 1); /* want_reply */ encrypt_packet(); + + ses.last_packet_time_keepalive_sent = monotonic_now(); + + /* keepalives shouldn't update idle timeout, reset it back */ + ses.last_packet_time_idle = old_time_idle; } /* Check all timeouts which are required. Currently these are the time for @@ -398,13 +432,8 @@ void send_msg_ignore() { static void checktimeouts() { time_t now; - - now = time(NULL); + now = monotonic_now(); - if (ses.connect_time != 0 && now - ses.connect_time >= AUTH_TIMEOUT) { - dropbear_close("Timeout before auth"); - } - /* we can't rekey if we haven't done remote ident exchange yet */ if (ses.remoteident == NULL) { return; @@ -417,13 +446,30 @@ static void checktimeouts() { send_msg_kexinit(); } - if (opts.keepalive_secs > 0 - && now - ses.last_trx_packet_time >= opts.keepalive_secs) { - send_msg_ignore(); + if (opts.keepalive_secs > 0 && ses.authstate.authdone) { + /* Avoid sending keepalives prior to auth - those are + not valid pre-auth packet types */ + + /* Send keepalives if we've been idle */ + if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) { + send_msg_keepalive(); + } + + /* Also send an explicit keepalive message to trigger a response + if the remote end hasn't sent us anything */ + if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs + && now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) { + send_msg_keepalive(); + } + + if (now - ses.last_packet_time_keepalive_recv + >= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) { + dropbear_exit("Keepalive timeout"); + } } - if (opts.idle_timeout_secs > 0 && ses.last_packet_time > 0 - && now - ses.last_packet_time >= opts.idle_timeout_secs) { + if (opts.idle_timeout_secs > 0 + && now - ses.last_packet_time_idle >= opts.idle_timeout_secs) { dropbear_close("Idle timeout"); } } @@ -434,12 +480,13 @@ static long select_timeout() { long ret = LONG_MAX; if (KEX_REKEY_TIMEOUT > 0) ret = MIN(KEX_REKEY_TIMEOUT, ret); - if (AUTH_TIMEOUT > 0) + /* AUTH_TIMEOUT is only relevant before authdone */ + if (ses.authstate.authdone != 1 && AUTH_TIMEOUT > 0) ret = MIN(AUTH_TIMEOUT, ret); if (opts.keepalive_secs > 0) ret = MIN(opts.keepalive_secs, ret); - if (opts.idle_timeout_secs > 0) - ret = MIN(opts.idle_timeout_secs, ret); + if (opts.idle_timeout_secs > 0) + ret = MIN(opts.idle_timeout_secs, ret); return ret; } @@ -488,3 +535,47 @@ void fill_passwd(const char* username) { } } +/* Called when channels are modified */ +void update_channel_prio() { + enum dropbear_prio new_prio; + int any = 0; + unsigned int i; + + TRACE(("update_channel_prio")) + + new_prio = DROPBEAR_PRIO_BULK; + for (i = 0; i < ses.chansize; i++) { + struct Channel *channel = ses.channels[i]; + if (!channel || channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) { + if (channel && channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) { + TRACE(("update_channel_prio: early %d", channel->index)) + } + continue; + } + any = 1; + if (channel->prio == DROPBEAR_CHANNEL_PRIO_INTERACTIVE) + { + TRACE(("update_channel_prio: lowdelay %d", channel->index)) + new_prio = DROPBEAR_PRIO_LOWDELAY; + break; + } else if (channel->prio == DROPBEAR_CHANNEL_PRIO_UNKNOWABLE + && new_prio == DROPBEAR_PRIO_BULK) + { + TRACE(("update_channel_prio: unknowable %d", channel->index)) + new_prio = DROPBEAR_PRIO_DEFAULT; + } + } + + if (any == 0) { + /* lowdelay during setup */ + TRACE(("update_channel_prio: not any")) + new_prio = DROPBEAR_PRIO_LOWDELAY; + } + + if (new_prio != ses.socket_prio) { + TRACE(("Dropbear priority transitioning %4.4s -> %4.4s", (char*)&ses.socket_prio, (char*)&new_prio)) + set_sock_priority(ses.sock_out, new_prio); + ses.socket_prio = new_prio; + } +} + diff --git a/release/src-rt-6.x.4708/router/dropbear/config.h.in b/release/src-rt-6.x.4708/router/dropbear/config.h.in index 0d55cb67ad..924633ddd9 100644 --- a/release/src-rt-6.x.4708/router/dropbear/config.h.in +++ b/release/src-rt-6.x.4708/router/dropbear/config.h.in @@ -138,12 +138,6 @@ /* Define to 1 if you have the `pam' library (-lpam). */ #undef HAVE_LIBPAM -/* Define to 1 if you have the `tomcrypt' library (-ltomcrypt). */ -#undef HAVE_LIBTOMCRYPT - -/* Define to 1 if you have the `tommath' library (-ltommath). */ -#undef HAVE_LIBTOMMATH - /* Define to 1 if you have the header file. */ #undef HAVE_LIBUTIL_H @@ -162,6 +156,12 @@ /* Define to 1 if you have the `logwtmp' function. */ #undef HAVE_LOGWTMP +/* Define to 1 if you have the `mach_absolute_time' function. */ +#undef HAVE_MACH_ABSOLUTE_TIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACH_MACH_TIME_H + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H diff --git a/release/src-rt-6.x.4708/router/dropbear/configure b/release/src-rt-6.x.4708/router/dropbear/configure index 6ebe9c8de9..cc61d70185 100755 --- a/release/src-rt-6.x.4708/router/dropbear/configure +++ b/release/src-rt-6.x.4708/router/dropbear/configure @@ -622,6 +622,7 @@ ac_includes_default="\ ac_subst_vars='LTLIBOBJS LIBOBJS BUNDLED_LIBTOM +LIBTOM_LIBS CRYPTLIB EGREP GREP @@ -5854,6 +5855,31 @@ fi done +# OS X monotonic time +for ac_header in mach/mach_time.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "mach/mach_time.h" "ac_cv_header_mach_mach_time_h" "$ac_includes_default" +if test "x$ac_cv_header_mach_mach_time_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MACH_MACH_TIME_H 1 +_ACEOF + +fi + +done + +for ac_func in mach_absolute_time +do : + ac_fn_c_check_func "$LINENO" "mach_absolute_time" "ac_cv_func_mach_absolute_time" +if test "x$ac_cv_func_mach_absolute_time" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MACH_ABSOLUTE_TIME 1 +_ACEOF + +fi +done + + # Check whether --enable-bundled-libtom was given. if test "${enable_bundled_libtom+set}" = set; then : enableval=$enable_bundled_libtom; @@ -5900,14 +5926,9 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tommath_mp_exptmod" >&5 $as_echo "$ac_cv_lib_tommath_mp_exptmod" >&6; } if test "x$ac_cv_lib_tommath_mp_exptmod" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBTOMMATH 1 -_ACEOF - - LIBS="-ltommath $LIBS" - + LIBTOM_LIBS="$LIBTOM_LIBS -ltommath" else - as_fn_error $? "Missing system libtomcrypt and --disable-bundled-libtom was specified" "$LINENO" 5 + as_fn_error $? "Missing system libtommath and --disable-bundled-libtom was specified" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for register_cipher in -ltomcrypt" >&5 @@ -5947,12 +5968,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tomcrypt_register_cipher" >&5 $as_echo "$ac_cv_lib_tomcrypt_register_cipher" >&6; } if test "x$ac_cv_lib_tomcrypt_register_cipher" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBTOMCRYPT 1 -_ACEOF - - LIBS="-ltomcrypt $LIBS" - + LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt" else as_fn_error $? "Missing system libtomcrypt and --disable-bundled-libtom was specified" "$LINENO" 5 fi @@ -5999,12 +6015,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tommath_mp_exptmod" >&5 $as_echo "$ac_cv_lib_tommath_mp_exptmod" >&6; } if test "x$ac_cv_lib_tommath_mp_exptmod" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBTOMMATH 1 -_ACEOF - - LIBS="-ltommath $LIBS" - + LIBTOM_LIBS="$LIBTOM_LIBS -ltommath" else BUNDLED_LIBTOM=1 fi @@ -6046,12 +6057,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tomcrypt_register_cipher" >&5 $as_echo "$ac_cv_lib_tomcrypt_register_cipher" >&6; } if test "x$ac_cv_lib_tomcrypt_register_cipher" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBTOMCRYPT 1 -_ACEOF - - LIBS="-ltomcrypt $LIBS" - + LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt" else BUNDLED_LIBTOM=1 fi @@ -6070,6 +6076,7 @@ fi + # Check whether --enable-lastlog was given. if test "${enable_lastlog+set}" = set; then : enableval=$enable_lastlog; @@ -6791,6 +6798,7 @@ fi # XXX there must be a nicer way to do this +if test $BUNDLED_LIBTOM = 1 ; then as_dir=libtomcrypt/src/ciphers/aes; as_fn_mkdir_p as_dir=libtomcrypt/src/ciphers/safer; as_fn_mkdir_p as_dir=libtomcrypt/src/ciphers/twofish; as_fn_mkdir_p @@ -6841,9 +6849,11 @@ as_dir=libtomcrypt/src/pk/katja; as_fn_mkdir_p as_dir=libtomcrypt/src/pk/pkcs1; as_fn_mkdir_p as_dir=libtomcrypt/src/pk/rsa; as_fn_mkdir_p as_dir=libtomcrypt/src/prngs; as_fn_mkdir_p +LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile" +fi ac_config_headers="$ac_config_headers config.h" -ac_config_files="$ac_config_files Makefile libtomcrypt/Makefile libtommath/Makefile" +ac_config_files="$ac_config_files Makefile $LIBTOM_FILES" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -7536,8 +7546,7 @@ do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "libtomcrypt/Makefile") CONFIG_FILES="$CONFIG_FILES libtomcrypt/Makefile" ;; - "libtommath/Makefile") CONFIG_FILES="$CONFIG_FILES libtommath/Makefile" ;; + "$LIBTOM_FILES") CONFIG_FILES="$CONFIG_FILES $LIBTOM_FILES" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/release/src-rt-6.x.4708/router/dropbear/configure.ac b/release/src-rt-6.x.4708/router/dropbear/configure.ac index e63d164475..b0e85e5405 100644 --- a/release/src-rt-6.x.4708/router/dropbear/configure.ac +++ b/release/src-rt-6.x.4708/router/dropbear/configure.ac @@ -361,6 +361,10 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline ) AC_CHECK_FUNCS(setutxent utmpxname) AC_CHECK_FUNCS(logout updwtmp logwtmp) +# OS X monotonic time +AC_CHECK_HEADERS([mach/mach_time.h]) +AC_CHECK_FUNCS(mach_absolute_time) + AC_ARG_ENABLE(bundled-libtom, [ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists. --disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist. @@ -371,16 +375,16 @@ AC_ARG_ENABLE(bundled-libtom, AC_MSG_NOTICE(Forcing bundled libtom*) else BUNDLED_LIBTOM=0 - AC_CHECK_LIB(tommath, mp_exptmod, , - [AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] ) - AC_CHECK_LIB(tomcrypt, register_cipher, , + AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath", + [AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] ) + AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt", [AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] ) fi ], [ BUNDLED_LIBTOM=0 - AC_CHECK_LIB(tommath, mp_exptmod, , BUNDLED_LIBTOM=1) - AC_CHECK_LIB(tomcrypt, register_cipher, , BUNDLED_LIBTOM=1) + AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath", BUNDLED_LIBTOM=1) + AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt", BUNDLED_LIBTOM=1) ] ) @@ -388,6 +392,7 @@ if test $BUNDLED_LIBTOM = 1 ; then AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom) fi +AC_SUBST(LIBTOM_LIBS) AC_SUBST(BUNDLED_LIBTOM) dnl Added from OpenSSH 3.6.1p2's configure.ac @@ -655,6 +660,7 @@ fi AC_EXEEXT # XXX there must be a nicer way to do this +if test $BUNDLED_LIBTOM = 1 ; then AS_MKDIR_P(libtomcrypt/src/ciphers/aes) AS_MKDIR_P(libtomcrypt/src/ciphers/safer) AS_MKDIR_P(libtomcrypt/src/ciphers/twofish) @@ -705,8 +711,10 @@ AS_MKDIR_P(libtomcrypt/src/pk/katja) AS_MKDIR_P(libtomcrypt/src/pk/pkcs1) AS_MKDIR_P(libtomcrypt/src/pk/rsa) AS_MKDIR_P(libtomcrypt/src/prngs) +LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile" +fi AC_CONFIG_HEADER(config.h) -AC_CONFIG_FILES(Makefile libtomcrypt/Makefile libtommath/Makefile) +AC_CONFIG_FILES(Makefile $LIBTOM_FILES) AC_OUTPUT AC_MSG_NOTICE() diff --git a/release/src-rt-6.x.4708/router/dropbear/dbclient.1 b/release/src-rt-6.x.4708/router/dropbear/dbclient.1 index 48399826e8..cf9c64776f 100644 --- a/release/src-rt-6.x.4708/router/dropbear/dbclient.1 +++ b/release/src-rt-6.x.4708/router/dropbear/dbclient.1 @@ -15,18 +15,17 @@ dbclient \- lightweight SSH client .B dbclient [ .I args ] -.I [user1]@host1[%port1],[user2]@host2[%port2],... +.I [user1]@host1[^port1],[user2]@host2[^port2],... .SH DESCRIPTION .B dbclient -is a SSH client designed to be small enough to be used in small memory -environments, while still being functional and secure enough for general use. +is a small SSH client .SH OPTIONS .TP .B \-p \fIport Connect to .I port -on the remote host. Alternatively a port can be specified as hostname%port. +on the remote host. Alternatively a port can be specified as hostname^port. Default is 22. .TP .B \-i \fIidfile @@ -34,7 +33,7 @@ Identity file. Read the identity key from file .I idfile (multiple allowed). This file is created with dropbearkey(1) or converted -from OpenSSH with dropbearconvert(1). +from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is used .TP .B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR Local port forwarding. @@ -98,7 +97,7 @@ Ensure that traffic is transmitted at a certain interval in seconds. This is useful for working around firewalls or routers that drop connections after a certain period of inactivity. The trade-off is that a session may be closed if there is a temporary lapse of network connectivity. A setting -if 0 disables keepalives. +if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed. .TP .B \-I \fIidle_timeout Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds. @@ -121,13 +120,16 @@ Specify a comma separated list of authentication MACs to enable. Use \fI-m help\ .TP .B \-s The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR +.TP +.B \-V +Print the version .SH MULTI-HOP Dropbear will also allow multiple "hops" to be specified, separated by commas. In this case a connection will be made to the first host, then a TCP forwarded connection will be made through that to the second host, and so on. Hosts other than the final destination will not see anything other than the encrypted SSH stream. -A port for a host can be specified with a hash (eg matt@martello%44 ). +A port for a host can be specified with a hash (eg matt@martello^44 ). This syntax can also be used with scp or rsync (specifying dbclient as the ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg diff --git a/release/src-rt-6.x.4708/router/dropbear/dbutil.c b/release/src-rt-6.x.4708/router/dropbear/dbutil.c index 082a5a20a6..ae7313207e 100644 --- a/release/src-rt-6.x.4708/router/dropbear/dbutil.c +++ b/release/src-rt-6.x.4708/router/dropbear/dbutil.c @@ -48,6 +48,19 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" + +#ifdef __linux__ +#define _GNU_SOURCE +/* To call clock_gettime() directly */ +#include +#endif /* __linux */ + +#ifdef HAVE_MACH_MACH_TIME_H +#include +#include +#endif + #include "includes.h" #include "dbutil.h" #include "buffer.h" @@ -148,7 +161,7 @@ void dropbear_trace(const char* format, ...) { gettimeofday(&tv, NULL); va_start(param, format); - fprintf(stderr, "TRACE (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec); + fprintf(stderr, "TRACE (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec); vfprintf(stderr, format, param); fprintf(stderr, "\n"); va_end(param); @@ -170,7 +183,7 @@ void dropbear_trace2(const char* format, ...) { gettimeofday(&tv, NULL); va_start(param, format); - fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec); + fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec); vfprintf(stderr, format, param); fprintf(stderr, "\n"); va_end(param); @@ -189,6 +202,9 @@ void set_sock_priority(int sock, enum dropbear_prio prio) { int iptos_val = 0, so_prio_val = 0, rc; + /* Don't log ENOTSOCK errors so that this can harmlessly be called + * on a client '-J' proxy pipe */ + /* set the TOS bit for either ipv4 or ipv6 */ #ifdef IPTOS_LOWDELAY if (prio == DROPBEAR_PRIO_LOWDELAY) { @@ -198,12 +214,12 @@ void set_sock_priority(int sock, enum dropbear_prio prio) { } #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val)); - if (rc < 0) { + if (rc < 0 && errno != ENOTSOCK) { TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno))); } #endif rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val)); - if (rc < 0) { + if (rc < 0 && errno != ENOTSOCK) { TRACE(("Couldn't set IP_TOS (%s)", strerror(errno))); } #endif @@ -216,7 +232,7 @@ void set_sock_priority(int sock, enum dropbear_prio prio) { } /* linux specific, sets QoS class. see tc-prio(8) */ rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val)); - if (rc < 0) + if (rc < 0 && errno != ENOTSOCK) dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)", strerror(errno)); #endif @@ -319,7 +335,7 @@ int dropbear_listen(const char* address, const char* port, continue; } - if (listen(sock, 20) < 0) { + if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) { err = errno; close(sock); TRACE(("listen() failed")) @@ -812,6 +828,10 @@ out: /* make sure that the socket closes */ void m_close(int fd) { + if (fd == -1) { + return; + } + int val; do { val = close(fd); @@ -916,6 +936,23 @@ int m_str_to_uint(const char* str, unsigned int *val) { } } +/* Returns malloced path. Only expands ~ in first character */ +char * expand_tilde(const char *inpath) { + struct passwd *pw = NULL; + if (inpath[0] == '~') { + pw = getpwuid(getuid()); + if (pw && pw->pw_dir) { + int len = strlen(inpath) + strlen(pw->pw_dir) + 1; + char *buf = m_malloc(len); + snprintf(buf, len, "%s/%s", pw->pw_dir, &inpath[1]); + return buf; + } + } + + /* Fallback */ + return m_strdup(inpath); +} + int constant_time_memcmp(const void* a, const void *b, size_t n) { const char *xa = a, *xb = b; @@ -928,3 +965,56 @@ int constant_time_memcmp(const void* a, const void *b, size_t n) return c; } +#if defined(__linux__) && defined(SYS_clock_gettime) +/* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to +reach userspace include headers */ +#ifndef CLOCK_MONOTONIC_COARSE +#define CLOCK_MONOTONIC_COARSE 6 +#endif +static clockid_t get_linux_clock_source() { + struct timespec ts; + if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) { + return CLOCK_MONOTONIC_COARSE; + } + + if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) { + return CLOCK_MONOTONIC; + } + return -1; +} +#endif + +time_t monotonic_now() { +#if defined(__linux__) && defined(SYS_clock_gettime) + static clockid_t clock_source = -2; + + if (clock_source == -2) { + /* First run, find out which one works. + -1 will fall back to time() */ + clock_source = get_linux_clock_source(); + } + + if (clock_source >= 0) { + struct timespec ts; + if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) { + /* Intermittent clock failures should not happen */ + dropbear_exit("Clock broke"); + } + return ts.tv_sec; + } +#endif /* linux clock_gettime */ + +#if defined(HAVE_MACH_ABSOLUTE_TIME) + /* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */ + static mach_timebase_info_data_t timebase_info; + if (timebase_info.denom == 0) { + mach_timebase_info(&timebase_info); + } + return mach_absolute_time() * timebase_info.numer / timebase_info.denom + / 1e9; +#endif /* osx mach_absolute_time */ + + /* Fallback for everything else - this will sometimes go backwards */ + return time(NULL); +} + diff --git a/release/src-rt-6.x.4708/router/dropbear/dbutil.h b/release/src-rt-6.x.4708/router/dropbear/dbutil.h index 4c7b123779..cdad9bca5b 100644 --- a/release/src-rt-6.x.4708/router/dropbear/dbutil.h +++ b/release/src-rt-6.x.4708/router/dropbear/dbutil.h @@ -62,9 +62,9 @@ extern int debug_trace; #endif enum dropbear_prio { - DROPBEAR_PRIO_DEFAULT, - DROPBEAR_PRIO_LOWDELAY, - DROPBEAR_PRIO_BULK, + DROPBEAR_PRIO_DEFAULT = 10, + DROPBEAR_PRIO_LOWDELAY = 11, + DROPBEAR_PRIO_BULK = 12, }; char * stripcontrol(const char * text); @@ -91,7 +91,7 @@ void m_close(int fd); void * m_malloc(size_t size); void * m_strdup(const char * str); void * m_realloc(void* ptr, size_t size); -#define m_free(X) free(X); (X) = NULL; +#define m_free(X) do {free(X); (X) = NULL;} while (0); void m_burn(void* data, unsigned int len); void setnonblocking(int fd); void disallow_core(); @@ -106,4 +106,10 @@ int m_str_to_uint(const char* str, unsigned int *val); /* Returns 0 if a and b have the same contents */ int constant_time_memcmp(const void* a, const void *b, size_t n); +/* Returns a time in seconds that doesn't go backwards - does not correspond to +a real-world clock */ +time_t monotonic_now(); + +char * expand_tilde(const char *inpath); + #endif /* _DBUTIL_H_ */ diff --git a/release/src-rt-6.x.4708/router/dropbear/debian/changelog b/release/src-rt-6.x.4708/router/dropbear/debian/changelog index 0a668dbfdc..12484cc962 100644 --- a/release/src-rt-6.x.4708/router/dropbear/debian/changelog +++ b/release/src-rt-6.x.4708/router/dropbear/debian/changelog @@ -1,3 +1,33 @@ +dropbear (2015.67-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Wed, 28 Jan 2015 22:53:59 +0800 + +dropbear (2014.66-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Thu, 23 Oct 2014 22:54:00 +0800 + +dropbear (2014.65-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Fri, 8 Aug 2014 22:54:00 +0800 + +dropbear (2014.64-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Sun, 27 Jul 2014 22:54:00 +0800 + +dropbear (2014.63-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Wed, 19 Feb 2014 22:54:00 +0800 + dropbear (2013.62) unstable; urgency=low * New upstream release. diff --git a/release/src-rt-6.x.4708/router/dropbear/dropbear.8 b/release/src-rt-6.x.4708/router/dropbear/dropbear.8 index 032e4ce0f6..42f8ddb350 100644 --- a/release/src-rt-6.x.4708/router/dropbear/dropbear.8 +++ b/release/src-rt-6.x.4708/router/dropbear/dropbear.8 @@ -10,8 +10,7 @@ dropbear \- lightweight SSH server .IR [address:]port ] .SH DESCRIPTION .B dropbear -is a SSH server designed to be small enough to be used in small memory -environments, while still being functional and secure enough for general use. +is a small SSH server .SH OPTIONS .TP .B \-b \fIbanner @@ -88,10 +87,14 @@ Ensure that traffic is transmitted at a certain interval in seconds. This is useful for working around firewalls or routers that drop connections after a certain period of inactivity. The trade-off is that a session may be closed if there is a temporary lapse of network connectivity. A setting -if 0 disables keepalives. +if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed. .TP .B \-I \fIidle_timeout Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds. +.TP +.B \-V +Print the version + .SH FILES .TP diff --git a/release/src-rt-6.x.4708/router/dropbear/dropbearconvert.1 b/release/src-rt-6.x.4708/router/dropbear/dropbearconvert.1 index 4643f5f96c..b2f34ef59b 100644 --- a/release/src-rt-6.x.4708/router/dropbear/dropbearconvert.1 +++ b/release/src-rt-6.x.4708/router/dropbear/dropbearconvert.1 @@ -39,9 +39,9 @@ or An existing Dropbear or OpenSSH private key file .TP .B output file -The path to write the converted private key file +The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default .SH EXAMPLE - # dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/dropbear_priv + # dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear .SH AUTHOR Matt Johnston (matt@ucc.asn.au). .SH SEE ALSO diff --git a/release/src-rt-6.x.4708/router/dropbear/dropbearkey.1 b/release/src-rt-6.x.4708/router/dropbear/dropbearkey.1 index 207a6fef87..b4d202ee16 100644 --- a/release/src-rt-6.x.4708/router/dropbear/dropbearkey.1 +++ b/release/src-rt-6.x.4708/router/dropbear/dropbearkey.1 @@ -33,7 +33,7 @@ or .TP .B \-f \fIfile Write the secret key to the file -.IR file . +.IR file . For client authentication ~/.ssh/id_dropbear is loaded by default .TP .B \-s \fIbits Set the key size to diff --git a/release/src-rt-6.x.4708/router/dropbear/dropbearkey.c b/release/src-rt-6.x.4708/router/dropbear/dropbearkey.c index 1eb4db2f4a..7eb2f3f01f 100644 --- a/release/src-rt-6.x.4708/router/dropbear/dropbearkey.c +++ b/release/src-rt-6.x.4708/router/dropbear/dropbearkey.c @@ -76,7 +76,8 @@ static void printhelp(char * progname) { #ifdef DROPBEAR_ECDSA " ecdsa\n" #endif - "-f filename Use filename for the secret key\n" + "-f filename Use filename for the secret key.\n" + " ~/.ssh/id_dropbear is recommended for client keys.\n" "-s bits Key size in bits, should be a multiple of 8 (optional)\n" #ifdef DROPBEAR_DSS " DSS has a fixed size of 1024 bits\n" diff --git a/release/src-rt-6.x.4708/router/dropbear/ecdsa.c b/release/src-rt-6.x.4708/router/dropbear/ecdsa.c index 195121f179..039601499d 100644 --- a/release/src-rt-6.x.4708/router/dropbear/ecdsa.c +++ b/release/src-rt-6.x.4708/router/dropbear/ecdsa.c @@ -131,6 +131,7 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) { if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) { ecc_free(new_key); + m_free(new_key); return NULL; } diff --git a/release/src-rt-6.x.4708/router/dropbear/genrsa.c b/release/src-rt-6.x.4708/router/dropbear/genrsa.c index cdc585db44..dfd81b3a95 100644 --- a/release/src-rt-6.x.4708/router/dropbear/genrsa.c +++ b/release/src-rt-6.x.4708/router/dropbear/genrsa.c @@ -58,12 +58,18 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) { exit(1); } - getrsaprime(key->p, &pminus, key->e, size/16); - getrsaprime(key->q, &qminus, key->e, size/16); + while (1) { + getrsaprime(key->p, &pminus, key->e, size/16); + getrsaprime(key->q, &qminus, key->e, size/16); - if (mp_mul(key->p, key->q, key->n) != MP_OKAY) { - fprintf(stderr, "RSA generation failed\n"); - exit(1); + if (mp_mul(key->p, key->q, key->n) != MP_OKAY) { + fprintf(stderr, "RSA generation failed\n"); + exit(1); + } + + if ((unsigned int)mp_count_bits(key->n) == size) { + break; + } } /* lcm(p-1, q-1) */ @@ -91,16 +97,16 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus, unsigned char *buf; DEF_MP_INT(temp_gcd); - buf = (unsigned char*)m_malloc(size_bytes+1); + buf = (unsigned char*)m_malloc(size_bytes); m_mp_init(&temp_gcd); do { /* generate a random odd number with MSB set, then find the the next prime above it */ - genrandom(buf, size_bytes+1); - buf[0] |= 0x80; /* MSB set */ + genrandom(buf, size_bytes); + buf[0] |= 0x80; - bytes_to_mp(prime, buf, size_bytes+1); + bytes_to_mp(prime, buf, size_bytes); /* find the next integer which is prime, 8 round of miller-rabin */ if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) { @@ -122,7 +128,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus, /* now we have a good value for result */ mp_clear(&temp_gcd); - m_burn(buf, size_bytes+1); + m_burn(buf, size_bytes); m_free(buf); } diff --git a/release/src-rt-6.x.4708/router/dropbear/gensignkey.c b/release/src-rt-6.x.4708/router/dropbear/gensignkey.c index cb66ffff7f..e6c40e0053 100644 --- a/release/src-rt-6.x.4708/router/dropbear/gensignkey.c +++ b/release/src-rt-6.x.4708/router/dropbear/gensignkey.c @@ -26,7 +26,7 @@ static int buf_writefile(buffer * buf, const char * filename) { while (buf->pos != buf->len) { int len = write(fd, buf_getptr(buf, buf->len - buf->pos), buf->len - buf->pos); - if (errno == EINTR) { + if (len == -1 && errno == EINTR) { continue; } if (len <= 0) { @@ -41,6 +41,9 @@ static int buf_writefile(buffer * buf, const char * filename) { out: if (fd >= 0) { + if (fsync(fd) != 0) { + dropbear_log(LOG_ERR, "fsync of %s failed: %s", filename, strerror(errno)); + } m_close(fd); } return ret; diff --git a/release/src-rt-6.x.4708/router/dropbear/keyimport.c b/release/src-rt-6.x.4708/router/dropbear/keyimport.c index 3da14adbc0..6f2634fa45 100644 --- a/release/src-rt-6.x.4708/router/dropbear/keyimport.c +++ b/release/src-rt-6.x.4708/router/dropbear/keyimport.c @@ -602,13 +602,18 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase)) */ blobbuf = buf_new(3000); +#ifdef DROPBEAR_DSS if (key->type == OSSH_DSA) { buf_putstring(blobbuf, "ssh-dss", 7); retkey->type = DROPBEAR_SIGNKEY_DSS; - } else if (key->type == OSSH_RSA) { + } +#endif +#ifdef DROPBEAR_RSA + if (key->type == OSSH_RSA) { buf_putstring(blobbuf, "ssh-rsa", 7); retkey->type = DROPBEAR_SIGNKEY_RSA; } +#endif for (i = 0; i < num_integers; i++) { ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, @@ -622,7 +627,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase)) if (i == 0) { /* First integer is a version indicator */ - int expected; + int expected = -1; switch (key->type) { case OSSH_RSA: case OSSH_DSA: @@ -805,7 +810,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase)) } m_burn(key->keyblob, key->keyblob_size); m_free(key->keyblob); - m_burn(key, sizeof(key)); + m_burn(key, sizeof(*key)); m_free(key); if (errmsg) { fprintf(stderr, "Error: %s\n", errmsg); @@ -821,7 +826,7 @@ static int openssh_write(const char *filename, sign_key *key, unsigned char *outblob = NULL; int outlen = -9999; struct mpint_pos numbers[9]; - int nnumbers = -1, pos, len, seqlen, i; + int nnumbers = -1, pos = 0, len = 0, seqlen, i; char *header = NULL, *footer = NULL; char zero[1]; int ret = 0; @@ -831,7 +836,14 @@ static int openssh_write(const char *filename, sign_key *key, mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */ #endif - if (key->type == DROPBEAR_SIGNKEY_RSA || key->type == DROPBEAR_SIGNKEY_DSS) + if ( +#ifdef DROPBEAR_RSA + key->type == DROPBEAR_SIGNKEY_RSA || +#endif +#ifdef DROPBEAR_DSS + key->type == DROPBEAR_SIGNKEY_DSS || +#endif + 0) { /* * Fetch the key blobs. diff --git a/release/src-rt-6.x.4708/router/dropbear/loginrec.h b/release/src-rt-6.x.4708/router/dropbear/loginrec.h index bd400065d7..d2da8d24f6 100644 --- a/release/src-rt-6.x.4708/router/dropbear/loginrec.h +++ b/release/src-rt-6.x.4708/router/dropbear/loginrec.h @@ -79,10 +79,10 @@ # if defined(HAVE_UTMP_H) && defined(UTMP_FILE) && !defined(DISABLE_UTMP) # define USE_UTMP # endif -# if defined(HAVE_WTMPX_H) && defined(WTMPX_FILE) && !defined(DISABLE_WTMPX) +# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX) # define USE_WTMPX # endif -# if defined(HAVE_WTMP_H) && defined(WTMP_FILE) && !defined(DISABLE_WTMP) +# if defined(WTMP_FILE) && !defined(DISABLE_WTMP) # define USE_WTMP # endif diff --git a/release/src-rt-6.x.4708/router/dropbear/options.h b/release/src-rt-6.x.4708/router/dropbear/options.h index bc928da4ea..fa08b270a2 100644 --- a/release/src-rt-6.x.4708/router/dropbear/options.h +++ b/release/src-rt-6.x.4708/router/dropbear/options.h @@ -95,8 +95,12 @@ much traffic. */ #define DROPBEAR_AES256 /* Compiling in Blowfish will add ~6kB to runtime heap memory usage */ /*#define DROPBEAR_BLOWFISH*/ -#define DROPBEAR_TWOFISH256 -#define DROPBEAR_TWOFISH128 +/*#define DROPBEAR_TWOFISH256*/ +/*#define DROPBEAR_TWOFISH128*/ + +/* Enable CBC mode for ciphers. This has security issues though + * is the most compatible with older SSH implementations */ +#define DROPBEAR_ENABLE_CBC_MODE /* Enable "Counter Mode" for ciphers. This is more secure than normal * CBC mode against certain attacks. This adds around 1kB to binary @@ -123,8 +127,8 @@ much traffic. */ * which are not the standard form. */ #define DROPBEAR_SHA1_HMAC #define DROPBEAR_SHA1_96_HMAC -/*#define DROPBEAR_SHA2_256_HMAC*/ -/*#define DROPBEAR_SHA2_512_HMAC*/ +#define DROPBEAR_SHA2_256_HMAC +#define DROPBEAR_SHA2_512_HMAC #define DROPBEAR_MD5_HMAC /* You can also disable integrity. Don't bother disabling this if you're @@ -170,6 +174,11 @@ much traffic. */ #define DROPBEAR_ZLIB_WINDOW_BITS 15 #endif +/* Server won't allow zlib compression until after authentication. Prevents + flaws in the zlib library being unauthenticated exploitable flaws. + Some old ssh clients may not support the alternative zlib@openssh.com method */ +#define DROPBEAR_SERVER_DELAY_ZLIB 1 + /* Whether to do reverse DNS lookups. */ /*#define DO_HOST_LOOKUP */ @@ -207,6 +216,10 @@ much traffic. */ #define ENABLE_CLI_PUBKEY_AUTH #define ENABLE_CLI_INTERACT_AUTH +/* A default argument for dbclient -i . + leading "~" is expanded */ +#define DROPBEAR_DEFAULT_CLI_AUTHKEY "~/.ssh/id_dropbear" + /* This variable can be used to set a password for client * authentication on the commandline. Beware of platforms * that don't protect environment variables of processes etc. Also @@ -222,12 +235,11 @@ much traffic. */ * return the password on standard output */ /*#define ENABLE_CLI_ASKPASS_HELPER*/ -/* Send a real auth request first rather than requesting a list of available methods. - * It saves a network round trip at login but prevents immediate login to - * accounts with no password, and might be rejected by some strict servers (none - * encountered yet) - hence it isn't enabled by default. */ -/* #define CLI_IMMEDIATE_AUTH */ - +/* 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 + * could cause problems with non-compliant servers */ +/* #define DROPBEAR_CLI_IMMEDIATE_AUTH */ /* Source for randomness. This must be able to provide hundreds of bytes per SSH * connection without blocking. In addition /dev/random is used for seeding @@ -309,6 +321,11 @@ much traffic. */ be overridden at runtime with -K. 0 disables keepalives */ #define DEFAULT_KEEPALIVE 0 +/* If this many KEEPALIVES are sent with no packets received from the +other side, exit. Not run-time configurable - if you have a need +for runtime configuration please mail the Dropbear list */ +#define DEFAULT_KEEPALIVE_LIMIT 3 + /* Ensure that data is received within IDLE_TIMEOUT seconds. This can be overridden at runtime with -I. 0 disables idle timeouts */ #define DEFAULT_IDLE_TIMEOUT 0 diff --git a/release/src-rt-6.x.4708/router/dropbear/packet.c b/release/src-rt-6.x.4708/router/dropbear/packet.c index 1b5ee93d4f..89b1bcfde1 100644 --- a/release/src-rt-6.x.4708/router/dropbear/packet.c +++ b/release/src-rt-6.x.4708/router/dropbear/packet.c @@ -41,7 +41,11 @@ static void make_mac(unsigned int seqno, const struct key_context_directional * unsigned char *output_mac); static int checkmac(); -#define ZLIB_COMPRESS_INCR 100 +/* For exact details see http://www.zlib.net/zlib_tech.html + * 5 bytes per 16kB block, plus 6 bytes for the stream. + * We might allocate 5 unnecessary bytes here if it's an + * exact multiple. */ +#define ZLIB_COMPRESS_EXPANSION (((RECV_MAX_PAYLOAD_LEN/16384)+1)*5 + 6) #define ZLIB_DECOMPRESS_INCR 1024 #ifndef DISABLE_ZLIB static buffer* buf_decompress(buffer* buf, unsigned int len); @@ -53,42 +57,55 @@ void write_packet() { int len, written; buffer * writebuf = NULL; - time_t now; unsigned packet_type; - int all_ignore = 1; #ifdef HAVE_WRITEV struct iovec *iov = NULL; int i; struct Link *l; + int iov_max_count; #endif TRACE2(("enter write_packet")) dropbear_assert(!isempty(&ses.writequeue)); -#ifdef HAVE_WRITEV - iov = m_malloc(sizeof(*iov) * ses.writequeue.count); +#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV)) + +#ifndef IOV_MAX +#define IOV_MAX UIO_MAXIOV +#endif + + /* Make sure the size of the iov is below the maximum allowed by the OS. */ + iov_max_count = ses.writequeue.count; + if (iov_max_count > IOV_MAX) + { + iov_max_count = IOV_MAX; + } + + iov = m_malloc(sizeof(*iov) * iov_max_count); for (l = ses.writequeue.head, i = 0; l; l = l->link, i++) { writebuf = (buffer*)l->item; packet_type = writebuf->data[writebuf->len-1]; len = writebuf->len - 1 - writebuf->pos; dropbear_assert(len > 0); - all_ignore &= (packet_type == SSH_MSG_IGNORE); TRACE2(("write_packet writev #%d type %d len %d/%d", i, packet_type, len, writebuf->len-1)) iov[i].iov_base = buf_getptr(writebuf, len); iov[i].iov_len = len; } - written = writev(ses.sock_out, iov, ses.writequeue.count); + /* This may return EAGAIN. The main loop sometimes + calls write_packet() without bothering to test with select() since + it's likely to be necessary */ + written = writev(ses.sock_out, iov, iov_max_count); if (written < 0) { - if (errno == EINTR) { + if (errno == EINTR || errno == EAGAIN) { m_free(iov); - TRACE2(("leave writepacket: EINTR")) + TRACE2(("leave write_packet: EINTR")) return; } else { - dropbear_exit("Error writing"); + dropbear_exit("Error writing: %s", strerror(errno)); } - } + } if (written == 0) { ses.remoteclosed(); @@ -109,8 +126,7 @@ void write_packet() { } m_free(iov); - -#else +#else /* No writev () */ /* Get the next buffer in the queue of encrypted packets to write*/ writebuf = (buffer*)examine(&ses.writequeue); @@ -123,14 +139,13 @@ void write_packet() { written = write(ses.sock_out, buf_getptr(writebuf, len), len); if (written < 0) { - if (errno == EINTR) { + if (errno == EINTR || errno == EAGAIN) { TRACE2(("leave writepacket: EINTR")) return; } else { - dropbear_exit("Error writing"); + dropbear_exit("Error writing: %s", strerror(errno)); } } - all_ignore = (packet_type == SSH_MSG_IGNORE); if (written == 0) { ses.remoteclosed(); @@ -145,14 +160,7 @@ void write_packet() { /* More packet left to write, leave it in the queue for later */ buf_incrpos(writebuf, written); } - -#endif - now = time(NULL); - ses.last_trx_packet_time = now; - - if (!all_ignore) { - ses.last_packet_time = now; - } +#endif /* writev */ TRACE2(("leave write_packet")) } @@ -250,7 +258,7 @@ static int read_packet_init() { ses.remoteclosed(); } if (slen < 0) { - if (errno == EINTR) { + if (errno == EINTR || errno == EAGAIN) { TRACE2(("leave read_packet_init: EINTR")) return DROPBEAR_FAILURE; } @@ -275,14 +283,14 @@ static int read_packet_init() { } len = buf_getint(ses.readbuf) + 4 + macsize; - TRACE2(("packet size is %d, block %d mac %d", len, blocksize, macsize)) + TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize)) /* check packet length */ if ((len > RECV_MAX_PACKET_LEN) || (len < MIN_PACKET_LEN + macsize) || ((len - macsize) % blocksize != 0)) { - dropbear_exit("Integrity error (bad packet size %d)", len); + dropbear_exit("Integrity error (bad packet size %u)", len); } if (len > ses.readbuf->size) { @@ -333,8 +341,8 @@ void decrypt_packet() { /* payload length */ /* - 4 - 1 is for LEN and PADLEN values */ len = ses.readbuf->len - padlen - 4 - 1 - macsize; - if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) { - dropbear_exit("Bad packet size %d", len); + if ((len > RECV_MAX_PAYLOAD_LEN+ZLIB_COMPRESS_EXPANSION) || (len < 1)) { + dropbear_exit("Bad packet size %u", len); } buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF); @@ -422,6 +430,8 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) { if (zstream->avail_out == 0) { int new_size = 0; if (ret->size >= RECV_MAX_PAYLOAD_LEN) { + /* Already been increased as large as it can go, + * yet didn't finish up the decompression */ dropbear_exit("bad packet, oversized decompressed"); } new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR); @@ -497,6 +507,8 @@ void encrypt_packet() { unsigned char packet_type; unsigned int len, encrypt_buf_size; unsigned char mac_bytes[MAX_MAC_LEN]; + + time_t now; TRACE2(("enter encrypt_packet()")) @@ -526,7 +538,7 @@ void encrypt_packet() { + mac_size #ifndef DISABLE_ZLIB /* some extra in case 'compression' makes it larger */ - + ZLIB_COMPRESS_INCR + + ZLIB_COMPRESS_EXPANSION #endif /* and an extra cleartext (stripped before transmission) byte for the * packet type */ @@ -539,14 +551,7 @@ void encrypt_packet() { #ifndef DISABLE_ZLIB /* compression */ if (is_compress_trans()) { - int compress_delta; buf_compress(writebuf, ses.writepayload, ses.writepayload->len); - compress_delta = (writebuf->len - PACKET_PAYLOAD_OFF) - ses.writepayload->len; - - /* Handle the case where 'compress' increased the size. */ - if (compress_delta > ZLIB_COMPRESS_INCR) { - buf_resize(writebuf, writebuf->size + compress_delta); - } } else #endif { @@ -611,6 +616,18 @@ void encrypt_packet() { ses.kexstate.datatrans += writebuf->len; ses.transseq++; + now = monotonic_now(); + ses.last_packet_time_any_sent = now; + /* idle timeout shouldn't be affected by responses to keepalives. + send_msg_keepalive() itself also does tricks with + ses.last_packet_idle_time - read that if modifying this code */ + if (packet_type != SSH_MSG_REQUEST_FAILURE + && packet_type != SSH_MSG_UNIMPLEMENTED + && packet_type != SSH_MSG_IGNORE) { + ses.last_packet_time_idle = now; + + } + TRACE2(("leave encrypt_packet()")) } @@ -694,7 +711,7 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) { /* the buffer has been filled, we must extend. This only happens in * unusual circumstances where the data grows in size after deflate(), * but it is possible */ - buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR); + buf_resize(dest, dest->size + ZLIB_COMPRESS_EXPANSION); } TRACE2(("leave buf_compress")) diff --git a/release/src-rt-6.x.4708/router/dropbear/process-packet.c b/release/src-rt-6.x.4708/router/dropbear/process-packet.c index 0b92510675..ddeb9cec8f 100644 --- a/release/src-rt-6.x.4708/router/dropbear/process-packet.c +++ b/release/src-rt-6.x.4708/router/dropbear/process-packet.c @@ -44,6 +44,7 @@ void process_packet() { unsigned char type; unsigned int i; + time_t now; TRACE2(("enter process_packet")) @@ -52,7 +53,8 @@ void process_packet() { ses.lastpacket = type; - ses.last_packet_time = time(NULL); + now = monotonic_now(); + ses.last_packet_time_keepalive_recv = now; /* These packets we can receive at any time */ switch(type) { @@ -65,24 +67,49 @@ void process_packet() { case SSH_MSG_UNIMPLEMENTED: /* debugging XXX */ TRACE(("SSH_MSG_UNIMPLEMENTED")) - dropbear_exit("Received SSH_MSG_UNIMPLEMENTED"); + goto out; case SSH_MSG_DISCONNECT: /* TODO cleanup? */ dropbear_close("Disconnect received"); } + /* Ignore these packet types so that keepalives don't interfere with + idle detection. This is slightly incorrect since a tcp forwarded + global request with failure won't trigger the idle timeout, + but that's probably acceptable */ + if (!(type == SSH_MSG_GLOBAL_REQUEST || type == SSH_MSG_REQUEST_FAILURE)) { + ses.last_packet_time_idle = now; + } + /* This applies for KEX, where the spec says the next packet MUST be * NEWKEYS */ - if (ses.requirenext[0] != 0) { - if (ses.requirenext[0] != type - && (ses.requirenext[1] == 0 || ses.requirenext[1] != type)) { - dropbear_exit("Unexpected packet type %d, expected [%d,%d]", type, - ses.requirenext[0], ses.requirenext[1]); - } else { + if (ses.requirenext != 0) { + if (ses.requirenext == type) + { /* Got what we expected */ - ses.requirenext[0] = 0; - ses.requirenext[1] = 0; + TRACE(("got expected packet %d during kexinit", type)) + } + else + { + /* RFC4253 7.1 - various messages are allowed at this point. + The only ones we know about have already been handled though, + so just return "unimplemented" */ + if (type >= 1 && type <= 49 + && type != SSH_MSG_SERVICE_REQUEST + && type != SSH_MSG_SERVICE_ACCEPT + && type != SSH_MSG_KEXINIT) + { + TRACE(("unknown allowed packet during kexinit")) + recv_unimplemented(); + goto out; + } + else + { + TRACE(("disallowed packet during kexinit")) + dropbear_exit("Unexpected packet type %d, expected %d", type, + ses.requirenext); + } } } @@ -94,6 +121,12 @@ void process_packet() { goto out; } + /* Only clear the flag after we have checked ignorenext */ + if (ses.requirenext != 0 && ses.requirenext == type) + { + ses.requirenext = 0; + } + /* Kindly the protocol authors gave all the preauth packets type values * less-than-or-equal-to 60 ( == MAX_UNAUTH_PACKET_TYPE ). diff --git a/release/src-rt-6.x.4708/router/dropbear/release.sh b/release/src-rt-6.x.4708/router/dropbear/release.sh new file mode 100644 index 0000000000..f377d0e305 --- /dev/null +++ b/release/src-rt-6.x.4708/router/dropbear/release.sh @@ -0,0 +1,40 @@ +#!/bin/sh +VERSION=$(echo '#include "sysoptions.h"\necho DROPBEAR_VERSION' | cpp - | sh) +echo Releasing version "$VERSION" ... +if ! head -n1 CHANGES | grep -q $VERSION ; then + echo "CHANGES needs updating" + exit 1 +fi + +if ! head -n1 debian/changelog | grep -q $VERSION ; then + echo "debian/changelog needs updating" + exit 1 +fi + +head -n1 CHANGES + +#sleep 3 + +RELDIR=$PWD/../dropbear-$VERSION +ARCHIVE=${RELDIR}.tar.bz2 +if test -e $RELDIR; then + echo "$RELDIR exists" + exit 1 +fi + +if test -e $ARCHIVE; then + echo "$ARCHIVE exists" + exit 1 +fi + +hg archive "$RELDIR" || exit 2 + +(cd "$RELDIR" && autoconf && autoheader) || exit 2 + +rm -r "$RELDIR/autom4te.cache" || exit 2 + +(cd $RELDIR/.. && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2 + +ls -l $ARCHIVE +openssl sha1 $ARCHIVE +echo "Done to $ARCHIVE" diff --git a/release/src-rt-6.x.4708/router/dropbear/rsa.c b/release/src-rt-6.x.4708/router/dropbear/rsa.c index 7eb64131a4..193e5774b8 100644 --- a/release/src-rt-6.x.4708/router/dropbear/rsa.c +++ b/release/src-rt-6.x.4708/router/dropbear/rsa.c @@ -347,7 +347,9 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf) { mp_clear(&rsa_s); #if defined(DEBUG_RSA) && defined(DEBUG_TRACE) - printhex("RSA sig", buf->data, buf->len); + if (!debug_trace) { + printhex("RSA sig", buf->data, buf->len); + } #endif diff --git a/release/src-rt-6.x.4708/router/dropbear/runopts.h b/release/src-rt-6.x.4708/router/dropbear/runopts.h index 21fc8e5627..87567164a6 100644 --- a/release/src-rt-6.x.4708/router/dropbear/runopts.h +++ b/release/src-rt-6.x.4708/router/dropbear/runopts.h @@ -37,14 +37,18 @@ typedef struct runopts { int listen_fwd_all; #endif unsigned int recv_window; - time_t keepalive_secs; - time_t idle_timeout_secs; + time_t keepalive_secs; /* Time between sending keepalives. 0 is off */ + time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */ #ifndef DISABLE_ZLIB /* TODO: add a commandline flag. Currently this is on by default if compression * is compiled in, but disabled for a client's non-final multihop stages. (The * intermediate stages are compressed streams, so are uncompressible. */ - int enable_compress; + enum { + DROPBEAR_COMPRESS_DELAYED, /* Server only */ + DROPBEAR_COMPRESS_ON, + DROPBEAR_COMPRESS_OFF, + } compress_mode; #endif #ifdef ENABLE_USER_ALGO_LIST @@ -164,4 +168,6 @@ void cli_getopts(int argc, char ** argv); void parse_ciphers_macs(); #endif +void print_version(void); + #endif /* _RUNOPTS_H_ */ diff --git a/release/src-rt-6.x.4708/router/dropbear/scp.c b/release/src-rt-6.x.4708/router/dropbear/scp.c index 65cbb776ca..11c966546d 100644 --- a/release/src-rt-6.x.4708/router/dropbear/scp.c +++ b/release/src-rt-6.x.4708/router/dropbear/scp.c @@ -1146,7 +1146,7 @@ usage(void) { (void) fprintf(stderr, "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" - " [-l limit] [-o ssh_option] [-P port] [-S program]\n" + " [-l limit] [-P port] [-S program]\n" " [[user@]host1:]file1 [...] [[user@]host2:]file2\n"); exit(1); } diff --git a/release/src-rt-6.x.4708/router/dropbear/session.h b/release/src-rt-6.x.4708/router/dropbear/session.h index 91e306a7f7..ed0f5be16f 100644 --- a/release/src-rt-6.x.4708/router/dropbear/session.h +++ b/release/src-rt-6.x.4708/router/dropbear/session.h @@ -47,6 +47,9 @@ void session_loop(void(*loophandler)()); void session_cleanup(); void send_session_identification(); void send_msg_ignore(); +void ignore_recv_response(); + +void update_channel_prio(); const char* get_user_shell(); void fill_passwd(const char* username); @@ -104,10 +107,6 @@ struct sshsession { /* Is it a client or server? */ unsigned char isserver; - time_t connect_time; /* time the connection was established - (cleared after auth once we're not - respecting AUTH_TIMEOUT any more) */ - int sock_in; int sock_out; @@ -135,9 +134,8 @@ struct sshsession { unsigned dataallowed : 1; /* whether we can send data packets or we are in the middle of a KEX or something */ - unsigned char requirenext[2]; /* bytes indicating what packets we require next, - or 0x00 for any. Second option can only be - used if the first byte is also set */ + unsigned char requirenext; /* byte indicating what packets we require next, + or 0x00 for any. */ unsigned char ignorenext; /* whether to ignore the next packet, used for kex_follows stuff */ @@ -147,11 +145,14 @@ struct sshsession { int signal_pipe[2]; /* stores endpoints of a self-pipe used for race-free signal handling */ - time_t last_trx_packet_time; /* time of the last packet transmission, for - keepalive purposes */ + /* time of the last packet send/receive, for keepalive. Not real-world clock */ + time_t last_packet_time_keepalive_sent; + time_t last_packet_time_keepalive_recv; + time_t last_packet_time_any_sent; - time_t last_packet_time; /* time of the last packet transmission or receive, for - idle timeout purposes */ + time_t last_packet_time_idle; /* time of the last packet transmission or receive, for + idle timeout purposes so ignores SSH_MSG_IGNORE + or responses to keepalives. Not real-world clock */ /* KEX/encryption related */ @@ -187,8 +188,11 @@ struct sshsession { 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; - /* TCP forwarding - where manage listeners */ struct Listener ** listeners; unsigned int listensize; @@ -218,6 +222,11 @@ struct serversession { /* The resolved remote address, used for lastlog etc */ char *remotehost; + time_t connect_time; /* time the connection was established + (cleared after auth once we're not + respecting AUTH_TIMEOUT any more). + A monotonic time, not realworld */ + #ifdef USE_VFORK pid_t server_pid; #endif @@ -233,6 +242,7 @@ typedef enum { typedef enum { STATE_NOTHING, + USERAUTH_WAIT, USERAUTH_REQ_SENT, USERAUTH_FAIL_RCVD, USERAUTH_SUCCESS_RCVD, @@ -267,6 +277,7 @@ struct clientsession { int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD, for the last type of auth we tried */ + int ignore_next_auth_response; #ifdef ENABLE_CLI_INTERACT_AUTH int auth_interact_failed; /* flag whether interactive auth can still be used */ diff --git a/release/src-rt-6.x.4708/router/dropbear/signkey.c b/release/src-rt-6.x.4708/router/dropbear/signkey.c index 4ac40cbebf..ea7c67d414 100644 --- a/release/src-rt-6.x.4708/router/dropbear/signkey.c +++ b/release/src-rt-6.x.4708/router/dropbear/signkey.c @@ -106,6 +106,7 @@ enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) void ** signkey_key_ptr(sign_key *key, enum signkey_type type) { switch (type) { +#ifdef DROPBEAR_ECDSA #ifdef DROPBEAR_ECC_256 case DROPBEAR_SIGNKEY_ECDSA_NISTP256: return (void**)&key->ecckey256; @@ -118,6 +119,7 @@ signkey_key_ptr(sign_key *key, enum signkey_type type) { case DROPBEAR_SIGNKEY_ECDSA_NISTP521: return (void**)&key->ecckey521; #endif +#endif /* DROPBEAR_ECDSA */ #ifdef DROPBEAR_RSA case DROPBEAR_SIGNKEY_RSA: return (void**)&key->rsakey; diff --git a/release/src-rt-6.x.4708/router/dropbear/svr-auth.c b/release/src-rt-6.x.4708/router/dropbear/svr-auth.c index 9051d85fc1..89760ef9e5 100644 --- a/release/src-rt-6.x.4708/router/dropbear/svr-auth.c +++ b/release/src-rt-6.x.4708/router/dropbear/svr-auth.c @@ -392,8 +392,7 @@ void send_msg_userauth_success() { /* authdone must be set after encrypt_packet() for * delayed-zlib mode */ ses.authstate.authdone = 1; - ses.connect_time = 0; - + svr_ses.connect_time = 0; if (ses.authstate.pw_uid == 0) { ses.allowprivport = 1; diff --git a/release/src-rt-6.x.4708/router/dropbear/svr-chansession.c b/release/src-rt-6.x.4708/router/dropbear/svr-chansession.c index dd9ea02b82..67122bb11a 100644 --- a/release/src-rt-6.x.4708/router/dropbear/svr-chansession.c +++ b/release/src-rt-6.x.4708/router/dropbear/svr-chansession.c @@ -53,6 +53,7 @@ static void sesssigchild_handler(int val); static void closechansess(struct Channel *channel); static int newchansess(struct Channel *channel); static void chansessionrequest(struct Channel *channel); +static int sesscheckclose(struct Channel *channel); static void send_exitsignalstatus(struct Channel *channel); static void send_msg_chansess_exitstatus(struct Channel * channel, @@ -61,6 +62,14 @@ static void send_msg_chansess_exitsignal(struct Channel * channel, struct ChanSess * chansess); static void get_termmodes(struct ChanSess *chansess); +const struct ChanType svrchansess = { + 0, /* sepfds */ + "session", /* name */ + newchansess, /* inithandler */ + sesscheckclose, /* checkclosehandler */ + chansessionrequest, /* reqhandler */ + closechansess, /* closehandler */ +}; /* required to clear environment */ extern char** environ; @@ -87,6 +96,11 @@ static void sesssigchild_handler(int UNUSED(dummy)) { 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)) @@ -140,6 +154,8 @@ static void sesssigchild_handler(int UNUSED(dummy)) { sigemptyset(&sa_chld.sa_mask); sigaction(SIGCHLD, &sa_chld, NULL); TRACE(("leave sigchld handler")) + + errno = saved_errno; } /* send the exit status or the signal causing termination for a session */ @@ -225,6 +241,7 @@ static int newchansess(struct Channel *channel) { chansess = (struct ChanSess*)m_malloc(sizeof(struct ChanSess)); chansess->cmd = NULL; chansess->connection_string = NULL; + chansess->client_string = NULL; chansess->pid = 0; /* pty details */ @@ -249,6 +266,8 @@ static int newchansess(struct Channel *channel) { chansess->agentdir = NULL; #endif + channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE; + return 0; } @@ -584,19 +603,26 @@ static int sessionpty(struct ChanSess * chansess) { return DROPBEAR_SUCCESS; } -static char* make_connection_string() { +static void make_connection_string(struct ChanSess *chansess) { char *local_ip, *local_port, *remote_ip, *remote_port; size_t len; - char *ret; get_socket_address(ses.sock_in, &local_ip, &local_port, &remote_ip, &remote_port, 0); - len = strlen(local_ip) + strlen(local_port) + strlen(remote_ip) + strlen(remote_port) + 4; - ret = m_malloc(len); - snprintf(ret, len, "%s %s %s %s", remote_ip, remote_port, local_ip, local_port); + + /* "remoteip remoteport localip localport" */ + len = strlen(local_ip) + strlen(remote_ip) + 20; + chansess->connection_string = m_malloc(len); + snprintf(chansess->connection_string, len, "%s %s %s %s", remote_ip, remote_port, local_ip, local_port); + + /* deprecated but bash only loads .bashrc if SSH_CLIENT is set */ + /* "remoteip remoteport localport" */ + len = strlen(remote_ip) + 20; + chansess->client_string = m_malloc(len); + snprintf(chansess->client_string, len, "%s %s %s", remote_ip, remote_port, local_port); + m_free(local_ip); m_free(local_port); m_free(remote_ip); m_free(remote_port); - return ret; } /* Handle a command request from the client. This is used for both shell @@ -659,13 +685,16 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess, /* uClinux will vfork(), so there'll be a race as connection_string is freed below. */ #ifndef USE_VFORK - chansess->connection_string = make_connection_string(); + make_connection_string(chansess); #endif if (chansess->term == NULL) { /* no pty */ - set_sock_priority(ses.sock_out, DROPBEAR_PRIO_BULK); ret = noptycommand(channel, chansess); + if (ret == DROPBEAR_SUCCESS) { + channel->prio = DROPBEAR_CHANNEL_PRIO_BULK; + update_channel_prio(); + } } else { /* want pty */ ret = ptycommand(channel, chansess); @@ -673,6 +702,7 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess, #ifndef USE_VFORK m_free(chansess->connection_string); + m_free(chansess->client_string); #endif if (ret == DROPBEAR_FAILURE) { @@ -928,6 +958,10 @@ static void execchild(void *user_data) { if (chansess->connection_string) { addnewvar("SSH_CONNECTION", chansess->connection_string); } + + if (chansess->client_string) { + addnewvar("SSH_CLIENT", chansess->client_string); + } #ifdef ENABLE_SVR_PUBKEY_OPTIONS if (chansess->original_command) { @@ -956,16 +990,6 @@ static void execchild(void *user_data) { dropbear_exit("Child failed"); } -const struct ChanType svrchansess = { - 0, /* sepfds */ - "session", /* name */ - newchansess, /* inithandler */ - sesscheckclose, /* checkclosehandler */ - chansessionrequest, /* reqhandler */ - closechansess, /* closehandler */ -}; - - /* Set up the general chansession environment, in particular child-exit * handling */ void svr_chansessinitialise() { diff --git a/release/src-rt-6.x.4708/router/dropbear/svr-kex.c b/release/src-rt-6.x.4708/router/dropbear/svr-kex.c index e42a67cd65..6cc5433a3c 100644 --- a/release/src-rt-6.x.4708/router/dropbear/svr-kex.c +++ b/release/src-rt-6.x.4708/router/dropbear/svr-kex.c @@ -80,12 +80,32 @@ void recv_msg_kexdh_init() { } send_msg_newkeys(); - ses.requirenext[0] = SSH_MSG_NEWKEYS; - ses.requirenext[1] = 0; + ses.requirenext = SSH_MSG_NEWKEYS; TRACE(("leave recv_msg_kexdh_init")) } + #ifdef DROPBEAR_DELAY_HOSTKEY + +static void fsync_parent_dir(const char* fn) { +#ifdef HAVE_LIBGEN_H + char *fn_dir = m_strdup(fn); + char *dir = dirname(fn_dir); + int dirfd = open(dir, O_RDONLY); + + if (dirfd != -1) { + if (fsync(dirfd) != 0) { + TRACE(("fsync of directory %s failed: %s", dir, strerror(errno))) + } + m_close(dirfd); + } else { + TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno))) + } + + free(fn_dir); +#endif +} + static void svr_ensure_hostkey() { const char* fn = NULL; @@ -143,6 +163,10 @@ static void svr_ensure_hostkey() { } } + /* ensure directory update is flushed to disk, otherwise we can end up + with zero-byte hostkey files if the power goes off */ + fsync_parent_dir(fn); + ret = readhostkey(fn, svr_opts.hostkey, &type); if (ret == DROPBEAR_SUCCESS) { diff --git a/release/src-rt-6.x.4708/router/dropbear/svr-main.c b/release/src-rt-6.x.4708/router/dropbear/svr-main.c index 73b281baae..284e02d901 100644 --- a/release/src-rt-6.x.4708/router/dropbear/svr-main.c +++ b/release/src-rt-6.x.4708/router/dropbear/svr-main.c @@ -337,20 +337,24 @@ out: static void sigchld_handler(int UNUSED(unused)) { struct sigaction sa_chld; + const int saved_errno = errno; + while(waitpid(-1, NULL, WNOHANG) > 0); sa_chld.sa_handler = sigchld_handler; sa_chld.sa_flags = SA_NOCLDSTOP; + sigemptyset(&sa_chld.sa_mask); if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { dropbear_exit("signal() error"); } + errno = saved_errno; } /* catch any segvs */ static void sigsegv_handler(int UNUSED(unused)) { fprintf(stderr, "Aiee, segfault! You should probably report " "this as a bug to the developer\n"); - exit(EXIT_FAILURE); + _exit(EXIT_FAILURE); } /* catch ctrl-c or sigterm */ @@ -406,7 +410,7 @@ static size_t listensockets(int *sock, size_t sockcount, int *maxfd) { size_t sockpos = 0; int nsock; - TRACE(("listensockets: %d to try\n", svr_opts.portcount)) + TRACE(("listensockets: %d to try", svr_opts.portcount)) for (i = 0; i < svr_opts.portcount; i++) { diff --git a/release/src-rt-6.x.4708/router/dropbear/svr-runopts.c b/release/src-rt-6.x.4708/router/dropbear/svr-runopts.c index 414cb45e0a..09fc9af56c 100644 --- a/release/src-rt-6.x.4708/router/dropbear/svr-runopts.c +++ b/release/src-rt-6.x.4708/router/dropbear/svr-runopts.c @@ -92,6 +92,7 @@ static void printhelp(const char * progname) { "-W (default %d, larger may be faster, max 1MB)\n" "-K (0 is never, default %d, in seconds)\n" "-I (0 is never, default %d, in seconds)\n" + "-V Version\n" #ifdef DEBUG_TRACE "-v verbose (compiled with DEBUG_TRACE)\n" #endif @@ -139,9 +140,15 @@ void svr_getopts(int argc, char ** argv) { #ifdef ENABLE_SVR_REMOTETCPFWD svr_opts.noremotetcp = 0; #endif + #ifndef DISABLE_ZLIB - opts.enable_compress = 1; +#if DROPBEAR_SERVER_DELAY_ZLIB + opts.compress_mode = DROPBEAR_COMPRESS_DELAYED; +#else + opts.compress_mode = DROPBEAR_COMPRESS_ON; #endif +#endif + /* not yet opts.ipv4 = 1; opts.ipv6 = 1; @@ -256,7 +263,7 @@ void svr_getopts(int argc, char ** argv) { #endif case 'h': printhelp(argv[0]); - exit(EXIT_FAILURE); + exit(EXIT_SUCCESS); break; case 'u': /* backwards compatibility with old urandom option */ @@ -266,6 +273,10 @@ void svr_getopts(int argc, char ** argv) { debug_trace = 1; break; #endif + case 'V': + print_version(); + exit(EXIT_SUCCESS); + break; default: fprintf(stderr, "Unknown argument %s\n", argv[i]); printhelp(argv[0]); @@ -405,7 +416,9 @@ static void loadhostkey(const char *keyfile, int fatal_duplicate) { sign_key * read_key = new_sign_key(); enum signkey_type type = DROPBEAR_SIGNKEY_ANY; if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) { - dropbear_log(LOG_WARNING, "Failed loading %s", keyfile); + if (!svr_opts.delay_hostkey) { + dropbear_log(LOG_WARNING, "Failed loading %s", keyfile); + } } #ifdef DROPBEAR_RSA diff --git a/release/src-rt-6.x.4708/router/dropbear/svr-session.c b/release/src-rt-6.x.4708/router/dropbear/svr-session.c index e9fde24b78..343cb30cca 100644 --- a/release/src-rt-6.x.4708/router/dropbear/svr-session.c +++ b/release/src-rt-6.x.4708/router/dropbear/svr-session.c @@ -58,6 +58,10 @@ static const packettype svr_packettypes[] = { {SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open}, {SSH_MSG_CHANNEL_EOF, recv_msg_channel_eof}, {SSH_MSG_CHANNEL_CLOSE, recv_msg_channel_close}, + {SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response}, + {SSH_MSG_CHANNEL_FAILURE, ignore_recv_response}, + {SSH_MSG_REQUEST_FAILURE, ignore_recv_response}, /* for keepalive */ + {SSH_MSG_REQUEST_SUCCESS, ignore_recv_response}, /* client */ #ifdef USING_LISTENERS {SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation}, {SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure}, @@ -80,12 +84,22 @@ svr_session_cleanup(void) svr_pubkey_options_cleanup(); } +static void +svr_sessionloop() { + if (svr_ses.connect_time != 0 + && monotonic_now() - svr_ses.connect_time >= AUTH_TIMEOUT) { + dropbear_close("Timeout before auth"); + } +} + void svr_session(int sock, int childpipe) { char *host, *port; size_t len; common_session_init(sock, sock); + svr_ses.connect_time = monotonic_now();; + /* Initialise server specific parts of the session */ svr_ses.childpipe = childpipe; #ifdef USE_VFORK @@ -95,8 +109,6 @@ void svr_session(int sock, int childpipe) { chaninitialise(svr_chantypes); svr_chansessinitialise(); - ses.connect_time = time(NULL); - /* for logging the remote address */ get_socket_address(ses.sock_in, NULL, NULL, &host, &port, 0); len = strlen(host) + strlen(port) + 2; @@ -128,7 +140,7 @@ void svr_session(int sock, int childpipe) { /* Run the main for loop. NULL is for the dispatcher - only the client * code makes use of it */ - session_loop(NULL); + session_loop(svr_sessionloop); /* Not reached */ diff --git a/release/src-rt-6.x.4708/router/dropbear/svr-tcpfwd.c b/release/src-rt-6.x.4708/router/dropbear/svr-tcpfwd.c index 179d5ffc8c..e5f219e4b4 100644 --- a/release/src-rt-6.x.4708/router/dropbear/svr-tcpfwd.c +++ b/release/src-rt-6.x.4708/router/dropbear/svr-tcpfwd.c @@ -34,14 +34,6 @@ #include "runopts.h" #include "auth.h" -static void send_msg_request_failure(); - -static void send_msg_request_failure() { - CHECKCLEARTOWRITE(); - buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); - encrypt_packet(); -} - #ifndef ENABLE_SVR_REMOTETCPFWD /* This is better than SSH_MSG_UNIMPLEMENTED */ @@ -53,7 +45,6 @@ void recv_msg_global_request_remotetcp() { /* */ #endif /* !ENABLE_SVR_REMOTETCPFWD */ -static void send_msg_request_success(); static int svr_cancelremotetcp(); static int svr_remotetcpreq(); static int newtcpdirect(struct Channel * channel); @@ -62,7 +53,7 @@ static int newtcpdirect(struct Channel * channel); static const struct ChanType svr_chan_tcpremote = { 1, /* sepfds */ "forwarded-tcpip", - NULL, + tcp_prio_inithandler, NULL, NULL, NULL @@ -115,15 +106,6 @@ out: TRACE(("leave recv_msg_global_request")) } - -static void send_msg_request_success() { - - CHECKCLEARTOWRITE(); - buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS); - encrypt_packet(); - -} - static int matchtcp(void* typedata1, void* typedata2) { const struct TCPListener *info1 = (struct TCPListener*)typedata1; @@ -258,6 +240,8 @@ static int newtcpdirect(struct Channel * channel) { int len; int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; + TRACE(("newtcpdirect channel %d", channel->index)) + if (svr_opts.nolocaltcp || !svr_pubkey_allows_tcpfwd()) { TRACE(("leave newtcpdirect: local tcp forwarding disabled")) goto out; @@ -299,6 +283,8 @@ static int newtcpdirect(struct Channel * channel) { * progress succeeds */ channel->writefd = sock; channel->initconn = 1; + + channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; err = SSH_OPEN_IN_PROGRESS; diff --git a/release/src-rt-6.x.4708/router/dropbear/svr-x11fwd.c b/release/src-rt-6.x.4708/router/dropbear/svr-x11fwd.c index f6368d7e90..ceca26a991 100644 --- a/release/src-rt-6.x.4708/router/dropbear/svr-x11fwd.c +++ b/release/src-rt-6.x.4708/router/dropbear/svr-x11fwd.c @@ -182,10 +182,15 @@ void x11cleanup(struct ChanSess *chansess) { } } +static int x11_inithandler(struct Channel *channel) { + channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE; + return 0; +} + static const struct ChanType chan_x11 = { 0, /* sepfds */ "x11", - NULL, /* inithandler */ + x11_inithandler, /* inithandler */ NULL, /* checkclose */ NULL, /* reqhandler */ NULL /* closehandler */ diff --git a/release/src-rt-6.x.4708/router/dropbear/sysoptions.h b/release/src-rt-6.x.4708/router/dropbear/sysoptions.h index c569ab4963..bec72461d8 100644 --- a/release/src-rt-6.x.4708/router/dropbear/sysoptions.h +++ b/release/src-rt-6.x.4708/router/dropbear/sysoptions.h @@ -4,7 +4,7 @@ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "2013.62" +#define DROPBEAR_VERSION "2015.67" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION @@ -153,8 +153,7 @@ #define MAX_CHANNELS 100 /* simple mem restriction, includes each tcp/x11 connection, so can't be _too_ small */ -#define MAX_STRING_LEN 1400 /* ~= MAX_PROPOSED_ALGO * MAX_NAME_LEN, also - is the max length for a password etc */ +#define MAX_STRING_LEN 2400 /* Sun SSH needs this long for algos */ /* For a 4096 bit DSS key, empirically determined */ #define MAX_PUBKEY_SIZE 1700 @@ -176,6 +175,7 @@ accept for keyb-interactive auth */ + #if defined(DROPBEAR_AES256) || defined(DROPBEAR_AES128) #define DROPBEAR_AES #endif @@ -250,4 +250,13 @@ #define USE_VFORK #endif /* don't HAVE_FORK */ +#if MAX_UNAUTH_CLIENTS > MAX_CHANNELS +#define DROPBEAR_LISTEN_BACKLOG MAX_UNAUTH_CLIENTS +#else +#define DROPBEAR_LISTEN_BACKLOG MAX_CHANNELS +#endif + +/* Use this string since some implementations might special-case it */ +#define DROPBEAR_KEEPALIVE_STRING "keepalive@openssh.com" + /* no include guard for this file */ diff --git a/release/src-rt-6.x.4708/router/dropbear/tcp-accept.c b/release/src-rt-6.x.4708/router/dropbear/tcp-accept.c index bb7c5e36a1..35be32d870 100644 --- a/release/src-rt-6.x.4708/router/dropbear/tcp-accept.c +++ b/release/src-rt-6.x.4708/router/dropbear/tcp-accept.c @@ -30,6 +30,7 @@ #include "buffer.h" #include "packet.h" #include "listener.h" +#include "listener.h" #include "runopts.h" #ifdef DROPBEAR_TCP_ACCEPT @@ -44,6 +45,13 @@ static void cleanup_tcp(struct Listener *listener) { m_free(tcpinfo); } +int tcp_prio_inithandler(struct Channel* channel) +{ + TRACE(("tcp_prio_inithandler channel %d", channel->index)) + channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE; + return 0; +} + static void tcp_acceptor(struct Listener *listener, int sock) { int fd; diff --git a/release/src-rt-6.x.4708/router/dropbear/tcpfwd.h b/release/src-rt-6.x.4708/router/dropbear/tcpfwd.h index 7f0cd93f8c..654664cc62 100644 --- a/release/src-rt-6.x.4708/router/dropbear/tcpfwd.h +++ b/release/src-rt-6.x.4708/router/dropbear/tcpfwd.h @@ -70,5 +70,9 @@ void cli_recv_msg_request_failure(); /* Common */ int listen_tcpfwd(struct TCPListener* tcpinfo); +int tcp_prio_inithandler(struct Channel* chan); + +/* A random identifier */ +#define CHANNEL_ID_TCPFORWARDED 0x43612c67 #endif -- 2.11.4.GIT