Compare commits

..

88 Commits

Author SHA1 Message Date
Matt Johnston
cce29ba38c 2014.64 2014-08-08 21:40:42 +08:00
Mike Frysinger
ed2e276b3a use xauth in /usr/bin
Since the x.org rework, X has been installed into standard paths and not
its own random prefixes.  I think it's time we update the default paths
accordingly.
2014-08-01 06:14:19 -04:00
Matt Johnston
12a020aa62 Don't warn about ENOTSOCK when setting priority 2014-08-06 22:16:38 +08:00
Matt Johnston
b969101b33 Be a bit safer in case pw_name doesn't exist 2014-08-06 22:10:57 +08:00
Matt Johnston
86a742f635 merge 2014-08-06 22:08:16 +08:00
Matt Johnston
9468f7f6d6 Merge pull request #2 from iquaba/patch-1
Try without identifying current user
2014-08-06 22:04:49 +08:00
Matt Johnston
628a3f5cca Test for EAGAIN too 2014-08-06 21:55:43 +08:00
iquaba
e815e97440 Try without identifying current user
Small change that warns the user if the current user cannot be identified rather than aborting.  This came in handy when I put dropbear on a dlink that did not have a true user environment.  Falling back on the "-l" option and user@ options works just fine as a client.  The only implication I found is that the -J option will fail ungracefully without a known own_user.
2014-08-06 08:48:43 -05:00
Matt Johnston
0e7409c7ff Make sure the check_close() handler runs when a server child process exits 2014-07-28 23:23:49 +08:00
Matt Johnston
393ca2a290 Fix some format string warnings 2014-07-28 22:59:16 +08:00
Matt Johnston
ad1d48e07b Fix clock_gettime handling 2014-07-28 22:48:48 +08:00
Matt Johnston
ac98aae160 Added signature for changeset 96584b934d04 2014-07-27 23:11:52 +08:00
Matt Johnston
c1267398a2 Added tag DROPBEAR_2014.64 for changeset 0d2d39957c02 2014-07-27 23:11:47 +08:00
Matt Johnston
8c3a2bb63e Archive should be bz2 nor gz 2014-07-27 22:56:35 +08:00
Matt Johnston
923fc9087c - Don't use multichar constants since recent gcc complains
- Add release script
- Simplify print_version
2014-07-27 22:55:29 +08:00
Matt Johnston
83511fecc0 Version 2014.64 2014-07-27 22:25:18 +08:00
Matt Johnston
ed0552f214 Add '-V' for version
-h should exit with success
Update manpages
2014-07-27 22:06:26 +08:00
Matt Johnston
5cf83a7212 Avoid use-after-free when channel inithandler fails. Thanks to Coverity 2014-07-26 10:18:55 +08:00
Matt Johnston
7808eff0a9 changes for 2014.64 2014-07-25 22:22:39 +08:00
Matt Johnston
da57dd13c5 Set tcp priority as follows:
if (connecting || ptys || x11) tos = LOWDELAY;
else if (tcp_forwards) tos = 0;
else tos = BULK;

TCP forwards could be either lowdelay or bulk, hence the default priority.
2014-07-16 22:53:32 +08:00
Matt Johnston
f1826ea389 Fix auth timeout regression 2014-07-09 22:02:22 +08:00
Matt Johnston
c884e5000e Make -K keepalive behave like OpenSSH's ServerAliveInterval 2014-07-09 00:15:20 +08:00
Matt Johnston
1ccac01cee Make sure client exit messages don't get lost 2014-07-09 00:13:17 +08:00
Matt Johnston
50a5d3756f Send a failure response if a client receives a global request 2014-07-08 21:59:36 +08:00
Matt Johnston
ca86726f9f Improve handling lots of concurrent forwarded connections. Increase
connection backlog, avoid check_close() for channels that haven't had IO
2014-06-25 23:42:39 +08:00
Matt Johnston
6b5317e7cc Fix compiling with ECDSA and DSS disabled 2014-06-25 23:37:44 +08:00
Matt Johnston
2a1d28ea3a Be more careful in case a platform doesn't define UIO_MAXIOV nor IOV_MAX 2014-05-20 21:21:02 +08:00
Ronny Meeus
0e0ff51582 Limit size of the iovect passed to writev in packet.c 2014-05-20 21:18:48 +08:00
Ronny Meeus
cd700aaf6e Print errno information in write_packet 2014-05-20 20:56:59 +08:00
Matt Johnston
188ec1e258 Fix pubkey auth if the first key presented fails (infinite loop of
auth requests). Regresssion in ff597bf2cfb0
2014-04-23 16:22:50 +08:00
Matt Johnston
d01fb265d6 Fix monotonic_now() on OS X 2014-03-21 22:16:42 +08:00
Matt Johnston
db688e3ec1 Experiment of always writing data if available. Might waste a writev() with
EAGAIN but always saves a select() - needs testing with bandwidth-limited
and CPU-limited situations.
2014-03-15 11:37:02 +08:00
Matt Johnston
e767bbb41f Add new monotonic_now() wrapper so that timeouts are unaffected by
system clock changes
2014-03-13 23:50:09 +08:00
Matt Johnston
2b599df57a Fix typo 2014-03-13 23:08:47 +08:00
Yousong Zhou
5baa10a6b6 Use AUTH_TIMEOUT only before authdone != 1.
While at it, fix a few indentations and typo.
2014-03-13 16:28:16 +08:00
Matt Johnston
3e1a389629 Don't need to mkdir 2014-03-08 21:00:57 +08:00
Matt Johnston
37e6207396 Fix env vars for travis again 2014-03-07 21:46:51 +08:00
Matt Johnston
927a2dc849 Fix "make install" dependency so that it works without prior "make" 2014-03-07 21:30:20 +08:00
Matt Johnston
ce9f9594da Add some tests for multi 2014-03-07 21:14:12 +08:00
Matt Johnston
f0bf37b6cb Install system libtom libs, run dropbearkey when it's done 2014-03-07 21:03:43 +08:00
Matt Johnston
2f0b35a105 The arguments are for configure, not make! 2014-03-07 20:52:57 +08:00
Matt Johnston
7a9ed81f5f Add Travis CI autobuilder config 2014-03-07 20:44:32 +08:00
Matt Johnston
12e7d570a2 Make some debug info conditional 2014-02-24 20:53:32 +08:00
Matt Johnston
bb7934bf04 A few fixes for cases where compression increases payload sizes, and
be more precise about maximum channel sizes
2014-02-22 18:02:09 +08:00
Matt Johnston
fb3c718963 Fix typo in Catalin's name 2014-02-19 22:18:11 +08:00
Matt Johnston
231fc607f9 Added signature for changeset 277429102f13 2014-02-19 22:14:58 +08:00
Matt Johnston
9594a3aa45 Added tag DROPBEAR_2014.63 for changeset 2351b2da8e0d 2014-02-19 22:14:52 +08:00
Matt Johnston
162fcab347 2014.63 2014-02-19 22:04:35 +08:00
Catalin Patulea
0c8bdfd7cd README: fix ecdsa key generation command 2014-02-09 03:56:50 -05:00
Matt Johnston
5e4dc71907 CHANGES for 2014.63 2014-02-19 22:01:01 +08:00
Matt Johnston
3e4433f715 - Fix dbclient with port 0 for server-allocated
- Fix port forwards with a bind address of 127.0.0.1 vs "localhost" etc
2014-02-18 21:33:56 +08:00
Matt Johnston
29062e629f Fix building with system libtomcrypt/libtommath 2014-02-18 21:03:27 +08:00
Steve Dover
47f7272ba1 Add linux/types.h to includes to avoid missing ___u64 etc 2014-02-17 22:05:59 +08:00
Matt Johnston
bf6f3f613d Read (and enqueue) packets from interactive input even when
we're waiting for a key exchange.

This should hopefully fix the situation where "~." doesn't work to terminate a
client session when a laptop wakes up. The client will be stuck waiting for a
key exchange on a dead connection, so won't have read the escape character
2014-02-17 21:41:06 +08:00
Matt Johnston
0c9a643216 Change port separator to ^ since % is used in ipv6 addresses 2014-02-15 21:42:35 +08:00
Matt Johnston
fa2d843403 Disable immediate auth for delayed-zlib mode 2014-02-15 21:23:41 +08:00
Matt Johnston
1dc5312f00 - Save errno in signal handlers
- Use _exit() in segv handler
2014-02-15 21:13:57 +08:00
Matt Johnston
73444f2957 generate RSA keys of exact length 2014-02-14 23:18:45 +08:00
Matt Johnston
a18a6b8db8 cleanup before clearing keys 2014-02-12 22:15:02 +08:00
Nicolas Boos
bf56591fb8 Fix linking -lcrypt for systems without libcrypt in /usr/lib 2014-02-07 07:57:45 +08:00
Nicolas Boos
5ea428a30d Avoid linking dropbearconvert and dropbearkey to libz or libutil 2014-02-07 07:53:32 +08:00
Matt Johnston
af524c4d65 Fix check for EINTR 2014-01-28 22:44:24 +08:00
Matt Johnston
2bc9f35052 Back out accidentally committed files 2014-01-23 22:29:04 +08:00
Matt Johnston
55a0c5068f requirenext doesn't need two values 2014-01-23 22:25:52 +08:00
Matt Johnston
8128b15e41 Fix failing rekeying when we receive a still-in-flight packet 2014-01-23 21:56:35 +08:00
Matt Johnston
8081b0e033 Forgot to save the change 2014-01-17 21:42:32 +08:00
Matt Johnston
61cecbb337 DROPBEAR_CLI_AUTH_IMMEDIATE fixed, now enabled by default 2014-01-17 21:39:27 +08:00
Mike Frysinger
aee1309c91 Fix so that "make install" for multi target won't fail on scp which doesn't
have a manpage
2013-12-11 21:50:33 +08:00
Mike Frysinger
710c1df413 Turn dropbearmulti into a real target so we don't constantly re-link it 2013-12-11 21:48:02 +08:00
Matt Johnston
0f165a95a8 Added signature for changeset 3d1d7d151c0c 2013-12-03 22:00:38 +08:00
Matt Johnston
581f04c80b Added tag DROPBEAR_2013.62 for changeset 3d1d7d151c0c 2013-12-03 22:00:29 +08:00
Matt Johnston
511be4acc6 2013.62 2013-12-03 21:39:06 +08:00
Matt Johnston
d77b29f1d7 Update to 2013-10-01 2013-12-03 21:36:12 +08:00
Matt Johnston
092a4d9a7e Fix disabling DSS key 2013-12-03 21:26:59 +08:00
Matt Johnston
b3cab3ce31 Log when generating a hostkey 2013-12-03 21:13:58 +08:00
Matt Johnston
e5279b0e2e Update README 2013-12-03 21:03:23 +08:00
Matt Johnston
9ff337aa3b Exit if we don't have keys and -R wasn't specified 2013-12-03 20:59:03 +08:00
Catalin Patulea
441facc6e0 Fix TRACEs of cli_send_netcat_request 2013-12-03 00:06:35 +08:00
Matt Johnston
998d6cdfc4 - Sockets are set to lowdelay priority initially to improve conneciton setup
time
- Set non-pty connections to bulk for client and server
2013-12-03 00:04:48 +08:00
Catalin Patulea
ddc10b2d0c Set IPTOS_LOWDELAY on PTY sessions only 2013-12-02 22:55:43 +08:00
Matt Johnston
4f6f651b7d Only define LTM_DESC if it isn't already 2013-12-02 22:15:17 +08:00
Matt Johnston
68c7667a20 merge 2013-11-27 21:32:45 +08:00
Matt Johnston
0b62d71e70 - Increase buffer size, fixes converting 521bit ECC key
- Fix assertion that key size is exactly curve size
2013-11-27 21:30:05 +08:00
Matt Johnston
be5780ef90 Fix library order of libtom* 2013-11-25 23:39:15 +08:00
Matt Johnston
e5c52796c3 Try and fix utmp handling 2013-11-25 23:30:01 +08:00
Matt Johnston
c5e36f8e3c Fix some warnings 2013-11-25 23:08:33 +08:00
Matt Johnston
5a85c4b91b Added signature for changeset 9ec083a21adf 2013-11-14 22:39:27 +08:00
Matt Johnston
0201072c1b Added tag DROPBEAR_2013.61test for changeset e894dbc015ba 2013-11-14 22:39:16 +08:00
51 changed files with 1007 additions and 302 deletions

View File

@@ -7,3 +7,7 @@ f168962bab857ca030829e4cd73d9b32c868c874 0 iEYEABECAAYFAlFwDNwACgkQjPn4sExkf7wJ6
deb211f75ca194e2fcf0d2e5f71c60474e42ec95 0 iEYEABECAAYFAlJO01cACgkQjPn4sExkf7yDqACaA/P+Yl/K2Cv3OC5G0b7ck2Kb75EAoIeW7qpCyclzJLWwk95koED+4lxD
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

View File

@@ -40,3 +40,7 @@ d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
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

20
.travis.yml Normal file
View File

@@ -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

104
CHANGES
View File

@@ -1,3 +1,104 @@
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
have a PTY (eg scp, rsync). Thanks to Catalin Patulea for the patch.
- Log when a hostkey is generated with -R, fix some bugs in handling server
hostkey commandline options
- Fix crash in Dropbearconvert and 521 bit key, reported by NiLuJe
- Update config.guess and config.sub again
2013.61test - Thursday 14 November 2013
- ECC (elliptic curve) support. Supports ECDSA hostkeys (requires new keys to
@@ -15,6 +116,9 @@
- Compile fixes for old vendor compilers like Tru64 from Daniel Richard G.
- Make authorized_keys handling more robust, don't exit encountering
malformed lines. Thanks to Lorin Hochstein and Mark Stillwell
2013.60 - Wednesday 16 October 2013
- Fix "make install" so that it doesn't always install to /bin and /sbin

View File

@@ -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)
@@ -136,7 +138,7 @@ insmulti%: dropbearmulti
-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
@@ -145,7 +147,7 @@ inst_dropbear: dropbear
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 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

10
README
View File

@@ -42,8 +42,7 @@ If you have an OpenSSH-style private key ~/.ssh/id_rsa, you need to do:
dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_rsa.db
dbclient -i ~/.ssh/id_rsa.db <hostname>
Currently encrypted keys aren't supported, neither is agent forwarding. At some
stage both hopefully will be.
Dropbear does not support encrypted hostkeys though can connect to ssh-agent.
============================================================================
@@ -52,13 +51,18 @@ dropbearkey's '-y' option.
============================================================================
To run the server, you need to generate server keys, this is one-off:
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_ecdsa_host_key
or alternatively convert OpenSSH keys to Dropbear:
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
You can also get Dropbear to create keys when the first connection is made -
this is preferable to generating keys when the system boots. Make sure
/etc/dropbear/ exists and then pass '-R' to the dropbear server.
============================================================================
If the server is run as non-root, you most likely won't be able to allocate a

View File

@@ -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[]);
@@ -129,4 +129,7 @@ void recv_msg_channel_open_confirmation();
void recv_msg_channel_open_failure();
#endif
void send_msg_request_success();
void send_msg_request_failure();
#endif /* _CHANNEL_H_ */

View File

@@ -201,7 +201,7 @@ static void agent_get_key_list(m_list * ret_list)
num = buf_getint(inbuf);
for (i = 0; i < num; i++) {
sign_key * pubkey = NULL;
int key_type = DROPBEAR_SIGNKEY_ANY;
enum signkey_type key_type = DROPBEAR_SIGNKEY_ANY;
buffer * key_buf;
/* each public key is encoded as a string */

View File

@@ -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 */

View File

@@ -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();
@@ -357,6 +357,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,6 +374,9 @@ static int cli_initchansess(struct Channel *channel) {
if (cli_opts.wantpty) {
send_chansess_pty_req(channel);
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
} else {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
send_chansess_shell_req(channel);
@@ -387,7 +395,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
@@ -398,6 +406,7 @@ void cli_send_netcat_request() {
const unsigned char* source_host = "127.0.0.1";
const int source_port = 22;
TRACE(("enter cli_send_netcat_request"))
cli_opts.wantpty = 0;
if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat)
@@ -414,7 +423,7 @@ void cli_send_netcat_request() {
buf_putint(ses.writepayload, source_port);
encrypt_packet();
TRACE(("leave cli_send_chansess_request"))
TRACE(("leave cli_send_netcat_request"))
}
#endif

View File

@@ -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"))
}

View File

@@ -104,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);
}
@@ -118,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) {

View File

@@ -90,6 +90,7 @@ static void printhelp() {
"-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
"-m <MAC list> 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
@@ -163,6 +164,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();
@@ -322,6 +325,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;
@@ -617,7 +624,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 +683,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

View File

@@ -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,6 +69,7 @@ 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},
#ifdef ENABLE_CLI_REMOTETCPFWD
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
@@ -228,6 +230,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 +368,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();
}

View File

@@ -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;

View File

@@ -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"))
}
@@ -864,6 +895,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 +912,8 @@ failure:
cleanup:
m_free(type);
update_channel_prio();
TRACE(("leave recv_msg_channel_open"))
}
@@ -992,7 +1029,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 +1060,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 +1095,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 +1122,15 @@ 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();
}

View File

@@ -270,7 +270,7 @@ static void kexinitialise() {
ses.kexstate.our_first_follows_matches = 0;
ses.kexstate.lastkextime = time(NULL);
ses.kexstate.lastkextime = monotonic_now();
}
@@ -483,9 +483,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 +525,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 +545,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,6 +789,13 @@ 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);
ses.kexhashbuf = NULL;

View File

@@ -106,3 +106,8 @@ parse_ciphers_macs()
}
#endif
void print_version() {
fprintf(stderr, "Dropbear v%s\n", DROPBEAR_VERSION);
}

View File

@@ -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,21 @@ static int ident_readln(int fd, char* buf, int count) {
return pos+1;
}
void send_msg_ignore() {
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;
/* Try to force a response from the other end. Some peers will
reply with SSH_MSG_REQUEST_FAILURE, some will reply with SSH_MSG_UNIMPLEMENTED */
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
/* A short string */
buf_putstring(ses.writepayload, "k@dropbear.nl", 0);
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 +416,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 +430,27 @@ 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) {
/* 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 +461,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 +516,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;
}
}

17
config.sub vendored
View File

@@ -2,7 +2,7 @@
# Configuration validation subroutine script.
# Copyright 1992-2013 Free Software Foundation, Inc.
timestamp='2013-04-24'
timestamp='2013-10-01'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -257,7 +257,7 @@ case $basic_machine in
| avr | avr32 \
| be32 | be64 \
| bfin \
| c4x | clipper \
| c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx \
| epiphany \
| fido | fr30 | frv \
@@ -265,6 +265,7 @@ case $basic_machine in
| hexagon \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
| k1om \
| le32 | le64 \
| lm32 \
| m32c | m32r | m32rle | m68000 | m68k | m88k \
@@ -324,7 +325,7 @@ case $basic_machine in
c6x)
basic_machine=tic6x-unknown
;;
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
basic_machine=$basic_machine-unknown
os=-none
;;
@@ -372,7 +373,7 @@ case $basic_machine in
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| clipper-* | craynv-* | cydra-* \
| c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
@@ -381,6 +382,7 @@ case $basic_machine in
| hexagon-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
| k1om-* \
| le32-* | le64-* \
| lm32-* \
| m32c-* | m32r-* | m32rle-* \
@@ -794,7 +796,7 @@ case $basic_machine in
os=-mingw64
;;
mingw32)
basic_machine=i386-pc
basic_machine=i686-pc
os=-mingw32
;;
mingw32ce)
@@ -830,7 +832,7 @@ case $basic_machine in
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
msys)
basic_machine=i386-pc
basic_machine=i686-pc
os=-msys
;;
mvs)
@@ -1546,6 +1548,9 @@ case $basic_machine in
c4x-* | tic4x-*)
os=-coff
;;
c8051-*)
os=-elf
;;
hexagon-*)
os=-elf
;;

View File

@@ -21,7 +21,7 @@ AC_SUBST(LD)
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
CFLAGS="-Os -W -Wall"
CFLAGS="-Os -W -Wall -Wno-pointer-sign"
fi
# large file support is useful for scp
@@ -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(tomcrypt, register_cipher, ,
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tommath, mp_exptmod, ,
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(tomcrypt, register_cipher, , BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tommath, mp_exptmod, , 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
@@ -540,7 +545,9 @@ dnl wtmp detection
AC_MSG_CHECKING([if your system defines WTMP_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
@@ -598,9 +605,11 @@ dnl wtmpx detection
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
# include <utmpx.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>

View File

@@ -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
@@ -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

130
dbutil.c
View File

@@ -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 <sys/syscall.h>
#endif /* __linux */
#ifdef HAVE_MACH_MACH_TIME_H
#include <mach/mach_time.h>
#include <mach/mach.h>
#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,35 +183,58 @@ 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);
}
#endif /* DEBUG_TRACE */
static void set_sock_priority(int sock) {
void set_sock_nodelay(int sock) {
int val;
/* disable nagle */
val = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
}
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
val = IPTOS_LOWDELAY;
if (prio == DROPBEAR_PRIO_LOWDELAY) {
iptos_val = IPTOS_LOWDELAY;
} else if (prio == DROPBEAR_PRIO_BULK) {
iptos_val = IPTOS_THROUGHPUT;
}
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
#endif
#ifdef SO_PRIORITY
/* linux specific, sets QoS class.
* 6 looks to be optimal for interactive traffic (see tc-prio(8) ). */
val = 6;
setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &val, sizeof(val));
if (prio == DROPBEAR_PRIO_LOWDELAY) {
so_prio_val = TC_PRIO_INTERACTIVE;
} else if (prio == DROPBEAR_PRIO_BULK) {
so_prio_val = TC_PRIO_BULK;
}
/* 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 && errno != ENOTSOCK)
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
strerror(errno));
#endif
}
@@ -290,7 +326,7 @@ int dropbear_listen(const char* address, const char* port,
}
#endif
set_sock_priority(sock);
set_sock_nodelay(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
err = errno;
@@ -299,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"))
@@ -429,7 +465,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
TRACE(("Error connecting: %s", strerror(err)))
} else {
/* Success */
set_sock_priority(sock);
set_sock_nodelay(sock);
}
freeaddrinfo(res0);
@@ -792,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);
@@ -881,14 +921,17 @@ void disallow_core() {
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE, with the result in *val */
int m_str_to_uint(const char* str, unsigned int *val) {
unsigned long l;
errno = 0;
*val = strtoul(str, NULL, 10);
l = strtoul(str, NULL, 10);
/* The c99 spec doesn't actually seem to define EINVAL, but most platforms
* I've looked at mention it in their manpage */
if ((*val == 0 && errno == EINVAL)
|| (*val == ULONG_MAX && errno == ERANGE)) {
if ((l == 0 && errno == EINVAL)
|| (l == ULONG_MAX && errno == ERANGE)
|| (l > UINT_MAX)) {
return DROPBEAR_FAILURE;
} else {
*val = l;
return DROPBEAR_SUCCESS;
}
}
@@ -905,3 +948,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);
}

View File

@@ -61,11 +61,19 @@ void printmpint(const char *label, mp_int *mp);
extern int debug_trace;
#endif
enum dropbear_prio {
DROPBEAR_PRIO_DEFAULT = 10,
DROPBEAR_PRIO_LOWDELAY = 11,
DROPBEAR_PRIO_BULK = 12,
};
char * stripcontrol(const char * text);
void get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup);
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port, int host_lookup);
void set_sock_nodelay(int sock);
void set_sock_priority(int sock, enum dropbear_prio prio);
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
@@ -98,4 +106,9 @@ 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();
#endif /* _DBUTIL_H_ */

22
debian/changelog vendored
View File

@@ -1,8 +1,26 @@
dropbear (2013.61test-0.1) unstable; urgency=low
dropbear (2014.65-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 14 Nov 2013 22:54:00 +0800
-- Matt Johnston <matt@ucc.asn.au> Fri, 8 Aug 2014 22:54:00 +0800
dropbear (2014.64-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Sun, 27 Jul 2014 22:54:00 +0800
dropbear (2014.63-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Feb 2014 22:54:00 +0800
dropbear (2013.62) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Tue, 7 Dec 2013 22:54:00 +0800
dropbear (2013.60-0.1) unstable; urgency=low

View File

@@ -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
@@ -29,7 +28,7 @@ This file is generated with
or automatically with the '-R' option. See "Host Key Files" below.
.TP
.B \-R
Generate hostkeys automatically
Generate hostkeys automatically. See "Host Key Files" below.
.TP
.B \-F
Don't fork into background.
@@ -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

4
ecc.c
View File

@@ -75,8 +75,8 @@ struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp) {
ecc_key * new_ecc_key(void) {
ecc_key *key = m_malloc(sizeof(*key));
m_mp_alloc_init_multi(&key->pubkey.x, &key->pubkey.y,
&key->pubkey.z, &key->k, NULL);
m_mp_alloc_init_multi((mp_int**)&key->pubkey.x, (mp_int**)&key->pubkey.y,
(mp_int**)&key->pubkey.z, (mp_int**)&key->k, NULL);
return key;
}

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -156,6 +156,11 @@ typedef unsigned int u_int32_t;
typedef u_int32_t uint32_t;
#endif /* HAVE_UINT32_T */
#ifdef SO_PRIORITY
#include <linux/types.h>
#include <linux/pkt_sched.h>
#endif
#include "fake-rfc2553.h"
#ifndef LOG_AUTHPRIV

View File

@@ -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,
@@ -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.
@@ -1033,6 +1045,7 @@ static int openssh_write(const char *filename, sign_key *key,
int curve_oid_len = 0;
const void* curve_oid = NULL;
unsigned long pubkey_size = 2*curve_size+1;
unsigned int k_size;
/* version. less than 10 bytes */
buf_incrwritepos(seq_buf,
@@ -1040,11 +1053,12 @@ static int openssh_write(const char *filename, sign_key *key,
buf_putbyte(seq_buf, 1);
/* privateKey */
dropbear_assert(mp_unsigned_bin_size((*eck)->k) == curve_size);
k_size = mp_unsigned_bin_size((*eck)->k);
dropbear_assert(k_size <= curve_size);
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, curve_size, 0));
mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, curve_size));
buf_incrwritepos(seq_buf, curve_size);
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, k_size, 0));
mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, k_size));
buf_incrwritepos(seq_buf, k_size);
/* SECGCurveNames */
switch (key->type)
@@ -1085,7 +1099,7 @@ static int openssh_write(const char *filename, sign_key *key,
buf_setpos(seq_buf, 0);
outblob = (unsigned char*)m_malloc(200);
outblob = (unsigned char*)m_malloc(1000);
pos = 0;
pos += ber_write_id_len(outblob+pos, 16, seq_buf->len, ASN1_CONSTRUCTED);

View File

@@ -73,16 +73,16 @@
#else
/* Simply select your favourite login types. */
/* Can't do if-else because some systems use several... <sigh> */
# if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
# if defined(HAVE_UTMPX_H) && defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
# define USE_UTMPX
# endif
# if defined(UTMP_FILE) && !defined(DISABLE_UTMP)
# if defined(HAVE_UTMP_H) && defined(UTMP_FILE) && !defined(DISABLE_UTMP)
# define USE_UTMP
# endif
# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
# if defined(HAVE_WTMPX_H) && defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
# define USE_WTMPX
# endif
# if defined(WTMP_FILE) && !defined(DISABLE_WTMP)
# if defined(HAVE_WTMP_H) && defined(WTMP_FILE) && !defined(DISABLE_WTMP)
# define USE_WTMP
# endif

View File

@@ -222,12 +222,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
@@ -265,7 +264,7 @@ much traffic. */
/* The command to invoke for xauth when using X11 forwarding.
* "-q" for quiet */
#ifndef XAUTH_COMMAND
#define XAUTH_COMMAND "/usr/bin/X11/xauth -q"
#define XAUTH_COMMAND "/usr/bin/xauth -q"
#endif
/* if you want to enable running an sftp server (such as the one included with
@@ -309,6 +308,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

View File

@@ -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;
}
@@ -333,7 +341,7 @@ 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)) {
if ((len > RECV_MAX_PAYLOAD_LEN+ZLIB_COMPRESS_EXPANSION) || (len < 1)) {
dropbear_exit("Bad packet size %d", len);
}
@@ -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"))

View File

@@ -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 ).

40
release.sh Executable file
View File

@@ -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 "CHANGES 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"

4
rsa.c
View File

@@ -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

View File

@@ -37,8 +37,8 @@ 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
@@ -164,4 +164,6 @@ void cli_getopts(int argc, char ** argv);
void parse_ciphers_macs();
#endif
void print_version(void);
#endif /* _RUNOPTS_H_ */

View File

@@ -48,6 +48,8 @@ void session_cleanup();
void send_session_identification();
void send_msg_ignore();
void update_channel_prio();
const char* get_user_shell();
void fill_passwd(const char* username);
@@ -104,10 +106,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 +133,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 +144,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 +187,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 +221,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 +241,7 @@ typedef enum {
typedef enum {
STATE_NOTHING,
USERAUTH_WAIT,
USERAUTH_REQ_SENT,
USERAUTH_FAIL_RCVD,
USERAUTH_SUCCESS_RCVD,
@@ -267,6 +276,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 */

View File

@@ -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;
@@ -508,14 +510,13 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
* signature blob */
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
unsigned int bloblen;
unsigned char * type_name = NULL;
unsigned int type_name_len = 0;
enum signkey_type type;
TRACE(("enter buf_verify"))
bloblen = buf_getint(buf);
buf_getint(buf); /* blob length */
type_name = buf_getstring(buf, &type_name_len);
type = signkey_type_from_name(type_name, type_name_len);
m_free(type_name);

View File

@@ -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;

View File

@@ -87,6 +87,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 +145,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 */
@@ -249,6 +256,8 @@ static int newchansess(struct Channel *channel) {
chansess->agentdir = NULL;
#endif
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
return 0;
}
@@ -665,6 +674,10 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
if (chansess->term == NULL) {
/* no pty */
ret = noptycommand(channel, chansess);
if (ret == DROPBEAR_SUCCESS) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
update_channel_prio();
}
} else {
/* want pty */
ret = ptycommand(channel, chansess);

View File

@@ -80,8 +80,7 @@ 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"))
}
@@ -145,6 +144,20 @@ static void svr_ensure_hostkey() {
ret = readhostkey(fn, svr_opts.hostkey, &type);
if (ret == DROPBEAR_SUCCESS) {
char *fp = NULL;
unsigned int len;
buffer *key_buf = buf_new(MAX_PUBKEY_SIZE);
buf_put_pub_key(key_buf, svr_opts.hostkey, type);
buf_setpos(key_buf, 4);
len = key_buf->len - key_buf->pos;
fp = sign_key_fingerprint(buf_getptr(key_buf, len), len);
dropbear_log(LOG_INFO, "Generated hostkey %s, fingerprint is %s",
fn, fp);
m_free(fp);
buf_free(key_buf);
}
out:
if (fn_temp) {
unlink(fn_temp);

View File

@@ -137,6 +137,11 @@ void main_noinetd() {
dropbear_exit("No listening ports available.");
}
for (i = 0; i < listensockcount; i++) {
set_sock_priority(listensocks[i], DROPBEAR_PRIO_LOWDELAY);
FD_SET(listensocks[i], &fds);
}
/* fork */
if (svr_opts.forkbg) {
int closefds = 0;
@@ -332,6 +337,8 @@ 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;
@@ -339,13 +346,14 @@ static void sigchld_handler(int UNUSED(unused)) {
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 */

View File

@@ -92,6 +92,7 @@ static void printhelp(const char * progname) {
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d, in seconds)\n"
"-I <idle_timeout> (0 is never, default %d, in seconds)\n"
"-V Version\n"
#ifdef DEBUG_TRACE
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
@@ -256,7 +257,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 +267,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]);
@@ -452,6 +457,7 @@ static void addhostkey(const char *keyfile) {
void load_all_hostkeys() {
int i;
int disable_unset_keys = 1;
int any_keys = 0;
svr_opts.hostkey = new_sign_key();
@@ -474,8 +480,7 @@ void load_all_hostkeys() {
#endif
#ifdef DROPBEAR_DELAY_HOSTKEY
if (svr_opts.delay_hostkey)
{
if (svr_opts.delay_hostkey) {
disable_unset_keys = 0;
}
#endif
@@ -483,12 +488,16 @@ void load_all_hostkeys() {
#ifdef DROPBEAR_RSA
if (disable_unset_keys && !svr_opts.hostkey->rsakey) {
disablekey(DROPBEAR_SIGNKEY_RSA);
} else {
any_keys = 1;
}
#endif
#ifdef DROPBEAR_DSS
if (disable_unset_keys && !svr_opts.hostkey->dsskey) {
disablekey(DROPBEAR_SIGNKEY_RSA);
disablekey(DROPBEAR_SIGNKEY_DSS);
} else {
any_keys = 1;
}
#endif
@@ -498,6 +507,8 @@ void load_all_hostkeys() {
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 256)
&& !svr_opts.hostkey->ecckey256) {
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
} else {
any_keys = 1;
}
#endif
@@ -505,6 +516,8 @@ void load_all_hostkeys() {
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 384)
&& !svr_opts.hostkey->ecckey384) {
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
} else {
any_keys = 1;
}
#endif
@@ -512,8 +525,13 @@ void load_all_hostkeys() {
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 521)
&& !svr_opts.hostkey->ecckey521) {
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
} else {
any_keys = 1;
}
#endif
#endif /* DROPBEAR_ECDSA */
if (!any_keys) {
dropbear_exit("No hostkeys available");
}
}

View File

@@ -80,12 +80,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 +105,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 +136,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 */
@@ -142,7 +150,7 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
if (!sessinitdone) {
/* before session init */
snprintf(fmtbuf, sizeof(fmtbuf),
"Premature exit: %s", format);
"Early exit: %s", format);
} else if (ses.authstate.authdone) {
/* user has authenticated */
snprintf(fmtbuf, sizeof(fmtbuf),

View File

@@ -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;

View File

@@ -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 */

View File

@@ -4,7 +4,7 @@
*******************************************************************/
#ifndef DROPBEAR_VERSION
#define DROPBEAR_VERSION "2013.61test"
#define DROPBEAR_VERSION "2014.65"
#endif
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
@@ -92,8 +92,10 @@
#if defined(DROPBEAR_ECDH) || defined (DROPBEAR_ECDSA)
#define DROPBEAR_ECC
/* Debian doesn't define this in system headers */
#ifndef LTM_DESC
#define LTM_DESC
#endif
#endif
#ifdef DROPBEAR_ECC
#define DROPBEAR_ECC_256
@@ -174,6 +176,7 @@
accept for keyb-interactive
auth */
#if defined(DROPBEAR_AES256) || defined(DROPBEAR_AES128)
#define DROPBEAR_AES
#endif
@@ -248,4 +251,10 @@
#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
/* no include guard for this file */

View File

@@ -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;

View File

@@ -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