1
0
mirror of http://galexander.org/git/simplesshd.git synced 2025-03-03 00:06:04 +00:00

stock dropbear-2014.66 source tree

This commit is contained in:
Greg Alexander 2014-12-10 16:56:49 -05:00
parent 3bbf3ce0dc
commit b221c41798
728 changed files with 154296 additions and 0 deletions

View File

@ -0,0 +1,5 @@
repo: d7da3b1e15401eb234ec866d5eac992fc4cd5878
node: 735511a4c761141416ad0e6728989d2dafa55bc2
branch: default
latesttag: DROPBEAR_2014.65
latesttagdistance: 12

14
dropbear/.hgsigs Normal file
View File

@ -0,0 +1,14 @@
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 0 iD8DBQBOuADmjPn4sExkf7wRAv/fAJ9FJFvjDoF+wd1ipDx1wkzdeBQNqgCgykUrSbXv76FBbxKntVbk9oS3GjI=
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 0 iD8DBQBOuSlQjPn4sExkf7wRAvkbAKCgE1e8xEMQ16CGeoywhIQ0QR4eNgCfZdYYlzjb/+521Uvh5/7FRYEmrho=
85f835f2fe0ac2c503c50a414de127222fb0a57c 0 iD8DBQBPRkMUjPn4sExkf7wRAvM4AJ9mw2OAkyjhSbamM1MizlEJUX18HACgoFKQkYf6BnYxN34Nv2HhM0cmzUc=
9b80981212fe6c01b7c16b3ca7c4e66af56f12f1 0 iEYEABECAAYFAlFLKKcACgkQjPn4sExkf7xK7wCfcioCmJPsysSbQO6+4qZMVe0mmLwAn2/o+wRf4MrUXlohrr7aXEF9vdSB
095b46180bbc412b029420587736a6185afc17e1 0 iEYEABECAAYFAlFsCnkACgkQjPn4sExkf7xLrwCfeMWjUaSmfU/fvseT5TdrYRqBEVQAoLz5SFLEA40C5f8zE8Ma/vgVJVIC
f168962bab857ca030829e4cd73d9b32c868c874 0 iEYEABECAAYFAlFwDNwACgkQjPn4sExkf7wJ6QCePVovn/avKXUyNwNBYCcov6JLYqkAnRCPQdkXgv20N3t10r6PRMBBo1/S
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
caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq

47
dropbear/.hgtags Normal file
View File

@ -0,0 +1,47 @@
03f65e461915a940939e4cc689fc89721ffc40de DROPBEAR_0.48.1
0f967bfef5cd0056b7ec60e2305d917e51cbf30d DROPBEAR_0.44
170329dc8ce5dfcf6298e1ad6699f109bf78e73d DROPBEAR_0.51
1dbd2473482f320ea59f76ce961385cb3a0150a9 DROPBEAR_0.46
2098857ab826dd42ae05a9a22c3ce2cc835b9844 DROPBEAR_0.45
36160290a1b27451178be36752ed038840f59cdd LTC_DB_0.46
39d5d58461d6e93337636e69d4cdf184a09c8d24 LTC_1.05
55a99934db873be2e63b5968fb6532e5d9bd02e4 DROPBEAR_0.48
59400faa4b44708c5d0b595e81193bc621e752d3 libtomcrypt-1.05
66087d87c3555c78b47cf01f32bb5a32054c3ceb DROPBEAR_0.44test4
677843bfa734238a67636b461a02c110c462ffaf DROPBEAR_0.44test1
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
8220862baae829ebc762587b99c662480d57bb23 DROPBEAR_0.53
86e0b50a9b588239c3fc9cc9cfe255ef586df17b ltm-0.30-orig
88e0a1ad951add46b795511dc2698e36b4aee922 DROPBEAR_0.44test3
8e94663164c6e106ccc5c9e997dedf6e04d77dd2 LTM_DB_0.44
91fbc376f01084037cd5f6a5bf2e2db4903e8e99 libtommath-0.35
97db060d0ef5f8cf8e67eb602ef037055a185ca9 libtommath-0.40
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 DROPBEAR_0.53.1
ab370c629d363f8c9a3eca512bfa86e362034654 DROPBEAR_0.49
c2ac796b130eeb6fa840873d8c230544c8ec7e4b DROPBEAR_0.44test2
cd1143579f00b0248c79f63ca70efee4a35a57e8 LTC_DB_0.44
ce104c8b0be1ff3f2c2590b7cdc3fd6870c865cd DROPBEAR_0.52
d5faf4814ddbc5abd9e209409bb9e7a4686c8cd7 libtomcrypt-1.16
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
d8254fc979e99560c93ca2cece77a6df31927ea5 LTM_0.35
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.46
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.47
e37b160c414cab6466622f63b0c4dcbf6ebc47a9 DROPBEAR_0.47
e430a26064ee86ab79aef372118d6d03b2441996 DROPBEAR_0.50
e5d119ea4c63656bc54ecfd865d04591ac2ed225 LTC_DB_0.47
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 DROPBEAR_2011.54
d354464b2aa6f6ba0bf44d43bcae5aa798435393 DROPBEAR_2012.55
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
0000000000000000000000000000000000000000 t:ltc-0.95-orig
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1
1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56
96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57
e76614145aea67f66e4a4257685c771efba21aa1 DROPBEAR_2013.58
7b68e581985fd4ea50869f8608ab95cda5d17876 DROPBEAR_2013.59
a50a1dc743317fad9b3737bc68fbca640659bb6d DROPBEAR_2013.60
e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test
3d1d7d151c0ce3a79da62e86463f5632fa2b144a DROPBEAR_2013.62
2351b2da8e0d08dcc6e64fcc328b53b9630bda68 DROPBEAR_2014.63
0d2d39957c029adb7f4327d37fe6b4900f0736d9 DROPBEAR_2014.64
e9579816f20ea85affc6135e87f8477992808948 DROPBEAR_2014.65

20
dropbear/.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

1061
dropbear/CHANGES Normal file

File diff suppressed because it is too large Load Diff

79
dropbear/INSTALL Normal file
View File

@ -0,0 +1,79 @@
Basic Dropbear build instructions:
- Edit options.h to set which features you want.
- Edit debug.h if you want any debug options (not usually required).
(If using a non-tarball copy, "autoconf; autoheader")
./configure (optionally with --disable-zlib or --disable-syslog,
or --help for other options)
Now compile:
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp"
And install (/usr/local/bin is usual default):
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" install
(you can leave items out of the PROGRAMS list to avoid compiling them. If you
recompile after changing the PROGRAMS list, you *MUST* "make clean" before
recompiling - bad things will happen otherwise)
See MULTI for instructions on making all-in-one binaries.
If you want to compile statically, add "STATIC=1" to the make command-line.
Binaries can be stripped with "make strip"
============================================================================
If you're compiling for a 386-class CPU, you will probably need to add
CFLAGS=-DLTC_NO_BSWAP so that libtomcrypt doesn't use 486+ instructions.
============================================================================
Compiling with uClibc:
Firstly, make sure you have at least uclibc 0.9.17, as getusershell() in prior
versions is broken. Also note that you may get strange issues if your uClibc
headers don't match the library you are running with, ie the headers might
say that shadow password support exists, but the libraries don't have it.
Compiling for uClibc should be the same as normal, just set CC to the magic
uClibc toolchain compiler (ie export CC=i386-uclibc-gcc or whatever).
You can use "make STATIC=1" to make statically linked binaries, and it is
advisable to strip the binaries too. If you're looking to make a small binary,
you should remove unneeded ciphers and MD5, by editing options.h
It is possible to compile zlib in, by copying zlib.h and zconf.h into a
subdirectory (ie zlibincludes), and
export CFLAGS="-Izlibincludes -I../zlibincludes"
export LDFLAGS=/usr/lib/libz.a
before ./configure and make.
If you disable zlib, you must explicitly disable compression for the client -
OpenSSH is possibly buggy in this regard, it seems you need to disable it
globally in ~/.ssh/config, not just in the host entry in that file.
You may want to manually disable lastlog recording when using uClibc, configure
with --disable-lastlog.
One common problem is pty allocation. There are a number of types of pty
allocation which can be used -- if they work properly, the end result is the
same for each type. Running configure should detect the best type to use
automatically, however for some systems, this may be incorrect. Some
things to note:
If your system expects /dev/pts to be mounted (this is a uClibc option),
make sure that it is.
Make sure that your libc headers match the library version you are using.
If openpty() is being used (HAVE_OPENPTY defined in config.h) and it fails,
you can try compiling with --disable-openpty. You will probably then need
to create all the /dev/pty?? and /dev/tty?? devices, which can be
problematic for devfs. In general, openpty() is the best way to allocate
PTYs, so it's best to try and get it working.

141
dropbear/LICENSE Normal file
View File

@ -0,0 +1,141 @@
Dropbear contains a number of components from different sources, hence there
are a few licenses and authors involved. All licenses are fairly
non-restrictive.
The majority of code is written by Matt Johnston, under the license below.
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
same license:
Copyright (c) 2002-2014 Matt Johnston
Portions copyright (c) 2004 Mihnea Stoenescu
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=====
LibTomCrypt and LibTomMath are written by Tom St Denis, and are Public Domain.
=====
sshpty.c is taken from OpenSSH 3.5p1,
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
All rights reserved
"As far as I am concerned, the code I have written for this software
can be used freely for any purpose. Any derived versions of this
software must be clearly marked as such, and if the derived work is
incompatible with the protocol description in the RFC file, it must be
called by a name other than "ssh" or "Secure Shell". "
=====
loginrec.c
loginrec.h
atomicio.h
atomicio.c
and strlcat() (included in util.c) are from OpenSSH 3.6.1p2, and are licensed
under the 2 point BSD license.
loginrec is written primarily by Andre Lucas, atomicio.c by Theo de Raadt.
strlcat() is (c) Todd C. Miller
=====
Import code in keyimport.c is modified from PuTTY's import.c, licensed as
follows:
PuTTY is copyright 1997-2003 Simon Tatham.
Portions copyright Robert de Bath, Joris van Rantwijk, Delian
Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
Justin Bradford, and CORE SDI S.A.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=====
curve25519-donna:
/* Copyright 2008, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* curve25519-donna: Curve25519 elliptic curve, public key function
*
* http://code.google.com/p/curve25519-donna/
*
* Adam Langley <agl@imperialviolet.org>
*
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
*
* More information about curve25519 can be found here
* http://cr.yp.to/ecdh.html
*
* djb's sample implementation of curve25519 is written in a special assembly
* language called qhasm and uses the floating point registers.
*
* This is, almost, a clean room reimplementation from the curve25519 paper. It
* uses many of the tricks described therein. Only the crecip function is taken
* from the sample implementation.
*/

22
dropbear/MULTI Normal file
View File

@ -0,0 +1,22 @@
Multi-binary compilation
========================
To compile for systems without much space (floppy distributions etc), you
can create a single binary. This will save disk space by avoiding repeated
code between the various parts.
If you are familiar with "busybox", it's the same principle.
To compile the multi-binary, first "make clean" (if you've compiled
previously), then
make PROGRAMS="programs you want here" MULTI=1
To use the binary, symlink it from the desired executable:
ln -s dropbearmulti dropbear
ln -s dropbearmulti dbclient
etc
then execute as normal:
./dropbear <options here>

225
dropbear/Makefile.in Normal file
View File

@ -0,0 +1,225 @@
# This Makefile is for Dropbear SSH Server and Client
# @configure_input@
# invocation:
# make PROGRAMS="dropbear dbclient scp" MULTI=1 STATIC=1 SCPPROGRESS=1
#
# to make a multiple-program statically linked binary "staticdropbearmulti".
# This example will include dropbear, scp, dropbearkey, dropbearconvert, and
# dbclient functionality, and includes the progress-bar functionality in scp.
# Hopefully that seems intuitive.
ifndef PROGRAMS
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
endif
STATIC_LTC=libtomcrypt/libtomcrypt.a
STATIC_LTM=libtommath/libtommath.a
LIBTOM_LIBS=@LIBTOM_LIBS@
ifeq (@BUNDLED_LIBTOM@, 1)
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
endif
COMMONOBJS=dbutil.o buffer.o \
dss.o bignum.o \
signkey.o rsa.o dbrandom.o \
queue.o \
atomicio.o compat.o fake-rfc2553.o \
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
gensignkey.o gendss.o genrsa.o
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
svr-tcpfwd.o svr-authpam.o
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-runopts.o cli-chansession.o \
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
cli-agentfwd.o list.o
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
tcp-accept.o listener.o process-packet.o \
common-runopts.o circbuffer.o curve25519-donna.o
KEYOBJS=dropbearkey.o
CONVERTOBJS=dropbearconvert.o keyimport.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
dss.h bignum.h signkey.h rsa.h dbrandom.h service.h auth.h \
debug.h channel.h chansession.h config.h queue.h sshpty.h \
termcodes.h gendss.h genrsa.h runopts.h includes.h \
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
listener.h fake-rfc2553.h ecc.h ecdsa.h
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
scpobjs=$(SCPOBJS)
VPATH=@srcdir@
srcdir=@srcdir@
prefix=@prefix@
exec_prefix=@exec_prefix@
datarootdir = @datarootdir@
bindir=@bindir@
sbindir=@sbindir@
mandir=@mandir@
CC=@CC@
AR=@AR@
RANLIB=@RANLIB@
STRIP=@STRIP@
INSTALL=@INSTALL@
CPPFLAGS=@CPPFLAGS@
CFLAGS+=-I. -I$(srcdir) $(CPPFLAGS) @CFLAGS@
LIBS+=@LIBS@
LDFLAGS=@LDFLAGS@
EXEEXT=@EXEEXT@
# whether we're building client, server, or both for the common objects.
# evilness so we detect 'dropbear' by itself as a word
space:= $(empty) $(empty)
ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z))))
CFLAGS+= -DDROPBEAR_SERVER
endif
ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdbclientZ, Z$(prog)Z))))
CFLAGS+= -DDROPBEAR_CLIENT
endif
# these are exported so that libtomcrypt's makefile will use them
export CC
export CFLAGS
export RANLIB AR STRIP
ifeq ($(STATIC), 1)
LDFLAGS+=-static
endif
ifeq ($(MULTI), 1)
TARGETS=dropbearmulti
else
TARGETS=$(PROGRAMS)
endif
# for the scp progress meter. The -D doesn't affect anything else.
ifeq ($(SCPPROGRESS), 1)
CFLAGS+=-DPROGRESS_METER
endif
all: $(TARGETS)
strip: $(TARGETS)
$(STRIP) $(addsuffix $(EXEEXT), $(TARGETS))
install: $(addprefix inst_, $(TARGETS))
insmultidropbear: dropbearmulti
$(INSTALL) -d $(DESTDIR)$(sbindir)
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
insmulti%: dropbearmulti
$(INSTALL) -d $(DESTDIR)$(bindir)
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
# dropbear should go in sbin, so it needs a seperate rule
inst_dropbear: dropbear
$(INSTALL) -d $(DESTDIR)$(sbindir)
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
inst_%: %
$(INSTALL) -d $(DESTDIR)$(bindir)
$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS))
# for some reason the rule further down doesn't like $($@objs) as a prereq.
dropbear: $(dropbearobjs)
dbclient: $(dbclientobjs)
dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)
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
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $(SCPOBJS)
# multi-binary compilation.
MULTIOBJS=
ifeq ($(MULTI),1)
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
endif
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
multibinary: dropbearmulti$(EXEEXT)
multilink: multibinary $(addprefix link, $(PROGRAMS))
link%:
-rm -f $*$(EXEEXT)
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
$(STATIC_LTC): options.h
cd libtomcrypt && $(MAKE)
$(STATIC_LTM): options.h
cd libtommath && $(MAKE)
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
ltc-clean:
cd libtomcrypt && $(MAKE) clean
ltm-clean:
cd libtommath && $(MAKE) clean
sizes: dropbear
objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn
clean: ltc-clean ltm-clean thisclean
thisclean:
-rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress \
dropbearmulti *.o *.da *.bb *.bbg *.prof
distclean: clean tidy
-rm -f config.h
-rm -f Makefile
tidy:
-rm -f *~ *.gcov */*~

78
dropbear/README Normal file
View File

@ -0,0 +1,78 @@
This is Dropbear, a smallish SSH server and client.
https://matt.ucc.asn.au/dropbear/dropbear.html
INSTALL has compilation instructions.
MULTI has instructions on making a multi-purpose binary (ie a single binary
which performs multiple tasks, to save disk space)
SMALL has some tips on creating small binaries.
See TODO for a few of the things I know need looking at, and please contact
me if you have any questions/bugs found/features/ideas/comments etc :)
Matt Johnston
matt@ucc.asn.au
In the absence of detailed documentation, some notes follow:
============================================================================
Server public key auth:
You can use ~/.ssh/authorized_keys in the same way as with OpenSSH, just put
the key entries in that file. They should be of the form:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwVa6M6cGVmUcLl2cFzkxEoJd06Ub4bVDsYrWvXhvUV+ZAM9uGuewZBDoAqNKJxoIn0Hyd0Nk/yU99UVv6NWV/5YSHtnf35LKds56j7cuzoQpFIdjNwdxAN0PCET/MG8qyskG/2IE2DPNIaJ3Wy+Ws4IZEgdJgPlTYUBWWtCWOGc= someone@hostname
You must make sure that ~/.ssh, and the key file, are only writable by the
user. Beware of editors that split the key into multiple lines.
Dropbear supports some options for authorized_keys entries, see the manpage.
============================================================================
Client public key auth:
Dropbear can do public key auth as a client, but you will have to convert
OpenSSH style keys to Dropbear format, or use dropbearkey to create them.
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>
Dropbear does not support encrypted hostkeys though can connect to ssh-agent.
============================================================================
If you want to get the public-key portion of a Dropbear private key, look at
dropbearkey's '-y' option.
============================================================================
To run the server, you need to server keys, this is one-off:
./dropbearkey -t rsa -f dropbear_rsa_host_key
./dropbearkey -t dss -f dropbear_dss_host_key
./dropbearkey -t ecdsa -f dropbear_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
pty, and you cannot login as any user other than that running the daemon
(obviously). Shadow passwords will also be unusable as non-root.
============================================================================
The Dropbear distribution includes a standalone version of OpenSSH's scp
program. You can compile it with "make scp", you may want to change the path
of the ssh binary, specified by _PATH_SSH_PROGRAM in options.h . By default
the progress meter isn't compiled in to save space, you can enable it by
adding 'SCPPROGRESS=1' to the make commandline.

53
dropbear/SMALL Normal file
View File

@ -0,0 +1,53 @@
Tips for a small system:
If you only want server functionality (for example), compile with
make PROGRAMS=dropbear
rather than just
make dropbear
so that client functionality in shared portions of Dropbear won't be included.
The same applies if you are compiling just a client.
---
The following are set in options.h:
- You can safely disable blowfish and twofish ciphers, and MD5 hmac, without
affecting interoperability
- If you're compiling statically, you can turn off host lookups
- You can disable either password or public-key authentication, though note
that the IETF draft states that pubkey authentication is required.
- Similarly with DSS and RSA, you can disable one of these if you know that
all clients will be able to support a particular one. The IETF draft
states that DSS is required, however you may prefer to use RSA.
DON'T disable either of these on systems where you aren't 100% sure about
who will be connecting and what clients they will be using.
- Disabling the MOTD code and SFTP-SERVER may save a small amount of codesize
- You can disable x11, tcp and agent forwarding as desired. None of these are
essential, although agent-forwarding is often useful even on firewall boxes.
---
If you are compiling statically, you may want to disable zlib, as it will use
a few tens of kB of binary-size (./configure --disable-zlib).
You can create a combined binary, see the file MULTI, which will put all
the functions into one binary, avoiding repeated code.
If you're compiling with gcc, you might want to look at gcc's options for
stripping unused code. The relevant vars to set before configure are:
LDFLAGS=-Wl,--gc-sections
CFLAGS="-ffunction-sections -fdata-sections"
You can also experiment with optimisation flags such as -Os, note that in some
cases these flags actually seem to increase size, so experiment before
deciding.
Of course using small C libraries such as uClibc and dietlibc can also help.
If you have any queries, mail me and I'll see if I can help.

27
dropbear/TODO Normal file
View File

@ -0,0 +1,27 @@
Current:
Things which might need doing:
- default private dbclient keys
- Make options.h generated from configure perhaps?
- handle /etc/environment in AIX
- check that there aren't timing issues with valid/invalid user authentication
feedback.
- Binding to different interfaces
- CTR mode
- SSH_MSG_IGNORE sending to improve CBC security
- DH Group Exchange possibly, or just add group14 (whatever it's called today)
- fix scp.c for IRIX
- Be able to use OpenSSH keys for the client? or at least have some form of
encrypted keys.
- Client agent forwarding
- Handle restrictions in ~/.ssh/authorized_keys ?

63
dropbear/agentfwd.h Normal file
View File

@ -0,0 +1,63 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _AGENTFWD_H_
#define _AGENTFWD_H_
#include "includes.h"
#include "chansession.h"
#include "channel.h"
#include "auth.h"
#include "list.h"
#ifdef ENABLE_CLI_AGENTFWD
/* An agent reply can be reasonably large, as it can
* contain a list of all public keys held by the agent.
* 10000 is arbitrary */
#define MAX_AGENT_REPLY 10000
/* client functions */
void cli_load_agent_keys(m_list * ret_list);
void agent_buf_sign(buffer *sigblob, sign_key *key,
buffer *data_buf);
void cli_setup_agent(struct Channel *channel);
#ifdef __hpux
#define seteuid(a) setresuid(-1, (a), -1)
#define setegid(a) setresgid(-1, (a), -1)
#endif
extern const struct ChanType cli_chan_agent;
#endif /* ENABLE_CLI_AGENTFWD */
#ifdef ENABLE_SVR_AGENTFWD
int svr_agentreq(struct ChanSess * chansess);
void svr_agentcleanup(struct ChanSess * chansess);
void svr_agentset(struct ChanSess *chansess);
#endif /* ENABLE_SVR_AGENTFWD */
#endif /* _AGENTFWD_H_ */

136
dropbear/algo.h Normal file
View File

@ -0,0 +1,136 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _ALGO_H_
#define _ALGO_H_
#include "includes.h"
#include "buffer.h"
#define DROPBEAR_MODE_UNUSED 0
#define DROPBEAR_MODE_CBC 1
#define DROPBEAR_MODE_CTR 2
struct Algo_Type {
const unsigned char *name; /* identifying name */
char val; /* a value for this cipher, or -1 for invalid */
const void *data; /* algorithm specific data */
char usable; /* whether we can use this algorithm */
const void *mode; /* the mode, currently only used for ciphers,
points to a 'struct dropbear_cipher_mode' */
};
typedef struct Algo_Type algo_type;
/* lists mapping ssh types of algorithms to internal values */
extern algo_type sshkex[];
extern algo_type sshhostkey[];
extern algo_type sshciphers[];
extern algo_type sshhashes[];
extern algo_type ssh_compress[];
extern algo_type ssh_nocompress[];
extern const struct dropbear_cipher dropbear_nocipher;
extern const struct dropbear_cipher_mode dropbear_mode_none;
extern const struct dropbear_hash dropbear_nohash;
struct dropbear_cipher {
const struct ltc_cipher_descriptor *cipherdesc;
const unsigned long keysize;
const unsigned char blocksize;
};
struct dropbear_cipher_mode {
int (*start)(int cipher, const unsigned char *IV,
const unsigned char *key,
int keylen, int num_rounds, void *cipher_state);
int (*encrypt)(const unsigned char *pt, unsigned char *ct,
unsigned long len, void *cipher_state);
int (*decrypt)(const unsigned char *ct, unsigned char *pt,
unsigned long len, void *cipher_state);
};
struct dropbear_hash {
const struct ltc_hash_descriptor *hash_desc;
const unsigned long keysize;
/* hashsize may be truncated from the size returned by hash_desc,
eg sha1-96 */
const unsigned char hashsize;
};
enum dropbear_kex_mode {
DROPBEAR_KEX_NORMAL_DH,
DROPBEAR_KEX_ECDH,
DROPBEAR_KEX_CURVE25519,
};
struct dropbear_kex {
enum dropbear_kex_mode mode;
/* "normal" DH KEX */
const unsigned char *dh_p_bytes;
const int dh_p_len;
/* elliptic curve DH KEX */
#ifdef DROPBEAR_ECDH
const struct dropbear_ecc_curve *ecc_curve;
#else
const void* dummy;
#endif
/* both */
const struct ltc_hash_descriptor *hash_desc;
};
int have_algo(char* algo, size_t algolen, algo_type algos[]);
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
enum kexguess2_used {
KEXGUESS2_LOOK,
KEXGUESS2_NO,
KEXGUESS2_YES,
};
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
#define KEXGUESS2_ALGO_ID 99
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
enum kexguess2_used *kexguess2, int *goodguess);
#ifdef ENABLE_USER_ALGO_LIST
int check_user_algos(const char* user_algo_list, algo_type * algos,
const char *algo_desc);
char * algolist_string(algo_type algos[]);
#endif
enum {
DROPBEAR_COMP_NONE,
DROPBEAR_COMP_ZLIB,
DROPBEAR_COMP_ZLIB_DELAY,
};
#endif /* _ALGO_H_ */

63
dropbear/atomicio.c Normal file
View File

@ -0,0 +1,63 @@
/*
* Copied from OpenSSH 3.6.1p2.
*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RCSID("OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp "); */
#include "atomicio.h"
/*
* ensure all of data on socket comes through. f==read || f==write
*/
ssize_t
atomicio(f, fd, _s, n)
ssize_t (*f) ();
int fd;
void *_s;
size_t n;
{
char *s = _s;
ssize_t res;
size_t pos = 0;
while (n > pos) {
res = (f) (fd, s + pos, n - pos);
switch (res) {
case -1:
#ifdef EWOULDBLOCK
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
#else
if (errno == EINTR || errno == EAGAIN)
#endif
continue;
case 0:
return (res);
default:
pos += res;
}
}
return (pos);
}

36
dropbear/atomicio.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copied from OpenSSH 3.6.1p2, required for loginrec.c
*
* $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $
*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
/*
* Ensure all of data on socket comes through. f==read || f==write
*/
ssize_t atomicio(ssize_t (*)(), int, void *, size_t);

140
dropbear/auth.h Normal file
View File

@ -0,0 +1,140 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _AUTH_H_
#define _AUTH_H_
#include "includes.h"
#include "signkey.h"
#include "chansession.h"
void svr_authinitialise();
void cli_authinitialise();
/* Server functions */
void recv_msg_userauth_request();
void send_msg_userauth_failure(int partial, int incrfail);
void send_msg_userauth_success();
void send_msg_userauth_banner(buffer *msg);
void svr_auth_password();
void svr_auth_pubkey();
void svr_auth_pam();
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
int svr_pubkey_allows_agentfwd();
int svr_pubkey_allows_tcpfwd();
int svr_pubkey_allows_x11fwd();
int svr_pubkey_allows_pty();
void svr_pubkey_set_forced_command(struct ChanSess *chansess);
void svr_pubkey_options_cleanup();
int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filename);
#else
/* no option : success */
#define svr_pubkey_allows_agentfwd() 1
#define svr_pubkey_allows_tcpfwd() 1
#define svr_pubkey_allows_x11fwd() 1
#define svr_pubkey_allows_pty() 1
static inline void svr_pubkey_set_forced_command(struct ChanSess *chansess) { }
static inline void svr_pubkey_options_cleanup() { }
#define svr_add_pubkey_options(x,y,z) DROPBEAR_SUCCESS
#endif
/* Client functions */
void recv_msg_userauth_failure();
void recv_msg_userauth_success();
void recv_msg_userauth_specific_60();
void recv_msg_userauth_pk_ok();
void recv_msg_userauth_info_request();
void cli_get_user();
void cli_auth_getmethods();
int cli_auth_try();
void recv_msg_userauth_banner();
void cli_pubkeyfail();
void cli_auth_password();
int cli_auth_pubkey();
void cli_auth_interactive();
char* getpass_or_cancel(char* prompt);
void cli_auth_pubkey_cleanup();
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
#define AUTH_TYPE_NONE 1
#define AUTH_TYPE_PUBKEY 1 << 1
#define AUTH_TYPE_PASSWORD 1 << 2
#define AUTH_TYPE_INTERACT 1 << 3
#define AUTH_METHOD_NONE "none"
#define AUTH_METHOD_NONE_LEN 4
#define AUTH_METHOD_PUBKEY "publickey"
#define AUTH_METHOD_PUBKEY_LEN 9
#define AUTH_METHOD_PASSWORD "password"
#define AUTH_METHOD_PASSWORD_LEN 8
#define AUTH_METHOD_INTERACT "keyboard-interactive"
#define AUTH_METHOD_INTERACT_LEN 20
/* This structure is shared between server and client - it contains
* relatively little extraneous bits when used for the client rather than the
* server */
struct AuthState {
char *username; /* This is the username the client presents to check. It
is updated each run through, used for auth checking */
unsigned char authtypes; /* Flags indicating which auth types are still
valid */
unsigned int failcount; /* Number of (failed) authentication attempts.*/
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for
client and server (though has differing
meanings). */
unsigned perm_warn : 1; /* Server only, set if bad permissions on
~/.ssh/authorized_keys have already been
logged. */
/* These are only used for the server */
uid_t pw_uid;
gid_t pw_gid;
char *pw_dir;
char *pw_shell;
char *pw_name;
char *pw_passwd;
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
struct PubKeyOptions* pubkey_options;
#endif
};
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
struct PubKeyOptions;
struct PubKeyOptions {
/* Flags */
int no_port_forwarding_flag;
int no_agent_forwarding_flag;
int no_x11_forwarding_flag;
int no_pty_flag;
/* "command=" option. */
unsigned char * forced_command;
};
#endif
#endif /* _AUTH_H_ */

88
dropbear/bignum.c Normal file
View File

@ -0,0 +1,88 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
/* Contains helper functions for mp_int handling */
#include "includes.h"
#include "dbutil.h"
/* wrapper for mp_init, failing fatally on errors (memory allocation) */
void m_mp_init(mp_int *mp) {
if (mp_init(mp) != MP_OKAY) {
dropbear_exit("Mem alloc error");
}
}
/* simplified duplication of bn_mp_multi's mp_init_multi, but die fatally
* on error */
void m_mp_init_multi(mp_int *mp, ...)
{
mp_int* cur_arg = mp;
va_list args;
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
if (mp_init(cur_arg) != MP_OKAY) {
dropbear_exit("Mem alloc error");
}
cur_arg = va_arg(args, mp_int*);
}
va_end(args);
}
void m_mp_alloc_init_multi(mp_int **mp, ...)
{
mp_int** cur_arg = mp;
va_list args;
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
*cur_arg = m_malloc(sizeof(mp_int));
if (mp_init(*cur_arg) != MP_OKAY) {
dropbear_exit("Mem alloc error");
}
cur_arg = va_arg(args, mp_int**);
}
va_end(args);
}
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
dropbear_exit("Mem alloc error");
}
}
/* hash the ssh representation of the mp_int mp */
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
hash_state *hs, mp_int *mp) {
buffer * buf;
buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
plus header + some leeway*/
buf_putmpint(buf, mp);
hash_desc->process(hs, buf->data, buf->len);
buf_free(buf);
}

38
dropbear/bignum.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _BIGNUM_H_
#define _BIGNUM_H_
#include "includes.h"
#include "dbutil.h"
void m_mp_init(mp_int *mp);
void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
void m_mp_alloc_init_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
hash_state *hs, mp_int *mp);
#endif /* _BIGNUM_H_ */

357
dropbear/buffer.c Normal file
View File

@ -0,0 +1,357 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
/* Buffer handling routines, designed to avoid overflows/using invalid data */
#include "includes.h"
#include "dbutil.h"
#include "buffer.h"
/* Prevent integer overflows when incrementing buffer position/length.
* Calling functions should check arguments first, but this provides a
* backstop */
#define BUF_MAX_INCR 1000000000
#define BUF_MAX_SIZE 1000000000
/* avoid excessively large numbers, > ~8192 bits */
#define BUF_MAX_MPINT (8240 / 8)
/* Create (malloc) a new buffer of size */
buffer* buf_new(unsigned int size) {
buffer* buf;
if (size > BUF_MAX_SIZE) {
dropbear_exit("buf->size too big");
}
buf = (buffer*)m_malloc(sizeof(buffer));
if (size > 0) {
buf->data = (unsigned char*)m_malloc(size);
} else {
buf->data = NULL;
}
buf->size = size;
buf->pos = 0;
buf->len = 0;
return buf;
}
/* free the buffer's data and the buffer itself */
void buf_free(buffer* buf) {
m_free(buf->data)
m_free(buf);
}
/* overwrite the contents of the buffer to clear it */
void buf_burn(buffer* buf) {
m_burn(buf->data, buf->size);
}
/* resize a buffer, pos and len will be repositioned if required when
* downsizing */
void buf_resize(buffer *buf, unsigned int newsize) {
if (newsize > BUF_MAX_SIZE) {
dropbear_exit("buf->size too big");
}
buf->data = m_realloc(buf->data, newsize);
buf->size = newsize;
buf->len = MIN(newsize, buf->len);
buf->pos = MIN(newsize, buf->pos);
}
/* Create a copy of buf, allocating required memory etc. */
/* The new buffer is sized the same as the length of the source buffer. */
buffer* buf_newcopy(buffer* buf) {
buffer* ret;
ret = buf_new(buf->len);
ret->len = buf->len;
memcpy(ret->data, buf->data, buf->len);
return ret;
}
/* Set the length of the buffer */
void buf_setlen(buffer* buf, unsigned int len) {
if (len > buf->size) {
dropbear_exit("Bad buf_setlen");
}
buf->len = len;
}
/* Increment the length of the buffer */
void buf_incrlen(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR || buf->len + incr > buf->size) {
dropbear_exit("Bad buf_incrlen");
}
buf->len += incr;
}
/* Set the position of the buffer */
void buf_setpos(buffer* buf, unsigned int pos) {
if (pos > buf->len) {
dropbear_exit("Bad buf_setpos");
}
buf->pos = pos;
}
/* increment the postion by incr, increasing the buffer length if required */
void buf_incrwritepos(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
dropbear_exit("Bad buf_incrwritepos");
}
buf->pos += incr;
if (buf->pos > buf->len) {
buf->len = buf->pos;
}
}
/* increment the position by incr, negative values are allowed, to
* decrement the pos*/
void buf_incrpos(buffer* buf, int incr) {
if (incr > BUF_MAX_INCR ||
(unsigned int)((int)buf->pos + incr) > buf->len
|| ((int)buf->pos + incr) < 0) {
dropbear_exit("Bad buf_incrpos");
}
buf->pos += incr;
}
/* Get a byte from the buffer and increment the pos */
unsigned char buf_getbyte(buffer* buf) {
/* This check is really just ==, but the >= allows us to check for the
* bad case of pos > len, which should _never_ happen. */
if (buf->pos >= buf->len) {
dropbear_exit("Bad buf_getbyte");
}
return buf->data[buf->pos++];
}
/* Get a bool from the buffer and increment the pos */
unsigned char buf_getbool(buffer* buf) {
unsigned char b;
b = buf_getbyte(buf);
if (b != 0)
b = 1;
return b;
}
/* put a byte, incrementing the length if required */
void buf_putbyte(buffer* buf, unsigned char val) {
if (buf->pos >= buf->len) {
buf_incrlen(buf, 1);
}
buf->data[buf->pos] = val;
buf->pos++;
}
/* returns an in-place pointer to the buffer, checking that
* the next len bytes from that position can be used */
unsigned char* buf_getptr(buffer* buf, unsigned int len) {
if (buf->pos + len > buf->len) {
dropbear_exit("Bad buf_getptr");
}
return &buf->data[buf->pos];
}
/* like buf_getptr, but checks against total size, not used length.
* This allows writing past the used length, but not past the size */
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
if (buf->pos + len > buf->size) {
dropbear_exit("Bad buf_getwriteptr");
}
return &buf->data[buf->pos];
}
/* Return a null-terminated string, it is malloced, so must be free()ed
* Note that the string isn't checked for null bytes, hence the retlen
* may be longer than what is returned by strlen */
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
unsigned int len;
unsigned char* ret;
len = buf_getint(buf);
if (len > MAX_STRING_LEN) {
dropbear_exit("String too long");
}
if (retlen != NULL) {
*retlen = len;
}
ret = m_malloc(len+1);
memcpy(ret, buf_getptr(buf, len), len);
buf_incrpos(buf, len);
ret[len] = '\0';
return ret;
}
/* Return a string as a newly allocated buffer */
buffer * buf_getstringbuf(buffer *buf) {
buffer *ret;
unsigned char* str;
unsigned int len;
str = buf_getstring(buf, &len);
ret = m_malloc(sizeof(*ret));
ret->data = str;
ret->len = len;
ret->size = len;
ret->pos = 0;
return ret;
}
/* Just increment the buffer position the same as if we'd used buf_getstring,
* but don't bother copying/malloc()ing for it */
void buf_eatstring(buffer *buf) {
buf_incrpos( buf, buf_getint(buf) );
}
/* Get an uint32 from the buffer and increment the pos */
unsigned int buf_getint(buffer* buf) {
unsigned int ret;
LOAD32H(ret, buf_getptr(buf, 4));
buf_incrpos(buf, 4);
return ret;
}
/* put a 32bit uint into the buffer, incr bufferlen & pos if required */
void buf_putint(buffer* buf, int unsigned val) {
STORE32H(val, buf_getwriteptr(buf, 4));
buf_incrwritepos(buf, 4);
}
/* put a SSH style string into the buffer, increasing buffer len if required */
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
buf_putint(buf, len);
buf_putbytes(buf, str, len);
}
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
buf_putstring(buf, buf_str->data, buf_str->len);
}
/* put the set of len bytes into the buffer, incrementing the pos, increasing
* len if required */
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
memcpy(buf_getwriteptr(buf, len), bytes, len);
buf_incrwritepos(buf, len);
}
/* for our purposes we only need positive (or 0) numbers, so will
* fail if we get negative numbers */
void buf_putmpint(buffer* buf, mp_int * mp) {
unsigned int len, pad = 0;
TRACE2(("enter buf_putmpint"))
dropbear_assert(mp != NULL);
if (SIGN(mp) == MP_NEG) {
dropbear_exit("negative bignum");
}
/* zero check */
if (USED(mp) == 1 && DIGIT(mp, 0) == 0) {
len = 0;
} else {
/* SSH spec requires padding for mpints with the MSB set, this code
* implements it */
len = mp_count_bits(mp);
/* if the top bit of MSB is set, we need to pad */
pad = (len%8 == 0) ? 1 : 0;
len = len / 8 + 1; /* don't worry about rounding, we need it for
padding anyway when len%8 == 0 */
}
/* store the length */
buf_putint(buf, len);
/* store the actual value */
if (len > 0) {
if (pad) {
buf_putbyte(buf, 0x00);
}
if (mp_to_unsigned_bin(mp, buf_getwriteptr(buf, len-pad)) != MP_OKAY) {
dropbear_exit("mpint error");
}
buf_incrwritepos(buf, len-pad);
}
TRACE2(("leave buf_putmpint"))
}
/* Retrieve an mp_int from the buffer.
* Will fail for -ve since they shouldn't be required here.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_getmpint(buffer* buf, mp_int* mp) {
unsigned int len;
len = buf_getint(buf);
if (len == 0) {
mp_zero(mp);
return DROPBEAR_SUCCESS;
}
if (len > BUF_MAX_MPINT) {
return DROPBEAR_FAILURE;
}
/* check for negative */
if (*buf_getptr(buf, 1) & (1 << (CHAR_BIT-1))) {
return DROPBEAR_FAILURE;
}
if (mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
return DROPBEAR_FAILURE;
}
buf_incrpos(buf, len);
return DROPBEAR_SUCCESS;
}

68
dropbear/buffer.h Normal file
View File

@ -0,0 +1,68 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _BUFFER_H_
#define _BUFFER_H_
#include "includes.h"
struct buf {
unsigned char * data;
unsigned int len; /* the used size */
unsigned int pos;
unsigned int size; /* the memory size */
};
typedef struct buf buffer;
buffer * buf_new(unsigned int size);
void buf_resize(buffer *buf, unsigned int newsize);
void buf_free(buffer* buf);
void buf_burn(buffer* buf);
buffer* buf_newcopy(buffer* buf);
void buf_setlen(buffer* buf, unsigned int len);
void buf_incrlen(buffer* buf, unsigned int incr);
void buf_setpos(buffer* buf, unsigned int pos);
void buf_incrpos(buffer* buf, int incr); /* -ve is ok, to go backwards */
void buf_incrwritepos(buffer* buf, unsigned int incr);
unsigned char buf_getbyte(buffer* buf);
unsigned char buf_getbool(buffer* buf);
void buf_putbyte(buffer* buf, unsigned char val);
unsigned char* buf_getptr(buffer* buf, unsigned int len);
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
buffer * buf_getstringbuf(buffer *buf);
void buf_eatstring(buffer *buf);
void buf_putint(buffer* buf, unsigned int val);
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
void buf_putbufstring(buffer *buf, const buffer* buf_str);
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
void buf_putmpint(buffer* buf, mp_int * mp);
int buf_getmpint(buffer* buf, mp_int* mp);
unsigned int buf_getint(buffer* buf);
#endif /* _BUFFER_H_ */

140
dropbear/channel.h Normal file
View File

@ -0,0 +1,140 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CHANNEL_H_
#define _CHANNEL_H_
#include "includes.h"
#include "buffer.h"
#include "circbuffer.h"
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
#define SSH_OPEN_CONNECT_FAILED 2
#define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3
#define SSH_OPEN_RESOURCE_SHORTAGE 4
/* Not a real type */
#define SSH_OPEN_IN_PROGRESS 99
#define CHAN_EXTEND_SIZE 3 /* how many extra slots to add when we need more */
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 */
unsigned int remotechan;
unsigned int recvwindow, transwindow;
unsigned int recvdonelen;
unsigned int recvmaxpacket, transmaxpacket;
void* typedata; /* a pointer to type specific data */
int writefd; /* read from wire, written to insecure side */
int readfd; /* read from insecure side, written to wire */
int errfd; /* used like writefd or readfd, depending if it's client or server.
Doesn't exactly belong here, but is cleaner here */
circbuffer *writebuf; /* data from the wire, for local consumption. Can be
initially NULL */
circbuffer *extrabuf; /* extended-data for the program - used like writebuf
but for stderr */
/* whether close/eof messages have been exchanged */
int sent_close, recv_close;
int recv_eof, sent_eof;
/* Set after running the ChanType-specific close hander
* to ensure we don't run it twice (nor type->checkclose()). */
int close_handler_done;
int initconn; /* used for TCP forwarding, whether the channel has been
fully initialised */
int await_open; /* flag indicating whether we've sent an open request
for this channel (and are awaiting a confirmation
or failure). */
int flushing;
/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len);
const struct ChanType* type;
enum dropbear_channel_prio prio;
};
struct ChanType {
int sepfds; /* Whether this channel has seperate pipes for in/out or not */
char *name;
int (*inithandler)(struct Channel*);
int (*check_close)(struct Channel*);
void (*reqhandler)(struct Channel*);
void (*closehandler)(struct Channel*);
};
void chaninitialise(const struct ChanType *chantypes[]);
void chancleanup();
void setchannelfds(fd_set *readfd, fd_set *writefd);
void channelio(fd_set *readfd, fd_set *writefd);
struct Channel* getchannel();
/* Returns an arbitrary channel that is in a ready state - not
being initialised and no EOF in either direction. NULL if none. */
struct Channel* get_any_ready_channel();
void recv_msg_channel_open();
void recv_msg_channel_request();
void send_msg_channel_failure(struct Channel *channel);
void send_msg_channel_success(struct Channel *channel);
void recv_msg_channel_data();
void recv_msg_channel_extended_data();
void recv_msg_channel_window_adjust();
void recv_msg_channel_close();
void recv_msg_channel_eof();
void common_recv_msg_channel_data(struct Channel *channel, int fd,
circbuffer * buf);
#ifdef DROPBEAR_CLIENT
extern const struct ChanType clichansess;
#endif
#if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
int send_msg_channel_open_init(int fd, const struct ChanType *type);
void recv_msg_channel_open_confirmation();
void recv_msg_channel_open_failure();
#endif
void start_send_channel_request(struct Channel *channel, unsigned char *type);
void send_msg_request_success();
void send_msg_request_failure();
#endif /* _CHANNEL_H_ */

106
dropbear/chansession.h Normal file
View File

@ -0,0 +1,106 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CHANSESSION_H_
#define _CHANSESSION_H_
#include "loginrec.h"
#include "channel.h"
#include "listener.h"
struct exitinfo {
int exitpid; /* -1 if not exited */
int exitstatus;
int exitsignal;
int exitcore;
};
struct ChanSess {
unsigned char * cmd; /* command to exec */
pid_t pid; /* child process pid */
/* pty details */
int master; /* the master terminal fd*/
int slave;
unsigned char * tty;
unsigned char * term;
/* exit details */
struct exitinfo exit;
/* These are only set temporarily before forking */
/* Used to set $SSH_CONNECTION in the child session. */
char *connection_string;
/* Used to set $SSH_CLIENT in the child session. */
char *client_string;
#ifndef DISABLE_X11FWD
struct Listener * x11listener;
int x11port;
char * x11authprot;
char * x11authcookie;
unsigned int x11screennum;
unsigned char x11singleconn;
#endif
#ifdef ENABLE_SVR_AGENTFWD
struct Listener * agentlistener;
char * agentfile;
char * agentdir;
#endif
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
char *original_command;
#endif
};
struct ChildPid {
pid_t pid;
struct ChanSess * chansess;
};
void addnewvar(const char* param, const char* var);
void cli_send_chansess_request();
void cli_tty_cleanup();
void cli_chansess_winchange();
#ifdef ENABLE_CLI_NETCAT
void cli_send_netcat_request();
#endif
void svr_chansessinitialise();
extern const struct ChanType svrchansess;
struct SigMap {
int signal;
char* name;
};
extern const struct SigMap signames[];
#endif /* _CHANSESSION_H_ */

141
dropbear/circbuffer.c Normal file
View File

@ -0,0 +1,141 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002-2004 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
#include "circbuffer.h"
#define MAX_CBUF_SIZE 100000000
circbuffer * cbuf_new(unsigned int size) {
circbuffer *cbuf = NULL;
if (size > MAX_CBUF_SIZE) {
dropbear_exit("Bad cbuf size");
}
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
if (size > 0) {
cbuf->data = (unsigned char*)m_malloc(size);
}
cbuf->used = 0;
cbuf->readpos = 0;
cbuf->writepos = 0;
cbuf->size = size;
return cbuf;
}
void cbuf_free(circbuffer * cbuf) {
m_burn(cbuf->data, cbuf->size);
m_free(cbuf->data);
m_free(cbuf);
}
unsigned int cbuf_getused(circbuffer * cbuf) {
return cbuf->used;
}
unsigned int cbuf_getavail(circbuffer * cbuf) {
return cbuf->size - cbuf->used;
}
unsigned int cbuf_readlen(circbuffer *cbuf) {
dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == 0) {
TRACE(("cbuf_readlen: unused buffer"))
return 0;
}
if (cbuf->readpos < cbuf->writepos) {
return cbuf->writepos - cbuf->readpos;
}
return cbuf->size - cbuf->readpos;
}
unsigned int cbuf_writelen(circbuffer *cbuf) {
dropbear_assert(cbuf->used <= cbuf->size);
dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == cbuf->size) {
TRACE(("cbuf_writelen: full buffer"))
return 0; /* full */
}
if (cbuf->writepos < cbuf->readpos) {
return cbuf->readpos - cbuf->writepos;
}
return cbuf->size - cbuf->writepos;
}
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("Bad cbuf read");
}
return &cbuf->data[cbuf->readpos];
}
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("Bad cbuf write");
}
return &cbuf->data[cbuf->writepos];
}
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("Bad cbuf write");
}
cbuf->used += len;
dropbear_assert(cbuf->used <= cbuf->size);
cbuf->writepos = (cbuf->writepos + len) % cbuf->size;
}
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("Bad cbuf read");
}
dropbear_assert(cbuf->used >= len);
cbuf->used -= len;
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;
}

50
dropbear/circbuffer.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002-2004 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CIRCBUFFER_H_
#define _CIRCBUFFER_H_
struct circbuf {
unsigned int size;
unsigned int readpos;
unsigned int writepos;
unsigned int used;
unsigned char* data;
};
typedef struct circbuf circbuffer;
circbuffer * cbuf_new(unsigned int size);
void cbuf_free(circbuffer * cbuf);
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */
unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len);
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
void cbuf_incrread(circbuffer *cbuf, unsigned int len);
#endif

308
dropbear/cli-agentfwd.c Normal file
View File

@ -0,0 +1,308 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2005 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#ifdef ENABLE_CLI_AGENTFWD
#include "agentfwd.h"
#include "session.h"
#include "ssh.h"
#include "dbutil.h"
#include "chansession.h"
#include "channel.h"
#include "packet.h"
#include "buffer.h"
#include "dbrandom.h"
#include "listener.h"
#include "runopts.h"
#include "atomicio.h"
#include "signkey.h"
#include "auth.h"
/* The protocol implemented to talk to OpenSSH's SSH2 agent is documented in
PROTOCOL.agent in recent OpenSSH source distributions (5.1p1 has it). */
static int new_agent_chan(struct Channel * channel);
const struct ChanType cli_chan_agent = {
0, /* sepfds */
"auth-agent@openssh.com",
new_agent_chan,
NULL,
NULL,
NULL
};
static int connect_agent() {
int fd = -1;
char* agent_sock = NULL;
agent_sock = getenv("SSH_AUTH_SOCK");
if (agent_sock == NULL)
return -1;
fd = connect_unix(agent_sock);
if (fd < 0) {
dropbear_log(LOG_INFO, "Failed to connect to agent");
}
return fd;
}
/* handle a request for a connection to the locally running ssh-agent
or forward. */
static int new_agent_chan(struct Channel * channel) {
int fd = -1;
if (!cli_opts.agent_fwd)
return SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
fd = connect_agent();
if (fd < 0) {
return SSH_OPEN_CONNECT_FAILED;
}
setnonblocking(fd);
ses.maxfd = MAX(ses.maxfd, fd);
channel->readfd = fd;
channel->writefd = fd;
return 0;
}
/* Sends a request to the agent, returning a newly allocated buffer
* with the response */
/* This function will block waiting for a response - it will
* only be used by client authentication (not for forwarded requests)
* won't cause problems for interactivity. */
/* Packet format (from draft-ylonen)
4 bytes Length, msb first. Does not include length itself.
1 byte Packet type. The value 255 is reserved for future extensions.
data Any data, depending on packet type. Encoding as in the ssh packet
protocol.
*/
static buffer * agent_request(unsigned char type, buffer *data) {
buffer * payload = NULL;
buffer * inbuf = NULL;
size_t readlen = 0;
ssize_t ret;
const int fd = cli_opts.agent_fd;
unsigned int data_len = 0;
if (data)
{
data_len = data->len;
}
payload = buf_new(4 + 1 + data_len);
buf_putint(payload, 1 + data_len);
buf_putbyte(payload, type);
if (data) {
buf_putbytes(payload, data->data, data->len);
}
buf_setpos(payload, 0);
ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len);
if ((size_t)ret != payload->len) {
TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno)))
goto out;
}
buf_free(payload);
payload = NULL;
TRACE(("Wrote out bytes for agent_request"))
/* Now we read the response */
inbuf = buf_new(4);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, 4), 4);
if (ret != 4) {
TRACE(("read of length failed for agent_request"))
goto out;
}
buf_setpos(inbuf, 0);
buf_setlen(inbuf, ret);
readlen = buf_getint(inbuf);
if (readlen > MAX_AGENT_REPLY) {
TRACE(("agent reply is too big"));
goto out;
}
buf_resize(inbuf, readlen);
buf_setpos(inbuf, 0);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
if ((size_t)ret != readlen) {
TRACE(("read of data failed for agent_request"))
goto out;
}
buf_incrwritepos(inbuf, readlen);
buf_setpos(inbuf, 0);
out:
if (payload)
buf_free(payload);
return inbuf;
}
static void agent_get_key_list(m_list * ret_list)
{
buffer * inbuf = NULL;
unsigned int num = 0;
unsigned char packet_type;
unsigned int i;
int ret;
inbuf = agent_request(SSH2_AGENTC_REQUEST_IDENTITIES, NULL);
if (!inbuf) {
TRACE(("agent_request failed returning identities"))
goto out;
}
/* The reply has a format of:
byte SSH2_AGENT_IDENTITIES_ANSWER
uint32 num_keys
Followed by zero or more consecutive keys, encoded as:
string key_blob
string key_comment
*/
packet_type = buf_getbyte(inbuf);
if (packet_type != SSH2_AGENT_IDENTITIES_ANSWER) {
goto out;
}
num = buf_getint(inbuf);
for (i = 0; i < num; i++) {
sign_key * pubkey = NULL;
enum signkey_type key_type = DROPBEAR_SIGNKEY_ANY;
buffer * key_buf;
/* each public key is encoded as a string */
key_buf = buf_getstringbuf(inbuf);
pubkey = new_sign_key();
ret = buf_get_pub_key(key_buf, pubkey, &key_type);
buf_free(key_buf);
if (ret != DROPBEAR_SUCCESS) {
/* This is slack, properly would cleanup vars etc */
dropbear_exit("Bad pubkey received from agent");
}
pubkey->type = key_type;
pubkey->source = SIGNKEY_SOURCE_AGENT;
list_append(ret_list, pubkey);
/* We'll ignore the comment for now. might want it later.*/
buf_eatstring(inbuf);
}
out:
if (inbuf) {
buf_free(inbuf);
inbuf = NULL;
}
}
void cli_setup_agent(struct Channel *channel) {
if (!getenv("SSH_AUTH_SOCK")) {
return;
}
start_send_channel_request(channel, "auth-agent-req@openssh.com");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
encrypt_packet();
}
/* Returned keys are prepended to ret_list, which will
be updated. */
void cli_load_agent_keys(m_list *ret_list) {
/* agent_fd will be closed after successful auth */
cli_opts.agent_fd = connect_agent();
if (cli_opts.agent_fd < 0) {
return;
}
agent_get_key_list(ret_list);
}
void agent_buf_sign(buffer *sigblob, sign_key *key,
buffer *data_buf) {
buffer *request_data = NULL;
buffer *response = NULL;
unsigned int siglen;
int packet_type;
/* Request format
byte SSH2_AGENTC_SIGN_REQUEST
string key_blob
string data
uint32 flags
*/
request_data = buf_new(MAX_PUBKEY_SIZE + data_buf->len + 12);
buf_put_pub_key(request_data, key, key->type);
buf_putbufstring(request_data, data_buf);
buf_putint(request_data, 0);
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
if (!response) {
goto fail;
}
packet_type = buf_getbyte(response);
if (packet_type != SSH2_AGENT_SIGN_RESPONSE) {
goto fail;
}
/* Response format
byte SSH2_AGENT_SIGN_RESPONSE
string signature_blob
*/
siglen = buf_getint(response);
buf_putbytes(sigblob, buf_getptr(response, siglen), siglen);
goto cleanup;
fail:
/* XXX don't fail badly here. instead propagate a failure code back up to
the cli auth pubkey code, and just remove this key from the list of
ones to try. */
dropbear_exit("Agent failed signing key");
cleanup:
if (request_data) {
buf_free(request_data);
}
if (response) {
buf_free(response);
}
}
#endif

349
dropbear/cli-auth.c Normal file
View File

@ -0,0 +1,349 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "session.h"
#include "auth.h"
#include "dbutil.h"
#include "buffer.h"
#include "ssh.h"
#include "packet.h"
#include "runopts.h"
void cli_authinitialise() {
memset(&ses.authstate, 0, sizeof(ses.authstate));
}
/* Send a "none" auth request to get available methods */
void cli_auth_getmethods() {
TRACE(("enter cli_auth_getmethods"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
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"))
}
void recv_msg_userauth_banner() {
unsigned char* banner = NULL;
unsigned int bannerlen;
unsigned int i, linecount;
TRACE(("enter recv_msg_userauth_banner"))
if (ses.authstate.authdone) {
TRACE(("leave recv_msg_userauth_banner: banner after auth done"))
return;
}
banner = buf_getstring(ses.payload, &bannerlen);
buf_eatstring(ses.payload); /* The language string */
if (bannerlen > MAX_BANNER_SIZE) {
TRACE(("recv_msg_userauth_banner: bannerlen too long: %d", bannerlen))
goto out;
}
cleantext(banner);
/* Limit to 25 lines */
linecount = 1;
for (i = 0; i < bannerlen; i++) {
if (banner[i] == '\n') {
if (linecount >= MAX_BANNER_LINES) {
banner[i] = '\0';
break;
}
linecount++;
}
}
fprintf(stderr, "%s\n", banner);
out:
m_free(banner);
TRACE(("leave recv_msg_userauth_banner"))
}
/* This handles the message-specific types which
* all have a value of 60. These are
* SSH_MSG_USERAUTH_PASSWD_CHANGEREQ,
* SSH_MSG_USERAUTH_PK_OK, &
* SSH_MSG_USERAUTH_INFO_REQUEST. */
void recv_msg_userauth_specific_60() {
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
recv_msg_userauth_pk_ok();
return;
}
#endif
#ifdef ENABLE_CLI_INTERACT_AUTH
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT) {
recv_msg_userauth_info_request();
return;
}
#endif
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (cli_ses.lastauthtype == AUTH_TYPE_PASSWORD) {
/* Eventually there could be proper password-changing
* support. However currently few servers seem to
* implement it, and password auth is last-resort
* regardless - keyboard-interactive is more likely
* to be used anyway. */
dropbear_close("Your password has expired.");
}
#endif
dropbear_exit("Unexpected userauth packet");
}
void recv_msg_userauth_failure() {
unsigned char * methods = NULL;
unsigned char * tok = NULL;
unsigned int methlen = 0;
unsigned int partial = 0;
unsigned int i = 0;
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();
}
#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;
}
#endif
cli_ses.state = USERAUTH_FAIL_RCVD;
cli_ses.lastauthtype = AUTH_TYPE_NONE;
}
methods = buf_getstring(ses.payload, &methlen);
partial = buf_getbool(ses.payload);
if (partial) {
dropbear_log(LOG_INFO, "Authentication partially succeeded, more attempts required");
} else {
ses.authstate.failcount++;
}
TRACE(("Methods (len %d): '%s'", methlen, methods))
ses.authstate.authdone=0;
ses.authstate.authtypes=0;
/* Split with nulls rather than commas */
for (i = 0; i < methlen; i++) {
if (methods[i] == ',') {
methods[i] = '\0';
}
}
tok = methods; /* tok stores the next method we'll compare */
for (i = 0; i <= methlen; i++) {
if (methods[i] == '\0') {
TRACE(("auth method '%s'", tok))
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (strncmp(AUTH_METHOD_PUBKEY, tok,
AUTH_METHOD_PUBKEY_LEN) == 0) {
ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
}
#endif
#ifdef ENABLE_CLI_INTERACT_AUTH
if (strncmp(AUTH_METHOD_INTERACT, tok,
AUTH_METHOD_INTERACT_LEN) == 0) {
ses.authstate.authtypes |= AUTH_TYPE_INTERACT;
}
#endif
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (strncmp(AUTH_METHOD_PASSWORD, tok,
AUTH_METHOD_PASSWORD_LEN) == 0) {
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
}
#endif
tok = &methods[i+1]; /* Must make sure we don't use it after the
last loop, since it'll point to something
undefined */
}
}
m_free(methods);
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 */
ses.authstate.authdone = 1;
cli_ses.state = USERAUTH_SUCCESS_RCVD;
cli_ses.lastauthtype = AUTH_TYPE_NONE;
#ifdef ENABLE_CLI_PUBKEY_AUTH
cli_auth_pubkey_cleanup();
#endif
}
int cli_auth_try() {
int finished = 0;
TRACE(("enter cli_auth_try"))
CHECKCLEARTOWRITE();
/* Order to try is pubkey, interactive, password.
* As soon as "finished" is set for one, we don't do any more. */
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
finished = cli_auth_pubkey();
cli_ses.lastauthtype = AUTH_TYPE_PUBKEY;
}
#endif
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
} else {
cli_auth_password();
finished = 1;
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
}
}
#endif
#ifdef ENABLE_CLI_INTERACT_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
} else {
if (!cli_ses.auth_interact_failed) {
cli_auth_interactive();
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
finished = 1;
}
}
}
#endif
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
if (finished) {
TRACE(("leave cli_auth_try success"))
return DROPBEAR_SUCCESS;
}
TRACE(("leave cli_auth_try failure"))
return DROPBEAR_FAILURE;
}
/* A helper for getpass() that exits if the user cancels. The returned
* password is statically allocated by getpass() */
char* getpass_or_cancel(char* prompt)
{
char* password = NULL;
#ifdef DROPBEAR_PASSWORD_ENV
/* Password provided in an environment var */
password = getenv(DROPBEAR_PASSWORD_ENV);
if (password)
{
return password;
}
#endif
password = getpass(prompt);
/* 0x03 is a ctrl-c character in the buffer. */
if (password == NULL || strchr(password, '\3') != NULL) {
dropbear_close("Interrupted.");
}
return password;
}

175
dropbear/cli-authinteract.c Normal file
View File

@ -0,0 +1,175 @@
/*
* Dropbear SSH
*
* Copyright (c) 2005 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "buffer.h"
#include "dbutil.h"
#include "session.h"
#include "ssh.h"
#include "runopts.h"
#ifdef ENABLE_CLI_INTERACT_AUTH
static unsigned char* get_response(unsigned char* prompt)
{
FILE* tty = NULL;
unsigned char* response = NULL;
/* not a password, but a reasonable limit */
char buf[DROPBEAR_MAX_CLI_PASS];
char* ret = NULL;
fprintf(stderr, "%s", prompt);
tty = fopen(_PATH_TTY, "r");
if (tty) {
ret = fgets(buf, sizeof(buf), tty);
fclose(tty);
} else {
ret = fgets(buf, sizeof(buf), stdin);
}
if (ret == NULL) {
response = (unsigned char*)m_strdup("");
} else {
unsigned int buflen = strlen(buf);
/* fgets includes newlines */
if (buflen > 0 && buf[buflen-1] == '\n')
buf[buflen-1] = '\0';
response = (unsigned char*)m_strdup(buf);
}
m_burn(buf, sizeof(buf));
return response;
}
void recv_msg_userauth_info_request() {
unsigned char *name = NULL;
unsigned char *instruction = NULL;
unsigned int num_prompts = 0;
unsigned int i;
unsigned char *prompt = NULL;
unsigned int echo = 0;
unsigned char *response = NULL;
TRACE(("enter recv_msg_recv_userauth_info_request"))
/* Let the user know what password/host they are authing for */
if (!cli_ses.interact_request_received) {
fprintf(stderr, "Login for %s@%s\n", cli_opts.username,
cli_opts.remotehost);
}
cli_ses.interact_request_received = 1;
name = buf_getstring(ses.payload, NULL);
instruction = buf_getstring(ses.payload, NULL);
/* language tag */
buf_eatstring(ses.payload);
num_prompts = buf_getint(ses.payload);
if (num_prompts >= DROPBEAR_MAX_CLI_INTERACT_PROMPTS) {
dropbear_exit("Too many prompts received for keyboard-interactive");
}
/* we'll build the response as we go */
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_INFO_RESPONSE);
buf_putint(ses.writepayload, num_prompts);
if (strlen(name) > 0) {
cleantext(name);
fprintf(stderr, "%s", name);
}
m_free(name);
if (strlen(instruction) > 0) {
cleantext(instruction);
fprintf(stderr, "%s", instruction);
}
m_free(instruction);
for (i = 0; i < num_prompts; i++) {
unsigned int response_len = 0;
prompt = buf_getstring(ses.payload, NULL);
cleantext(prompt);
echo = buf_getbool(ses.payload);
if (!echo) {
unsigned char* p = getpass_or_cancel(prompt);
response = m_strdup(p);
m_burn(p, strlen(p));
} else {
response = get_response(prompt);
}
response_len = strlen(response);
buf_putstring(ses.writepayload, response, response_len);
m_burn(response, response_len);
m_free(prompt);
m_free(response);
}
encrypt_packet();
TRACE(("leave recv_msg_recv_userauth_info_request"))
}
void cli_auth_interactive() {
TRACE(("enter cli_auth_interactive"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
/* username */
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
/* service name */
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
/* method */
buf_putstring(ses.writepayload, AUTH_METHOD_INTERACT,
AUTH_METHOD_INTERACT_LEN);
/* empty language tag */
buf_putstring(ses.writepayload, "", 0);
/* empty submethods */
buf_putstring(ses.writepayload, "", 0);
encrypt_packet();
cli_ses.interact_request_received = 0;
TRACE(("leave cli_auth_interactive"))
}
#endif /* ENABLE_CLI_INTERACT_AUTH */

161
dropbear/cli-authpasswd.c Normal file
View File

@ -0,0 +1,161 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "buffer.h"
#include "dbutil.h"
#include "session.h"
#include "ssh.h"
#include "runopts.h"
#ifdef ENABLE_CLI_PASSWORD_AUTH
#ifdef ENABLE_CLI_ASKPASS_HELPER
/* Returns 1 if we want to use the askpass program, 0 otherwise */
static int want_askpass()
{
char* askpass_prog = NULL;
askpass_prog = getenv("SSH_ASKPASS");
return askpass_prog &&
((!isatty(STDIN_FILENO) && getenv("DISPLAY") )
|| getenv("SSH_ASKPASS_ALWAYS"));
}
/* returns a statically allocated password from a helper app, or NULL
* on failure */
static char *gui_getpass(const char *prompt) {
pid_t pid;
int p[2], maxlen, len, status;
static char buf[DROPBEAR_MAX_CLI_PASS + 1];
char* helper = NULL;
TRACE(("enter gui_getpass"))
helper = getenv("SSH_ASKPASS");
if (!helper)
{
TRACE(("leave gui_getpass: no askpass program"))
return NULL;
}
if (pipe(p) < 0) {
TRACE(("error creating child pipe"))
return NULL;
}
pid = fork();
if (pid < 0) {
TRACE(("fork error"))
return NULL;
}
if (!pid) {
/* child */
close(p[0]);
if (dup2(p[1], STDOUT_FILENO) < 0) {
TRACE(("error redirecting stdout"))
exit(1);
}
close(p[1]);
execlp(helper, helper, prompt, (char *)0);
TRACE(("execlp error"))
exit(1);
}
close(p[1]);
maxlen = sizeof(buf);
while (maxlen > 0) {
len = read(p[0], buf + sizeof(buf) - maxlen, maxlen);
if (len > 0) {
maxlen -= len;
} else {
if (errno != EINTR)
break;
}
}
close(p[0]);
while (waitpid(pid, &status, 0) < 0 && errno == EINTR)
;
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
return(NULL);
len = sizeof(buf) - maxlen;
buf[len] = '\0';
if (len > 0 && buf[len - 1] == '\n')
buf[len - 1] = '\0';
TRACE(("leave gui_getpass"))
return(buf);
}
#endif /* ENABLE_CLI_ASKPASS_HELPER */
void cli_auth_password() {
char* password = NULL;
char prompt[80];
TRACE(("enter cli_auth_password"))
CHECKCLEARTOWRITE();
snprintf(prompt, sizeof(prompt), "%s@%s's password: ",
cli_opts.username, cli_opts.remotehost);
#ifdef ENABLE_CLI_ASKPASS_HELPER
if (want_askpass())
{
password = gui_getpass(prompt);
if (!password) {
dropbear_exit("No password");
}
} else
#endif
{
password = getpass_or_cancel(prompt);
}
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN);
buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */
buf_putstring(ses.writepayload, password, strlen(password));
encrypt_packet();
m_burn(password, strlen(password));
TRACE(("leave cli_auth_password"))
}
#endif /* ENABLE_CLI_PASSWORD_AUTH */

222
dropbear/cli-authpubkey.c Normal file
View File

@ -0,0 +1,222 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "buffer.h"
#include "dbutil.h"
#include "session.h"
#include "ssh.h"
#include "runopts.h"
#include "auth.h"
#include "agentfwd.h"
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
* We use it to remove the key we tried from the list */
void cli_pubkeyfail() {
m_list_elem *iter;
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
sign_key *iter_key = (sign_key*)iter->item;
if (iter_key == cli_ses.lastprivkey)
{
/* found the failing key */
list_remove(iter);
sign_key_free(iter_key);
cli_ses.lastprivkey = NULL;
return;
}
}
}
void recv_msg_userauth_pk_ok() {
m_list_elem *iter;
buffer* keybuf = NULL;
char* algotype = NULL;
unsigned int algolen;
int keytype;
unsigned int remotelen;
TRACE(("enter recv_msg_userauth_pk_ok"))
algotype = buf_getstring(ses.payload, &algolen);
keytype = signkey_type_from_name(algotype, algolen);
TRACE(("recv_msg_userauth_pk_ok: type %d", keytype))
m_free(algotype);
keybuf = buf_new(MAX_PUBKEY_SIZE);
remotelen = buf_getint(ses.payload);
/* Iterate through our keys, find which one it was that matched, and
* send a real request with that key */
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
sign_key *key = (sign_key*)iter->item;
if (key->type != keytype) {
/* Types differed */
TRACE(("types differed"))
continue;
}
/* Now we compare the contents of the key */
keybuf->pos = keybuf->len = 0;
buf_put_pub_key(keybuf, key, keytype);
buf_setpos(keybuf, 0);
buf_incrpos(keybuf, 4); /* first int is the length of the remainder (ie
remotelen) which has already been taken from
the remote buffer */
if (keybuf->len-4 != remotelen) {
TRACE(("lengths differed: localh %d remote %d", keybuf->len, remotelen))
/* Lengths differed */
continue;
}
if (memcmp(buf_getptr(keybuf, remotelen),
buf_getptr(ses.payload, remotelen), remotelen) != 0) {
/* Data didn't match this key */
TRACE(("data differed"))
continue;
}
/* Success */
break;
}
buf_free(keybuf);
if (iter != NULL) {
TRACE(("matching key"))
/* XXX TODO: if it's an encrypted key, here we ask for their
* password */
send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1);
} else {
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
}
TRACE(("leave recv_msg_userauth_pk_ok"))
}
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
buffer *data_buf) {
#ifdef ENABLE_CLI_AGENTFWD
if (key->source == SIGNKEY_SOURCE_AGENT) {
/* Format the agent signature ourselves, as buf_put_sign would. */
buffer *sigblob;
sigblob = buf_new(MAX_PUBKEY_SIZE);
agent_buf_sign(sigblob, key, data_buf);
buf_putbufstring(buf, sigblob);
buf_free(sigblob);
} else
#endif /* ENABLE_CLI_AGENTFWD */
{
buf_put_sign(buf, key, type, data_buf);
}
}
/* TODO: make it take an agent reference to use as well */
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
const char *algoname = NULL;
int algolen;
buffer* sigbuf = NULL;
TRACE(("enter send_msg_userauth_pubkey"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
AUTH_METHOD_PUBKEY_LEN);
buf_putbyte(ses.writepayload, realsign);
algoname = signkey_name_from_type(type, &algolen);
buf_putstring(ses.writepayload, algoname, algolen);
buf_put_pub_key(ses.writepayload, key, type);
if (realsign) {
TRACE(("realsign"))
/* We put the signature as well - this contains string(session id), then
* the contents of the write payload to this point */
sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len);
buf_putbufstring(sigbuf, ses.session_id);
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
buf_free(sigbuf); /* Nothing confidential in the buffer */
}
encrypt_packet();
TRACE(("leave send_msg_userauth_pubkey"))
}
/* Returns 1 if a key was tried */
int cli_auth_pubkey() {
TRACE(("enter cli_auth_pubkey"))
#ifdef ENABLE_CLI_AGENTFWD
if (!cli_opts.agent_keys_loaded) {
/* get the list of available keys from the agent */
cli_load_agent_keys(cli_opts.privkeys);
cli_opts.agent_keys_loaded = 1;
}
#endif
if (cli_opts.privkeys->first) {
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
/* Send a trial request */
send_msg_userauth_pubkey(key, key->type, 0);
cli_ses.lastprivkey = key;
TRACE(("leave cli_auth_pubkey-success"))
return 1;
} else {
/* no more keys left */
TRACE(("leave cli_auth_pubkey-failure"))
return 0;
}
}
void cli_auth_pubkey_cleanup() {
#ifdef ENABLE_CLI_AGENTFWD
m_close(cli_opts.agent_fd);
cli_opts.agent_fd = -1;
#endif
while (cli_opts.privkeys->first) {
sign_key * key = list_remove(cli_opts.privkeys->first);
sign_key_free(key);
}
}
#endif /* Pubkey auth */

59
dropbear/cli-channel.c Normal file
View File

@ -0,0 +1,59 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002-2004 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "channel.h"
#include "buffer.h"
#include "circbuffer.h"
#include "dbutil.h"
#include "session.h"
#include "ssh.h"
/* We receive channel data - only used by the client chansession code*/
void recv_msg_channel_extended_data() {
struct Channel *channel;
unsigned int datatype;
TRACE(("enter recv_msg_channel_extended_data"))
channel = getchannel();
if (channel->type != &clichansess) {
TRACE(("leave recv_msg_channel_extended_data: chantype is wrong"))
return; /* we just ignore it */
}
datatype = buf_getint(ses.payload);
if (datatype != SSH_EXTENDED_DATA_STDERR) {
TRACE(("leave recv_msg_channel_extended_data: wrong datatype: %d",
datatype))
return;
}
common_recv_msg_channel_data(channel, channel->errfd, channel->extrabuf);
TRACE(("leave recv_msg_channel_extended_data"))
}

488
dropbear/cli-chansession.c Normal file
View File

@ -0,0 +1,488 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "packet.h"
#include "buffer.h"
#include "session.h"
#include "dbutil.h"
#include "channel.h"
#include "ssh.h"
#include "runopts.h"
#include "termcodes.h"
#include "chansession.h"
#include "agentfwd.h"
static void cli_closechansess(struct Channel *channel);
static int cli_initchansess(struct Channel *channel);
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();
const struct ChanType clichansess = {
0, /* sepfds */
"session", /* name */
cli_initchansess, /* inithandler */
NULL, /* checkclosehandler */
cli_chansessreq, /* reqhandler */
cli_closechansess, /* closehandler */
};
static void cli_chansessreq(struct Channel *channel) {
unsigned char* type = NULL;
int wantreply;
TRACE(("enter cli_chansessreq"))
type = buf_getstring(ses.payload, NULL);
wantreply = buf_getbool(ses.payload);
if (strcmp(type, "exit-status") == 0) {
cli_ses.retval = buf_getint(ses.payload);
TRACE(("got exit-status of '%d'", cli_ses.retval))
} else if (strcmp(type, "exit-signal") == 0) {
TRACE(("got exit-signal, ignoring it"))
} else {
TRACE(("unknown request '%s'", type))
if (wantreply) {
send_msg_channel_failure(channel);
}
goto out;
}
out:
m_free(type);
}
/* If the main session goes, we close it up */
static void cli_closechansess(struct Channel *UNUSED(channel)) {
cli_tty_cleanup(); /* Restore tty modes etc */
/* This channel hasn't gone yet, so we have > 1 */
if (ses.chancount > 1) {
dropbear_log(LOG_INFO, "Waiting for other channels to close...");
}
}
/* Taken from OpenSSH's sshtty.c:
* RCSID("OpenBSD: sshtty.c,v 1.5 2003/09/19 17:43:35 markus Exp "); */
static void cli_tty_setup() {
struct termios tio;
TRACE(("enter cli_pty_setup"))
if (cli_ses.tty_raw_mode == 1) {
TRACE(("leave cli_tty_setup: already in raw mode!"))
return;
}
if (tcgetattr(STDIN_FILENO, &tio) == -1) {
dropbear_exit("Failed to set raw TTY mode");
}
/* make a copy */
cli_ses.saved_tio = tio;
tio.c_iflag |= IGNPAR;
tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
#ifdef IUCLC
tio.c_iflag &= ~IUCLC;
#endif
tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
#ifdef IEXTEN
tio.c_lflag &= ~IEXTEN;
#endif
tio.c_oflag &= ~OPOST;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
if (tcsetattr(STDIN_FILENO, TCSADRAIN, &tio) == -1) {
dropbear_exit("Failed to set raw TTY mode");
}
cli_ses.tty_raw_mode = 1;
TRACE(("leave cli_tty_setup"))
}
void cli_tty_cleanup() {
TRACE(("enter cli_tty_cleanup"))
if (cli_ses.tty_raw_mode == 0) {
TRACE(("leave cli_tty_cleanup: not in raw mode"))
return;
}
if (tcsetattr(STDIN_FILENO, TCSADRAIN, &cli_ses.saved_tio) == -1) {
dropbear_log(LOG_WARNING, "Failed restoring TTY");
} else {
cli_ses.tty_raw_mode = 0;
}
TRACE(("leave cli_tty_cleanup"))
}
static void put_termcodes() {
struct termios tio;
unsigned int sshcode;
const struct TermCode *termcode;
unsigned int value;
unsigned int mapcode;
unsigned int bufpos1, bufpos2;
TRACE(("enter put_termcodes"))
if (tcgetattr(STDIN_FILENO, &tio) == -1) {
dropbear_log(LOG_WARNING, "Failed reading termmodes");
buf_putint(ses.writepayload, 1); /* Just the terminator */
buf_putbyte(ses.writepayload, 0); /* TTY_OP_END */
return;
}
bufpos1 = ses.writepayload->pos;
buf_putint(ses.writepayload, 0); /* A placeholder for the final length */
/* As with Dropbear server, we ignore baud rates for now */
for (sshcode = 1; sshcode < MAX_TERMCODE; sshcode++) {
termcode = &termcodes[sshcode];
mapcode = termcode->mapcode;
switch (termcode->type) {
case TERMCODE_NONE:
continue;
case TERMCODE_CONTROLCHAR:
value = tio.c_cc[mapcode];
break;
case TERMCODE_INPUT:
value = tio.c_iflag & mapcode;
break;
case TERMCODE_OUTPUT:
value = tio.c_oflag & mapcode;
break;
case TERMCODE_LOCAL:
value = tio.c_lflag & mapcode;
break;
case TERMCODE_CONTROL:
value = tio.c_cflag & mapcode;
break;
default:
continue;
}
/* If we reach here, we have something to say */
buf_putbyte(ses.writepayload, sshcode);
buf_putint(ses.writepayload, value);
}
buf_putbyte(ses.writepayload, 0); /* THE END, aka TTY_OP_END */
/* Put the string length at the start of the buffer */
bufpos2 = ses.writepayload->pos;
buf_setpos(ses.writepayload, bufpos1); /* Jump back */
buf_putint(ses.writepayload, bufpos2 - bufpos1 - 4); /* len(termcodes) */
buf_setpos(ses.writepayload, bufpos2); /* Back where we were */
TRACE(("leave put_termcodes"))
}
static void put_winsize() {
struct winsize ws;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
/* Some sane defaults */
ws.ws_row = 25;
ws.ws_col = 80;
ws.ws_xpixel = 0;
ws.ws_ypixel = 0;
}
buf_putint(ses.writepayload, ws.ws_col); /* Cols */
buf_putint(ses.writepayload, ws.ws_row); /* Rows */
buf_putint(ses.writepayload, ws.ws_xpixel); /* Width */
buf_putint(ses.writepayload, ws.ws_ypixel); /* Height */
}
static void sigwinch_handler(int UNUSED(unused)) {
cli_ses.winchange = 1;
}
void cli_chansess_winchange() {
unsigned int i;
struct Channel *channel = NULL;
for (i = 0; i < ses.chansize; i++) {
channel = ses.channels[i];
if (channel != NULL && channel->type == &clichansess) {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
buf_putint(ses.writepayload, channel->remotechan);
buf_putstring(ses.writepayload, "window-change", 13);
buf_putbyte(ses.writepayload, 0); /* FALSE says the spec */
put_winsize();
encrypt_packet();
}
}
cli_ses.winchange = 0;
}
static void send_chansess_pty_req(struct Channel *channel) {
unsigned char* term = NULL;
TRACE(("enter send_chansess_pty_req"))
start_send_channel_request(channel, "pty-req");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
/* Get the terminal */
term = getenv("TERM");
if (term == NULL) {
term = "vt100"; /* Seems a safe default */
}
buf_putstring(ses.writepayload, term, strlen(term));
/* Window size */
put_winsize();
/* Terminal mode encoding */
put_termcodes();
encrypt_packet();
/* Set up a window-change handler */
if (signal(SIGWINCH, sigwinch_handler) == SIG_ERR) {
dropbear_exit("Signal error");
}
TRACE(("leave send_chansess_pty_req"))
}
static void send_chansess_shell_req(struct Channel *channel) {
unsigned char* reqtype = NULL;
TRACE(("enter send_chansess_shell_req"))
if (cli_opts.cmd) {
if (cli_opts.is_subsystem) {
reqtype = "subsystem";
} else {
reqtype = "exec";
}
} else {
reqtype = "shell";
}
start_send_channel_request(channel, reqtype);
/* XXX TODO */
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
if (cli_opts.cmd) {
buf_putstring(ses.writepayload, cli_opts.cmd, strlen(cli_opts.cmd));
}
encrypt_packet();
TRACE(("leave send_chansess_shell_req"))
}
/* Shared for normal client channel and netcat-alike */
static int cli_init_stdpipe_sess(struct Channel *channel) {
channel->writefd = STDOUT_FILENO;
setnonblocking(STDOUT_FILENO);
channel->readfd = STDIN_FILENO;
setnonblocking(STDIN_FILENO);
channel->errfd = STDERR_FILENO;
setnonblocking(STDERR_FILENO);
channel->extrabuf = cbuf_new(opts.recv_window);
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);
#ifdef ENABLE_CLI_AGENTFWD
if (cli_opts.agent_fwd) {
cli_setup_agent(channel);
}
#endif
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);
if (cli_opts.wantpty) {
cli_tty_setup();
channel->read_mangler = cli_escape_handler;
cli_ses.last_char = '\r';
}
return 0; /* Success */
}
#ifdef ENABLE_CLI_NETCAT
static const struct ChanType cli_chan_netcat = {
0, /* sepfds */
"direct-tcpip",
cli_init_netcat, /* inithandler */
NULL,
NULL,
cli_closechansess
};
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)
== DROPBEAR_FAILURE) {
dropbear_exit("Couldn't open initial channel");
}
buf_putstring(ses.writepayload, cli_opts.netcat_host,
strlen(cli_opts.netcat_host));
buf_putint(ses.writepayload, cli_opts.netcat_port);
/* originator ip - localhost is accurate enough */
buf_putstring(ses.writepayload, source_host, strlen(source_host));
buf_putint(ses.writepayload, source_port);
encrypt_packet();
TRACE(("leave cli_send_netcat_request"))
}
#endif
void cli_send_chansess_request() {
TRACE(("enter cli_send_chansess_request"))
if (send_msg_channel_open_init(STDIN_FILENO, &clichansess)
== DROPBEAR_FAILURE) {
dropbear_exit("Couldn't open initial channel");
}
/* No special channel request data */
encrypt_packet();
TRACE(("leave cli_send_chansess_request"))
}
/* returns 1 if the character should be consumed, 0 to pass through */
static int
do_escape(unsigned char c) {
switch (c) {
case '.':
dropbear_exit("Terminated");
return 1;
break;
case 0x1a:
/* ctrl-z */
cli_tty_cleanup();
kill(getpid(), SIGTSTP);
/* after continuation */
cli_tty_setup();
cli_ses.winchange = 1;
return 1;
break;
}
return 0;
}
static
void cli_escape_handler(struct Channel* UNUSED(channel), unsigned char* buf, int *len) {
char c;
int skip_char = 0;
/* only handle escape characters if they are read one at a time. simplifies
the code and avoids nasty people putting ~. at the start of a line to paste */
if (*len != 1) {
cli_ses.last_char = 0x0;
return;
}
c = buf[0];
if (cli_ses.last_char == DROPBEAR_ESCAPE_CHAR) {
skip_char = do_escape(c);
cli_ses.last_char = 0x0;
} else {
if (c == DROPBEAR_ESCAPE_CHAR) {
if (cli_ses.last_char == '\r') {
cli_ses.last_char = DROPBEAR_ESCAPE_CHAR;
skip_char = 1;
} else {
cli_ses.last_char = 0x0;
}
} else {
cli_ses.last_char = c;
}
}
if (skip_char) {
*len = 0;
}
}

408
dropbear/cli-kex.c Normal file
View File

@ -0,0 +1,408 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002-2004 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "session.h"
#include "dbutil.h"
#include "algo.h"
#include "buffer.h"
#include "session.h"
#include "kex.h"
#include "ssh.h"
#include "packet.h"
#include "bignum.h"
#include "dbrandom.h"
#include "runopts.h"
#include "signkey.h"
#include "ecc.h"
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
#define MAX_KNOWNHOSTS_LINE 4500
void send_msg_kexdh_init() {
TRACE(("send_msg_kexdh_init()"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
switch (ses.newkeys->algo_kex->mode) {
case DROPBEAR_KEX_NORMAL_DH:
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|| !cli_ses.dh_param) {
if (cli_ses.dh_param) {
free_kexdh_param(cli_ses.dh_param);
}
cli_ses.dh_param = gen_kexdh_param();
}
buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
break;
case DROPBEAR_KEX_ECDH:
#ifdef DROPBEAR_ECDH
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|| !cli_ses.ecdh_param) {
if (cli_ses.ecdh_param) {
free_kexecdh_param(cli_ses.ecdh_param);
}
cli_ses.ecdh_param = gen_kexecdh_param();
}
buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
#endif
break;
#ifdef DROPBEAR_CURVE25519
case DROPBEAR_KEX_CURVE25519:
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|| !cli_ses.curve25519_param) {
if (cli_ses.curve25519_param) {
free_kexcurve25519_param(cli_ses.curve25519_param);
}
cli_ses.curve25519_param = gen_kexcurve25519_param();
}
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
#endif
break;
}
cli_ses.param_kex_algo = ses.newkeys->algo_kex;
encrypt_packet();
}
/* Handle a diffie-hellman key exchange reply. */
void recv_msg_kexdh_reply() {
sign_key *hostkey = NULL;
unsigned int type, keybloblen;
unsigned char* keyblob = NULL;
TRACE(("enter recv_msg_kexdh_reply"))
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
dropbear_exit("Received out-of-order kexdhreply");
}
type = ses.newkeys->algo_hostkey;
TRACE(("type is %d", type))
hostkey = new_sign_key();
keybloblen = buf_getint(ses.payload);
keyblob = buf_getptr(ses.payload, keybloblen);
if (!ses.kexstate.donefirstkex) {
/* Only makes sense the first time */
checkhostkey(keyblob, keybloblen);
}
if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
TRACE(("failed getting pubkey"))
dropbear_exit("Bad KEX packet");
}
switch (ses.newkeys->algo_kex->mode) {
case DROPBEAR_KEX_NORMAL_DH:
{
DEF_MP_INT(dh_f);
m_mp_init(&dh_f);
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
TRACE(("failed getting mpint"))
dropbear_exit("Bad KEX packet");
}
kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
mp_clear(&dh_f);
}
break;
case DROPBEAR_KEX_ECDH:
#ifdef DROPBEAR_ECDH
{
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
buf_free(ecdh_qs);
}
#endif
break;
#ifdef DROPBEAR_CURVE25519
case DROPBEAR_KEX_CURVE25519:
{
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey);
buf_free(ecdh_qs);
}
#endif
break;
}
if (cli_ses.dh_param) {
free_kexdh_param(cli_ses.dh_param);
cli_ses.dh_param = NULL;
}
#ifdef DROPBEAR_ECDH
if (cli_ses.ecdh_param) {
free_kexecdh_param(cli_ses.ecdh_param);
cli_ses.ecdh_param = NULL;
}
#endif
#ifdef DROPBEAR_CURVE25519
if (cli_ses.curve25519_param) {
free_kexcurve25519_param(cli_ses.curve25519_param);
cli_ses.curve25519_param = NULL;
}
#endif
cli_ses.param_kex_algo = NULL;
if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
dropbear_exit("Bad hostkey signature");
}
sign_key_free(hostkey);
hostkey = NULL;
send_msg_newkeys();
ses.requirenext = SSH_MSG_NEWKEYS;
TRACE(("leave recv_msg_kexdh_init"))
}
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen,
const char* algoname) {
char* fp = NULL;
FILE *tty = NULL;
char response = 'z';
fp = sign_key_fingerprint(keyblob, keybloblen);
if (cli_opts.always_accept_key) {
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
cli_opts.remotehost,
algoname,
fp);
m_free(fp);
return;
}
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(%s fingerprint %s)\nDo you want to continue connecting? (y/n) ",
cli_opts.remotehost,
algoname,
fp);
m_free(fp);
tty = fopen(_PATH_TTY, "r");
if (tty) {
response = getc(tty);
fclose(tty);
} else {
response = getc(stdin);
}
if (response == 'y') {
return;
}
dropbear_exit("Didn't validate host key");
}
static FILE* open_known_hosts_file(int * readonly)
{
FILE * hostsfile = NULL;
char * filename = NULL;
char * homedir = NULL;
homedir = getenv("HOME");
if (!homedir) {
struct passwd * pw = NULL;
pw = getpwuid(getuid());
if (pw) {
homedir = pw->pw_dir;
}
}
if (homedir) {
unsigned int len;
len = strlen(homedir);
filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/
snprintf(filename, len+18, "%s/.ssh", homedir);
/* Check that ~/.ssh exists - easiest way is just to mkdir */
if (mkdir(filename, S_IRWXU) != 0) {
if (errno != EEXIST) {
dropbear_log(LOG_INFO, "Warning: failed creating %s/.ssh: %s",
homedir, strerror(errno));
TRACE(("mkdir didn't work: %s", strerror(errno)))
goto out;
}
}
snprintf(filename, len+18, "%s/.ssh/known_hosts", homedir);
hostsfile = fopen(filename, "a+");
if (hostsfile != NULL) {
*readonly = 0;
fseek(hostsfile, 0, SEEK_SET);
} else {
/* We mightn't have been able to open it if it was read-only */
if (errno == EACCES || errno == EROFS) {
TRACE(("trying readonly: %s", strerror(errno)))
*readonly = 1;
hostsfile = fopen(filename, "r");
}
}
}
if (hostsfile == NULL) {
TRACE(("hostsfile didn't open: %s", strerror(errno)))
dropbear_log(LOG_WARNING, "Failed to open %s/.ssh/known_hosts",
homedir);
goto out;
}
out:
m_free(filename);
return hostsfile;
}
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
FILE *hostsfile = NULL;
int readonly = 0;
unsigned int hostlen, algolen;
unsigned long len;
const char *algoname = NULL;
char * fingerprint = NULL;
buffer * line = NULL;
int ret;
if (cli_opts.no_hostkey_check) {
fprintf(stderr, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost);
return;
}
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
hostsfile = open_known_hosts_file(&readonly);
if (!hostsfile) {
ask_to_confirm(keyblob, keybloblen, algoname);
/* ask_to_confirm will exit upon failure */
return;
}
line = buf_new(MAX_KNOWNHOSTS_LINE);
hostlen = strlen(cli_opts.remotehost);
do {
if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
TRACE(("failed reading line: prob EOF"))
break;
}
/* The line is too short to be sensible */
/* "30" is 'enough to hold ssh-dss plus the spaces, ie so we don't
* buf_getfoo() past the end and die horribly - the base64 parsing
* code is what tiptoes up to the end nicely */
if (line->len < (hostlen+30) ) {
TRACE(("line is too short to be sensible"))
continue;
}
/* Compare hostnames */
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
hostlen) != 0) {
continue;
}
buf_incrpos(line, hostlen);
if (buf_getbyte(line) != ' ') {
/* there wasn't a space after the hostname, something dodgy */
TRACE(("missing space afte matching hostname"))
continue;
}
if (strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) {
TRACE(("algo doesn't match"))
continue;
}
buf_incrpos(line, algolen);
if (buf_getbyte(line) != ' ') {
TRACE(("missing space after algo"))
continue;
}
/* Now we're at the interesting hostkey */
ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen,
line, &fingerprint);
if (ret == DROPBEAR_SUCCESS) {
/* Good matching key */
TRACE(("good matching key"))
goto out;
}
/* The keys didn't match. eep. Note that we're "leaking"
the fingerprint strings here, but we're exiting anyway */
dropbear_exit("\n\n%s host key mismatch for %s !\n"
"Fingerprint is %s\n"
"Expected %s\n"
"If you know that the host key is correct you can\nremove the bad entry from ~/.ssh/known_hosts",
algoname,
cli_opts.remotehost,
sign_key_fingerprint(keyblob, keybloblen),
fingerprint ? fingerprint : "UNKNOWN");
} while (1); /* keep going 'til something happens */
/* Key doesn't exist yet */
ask_to_confirm(keyblob, keybloblen, algoname);
/* If we get here, they said yes */
if (readonly) {
TRACE(("readonly"))
goto out;
}
if (!cli_opts.always_accept_key) {
/* put the new entry in the file */
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
buf_setpos(line, 0);
buf_setlen(line, 0);
buf_putbytes(line, cli_opts.remotehost, hostlen);
buf_putbyte(line, ' ');
buf_putbytes(line, algoname, algolen);
buf_putbyte(line, ' ');
len = line->size - line->pos;
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
* will die horribly in the case anyway */
base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);
buf_incrwritepos(line, len);
buf_putbyte(line, '\n');
buf_setpos(line, 0);
fwrite(buf_getptr(line, line->len), line->len, 1, hostsfile);
/* We ignore errors, since there's not much we can do about them */
}
out:
if (hostsfile != NULL) {
fclose(hostsfile);
}
if (line != NULL) {
buf_free(line);
}
m_free(fingerprint);
}

147
dropbear/cli-main.c Normal file
View File

@ -0,0 +1,147 @@
/*
* Dropbear - a SSH2 server
* SSH client implementation
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
#include "runopts.h"
#include "session.h"
#include "dbrandom.h"
#include "crypto_desc.h"
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
static void cli_dropbear_log(int priority, const char* format, va_list param);
#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out);
#endif
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
int cli_main(int argc, char ** argv) {
#else
int main(int argc, char ** argv) {
#endif
int sock_in, sock_out;
char* error = NULL;
_dropbear_exit = cli_dropbear_exit;
_dropbear_log = cli_dropbear_log;
disallow_core();
seedrandom();
crypto_init();
cli_getopts(argc, argv);
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport))
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
dropbear_exit("signal() error");
}
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
cli_proxy_cmd(&sock_in, &sock_out);
m_free(cli_opts.proxycmd);
} else
#endif
{
int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
0, &error);
sock_in = sock_out = sock;
}
if (sock_in < 0) {
dropbear_exit("%s", error);
}
cli_session(sock_in, sock_out);
/* not reached */
return -1;
}
#endif /* DBMULTI stuff */
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
char fmtbuf[300];
if (!sessinitdone) {
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
format);
} else {
snprintf(fmtbuf, sizeof(fmtbuf),
"Connection to %s@%s:%s exited: %s",
cli_opts.username, cli_opts.remotehost,
cli_opts.remoteport, format);
}
/* 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);
}
static void cli_dropbear_log(int UNUSED(priority),
const char* format, va_list param) {
char printbuf[1024];
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) {
const char *cmd = user_data_cmd;
char *usershell;
usershell = m_strdup(get_user_shell());
run_shell_command(cmd, ses.maxfd, usershell);
dropbear_exit("Failed to run '%s'\n", cmd);
}
#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out) {
int ret;
fill_passwd(cli_opts.own_user);
ret = spawn_command(exec_proxy_cmd, cli_opts.proxycmd,
sock_out, sock_in, NULL, NULL);
if (ret == DROPBEAR_FAILURE) {
dropbear_exit("Failed running proxy command");
*sock_in = *sock_out = -1;
}
}
#endif /* ENABLE_CLI_PROXYCMD */

789
dropbear/cli-runopts.c Normal file
View File

@ -0,0 +1,789 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "runopts.h"
#include "signkey.h"
#include "buffer.h"
#include "dbutil.h"
#include "algo.h"
#include "tcpfwd.h"
#include "list.h"
cli_runopts cli_opts; /* GLOBAL */
static void printhelp();
static void parse_hostname(const char* orighostarg);
static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
static void fill_own_user();
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename);
#endif
#ifdef ENABLE_CLI_ANYTCPFWD
static void addforward(const char* str, m_list *fwdlist);
#endif
#ifdef ENABLE_CLI_NETCAT
static void add_netcat(const char *str);
#endif
static void printhelp() {
fprintf(stderr, "Dropbear SSH client v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
#ifdef ENABLE_CLI_MULTIHOP
"Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n"
#else
"Usage: %s [options] [user@]host[/port] [command]\n"
#endif
"-p <remoteport>\n"
"-l <username>\n"
"-t Allocate a pty\n"
"-T Don't allocate a pty\n"
"-N Don't run a remote command\n"
"-f Run in background after auth\n"
"-y Always accept remote host key if unknown\n"
"-y -y Don't perform any remote host key checking (caution)\n"
"-s Request a subsystem (use by external sftp)\n"
#ifdef ENABLE_CLI_PUBKEY_AUTH
"-i <identityfile> (multiple allowed)\n"
#endif
#ifdef ENABLE_CLI_AGENTFWD
"-A Enable agent auth forwarding\n"
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
"-L <[listenaddress:]listenport:remotehost:remoteport> Local port forwarding\n"
"-g Allow remote hosts to connect to forwarded ports\n"
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
"-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n"
#endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
"-I <idle_timeout> (0 is never, default %d)\n"
#ifdef ENABLE_CLI_NETCAT
"-B <endhost:endport> Netcat-alike forwarding\n"
#endif
#ifdef ENABLE_CLI_PROXYCMD
"-J <proxy_program> Use program pipe rather than TCP connection\n"
#endif
#ifdef ENABLE_USER_ALGO_LIST
"-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
,DROPBEAR_VERSION, cli_opts.progname,
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
}
void cli_getopts(int argc, char ** argv) {
unsigned int i, j;
char ** next = 0;
unsigned int cmdlen;
#ifdef ENABLE_CLI_PUBKEY_AUTH
int nextiskey = 0; /* A flag if the next argument is a keyfile */
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
int nextislocal = 0;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
int nextisremote = 0;
#endif
#ifdef ENABLE_CLI_NETCAT
int nextisnetcat = 0;
#endif
char* dummy = NULL; /* Not used for anything real */
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char *host_arg = NULL;
/* see printhelp() for options */
cli_opts.progname = argv[0];
cli_opts.remotehost = NULL;
cli_opts.remoteport = NULL;
cli_opts.username = NULL;
cli_opts.cmd = NULL;
cli_opts.no_cmd = 0;
cli_opts.backgrounded = 0;
cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
cli_opts.always_accept_key = 0;
cli_opts.no_hostkey_check = 0;
cli_opts.is_subsystem = 0;
#ifdef ENABLE_CLI_PUBKEY_AUTH
cli_opts.privkeys = list_new();
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
cli_opts.localfwds = list_new();
opts.listen_fwd_all = 0;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
cli_opts.remotefwds = list_new();
#endif
#ifdef ENABLE_CLI_AGENTFWD
cli_opts.agent_fwd = 0;
cli_opts.agent_fd = -1;
cli_opts.agent_keys_loaded = 0;
#endif
#ifdef ENABLE_CLI_PROXYCMD
cli_opts.proxycmd = NULL;
#endif
#ifndef DISABLE_ZLIB
opts.enable_compress = 1;
#endif
#ifdef ENABLE_USER_ALGO_LIST
opts.cipher_list = NULL;
opts.mac_list = NULL;
#endif
/* not yet
opts.ipv4 = 1;
opts.ipv6 = 1;
*/
opts.recv_window = DEFAULT_RECV_WINDOW;
opts.keepalive_secs = DEFAULT_KEEPALIVE;
opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
fill_own_user();
/* Iterate all the arguments */
for (i = 1; i < (unsigned int)argc; i++) {
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (nextiskey) {
/* Load a hostkey since the previous argument was "-i" */
loadidentityfile(argv[i]);
nextiskey = 0;
continue;
}
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
if (nextisremote) {
TRACE(("nextisremote true"))
addforward(argv[i], cli_opts.remotefwds);
nextisremote = 0;
continue;
}
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
if (nextislocal) {
TRACE(("nextislocal true"))
addforward(argv[i], cli_opts.localfwds);
nextislocal = 0;
continue;
}
#endif
#ifdef ENABLE_CLI_NETCAT
if (nextisnetcat) {
TRACE(("nextisnetcat true"))
add_netcat(argv[i]);
nextisnetcat = 0;
continue;
}
#endif
if (next) {
/* The previous flag set a value to assign */
*next = argv[i];
if (*next == NULL) {
dropbear_exit("Invalid null argument");
}
next = NULL;
continue;
}
if (argv[i][0] == '-') {
/* A flag *waves* */
switch (argv[i][1]) {
case 'y': /* always accept the remote hostkey */
if (cli_opts.always_accept_key) {
/* twice means no checking at all */
cli_opts.no_hostkey_check = 1;
}
cli_opts.always_accept_key = 1;
break;
case 'p': /* remoteport */
next = &cli_opts.remoteport;
break;
#ifdef ENABLE_CLI_PUBKEY_AUTH
case 'i': /* an identityfile */
/* Keep scp happy when it changes "-i file" to "-ifile" */
if (strlen(argv[i]) > 2) {
loadidentityfile(&argv[i][2]);
} else {
nextiskey = 1;
}
break;
#endif
case 't': /* we want a pty */
cli_opts.wantpty = 1;
break;
case 'T': /* don't want a pty */
cli_opts.wantpty = 0;
break;
case 'N':
cli_opts.no_cmd = 1;
break;
case 'f':
cli_opts.backgrounded = 1;
break;
case 's':
cli_opts.is_subsystem = 1;
break;
#ifdef ENABLE_CLI_LOCALTCPFWD
case 'L':
nextislocal = 1;
break;
case 'g':
opts.listen_fwd_all = 1;
break;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
case 'R':
nextisremote = 1;
break;
#endif
#ifdef ENABLE_CLI_NETCAT
case 'B':
nextisnetcat = 1;
break;
#endif
#ifdef ENABLE_CLI_PROXYCMD
case 'J':
next = &cli_opts.proxycmd;
break;
#endif
case 'l':
next = &cli_opts.username;
break;
case 'h':
printhelp();
exit(EXIT_SUCCESS);
break;
case 'u':
/* backwards compatibility with old urandom option */
break;
case 'W':
next = &recv_window_arg;
break;
case 'K':
next = &keepalive_arg;
break;
case 'I':
next = &idle_timeout_arg;
break;
#ifdef ENABLE_CLI_AGENTFWD
case 'A':
cli_opts.agent_fwd = 1;
break;
#endif
#ifdef ENABLE_USER_ALGO_LIST
case 'c':
next = &opts.cipher_list;
break;
case 'm':
next = &opts.mac_list;
break;
#endif
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
break;
#endif
case 'F':
case 'e':
#ifndef ENABLE_USER_ALGO_LIST
case 'c':
case 'm':
#endif
case 'D':
#ifndef ENABLE_CLI_REMOTETCPFWD
case 'R':
#endif
#ifndef ENABLE_CLI_LOCALTCPFWD
case 'L':
#endif
case 'V':
print_version();
exit(EXIT_SUCCESS);
break;
case 'o':
case 'b':
next = &dummy;
default:
fprintf(stderr,
"WARNING: Ignoring unknown argument '%s'\n", argv[i]);
break;
} /* Switch */
/* Now we handle args where they might be "-luser" (no spaces)*/
if (next && strlen(argv[i]) > 2) {
*next = &argv[i][2];
next = NULL;
}
continue; /* next argument */
} else {
TRACE(("non-flag arg: '%s'", argv[i]))
/* Either the hostname or commands */
if (host_arg == NULL) {
host_arg = argv[i];
} else {
/* this is part of the commands to send - after this we
* don't parse any more options, and flags are sent as the
* command */
cmdlen = 0;
for (j = i; j < (unsigned int)argc; j++) {
cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
}
/* Allocate the space */
cli_opts.cmd = (char*)m_malloc(cmdlen);
cli_opts.cmd[0] = '\0';
/* Append all the bits */
for (j = i; j < (unsigned int)argc; j++) {
strlcat(cli_opts.cmd, argv[j], cmdlen);
strlcat(cli_opts.cmd, " ", cmdlen);
}
/* It'll be null-terminated here */
/* We've eaten all the options and flags */
break;
}
}
}
/* And now a few sanity checks and setup */
#ifdef ENABLE_USER_ALGO_LIST
parse_ciphers_macs();
#endif
if (host_arg == NULL) {
printhelp();
exit(EXIT_FAILURE);
}
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
/* To match the common path of m_freeing it */
cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
}
#endif
if (cli_opts.remoteport == NULL) {
cli_opts.remoteport = "22";
}
/* If not explicitly specified with -t or -T, we don't want a pty if
* there's a command, but we do otherwise */
if (cli_opts.wantpty == 9) {
if (cli_opts.cmd == NULL) {
cli_opts.wantpty = 1;
} else {
cli_opts.wantpty = 0;
}
}
if (cli_opts.backgrounded && cli_opts.cmd == NULL
&& cli_opts.no_cmd == 0) {
dropbear_exit("Command required for -f");
}
if (recv_window_arg) {
opts.recv_window = atol(recv_window_arg);
if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
dropbear_exit("Bad recv window '%s'", recv_window_arg);
}
}
if (keepalive_arg) {
unsigned int val;
if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
}
opts.keepalive_secs = val;
}
if (idle_timeout_arg) {
unsigned int val;
if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
}
opts.idle_timeout_secs = val;
}
#ifdef ENABLE_CLI_NETCAT
if (cli_opts.cmd && cli_opts.netcat_host) {
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
#ifdef ENABLE_CLI_MULTIHOP
parse_multihop_hostname(host_arg, argv[0]);
#else
parse_hostname(host_arg);
#endif
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename) {
sign_key *key;
enum signkey_type keytype;
key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY;
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
sign_key_free(key);
} else {
key->type = keytype;
key->source = SIGNKEY_SOURCE_RAW_FILE;
key->filename = m_strdup(filename);
list_append(cli_opts.privkeys, key);
}
}
#endif
#ifdef ENABLE_CLI_MULTIHOP
static char*
multihop_passthrough_args() {
char *ret;
int total;
unsigned int len = 0;
m_list_elem *iter;
/* Fill out -i, -y, -W options that make sense for all
* the intermediate processes */
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
len += 3 + strlen(key->filename);
}
len += 30; /* space for -W <size>, terminator. */
ret = m_malloc(len);
total = 0;
if (cli_opts.no_hostkey_check)
{
int written = snprintf(ret+total, len-total, "-y -y ");
total += written;
}
else if (cli_opts.always_accept_key)
{
int written = snprintf(ret+total, len-total, "-y ");
total += written;
}
if (opts.recv_window != DEFAULT_RECV_WINDOW)
{
int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window);
total += written;
}
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
const size_t size = len - total;
int written = snprintf(ret+total, size, "-i %s ", key->filename);
dropbear_assert((unsigned int)written < size);
total += written;
}
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
if (total > 0)
{
total--;
}
return ret;
}
/* Sets up 'onion-forwarding' connections. This will spawn
* a separate dbclient process for each hop.
* As an example, if the cmdline is
* dbclient wrt,madako,canyons
* then we want to run:
* dbclient -J "dbclient -B canyons:22 wrt,madako" canyons
* and then the inner dbclient will recursively run:
* dbclient -J "dbclient -B madako:22 wrt" madako
* etc for as many hosts as we want.
*
* Ports for hosts can be specified as host/port.
*/
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
char *userhostarg = NULL;
char *hostbuf = NULL;
char *last_hop = NULL;
char *remainder = NULL;
/* both scp and rsync parse a user@host argument
* and turn it into "-l user host". This breaks
* for our multihop syntax, so we suture it back together.
* This will break usernames that have both '@' and ',' in them,
* though that should be fairly uncommon. */
if (cli_opts.username
&& strchr(cli_opts.username, ',')
&& strchr(cli_opts.username, '@')) {
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
hostbuf = m_malloc(len);
snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
} else {
hostbuf = m_strdup(orighostarg);
}
userhostarg = hostbuf;
last_hop = strrchr(userhostarg, ',');
if (last_hop) {
if (last_hop == userhostarg) {
dropbear_exit("Bad multi-hop hostnames");
}
*last_hop = '\0';
last_hop++;
remainder = userhostarg;
userhostarg = last_hop;
}
parse_hostname(userhostarg);
if (last_hop) {
/* Set up the proxycmd */
unsigned int cmd_len = 0;
char *passthrough_args = multihop_passthrough_args();
if (cli_opts.proxycmd) {
dropbear_exit("-J can't be used with multihop mode");
}
if (cli_opts.remoteport == NULL) {
cli_opts.remoteport = "22";
}
cmd_len = strlen(argv0) + strlen(remainder)
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
+ strlen(passthrough_args)
+ 30;
cli_opts.proxycmd = m_malloc(cmd_len);
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport,
passthrough_args, remainder);
#ifndef DISABLE_ZLIB
/* The stream will be incompressible since it's encrypted. */
opts.enable_compress = 0;
#endif
m_free(passthrough_args);
}
m_free(hostbuf);
}
#endif /* !ENABLE_CLI_MULTIHOP */
/* Parses a [user@]hostname[/port] argument. */
static void parse_hostname(const char* orighostarg) {
char *userhostarg = NULL;
char *port = NULL;
userhostarg = m_strdup(orighostarg);
cli_opts.remotehost = strchr(userhostarg, '@');
if (cli_opts.remotehost == NULL) {
/* no username portion, the cli-auth.c code can figure the
* local user's name */
cli_opts.remotehost = userhostarg;
} else {
cli_opts.remotehost[0] = '\0'; /* Split the user/host */
cli_opts.remotehost++;
cli_opts.username = userhostarg;
}
if (cli_opts.username == NULL) {
cli_opts.username = m_strdup(cli_opts.own_user);
}
port = strchr(cli_opts.remotehost, '^');
if (!port) {
/* legacy separator */
port = strchr(cli_opts.remotehost, '/');
}
if (port) {
*port = '\0';
cli_opts.remoteport = port+1;
}
if (cli_opts.remotehost[0] == '\0') {
dropbear_exit("Bad hostname");
}
}
#ifdef ENABLE_CLI_NETCAT
static void add_netcat(const char* origstr) {
char *portstr = NULL;
char * str = m_strdup(origstr);
portstr = strchr(str, ':');
if (portstr == NULL) {
TRACE(("No netcat port"))
goto fail;
}
*portstr = '\0';
portstr++;
if (strchr(portstr, ':')) {
TRACE(("Multiple netcat colons"))
goto fail;
}
if (m_str_to_uint(portstr, &cli_opts.netcat_port) == DROPBEAR_FAILURE) {
TRACE(("bad netcat port"))
goto fail;
}
if (cli_opts.netcat_port > 65535) {
TRACE(("too large netcat port"))
goto fail;
}
cli_opts.netcat_host = str;
return;
fail:
dropbear_exit("Bad netcat endpoint '%s'", origstr);
}
#endif
static void fill_own_user() {
uid_t uid;
struct passwd *pw = NULL;
uid = getuid();
pw = getpwuid(uid);
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");
}
}
#ifdef ENABLE_CLI_ANYTCPFWD
/* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
* set, and add it to the forwarding list */
static void addforward(const char* origstr, m_list *fwdlist) {
char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL;
char * listenaddr = NULL;
char * listenport = NULL;
char * connectaddr = NULL;
char * connectport = NULL;
struct TCPFwdEntry* newfwd = NULL;
char * str = NULL;
TRACE(("enter addforward"))
/* We need to split the original argument up. This var
is never free()d. */
str = m_strdup(origstr);
part1 = str;
part2 = strchr(str, ':');
if (part2 == NULL) {
TRACE(("part2 == NULL"))
goto fail;
}
*part2 = '\0';
part2++;
part3 = strchr(part2, ':');
if (part3 == NULL) {
TRACE(("part3 == NULL"))
goto fail;
}
*part3 = '\0';
part3++;
part4 = strchr(part3, ':');
if (part4) {
*part4 = '\0';
part4++;
}
if (part4) {
listenaddr = part1;
listenport = part2;
connectaddr = part3;
connectport = part4;
} else {
listenaddr = NULL;
listenport = part1;
connectaddr = part2;
connectport = part3;
}
newfwd = m_malloc(sizeof(struct TCPFwdEntry));
/* Now we check the ports - note that the port ints are unsigned,
* the check later only checks for >= MAX_PORT */
if (m_str_to_uint(listenport, &newfwd->listenport) == DROPBEAR_FAILURE) {
TRACE(("bad listenport strtoul"))
goto fail;
}
if (m_str_to_uint(connectport, &newfwd->connectport) == DROPBEAR_FAILURE) {
TRACE(("bad connectport strtoul"))
goto fail;
}
newfwd->listenaddr = listenaddr;
newfwd->connectaddr = connectaddr;
if (newfwd->listenport > 65535) {
TRACE(("listenport > 65535"))
goto badport;
}
if (newfwd->connectport > 65535) {
TRACE(("connectport > 65535"))
goto badport;
}
newfwd->have_reply = 0;
list_append(fwdlist, newfwd);
TRACE(("leave addforward: done"))
return;
fail:
dropbear_exit("Bad TCP forward '%s'", origstr);
badport:
dropbear_exit("Bad TCP port in '%s'", origstr);
}
#endif

382
dropbear/cli-session.c Normal file
View File

@ -0,0 +1,382 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "session.h"
#include "dbutil.h"
#include "kex.h"
#include "ssh.h"
#include "packet.h"
#include "tcpfwd.h"
#include "channel.h"
#include "dbrandom.h"
#include "service.h"
#include "runopts.h"
#include "chansession.h"
#include "agentfwd.h"
#include "crypto_desc.h"
static void cli_remoteclosed();
static void cli_sessionloop();
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 */
/* Sorted in decreasing frequency will be more efficient - data and window
* should be first */
static const packettype cli_packettypes[] = {
/* TYPE, FUNCTION */
{SSH_MSG_CHANNEL_DATA, recv_msg_channel_data},
{SSH_MSG_CHANNEL_EXTENDED_DATA, recv_msg_channel_extended_data},
{SSH_MSG_CHANNEL_WINDOW_ADJUST, recv_msg_channel_window_adjust},
{SSH_MSG_USERAUTH_FAILURE, recv_msg_userauth_failure}, /* client */
{SSH_MSG_USERAUTH_SUCCESS, recv_msg_userauth_success}, /* client */
{SSH_MSG_KEXINIT, recv_msg_kexinit},
{SSH_MSG_KEXDH_REPLY, recv_msg_kexdh_reply}, /* client */
{SSH_MSG_NEWKEYS, recv_msg_newkeys},
{SSH_MSG_SERVICE_ACCEPT, recv_msg_service_accept}, /* client */
{SSH_MSG_CHANNEL_REQUEST, recv_msg_channel_request},
{SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open},
{SSH_MSG_CHANNEL_EOF, recv_msg_channel_eof},
{SSH_MSG_CHANNEL_CLOSE, recv_msg_channel_close},
{SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation},
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
{SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */
{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_cli},
{SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response},
{SSH_MSG_CHANNEL_FAILURE, ignore_recv_response},
#ifdef ENABLE_CLI_REMOTETCPFWD
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
#else
/* For keepalive */
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
#endif
{0, 0} /* End */
};
static const struct ChanType *cli_chantypes[] = {
#ifdef ENABLE_CLI_REMOTETCPFWD
&cli_chan_tcpremote,
#endif
#ifdef ENABLE_CLI_AGENTFWD
&cli_chan_agent,
#endif
NULL /* Null termination */
};
void cli_session(int sock_in, int sock_out) {
common_session_init(sock_in, sock_out);
chaninitialise(cli_chantypes);
/* Set up cli_ses vars */
cli_session_init();
/* Ready to go */
sessinitdone = 1;
/* Exchange identification */
send_session_identification();
send_msg_kexinit();
session_loop(cli_sessionloop);
/* Not reached */
}
#ifdef USE_KEX_FIRST_FOLLOWS
static void cli_send_kex_first_guess() {
send_msg_kexdh_init();
}
#endif
static void cli_session_init() {
cli_ses.state = STATE_NOTHING;
cli_ses.kex_state = KEX_NOTHING;
cli_ses.tty_raw_mode = 0;
cli_ses.winchange = 0;
/* We store std{in,out,err}'s flags, so we can set them back on exit
* (otherwise busybox's ash isn't happy */
cli_ses.stdincopy = dup(STDIN_FILENO);
cli_ses.stdinflags = fcntl(STDIN_FILENO, F_GETFL, 0);
cli_ses.stdoutcopy = dup(STDOUT_FILENO);
cli_ses.stdoutflags = fcntl(STDOUT_FILENO, F_GETFL, 0);
cli_ses.stderrcopy = dup(STDERR_FILENO);
cli_ses.stderrflags = fcntl(STDERR_FILENO, F_GETFL, 0);
cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a
specific exit status */
/* Auth */
cli_ses.lastprivkey = NULL;
cli_ses.lastauthtype = 0;
#ifdef DROPBEAR_NONE_CIPHER
cli_ses.cipher_none_after_auth = get_algo_usable(sshciphers, "none");
set_algo_usable(sshciphers, "none", 0);
#else
cli_ses.cipher_none_after_auth = 0;
#endif
/* For printing "remote host closed" for the user */
ses.remoteclosed = cli_remoteclosed;
ses.extra_session_cleanup = cli_session_cleanup;
/* packet handlers */
ses.packettypes = cli_packettypes;
ses.isserver = 0;
#ifdef USE_KEX_FIRST_FOLLOWS
ses.send_kex_first_guess = cli_send_kex_first_guess;
#endif
}
static void send_msg_service_request(char* servicename) {
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
buf_putstring(ses.writepayload, servicename, strlen(servicename));
encrypt_packet();
TRACE(("leave send_msg_service_request"))
}
static void recv_msg_service_accept(void) {
/* do nothing, if it failed then the server MUST have disconnected */
}
/* This function drives the progress of the session - it initiates KEX,
* service, userauth and channel requests */
static void cli_sessionloop() {
TRACE2(("enter cli_sessionloop"))
if (ses.lastpacket == 0) {
TRACE2(("exit cli_sessionloop: no real packets yet"))
return;
}
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
/* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT
* negotiation would have failed. */
if (!ses.kexstate.our_first_follows_matches) {
send_msg_kexdh_init();
}
cli_ses.kex_state = KEXDH_INIT_SENT;
TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"))
return;
}
/* A KEX has finished, so we should go back to our KEX_NOTHING state */
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.sentnewkeys) {
cli_ses.kex_state = KEX_NOTHING;
}
/* We shouldn't do anything else if a KEX is in progress */
if (cli_ses.kex_state != KEX_NOTHING) {
TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING"))
return;
}
if (ses.kexstate.donefirstkex == 0) {
/* We might reach here if we have partial packet reads or have
* received SSG_MSG_IGNORE etc. Just skip it */
TRACE2(("donefirstkex false\n"))
return;
}
switch (cli_ses.state) {
case STATE_NOTHING:
/* We've got the transport layer sorted, we now need to request
* userauth */
send_msg_service_request(SSH_SERVICE_USERAUTH);
cli_auth_getmethods();
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) {
dropbear_exit("No auth methods could be used.");
}
cli_ses.state = USERAUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: cli_auth_try"))
return;
case USERAUTH_SUCCESS_RCVD:
#ifdef DROPBEAR_NONE_CIPHER
if (cli_ses.cipher_none_after_auth)
{
set_algo_usable(sshciphers, "none", 1);
send_msg_kexinit();
}
#endif
if (cli_opts.backgrounded) {
int devnull;
/* keeping stdin open steals input from the terminal and
is confusing, though stdout/stderr could be useful. */
devnull = open(_PATH_DEVNULL, O_RDONLY);
if (devnull < 0) {
dropbear_exit("Opening /dev/null: %d %s",
errno, strerror(errno));
}
dup2(devnull, STDIN_FILENO);
if (daemon(0, 1) < 0) {
dropbear_exit("Backgrounding failed: %d %s",
errno, strerror(errno));
}
}
#ifdef ENABLE_CLI_NETCAT
if (cli_opts.netcat_host) {
cli_send_netcat_request();
} else
#endif
if (!cli_opts.no_cmd) {
cli_send_chansess_request();
}
#ifdef ENABLE_CLI_LOCALTCPFWD
setup_localtcp();
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
setup_remotetcp();
#endif
TRACE(("leave cli_sessionloop: running"))
cli_ses.state = SESSION_RUNNING;
return;
case SESSION_RUNNING:
if (ses.chancount < 1 && !cli_opts.no_cmd) {
cli_finished();
}
if (cli_ses.winchange) {
cli_chansess_winchange();
}
return;
/* XXX more here needed */
default:
break;
}
TRACE2(("leave cli_sessionloop: fell out"))
}
static void cli_session_cleanup(void) {
if (!sessinitdone) {
return;
}
/* Set std{in,out,err} back to non-blocking - busybox ash dies nastily if
* we don't revert the flags */
fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags);
fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags);
fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
cli_tty_cleanup();
}
static void cli_finished() {
session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport);
exit(cli_ses.retval);
}
/* called when the remote side closes the connection */
static void cli_remoteclosed() {
/* XXX TODO perhaps print a friendlier message if we get this but have
* already sent/received disconnect message(s) ??? */
m_close(ses.sock_in);
m_close(ses.sock_out);
ses.sock_in = -1;
ses.sock_out = -1;
dropbear_exit("Remote closed the connection");
}
/* Operates in-place turning dirty (untrusted potentially containing control
* characters) text into clean text.
* Note: this is safe only with ascii - other charsets could have problems. */
void cleantext(unsigned char* dirtytext) {
unsigned int i, j;
unsigned char c;
j = 0;
for (i = 0; dirtytext[i] != '\0'; i++) {
c = dirtytext[i];
/* We can ignore '\r's */
if ( (c >= ' ' && c <= '~') || c == '\n' || c == '\t') {
dirtytext[j] = c;
j++;
}
}
/* 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();
}

280
dropbear/cli-tcpfwd.c Normal file
View File

@ -0,0 +1,280 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "options.h"
#include "dbutil.h"
#include "tcpfwd.h"
#include "channel.h"
#include "runopts.h"
#include "session.h"
#include "ssh.h"
#ifdef ENABLE_CLI_REMOTETCPFWD
static int newtcpforwarded(struct Channel * channel);
const struct ChanType cli_chan_tcpremote = {
1, /* sepfds */
"forwarded-tcpip",
newtcpforwarded,
NULL,
NULL,
NULL
};
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
static int cli_localtcp(const char* listenaddr,
unsigned int listenport,
const char* remoteaddr,
unsigned int remoteport);
static const struct ChanType cli_chan_tcplocal = {
1, /* sepfds */
"direct-tcpip",
tcp_prio_inithandler,
NULL,
NULL,
NULL
};
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
void setup_localtcp() {
m_list_elem *iter;
int ret;
TRACE(("enter setup_localtcp"))
for (iter = cli_opts.localfwds->first; iter; iter = iter->next) {
struct TCPFwdEntry * fwd = (struct TCPFwdEntry*)iter->item;
ret = cli_localtcp(
fwd->listenaddr,
fwd->listenport,
fwd->connectaddr,
fwd->connectport);
if (ret == DROPBEAR_FAILURE) {
dropbear_log(LOG_WARNING, "Failed local port forward %s:%d:%s:%d",
fwd->listenaddr,
fwd->listenport,
fwd->connectaddr,
fwd->connectport);
}
}
TRACE(("leave setup_localtcp"))
}
static int cli_localtcp(const char* listenaddr,
unsigned int listenport,
const char* remoteaddr,
unsigned int remoteport) {
struct TCPListener* tcpinfo = NULL;
int ret;
TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr,
remoteport));
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
tcpinfo->sendaddr = m_strdup(remoteaddr);
tcpinfo->sendport = remoteport;
if (listenaddr)
{
tcpinfo->listenaddr = m_strdup(listenaddr);
}
else
{
if (opts.listen_fwd_all) {
tcpinfo->listenaddr = m_strdup("");
} else {
tcpinfo->listenaddr = m_strdup("localhost");
}
}
tcpinfo->listenport = listenport;
tcpinfo->chantype = &cli_chan_tcplocal;
tcpinfo->tcp_type = direct;
ret = listen_tcpfwd(tcpinfo);
if (ret == DROPBEAR_FAILURE) {
m_free(tcpinfo);
}
TRACE(("leave cli_localtcp: %d", ret))
return ret;
}
#endif /* ENABLE_CLI_LOCALTCPFWD */
#ifdef ENABLE_CLI_REMOTETCPFWD
static void send_msg_global_request_remotetcp(const char *addr, int port) {
TRACE(("enter send_msg_global_request_remotetcp"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
buf_putstring(ses.writepayload, "tcpip-forward", 13);
buf_putbyte(ses.writepayload, 1); /* want_reply */
buf_putstring(ses.writepayload, addr, strlen(addr));
buf_putint(ses.writepayload, port);
encrypt_packet();
TRACE(("leave send_msg_global_request_remotetcp"))
}
/* The only global success/failure messages are for remotetcp.
* Since there isn't any identifier in these messages, we have to rely on them
* being in the same order as we sent the requests. This is the ordering
* of the cli_opts.remotefwds list.
* If the requested remote port is 0 the listen port will be
* dynamically allocated by the server and the port number will be returned
* to client and the port number reported to the user. */
void cli_recv_msg_request_success() {
/* We just mark off that we have received the reply,
* so that we can report failure for later ones. */
m_list_elem * iter = NULL;
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->have_reply) {
fwd->have_reply = 1;
if (fwd->listenport == 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);
}
}
return;
}
}
}
void cli_recv_msg_request_failure() {
m_list_elem *iter;
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->have_reply) {
fwd->have_reply = 1;
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", fwd->listenport, fwd->connectaddr, fwd->connectport);
return;
}
}
}
void setup_remotetcp() {
m_list_elem *iter;
TRACE(("enter setup_remotetcp"))
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->listenaddr)
{
/* we store the addresses so that we can compare them
when the server sends them back */
if (opts.listen_fwd_all) {
fwd->listenaddr = m_strdup("");
} else {
fwd->listenaddr = m_strdup("localhost");
}
}
send_msg_global_request_remotetcp(fwd->listenaddr, fwd->listenport);
}
TRACE(("leave setup_remotetcp"))
}
static int newtcpforwarded(struct Channel * channel) {
char *origaddr = NULL;
unsigned int origport;
m_list_elem * iter = NULL;
struct TCPFwdEntry *fwd;
char portstring[NI_MAXSERV];
int sock;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
origaddr = buf_getstring(ses.payload, NULL);
origport = buf_getint(ses.payload);
/* 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) {
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);
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
origaddr, origport);
goto out;
}
snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
sock = connect_remote(fwd->connectaddr, portstring, 1, NULL);
if (sock < 0) {
TRACE(("leave newtcpdirect: sock failed"))
err = SSH_OPEN_CONNECT_FAILED;
goto out;
}
ses.maxfd = MAX(ses.maxfd, sock);
/* We don't set readfd, that will get set after the connection's
* progress succeeds */
channel->writefd = sock;
channel->initconn = 1;
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
err = SSH_OPEN_IN_PROGRESS;
out:
m_free(origaddr);
TRACE(("leave newtcpdirect: err %d", err))
return err;
}
#endif /* ENABLE_CLI_REMOTETCPFWD */

542
dropbear/common-algo.c Normal file
View File

@ -0,0 +1,542 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "algo.h"
#include "session.h"
#include "dbutil.h"
#include "kex.h"
#include "ltc_prng.h"
#include "ecc.h"
/* This file (algo.c) organises the ciphers which can be used, and is used to
* decide which ciphers/hashes/compression/signing to use during key exchange*/
static int void_cipher(const unsigned char* in, unsigned char* out,
unsigned long len, void* UNUSED(cipher_state)) {
if (in != out) {
memmove(out, in, len);
}
return CRYPT_OK;
}
static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
const unsigned char* UNUSED(key),
int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
return CRYPT_OK;
}
/* Mappings for ciphers, parameters are
{&cipher_desc, keysize, blocksize} */
/* Remember to add new ciphers/hashes to regciphers/reghashes too */
#ifdef DROPBEAR_AES256
static const struct dropbear_cipher dropbear_aes256 =
{&aes_desc, 32, 16};
#endif
#ifdef DROPBEAR_AES128
static const struct dropbear_cipher dropbear_aes128 =
{&aes_desc, 16, 16};
#endif
#ifdef DROPBEAR_BLOWFISH
static const struct dropbear_cipher dropbear_blowfish =
{&blowfish_desc, 16, 8};
#endif
#ifdef DROPBEAR_TWOFISH256
static const struct dropbear_cipher dropbear_twofish256 =
{&twofish_desc, 32, 16};
#endif
#ifdef DROPBEAR_TWOFISH128
static const struct dropbear_cipher dropbear_twofish128 =
{&twofish_desc, 16, 16};
#endif
#ifdef DROPBEAR_3DES
static const struct dropbear_cipher dropbear_3des =
{&des3_desc, 24, 8};
#endif
/* used to indicate no encryption, as defined in rfc2410 */
const struct dropbear_cipher dropbear_nocipher =
{NULL, 16, 8};
/* A few void* s are required to silence warnings
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
const struct dropbear_cipher_mode dropbear_mode_cbc =
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
const struct dropbear_cipher_mode dropbear_mode_none =
{void_start, void_cipher, void_cipher};
#ifdef DROPBEAR_ENABLE_CTR_MODE
/* a wrapper to make ctr_start and cbc_start look the same */
static int dropbear_big_endian_ctr_start(int cipher,
const unsigned char *IV,
const unsigned char *key, int keylen,
int num_rounds, symmetric_CTR *ctr) {
return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
}
const struct dropbear_cipher_mode dropbear_mode_ctr =
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
#endif
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
{&hash_desc, keysize, hashsize} */
#ifdef DROPBEAR_SHA1_HMAC
static const struct dropbear_hash dropbear_sha1 =
{&sha1_desc, 20, 20};
#endif
#ifdef DROPBEAR_SHA1_96_HMAC
static const struct dropbear_hash dropbear_sha1_96 =
{&sha1_desc, 20, 12};
#endif
#ifdef DROPBEAR_SHA2_256_HMAC
static const struct dropbear_hash dropbear_sha2_256 =
{&sha256_desc, 32, 32};
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
static const struct dropbear_hash dropbear_sha2_512 =
{&sha512_desc, 64, 64};
#endif
#ifdef DROPBEAR_MD5_HMAC
static const struct dropbear_hash dropbear_md5 =
{&md5_desc, 16, 16};
#endif
const struct dropbear_hash dropbear_nohash =
{NULL, 16, 0}; /* used initially */
/* The following map ssh names to internal values.
* The ordering here is important for the client - the first mode
* that is also supported by the server will get used. */
algo_type sshciphers[] = {
#ifdef DROPBEAR_ENABLE_CTR_MODE
#ifdef DROPBEAR_AES128
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_3DES
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_AES256
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
#endif
#endif /* DROPBEAR_ENABLE_CTR_MODE */
/* CBC modes are always enabled */
#ifdef DROPBEAR_AES128
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_3DES
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_AES256
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_TWOFISH256
{"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
{"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_TWOFISH128
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_BLOWFISH
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_NONE_CIPHER
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
#endif
{NULL, 0, NULL, 0, NULL}
};
algo_type sshhashes[] = {
#ifdef DROPBEAR_SHA2_256_HMAC
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
#endif
#ifdef DROPBEAR_SHA1_96_HMAC
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
#endif
#ifdef DROPBEAR_SHA1_HMAC
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
#endif
#ifdef DROPBEAR_MD5_HMAC
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
#endif
#ifdef DROPBEAR_NONE_INTEGRITY
{"none", 0, (void*)&dropbear_nohash, 1, NULL},
#endif
{NULL, 0, NULL, 0, NULL}
};
#ifndef DISABLE_ZLIB
algo_type ssh_compress[] = {
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
};
#endif
algo_type ssh_nocompress[] = {
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
};
algo_type sshhostkey[] = {
#ifdef DROPBEAR_ECDSA
#ifdef DROPBEAR_ECC_256
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
#endif
#ifdef DROPBEAR_ECC_384
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
#endif
#ifdef DROPBEAR_ECC_521
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
#endif
#endif
#ifdef DROPBEAR_RSA
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
#endif
#ifdef DROPBEAR_DSS
{"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL},
#endif
{NULL, 0, NULL, 0, NULL}
};
static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
static const struct dropbear_kex kex_dh_group14 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
/* These can't be const since dropbear_ecc_fill_dp() fills out
ecc_curve at runtime */
#ifdef DROPBEAR_ECDH
#ifdef DROPBEAR_ECC_256
static struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
#endif
#ifdef DROPBEAR_ECC_384
static struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
#endif
#ifdef DROPBEAR_ECC_521
static struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
#endif
#endif /* DROPBEAR_ECDH */
#ifdef DROPBEAR_CURVE25519
/* Referred to directly */
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
#endif
algo_type sshkex[] = {
#ifdef DROPBEAR_CURVE25519
{"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL},
#endif
#ifdef DROPBEAR_ECDH
#ifdef DROPBEAR_ECC_521
{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
#endif
#ifdef DROPBEAR_ECC_384
{"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
#endif
#ifdef DROPBEAR_ECC_256
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
#endif
#endif
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL},
#ifdef USE_KEXGUESS2
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
#endif
{NULL, 0, NULL, 0, NULL}
};
/* algolen specifies the length of algo, algos is our local list to match
* against.
* Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
* otherwise */
int have_algo(char* algo, size_t algolen, algo_type algos[]) {
int i;
for (i = 0; algos[i].name != NULL; i++) {
if (strlen(algos[i].name) == algolen
&& (strncmp(algos[i].name, algo, algolen) == 0)) {
return DROPBEAR_SUCCESS;
}
}
return DROPBEAR_FAILURE;
}
/* Output a comma separated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
unsigned int i, len;
unsigned int donefirst = 0;
buffer *algolist = NULL;
algolist = buf_new(200);
for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) {
if (donefirst)
buf_putbyte(algolist, ',');
donefirst = 1;
len = strlen(localalgos[i].name);
buf_putbytes(algolist, localalgos[i].name, len);
}
}
buf_putstring(buf, algolist->data, algolist->len);
buf_free(algolist);
}
/* match the first algorithm in the comma-separated list in buf which is
* also in localalgos[], or return NULL on failure.
* (*goodguess) is set to 1 if the preferred client/server algos match,
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
* guessed correctly */
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
enum kexguess2_used *kexguess2, int *goodguess)
{
unsigned char * algolist = NULL;
const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
unsigned int len;
unsigned int remotecount, localcount, clicount, servcount, i, j;
algo_type * ret = NULL;
const unsigned char **clinames, **servnames;
if (goodguess) {
*goodguess = 0;
}
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
TRACE(("buf_match_algo: %s", algolist))
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
goto out;
}
/* remotenames will contain a list of the strings parsed out */
/* We will have at least one string (even if it's just "") */
remotenames[0] = algolist;
remotecount = 1;
for (i = 0; i < len; i++) {
if (algolist[i] == '\0') {
/* someone is trying something strange */
goto out;
}
if (algolist[i] == ',') {
algolist[i] = '\0';
remotenames[remotecount] = &algolist[i+1];
remotecount++;
}
if (remotecount >= MAX_PROPOSED_ALGO) {
break;
}
}
if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
for (i = 0; i < remotecount; i++)
{
if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
*kexguess2 = KEXGUESS2_YES;
break;
}
}
if (*kexguess2 == KEXGUESS2_LOOK) {
*kexguess2 = KEXGUESS2_NO;
}
}
for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) {
localnames[i] = localalgos[i].name;
} else {
localnames[i] = NULL;
}
}
localcount = i;
if (IS_DROPBEAR_SERVER) {
clinames = remotenames;
clicount = remotecount;
servnames = localnames;
servcount = localcount;
} else {
clinames = localnames;
clicount = localcount;
servnames = remotenames;
servcount = remotecount;
}
/* iterate and find the first match */
for (i = 0; i < clicount; i++) {
for (j = 0; j < servcount; j++) {
if (!(servnames[j] && clinames[i])) {
/* unusable algos are NULL */
continue;
}
if (strcmp(servnames[j], clinames[i]) == 0) {
/* set if it was a good guess */
if (goodguess && kexguess2) {
if (*kexguess2 == KEXGUESS2_YES) {
if (i == 0) {
*goodguess = 1;
}
} else {
if (i == 0 && j == 0) {
*goodguess = 1;
}
}
}
/* set the algo to return */
if (IS_DROPBEAR_SERVER) {
ret = &localalgos[j];
} else {
ret = &localalgos[i];
}
goto out;
}
}
}
out:
m_free(algolist);
return ret;
}
#ifdef DROPBEAR_NONE_CIPHER
void
set_algo_usable(algo_type algos[], const char * algo_name, int usable)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
a->usable = usable;
return;
}
}
}
int
get_algo_usable(algo_type algos[], const char * algo_name)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
return a->usable;
}
}
return 0;
}
#endif /* DROPBEAR_NONE_CIPHER */
#ifdef ENABLE_USER_ALGO_LIST
char *
algolist_string(algo_type algos[])
{
char *ret_list;
buffer *b = buf_new(200);
buf_put_algolist(b, algos);
buf_setpos(b, b->len);
buf_putbyte(b, '\0');
buf_setpos(b, 4);
ret_list = m_strdup(buf_getptr(b, b->len - b->pos));
buf_free(b);
return ret_list;
}
static algo_type*
check_algo(const char* algo_name, algo_type *algos)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
return a;
}
}
return NULL;
}
static void
try_add_algo(const char *algo_name, algo_type *algos,
const char *algo_desc, algo_type * new_algos, int *num_ret)
{
algo_type *match_algo = check_algo(algo_name, algos);
if (!match_algo)
{
dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc);
return;
}
new_algos[*num_ret] = *match_algo;
(*num_ret)++;
}
/* Checks a user provided comma-separated algorithm list for available
* options. Any that are not acceptable are removed in-place. Returns the
* number of valid algorithms. */
int
check_user_algos(const char* user_algo_list, algo_type * algos,
const char *algo_desc)
{
algo_type new_algos[MAX_PROPOSED_ALGO];
/* this has two passes. first we sweep through the given list of
* algorithms and mark them as usable=2 in the algo_type[] array... */
int num_ret = 0;
char *work_list = m_strdup(user_algo_list);
char *last_name = work_list;
char *c;
for (c = work_list; *c; c++)
{
if (*c == ',')
{
*c = '\0';
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
c++;
last_name = c;
}
}
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
m_free(work_list);
new_algos[num_ret].name = NULL;
/* Copy one more as a blank delimiter */
memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1));
return num_ret;
}
#endif /* ENABLE_USER_ALGO_LIST */

1168
dropbear/common-channel.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "chansession.h"
/* Mapping of signal values to ssh signal strings */
const struct SigMap signames[] = {
{SIGABRT, "ABRT"},
{SIGALRM, "ALRM"},
{SIGFPE, "FPE"},
{SIGHUP, "HUP"},
{SIGILL, "ILL"},
{SIGINT, "INT"},
{SIGKILL, "KILL"},
{SIGPIPE, "PIPE"},
{SIGQUIT, "QUIT"},
{SIGSEGV, "SEGV"},
{SIGTERM, "TERM"},
{SIGUSR1, "USR1"},
{SIGUSR2, "USR2"},
{0, NULL}
};

972
dropbear/common-kex.c Normal file
View File

@ -0,0 +1,972 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002-2004 Matt Johnston
* Portions Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
#include "algo.h"
#include "buffer.h"
#include "session.h"
#include "kex.h"
#include "ssh.h"
#include "packet.h"
#include "bignum.h"
#include "dbrandom.h"
#include "runopts.h"
#include "ecc.h"
#include "crypto_desc.h"
/* diffie-hellman-group1-sha1 value for p */
const unsigned char dh_p_1[DH_P_1_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
/* diffie-hellman-group14-sha1 value for p */
const unsigned char dh_p_14[DH_P_14_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF};
/* Same for group1 and group14 */
static const int DH_G_VAL = 2;
static void kexinitialise();
static void gen_new_keys();
#ifndef DISABLE_ZLIB
static void gen_new_zstream_recv();
static void gen_new_zstream_trans();
#endif
static void read_kex_algos();
/* helper function for gen_new_keys */
static void hashkeys(unsigned char *out, unsigned int outlen,
const hash_state * hs, const unsigned char X);
static void finish_kexhashbuf(void);
/* Send our list of algorithms we can use */
void send_msg_kexinit() {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_KEXINIT);
/* cookie */
genrandom(buf_getwriteptr(ses.writepayload, 16), 16);
buf_incrwritepos(ses.writepayload, 16);
/* kex algos */
buf_put_algolist(ses.writepayload, sshkex);
/* server_host_key_algorithms */
buf_put_algolist(ses.writepayload, sshhostkey);
/* encryption_algorithms_client_to_server */
buf_put_algolist(ses.writepayload, sshciphers);
/* encryption_algorithms_server_to_client */
buf_put_algolist(ses.writepayload, sshciphers);
/* mac_algorithms_client_to_server */
buf_put_algolist(ses.writepayload, sshhashes);
/* mac_algorithms_server_to_client */
buf_put_algolist(ses.writepayload, sshhashes);
/* compression_algorithms_client_to_server */
buf_put_algolist(ses.writepayload, ses.compress_algos);
/* compression_algorithms_server_to_client */
buf_put_algolist(ses.writepayload, ses.compress_algos);
/* languages_client_to_server */
buf_putstring(ses.writepayload, "", 0);
/* languages_server_to_client */
buf_putstring(ses.writepayload, "", 0);
/* first_kex_packet_follows */
buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL));
/* reserved unit32 */
buf_putint(ses.writepayload, 0);
/* set up transmitted kex packet buffer for hashing.
* This is freed after the end of the kex */
ses.transkexinit = buf_newcopy(ses.writepayload);
encrypt_packet();
ses.dataallowed = 0; /* don't send other packets during kex */
ses.kexstate.sentkexinit = 1;
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
if (ses.send_kex_first_guess) {
ses.newkeys->algo_kex = sshkex[0].data;
ses.newkeys->algo_hostkey = sshhostkey[0].val;
ses.send_kex_first_guess();
}
TRACE(("DATAALLOWED=0"))
TRACE(("-> KEXINIT"))
}
static void switch_keys() {
TRACE2(("enter switch_keys"))
if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) {
dropbear_exit("Unexpected newkeys message");
}
if (!ses.keys) {
ses.keys = m_malloc(sizeof(*ses.newkeys));
}
if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) {
TRACE(("switch_keys recv"))
#ifndef DISABLE_ZLIB
gen_new_zstream_recv();
#endif
ses.keys->recv = ses.newkeys->recv;
m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv));
ses.newkeys->recv.valid = 0;
}
if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) {
TRACE(("switch_keys trans"))
#ifndef DISABLE_ZLIB
gen_new_zstream_trans();
#endif
ses.keys->trans = ses.newkeys->trans;
m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans));
ses.newkeys->trans.valid = 0;
}
if (ses.kexstate.sentnewkeys && ses.kexstate.recvnewkeys)
{
TRACE(("switch_keys done"))
ses.keys->algo_kex = ses.newkeys->algo_kex;
ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
ses.keys->allow_compress = 0;
m_free(ses.newkeys);
ses.newkeys = NULL;
kexinitialise();
}
TRACE2(("leave switch_keys"))
}
/* Bring new keys into use after a key exchange, and let the client know*/
void send_msg_newkeys() {
TRACE(("enter send_msg_newkeys"))
/* generate the kexinit request */
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS);
encrypt_packet();
/* set up our state */
ses.kexstate.sentnewkeys = 1;
ses.kexstate.donefirstkex = 1;
ses.dataallowed = 1; /* we can send other packets again now */
gen_new_keys();
switch_keys();
TRACE(("leave send_msg_newkeys"))
}
/* Bring the new keys into use after a key exchange */
void recv_msg_newkeys() {
TRACE(("enter recv_msg_newkeys"))
ses.kexstate.recvnewkeys = 1;
switch_keys();
TRACE(("leave recv_msg_newkeys"))
}
/* Set up the kex for the first time */
void kexfirstinitialise() {
ses.kexstate.donefirstkex = 0;
#ifndef DISABLE_ZLIB
if (opts.enable_compress) {
ses.compress_algos = ssh_compress;
} else
#endif
{
ses.compress_algos = ssh_nocompress;
}
kexinitialise();
}
/* Reset the kex state, ready for a new negotiation */
static void kexinitialise() {
TRACE(("kexinitialise()"))
/* sent/recv'd MSG_KEXINIT */
ses.kexstate.sentkexinit = 0;
ses.kexstate.recvkexinit = 0;
/* sent/recv'd MSG_NEWKEYS */
ses.kexstate.recvnewkeys = 0;
ses.kexstate.sentnewkeys = 0;
/* first_packet_follows */
ses.kexstate.them_firstfollows = 0;
ses.kexstate.datatrans = 0;
ses.kexstate.datarecv = 0;
ses.kexstate.our_first_follows_matches = 0;
ses.kexstate.lastkextime = monotonic_now();
}
/* Helper function for gen_new_keys, creates a hash. It makes a copy of the
* already initialised hash_state hs, which should already have processed
* the dh_K and hash, since these are common. X is the letter 'A', 'B' etc.
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
*
* See Section 7.2 of rfc4253 (ssh transport) for details */
static void hashkeys(unsigned char *out, unsigned int outlen,
const hash_state * hs, const unsigned char X) {
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
hash_state hs2;
unsigned int offset;
unsigned char tmpout[MAX_HASH_SIZE];
memcpy(&hs2, hs, sizeof(hash_state));
hash_desc->process(&hs2, &X, 1);
hash_desc->process(&hs2, ses.session_id->data, ses.session_id->len);
hash_desc->done(&hs2, tmpout);
memcpy(out, tmpout, MIN(hash_desc->hashsize, outlen));
for (offset = hash_desc->hashsize;
offset < outlen;
offset += hash_desc->hashsize)
{
/* need to extend */
memcpy(&hs2, hs, sizeof(hash_state));
hash_desc->process(&hs2, out, offset);
hash_desc->done(&hs2, tmpout);
memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
}
}
/* Generate the actual encryption/integrity keys, using the results of the
* key exchange, as specified in section 7.2 of the transport rfc 4253.
* This occurs after the DH key-exchange.
*
* ses.newkeys is the new set of keys which are generated, these are only
* taken into use after both sides have sent a newkeys message */
static void gen_new_keys() {
unsigned char C2S_IV[MAX_IV_LEN];
unsigned char C2S_key[MAX_KEY_LEN];
unsigned char S2C_IV[MAX_IV_LEN];
unsigned char S2C_key[MAX_KEY_LEN];
/* unsigned char key[MAX_KEY_LEN]; */
unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key;
hash_state hs;
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
char mactransletter, macrecvletter; /* Client or server specific */
TRACE(("enter gen_new_keys"))
/* the dh_K and hash are the start of all hashes, we make use of that */
hash_desc->init(&hs);
hash_process_mp(hash_desc, &hs, ses.dh_K);
mp_clear(ses.dh_K);
m_free(ses.dh_K);
hash_desc->process(&hs, ses.hash->data, ses.hash->len);
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
if (IS_DROPBEAR_CLIENT) {
trans_IV = C2S_IV;
recv_IV = S2C_IV;
trans_key = C2S_key;
recv_key = S2C_key;
mactransletter = 'E';
macrecvletter = 'F';
} else {
trans_IV = S2C_IV;
recv_IV = C2S_IV;
trans_key = S2C_key;
recv_key = C2S_key;
mactransletter = 'F';
macrecvletter = 'E';
}
hashkeys(C2S_IV, sizeof(C2S_IV), &hs, 'A');
hashkeys(S2C_IV, sizeof(S2C_IV), &hs, 'B');
hashkeys(C2S_key, sizeof(C2S_key), &hs, 'C');
hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D');
if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
if (recv_cipher < 0)
dropbear_exit("Crypto error");
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
recv_IV, recv_key,
ses.newkeys->recv.algo_crypt->keysize, 0,
&ses.newkeys->recv.cipher_state) != CRYPT_OK) {
dropbear_exit("Crypto error");
}
}
if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
if (trans_cipher < 0)
dropbear_exit("Crypto error");
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
trans_IV, trans_key,
ses.newkeys->trans.algo_crypt->keysize, 0,
&ses.newkeys->trans.cipher_state) != CRYPT_OK) {
dropbear_exit("Crypto error");
}
}
if (ses.newkeys->trans.algo_mac->hash_desc != NULL) {
hashkeys(ses.newkeys->trans.mackey,
ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hash_desc->name);
}
if (ses.newkeys->recv.algo_mac->hash_desc != NULL) {
hashkeys(ses.newkeys->recv.mackey,
ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hash_desc->name);
}
/* Ready to switch over */
ses.newkeys->trans.valid = 1;
ses.newkeys->recv.valid = 1;
m_burn(C2S_IV, sizeof(C2S_IV));
m_burn(C2S_key, sizeof(C2S_key));
m_burn(S2C_IV, sizeof(S2C_IV));
m_burn(S2C_key, sizeof(S2C_key));
TRACE(("leave gen_new_keys"))
}
#ifndef DISABLE_ZLIB
int is_compress_trans() {
return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|| (ses.authstate.authdone
&& ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
}
int is_compress_recv() {
return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|| (ses.authstate.authdone
&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
}
/* Set up new zlib compression streams, close the old ones. Only
* called from gen_new_keys() */
static void gen_new_zstream_recv() {
/* create new zstreams */
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->recv.zstream->zalloc = Z_NULL;
ses.newkeys->recv.zstream->zfree = Z_NULL;
if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
dropbear_exit("zlib error");
}
} else {
ses.newkeys->recv.zstream = NULL;
}
/* clean up old keys */
if (ses.keys->recv.zstream != NULL) {
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("Crypto error");
}
m_free(ses.keys->recv.zstream);
}
}
static void gen_new_zstream_trans() {
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->trans.zstream->zalloc = Z_NULL;
ses.newkeys->trans.zstream->zfree = Z_NULL;
if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS,
DROPBEAR_ZLIB_MEM_LEVEL, Z_DEFAULT_STRATEGY)
!= Z_OK) {
dropbear_exit("zlib error");
}
} else {
ses.newkeys->trans.zstream = NULL;
}
if (ses.keys->trans.zstream != NULL) {
if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("Crypto error");
}
m_free(ses.keys->trans.zstream);
}
}
#endif /* DISABLE_ZLIB */
/* Executed upon receiving a kexinit message from the client to initiate
* key exchange. If we haven't already done so, we send the list of our
* preferred algorithms. The client's requested algorithms are processed,
* 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 */
void recv_msg_kexinit() {
unsigned int kexhashbuf_len = 0;
unsigned int remote_ident_len = 0;
unsigned int local_ident_len = 0;
TRACE(("<- KEXINIT"))
TRACE(("enter recv_msg_kexinit"))
if (!ses.kexstate.sentkexinit) {
/* we need to send a kex packet */
send_msg_kexinit();
TRACE(("continue recv_msg_kexinit: sent kexinit"))
}
/* start the kex hash */
local_ident_len = strlen(LOCAL_IDENT);
remote_ident_len = strlen((char*)ses.remoteident);
kexhashbuf_len = local_ident_len + remote_ident_len
+ ses.transkexinit->len + ses.payload->len
+ KEXHASHBUF_MAX_INTS;
ses.kexhashbuf = buf_new(kexhashbuf_len);
if (IS_DROPBEAR_CLIENT) {
/* read the peer's choice of algos */
read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
(unsigned char*)LOCAL_IDENT, local_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf,
ses.transkexinit->data, ses.transkexinit->len);
/* 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 */
/* read the peer's choice of algos */
read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
(unsigned char*)LOCAL_IDENT, local_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0);
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf,
ses.transkexinit->data, ses.transkexinit->len);
ses.requirenext = SSH_MSG_KEXDH_INIT;
}
buf_free(ses.transkexinit);
ses.transkexinit = NULL;
/* the rest of ses.kexhashbuf will be done after DH exchange */
ses.kexstate.recvkexinit = 1;
TRACE(("leave recv_msg_kexinit"))
}
static void load_dh_p(mp_int * dh_p)
{
bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes,
ses.newkeys->algo_kex->dh_p_len);
}
/* Initialises and generate one side of the diffie-hellman key exchange values.
* See the transport rfc 4253 section 8 for details */
/* dh_pub and dh_priv MUST be already initialised */
struct kex_dh_param *gen_kexdh_param() {
struct kex_dh_param *param = NULL;
DEF_MP_INT(dh_p);
DEF_MP_INT(dh_q);
DEF_MP_INT(dh_g);
TRACE(("enter gen_kexdh_vals"))
param = m_malloc(sizeof(*param));
m_mp_init_multi(&param->pub, &param->priv, &dh_g, &dh_p, &dh_q, NULL);
/* read the prime and generator*/
load_dh_p(&dh_p);
if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
/* calculate q = (p-1)/2 */
/* dh_priv is just a temp var here */
if (mp_sub_d(&dh_p, 1, &param->priv) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
if (mp_div_2(&param->priv, &dh_q) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
/* Generate a private portion 0 < dh_priv < dh_q */
gen_random_mpint(&dh_q, &param->priv);
/* f = g^y mod p */
if (mp_exptmod(&dh_g, &param->priv, &dh_p, &param->pub) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL);
return param;
}
void free_kexdh_param(struct kex_dh_param *param)
{
mp_clear_multi(&param->pub, &param->priv, NULL);
m_free(param);
}
/* This function is fairly common between client/server, with some substitution
* of dh_e/dh_f etc. Hence these arguments:
* dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is
* vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
sign_key *hostkey) {
mp_int dh_p;
mp_int *dh_e = NULL, *dh_f = NULL;
/* read the prime and generator*/
m_mp_init(&dh_p);
load_dh_p(&dh_p);
/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
if (mp_cmp(dh_pub_them, &dh_p) != MP_LT
|| mp_cmp_d(dh_pub_them, 0) != MP_GT) {
dropbear_exit("Diffie-Hellman error");
}
/* K = e^y mod p = f^x mod p */
m_mp_alloc_init_multi(&ses.dh_K, NULL);
if (mp_exptmod(dh_pub_them, &param->priv, &dh_p, ses.dh_K) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
/* clear no longer needed vars */
mp_clear_multi(&dh_p, NULL);
/* From here on, the code needs to work with the _same_ vars on each side,
* not vice-versaing for client/server */
if (IS_DROPBEAR_CLIENT) {
dh_e = &param->pub;
dh_f = dh_pub_them;
} else {
dh_e = dh_pub_them;
dh_f = &param->pub;
}
/* Create the remainder of the hash buffer, to generate the exchange hash */
/* K_S, the host key */
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
/* e, exchange value sent by the client */
buf_putmpint(ses.kexhashbuf, dh_e);
/* f, exchange value sent by the server */
buf_putmpint(ses.kexhashbuf, dh_f);
/* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K);
/* calculate the hash H to sign */
finish_kexhashbuf();
}
#ifdef DROPBEAR_ECDH
struct kex_ecdh_param *gen_kexecdh_param() {
struct kex_ecdh_param *param = m_malloc(sizeof(*param));
if (ecc_make_key_ex(NULL, dropbear_ltc_prng,
&param->key, ses.newkeys->algo_kex->ecc_curve->dp) != CRYPT_OK) {
dropbear_exit("ECC error");
}
return param;
}
void free_kexecdh_param(struct kex_ecdh_param *param) {
ecc_free(&param->key);
m_free(param);
}
void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
sign_key *hostkey) {
const struct dropbear_kex *algo_kex = ses.newkeys->algo_kex;
/* public keys from client and server */
ecc_key *Q_C, *Q_S, *Q_them;
Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve);
ses.dh_K = dropbear_ecc_shared_secret(Q_them, &param->key);
/* Create the remainder of the hash buffer, to generate the exchange hash
See RFC5656 section 4 page 7 */
if (IS_DROPBEAR_CLIENT) {
Q_C = &param->key;
Q_S = Q_them;
} else {
Q_C = Q_them;
Q_S = &param->key;
}
/* K_S, the host key */
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
/* Q_C, client's ephemeral public key octet string */
buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_C);
/* Q_S, server's ephemeral public key octet string */
buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_S);
/* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K);
/* calculate the hash H to sign */
finish_kexhashbuf();
}
#endif /* DROPBEAR_ECDH */
#ifdef DROPBEAR_CURVE25519
struct kex_curve25519_param *gen_kexcurve25519_param () {
/* Per http://cr.yp.to/ecdh.html */
struct kex_curve25519_param *param = m_malloc(sizeof(*param));
const unsigned char basepoint[32] = {9};
genrandom(param->priv, CURVE25519_LEN);
param->priv[0] &= 248;
param->priv[31] &= 127;
param->priv[31] |= 64;
curve25519_donna(param->pub, param->priv, basepoint);
return param;
}
void free_kexcurve25519_param(struct kex_curve25519_param *param)
{
m_burn(param->priv, CURVE25519_LEN);
m_free(param);
}
void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_them,
sign_key *hostkey) {
unsigned char out[CURVE25519_LEN];
const unsigned char* Q_C = NULL;
const unsigned char* Q_S = NULL;
if (buf_pub_them->len != CURVE25519_LEN)
{
dropbear_exit("Bad curve25519");
}
curve25519_donna(out, param->priv, buf_pub_them->data);
m_mp_alloc_init_multi(&ses.dh_K, NULL);
bytes_to_mp(ses.dh_K, out, CURVE25519_LEN);
m_burn(out, sizeof(out));
/* Create the remainder of the hash buffer, to generate the exchange hash.
See RFC5656 section 4 page 7 */
if (IS_DROPBEAR_CLIENT) {
Q_C = param->pub;
Q_S = buf_pub_them->data;
} else {
Q_S = param->pub;
Q_C = buf_pub_them->data;
}
/* K_S, the host key */
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
/* Q_C, client's ephemeral public key octet string */
buf_putstring(ses.kexhashbuf, Q_C, CURVE25519_LEN);
/* Q_S, server's ephemeral public key octet string */
buf_putstring(ses.kexhashbuf, Q_S, CURVE25519_LEN);
/* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K);
/* calculate the hash H to sign */
finish_kexhashbuf();
}
#endif /* DROPBEAR_CURVE25519 */
static void finish_kexhashbuf(void) {
hash_state hs;
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
hash_desc->init(&hs);
buf_setpos(ses.kexhashbuf, 0);
hash_desc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
ses.kexhashbuf->len);
ses.hash = buf_new(hash_desc->hashsize);
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;
/* first time around, we set the session_id to H */
if (ses.session_id == NULL) {
/* create the session_id, this never needs freeing */
ses.session_id = buf_newcopy(ses.hash);
}
}
/* read the other side's algo list. buf_match_algo is a callback to match
* algos for the client or server. */
static void read_kex_algos() {
/* for asymmetry */
algo_type * c2s_hash_algo = NULL;
algo_type * s2c_hash_algo = NULL;
algo_type * c2s_cipher_algo = NULL;
algo_type * s2c_cipher_algo = NULL;
algo_type * c2s_comp_algo = NULL;
algo_type * s2c_comp_algo = NULL;
/* the generic one */
algo_type * algo = NULL;
/* which algo couldn't match */
char * erralgo = NULL;
int goodguess = 0;
int allgood = 1; /* we AND this with each goodguess and see if its still
true after */
#ifdef USE_KEXGUESS2
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
#else
enum kexguess2_used kexguess2 = KEXGUESS2_NO;
#endif
buf_incrpos(ses.payload, 16); /* start after the cookie */
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
/* kex_algorithms */
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
erralgo = "kex";
goto error;
}
TRACE(("kexguess2 %d", kexguess2))
TRACE(("kex algo %s", algo->name))
ses.newkeys->algo_kex = algo->data;
/* server_host_key_algorithms */
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL) {
erralgo = "hostkey";
goto error;
}
TRACE(("hostkey algo %s", algo->name))
ses.newkeys->algo_hostkey = algo->val;
/* encryption_algorithms_client_to_server */
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
if (c2s_cipher_algo == NULL) {
erralgo = "enc c->s";
goto error;
}
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
if (s2c_cipher_algo == NULL) {
erralgo = "enc s->c";
goto error;
}
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
if (c2s_hash_algo == NULL) {
erralgo = "mac c->s";
goto error;
}
TRACE(("hash c2s is %s", c2s_hash_algo->name))
/* mac_algorithms_server_to_client */
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
if (s2c_hash_algo == NULL) {
erralgo = "mac s->c";
goto error;
}
TRACE(("hash s2c is %s", s2c_hash_algo->name))
/* compression_algorithms_client_to_server */
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
if (c2s_comp_algo == NULL) {
erralgo = "comp c->s";
goto error;
}
TRACE(("hash c2s is %s", c2s_comp_algo->name))
/* compression_algorithms_server_to_client */
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
if (s2c_comp_algo == NULL) {
erralgo = "comp s->c";
goto error;
}
TRACE(("hash s2c is %s", s2c_comp_algo->name))
/* languages_client_to_server */
buf_eatstring(ses.payload);
/* languages_server_to_client */
buf_eatstring(ses.payload);
/* their first_kex_packet_follows */
if (buf_getbool(ses.payload)) {
TRACE(("them kex firstfollows. allgood %d", allgood))
ses.kexstate.them_firstfollows = 1;
/* if the guess wasn't good, we ignore the packet sent */
if (!allgood) {
ses.ignorenext = 1;
}
}
/* Handle the asymmetry */
if (IS_DROPBEAR_CLIENT) {
ses.newkeys->recv.algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data;
ses.newkeys->trans.algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data;
ses.newkeys->recv.crypt_mode =
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
ses.newkeys->trans.crypt_mode =
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
ses.newkeys->recv.algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->trans.algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
} else {
/* SERVER */
ses.newkeys->recv.algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data;
ses.newkeys->trans.algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data;
ses.newkeys->recv.crypt_mode =
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
ses.newkeys->trans.crypt_mode =
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
ses.newkeys->recv.algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->trans.algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
}
/* reserved for future extensions */
buf_getint(ses.payload);
if (ses.send_kex_first_guess && allgood) {
TRACE(("our_first_follows_matches 1"))
ses.kexstate.our_first_follows_matches = 1;
}
return;
error:
dropbear_exit("No matching algo %s", erralgo);
}

113
dropbear/common-runopts.c Normal file
View File

@ -0,0 +1,113 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "runopts.h"
#include "signkey.h"
#include "buffer.h"
#include "dbutil.h"
#include "auth.h"
#include "algo.h"
#include "dbrandom.h"
runopts opts; /* GLOBAL */
/* returns success or failure, and the keytype in *type. If we want
* to restrict the type, type can contain a type to return */
int readhostkey(const char * filename, sign_key * hostkey,
enum signkey_type *type) {
int ret = DROPBEAR_FAILURE;
buffer *buf;
buf = buf_new(MAX_PRIVKEY_SIZE);
if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
goto out;
}
buf_setpos(buf, 0);
addrandom(buf_getptr(buf, buf->len), buf->len);
if (buf_get_priv_key(buf, hostkey, type) == DROPBEAR_FAILURE) {
goto out;
}
ret = DROPBEAR_SUCCESS;
out:
buf_burn(buf);
buf_free(buf);
return ret;
}
#ifdef ENABLE_USER_ALGO_LIST
void
parse_ciphers_macs()
{
if (opts.cipher_list)
{
if (strcmp(opts.cipher_list, "help") == 0)
{
char *ciphers = algolist_string(sshciphers);
dropbear_log(LOG_INFO, "Available ciphers:\n%s\n", ciphers);
m_free(ciphers);
dropbear_exit(".");
}
if (strcmp(opts.cipher_list, "none") == 0)
{
/* Encryption is required during authentication */
opts.cipher_list = "none,aes128-ctr";
}
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0)
{
dropbear_exit("No valid ciphers specified for '-c'");
}
}
if (opts.mac_list)
{
if (strcmp(opts.mac_list, "help") == 0)
{
char *macs = algolist_string(sshhashes);
dropbear_log(LOG_INFO, "Available MACs:\n%s\n", macs);
m_free(macs);
dropbear_exit(".");
}
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
{
dropbear_exit("No valid MACs specified for '-m'");
}
}
}
#endif
void print_version() {
fprintf(stderr, "Dropbear v%s\n", DROPBEAR_VERSION);
}

581
dropbear/common-session.c Normal file
View File

@ -0,0 +1,581 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "session.h"
#include "dbutil.h"
#include "packet.h"
#include "algo.h"
#include "buffer.h"
#include "dss.h"
#include "ssh.h"
#include "dbrandom.h"
#include "kex.h"
#include "channel.h"
#include "runopts.h"
static void checktimeouts();
static long select_timeout();
static int ident_readln(int fd, char* buf, int count);
static void read_session_identification();
struct sshsession ses; /* GLOBAL */
/* need to know if the session struct has been initialised, this way isn't the
* cleanest, but works OK */
int sessinitdone = 0; /* GLOBAL */
/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
int exitflag = 0; /* GLOBAL */
/* called only at the start of a session, set up initial state */
void common_session_init(int sock_in, int sock_out) {
time_t now;
TRACE(("enter session_init"))
ses.sock_in = sock_in;
ses.sock_out = sock_out;
ses.maxfd = MAX(sock_in, sock_out);
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");
}
setnonblocking(ses.signal_pipe[0]);
setnonblocking(ses.signal_pipe[1]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
kexfirstinitialise(); /* initialise the kex state */
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
ses.transseq = 0;
ses.readbuf = NULL;
ses.payload = NULL;
ses.recvseq = 0;
initqueue(&ses.writequeue);
ses.requirenext = SSH_MSG_KEXINIT;
ses.dataallowed = 1; /* we can send data until we actually
send the SSH_MSG_KEXINIT */
ses.ignorenext = 0;
ses.lastpacket = 0;
ses.reply_queue_head = NULL;
ses.reply_queue_tail = NULL;
/* set all the algos to none */
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
ses.newkeys = NULL;
ses.keys->recv.algo_crypt = &dropbear_nocipher;
ses.keys->trans.algo_crypt = &dropbear_nocipher;
ses.keys->recv.crypt_mode = &dropbear_mode_none;
ses.keys->trans.crypt_mode = &dropbear_mode_none;
ses.keys->recv.algo_mac = &dropbear_nohash;
ses.keys->trans.algo_mac = &dropbear_nohash;
ses.keys->algo_kex = NULL;
ses.keys->algo_hostkey = -1;
ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
#ifndef DISABLE_ZLIB
ses.keys->recv.zstream = NULL;
ses.keys->trans.zstream = NULL;
#endif
/* key exchange buffers */
ses.session_id = NULL;
ses.kexhashbuf = NULL;
ses.transkexinit = NULL;
ses.dh_K = NULL;
ses.remoteident = NULL;
ses.chantypes = NULL;
ses.allowprivport = 0;
TRACE(("leave session_init"))
}
void session_loop(void(*loophandler)()) {
fd_set readfd, writefd;
struct timeval timeout;
int val;
/* main loop, select()s for all sockets in use */
for(;;) {
timeout.tv_sec = select_timeout();
timeout.tv_usec = 0;
FD_ZERO(&writefd);
FD_ZERO(&readfd);
dropbear_assert(ses.payload == NULL);
/* during initial setup we flush out the KEXINIT packet before
* attempting to read the remote version string, which might block */
if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
FD_SET(ses.sock_in, &readfd);
}
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
FD_SET(ses.sock_out, &writefd);
}
/* We get woken up when signal handlers write to this pipe.
SIGCHLD in svr-chansession is the only one currently. */
FD_SET(ses.signal_pipe[0], &readfd);
/* set up for channels which can be read/written */
setchannelfds(&readfd, &writefd);
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
if (exitflag) {
dropbear_exit("Terminated by signal");
}
if (val < 0 && errno != EINTR) {
dropbear_exit("Error in select");
}
if (val <= 0) {
/* If we were interrupted or the select timed out, we still
* want to iterate over channels etc for reading, to handle
* server processes exiting etc.
* We don't want to read/write FDs. */
FD_ZERO(&writefd);
FD_ZERO(&readfd);
}
/* We'll just empty out the pipe if required. We don't do
any thing with the data, since the pipe's purpose is purely to
wake up the select() above. */
if (FD_ISSET(ses.signal_pipe[0], &readfd)) {
char x;
while (read(ses.signal_pipe[0], &x, 1) > 0) {}
}
/* check for auth timeout, rekeying required etc */
checktimeouts();
/* process session socket's incoming data */
if (ses.sock_in != -1) {
if (FD_ISSET(ses.sock_in, &readfd)) {
if (!ses.remoteident) {
/* blocking read of the version string */
read_session_identification();
} else {
read_packet();
}
}
/* Process the decrypted packet. After this, the read buffer
* will be ready for a new packet */
if (ses.payload != NULL) {
process_packet();
}
}
/* if required, flush out any queued reply packets that
were being held up during a KEX */
maybe_flush_reply_queue();
/* process pipes etc for the channels, ses.dataallowed == 0
* during rekeying ) */
channelio(&readfd, &writefd);
/* process session socket's outgoing data */
if (ses.sock_out != -1) {
if (!isempty(&ses.writequeue)) {
write_packet();
}
}
if (loophandler) {
loophandler();
}
} /* for(;;) */
/* Not reached */
}
/* clean up a session on exit */
void session_cleanup() {
TRACE(("enter session_cleanup"))
/* we can't cleanup if we don't know the session state */
if (!sessinitdone) {
TRACE(("leave session_cleanup: !sessinitdone"))
return;
}
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);
ses.session_id = NULL;
}
if (ses.hash) {
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
}
m_burn(ses.keys, sizeof(struct key_context));
m_free(ses.keys);
TRACE(("leave session_cleanup"))
}
void send_session_identification() {
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
buf_putbyte(writebuf, 0x0); /* packet type */
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, writebuf);
}
static void read_session_identification() {
/* max length of 255 chars */
char linebuf[256];
int len = 0;
char done = 0;
int i;
/* If they send more than 50 lines, something is wrong */
for (i = 0; i < 50; i++) {
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
if (len < 0 && errno != EINTR) {
/* It failed */
break;
}
if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) {
/* start of line matches */
done = 1;
break;
}
}
if (!done) {
TRACE(("err: %s for '%s'\n", strerror(errno), linebuf))
ses.remoteclosed();
} else {
/* linebuf is already null terminated */
ses.remoteident = m_malloc(len);
memcpy(ses.remoteident, linebuf, len);
}
/* Shall assume that 2.x will be backwards compatible. */
if (strncmp(ses.remoteident, "SSH-2.", 6) != 0
&& strncmp(ses.remoteident, "SSH-1.99-", 9) != 0) {
dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
}
TRACE(("remoteident: %s", ses.remoteident))
}
/* returns the length including null-terminating zero on success,
* or -1 on failure */
static int ident_readln(int fd, char* buf, int count) {
char in;
int pos = 0;
int num = 0;
fd_set fds;
struct timeval timeout;
TRACE(("enter ident_readln"))
if (count < 1) {
return -1;
}
FD_ZERO(&fds);
/* select since it's a non-blocking fd */
/* leave space to null-terminate */
while (pos < count-1) {
FD_SET(fd, &fds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL, &timeout) < 0) {
if (errno == EINTR) {
continue;
}
TRACE(("leave ident_readln: select error"))
return -1;
}
checktimeouts();
/* Have to go one byte at a time, since we don't want to read past
* the end, and have to somehow shove bytes back into the normal
* packet reader */
if (FD_ISSET(fd, &fds)) {
num = read(fd, &in, 1);
/* a "\n" is a newline, "\r" we want to read in and keep going
* so that it won't be read as part of the next line */
if (num < 0) {
/* error */
if (errno == EINTR) {
continue; /* not a real error */
}
TRACE(("leave ident_readln: read error"))
return -1;
}
if (num == 0) {
/* EOF */
TRACE(("leave ident_readln: EOF"))
return -1;
}
if (in == '\n') {
/* end of ident string */
break;
}
/* we don't want to include '\r's */
if (in != '\r') {
buf[pos] = in;
pos++;
}
}
}
buf[pos] = '\0';
TRACE(("leave ident_readln: return %d", pos+1))
return pos+1;
}
void ignore_recv_response() {
// Do nothing
TRACE(("Ignored msg_request_response"))
}
static void send_msg_keepalive() {
CHECKCLEARTOWRITE();
time_t old_time_idle = ses.last_packet_time_idle;
struct Channel *chan = get_any_ready_channel();
if (chan) {
/* Channel requests are preferable, more implementations
handle them than SSH_MSG_GLOBAL_REQUEST */
TRACE(("keepalive channel request %d", chan->index))
start_send_channel_request(chan, DROPBEAR_KEEPALIVE_STRING);
} else {
TRACE(("keepalive global request"))
/* Some peers will reply with SSH_MSG_REQUEST_FAILURE,
some will reply with SSH_MSG_UNIMPLEMENTED, some will exit. */
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
buf_putstring(ses.writepayload, DROPBEAR_KEEPALIVE_STRING,
strlen(DROPBEAR_KEEPALIVE_STRING));
}
buf_putbyte(ses.writepayload, 1); /* want_reply */
encrypt_packet();
ses.last_packet_time_keepalive_sent = monotonic_now();
/* keepalives shouldn't update idle timeout, reset it back */
ses.last_packet_time_idle = old_time_idle;
}
/* Check all timeouts which are required. Currently these are the time for
* user authentication, and the automatic rekeying. */
static void checktimeouts() {
time_t now;
now = monotonic_now();
/* we can't rekey if we haven't done remote ident exchange yet */
if (ses.remoteident == NULL) {
return;
}
if (!ses.kexstate.sentkexinit
&& (now - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
|| ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) {
TRACE(("rekeying after timeout or max data reached"))
send_msg_kexinit();
}
if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
/* Avoid sending keepalives prior to auth - those are
not valid pre-auth packet types */
/* Send keepalives if we've been idle */
if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
send_msg_keepalive();
}
/* Also send an explicit keepalive message to trigger a response
if the remote end hasn't sent us anything */
if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
&& now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
send_msg_keepalive();
}
if (now - ses.last_packet_time_keepalive_recv
>= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
dropbear_exit("Keepalive timeout");
}
}
if (opts.idle_timeout_secs > 0
&& now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
dropbear_close("Idle timeout");
}
}
static long select_timeout() {
/* determine the minimum timeout that might be required, so
as to avoid waking when unneccessary */
long ret = LONG_MAX;
if (KEX_REKEY_TIMEOUT > 0)
ret = MIN(KEX_REKEY_TIMEOUT, ret);
/* 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);
return ret;
}
const char* get_user_shell() {
/* an empty shell should be interpreted as "/bin/sh" */
if (ses.authstate.pw_shell[0] == '\0') {
return "/bin/sh";
} else {
return ses.authstate.pw_shell;
}
}
void fill_passwd(const char* username) {
struct passwd *pw = NULL;
if (ses.authstate.pw_name)
m_free(ses.authstate.pw_name);
if (ses.authstate.pw_dir)
m_free(ses.authstate.pw_dir);
if (ses.authstate.pw_shell)
m_free(ses.authstate.pw_shell);
if (ses.authstate.pw_passwd)
m_free(ses.authstate.pw_passwd);
pw = getpwnam(username);
if (!pw) {
return;
}
ses.authstate.pw_uid = pw->pw_uid;
ses.authstate.pw_gid = pw->pw_gid;
ses.authstate.pw_name = m_strdup(pw->pw_name);
ses.authstate.pw_dir = m_strdup(pw->pw_dir);
ses.authstate.pw_shell = m_strdup(pw->pw_shell);
{
char *passwd_crypt = pw->pw_passwd;
#ifdef HAVE_SHADOW_H
/* get the shadow password if possible */
struct spwd *spasswd = getspnam(ses.authstate.pw_name);
if (spasswd && spasswd->sp_pwdp) {
passwd_crypt = spasswd->sp_pwdp;
}
#endif
if (!passwd_crypt) {
/* android supposedly returns NULL */
passwd_crypt = "!!";
}
ses.authstate.pw_passwd = m_strdup(passwd_crypt);
}
}
/* 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;
}
}

285
dropbear/compat.c Normal file
View File

@ -0,0 +1,285 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* strlcat() is copyright as follows:
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* daemon() and getusershell() is copyright as follows:
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Modifications for Dropbear to getusershell() are by Paul Marinceu
*/
#include "includes.h"
#ifndef HAVE_GETUSERSHELL
static char **curshell, **shells, *strings;
static char **initshells();
#endif
#ifndef HAVE_STRLCPY
/* Implemented by matt as specified in freebsd 4.7 manpage.
* We don't require great speed, is simply for use with sshpty code */
size_t strlcpy(char *dst, const char *src, size_t size) {
size_t i;
/* this is undefined, though size==0 -> return 0 */
if (size < 1) {
return 0;
}
for (i = 0; i < size-1; i++) {
if (src[i] == '\0') {
break;
} else {
dst[i] = src[i];
}
}
dst[i] = '\0';
return strlen(src);
}
#endif /* HAVE_STRLCPY */
#ifndef HAVE_STRLCAT
/* taken from openbsd-compat for OpenSSH 3.6.1p1 */
/* "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"
*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
strlcat(dst, src, siz)
char *dst;
const char *src;
size_t siz;
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
#endif /* HAVE_STRLCAT */
#ifndef HAVE_DAEMON
/* From NetBSD - daemonise a process */
int daemon(int nochdir, int noclose) {
int fd;
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}
if (setsid() == -1)
return -1;
if (!nochdir)
(void)chdir("/");
if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
(void)close(fd);
}
return 0;
}
#endif /* HAVE_DAEMON */
#ifndef HAVE_BASENAME
char *basename(const char *path) {
char *foo = strrchr(path, '/');
if (!foo)
{
return path;
}
return ++foo;
}
#endif /* HAVE_BASENAME */
#ifndef HAVE_GETUSERSHELL
/*
* Get a list of shells from /etc/shells, if it exists.
*/
char * getusershell() {
char *ret;
if (curshell == NULL)
curshell = initshells();
ret = *curshell;
if (ret != NULL)
curshell++;
return (ret);
}
void endusershell() {
if (shells != NULL)
free(shells);
shells = NULL;
if (strings != NULL)
free(strings);
strings = NULL;
curshell = NULL;
}
void setusershell() {
curshell = initshells();
}
static char **initshells() {
/* don't touch this list. */
const char *okshells[] = { "/bin/sh", "/bin/csh", NULL };
register char **sp, *cp;
register FILE *fp;
struct stat statb;
int flen;
if (shells != NULL)
free(shells);
shells = NULL;
if (strings != NULL)
free(strings);
strings = NULL;
if ((fp = fopen("/etc/shells", "rc")) == NULL)
return (char **) okshells;
if (fstat(fileno(fp), &statb) == -1) {
(void)fclose(fp);
return (char **) okshells;
}
if ((strings = malloc((u_int)statb.st_size + 1)) == NULL) {
(void)fclose(fp);
return (char **) okshells;
}
shells = calloc((unsigned)statb.st_size / 3, sizeof (char *));
if (shells == NULL) {
(void)fclose(fp);
free(strings);
strings = NULL;
return (char **) okshells;
}
sp = shells;
cp = strings;
flen = statb.st_size;
while (fgets(cp, flen - (cp - strings), fp) != NULL) {
while (*cp != '#' && *cp != '/' && *cp != '\0')
cp++;
if (*cp == '#' || *cp == '\0')
continue;
*sp++ = cp;
while (!isspace(*cp) && *cp != '#' && *cp != '\0')
cp++;
*cp++ = '\0';
}
*sp = NULL;
(void)fclose(fp);
return (shells);
}
#endif /* HAVE_GETUSERSHELL */

56
dropbear/compat.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _COMPAT_H_
#define _COMPAT_H_
#include "includes.h"
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t size);
#endif
#ifndef HAVE_STRLCAT
size_t strlcat(char *dst, const char *src, size_t siz);
#endif
#ifndef HAVE_DAEMON
int daemon(int nochdir, int noclose);
#endif
#ifndef HAVE_BASENAME
char *basename(const char* path);
#endif
#ifndef HAVE_GETUSERSHELL
char *getusershell();
void setusershell();
void endusershell();
#endif
#ifndef _PATH_DEVNULL
#define _PATH_DEVNULL "/dev/null"
#endif
#endif /* _COMPAT_H_ */

1558
dropbear/config.guess vendored Normal file

File diff suppressed because it is too large Load Diff

450
dropbear/config.h.in Normal file
View File

@ -0,0 +1,450 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Using AIX */
#undef AIX
/* Broken getaddrinfo */
#undef BROKEN_GETADDRINFO
/* Use bundled libtom */
#undef BUNDLED_LIBTOM
/* lastlog file location */
#undef CONF_LASTLOG_FILE
/* utmpx file location */
#undef CONF_UTMPX_FILE
/* utmp file location */
#undef CONF_UTMP_FILE
/* wtmpx file location */
#undef CONF_WTMPX_FILE
/* wtmp file location */
#undef CONF_WTMP_FILE
/* Disable use of lastlog() */
#undef DISABLE_LASTLOG
/* Use PAM */
#undef DISABLE_PAM
/* Disable use of pututline() */
#undef DISABLE_PUTUTLINE
/* Disable use of pututxline() */
#undef DISABLE_PUTUTXLINE
/* Using syslog */
#undef DISABLE_SYSLOG
/* Disable use of utmp */
#undef DISABLE_UTMP
/* Disable use of utmpx */
#undef DISABLE_UTMPX
/* Disable use of wtmp */
#undef DISABLE_WTMP
/* Disable use of wtmpx */
#undef DISABLE_WTMPX
/* Use zlib */
#undef DISABLE_ZLIB
/* Define to 1 if you have the `basename' function. */
#undef HAVE_BASENAME
/* Define to 1 if you have the `clearenv' function. */
#undef HAVE_CLEARENV
/* Define if gai_strerror() returns const char * */
#undef HAVE_CONST_GAI_STRERROR_PROTO
/* Define to 1 if you have the <crypt.h> header file. */
#undef HAVE_CRYPT_H
/* Define to 1 if you have the `daemon' function. */
#undef HAVE_DAEMON
/* Use /dev/ptc & /dev/pts */
#undef HAVE_DEV_PTS_AND_PTC
/* Define to 1 if you have the `dup2' function. */
#undef HAVE_DUP2
/* Define to 1 if you have the `endutent' function. */
#undef HAVE_ENDUTENT
/* Define to 1 if you have the `endutxent' function. */
#undef HAVE_ENDUTXENT
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
/* Define to 1 if you have the `freeaddrinfo' function. */
#undef HAVE_FREEADDRINFO
/* Define to 1 if you have the `gai_strerror' function. */
#undef HAVE_GAI_STRERROR
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getnameinfo' function. */
#undef HAVE_GETNAMEINFO
/* Define to 1 if you have the `getspnam' function. */
#undef HAVE_GETSPNAM
/* Define to 1 if you have the `getusershell' function. */
#undef HAVE_GETUSERSHELL
/* Define to 1 if you have the `getutent' function. */
#undef HAVE_GETUTENT
/* Define to 1 if you have the `getutid' function. */
#undef HAVE_GETUTID
/* Define to 1 if you have the `getutline' function. */
#undef HAVE_GETUTLINE
/* Define to 1 if you have the `getutxent' function. */
#undef HAVE_GETUTXENT
/* Define to 1 if you have the `getutxid' function. */
#undef HAVE_GETUTXID
/* Define to 1 if you have the `getutxline' function. */
#undef HAVE_GETUTXLINE
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <ioctl.h> header file. */
#undef HAVE_IOCTL_H
/* Define to 1 if you have the <lastlog.h> header file. */
#undef HAVE_LASTLOG_H
/* Define to 1 if you have the <libgen.h> header file. */
#undef HAVE_LIBGEN_H
/* Define to 1 if you have the `pam' library (-lpam). */
#undef HAVE_LIBPAM
/* Define to 1 if you have the <libutil.h> header file. */
#undef HAVE_LIBUTIL_H
/* Define to 1 if you have the `z' library (-lz). */
#undef HAVE_LIBZ
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Have login() function */
#undef HAVE_LOGIN
/* Define to 1 if you have the `logout' function. */
#undef HAVE_LOGOUT
/* Define to 1 if you have the `logwtmp' function. */
#undef HAVE_LOGWTMP
/* Define to 1 if you have the `mach_absolute_time' function. */
#undef HAVE_MACH_ABSOLUTE_TIME
/* Define to 1 if you have the <mach/mach_time.h> header file. */
#undef HAVE_MACH_MACH_TIME_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#undef HAVE_MEMSET
/* Define to 1 if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H
/* Define to 1 if you have the <netinet/in.h> header file. */
#undef HAVE_NETINET_IN_H
/* Define to 1 if you have the <netinet/in_systm.h> header file. */
#undef HAVE_NETINET_IN_SYSTM_H
/* Define to 1 if you have the <netinet/tcp.h> header file. */
#undef HAVE_NETINET_TCP_H
/* Have openpty() function */
#undef HAVE_OPENPTY
/* Define to 1 if you have the `pam_fail_delay' function. */
#undef HAVE_PAM_FAIL_DELAY
/* Define to 1 if you have the <pam/pam_appl.h> header file. */
#undef HAVE_PAM_PAM_APPL_H
/* Define to 1 if you have the <paths.h> header file. */
#undef HAVE_PATHS_H
/* Define to 1 if you have the <pty.h> header file. */
#undef HAVE_PTY_H
/* Define to 1 if you have the `putenv' function. */
#undef HAVE_PUTENV
/* Define to 1 if you have the `pututline' function. */
#undef HAVE_PUTUTLINE
/* Define to 1 if you have the `pututxline' function. */
#undef HAVE_PUTUTXLINE
/* Define to 1 if you have the <security/pam_appl.h> header file. */
#undef HAVE_SECURITY_PAM_APPL_H
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if you have the `setutent' function. */
#undef HAVE_SETUTENT
/* Define to 1 if you have the `setutxent' function. */
#undef HAVE_SETUTXENT
/* Define to 1 if you have the <shadow.h> header file. */
#undef HAVE_SHADOW_H
/* Define to 1 if you have the `socket' function. */
#undef HAVE_SOCKET
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
#undef HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the <stropts.h> header file. */
#undef HAVE_STROPTS_H
/* Have struct addrinfo */
#undef HAVE_STRUCT_ADDRINFO
/* Have struct in6_addr */
#undef HAVE_STRUCT_IN6_ADDR
/* Have struct sockaddr_in6 */
#undef HAVE_STRUCT_SOCKADDR_IN6
/* Define to 1 if the system has the type `struct sockaddr_storage'. */
#undef HAVE_STRUCT_SOCKADDR_STORAGE
/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
/* Define to 1 if `ut_addr' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_ADDR
/* Define to 1 if `ut_addr_v6' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_ADDR_V6
/* Define to 1 if `ut_host' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_HOST
/* Define to 1 if `ut_id' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_ID
/* Define to 1 if `ut_syslen' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_SYSLEN
/* Define to 1 if `ut_time' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_TIME
/* Define to 1 if `ut_tv' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_TV
/* Define to 1 if `ut_type' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_TYPE
/* Define to 1 if `ut_addr' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_ADDR
/* Define to 1 if `ut_addr_v6' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_ADDR_V6
/* Define to 1 if `ut_exit' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_EXIT
/* Define to 1 if `ut_host' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_HOST
/* Define to 1 if `ut_id' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_ID
/* Define to 1 if `ut_pid' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_PID
/* Define to 1 if `ut_time' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_TIME
/* Define to 1 if `ut_tv' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_TV
/* Define to 1 if `ut_type' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_TYPE
/* Define to 1 if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/uio.h> header file. */
#undef HAVE_SYS_UIO_H
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
/* Define to 1 if you have the <termios.h> header file. */
#undef HAVE_TERMIOS_H
/* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T
/* Define to 1 if the system has the type `uint32_t'. */
#undef HAVE_UINT32_T
/* Define to 1 if the system has the type `uint8_t'. */
#undef HAVE_UINT8_T
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `updwtmp' function. */
#undef HAVE_UPDWTMP
/* Define to 1 if you have the <util.h> header file. */
#undef HAVE_UTIL_H
/* Define to 1 if you have the `utmpname' function. */
#undef HAVE_UTMPNAME
/* Define to 1 if you have the `utmpxname' function. */
#undef HAVE_UTMPXNAME
/* Define to 1 if you have the <utmpx.h> header file. */
#undef HAVE_UTMPX_H
/* Define to 1 if you have the <utmp.h> header file. */
#undef HAVE_UTMP_H
/* Define to 1 if the system has the type `u_int16_t'. */
#undef HAVE_U_INT16_T
/* Define to 1 if the system has the type `u_int32_t'. */
#undef HAVE_U_INT32_T
/* Define to 1 if the system has the type `u_int8_t'. */
#undef HAVE_U_INT8_T
/* Define to 1 if you have the `writev' function. */
#undef HAVE_WRITEV
/* Define to 1 if you have the `_getpty' function. */
#undef HAVE__GETPTY
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to the type of arg 1 for `select'. */
#undef SELECT_TYPE_ARG1
/* Define to the type of args 2, 3 and 4 for `select'. */
#undef SELECT_TYPE_ARG234
/* Define to the type of arg 5 for `select'. */
#undef SELECT_TYPE_ARG5
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Use /dev/ptmx */
#undef USE_DEV_PTMX
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `int' if <sys/types.h> doesn't define. */
#undef gid_t
/* Define to `int' if <sys/types.h> does not define. */
#undef mode_t
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
/* type to use in place of socklen_t if not defined */
#undef socklen_t
/* Define to `int' if <sys/types.h> doesn't define. */
#undef uid_t

1793
dropbear/config.sub vendored Normal file

File diff suppressed because it is too large Load Diff

8143
dropbear/configure vendored Executable file

File diff suppressed because it is too large Load Diff

725
dropbear/configure.ac Normal file
View File

@ -0,0 +1,725 @@
# -*- Autoconf -*-
# Process this file with autoconf and autoheader to produce a configure script.
# This Autoconf file was cobbled from various locations. In particular, a bunch
# of the platform checks have been taken straight from OpenSSH's configure.ac
# Huge thanks to them for dealing with the horrible platform-specifics :)
AC_PREREQ(2.59)
AC_INIT
AC_CONFIG_SRCDIR(buffer.c)
OLDCFLAGS=$CFLAGS
# Checks for programs.
AC_PROG_CC
AC_PROG_MAKE_SET
if test -z "$LD" ; then
LD=$CC
fi
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 -Wno-pointer-sign"
fi
# large file support is useful for scp
AC_SYS_LARGEFILE
# Host specific options
# this isn't a definitive list of hosts, they are just added as required
AC_CANONICAL_HOST
case "$host" in
*-*-linux*)
no_ptmx_check=1
;;
*-*-solaris*)
CFLAGS="$CFLAGS -I/usr/local/include"
LDFLAGS="$LDFLAGS -L/usr/local/lib -R/usr/local/lib"
conf_lastlog_location="/var/adm/lastlog"
AC_MSG_CHECKING(for obsolete utmp and wtmp in solaris2.x)
sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
if test "$sol2ver" -ge 8; then
AC_MSG_RESULT(yes)
AC_DEFINE(DISABLE_UTMP,,Disable utmp)
AC_DEFINE(DISABLE_WTMP,,Disable wtmp)
else
AC_MSG_RESULT(no)
fi
AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")
AC_CHECK_LIB(nsl, yp_match, LIBS="$LIBS -lnsl")
;;
*-*-aix*)
AC_DEFINE(AIX,,Using AIX)
# OpenSSH thinks it's broken. If it isn't, let me know.
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
;;
*-*-hpux*)
LIBS="$LIBS -lsec"
# It's probably broken.
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
;;
*-dec-osf*)
AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
;;
esac
AC_CHECK_TOOL(AR, ar, :)
AC_CHECK_TOOL(RANLIB, ranlib, :)
AC_CHECK_TOOL(STRIP, strip, :)
AC_CHECK_TOOL(INSTALL, install, :)
dnl Can't use login() or logout() with uclibc
AC_CHECK_DECL(__UCLIBC__,
[
no_loginfunc_check=1
AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.])
],,,)
# Checks for libraries.
AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt")
AC_SUBST(CRYPTLIB)
# Check if zlib is needed
AC_ARG_WITH(zlib,
[ --with-zlib=PATH Use zlib in PATH],
[
# option is given
if test -d "$withval/lib"; then
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
else
LDFLAGS="-L${withval} ${LDFLAGS}"
fi
if test -d "$withval/include"; then
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
else
CPPFLAGS="-I${withval} ${CPPFLAGS}"
fi
]
)
AC_ARG_ENABLE(zlib,
[ --disable-zlib Don't include zlib support],
[
if test "x$enableval" = "xno"; then
AC_DEFINE(DISABLE_ZLIB,, Use zlib)
AC_MSG_NOTICE(Disabling zlib)
else
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
AC_MSG_NOTICE(Enabling zlib)
fi
],
[
# if not disabled, check for zlib
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
AC_MSG_NOTICE(Enabling zlib)
]
)
# Check if pam is needed
AC_ARG_WITH(pam,
[ --with-pam=PATH Use pam in PATH],
[
# option is given
if test -d "$withval/lib"; then
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
else
LDFLAGS="-L${withval} ${LDFLAGS}"
fi
if test -d "$withval/include"; then
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
else
CPPFLAGS="-I${withval} ${CPPFLAGS}"
fi
]
)
AC_ARG_ENABLE(pam,
[ --enable-pam Try to include PAM support],
[
if test "x$enableval" = "xyes"; then
AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
AC_MSG_NOTICE(Enabling PAM)
AC_CHECK_FUNCS(pam_fail_delay)
else
AC_DEFINE(DISABLE_PAM,, Use PAM)
AC_MSG_NOTICE(Disabling PAM)
fi
],
[
# disable it by default
AC_DEFINE(DISABLE_PAM,, Use PAM)
AC_MSG_NOTICE(Disabling PAM)
]
)
AC_ARG_ENABLE(openpty,
[ --disable-openpty Don't use openpty, use alternative method],
[
if test "x$enableval" = "xno"; then
AC_MSG_NOTICE(Not using openpty)
else
AC_MSG_NOTICE(Using openpty if available)
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY,,Have openpty() function)])
fi
],
[
AC_MSG_NOTICE(Using openpty if available)
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY)])
]
)
AC_ARG_ENABLE(syslog,
[ --disable-syslog Don't include syslog support],
[
if test "x$enableval" = "xno"; then
AC_DEFINE(DISABLE_SYSLOG,, Using syslog)
AC_MSG_NOTICE(Disabling syslog)
else
AC_MSG_NOTICE(Enabling syslog)
fi
],
[
AC_MSG_NOTICE(Enabling syslog)
]
)
AC_ARG_ENABLE(shadow,
[ --disable-shadow Don't use shadow passwords (if available)],
[
if test "x$enableval" = "xno"; then
AC_MSG_NOTICE(Not using shadow passwords)
else
AC_CHECK_HEADERS([shadow.h])
AC_MSG_NOTICE(Using shadow passwords if available)
fi
],
[
AC_CHECK_HEADERS([shadow.h])
AC_MSG_NOTICE(Using shadow passwords if available)
]
)
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h netinet/in_systm.h sys/uio.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_UID_T
AC_TYPE_MODE_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_CHECK_TYPES([uint8_t, u_int8_t, uint16_t, u_int16_t, uint32_t, u_int32_t])
AC_CHECK_TYPES([struct sockaddr_storage])
AC_CHECK_TYPE([socklen_t], ,[
AC_MSG_CHECKING([for socklen_t equivalent])
AC_CACHE_VAL([curl_cv_socklen_t_equiv],
[
# Systems have either "struct sockaddr *" or
# "void *" as the second argument to getpeername
curl_cv_socklen_t_equiv=
for arg2 in "struct sockaddr" void; do
for t in int size_t unsigned long "unsigned long"; do
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
int getpeername (int, $arg2 *, $t *);
]],[[
$t len;
getpeername(0,0,&len);
]])],[
curl_cv_socklen_t_equiv="$t"
break
])
done
done
if test "x$curl_cv_socklen_t_equiv" = x; then
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
fi
])
AC_MSG_RESULT($curl_cv_socklen_t_equiv)
AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
[type to use in place of socklen_t if not defined])],
[#include <sys/types.h>
#include <sys/socket.h>])
# for the fake-rfc2553 stuff - straight from OpenSSH
AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
]],
[[ struct sockaddr_storage s; ]])],
[ ac_cv_have_struct_sockaddr_storage="yes" ],
[ ac_cv_have_struct_sockaddr_storage="no" ]
)
])
if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE)
fi
AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <netinet/in.h>
]],
[[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
[ ac_cv_have_struct_sockaddr_in6="yes" ],
[ ac_cv_have_struct_sockaddr_in6="no" ]
)
])
if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,,Have struct sockaddr_in6)
fi
AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <netinet/in.h>
]],
[[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
[ ac_cv_have_struct_in6_addr="yes" ],
[ ac_cv_have_struct_in6_addr="no" ]
)
])
if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
AC_DEFINE(HAVE_STRUCT_IN6_ADDR,,Have struct in6_addr)
fi
AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
]],
[[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
[ ac_cv_have_struct_addrinfo="yes" ],
[ ac_cv_have_struct_addrinfo="no" ]
)
])
if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
AC_DEFINE(HAVE_STRUCT_ADDRINFO,,Have struct addrinfo)
fi
# IRIX has a const char return value for gai_strerror()
AC_CHECK_FUNCS(gai_strerror,[
AC_DEFINE(HAVE_GAI_STRERROR)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
const char *gai_strerror(int);]],[[
char *str;
str = gai_strerror(0);]])],[
AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1,
[Define if gai_strerror() returns const char *])])])
# for loginrec.c
AC_CHECK_MEMBERS([struct utmp.ut_host, struct utmp.ut_pid, struct utmp.ut_type, struct utmp.ut_tv, struct utmp.ut_id, struct utmp.ut_addr, struct utmp.ut_addr_v6, struct utmp.ut_exit, struct utmp.ut_time],,,[
#include <sys/types.h>
#if HAVE_UTMP_H
#include <utmp.h>
#endif
])
AC_CHECK_MEMBERS([struct utmpx.ut_host, struct utmpx.ut_syslen, struct utmpx.ut_type, struct utmpx.ut_id, struct utmpx.ut_addr, struct utmpx.ut_addr_v6, struct utmpx.ut_time, struct utmpx.ut_tv],,,[
#include <sys/types.h>
#include <sys/socket.h>
#if HAVE_UTMPX_H
#include <utmpx.h>
#endif
])
AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family],,,[
#include <sys/types.h>
#include <sys/socket.h>
])
AC_CHECK_FUNCS(endutent getutent getutid getutline pututline setutent)
AC_CHECK_FUNCS(utmpname)
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.
Default is to use system if available, otherwise bundled.],
[
if test "x$enableval" = "xyes"; then
BUNDLED_LIBTOM=1
AC_MSG_NOTICE(Forcing bundled libtom*)
else
BUNDLED_LIBTOM=0
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath",
[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt",
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
fi
],
[
BUNDLED_LIBTOM=0
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath", BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt", BUNDLED_LIBTOM=1)
]
)
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
dnl allow user to disable some login recording features
AC_ARG_ENABLE(lastlog,
[ --disable-lastlog Disable use of lastlog even if detected [no]],
[ AC_DEFINE(DISABLE_LASTLOG,,Disable use of lastlog()) ]
)
AC_ARG_ENABLE(utmp,
[ --disable-utmp Disable use of utmp even if detected [no]],
[ AC_DEFINE(DISABLE_UTMP,,Disable use of utmp) ]
)
AC_ARG_ENABLE(utmpx,
[ --disable-utmpx Disable use of utmpx even if detected [no]],
[ AC_DEFINE(DISABLE_UTMPX,,Disable use of utmpx) ]
)
AC_ARG_ENABLE(wtmp,
[ --disable-wtmp Disable use of wtmp even if detected [no]],
[ AC_DEFINE(DISABLE_WTMP,,Disable use of wtmp) ]
)
AC_ARG_ENABLE(wtmpx,
[ --disable-wtmpx Disable use of wtmpx even if detected [no]],
[ AC_DEFINE(DISABLE_WTMPX,,Disable use of wtmpx) ]
)
AC_ARG_ENABLE(loginfunc,
[ --disable-loginfunc Disable use of login() etc. [no]],
[ no_loginfunc_check=1
AC_MSG_NOTICE(Not using login() etc) ]
)
AC_ARG_ENABLE(pututline,
[ --disable-pututline Disable use of pututline() etc. ([uw]tmp) [no]],
[ AC_DEFINE(DISABLE_PUTUTLINE,,Disable use of pututline()) ]
)
AC_ARG_ENABLE(pututxline,
[ --disable-pututxline Disable use of pututxline() etc. ([uw]tmpx) [no]],
[ AC_DEFINE(DISABLE_PUTUTXLINE,,Disable use of pututxline()) ]
)
AC_ARG_WITH(lastlog,
[ --with-lastlog=FILE|DIR specify lastlog location [common locations]],
[
if test "x$withval" = "xno" ; then
AC_DEFINE(DISABLE_LASTLOG)
else
conf_lastlog_location=$withval
fi
]
)
if test -z "$no_loginfunc_check"; then
dnl Checks for libutil functions (login(), logout() etc, not openpty() )
AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,,Have login() function)])
AC_CHECK_FUNCS(logout updwtmp logwtmp)
fi
dnl lastlog, [uw]tmpx? detection
dnl NOTE: set the paths in the platform section to avoid the
dnl need for command-line parameters
dnl lastlog and [uw]tmp are subject to a file search if all else fails
dnl lastlog detection
dnl NOTE: the code itself will detect if lastlog is a directory
AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
# include <lastlog.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifdef HAVE_LOGIN_H
# include <login.h>
#endif
]],
[[ char *lastlog = LASTLOG_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[
AC_MSG_RESULT(no)
AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
# include <lastlog.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]],
[[ char *lastlog = _PATH_LASTLOG; ]])],
[ AC_MSG_RESULT(yes) ],
[
AC_MSG_RESULT(no)
system_lastlog_path=no
])
]
)
if test -z "$conf_lastlog_location"; then
if test x"$system_lastlog_path" = x"no" ; then
for f in /var/log/lastlog /usr/adm/lastlog /var/adm/lastlog /etc/security/lastlog ; do
if (test -d "$f" || test -f "$f") ; then
conf_lastlog_location=$f
fi
done
if test -z "$conf_lastlog_location"; then
AC_MSG_WARN([** Cannot find lastlog **])
dnl Don't define DISABLE_LASTLOG - that means we don't try wtmp/wtmpx
fi
fi
fi
if test -n "$conf_lastlog_location"; then
AC_DEFINE_UNQUOTED(CONF_LASTLOG_FILE, "$conf_lastlog_location", lastlog file location)
fi
dnl utmp detection
AC_MSG_CHECKING([if your system defines UTMP_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]],
[[ char *utmp = UTMP_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
system_utmp_path=no ]
)
if test -z "$conf_utmp_location"; then
if test x"$system_utmp_path" = x"no" ; then
for f in /etc/utmp /usr/adm/utmp /var/run/utmp; do
if test -f $f ; then
conf_utmp_location=$f
fi
done
if test -z "$conf_utmp_location"; then
AC_DEFINE(DISABLE_UTMP)
fi
fi
fi
if test -n "$conf_utmp_location"; then
AC_DEFINE_UNQUOTED(CONF_UTMP_FILE, "$conf_utmp_location", utmp file location)
fi
dnl wtmp detection
AC_MSG_CHECKING([if your system defines WTMP_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]],
[[ char *wtmp = WTMP_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
system_wtmp_path=no ]
)
if test -z "$conf_wtmp_location"; then
if test x"$system_wtmp_path" = x"no" ; then
for f in /usr/adm/wtmp /var/log/wtmp; do
if test -f $f ; then
conf_wtmp_location=$f
fi
done
if test -z "$conf_wtmp_location"; then
AC_DEFINE(DISABLE_WTMP)
fi
fi
fi
if test -n "$conf_wtmp_location"; then
AC_DEFINE_UNQUOTED(CONF_WTMP_FILE, "$conf_wtmp_location", wtmp file location)
fi
dnl utmpx detection - I don't know any system so perverse as to require
dnl utmpx, but not define UTMPX_FILE (ditto wtmpx.) No doubt it's out
dnl there, though.
AC_MSG_CHECKING([if your system defines UTMPX_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]],
[[ char *utmpx = UTMPX_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
system_utmpx_path=no ]
)
if test -z "$conf_utmpx_location"; then
if test x"$system_utmpx_path" = x"no" ; then
AC_DEFINE(DISABLE_UTMPX)
fi
else
AC_DEFINE_UNQUOTED(CONF_UTMPX_FILE, "$conf_utmpx_location", utmpx file location)
fi
dnl wtmpx detection
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
#ifdef HAVE_UTMPX_H
# include <utmpx.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]],
[[ char *wtmpx = WTMPX_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
system_wtmpx_path=no ]
)
if test -z "$conf_wtmpx_location"; then
if test x"$system_wtmpx_path" = x"no" ; then
AC_DEFINE(DISABLE_WTMPX)
fi
else
AC_DEFINE_UNQUOTED(CONF_WTMPX_FILE, "$conf_wtmpx_location", wtmpx file location)
fi
# Checks for library functions.
AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
# Solaris needs ptmx
if test -z "$no_ptmx_check" ; then
if test x"$cross_compiling" = x"no" ; then
if test -e /dev/ptmx ; then
AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx)
fi
else
AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling])
fi
fi
if test -z "$no_ptc_check" ; then
if test x"$cross_compiling" = x"no" ; then
if test -e /dev/ptc ; then
AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts)
fi
else
AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling])
fi
fi
AC_EXEEXT
# XXX there must be a nicer way to do this
AS_MKDIR_P(libtomcrypt/src/ciphers/aes)
AS_MKDIR_P(libtomcrypt/src/ciphers/safer)
AS_MKDIR_P(libtomcrypt/src/ciphers/twofish)
AS_MKDIR_P(libtomcrypt/src/encauth/ccm)
AS_MKDIR_P(libtomcrypt/src/encauth/eax)
AS_MKDIR_P(libtomcrypt/src/encauth/gcm)
AS_MKDIR_P(libtomcrypt/src/encauth/ocb)
AS_MKDIR_P(libtomcrypt/src/hashes)
AS_MKDIR_P(libtomcrypt/src/hashes/chc)
AS_MKDIR_P(libtomcrypt/src/hashes/helper)
AS_MKDIR_P(libtomcrypt/src/hashes/sha2)
AS_MKDIR_P(libtomcrypt/src/hashes/whirl)
AS_MKDIR_P(libtomcrypt/src/mac/hmac)
AS_MKDIR_P(libtomcrypt/src/mac/omac)
AS_MKDIR_P(libtomcrypt/src/mac/pelican)
AS_MKDIR_P(libtomcrypt/src/mac/pmac)
AS_MKDIR_P(libtomcrypt/src/mac/f9)
AS_MKDIR_P(libtomcrypt/src/mac/xcbc)
AS_MKDIR_P(libtomcrypt/src/math/fp)
AS_MKDIR_P(libtomcrypt/src/misc/base64)
AS_MKDIR_P(libtomcrypt/src/misc/crypt)
AS_MKDIR_P(libtomcrypt/src/misc/mpi)
AS_MKDIR_P(libtomcrypt/src/misc/pkcs5)
AS_MKDIR_P(libtomcrypt/src/modes/cbc)
AS_MKDIR_P(libtomcrypt/src/modes/cfb)
AS_MKDIR_P(libtomcrypt/src/modes/ctr)
AS_MKDIR_P(libtomcrypt/src/modes/ecb)
AS_MKDIR_P(libtomcrypt/src/modes/ofb)
AS_MKDIR_P(libtomcrypt/src/modes/f8)
AS_MKDIR_P(libtomcrypt/src/modes/lrw)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/bit)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/boolean)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/choice)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/ia5)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/integer)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/object_identifier)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/octet)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/printable_string)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/sequence)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/set)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/short_integer)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utctime)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utf8)
AS_MKDIR_P(libtomcrypt/src/pk/dh)
AS_MKDIR_P(libtomcrypt/src/pk/dsa)
AS_MKDIR_P(libtomcrypt/src/pk/ecc)
AS_MKDIR_P(libtomcrypt/src/pk/katja)
AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
AS_MKDIR_P(libtomcrypt/src/pk/rsa)
AS_MKDIR_P(libtomcrypt/src/prngs)
AC_CONFIG_HEADER(config.h)
AC_CONFIG_FILES(Makefile libtomcrypt/Makefile libtommath/Makefile)
AC_OUTPUT
AC_MSG_NOTICE()
if test $BUNDLED_LIBTOM = 1 ; then
AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath)
else
AC_MSG_NOTICE(Using system libtomcrypt and libtommath)
fi
AC_MSG_NOTICE()
AC_MSG_NOTICE(Now edit options.h to choose features.)

75
dropbear/crypto_desc.c Normal file
View File

@ -0,0 +1,75 @@
#include "includes.h"
#include "dbutil.h"
#include "crypto_desc.h"
#include "ltc_prng.h"
#include "ecc.h"
#ifdef DROPBEAR_LTC_PRNG
int dropbear_ltc_prng = -1;
#endif
/* Register the compiled in ciphers.
* This should be run before using any of the ciphers/hashes */
void crypto_init() {
const struct ltc_cipher_descriptor *regciphers[] = {
#ifdef DROPBEAR_AES
&aes_desc,
#endif
#ifdef DROPBEAR_BLOWFISH
&blowfish_desc,
#endif
#ifdef DROPBEAR_TWOFISH
&twofish_desc,
#endif
#ifdef DROPBEAR_3DES
&des3_desc,
#endif
NULL
};
const struct ltc_hash_descriptor *reghashes[] = {
/* we need sha1 for hostkey stuff regardless */
&sha1_desc,
#ifdef DROPBEAR_MD5_HMAC
&md5_desc,
#endif
#ifdef DROPBEAR_SHA256
&sha256_desc,
#endif
#ifdef DROPBEAR_SHA384
&sha384_desc,
#endif
#ifdef DROPBEAR_SHA512
&sha512_desc,
#endif
NULL
};
int i;
for (i = 0; regciphers[i] != NULL; i++) {
if (register_cipher(regciphers[i]) == -1) {
dropbear_exit("Error registering crypto");
}
}
for (i = 0; reghashes[i] != NULL; i++) {
if (register_hash(reghashes[i]) == -1) {
dropbear_exit("Error registering crypto");
}
}
#ifdef DROPBEAR_LTC_PRNG
dropbear_ltc_prng = register_prng(&dropbear_prng_desc);
if (dropbear_ltc_prng == -1) {
dropbear_exit("Error registering crypto");
}
#endif
#ifdef DROPBEAR_ECC
ltc_mp = ltm_desc;
dropbear_ecc_fill_dp();
#endif
}

9
dropbear/crypto_desc.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _CRYPTO_DESC_H
#define _CRYPTO_DESC_H
void crypto_init();
extern int dropbear_ltc_prng;
#endif /* _CRYPTO_DESC_H */

734
dropbear/curve25519-donna.c Normal file
View File

@ -0,0 +1,734 @@
/* Copyright 2008, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* curve25519-donna: Curve25519 elliptic curve, public key function
*
* http://code.google.com/p/curve25519-donna/
*
* Adam Langley <agl@imperialviolet.org>
*
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
*
* More information about curve25519 can be found here
* http://cr.yp.to/ecdh.html
*
* djb's sample implementation of curve25519 is written in a special assembly
* language called qhasm and uses the floating point registers.
*
* This is, almost, a clean room reimplementation from the curve25519 paper. It
* uses many of the tricks described therein. Only the crecip function is taken
* from the sample implementation.
*/
#include <string.h>
#include <stdint.h>
#ifdef _MSC_VER
#define inline __inline
#endif
typedef uint8_t u8;
typedef int32_t s32;
typedef int64_t limb;
/* Field element representation:
*
* Field elements are written as an array of signed, 64-bit limbs, least
* significant first. The value of the field element is:
* x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
*
* i.e. the limbs are 26, 25, 26, 25, ... bits wide.
*/
/* Sum two numbers: output += in */
static void fsum(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; i += 2) {
output[0+i] = (output[0+i] + in[0+i]);
output[1+i] = (output[1+i] + in[1+i]);
}
}
/* Find the difference of two numbers: output = in - output
* (note the order of the arguments!)
*/
static void fdifference(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = (in[i] - output[i]);
}
}
/* Multiply a number by a scalar: output = in * scalar */
static void fscalar_product(limb *output, const limb *in, const limb scalar) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = in[i] * scalar;
}
}
/* Multiply two numbers: output = in2 * in
*
* output must be distinct to both inputs. The inputs are reduced coefficient
* form, the output is not.
*/
static void fproduct(limb *output, const limb *in2, const limb *in) {
output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
((limb) ((s32) in2[1])) * ((s32) in[0]);
output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[2]) +
((limb) ((s32) in2[2])) * ((s32) in[0]);
output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
((limb) ((s32) in2[2])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[3]) +
((limb) ((s32) in2[3])) * ((s32) in[0]);
output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
((limb) ((s32) in2[3])) * ((s32) in[1])) +
((limb) ((s32) in2[0])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[0]);
output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
((limb) ((s32) in2[3])) * ((s32) in[2]) +
((limb) ((s32) in2[1])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[0]);
output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
((limb) ((s32) in2[1])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[1])) +
((limb) ((s32) in2[2])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[2]) +
((limb) ((s32) in2[0])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[0]);
output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[3]) +
((limb) ((s32) in2[2])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[2]) +
((limb) ((s32) in2[1])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[0]);
output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[3]) +
((limb) ((s32) in2[1])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[1])) +
((limb) ((s32) in2[2])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[2]) +
((limb) ((s32) in2[0])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[0]);
output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[4]) +
((limb) ((s32) in2[3])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[3]) +
((limb) ((s32) in2[2])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[2]) +
((limb) ((s32) in2[1])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[0]);
output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
((limb) ((s32) in2[3])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[3]) +
((limb) ((s32) in2[1])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[1])) +
((limb) ((s32) in2[4])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[4]) +
((limb) ((s32) in2[2])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[2]);
output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[5]) +
((limb) ((s32) in2[4])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[4]) +
((limb) ((s32) in2[3])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[3]) +
((limb) ((s32) in2[2])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[2]);
output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[5]) +
((limb) ((s32) in2[3])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[3])) +
((limb) ((s32) in2[4])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[4]);
output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[6]) +
((limb) ((s32) in2[5])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[5]) +
((limb) ((s32) in2[4])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[4]);
output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
((limb) ((s32) in2[5])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[5])) +
((limb) ((s32) in2[6])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[6]);
output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[7]) +
((limb) ((s32) in2[6])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[6]);
output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[7]));
output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[8]);
output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
}
/* Reduce a long form to a short form by taking the input mod 2^255 - 19. */
static void freduce_degree(limb *output) {
/* Each of these shifts and adds ends up multiplying the value by 19. */
output[8] += output[18] << 4;
output[8] += output[18] << 1;
output[8] += output[18];
output[7] += output[17] << 4;
output[7] += output[17] << 1;
output[7] += output[17];
output[6] += output[16] << 4;
output[6] += output[16] << 1;
output[6] += output[16];
output[5] += output[15] << 4;
output[5] += output[15] << 1;
output[5] += output[15];
output[4] += output[14] << 4;
output[4] += output[14] << 1;
output[4] += output[14];
output[3] += output[13] << 4;
output[3] += output[13] << 1;
output[3] += output[13];
output[2] += output[12] << 4;
output[2] += output[12] << 1;
output[2] += output[12];
output[1] += output[11] << 4;
output[1] += output[11] << 1;
output[1] += output[11];
output[0] += output[10] << 4;
output[0] += output[10] << 1;
output[0] += output[10];
}
#if (-1 & 3) != 3
#error "This code only works on a two's complement system"
#endif
/* return v / 2^26, using only shifts and adds. */
static inline limb
div_by_2_26(const limb v)
{
/* High word of v; no shift needed*/
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
/* Set to all 1s if v was negative; else set to 0s. */
const int32_t sign = ((int32_t) highword) >> 31;
/* Set to 0x3ffffff if v was negative; else set to 0. */
const int32_t roundoff = ((uint32_t) sign) >> 6;
/* Should return v / (1<<26) */
return (v + roundoff) >> 26;
}
/* return v / (2^25), using only shifts and adds. */
static inline limb
div_by_2_25(const limb v)
{
/* High word of v; no shift needed*/
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
/* Set to all 1s if v was negative; else set to 0s. */
const int32_t sign = ((int32_t) highword) >> 31;
/* Set to 0x1ffffff if v was negative; else set to 0. */
const int32_t roundoff = ((uint32_t) sign) >> 7;
/* Should return v / (1<<25) */
return (v + roundoff) >> 25;
}
static inline s32
div_s32_by_2_25(const s32 v)
{
const s32 roundoff = ((uint32_t)(v >> 31)) >> 7;
return (v + roundoff) >> 25;
}
/* Reduce all coefficients of the short form input so that |x| < 2^26.
*
* On entry: |output[i]| < 2^62
*/
static void freduce_coefficients(limb *output) {
unsigned i;
output[10] = 0;
for (i = 0; i < 10; i += 2) {
limb over = div_by_2_26(output[i]);
output[i] -= over << 26;
output[i+1] += over;
over = div_by_2_25(output[i+1]);
output[i+1] -= over << 25;
output[i+2] += over;
}
/* Now |output[10]| < 2 ^ 38 and all other coefficients are reduced. */
output[0] += output[10] << 4;
output[0] += output[10] << 1;
output[0] += output[10];
output[10] = 0;
/* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19 * 2^38
* So |over| will be no more than 77825 */
{
limb over = div_by_2_26(output[0]);
output[0] -= over << 26;
output[1] += over;
}
/* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 77825
* So |over| will be no more than 1. */
{
/* output[1] fits in 32 bits, so we can use div_s32_by_2_25 here. */
s32 over32 = div_s32_by_2_25((s32) output[1]);
output[1] -= over32 << 25;
output[2] += over32;
}
/* Finally, output[0,1,3..9] are reduced, and output[2] is "nearly reduced":
* we have |output[2]| <= 2^26. This is good enough for all of our math,
* but it will require an extra freduce_coefficients before fcontract. */
}
/* A helpful wrapper around fproduct: output = in * in2.
*
* output must be distinct to both inputs. The output is reduced degree and
* reduced coefficient.
*/
static void
fmul(limb *output, const limb *in, const limb *in2) {
limb t[19];
fproduct(t, in, in2);
freduce_degree(t);
freduce_coefficients(t);
memcpy(output, t, sizeof(limb) * 10);
}
static void fsquare_inner(limb *output, const limb *in) {
output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
((limb) ((s32) in[0])) * ((s32) in[2]));
output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
((limb) ((s32) in[0])) * ((s32) in[3]));
output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
((limb) ((s32) in[1])) * ((s32) in[4]) +
((limb) ((s32) in[0])) * ((s32) in[5]));
output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
((limb) ((s32) in[2])) * ((s32) in[4]) +
((limb) ((s32) in[0])) * ((s32) in[6]) +
2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
((limb) ((s32) in[2])) * ((s32) in[5]) +
((limb) ((s32) in[1])) * ((s32) in[6]) +
((limb) ((s32) in[0])) * ((s32) in[7]));
output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
((limb) ((s32) in[0])) * ((s32) in[8]) +
2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
((limb) ((s32) in[3])) * ((s32) in[5])));
output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
((limb) ((s32) in[3])) * ((s32) in[6]) +
((limb) ((s32) in[2])) * ((s32) in[7]) +
((limb) ((s32) in[1])) * ((s32) in[8]) +
((limb) ((s32) in[0])) * ((s32) in[9]));
output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
((limb) ((s32) in[4])) * ((s32) in[6]) +
((limb) ((s32) in[2])) * ((s32) in[8]) +
2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
((limb) ((s32) in[1])) * ((s32) in[9])));
output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
((limb) ((s32) in[4])) * ((s32) in[7]) +
((limb) ((s32) in[3])) * ((s32) in[8]) +
((limb) ((s32) in[2])) * ((s32) in[9]));
output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
((limb) ((s32) in[3])) * ((s32) in[9])));
output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
((limb) ((s32) in[5])) * ((s32) in[8]) +
((limb) ((s32) in[4])) * ((s32) in[9]));
output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
((limb) ((s32) in[6])) * ((s32) in[8]) +
2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
((limb) ((s32) in[6])) * ((s32) in[9]));
output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
}
static void
fsquare(limb *output, const limb *in) {
limb t[19];
fsquare_inner(t, in);
freduce_degree(t);
freduce_coefficients(t);
memcpy(output, t, sizeof(limb) * 10);
}
/* Take a little-endian, 32-byte number and expand it into polynomial form */
static void
fexpand(limb *output, const u8 *input) {
#define F(n,start,shift,mask) \
output[n] = ((((limb) input[start + 0]) | \
((limb) input[start + 1]) << 8 | \
((limb) input[start + 2]) << 16 | \
((limb) input[start + 3]) << 24) >> shift) & mask;
F(0, 0, 0, 0x3ffffff);
F(1, 3, 2, 0x1ffffff);
F(2, 6, 3, 0x3ffffff);
F(3, 9, 5, 0x1ffffff);
F(4, 12, 6, 0x3ffffff);
F(5, 16, 0, 0x1ffffff);
F(6, 19, 1, 0x3ffffff);
F(7, 22, 3, 0x1ffffff);
F(8, 25, 4, 0x3ffffff);
F(9, 28, 6, 0x3ffffff);
#undef F
}
#if (-32 >> 1) != -16
#error "This code only works when >> does sign-extension on negative numbers"
#endif
/* Take a fully reduced polynomial form number and contract it into a
* little-endian, 32-byte array
*/
static void
fcontract(u8 *output, limb *input) {
int i;
int j;
for (j = 0; j < 2; ++j) {
for (i = 0; i < 9; ++i) {
if ((i & 1) == 1) {
/* This calculation is a time-invariant way to make input[i] positive
by borrowing from the next-larger limb.
*/
const s32 mask = (s32)(input[i]) >> 31;
const s32 carry = -(((s32)(input[i]) & mask) >> 25);
input[i] = (s32)(input[i]) + (carry << 25);
input[i+1] = (s32)(input[i+1]) - carry;
} else {
const s32 mask = (s32)(input[i]) >> 31;
const s32 carry = -(((s32)(input[i]) & mask) >> 26);
input[i] = (s32)(input[i]) + (carry << 26);
input[i+1] = (s32)(input[i+1]) - carry;
}
}
{
const s32 mask = (s32)(input[9]) >> 31;
const s32 carry = -(((s32)(input[9]) & mask) >> 25);
input[9] = (s32)(input[9]) + (carry << 25);
input[0] = (s32)(input[0]) - (carry * 19);
}
}
/* The first borrow-propagation pass above ended with every limb
except (possibly) input[0] non-negative.
Since each input limb except input[0] is decreased by at most 1
by a borrow-propagation pass, the second borrow-propagation pass
could only have wrapped around to decrease input[0] again if the
first pass left input[0] negative *and* input[1] through input[9]
were all zero. In that case, input[1] is now 2^25 - 1, and this
last borrow-propagation step will leave input[1] non-negative.
*/
{
const s32 mask = (s32)(input[0]) >> 31;
const s32 carry = -(((s32)(input[0]) & mask) >> 26);
input[0] = (s32)(input[0]) + (carry << 26);
input[1] = (s32)(input[1]) - carry;
}
/* Both passes through the above loop, plus the last 0-to-1 step, are
necessary: if input[9] is -1 and input[0] through input[8] are 0,
negative values will remain in the array until the end.
*/
input[1] <<= 2;
input[2] <<= 3;
input[3] <<= 5;
input[4] <<= 6;
input[6] <<= 1;
input[7] <<= 3;
input[8] <<= 4;
input[9] <<= 6;
#define F(i, s) \
output[s+0] |= input[i] & 0xff; \
output[s+1] = (input[i] >> 8) & 0xff; \
output[s+2] = (input[i] >> 16) & 0xff; \
output[s+3] = (input[i] >> 24) & 0xff;
output[0] = 0;
output[16] = 0;
F(0,0);
F(1,3);
F(2,6);
F(3,9);
F(4,12);
F(5,16);
F(6,19);
F(7,22);
F(8,25);
F(9,28);
#undef F
}
/* Input: Q, Q', Q-Q'
* Output: 2Q, Q+Q'
*
* x2 z3: long form
* x3 z3: long form
* x z: short form, destroyed
* xprime zprime: short form, destroyed
* qmqp: short form, preserved
*/
static void fmonty(limb *x2, limb *z2, /* output 2Q */
limb *x3, limb *z3, /* output Q + Q' */
limb *x, limb *z, /* input Q */
limb *xprime, limb *zprime, /* input Q' */
const limb *qmqp /* input Q - Q' */) {
limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
zzprime[19], zzzprime[19], xxxprime[19];
memcpy(origx, x, 10 * sizeof(limb));
fsum(x, z);
fdifference(z, origx); // does x - z
memcpy(origxprime, xprime, sizeof(limb) * 10);
fsum(xprime, zprime);
fdifference(zprime, origxprime);
fproduct(xxprime, xprime, z);
fproduct(zzprime, x, zprime);
freduce_degree(xxprime);
freduce_coefficients(xxprime);
freduce_degree(zzprime);
freduce_coefficients(zzprime);
memcpy(origxprime, xxprime, sizeof(limb) * 10);
fsum(xxprime, zzprime);
fdifference(zzprime, origxprime);
fsquare(xxxprime, xxprime);
fsquare(zzzprime, zzprime);
fproduct(zzprime, zzzprime, qmqp);
freduce_degree(zzprime);
freduce_coefficients(zzprime);
memcpy(x3, xxxprime, sizeof(limb) * 10);
memcpy(z3, zzprime, sizeof(limb) * 10);
fsquare(xx, x);
fsquare(zz, z);
fproduct(x2, xx, zz);
freduce_degree(x2);
freduce_coefficients(x2);
fdifference(zz, xx); // does zz = xx - zz
memset(zzz + 10, 0, sizeof(limb) * 9);
fscalar_product(zzz, zz, 121665);
/* No need to call freduce_degree here:
fscalar_product doesn't increase the degree of its input. */
freduce_coefficients(zzz);
fsum(zzz, xx);
fproduct(z2, zz, zzz);
freduce_degree(z2);
freduce_coefficients(z2);
}
/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
* them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
* side-channel attacks.
*
* NOTE that this function requires that 'iswap' be 1 or 0; other values give
* wrong results. Also, the two limb arrays must be in reduced-coefficient,
* reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
* and all all values in a[0..9],b[0..9] must have magnitude less than
* INT32_MAX.
*/
static void
swap_conditional(limb a[19], limb b[19], limb iswap) {
unsigned i;
const s32 swap = (s32) -iswap;
for (i = 0; i < 10; ++i) {
const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
a[i] = ((s32)a[i]) ^ x;
b[i] = ((s32)b[i]) ^ x;
}
}
/* Calculates nQ where Q is the x-coordinate of a point on the curve
*
* resultx/resultz: the x coordinate of the resulting curve point (short form)
* n: a little endian, 32-byte number
* q: a point of the curve (short form)
*/
static void
cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
unsigned i, j;
memcpy(nqpqx, q, sizeof(limb) * 10);
for (i = 0; i < 32; ++i) {
u8 byte = n[31 - i];
for (j = 0; j < 8; ++j) {
const limb bit = byte >> 7;
swap_conditional(nqx, nqpqx, bit);
swap_conditional(nqz, nqpqz, bit);
fmonty(nqx2, nqz2,
nqpqx2, nqpqz2,
nqx, nqz,
nqpqx, nqpqz,
q);
swap_conditional(nqx2, nqpqx2, bit);
swap_conditional(nqz2, nqpqz2, bit);
t = nqx;
nqx = nqx2;
nqx2 = t;
t = nqz;
nqz = nqz2;
nqz2 = t;
t = nqpqx;
nqpqx = nqpqx2;
nqpqx2 = t;
t = nqpqz;
nqpqz = nqpqz2;
nqpqz2 = t;
byte <<= 1;
}
}
memcpy(resultx, nqx, sizeof(limb) * 10);
memcpy(resultz, nqz, sizeof(limb) * 10);
}
// -----------------------------------------------------------------------------
// Shamelessly copied from djb's code
// -----------------------------------------------------------------------------
static void
crecip(limb *out, const limb *z) {
limb z2[10];
limb z9[10];
limb z11[10];
limb z2_5_0[10];
limb z2_10_0[10];
limb z2_20_0[10];
limb z2_50_0[10];
limb z2_100_0[10];
limb t0[10];
limb t1[10];
int i;
/* 2 */ fsquare(z2,z);
/* 4 */ fsquare(t1,z2);
/* 8 */ fsquare(t0,t1);
/* 9 */ fmul(z9,t0,z);
/* 11 */ fmul(z11,z9,z2);
/* 22 */ fsquare(t0,z11);
/* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
/* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
/* 2^7 - 2^2 */ fsquare(t1,t0);
/* 2^8 - 2^3 */ fsquare(t0,t1);
/* 2^9 - 2^4 */ fsquare(t1,t0);
/* 2^10 - 2^5 */ fsquare(t0,t1);
/* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
/* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
/* 2^12 - 2^2 */ fsquare(t1,t0);
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
/* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
/* 2^22 - 2^2 */ fsquare(t1,t0);
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
/* 2^41 - 2^1 */ fsquare(t1,t0);
/* 2^42 - 2^2 */ fsquare(t0,t1);
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
/* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
/* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
/* 2^52 - 2^2 */ fsquare(t1,t0);
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
/* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
/* 2^102 - 2^2 */ fsquare(t0,t1);
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
/* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
/* 2^201 - 2^1 */ fsquare(t0,t1);
/* 2^202 - 2^2 */ fsquare(t1,t0);
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
/* 2^251 - 2^1 */ fsquare(t1,t0);
/* 2^252 - 2^2 */ fsquare(t0,t1);
/* 2^253 - 2^3 */ fsquare(t1,t0);
/* 2^254 - 2^4 */ fsquare(t0,t1);
/* 2^255 - 2^5 */ fsquare(t1,t0);
/* 2^255 - 21 */ fmul(out,t1,z11);
}
int curve25519_donna(u8 *, const u8 *, const u8 *);
int
curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
limb bp[10], x[10], z[11], zmone[10];
uint8_t e[32];
int i;
for (i = 0; i < 32; ++i) e[i] = secret[i];
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
fexpand(bp, basepoint);
cmult(x, z, e, bp);
crecip(zmone, z);
fmul(z, x, zmone);
freduce_coefficients(z);
fcontract(mypublic, z);
return 0;
}

169
dropbear/dbclient.1 Normal file
View File

@ -0,0 +1,169 @@
.TH dbclient 1
.SH NAME
dbclient \- lightweight SSH client
.SH SYNOPSIS
.B dbclient
[\-Tt] [\-p
.I port\fR] [\-i
.I id\fR] [\-L
.I l\fR:\fIh\fR:\fIr\fR] [\-R
.I l\fR:\fIh\fR:\fIr\fR] [\-l
.IR user ]
.I host
.RI [ command ]
.B dbclient
[
.I args ]
.I [user1]@host1[^port1],[user2]@host2[^port2],...
.SH DESCRIPTION
.B dbclient
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.
Default is 22.
.TP
.B \-i \fIidfile
Identity file.
Read the identity key from file
.I idfile
(multiple allowed). This file is created with dropbearkey(1) or converted
from OpenSSH with dropbearconvert(1).
.TP
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Local port forwarding.
Forward the port
.I listenport
on the local host through the SSH connection to port
.I port
on the host
.IR host .
.TP
.B \-R [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Remote port forwarding.
Forward the port
.I listenport
on the remote host through the SSH connection to port
.I port
on the host
.IR host .
.TP
.B \-l \fIuser
Username.
Login as
.I user
on the remote host.
.TP
.B \-t
Allocate a PTY.
.TP
.B \-T
Don't allocate a PTY.
.TP
.B \-N
Don't request a remote shell or run any commands. Any command arguments are ignored.
.TP
.B \-f
Fork into the background after authentication. A command argument (or -N) is required.
This is useful when using password authentication.
.TP
.B \-g
Allow non-local hosts to connect to forwarded ports. Applies to -L and -R
forwarded ports, though remote connections to -R forwarded ports may be limited
by the ssh server.
.TP
.B \-y
Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the
connection will abort as normal. If specified a second time no host key checking
is performed at all, this is usually undesirable.
.TP
.B \-A
Forward agent connections to the remote host. dbclient will use any
OpenSSH-style agent program if available ($SSH_AUTH_SOCK will be set) for
public key authentication. Forwarding is only enabled if -A is specified.
.TP
.B \-W \fIwindowsize
Specify the per-channel receive window buffer size. Increasing this
may improve network performance at the expense of memory use. Use -h to see the
default buffer size.
.TP
.B \-K \fItimeout_seconds
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 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 \-J \fIproxy_command
Use the standard input/output of the program \fIproxy_command\fR rather than using
a normal TCP connection. A hostname should be still be provided, as this is used for
comparing saved hostkeys.
.TP
.B \-B \fIendhost:endport
"Netcat-alike" mode, where Dropbear will connect to the given host, then create a
forwarded connection to \fIendhost\fR. This will then be presented as dbclient's
standard input/output.
.TP
.B \-c \fIcipherlist
Specify a comma separated list of ciphers to enable. Use \fI-c help\fR to list possibilities.
.TP
.B \-m \fIMAClist
Specify a comma separated list of authentication MACs to enable. Use \fI-m help\fR to list possibilities.
.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 ).
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
scp -S dbclient matt@martello,root@wrt,canyons:/tmp/dump .
Note that hostnames are resolved by the prior hop (so "canyons" would be resolved by the host "wrt")
in the example above, the same way as other -L TCP forwarded hosts are. Host keys are
checked locally based on the given hostname.
.SH ESCAPE CHARACTERS
Typing a newline followed by the key sequence \fI~.\fR (tilde, dot) will terminate a connection.
The sequence \fI~^Z\fR (tilde, ctrl-z) will background the connection. This behaviour only
applies when a PTY is used.
.SH ENVIRONMENT
.TP
.B DROPBEAR_PASSWORD
A password to use for remote authentication can be specified in the environment
variable DROPBEAR_PASSWORD. Care should be taken that the password is not
exposed to other users on a multi-user system, or stored in accessible files.
.TP
.B SSH_ASKPASS
dbclient can use an external program to request a password from a user.
SSH_ASKPASS should be set to the path of a program that will return a password
on standard output. This program will only be used if either DISPLAY is set and
standard input is not a TTY, or the environment variable SSH_ASKPASS_ALWAYS is
set.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
Mihnea Stoenescu wrote initial Dropbear client support
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8), dropbearkey(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html

90
dropbear/dbmulti.c Normal file
View File

@ -0,0 +1,90 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
/* definitions are cleanest if we just put them here */
int dropbear_main(int argc, char ** argv);
int dropbearkey_main(int argc, char ** argv);
int dropbearconvert_main(int argc, char ** argv);
int scp_main(int argc, char ** argv);
int main(int argc, char ** argv) {
char * progname;
if (argc > 0) {
/* figure which form we're being called as */
progname = basename(argv[0]);
#ifdef DBMULTI_dropbear
if (strcmp(progname, "dropbear") == 0) {
return dropbear_main(argc, argv);
}
#endif
#ifdef DBMULTI_dbclient
if (strcmp(progname, "dbclient") == 0
|| strcmp(progname, "ssh") == 0) {
return cli_main(argc, argv);
}
#endif
#ifdef DBMULTI_dropbearkey
if (strcmp(progname, "dropbearkey") == 0) {
return dropbearkey_main(argc, argv);
}
#endif
#ifdef DBMULTI_dropbearconvert
if (strcmp(progname, "dropbearconvert") == 0) {
return dropbearconvert_main(argc, argv);
}
#endif
#ifdef DBMULTI_scp
if (strcmp(progname, "scp") == 0) {
return scp_main(argc, argv);
}
#endif
}
fprintf(stderr, "Dropbear SSH multi-purpose v%s\n"
"Make a symlink pointing at this binary with one of the following names:\n"
#ifdef DBMULTI_dropbear
"'dropbear' - the Dropbear server\n"
#endif
#ifdef DBMULTI_dbclient
"'dbclient' or 'ssh' - the Dropbear client\n"
#endif
#ifdef DBMULTI_dropbearkey
"'dropbearkey' - the key generator\n"
#endif
#ifdef DBMULTI_dropbearconvert
"'dropbearconvert' - the key converter\n"
#endif
#ifdef DBMULTI_scp
"'scp' - secure copy\n"
#endif
,
DROPBEAR_VERSION);
exit(1);
}

312
dropbear/dbrandom.c Normal file
View File

@ -0,0 +1,312 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "buffer.h"
#include "dbutil.h"
#include "bignum.h"
#include "dbrandom.h"
/* this is used to generate unique output from the same hashpool */
static uint32_t counter = 0;
/* the max value for the counter, so it won't integer overflow */
#define MAX_COUNTER 1<<30
static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
static int donerandinit = 0;
#define INIT_SEED_SIZE 32 /* 256 bits */
/* The basic setup is we read some data from /dev/(u)random or prngd and hash it
* into hashpool. To read data, we hash together current hashpool contents,
* and a counter. We feed more data in by hashing the current pool and new
* data into the pool.
*
* It is important to ensure that counter doesn't wrap around before we
* feed in new entropy.
*
*/
/* Pass len=0 to hash an entire file */
static int
process_file(hash_state *hs, const char *filename,
unsigned int len, int prngd)
{
static int already_blocked = 0;
int readfd;
unsigned int readcount;
int ret = DROPBEAR_FAILURE;
#ifdef DROPBEAR_PRNGD_SOCKET
if (prngd)
{
readfd = connect_unix(filename);
}
else
#endif
{
readfd = open(filename, O_RDONLY);
}
if (readfd < 0) {
goto out;
}
readcount = 0;
while (len == 0 || readcount < len)
{
int readlen, wantread;
unsigned char readbuf[4096];
if (!already_blocked && !prngd)
{
int res;
struct timeval timeout;
fd_set read_fds;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
FD_ZERO(&read_fds);
FD_SET(readfd, &read_fds);
res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
if (res == 0)
{
dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
already_blocked = 1;
}
}
if (len == 0)
{
wantread = sizeof(readbuf);
}
else
{
wantread = MIN(sizeof(readbuf), len-readcount);
}
#ifdef DROPBEAR_PRNGD_SOCKET
if (prngd)
{
char egdcmd[2];
egdcmd[0] = 0x02; /* blocking read */
egdcmd[1] = (unsigned char)wantread;
if (write(readfd, egdcmd, 2) < 0)
{
dropbear_exit("Can't send command to egd");
}
}
#endif
readlen = read(readfd, readbuf, wantread);
if (readlen <= 0) {
if (readlen < 0 && errno == EINTR) {
continue;
}
if (readlen == 0 && len == 0)
{
/* whole file was read as requested */
break;
}
goto out;
}
sha1_process(hs, readbuf, readlen);
readcount += readlen;
}
ret = DROPBEAR_SUCCESS;
out:
close(readfd);
return ret;
}
void addrandom(char * buf, unsigned int len)
{
hash_state hs;
/* hash in the new seed data */
sha1_init(&hs);
/* existing state (zeroes on startup) */
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
/* new */
sha1_process(&hs, buf, len);
sha1_done(&hs, hashpool);
}
static void write_urandom()
{
#ifndef DROPBEAR_PRNGD_SOCKET
/* This is opportunistic, don't worry about failure */
unsigned char buf[INIT_SEED_SIZE];
FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w");
if (!f) {
return;
}
genrandom(buf, sizeof(buf));
fwrite(buf, sizeof(buf), 1, f);
fclose(f);
#endif
}
/* Initialise the prng from /dev/urandom or prngd. This function can
* be called multiple times */
void seedrandom() {
hash_state hs;
pid_t pid;
struct timeval tv;
clock_t clockval;
/* hash in the new seed data */
sha1_init(&hs);
/* existing state */
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
#ifdef DROPBEAR_PRNGD_SOCKET
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
!= DROPBEAR_SUCCESS) {
dropbear_exit("Failure reading random device %s",
DROPBEAR_PRNGD_SOCKET);
}
#else
/* non-blocking random source (probably /dev/urandom) */
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
!= DROPBEAR_SUCCESS) {
dropbear_exit("Failure reading random device %s",
DROPBEAR_URANDOM_DEV);
}
#endif
/* A few other sources to fall back on.
* Add more here for other platforms */
#ifdef __linux__
/* Seems to be a reasonable source of entropy from timers. Possibly hard
* for even local attackers to reproduce */
process_file(&hs, "/proc/timer_list", 0, 0);
/* Might help on systems with wireless */
process_file(&hs, "/proc/interrupts", 0, 0);
process_file(&hs, "/proc/loadavg", 0, 0);
process_file(&hs, "/proc/sys/kernel/random/entropy_avail", 0, 0);
/* Mostly network visible but useful in some situations.
* Limit size to avoid slowdowns on systems with lots of routes */
process_file(&hs, "/proc/net/netstat", 4096, 0);
process_file(&hs, "/proc/net/dev", 4096, 0);
process_file(&hs, "/proc/net/tcp", 4096, 0);
/* Also includes interface lo */
process_file(&hs, "/proc/net/rt_cache", 4096, 0);
process_file(&hs, "/proc/vmstat", 0, 0);
#endif
pid = getpid();
sha1_process(&hs, (void*)&pid, sizeof(pid));
/* gettimeofday() doesn't completely fill out struct timeval on
OS X (10.8.3), avoid valgrind warnings by clearing it first */
memset(&tv, 0x0, sizeof(tv));
gettimeofday(&tv, NULL);
sha1_process(&hs, (void*)&tv, sizeof(tv));
clockval = clock();
sha1_process(&hs, (void*)&clockval, sizeof(clockval));
/* When a private key is read by the client or server it will
* be added to the hashpool - see runopts.c */
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
/* Feed it all back into /dev/urandom - this might help if Dropbear
* is running from inetd and gets new state each time */
write_urandom();
}
/* return len bytes of pseudo-random data */
void genrandom(unsigned char* buf, unsigned int len) {
hash_state hs;
unsigned char hash[SHA1_HASH_SIZE];
unsigned int copylen;
if (!donerandinit) {
dropbear_exit("seedrandom not done");
}
while (len > 0) {
sha1_init(&hs);
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)&counter, sizeof(counter));
sha1_done(&hs, hash);
counter++;
if (counter > MAX_COUNTER) {
seedrandom();
}
copylen = MIN(len, SHA1_HASH_SIZE);
memcpy(buf, hash, copylen);
len -= copylen;
buf += copylen;
}
m_burn(hash, sizeof(hash));
}
/* Generates a random mp_int.
* max is a *mp_int specifying an upper bound.
* rand must be an initialised *mp_int for the result.
* the result rand satisfies: 0 < rand < max
* */
void gen_random_mpint(mp_int *max, mp_int *rand) {
unsigned char *randbuf = NULL;
unsigned int len = 0;
const unsigned char masks[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
const int size_bits = mp_count_bits(max);
len = size_bits / 8;
if ((size_bits % 8) != 0) {
len += 1;
}
randbuf = (unsigned char*)m_malloc(len);
do {
genrandom(randbuf, len);
/* Mask out the unrequired bits - mp_read_unsigned_bin expects
* MSB first.*/
randbuf[0] &= masks[size_bits % 8];
bytes_to_mp(rand, randbuf, len);
/* keep regenerating until we get one satisfying
* 0 < rand < max */
} while (mp_cmp(rand, max) != MP_LT);
m_burn(randbuf, len);
m_free(randbuf);
}

35
dropbear/dbrandom.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _RANDOM_H_
#define _RANDOM_H_
#include "includes.h"
void seedrandom();
void genrandom(unsigned char* buf, unsigned int len);
void addrandom(char * buf, unsigned int len);
void gen_random_mpint(mp_int *max, mp_int *rand);
#endif /* _RANDOM_H_ */

1003
dropbear/dbutil.c Normal file

File diff suppressed because it is too large Load Diff

114
dropbear/dbutil.h Normal file
View File

@ -0,0 +1,114 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _DBUTIL_H_
#define _DBUTIL_H_
#include "includes.h"
#include "buffer.h"
#ifndef DISABLE_SYSLOG
void startsyslog();
#endif
#ifdef __GNUC__
#define ATTRIB_PRINTF(fmt,args) __attribute__((format(printf, fmt, args)))
#define ATTRIB_NORETURN __attribute__((noreturn))
#define ATTRIB_SENTINEL __attribute__((sentinel))
#else
#define ATTRIB_PRINTF(fmt,args)
#define ATTRIB_NORETURN
#define ATTRIB_SENTINEL
#endif
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
extern void (*_dropbear_log)(int priority, const char* format, va_list param);
void dropbear_exit(const char* format, ...) ATTRIB_PRINTF(1,2) ATTRIB_NORETURN;
void dropbear_close(const char* format, ...) ATTRIB_PRINTF(1,2) ;
void dropbear_log(int priority, const char* format, ...) ATTRIB_PRINTF(2,3) ;
void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
#ifdef DEBUG_TRACE
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
void printhex(const char * label, const unsigned char * buf, int len);
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,
int *writefd, int *readfd, int *errfd, pid_t *pid);
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
#ifdef ENABLE_CONNECT_UNIX
int connect_unix(const char* addr);
#endif
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring);
int buf_readfile(buffer* buf, const char* filename);
int buf_getline(buffer * line, FILE * authfile);
void m_close(int fd);
void * m_malloc(size_t size);
void * m_strdup(const char * str);
void * m_realloc(void* ptr, size_t size);
#define m_free(X) free(X); (X) = NULL;
void m_burn(void* data, unsigned int len);
void setnonblocking(int fd);
void disallow_core();
int m_str_to_uint(const char* str, unsigned int *val);
/* Used to force mp_ints to be initialised */
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
/* Dropbear assertion */
#define dropbear_assert(X) do { if (!(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
/* 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_ */

View File

@ -0,0 +1,41 @@
Dropbear for Debian
-------------------
This package will attempt to listen on port 22. If the OpenSSH
package ("ssh") is installed, the file /etc/default/dropbear
will be set up so that the server does not start by default.
You can run Dropbear concurrently with OpenSSH 'sshd' by
modifying /etc/default/dropbear so that "NO_START" is set to
"0" and changing the port number that Dropbear runs on. Follow
the instructions in the file.
This package suggests you install the "ssh" package. This package
provides the "ssh" client program, as well as the "/usr/bin/scp"
binary you will need to be able to retrieve files from a server
running Dropbear via SCP.
Replacing OpenSSH "sshd" with Dropbear
--------------------------------------
You will still want to have the "ssh" package installed, as it
provides the "ssh" and "scp" binaries. When you install this
package, it checks for existing OpenSSH host keys and if found,
converts them to the Dropbear format.
If this appears to have worked, you should be able to change over
by following these steps:
1. Stop the OpenSSH server
% /etc/init.d/ssh stop
2. Prevent the OpenSSH server from starting in the future
% touch /etc/ssh/sshd_not_to_be_run
3. Modify the Dropbear defaults file, set NO_START to 0 and
ensure DROPBEAR_PORT is set to 22.
% editor /etc/default/dropbear
4. Restart the Dropbear server.
% /etc/init.d/dropbear restart
See the Dropbear homepage for more information:
http://matt.ucc.asn.au/dropbear/dropbear.html

View File

@ -0,0 +1,15 @@
Building with the diet libc
---------------------------
This package optionally can be built with the diet libc instead of the
glibc to provide small statically linked programs. The resulting package
has no dependency on any other package.
To use the diet libc, make sure the latest versions of the dietlibc-dev
package is installed, and set DEB_BUILD_OPTIONS=diet in the environment
when building the package, e.g.:
# apt-get install dietlibc-dev
$ DEB_BUILD_OPTIONS=diet fakeroot apt-get source -b dropbear
-- Gerrit Pape <pape@smarden.org>, Sat, 17 Jul 2004 19:09:34 +0000

View File

@ -0,0 +1,46 @@
Using the dropbear SSH server with runit's services supervision
---------------------------------------------------------------
The dropbear SSH server is perfectly suited to be run under runit's
service supervision, and this package already has prepared an adequate
service directory. Follow these steps to enable the dropbear service
using the runit package.
If not yet installed on your system, install the runit package, and make
sure its service supervision is enabled (it's by default)
# apt-get install runit
Make sure the dropbear service normally handled through the sysv init
script is stopped
# /etc/init.d/dropbear stop
Create the system user ``dropbearlog'' which will run the logger service,
and own the logs
# adduser --system --home /var/log/dropbear --no-create-home dropbearlog
Create the log directory and make the newly created system user the owner
of this directory
# mkdir -p /var/log/dropbear && chown dropbearlog /var/log/dropbear
Optionally adjust the configuration of the dropbear service by editing the
run script
# vi /etc/dropbear/run
Finally enable the service through runit's update-service(8) program, the
service will be started within five seconds, and automatically at boot
time, and the sysv init script will automatically be disabled; see the
sv(8) program for information on how to control services handled by runit.
See the svlogd(8) program on how to configure the log service.
# update-service --add /etc/dropbear
Optionally check the status of the service a few seconds later
# sv status dropbear
-- Gerrit Pape <pape@smarden.org>, Fri, 02 Mar 2007 20:41:08 +0000

383
dropbear/debian/changelog Normal file
View File

@ -0,0 +1,383 @@
dropbear (2014.66-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 23 Oct 2014 22:54:00 +0800
dropbear (2014.65-0.1) unstable; urgency=low
* New upstream release.
-- 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
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 16 Oct 2013 22:54:00 +0800
dropbear (2013.59-0.1) unstable; urgency=low
* New upstream release.
* Build with DEB_BUILD_MAINT_OPTIONS = hardening=+all
-- Matt Johnston <matt@ucc.asn.au> Fri, 4 Oct 2013 22:54:00 +0800
dropbear (2013.58-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 18 Apr 2013 22:54:00 +0800
dropbear (2013.57-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Apr 2013 22:54:00 +0800
dropbear (2013.56-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 21 Mar 2013 22:54:00 +0800
dropbear (2012.55-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 22 Feb 2012 22:54:00 +0800
dropbear (2011.54-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Tues, 8 Nov 2011 22:54:00 +0800
dropbear (0.53.1-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 2 Mar 2011 22:54:00 +0900
dropbear (0.53-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 24 Feb 2011 22:54:00 +0900
dropbear (0.52-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 12 Nov 2008 22:54:00 +0900
dropbear (0.51-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 27 Mar 2008 19:14:00 +0900
dropbear (0.50-4) unstable; urgency=low
* debian/dropbear.init: apply patch from Petter Reinholdtsen: add LSB
formatted dependency info in init.d script (closes: #466257).
* debian/rules: no longer include symlinks for ./supervise/ subdirectories.
* debian/dropbear.postinst: upgrade from << 0.50-4: if dropbear is managed
by runit, remove service, and re-add using update-service(8).
* debian/control: Standards-Version: 3.7.3.0.
* debian/rules: target clean: don't ignore errors but check for readable
./Makefile.
-- Gerrit Pape <pape@smarden.org> Thu, 06 Mar 2008 19:06:58 +0000
dropbear (0.50-3) unstable; urgency=low
* debian/dropbear.init: use the update-service(8) program from the runit
package instead of directly checking for the symlink in /var/service/.
* debian/README.runit: talk about update-service(8) instead of symlinks
in /var/service/.
-- Gerrit Pape <pape@smarden.org> Fri, 15 Feb 2008 00:32:37 +0000
dropbear (0.50-2) unstable; urgency=low
* debian/dropbear.README.Debian: no longer talk about entropy from
/dev/random, /dev/urandom is now used by default (thx Joey Hess,
closes: #441515).
-- Gerrit Pape <pape@smarden.org> Mon, 24 Sep 2007 16:49:17 +0000
dropbear (0.50-1) unstable; urgency=low
* debian/README.runit: minor.
* new upstream version.
* debian/diff/0001-options.h-use-dev-urandom-instead-of-dev-random-a.diff:
remove; fixed upstream.
-- Gerrit Pape <pape@smarden.org> Thu, 09 Aug 2007 23:01:01 +0000
dropbear (0.49-2) unstable; urgency=low
* debian/rules: apply diffs from debian/diff/ with patch -p1 instead of
-p0.
* debian/diff/0001-options.h-use-dev-urandom-instead-of-dev-random-a.diff:
new; options.h: use /dev/urandom instead of /dev/random as
DROPBEAR_RANDOM_DEV (closes: #386976).
* debian/rules: target clean: remove libtomcrypt/Makefile,
libtommath/Makefile.
-- Gerrit Pape <pape@smarden.org> Sat, 09 Jun 2007 08:59:59 +0000
dropbear (0.49-1) unstable; urgency=high
* new upstream release, fixes
* CVE-2007-1099: dropbear dbclient insufficient warning on hostkey
mismatch (closes: #412899).
* dbclient uses static "Password:" prompt instead of using the server's
prompt (closes: #394996).
* debian/control: Suggests: openssh-client, not ssh (closes: #405686);
Standards-Version: 3.7.2.2.
* debian/README.Debian: ssh -> openssh-server, openssh-client; remove
'Replacing OpenSSH "sshd" with Dropbear' part, this is simply done by not
installing the openssh-server package.
* debian/README.runit: runsvstat -> sv status.
-- Gerrit Pape <pape@smarden.org> Fri, 2 Mar 2007 20:48:18 +0000
dropbear (0.48.1-1) unstable; urgency=medium
* new upstream point release.
* Compile fix for scp
* debian/diff/dbclient.1.diff: new: document -R option to dbclient
accurately (thx Markus Schaber; closes: #351882).
* debian/dropbear.README.Debian: document a workaround for systems with
possibly blocking /dev/random device (closes: #355414)..
-- Gerrit Pape <pape@smarden.org> Sun, 16 Apr 2006 16:16:40 +0000
dropbear (0.48-1) unstable; urgency=medium
* New upstream release.
* SECURITY: Improve handling of denial of service attempts from a single
IP.
* debian/implicit: update to revision 1.11.
* new upstream release updates to scp from OpenSSH 4.3p2 - fixes a
security issue where use of system() could cause users to execute
arbitrary code through malformed filenames; CVE-2006-0225 (see also
#349645); the scp binary is not provided by this package though.
-- Gerrit Pape <pape@smarden.org> Fri, 10 Mar 2006 22:00:32 +0000
dropbear (0.47-1) unstable; urgency=high
* New upstream release.
* SECURITY: Fix incorrect buffer sizing; CVE-2005-4178.
-- Matt Johnston <matt@ucc.asn.au> Thu, 8 Dec 2005 19:20:21 +0800
dropbear (0.46-2) unstable; urgency=low
* debian/control: Standards-Version: 3.6.2.1; update descriptions to
mention included server and client (thx Tino Keitel).
* debian/dropbear.init: allow '/etc/init.d/dropbear stop' even though
'NO_START is not set to zero.' (closes: #336723).
-- Gerrit Pape <pape@smarden.org> Tue, 6 Dec 2005 13:30:49 +0000
dropbear (0.46-1) unstable; urgency=medium
* New upstream release, various fixes.
* debian/diff/dbclient-usage-typo.diff, debian/diff/manpages.diff: remove;
obsolete.
* debian/dbclient.1: move to ./dbclient.1.
-- Matt Johnston <matt@ucc.asn.au> Fri, 8 July 2005 21:32:55 +0800
dropbear (0.45-3) unstable; urgency=low
* debian/dropbear.init: init script prints human readable message in case
it's disabled (closes: #309099).
* debian/dropbear.postinst: configure: restart service through init script
instead of start.
* debian/dropbear.prerm: set -u -> set -e.
-- Gerrit Pape <pape@smarden.org> Wed, 25 May 2005 22:38:17 +0000
dropbear (0.45-2) unstable; urgency=low
* Matt Johnston:
* New upstream release, various fixes.
-- Gerrit Pape <pape@smarden.org> Sat, 12 Mar 2005 15:17:55 +0000
dropbear (0.44-1) unstable; urgency=low
* New upstream release.
* debian/rules: install /usr/bin/dbclient; handle possible patches more
gracefully; install debian/dbclient.1 man page; enable target patch;
minor.
* debian/implicit: update to revision 1.10.
* debian/dbclient.1: new; man page.
* debian/diff/dbclient-usage-typo.diff: new; fix typo.
* debian/diff/manpages.diff: new; add references to dbclient man page.
-- Gerrit Pape <pape@smarden.org> Sat, 8 Jan 2005 22:50:43 +0000
dropbear (0.43-2) unstable; urgency=high
* Matt Johnston:
* New upstream release 0.43
* SECURITY: Don't attempt to free uninitialised buffers in DSS verification
code
* Handle portforwarding to servers which don't send any initial data
(Closes: #258426)
* debian/dropbear.postinst: remove code causing bothersome warning on
package install (closes: #256752).
* debian/README.Debian.diet: new; how to build with the diet libc.
* debian/dropbear.docs: add debian/README.Debian.diet.
* debian/rules: support "diet" in DEB_BUILD_OPTIONS; minor cleanup.
-- Gerrit Pape <pape@smarden.org> Sat, 17 Jul 2004 19:31:19 +0000
dropbear (0.42-1) unstable; urgency=low
* New upstream release 0.42.
* debian/diff/cvs-20040520.diff: remove; obsolete.
* debian/rules: disable target patch.
-- Matt Johnston <matt@ucc.asn.au> Wed, 16 June 2004 12:44:54 +0800
dropbear (0.41-3) unstable; urgency=low
* 1st upload to the Debian archive (closes: #216553).
* debian/diff/cvs-20040520.diff: new; stable cvs snapshot.
* debian/rules: new target patch: apply diffs in debian/diff/, reverse
apply in target clean; install man pages.
* debian/control: Priority: optional.
-- Gerrit Pape <pape@smarden.org> Sun, 23 May 2004 08:32:37 +0000
dropbear (0.41-2) unstable; urgency=low
* new maintainer.
* debian/control: no longer Build-Depends: debhelper; Build-Depends:
libz-dev; Standards-Version: 3.6.1.0; Suggests: runit; update
descriptions.
* debian/rules: stop using debhelper, use implicit rules; cleanup;
install dropbearconvert into /usr/lib/dropbear/.
* debian/impicit: new; implicit rules.
* debian/copyright.in: adapt.
* debian/dropbear.init: minor adaptions; test for dropbear service
directory.
* debian/README.runit: new; how to use dropbear with runit.
* debian/README.Debian, debian/docs: rename to debian/dropbear.*.
* debian/dropbear.docs: add debian/README.runit
* debian/conffiles: rename to debian/dropbear.conffiles; add init
script, and run scripts.
* debian/postinst: rename to debian/dropbear.postinst; adapt; use
invloke-rc.d dropbear start.
* debian/dropbear.prerm: new; invoke-rc.d dropbear stop.
* debian/postrm: rename to debian/dropbear.postrm; adapt; clean up
service directories.
* debian/compat, debian/dirs, dropbear.default: remove; obsolete.
-- Gerrit Pape <pape@smarden.org> Sun, 16 May 2004 16:50:55 +0000
dropbear (0.41-1) unstable; urgency=low
* Updated to 0.41 release.
* Various minor fixes
-- Matt Johnston <matt@ucc.asn.au> Mon, 19 Jan 2004 23:20:54 +0800
dropbear (0.39-1) unstable; urgency=low
* updated to 0.39 release. Some new features, some bugfixes.
-- Matt Johnston <matt@ucc.asn.au> Tue, 16 Dec 2003 16:20:54 +0800
dropbear (0.38-1) unstable; urgency=medium
* updated to 0.38 release - various important bugfixes
-- Matt Johnston <matt@ucc.asn.au> Sat, 11 Oct 2003 16:28:54 +0800
dropbear (0.37-1) unstable; urgency=medium
* updated to 0.37 release - various important bugfixes
-- Matt Johnston <matt@ucc.asn.au> Wed, 24 Sept 2003 19:43:54 +0800
dropbear (0.36-1) unstable; urgency=high
* updated to 0.36 release - various important bugfixes
-- Matt Johnston <matt@ucc.asn.au> Tues, 19 Aug 2003 12:20:54 +0800
dropbear (0.35-1) unstable; urgency=high
* updated to 0.35 release - contains fix for remotely exploitable
vulnerability.
-- Matt Johnston <matt@ucc.asn.au> Sun, 17 Aug 2003 05:37:47 +0800
dropbear (0.34-1) unstable; urgency=medium
* updated to 0.34 release
-- Matt Johnston <matt@ucc.asn.au> Fri, 15 Aug 2003 15:10:00 +0800
dropbear (0.33-1) unstable; urgency=medium
* updated to 0.33 release
-- Matt Johnston <matt@ucc.asn.au> Sun, 22 Jun 2003 22:22:00 +0800
dropbear (0.32cvs-1) unstable; urgency=medium
* now maintained in UCC CVS
* debian/copyright.in file added, generated from LICENSE
-- Grahame Bowland <grahame@angrygoats.net> Tue, 21 Jun 2003 17:57:02 +0800
dropbear (0.32cvs-1) unstable; urgency=medium
* sync with CVS
* fixes X crash bug
-- Grahame Bowland <grahame@angrygoats.net> Tue, 20 Jun 2003 15:04:47 +0800
dropbear (0.32-2) unstable; urgency=low
* fix creation of host keys to use correct names in /etc/dropbear
* init script "restart" function fixed
* purging this package now deletes the host keys and /etc/dropbear
* change priority in debian/control to 'standard'
-- Grahame Bowland <grahame@angrygoats.net> Tue, 17 Jun 2003 15:04:47 +0800
dropbear (0.32-1) unstable; urgency=low
* Initial Release.
-- Grahame Bowland <grahame@angrygoats.net> Tue, 17 Jun 2003 15:04:47 +0800

20
dropbear/debian/control Normal file
View File

@ -0,0 +1,20 @@
Source: dropbear
Section: net
Priority: optional
Maintainer: Gerrit Pape <pape@smarden.org>
Build-Depends: libz-dev
Standards-Version: 3.7.3.0
Package: dropbear
Architecture: any
Depends: ${shlibs:Depends}
Suggests: openssh-client, runit
Description: lightweight SSH2 server and client
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html

View File

@ -0,0 +1,11 @@
This package was debianized by Grahame Bowland <grahame.angrygoats.net> on
Tue, 17 Jun 2003 15:04:47 +0800, maintained temporarily by Matt Johnston
<matt@ucc.asn.au>, and was adopted by Gerrit Pape <pape@smarden.org> on
Sun, 16 May 2004 14:38:33 +0000.
It was downloaded from http://matt.ucc.asn.au/dropbear/
Upstream Author: Matt Johnston <matt@ucc.asn.au>
Copyright:

View File

@ -0,0 +1,19 @@
Dropbear for Debian
-------------------
This package will attempt to setup the Dropbear ssh server to listen on
port 22. If the OpenSSH server package ("openssh-server") is installed,
the file /etc/default/dropbear will be set up so that the server does not
start by default.
You can run Dropbear concurrently with OpenSSH 'sshd' by modifying
/etc/default/dropbear so that "NO_START" is set to "0", and changing the
port number that Dropbear runs on. Follow the instructions in the file.
This package suggests you install the "openssh-client" package, which
provides the "ssh" client program, as well as the "/usr/bin/scp" binary
you will need to be able to retrieve files via SCP from a server running
Dropbear.
See the Dropbear homepage for more information:
http://matt.ucc.asn.au/dropbear/dropbear.html

View File

@ -0,0 +1,3 @@
/etc/init.d/dropbear
/etc/dropbear/run
/etc/dropbear/log/run

View File

View File

@ -0,0 +1,4 @@
README
TODO
debian/README.runit
debian/README.Debian.diet

View File

@ -0,0 +1,70 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: dropbear
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
### END INIT INFO
#
# Do not configure this file. Edit /etc/default/dropbear instead!
#
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/dropbear
NAME=dropbear
DESC="Dropbear SSH server"
DROPBEAR_PORT=22
DROPBEAR_EXTRA_ARGS=
NO_START=0
set -e
cancel() { echo "$1" >&2; exit 0; };
test ! -r /etc/default/dropbear || . /etc/default/dropbear
test -x "$DAEMON" || cancel "$DAEMON does not exist or is not executable."
test ! -x /usr/sbin/update-service || ! update-service --check dropbear ||
cancel 'The dropbear service is controlled through runit, use the sv(8) program'
test -z "$DROPBEAR_BANNER" || \
DROPBEAR_EXTRA_ARGS="$DROPBEAR_EXTRA_ARGS -b $DROPBEAR_BANNER"
test -n "$DROPBEAR_RSAKEY" || \
DROPBEAR_RSAKEY="/etc/dropbear/dropbear_rsa_host_key"
test -n "$DROPBEAR_DSSKEY" || \
DROPBEAR_DSSKEY="/etc/dropbear/dropbear_dss_host_key"
test -n "$DROPBEAR_RECEIVE_WINDOW" || \
DROPBEAR_RECEIVE_WINDOW="65536"
case "$1" in
start)
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /var/run/"$NAME".pid \
--exec "$DAEMON" -- -d "$DROPBEAR_DSSKEY" -r "$DROPBEAR_RSAKEY" \
-p "$DROPBEAR_PORT" -W "$DROPBEAR_RECEIVE_WINDOW" $DROPBEAR_EXTRA_ARGS
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/"$NAME".pid
echo "$NAME."
;;
restart|force-reload)
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/"$NAME".pid
sleep 1
start-stop-daemon --start --quiet --pidfile /var/run/"$NAME".pid \
--exec "$DAEMON" -- -d "$DROPBEAR_DSSKEY" -r "$DROPBEAR_RSAKEY" \
-p "$DROPBEAR_PORT" -W "$DROPBEAR_RECEIVE_WINDOW" $DROPBEAR_EXTRA_ARGS
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,79 @@
#!/bin/sh
set -e
test "$1" = 'configure' || exit 0
if test ! -e /etc/dropbear/dropbear_rsa_host_key; then
if test -f /etc/ssh/ssh_host_rsa_key; then
echo "Converting existing OpenSSH RSA host key to Dropbear format."
/usr/lib/dropbear/dropbearconvert openssh dropbear \
/etc/ssh/ssh_host_rsa_key /etc/dropbear/dropbear_rsa_host_key
else
echo "Generating Dropbear RSA key. Please wait."
dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
fi
fi
if test ! -e /etc/dropbear/dropbear_dss_host_key; then
if test -f /etc/ssh/ssh_host_dsa_key; then
echo "Converting existing OpenSSH RSA host key to Dropbear format."
/usr/lib/dropbear/dropbearconvert openssh dropbear \
/etc/ssh/ssh_host_dsa_key /etc/dropbear/dropbear_dss_host_key
else
echo "Generating Dropbear DSS key. Please wait."
dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key
fi
fi
if test ! -s /etc/default/dropbear; then
# check whether OpenSSH seems to be installed.
if test -x /usr/sbin/sshd; then
cat <<EOT
OpenSSH appears to be installed. Setting /etc/default/dropbear so that
Dropbear will not start by default. Edit this file to change this behaviour.
EOT
cat >>/etc/default/dropbear <<EOT
# disabled because OpenSSH is installed
# change to NO_START=0 to enable Dropbear
NO_START=1
EOT
fi
cat >>/etc/default/dropbear <<EOT
# the TCP port that Dropbear listens on
DROPBEAR_PORT=22
# any additional arguments for Dropbear
DROPBEAR_EXTRA_ARGS=
# specify an optional banner file containing a message to be
# sent to clients before they connect, such as "/etc/issue.net"
DROPBEAR_BANNER=""
# RSA hostkey file (default: /etc/dropbear/dropbear_rsa_host_key)
#DROPBEAR_RSAKEY="/etc/dropbear/dropbear_rsa_host_key"
# DSS hostkey file (default: /etc/dropbear/dropbear_dss_host_key)
#DROPBEAR_DSSKEY="/etc/dropbear/dropbear_dss_host_key"
# Receive window size - this is a tradeoff between memory and
# network performance
DROPBEAR_RECEIVE_WINDOW=65536
EOT
fi
if test -x /etc/init.d/dropbear; then
update-rc.d dropbear defaults >/dev/null
if test -x /usr/sbin/invoke-rc.d; then
invoke-rc.d dropbear restart
else
/etc/init.d/dropbear restart
fi
fi
if test -n "$2" && dpkg --compare-versions "$2" lt '0.50-4' &&
update-service --check dropbear 2>/dev/null; then
update-service --remove /etc/dropbear 2>/dev/null || :
sleep 6
rm -rf /var/run/dropbear /var/run/dropbear.log
update-service --add /etc/dropbear || :
fi

View File

@ -0,0 +1,12 @@
#! /bin/sh
set -e
test "$1" = 'purge' || exit 0
if test -e /etc/dropbear; then
rm -f /etc/dropbear/dropbear_rsa_host_key
rm -f /etc/dropbear/dropbear_dss_host_key
rmdir --ignore-fail-on-non-empty /etc/dropbear
fi
update-rc.d dropbear remove >/dev/null
rm -f /etc/default/dropbear
rm -rf /etc/dropbear/supervise /etc/dropbear/log/supervise

View File

@ -0,0 +1,11 @@
#!/bin/sh
set -e
test "$1" = 'remove' || test "$1" = 'deconfigure' || exit 0
if test -x /etc/init.d/dropbear; then
if test -x /usr/sbin/invoke-rc.d; then
invoke-rc.d dropbear stop
else
/etc/init.d/dropbear stop
fi
fi

93
dropbear/debian/implicit Normal file
View File

@ -0,0 +1,93 @@
# $Id: implicit,v 1.11 2005/11/29 21:57:55 pape Exp $
.PHONY: deb-checkdir deb-checkuid
deb-checkdir:
@test -e debian/control || sh -cx '! : wrong directory'
deb-checkuid:
@test "`id -u`" -eq 0 || sh -cx '! : need root privileges'
%.deb: %.deb-docs %.deb-DEBIAN
@rm -f $*.deb $*.deb-checkdir $*.deb-docs $*.deb-docs-base \
$*.deb-docs-docs $*.deb-docs-examples $*.deb-DEBIAN \
$*.deb-DEBIAN-dir $*.deb-DEBIAN-scripts $*.deb-DEBIAN-md5sums
%.udeb: %.deb-DEBIAN
@rm -f $*.deb $*.deb-checkdir $*.deb-DEBIAN $*.deb-DEBIAN-dir \
$*.deb-DEBIAN-scripts $*.deb-DEBIAN-md5sums
%.deb-checkdir:
@test -d debian/$* || sh -cx '! : directory debian/$* missing'
@test "`id -u`" -eq 0 || sh -cx '! : need root privileges'
%.deb-docs-base:
: implicit
@rm -f debian/$*/usr/share/doc/$*/* || :
@install -d -m0755 debian/$*/usr/share/doc/$*
: debian/$*/usr/share/doc/$*/
@sh -cx 'install -m0644 debian/copyright debian/$*/usr/share/doc/$*/'
@sh -cx 'install -m0644 debian/changelog \
debian/$*/usr/share/doc/$*/changelog.Debian'
@test ! -r changelog || \
sh -cx 'install -m0644 changelog debian/$*/usr/share/doc/$*/'
@test -r debian/$*/usr/share/doc/$*/changelog || \
sh -cx 'mv debian/$*/usr/share/doc/$*/changelog.Debian \
debian/$*/usr/share/doc/$*/changelog'
@test -s debian/$*/usr/share/doc/$*/changelog || \
sh -cx 'rm -f debian/$*/usr/share/doc/$*/changelog'
@gzip -9 debian/$*/usr/share/doc/$*/changelog*
%.deb-docs-docs:
@for i in `cat debian/$*.docs 2>/dev/null || :`; do \
if test -d $$i; then \
sh -cx "install -d -m0755 debian/$*/usr/share/doc/$*/$${i##*/}" && \
for j in $$i/*; do \
sh -cx "install -m0644 $$j \
debian/$*/usr/share/doc/$*/$${i##*/}/" || exit 1; \
done || exit 1; \
continue; \
fi; \
sh -cx "install -m0644 $$i debian/$*/usr/share/doc/$*/" || exit 1; \
done
@test ! -r debian/$*.README.Debian || \
sh -cx 'install -m0644 debian/$*.README.Debian \
debian/$*/usr/share/doc/$*/README.Debian'
@if test -r debian/$*.NEWS.Debian; then \
sh -cx 'install -m0644 debian/$*.NEWS.Debian \
debian/$*/usr/share/doc/$*/NEWS.Debian && \
gzip -9 debian/$*/usr/share/doc/$*/NEWS.Debian'; \
fi
%.deb-docs-examples:
@rm -rf debian/$*/usr/share/doc/$*/examples
: debian/$*/usr/share/doc/$*/examples/
@test ! -r debian/$*.examples || \
install -d -m0755 debian/$*/usr/share/doc/$*/examples
@for i in `cat debian/$*.examples 2>/dev/null || :`; do \
sh -cx "install -m0644 $$i debian/$*/usr/share/doc/$*/examples/" \
|| exit 1; \
done
%.deb-docs: %.deb-checkdir %.deb-docs-base %.deb-docs-docs %.deb-docs-examples
: debian/$*/usr/share/doc/$*/ ok
%.deb-DEBIAN-base:
@rm -rf debian/$*/DEBIAN
: debian/$*/DEBIAN/
@install -d -m0755 debian/$*/DEBIAN
@for i in conffiles shlibs templates; do \
test ! -r debian/$*.$$i || \
sh -cx "install -m0644 debian/$*.$$i debian/$*/DEBIAN/$$i" \
|| exit 1; \
done
%.deb-DEBIAN-scripts:
@for i in preinst prerm postinst postrm config; do \
test ! -r debian/$*.$$i || \
sh -cx "install -m0755 debian/$*.$$i debian/$*/DEBIAN/$$i" \
|| exit 1; \
done
%.deb-DEBIAN-md5sums:
: debian/$*/DEBIAN/md5sums
@rm -f debian/$*/DEBIAN/md5sums
@cd debian/$* && find * -path 'DEBIAN' -prune -o \
-type f -exec md5sum {} >>DEBIAN/md5sums \;
%.deb-DEBIAN: %.deb-checkdir %.deb-DEBIAN-base %.deb-DEBIAN-scripts \
%.deb-DEBIAN-md5sums
: debian/$*/DEBIAN/ ok

103
dropbear/debian/rules Executable file
View File

@ -0,0 +1,103 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk
#export DH_OPTIONS
DEB_HOST_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
STRIP =strip
ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
STRIP =: nostrip
endif
CONFFLAGS =
CC =gcc
ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
CONFFLAGS =--disable-zlib
CC =diet -v -Os gcc -nostdinc
endif
DIR =$(shell pwd)/debian/dropbear
patch: deb-checkdir patch-stamp
patch-stamp:
for i in `ls -1 debian/diff/*.diff || :`; do \
patch -p1 <$$i || exit 1; \
done
touch patch-stamp
config.status: patch-stamp configure
CC='$(CC)' \
CFLAGS='$(CFLAGS)'' -DSFTPSERVER_PATH="\"/usr/lib/sftp-server\""' \
./configure --host='$(DEB_HOST_GNU_TYPE)' \
--build='$(DEB_BUILD_GNU_TYPE)' --prefix=/usr \
--mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info \
$(CONFFLAGS)
build: deb-checkdir build-stamp
build-stamp: config.status
$(MAKE) CC='$(CC)' LD='$(CC)'
touch build-stamp
clean: deb-checkdir deb-checkuid
test ! -r Makefile || $(MAKE) distclean
rm -f libtomcrypt/Makefile libtommath/Makefile
test ! -e patch-stamp || \
for i in `ls -1r debian/diff/*.diff || :`; do \
patch -p1 -R <$$i; \
done
rm -f patch-stamp build-stamp config.log config.status
rm -rf '$(DIR)'
rm -f debian/files debian/substvars debian/copyright changelog
install: deb-checkdir deb-checkuid build-stamp
rm -rf '$(DIR)'
install -d -m0755 '$(DIR)'/etc/dropbear
# programs
install -d -m0755 '$(DIR)'/usr/sbin
install -m0755 dropbear '$(DIR)'/usr/sbin/dropbear
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 dbclient '$(DIR)'/usr/bin/dbclient
install -m0755 dropbearkey '$(DIR)'/usr/bin/dropbearkey
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearconvert \
'$(DIR)'/usr/lib/dropbear/dropbearconvert
$(STRIP) -R .comment -R .note '$(DIR)'/usr/sbin/* \
'$(DIR)'/usr/bin/* '$(DIR)'/usr/lib/dropbear/*
# init and run scripts
install -d -m0755 '$(DIR)'/etc/init.d
install -m0755 debian/dropbear.init '$(DIR)'/etc/init.d/dropbear
install -m0755 debian/service/run '$(DIR)'/etc/dropbear/run
install -d -m0755 '$(DIR)'/etc/dropbear/log
install -m0755 debian/service/log '$(DIR)'/etc/dropbear/log/run
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
# man pages
install -d -m0755 '$(DIR)'/usr/share/man/man8
install -d -m0755 '$(DIR)'/usr/share/man/man1
install -m644 dropbear.8 '$(DIR)'/usr/share/man/man8/
for i in dbclient.1 dropbearkey.1 dropbearconvert.1; do \
install -m644 $$i '$(DIR)'/usr/share/man/man1/ || exit 1; \
done
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
# copyright, changelog
cat debian/copyright.in LICENSE >debian/copyright
test -r changelog || ln -s CHANGES changelog
binary-indep:
binary-arch: install dropbear.deb
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/sbin/* '$(DIR)'/usr/bin/* \
'$(DIR)'/usr/lib/dropbear/*
dpkg-gencontrol -isp -pdropbear -P'$(DIR)'
dpkg -b '$(DIR)' ..
binary: binary-arch binary-indep
.PHONY: patch build clean install binary-indep binary-arch binary
include debian/implicit

View File

@ -0,0 +1,2 @@
#!/bin/sh
exec chpst -udropbearlog svlogd -tt ./main

View File

@ -0,0 +1,3 @@
#!/bin/sh
exec 2>&1
exec dropbear -d ./dropbear_dss_host_key -r ./dropbear_rsa_host_key -F -E -p 22

83
dropbear/debug.h Normal file
View File

@ -0,0 +1,83 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _DEBUG_H_
#define _DEBUG_H_
#include "includes.h"
/* Debugging */
/* Work well for valgrind - don't clear environment, be nicer with signals
* etc. Don't use this normally, it might cause problems */
/* #define DEBUG_VALGRIND */
/* Define this to compile in trace debugging printf()s.
* You'll need to run programs with "-v" to turn this on.
*
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing may not sanitise strings etc. This will add a reasonable
* amount to your executable size. */
/* #define DEBUG_TRACE */
/* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
* attempting to track down a problem */
/*#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \
ses.writepayload->pos == 0)*/
#define CHECKCLEARTOWRITE()
/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
* output when Dropbear forks. This will allow it gprof to be used.
* It's useful to run dropbear -F, so you don't fork as much */
/* (This is Linux specific) */
/*#define DEBUG_FORKGPROF*/
/* A couple of flags, not usually useful, and mightn't do anything */
/*#define DEBUG_KEXHASH*/
/*#define DEBUG_RSA*/
/* you don't need to touch this block */
#ifdef DEBUG_TRACE
#define TRACE(X) dropbear_trace X;
#define TRACE2(X) dropbear_trace2 X;
#else /*DEBUG_TRACE*/
#define TRACE(X)
#define TRACE2(X)
#endif /*DEBUG_TRACE*/
/* To debug with GDB it is easier to run with no forking of child processes.
You will need to pass "-F" as well. */
/* #define DEBUG_NOFORK */
/* For testing as non-root on shadowed systems, include the crypt of a password
* here. You can then log in as any user with this password. Ensure that you
* make your own password, and are careful about using this. This will also
* disable some of the chown pty code etc*/
/* #define DEBUG_HACKCRYPT "hL8nrFDt0aJ3E" */ /* this is crypt("password") */
#endif

192
dropbear/dropbear.8 Normal file
View File

@ -0,0 +1,192 @@
.TH dropbear 8
.SH NAME
dropbear \- lightweight SSH server
.SH SYNOPSIS
.B dropbear
[\-RFEmwsgjki] [\-b
.I banner\fR]
[\-r
.I hostkeyfile\fR] [\-p
.IR [address:]port ]
.SH DESCRIPTION
.B dropbear
is a small SSH server
.SH OPTIONS
.TP
.B \-b \fIbanner
bannerfile.
Display the contents of the file
.I banner
before user login (default: none).
.TP
.B \-r \fIhostkey
Use the contents of the file
.I hostkey
for the SSH hostkey.
This file is generated with
.BR dropbearkey (1)
or automatically with the '-R' option. See "Host Key Files" below.
.TP
.B \-R
Generate hostkeys automatically. See "Host Key Files" below.
.TP
.B \-F
Don't fork into background.
.TP
.B \-E
Log to standard error rather than syslog.
.TP
.B \-m
Don't display the message of the day on login.
.TP
.B \-w
Disallow root logins.
.TP
.B \-s
Disable password logins.
.TP
.B \-g
Disable password logins for root.
.TP
.B \-j
Disable local port forwarding.
.TP
.B \-k
Disable remote port forwarding.
.TP
.B \-p \fI[address:]port
Listen on specified
.I address
and TCP
.I port.
If just a port is given listen
on all addresses.
up to 10 can be specified (default 22 if none specified).
.TP
.B \-i
Service program mode.
Use this option to run
.B dropbear
under TCP/IP servers like inetd, tcpsvd, or tcpserver.
In program mode the \-F option is implied, and \-p options are ignored.
.TP
.B \-P \fIpidfile
Specify a pidfile to create when running as a daemon. If not specified, the
default is /var/run/dropbear.pid
.TP
.B \-a
Allow remote hosts to connect to forwarded ports.
.TP
.B \-W \fIwindowsize
Specify the per-channel receive window buffer size. Increasing this
may improve network performance at the expense of memory use. Use -h to see the
default buffer size.
.TP
.B \-K \fItimeout_seconds
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 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
Authorized Keys
~/.ssh/authorized_keys can be set up to allow remote login with a RSA or DSS
key. Each line is of the form
.TP
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
and can be extracted from a Dropbear private host key with "dropbearkey -y". This is the same format as used by OpenSSH, though the restrictions are a subset (keys with unknown restrictions are ignored).
Restrictions are comma separated, with double quotes around spaces in arguments.
Available restrictions are:
.TP
.B no-port-forwarding
Don't allow port forwarding for this connection
.TP
.B no-agent-forwarding
Don't allow agent forwarding for this connection
.TP
.B no-X11-forwarding
Don't allow X11 forwarding for this connection
.TP
.B no-pty
Disable PTY allocation. Note that a user can still obtain most of the
same functionality with other means even if no-pty is set.
.TP
.B command="\fIforced_command\fR"
Disregard the command provided by the user and always run \fIforced_command\fR.
The authorized_keys file and its containing ~/.ssh directory must only be
writable by the user, otherwise Dropbear will not allow a login using public
key authentication.
.TP
Host Key Files
Host key files are read at startup from a standard location, by default
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
/etc/dropbear/dropbear-ecdsa_host_key
or specified on the commandline with -r. These are of the form generated
by dropbearkey. The -R option can be used to automatically generate keys
in the default location - keys will be generated after startup when the first
connection is established. This had the benefit that the system /dev/urandom
random number source has a better chance of being securely seeded.
.TP
Message Of The Day
By default the file /etc/motd will be printed for any login shell (unless
disabled at compile-time). This can also be disabled per-user
by creating a file ~/.hushlogin .
.SH ENVIRONMENT VARIABLES
Dropbear sets the standard variables USER, LOGNAME, HOME, SHELL, PATH, and TERM.
The variables below are set for sessions as appropriate.
.TP
.B SSH_TTY
This is set to the allocated TTY if a PTY was used.
.TP
.B SSH_CONNECTION
Contains "<remote_ip> <remote_port> <local_ip> <local_port>".
.TP
.B DISPLAY
Set X11 forwarding is used.
.TP
.B SSH_ORIGINAL_COMMAND
If a 'command=' authorized_keys option was used, the original command is specified
in this variable. If a shell was requested this is set to an empty value.
.TP
.B SSH_AUTH_SOCK
Set to a forwarded ssh-agent connection.
.SH NOTES
Dropbear only supports SSH protocol version 2.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbearkey(1), dbclient(1), dropbearconvert(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html

View File

@ -0,0 +1,50 @@
.TH dropbearconvert 1
.SH NAME
dropbearconvert \- convert between Dropbear and OpenSSH private key formats
.SH SYNOPSIS
.B dropbearconvert
.I input_type
.I output_type
.I input_file
.I output_file
.SH DESCRIPTION
.B Dropbear
and
.B OpenSSH
SSH implementations have different private key formats.
.B dropbearconvert
can convert between the two.
.P
Dropbear uses the same SSH public key format as OpenSSH, it can be extracted
from a private key by using
.B dropbearkey \-y
.P
Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them
first.
.SH OPTIONS
.TP
.B input type
Either
.I dropbear
or
.I openssh
.TP
.B output type
Either
.I dropbear
or
.I openssh
.TP
.B input file
An existing Dropbear or OpenSSH private key file
.TP
.B output file
The path to write the converted private key file
.SH EXAMPLE
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/dropbear_priv
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.SH SEE ALSO
dropbearkey(1), ssh-keygen(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html

145
dropbear/dropbearconvert.c Normal file
View File

@ -0,0 +1,145 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
/* This program converts to/from Dropbear and OpenSSH private-key formats */
#include "includes.h"
#include "signkey.h"
#include "buffer.h"
#include "dbutil.h"
#include "keyimport.h"
#include "crypto_desc.h"
#include "dbrandom.h"
static int do_convert(int intype, const char* infile, int outtype,
const char* outfile);
static void printhelp(char * progname);
static void printhelp(char * progname) {
fprintf(stderr, "Usage: %s <inputtype> <outputtype> <inputfile> <outputfile>\n\n"
"CAUTION: This program is for convenience only, and is not secure if used on\n"
"untrusted input files, ie it could allow arbitrary code execution.\n"
"All parameters must be specified in order.\n"
"\n"
"The input and output types are one of:\n"
"openssh\n"
"dropbear\n"
"\n"
"Example:\n"
"dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key /etc/dropbear_rsa_host_key\n",
progname);
}
#if defined(DBMULTI_dropbearconvert) || !defined(DROPBEAR_MULTI)
#if defined(DBMULTI_dropbearconvert) && defined(DROPBEAR_MULTI)
int dropbearconvert_main(int argc, char ** argv) {
#else
int main(int argc, char ** argv) {
#endif
int intype, outtype;
const char* infile;
const char* outfile;
crypto_init();
seedrandom();
#ifdef DEBUG_TRACE
/* It's hard for it to get in the way _too_ much */
debug_trace = 1;
#endif
/* get the commandline options */
if (argc != 5) {
fprintf(stderr, "All arguments must be specified\n");
goto usage;
}
/* input type */
if (argv[1][0] == 'd') {
intype = KEYFILE_DROPBEAR;
} else if (argv[1][0] == 'o') {
intype = KEYFILE_OPENSSH;
} else {
fprintf(stderr, "Invalid input key type\n");
goto usage;
}
/* output type */
if (argv[2][0] == 'd') {
outtype = KEYFILE_DROPBEAR;
} else if (argv[2][0] == 'o') {
outtype = KEYFILE_OPENSSH;
} else {
fprintf(stderr, "Invalid output key type\n");
goto usage;
}
/* we don't want output readable by others */
umask(077);
infile = argv[3];
outfile = argv[4];
return do_convert(intype, infile, outtype, outfile);
usage:
printhelp(argv[0]);
return 1;
}
#endif
static int do_convert(int intype, const char* infile, int outtype,
const char* outfile) {
sign_key * key = NULL;
const char * keytype = NULL;
int ret = 1;
key = import_read(infile, NULL, intype);
if (!key) {
fprintf(stderr, "Error reading key from '%s'\n",
infile);
goto out;
}
keytype = signkey_name_from_type(key->type, NULL);
fprintf(stderr, "Key is a %s key\n", keytype);
if (import_write(outfile, key, NULL, outtype) != 1) {
fprintf(stderr, "Error writing key to '%s'\n", outfile);
} else {
fprintf(stderr, "Wrote key to '%s'\n", outfile);
ret = 0;
}
out:
if (key) {
sign_key_free(key);
}
return ret;
}

55
dropbear/dropbearkey.1 Normal file
View File

@ -0,0 +1,55 @@
.TH dropbearkey 1
.SH NAME
dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
.SH SYNOPSIS
.B dropbearkey
\-t
.I type
\-f
.I file
[\-s
.IR bits ]
.SH DESCRIPTION
.B dropbearkey
generates a
.I RSA
.I DSS,
or
.I ECDSA
format SSH private key, and saves it to a file for the use with the
Dropbear client or server.
Note that
some SSH implementations
use the term "DSA" rather than "DSS", they mean the same thing.
.SH OPTIONS
.TP
.B \-t \fItype
Type of key to generate.
Must be one of
.I rsa
.I ecdsa
or
.IR dss .
.TP
.B \-f \fIfile
Write the secret key to the file
.IR file .
.TP
.B \-s \fIbits
Set the key size to
.I bits
bits, should be multiple of 8 (optional).
.SH NOTES
The program dropbearconvert(1) can be used to convert between Dropbear and OpenSSH key formats.
.P
Dropbear does not support encrypted keys.
.SH EXAMPLE
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8), dbclient(1), dropbearconvert(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html

340
dropbear/dropbearkey.c Normal file
View File

@ -0,0 +1,340 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
/* The format of the keyfiles is basically a raw dump of the buffer. Data types
* are specified in the transport rfc 4253 - string is a 32-bit len then the
* non-null-terminated string, mp_int is a 32-bit len then the bignum data.
* The actual functions are buf_put_rsa_priv_key() and buf_put_dss_priv_key()
* RSA:
* string "ssh-rsa"
* mp_int e
* mp_int n
* mp_int d
* mp_int p (newer versions only)
* mp_int q (newer versions only)
*
* DSS:
* string "ssh-dss"
* mp_int p
* mp_int q
* mp_int g
* mp_int y
* mp_int x
*
*/
#include "includes.h"
#include "signkey.h"
#include "buffer.h"
#include "dbutil.h"
#include "genrsa.h"
#include "gendss.h"
#include "ecdsa.h"
#include "crypto_desc.h"
#include "dbrandom.h"
#include "gensignkey.h"
static void printhelp(char * progname);
static void printpubkey(sign_key * key, int keytype);
static int printpubfile(const char* filename);
/* Print a help message */
static void printhelp(char * progname) {
fprintf(stderr, "Usage: %s -t <type> -f <filename> [-s bits]\n"
"-t type Type of key to generate. One of:\n"
#ifdef DROPBEAR_RSA
" rsa\n"
#endif
#ifdef DROPBEAR_DSS
" dss\n"
#endif
#ifdef DROPBEAR_ECDSA
" ecdsa\n"
#endif
"-f filename Use filename for the secret key\n"
"-s bits Key size in bits, should be a multiple of 8 (optional)\n"
#ifdef DROPBEAR_DSS
" DSS has a fixed size of 1024 bits\n"
#endif
#ifdef DROPBEAR_ECDSA
" ECDSA has sizes "
#ifdef DROPBEAR_ECC_256
"256 "
#endif
#ifdef DROPBEAR_ECC_384
"384 "
#endif
#ifdef DROPBEAR_ECC_521
"521 "
#endif
"\n"
#endif
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
#ifdef DEBUG_TRACE
"-v verbose\n"
#endif
,progname);
}
/* fails fatally */
static void check_signkey_bits(enum signkey_type type, int bits)
{
switch (type) {
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
" multiple of 8\n");
}
break;
#endif
#ifdef DROPEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
if (bits != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
exit(EXIT_FAILURE);
}
#endif
default:
(void)0; /* quiet, compiler. ecdsa handles checks itself */
}
}
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
#if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
int dropbearkey_main(int argc, char ** argv) {
#else
int main(int argc, char ** argv) {
#endif
int i;
char ** next = 0;
char * filename = NULL;
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
char * typetext = NULL;
char * sizetext = NULL;
unsigned int bits = 0;
int printpub = 0;
crypto_init();
seedrandom();
/* get the commandline options */
for (i = 1; i < argc; i++) {
if (argv[i] == NULL) {
continue; /* Whack */
}
if (next) {
*next = argv[i];
next = NULL;
continue;
}
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'f':
next = &filename;
break;
case 't':
next = &typetext;
break;
case 's':
next = &sizetext;
break;
case 'y':
printpub = 1;
break;
case 'h':
printhelp(argv[0]);
exit(EXIT_SUCCESS);
break;
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
break;
#endif
default:
fprintf(stderr, "Unknown argument %s\n", argv[i]);
printhelp(argv[0]);
exit(EXIT_FAILURE);
break;
}
}
}
if (!filename) {
fprintf(stderr, "Must specify a key filename\n");
printhelp(argv[0]);
exit(EXIT_FAILURE);
}
if (printpub) {
int ret = printpubfile(filename);
exit(ret);
}
/* check/parse args */
if (!typetext) {
fprintf(stderr, "Must specify key type\n");
printhelp(argv[0]);
exit(EXIT_FAILURE);
}
#ifdef DROPBEAR_RSA
if (strcmp(typetext, "rsa") == 0)
{
keytype = DROPBEAR_SIGNKEY_RSA;
}
#endif
#ifdef DROPBEAR_DSS
if (strcmp(typetext, "dss") == 0)
{
keytype = DROPBEAR_SIGNKEY_DSS;
}
#endif
#ifdef DROPBEAR_ECDSA
if (strcmp(typetext, "ecdsa") == 0)
{
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
}
#endif
if (keytype == DROPBEAR_SIGNKEY_NONE) {
fprintf(stderr, "Unknown key type '%s'\n", typetext);
printhelp(argv[0]);
exit(EXIT_FAILURE);
}
if (sizetext) {
if (sscanf(sizetext, "%u", &bits) != 1) {
fprintf(stderr, "Bits must be an integer\n");
exit(EXIT_FAILURE);
}
check_signkey_bits(keytype, bits);;
}
fprintf(stderr, "Generating key, this may take a while...\n");
if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
{
dropbear_exit("Failed to generate key.\n");
}
printpubfile(filename);
return EXIT_SUCCESS;
}
#endif
static int printpubfile(const char* filename) {
buffer *buf = NULL;
sign_key *key = NULL;
enum signkey_type keytype;
int ret;
int err = DROPBEAR_FAILURE;
buf = buf_new(MAX_PRIVKEY_SIZE);
ret = buf_readfile(buf, filename);
if (ret != DROPBEAR_SUCCESS) {
fprintf(stderr, "Failed reading '%s'\n", filename);
goto out;
}
key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY;
buf_setpos(buf, 0);
ret = buf_get_priv_key(buf, key, &keytype);
if (ret == DROPBEAR_FAILURE) {
fprintf(stderr, "Bad key in '%s'\n", filename);
goto out;
}
printpubkey(key, keytype);
err = DROPBEAR_SUCCESS;
out:
buf_burn(buf);
buf_free(buf);
buf = NULL;
if (key) {
sign_key_free(key);
key = NULL;
}
return err;
}
static void printpubkey(sign_key * key, int keytype) {
buffer * buf = NULL;
unsigned char base64key[MAX_PUBKEY_SIZE*2];
unsigned long base64len;
int err;
const char * typestring = NULL;
char *fp = NULL;
int len;
struct passwd * pw = NULL;
char * username = NULL;
char hostname[100];
buf = buf_new(MAX_PUBKEY_SIZE);
buf_put_pub_key(buf, key, keytype);
buf_setpos(buf, 4);
len = buf->len - buf->pos;
base64len = sizeof(base64key);
err = base64_encode(buf_getptr(buf, len), len, base64key, &base64len);
if (err != CRYPT_OK) {
fprintf(stderr, "base64 failed");
}
typestring = signkey_name_from_type(keytype, NULL);
fp = sign_key_fingerprint(buf_getptr(buf, len), len);
/* a user@host comment is informative */
username = "";
pw = getpwuid(getuid());
if (pw) {
username = pw->pw_name;
}
gethostname(hostname, sizeof(hostname));
hostname[sizeof(hostname)-1] = '\0';
printf("Public key portion is:\n%s %s %s@%s\nFingerprint: %s\n",
typestring, base64key, username, hostname, fp);
m_free(fp);
buf_free(buf);
}

350
dropbear/dss.c Normal file
View File

@ -0,0 +1,350 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
#include "bignum.h"
#include "dss.h"
#include "buffer.h"
#include "ssh.h"
#include "dbrandom.h"
/* Handle DSS (Digital Signature Standard), aka DSA (D.S. Algorithm),
* operations, such as key reading, signing, verification. Key generation
* is in gendss.c, since it isn't required in the server itself.
*
* See FIPS186 or the Handbook of Applied Cryptography for details of the
* algorithm */
#ifdef DROPBEAR_DSS
/* Load a dss key from a buffer, initialising the values.
* The key will have the same format as buf_put_dss_key.
* These should be freed with dss_key_free.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
TRACE(("enter buf_get_dss_pub_key"))
dropbear_assert(key != NULL);
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, NULL);
key->x = NULL;
buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE
|| buf_getmpint(buf, key->q) == DROPBEAR_FAILURE
|| buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
|| buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
return DROPBEAR_FAILURE;
}
if (mp_count_bits(key->p) < MIN_DSS_KEYLEN) {
dropbear_log(LOG_WARNING, "DSS key too short");
TRACE(("leave buf_get_dss_pub_key: short key"))
return DROPBEAR_FAILURE;
}
TRACE(("leave buf_get_dss_pub_key: success"))
return DROPBEAR_SUCCESS;
}
/* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
* Loads a private dss key from a buffer
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
int ret = DROPBEAR_FAILURE;
dropbear_assert(key != NULL);
ret = buf_get_dss_pub_key(buf, key);
if (ret == DROPBEAR_FAILURE) {
return DROPBEAR_FAILURE;
}
m_mp_alloc_init_multi(&key->x, NULL);
ret = buf_getmpint(buf, key->x);
if (ret == DROPBEAR_FAILURE) {
m_free(key->x);
}
return ret;
}
/* Clear and free the memory used by a public or private key */
void dss_key_free(dropbear_dss_key *key) {
TRACE2(("enter dsa_key_free"))
if (key == NULL) {
TRACE2(("enter dsa_key_free: key == NULL"))
return;
}
if (key->p) {
mp_clear(key->p);
m_free(key->p);
}
if (key->q) {
mp_clear(key->q);
m_free(key->q);
}
if (key->g) {
mp_clear(key->g);
m_free(key->g);
}
if (key->y) {
mp_clear(key->y);
m_free(key->y);
}
if (key->x) {
mp_clear(key->x);
m_free(key->x);
}
m_free(key);
TRACE2(("leave dsa_key_free"))
}
/* put the dss public key into the buffer in the required format:
*
* string "ssh-dss"
* mpint p
* mpint q
* mpint g
* mpint y
*/
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
buf_putmpint(buf, key->p);
buf_putmpint(buf, key->q);
buf_putmpint(buf, key->g);
buf_putmpint(buf, key->y);
}
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
dropbear_assert(key != NULL);
buf_put_dss_pub_key(buf, key);
buf_putmpint(buf, key->x);
}
#ifdef DROPBEAR_SIGNKEY_VERIFY
/* Verify a DSS signature (in buf) made on data by the key given.
* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
unsigned char msghash[SHA1_HASH_SIZE];
hash_state hs;
int ret = DROPBEAR_FAILURE;
DEF_MP_INT(val1);
DEF_MP_INT(val2);
DEF_MP_INT(val3);
DEF_MP_INT(val4);
char * string = NULL;
int stringlen;
TRACE(("enter buf_dss_verify"))
dropbear_assert(key != NULL);
m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
/* get blob, check length */
string = buf_getstring(buf, &stringlen);
if (stringlen != 2*SHA1_HASH_SIZE) {
goto out;
}
/* hash the data */
sha1_init(&hs);
sha1_process(&hs, data_buf->data, data_buf->len);
sha1_done(&hs, msghash);
/* create the signature - s' and r' are the received signatures in buf */
/* w = (s')-1 mod q */
/* let val1 = s' */
bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, s' >= q"))
goto out;
}
/* let val2 = w = (s')^-1 mod q*/
if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) {
goto out;
}
/* u1 = ((SHA(M')w) mod q */
/* let val1 = SHA(M') = msghash */
bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
/* let val3 = u1 = ((SHA(M')w) mod q */
if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
goto out;
}
/* u2 = ((r')w) mod q */
/* let val1 = r' */
bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE);
if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, r' >= q"))
goto out;
}
/* let val4 = u2 = ((r')w) mod q */
if (mp_mulmod(&val1, &val2, key->q, &val4) != MP_OKAY) {
goto out;
}
/* v = (((g)^u1 (y)^u2) mod p) mod q */
/* val2 = g^u1 mod p */
if (mp_exptmod(key->g, &val3, key->p, &val2) != MP_OKAY) {
goto out;
}
/* val3 = y^u2 mod p */
if (mp_exptmod(key->y, &val4, key->p, &val3) != MP_OKAY) {
goto out;
}
/* val4 = ((g)^u1 (y)^u2) mod p */
if (mp_mulmod(&val2, &val3, key->p, &val4) != MP_OKAY) {
goto out;
}
/* val2 = v = (((g)^u1 (y)^u2) mod p) mod q */
if (mp_mod(&val4, key->q, &val2) != MP_OKAY) {
goto out;
}
/* check whether signatures verify */
if (mp_cmp(&val2, &val1) == MP_EQ) {
/* good sig */
ret = DROPBEAR_SUCCESS;
}
out:
mp_clear_multi(&val1, &val2, &val3, &val4, NULL);
m_free(string);
return ret;
}
#endif /* DROPBEAR_SIGNKEY_VERIFY */
/* Sign the data presented with key, writing the signature contents
* to the buffer */
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
unsigned char msghash[SHA1_HASH_SIZE];
unsigned int writelen;
unsigned int i;
DEF_MP_INT(dss_k);
DEF_MP_INT(dss_m);
DEF_MP_INT(dss_temp1);
DEF_MP_INT(dss_temp2);
DEF_MP_INT(dss_r);
DEF_MP_INT(dss_s);
hash_state hs;
TRACE(("enter buf_put_dss_sign"))
dropbear_assert(key != NULL);
/* hash the data */
sha1_init(&hs);
sha1_process(&hs, data_buf->data, data_buf->len);
sha1_done(&hs, msghash);
m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
&dss_m, NULL);
/* the random number generator's input has included the private key which
* avoids DSS's problem of private key exposure due to low entropy */
gen_random_mpint(key->q, &dss_k);
/* now generate the actual signature */
bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
/* g^k mod p */
if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) {
dropbear_exit("DSS error");
}
/* r = (g^k mod p) mod q */
if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
dropbear_exit("DSS error");
}
/* x*r mod q */
if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
dropbear_exit("DSS error");
}
/* (SHA1(M) + xr) mod q) */
if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
dropbear_exit("DSS error");
}
/* (k^-1) mod q */
if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
dropbear_exit("DSS error");
}
/* s = (k^-1(SHA1(M) + xr)) mod q */
if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
dropbear_exit("DSS error");
}
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
buf_putint(buf, 2*SHA1_HASH_SIZE);
writelen = mp_unsigned_bin_size(&dss_r);
dropbear_assert(writelen <= SHA1_HASH_SIZE);
/* need to pad to 160 bits with leading zeros */
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
buf_putbyte(buf, 0);
}
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
!= MP_OKAY) {
dropbear_exit("DSS error");
}
mp_clear(&dss_r);
buf_incrwritepos(buf, writelen);
writelen = mp_unsigned_bin_size(&dss_s);
dropbear_assert(writelen <= SHA1_HASH_SIZE);
/* need to pad to 160 bits with leading zeros */
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
buf_putbyte(buf, 0);
}
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
!= MP_OKAY) {
dropbear_exit("DSS error");
}
mp_clear(&dss_s);
buf_incrwritepos(buf, writelen);
mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
&dss_m, NULL);
/* create the signature to return */
TRACE(("leave buf_put_dss_sign"))
}
#endif /* DROPBEAR_DSS */

56
dropbear/dss.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _DSS_H_
#define _DSS_H_
#include "includes.h"
#include "buffer.h"
#ifdef DROPBEAR_DSS
typedef struct {
mp_int* p;
mp_int* q;
mp_int* g;
mp_int* y;
/* x is the private part */
mp_int* x;
} dropbear_dss_key;
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
#ifdef DROPBEAR_SIGNKEY_VERIFY
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
#endif
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key);
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key);
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key);
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key);
void dss_key_free(dropbear_dss_key *key);
#endif /* DROPBEAR_DSS */
#endif /* _DSS_H_ */

275
dropbear/ecc.c Normal file
View File

@ -0,0 +1,275 @@
#include "includes.h"
#include "options.h"
#include "ecc.h"
#include "dbutil.h"
#include "bignum.h"
#ifdef DROPBEAR_ECC
/* .dp members are filled out by dropbear_ecc_fill_dp() at startup */
#ifdef DROPBEAR_ECC_256
struct dropbear_ecc_curve ecc_curve_nistp256 = {
32, /* .ltc_size */
NULL, /* .dp */
&sha256_desc, /* .hash_desc */
"nistp256" /* .name */
};
#endif
#ifdef DROPBEAR_ECC_384
struct dropbear_ecc_curve ecc_curve_nistp384 = {
48, /* .ltc_size */
NULL, /* .dp */
&sha384_desc, /* .hash_desc */
"nistp384" /* .name */
};
#endif
#ifdef DROPBEAR_ECC_521
struct dropbear_ecc_curve ecc_curve_nistp521 = {
66, /* .ltc_size */
NULL, /* .dp */
&sha512_desc, /* .hash_desc */
"nistp521" /* .name */
};
#endif
struct dropbear_ecc_curve *dropbear_ecc_curves[] = {
#ifdef DROPBEAR_ECC_256
&ecc_curve_nistp256,
#endif
#ifdef DROPBEAR_ECC_384
&ecc_curve_nistp384,
#endif
#ifdef DROPBEAR_ECC_521
&ecc_curve_nistp521,
#endif
NULL
};
void dropbear_ecc_fill_dp() {
struct dropbear_ecc_curve **curve;
/* libtomcrypt guarantees they're ordered by size */
const ltc_ecc_set_type *dp = ltc_ecc_sets;
for (curve = dropbear_ecc_curves; *curve; curve++) {
for (;dp->size > 0; dp++) {
if (dp->size == (*curve)->ltc_size) {
(*curve)->dp = dp;
break;
}
}
if (!(*curve)->dp) {
dropbear_exit("Missing ECC params %s", (*curve)->name);
}
}
}
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp) {
struct dropbear_ecc_curve **curve = NULL;
for (curve = dropbear_ecc_curves; *curve; curve++) {
if ((*curve)->dp == dp) {
break;
}
}
assert(*curve);
return *curve;
}
ecc_key * new_ecc_key(void) {
ecc_key *key = m_malloc(sizeof(*key));
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;
}
/* Copied from libtomcrypt ecc_import.c (version there is static), modified
for different mp_int pointer without LTC_SOURCE */
static int ecc_is_point(ecc_key *key)
{
mp_int *prime, *b, *t1, *t2;
int err;
prime = m_malloc(sizeof(mp_int));
b = m_malloc(sizeof(mp_int));
t1 = m_malloc(sizeof(mp_int));
t2 = m_malloc(sizeof(mp_int));
m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);
/* load prime and b */
if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) { goto error; }
if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) { goto error; }
/* compute y^2 */
if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) { goto error; }
/* compute x^3 */
if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK) { goto error; }
if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) { goto error; }
if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK) { goto error; }
/* compute y^2 - x^3 */
if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) { goto error; }
/* compute y^2 - x^3 + 3x */
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK) { goto error; }
while (mp_cmp_d(t1, 0) == LTC_MP_LT) {
if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) { goto error; }
}
while (mp_cmp(t1, prime) != LTC_MP_LT) {
if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) { goto error; }
}
/* compare to b */
if (mp_cmp(t1, b) != LTC_MP_EQ) {
err = CRYPT_INVALID_PACKET;
} else {
err = CRYPT_OK;
}
error:
mp_clear_multi(prime, b, t1, t2, NULL);
m_free(prime);
m_free(b);
m_free(t1);
m_free(t2);
return err;
}
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key) {
unsigned long len = key->dp->size*2 + 1;
int err;
buf_putint(buf, len);
err = ecc_ansi_x963_export(key, buf_getwriteptr(buf, len), &len);
if (err != CRYPT_OK) {
dropbear_exit("ECC error");
}
buf_incrwritepos(buf, len);
}
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve) {
ecc_key *key = NULL;
int ret = DROPBEAR_FAILURE;
const unsigned int size = curve->dp->size;
unsigned char first;
TRACE(("enter buf_get_ecc_raw_pubkey"))
buf_setpos(buf, 0);
first = buf_getbyte(buf);
if (first == 2 || first == 3) {
dropbear_log(LOG_WARNING, "Dropbear doesn't support ECC point compression");
return NULL;
}
if (first != 4 || buf->len != 1+2*size) {
TRACE(("leave, wrong size"))
return NULL;
}
key = new_ecc_key();
key->dp = curve->dp;
if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
TRACE(("failed to read x"))
goto out;
}
buf_incrpos(buf, size);
if (mp_read_unsigned_bin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
TRACE(("failed to read y"))
goto out;
}
buf_incrpos(buf, size);
mp_set(key->pubkey.z, 1);
if (ecc_is_point(key) != CRYPT_OK) {
TRACE(("failed, not a point"))
goto out;
}
/* SEC1 3.2.3.1 Check that Q != 0 */
if (mp_cmp_d(key->pubkey.x, 0) == LTC_MP_EQ) {
TRACE(("failed, x == 0"))
goto out;
}
if (mp_cmp_d(key->pubkey.y, 0) == LTC_MP_EQ) {
TRACE(("failed, y == 0"))
goto out;
}
ret = DROPBEAR_SUCCESS;
out:
if (ret == DROPBEAR_FAILURE) {
if (key) {
ecc_free(key);
m_free(key);
key = NULL;
}
}
return key;
}
/* a modified version of libtomcrypt's "ecc_shared_secret" to output
a mp_int instead. */
mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key)
{
ecc_point *result = NULL;
mp_int *prime = NULL, *shared_secret = NULL;
int err = DROPBEAR_FAILURE;
/* type valid? */
if (private_key->type != PK_PRIVATE) {
goto done;
}
if (private_key->dp != public_key->dp) {
goto done;
}
/* make new point */
result = ltc_ecc_new_point();
if (result == NULL) {
goto done;
}
prime = m_malloc(sizeof(*prime));
m_mp_init(prime);
if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) {
goto done;
}
if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) {
goto done;
}
err = DROPBEAR_SUCCESS;
done:
if (err == DROPBEAR_SUCCESS) {
shared_secret = m_malloc(sizeof(*shared_secret));
m_mp_init(shared_secret);
mp_copy(result->x, shared_secret);
}
if (prime) {
mp_clear(prime);
m_free(prime);
}
if (result)
{
ltc_ecc_del_point(result);
}
if (err == DROPBEAR_FAILURE) {
dropbear_exit("ECC error");
}
return shared_secret;
}
#endif

36
dropbear/ecc.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef _DROPBEAR_ECC_H
#define _DROPBEAR_ECC_H
#include "includes.h"
#include "options.h"
#include "buffer.h"
#ifdef DROPBEAR_ECC
struct dropbear_ecc_curve {
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
const ltc_ecc_set_type *dp; /* curve domain parameters */
const struct ltc_hash_descriptor *hash_desc;
const unsigned char *name;
};
extern struct dropbear_ecc_curve ecc_curve_nistp256;
extern struct dropbear_ecc_curve ecc_curve_nistp384;
extern struct dropbear_ecc_curve ecc_curve_nistp521;
extern struct dropbear_ecc_curve *dropbear_ecc_curves[];
void dropbear_ecc_fill_dp();
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp);
/* "pubkey" refers to a point, but LTC uses ecc_key structure for both public
and private keys */
void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key);
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve);
int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key);
mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key);
#endif
#endif /* _DROPBEAR_ECC_H */

420
dropbear/ecdsa.c Normal file
View File

@ -0,0 +1,420 @@
#include "options.h"
#include "includes.h"
#include "dbutil.h"
#include "crypto_desc.h"
#include "ecc.h"
#include "ecdsa.h"
#include "signkey.h"
#ifdef DROPBEAR_ECDSA
int signkey_is_ecdsa(enum signkey_type type)
{
return type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521;
}
enum signkey_type ecdsa_signkey_type(ecc_key * key) {
#ifdef DROPBEAR_ECC_256
if (key->dp == ecc_curve_nistp256.dp) {
return DROPBEAR_SIGNKEY_ECDSA_NISTP256;
}
#endif
#ifdef DROPBEAR_ECC_384
if (key->dp == ecc_curve_nistp384.dp) {
return DROPBEAR_SIGNKEY_ECDSA_NISTP384;
}
#endif
#ifdef DROPBEAR_ECC_521
if (key->dp == ecc_curve_nistp521.dp) {
return DROPBEAR_SIGNKEY_ECDSA_NISTP521;
}
#endif
return DROPBEAR_SIGNKEY_NONE;
}
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
const ltc_ecc_set_type *dp = NULL; /* curve domain parameters */
ecc_key *new_key = NULL;
switch (bit_size) {
#ifdef DROPBEAR_ECC_256
case 256:
dp = ecc_curve_nistp256.dp;
break;
#endif
#ifdef DROPBEAR_ECC_384
case 384:
dp = ecc_curve_nistp384.dp;
break;
#endif
#ifdef DROPBEAR_ECC_521
case 521:
dp = ecc_curve_nistp521.dp;
break;
#endif
}
if (!dp) {
dropbear_exit("Key size %d isn't valid. Try "
#ifdef DROPBEAR_ECC_256
"256 "
#endif
#ifdef DROPBEAR_ECC_384
"384 "
#endif
#ifdef DROPBEAR_ECC_521
"521 "
#endif
, bit_size);
}
new_key = m_malloc(sizeof(*new_key));
if (ecc_make_key_ex(NULL, dropbear_ltc_prng, new_key, dp) != CRYPT_OK) {
dropbear_exit("ECC error");
}
return new_key;
}
ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
unsigned char *key_ident = NULL, *identifier = NULL;
unsigned int key_ident_len, identifier_len;
buffer *q_buf = NULL;
struct dropbear_ecc_curve **curve;
ecc_key *new_key = NULL;
/* string "ecdsa-sha2-[identifier]" */
key_ident = buf_getstring(buf, &key_ident_len);
/* string "[identifier]" */
identifier = buf_getstring(buf, &identifier_len);
if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
TRACE(("Bad identifier lengths"))
goto out;
}
if (memcmp(&key_ident[strlen("ecdsa-sha2-")], identifier, identifier_len) != 0) {
TRACE(("mismatching identifiers"))
goto out;
}
for (curve = dropbear_ecc_curves; *curve; curve++) {
if (memcmp(identifier, (char*)(*curve)->name, strlen((char*)(*curve)->name)) == 0) {
break;
}
}
if (!*curve) {
TRACE(("couldn't match ecc curve"))
goto out;
}
/* string Q */
q_buf = buf_getstringbuf(buf);
new_key = buf_get_ecc_raw_pubkey(q_buf, *curve);
out:
m_free(key_ident);
m_free(identifier);
if (q_buf) {
buf_free(q_buf);
q_buf = NULL;
}
TRACE(("leave buf_get_ecdsa_pub_key"))
return new_key;
}
ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
ecc_key *new_key = NULL;
TRACE(("enter buf_get_ecdsa_priv_key"))
new_key = buf_get_ecdsa_pub_key(buf);
if (!new_key) {
return NULL;
}
if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
ecc_free(new_key);
return NULL;
}
return new_key;
}
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
struct dropbear_ecc_curve *curve = NULL;
unsigned char key_ident[30];
curve = curve_for_dp(key->dp);
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
buf_putstring(buf, key_ident, strlen(key_ident));
buf_putstring(buf, curve->name, strlen(curve->name));
buf_put_ecc_raw_pubkey_string(buf, key);
}
void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) {
buf_put_ecdsa_pub_key(buf, key);
buf_putmpint(buf, key->k);
}
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
/* Based on libtomcrypt's ecc_sign_hash but without the asn1 */
int err = DROPBEAR_FAILURE;
struct dropbear_ecc_curve *curve = NULL;
hash_state hs;
unsigned char hash[64];
void *e = NULL, *p = NULL, *s = NULL, *r;
unsigned char key_ident[30];
buffer *sigbuf = NULL;
TRACE(("buf_put_ecdsa_sign"))
curve = curve_for_dp(key->dp);
if (ltc_init_multi(&r, &s, &p, &e, NULL) != CRYPT_OK) {
goto out;
}
curve->hash_desc->init(&hs);
curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
curve->hash_desc->done(&hs, hash);
if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
goto out;
}
if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
goto out;
}
for (;;) {
ecc_key R_key; /* ephemeral key */
if (ecc_make_key_ex(NULL, dropbear_ltc_prng, &R_key, key->dp) != CRYPT_OK) {
goto out;
}
if (ltc_mp.mpdiv(R_key.pubkey.x, p, NULL, r) != CRYPT_OK) {
goto out;
}
if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ) {
/* try again */
ecc_free(&R_key);
continue;
}
/* k = 1/k */
if (ltc_mp.invmod(R_key.k, p, R_key.k) != CRYPT_OK) {
goto out;
}
/* s = xr */
if (ltc_mp.mulmod(key->k, r, p, s) != CRYPT_OK) {
goto out;
}
/* s = e + xr */
if (ltc_mp.add(e, s, s) != CRYPT_OK) {
goto out;
}
if (ltc_mp.mpdiv(s, p, NULL, s) != CRYPT_OK) {
goto out;
}
/* s = (e + xr)/k */
if (ltc_mp.mulmod(s, R_key.k, p, s) != CRYPT_OK) {
goto out;
}
ecc_free(&R_key);
if (ltc_mp.compare_d(s, 0) != LTC_MP_EQ) {
break;
}
}
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
buf_putstring(buf, key_ident, strlen(key_ident));
/* enough for nistp521 */
sigbuf = buf_new(200);
buf_putmpint(sigbuf, (mp_int*)r);
buf_putmpint(sigbuf, (mp_int*)s);
buf_putbufstring(buf, sigbuf);
err = DROPBEAR_SUCCESS;
out:
if (r && s && p && e) {
ltc_deinit_multi(r, s, p, e, NULL);
}
if (sigbuf) {
buf_free(sigbuf);
}
if (err == DROPBEAR_FAILURE) {
dropbear_exit("ECC error");
}
}
/* returns values in s and r
returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int buf_get_ecdsa_verify_params(buffer *buf,
void *r, void* s) {
int ret = DROPBEAR_FAILURE;
unsigned int sig_len;
unsigned int sig_pos;
sig_len = buf_getint(buf);
sig_pos = buf->pos;
if (buf_getmpint(buf, r) != DROPBEAR_SUCCESS) {
goto out;
}
if (buf_getmpint(buf, s) != DROPBEAR_SUCCESS) {
goto out;
}
if (buf->pos - sig_pos != sig_len) {
goto out;
}
ret = DROPBEAR_SUCCESS;
out:
return ret;
}
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
/* Based on libtomcrypt's ecc_verify_hash but without the asn1 */
int ret = DROPBEAR_FAILURE;
hash_state hs;
struct dropbear_ecc_curve *curve = NULL;
unsigned char hash[64];
ecc_point *mG = NULL, *mQ = NULL;
void *r = NULL, *s = NULL, *v = NULL, *w = NULL, *u1 = NULL, *u2 = NULL,
*e = NULL, *p = NULL, *m = NULL;
void *mp = NULL;
/* verify
*
* w = s^-1 mod n
* u1 = xw
* u2 = rw
* X = u1*G + u2*Q
* v = X_x1 mod n
* accept if v == r
*/
TRACE(("buf_ecdsa_verify"))
curve = curve_for_dp(key->dp);
mG = ltc_ecc_new_point();
mQ = ltc_ecc_new_point();
if (ltc_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL) != CRYPT_OK
|| !mG
|| !mQ) {
dropbear_exit("ECC error");
}
if (buf_get_ecdsa_verify_params(buf, r, s) != DROPBEAR_SUCCESS) {
goto out;
}
curve->hash_desc->init(&hs);
curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
curve->hash_desc->done(&hs, hash);
if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
goto out;
}
/* get the order */
if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
goto out;
}
/* get the modulus */
if (ltc_mp.read_radix(m, (char *)key->dp->prime, 16) != CRYPT_OK) {
goto out;
}
/* check for zero */
if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ
|| ltc_mp.compare_d(s, 0) == LTC_MP_EQ
|| ltc_mp.compare(r, p) != LTC_MP_LT
|| ltc_mp.compare(s, p) != LTC_MP_LT) {
goto out;
}
/* w = s^-1 mod n */
if (ltc_mp.invmod(s, p, w) != CRYPT_OK) {
goto out;
}
/* u1 = ew */
if (ltc_mp.mulmod(e, w, p, u1) != CRYPT_OK) {
goto out;
}
/* u2 = rw */
if (ltc_mp.mulmod(r, w, p, u2) != CRYPT_OK) {
goto out;
}
/* find mG and mQ */
if (ltc_mp.read_radix(mG->x, (char *)key->dp->Gx, 16) != CRYPT_OK) {
goto out;
}
if (ltc_mp.read_radix(mG->y, (char *)key->dp->Gy, 16) != CRYPT_OK) {
goto out;
}
if (ltc_mp.set_int(mG->z, 1) != CRYPT_OK) {
goto out;
}
if (ltc_mp.copy(key->pubkey.x, mQ->x) != CRYPT_OK
|| ltc_mp.copy(key->pubkey.y, mQ->y) != CRYPT_OK
|| ltc_mp.copy(key->pubkey.z, mQ->z) != CRYPT_OK) {
goto out;
}
/* compute u1*mG + u2*mQ = mG */
if (ltc_mp.ecc_mul2add == NULL) {
if (ltc_mp.ecc_ptmul(u1, mG, mG, m, 0) != CRYPT_OK) {
goto out;
}
if (ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0) != CRYPT_OK) {
goto out;
}
/* find the montgomery mp */
if (ltc_mp.montgomery_setup(m, &mp) != CRYPT_OK) {
goto out;
}
/* add them */
if (ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp) != CRYPT_OK) {
goto out;
}
/* reduce */
if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) {
goto out;
}
} else {
/* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) {
goto out;
}
}
/* v = X_x1 mod n */
if (ltc_mp.mpdiv(mG->x, p, NULL, v) != CRYPT_OK) {
goto out;
}
/* does v == r */
if (ltc_mp.compare(v, r) == LTC_MP_EQ) {
ret = DROPBEAR_SUCCESS;
}
out:
ltc_ecc_del_point(mG);
ltc_ecc_del_point(mQ);
mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
if (mp != NULL) {
ltc_mp.montgomery_deinit(mp);
}
return ret;
}
#endif /* DROPBEAR_ECDSA */

35
dropbear/ecdsa.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _ECDSA_H_
#define _ECDSA_H_
#include "includes.h"
#include "buffer.h"
#include "signkey.h"
#ifdef DROPBEAR_ECDSA
/* Prefer the larger size - it's fast anyway */
#if defined(DROPBEAR_ECC_521)
#define ECDSA_DEFAULT_SIZE 521
#elif defined(DROPBEAR_ECC_384)
#define ECDSA_DEFAULT_SIZE 384
#elif defined(DROPBEAR_ECC_256)
#define ECDSA_DEFAULT_SIZE 256
#else
#define ECDSA_DEFAULT_SIZE 0
#endif
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size);
ecc_key *buf_get_ecdsa_pub_key(buffer* buf);
ecc_key *buf_get_ecdsa_priv_key(buffer *buf);
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key);
void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key);
enum signkey_type ecdsa_signkey_type(ecc_key * key);
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf);
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf);
/* Returns 1 on success */
int signkey_is_ecdsa(enum signkey_type type);
#endif
#endif /* _ECDSA_H_ */

237
dropbear/fake-rfc2553.c Normal file
View File

@ -0,0 +1,237 @@
/* Taken for Dropbear from OpenSSH 5.5p1 */
/*
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
* Copyright (C) 1999 WIDE Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Pseudo-implementation of RFC2553 name / address resolution functions
*
* But these functions are not implemented correctly. The minimum subset
* is implemented for ssh use only. For example, this routine assumes
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#include "includes.h"
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef HAVE_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags)
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
struct hostent *hp;
char tmpserv[16];
if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET)
return (EAI_FAMILY);
if (serv != NULL) {
snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
if (strlcpy(serv, tmpserv, servlen) >= servlen)
return (EAI_MEMORY);
}
if (host != NULL) {
if (flags & NI_NUMERICHOST) {
if (strlcpy(host, inet_ntoa(sin->sin_addr),
hostlen) >= hostlen)
return (EAI_MEMORY);
else
return (0);
} else {
hp = gethostbyaddr((char *)&sin->sin_addr,
sizeof(struct in_addr), AF_INET);
if (hp == NULL)
return (EAI_NODATA);
if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
return (EAI_MEMORY);
else
return (0);
}
}
return (0);
}
#endif /* !HAVE_GETNAMEINFO */
#ifndef HAVE_GAI_STRERROR
#ifdef HAVE_CONST_GAI_STRERROR_PROTO
const char *
#else
char *
#endif
gai_strerror(int err)
{
switch (err) {
case EAI_NODATA:
return ("no address associated with name");
case EAI_MEMORY:
return ("memory allocation failure.");
case EAI_NONAME:
return ("nodename nor servname provided, or not known");
case EAI_FAMILY:
return ("ai_family not supported");
default:
return ("unknown/invalid error.");
}
}
#endif /* !HAVE_GAI_STRERROR */
#ifndef HAVE_FREEADDRINFO
void
freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *next;
for(; ai != NULL;) {
next = ai->ai_next;
free(ai);
ai = next;
}
}
#endif /* !HAVE_FREEADDRINFO */
#ifndef HAVE_GETADDRINFO
static struct
addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints)
{
struct addrinfo *ai;
ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in));
if (ai == NULL)
return (NULL);
memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in));
ai->ai_addr = (struct sockaddr *)(ai + 1);
/* XXX -- ssh doesn't use sa_len */
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr->sa_family = ai->ai_family = AF_INET;
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
/* XXX: the following is not generally correct, but does what we want */
if (hints->ai_socktype)
ai->ai_socktype = hints->ai_socktype;
else
ai->ai_socktype = SOCK_STREAM;
if (hints->ai_protocol)
ai->ai_protocol = hints->ai_protocol;
return (ai);
}
int
getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
struct hostent *hp;
struct servent *sp;
struct in_addr in;
int i;
long int port;
u_long addr;
port = 0;
if (hints && hints->ai_family != AF_UNSPEC &&
hints->ai_family != AF_INET)
return (EAI_FAMILY);
if (servname != NULL) {
char *cp;
port = strtol(servname, &cp, 10);
if (port > 0 && port <= 65535 && *cp == '\0')
port = htons(port);
else if ((sp = getservbyname(servname, NULL)) != NULL)
port = sp->s_port;
else
port = 0;
}
if (hints && hints->ai_flags & AI_PASSIVE) {
addr = htonl(0x00000000);
if (hostname && inet_aton(hostname, &in) != 0)
addr = in.s_addr;
*res = malloc_ai(port, addr, hints);
if (*res == NULL)
return (EAI_MEMORY);
return (0);
}
if (!hostname) {
*res = malloc_ai(port, htonl(0x7f000001), hints);
if (*res == NULL)
return (EAI_MEMORY);
return (0);
}
if (inet_aton(hostname, &in)) {
*res = malloc_ai(port, in.s_addr, hints);
if (*res == NULL)
return (EAI_MEMORY);
return (0);
}
/* Don't try DNS if AI_NUMERICHOST is set */
if (hints && hints->ai_flags & AI_NUMERICHOST)
return (EAI_NONAME);
hp = gethostbyname(hostname);
if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
struct addrinfo *cur, *prev;
cur = prev = *res = NULL;
for (i = 0; hp->h_addr_list[i]; i++) {
struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
cur = malloc_ai(port, in->s_addr, hints);
if (cur == NULL) {
if (*res != NULL)
freeaddrinfo(*res);
return (EAI_MEMORY);
}
if (prev)
prev->ai_next = cur;
else
*res = cur;
prev = cur;
}
return (0);
}
return (EAI_NODATA);
}
#endif /* !HAVE_GETADDRINFO */

177
dropbear/fake-rfc2553.h Normal file
View File

@ -0,0 +1,177 @@
/* Taken for Dropbear from OpenSSH 5.5p1 */
/* $Id: fake-rfc2553.h,v 1.16 2008/07/14 11:37:37 djm Exp $ */
/*
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
* Copyright (C) 1999 WIDE Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Pseudo-implementation of RFC2553 name / address resolution functions
*
* But these functions are not implemented correctly. The minimum subset
* is implemented for ssh use only. For example, this routine assumes
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#ifndef _FAKE_RFC2553_H
#define _FAKE_RFC2553_H
#include "includes.h"
#include <sys/types.h>
#if defined(HAVE_NETDB_H)
# include <netdb.h>
#endif
/*
* First, socket and INET6 related definitions
*/
#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
# define _SS_MAXSIZE 128 /* Implementation specific max size */
# define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr))
struct sockaddr_storage {
struct sockaddr ss_sa;
char __ss_pad2[_SS_PADSIZE];
};
# define ss_family ss_sa.sa_family
#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
#ifndef IN6_IS_ADDR_LOOPBACK
# define IN6_IS_ADDR_LOOPBACK(a) \
(((u_int32_t *)(a))[0] == 0 && ((u_int32_t *)(a))[1] == 0 && \
((u_int32_t *)(a))[2] == 0 && ((u_int32_t *)(a))[3] == htonl(1))
#endif /* !IN6_IS_ADDR_LOOPBACK */
#ifndef HAVE_STRUCT_IN6_ADDR
struct in6_addr {
u_int8_t s6_addr[16];
};
#endif /* !HAVE_STRUCT_IN6_ADDR */
#ifndef HAVE_STRUCT_SOCKADDR_IN6
struct sockaddr_in6 {
unsigned short sin6_family;
u_int16_t sin6_port;
u_int32_t sin6_flowinfo;
struct in6_addr sin6_addr;
u_int32_t sin6_scope_id;
};
#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
#ifndef AF_INET6
/* Define it to something that should never appear */
#define AF_INET6 AF_MAX
#endif
/*
* Next, RFC2553 name / address resolution API
*/
#ifndef NI_NUMERICHOST
# define NI_NUMERICHOST (1)
#endif
#ifndef NI_NAMEREQD
# define NI_NAMEREQD (1<<1)
#endif
#ifndef NI_NUMERICSERV
# define NI_NUMERICSERV (1<<2)
#endif
#ifndef AI_PASSIVE
# define AI_PASSIVE (1)
#endif
#ifndef AI_CANONNAME
# define AI_CANONNAME (1<<1)
#endif
#ifndef AI_NUMERICHOST
# define AI_NUMERICHOST (1<<2)
#endif
#ifndef NI_MAXSERV
# define NI_MAXSERV 32
#endif /* !NI_MAXSERV */
#ifndef NI_MAXHOST
# define NI_MAXHOST 1025
#endif /* !NI_MAXHOST */
#ifndef EAI_NODATA
# define EAI_NODATA (INT_MAX - 1)
#endif
#ifndef EAI_MEMORY
# define EAI_MEMORY (INT_MAX - 2)
#endif
#ifndef EAI_NONAME
# define EAI_NONAME (INT_MAX - 3)
#endif
#ifndef EAI_SYSTEM
# define EAI_SYSTEM (INT_MAX - 4)
#endif
#ifndef EAI_FAMILY
# define EAI_FAMILY (INT_MAX - 5)
#endif
#ifndef HAVE_STRUCT_ADDRINFO
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for hostname */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
#endif /* !HAVE_STRUCT_ADDRINFO */
#ifndef HAVE_GETADDRINFO
#ifdef getaddrinfo
# undef getaddrinfo
#endif
#define getaddrinfo(a,b,c,d) (ssh_getaddrinfo(a,b,c,d))
int getaddrinfo(const char *, const char *,
const struct addrinfo *, struct addrinfo **);
#endif /* !HAVE_GETADDRINFO */
#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO)
#define gai_strerror(a) (_ssh_compat_gai_strerror(a))
char *gai_strerror(int);
#endif /* !HAVE_GAI_STRERROR */
#ifndef HAVE_FREEADDRINFO
#define freeaddrinfo(a) (ssh_freeaddrinfo(a))
void freeaddrinfo(struct addrinfo *);
#endif /* !HAVE_FREEADDRINFO */
#ifndef HAVE_GETNAMEINFO
#define getnameinfo(a,b,c,d,e,f,g) (ssh_getnameinfo(a,b,c,d,e,f,g))
int getnameinfo(const struct sockaddr *, size_t, char *, size_t,
char *, size_t, int);
#endif /* !HAVE_GETNAMEINFO */
#endif /* !_FAKE_RFC2553_H */

117
dropbear/filelist.txt Normal file
View File

@ -0,0 +1,117 @@
This file is out of date - it remains here in case it is still of use.
The basic naming convention is svr- and cli- for seperate parts,
then common- for common parts. Some files have no prefix.
A brief rundown on which files do what, and their corresponding sections
in the IETF drafts. The .c files usually have corresponding .h files.
Transport layer draft-ietf-secsh-transport-16.txt
===============
session.c Contains the main select() loop, and handles setting
up/closing down ssh connections
algo.c Framework for handling various ciphers/hashes/algos,
and choosing between the lists of client/server
preferred ones
kex.c Key exchange routines, used at startup to negotiate
which algorithms to use, and also to obtain session
keys. This also runs when rekeying during the
connection.
packet.c Handles the basic packet encryption/decryption,
and switching to the appropriate packet handlers.
Called from session.c's main select loop.
service.c Handles service requests (userauth or connection)
Authentication draft-ietf-secsh-userauth-17.txt
==============
auth.c General auth handling, including user checking etc,
passes different auth types to auth{passwd,pubkey}
authpasswd.c Handles /etc/passwd or /etc/shadow auth
authpubkey.c Handles ~/.ssh/authorized_keys auth
Connection draft-ietf-secsh-connect-17.txt
==========
channel.c Channel handling routines - each shell/tcp conn/agent
etc is a channel.
chansession.c Handles shell/exec requests
sshpty.c From OpenSSH, allocates PTYs etc
termcodes.c Mapping of POSIX terminal codes to SSH terminal codes
loginrec.c From OpenSSH, handles utmp/wtmp logging
x11fwd.c Handles X11 forwarding
agentfwd.c Handles auth-agent forwarding requests
localtcpfwd.c Handles -L style tcp forwarding requests, setting
up the listening port and also handling connections
to that port (and subsequent channels)
Program-related
===============
dbmulti.c Combination binary chooser main() function
dbutil.c Various utility functions, incl logging, memory etc
dropbearconvert.c Conversion from dropbear<->openssh keys, uses
keyimport.c to do most of the work
dropbearkey.c Generates keys, calling gen{dss,rsa}
keyimport.c Modified from PuTTY, converts between key types
main.c dropbear's main(), handles listening, forking for
new connections, child-process limits
runopts.c Parses commandline options
options.h Compile-time feature selection
config.h Features selected from configure
debug.h Compile-time selection of debug features
includes.h Included system headers etc
Generic Routines
================
signkey.c A generic handler for pubkeys, switches to dss or rsa
depending on the key type
rsa.c RSA asymmetric crypto routines
dss.c DSS asymmetric crypto routines
gendss.c DSS key generation
genrsa.c RSA key generation
bignum.c Some bignum helper functions
queue.c A queue, used to enqueue encrypted packets to send
random.c PRNG, based on /dev/urandom or prngd
atomicio.c From OpenSSH, does `blocking' IO on non-blocking fds
buffer.c Buffer-usage routines, with size checking etc
vim:set ts=8:

195
dropbear/gendss.c Normal file
View File

@ -0,0 +1,195 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
#include "signkey.h"
#include "bignum.h"
#include "dbrandom.h"
#include "buffer.h"
#include "gendss.h"
#include "dss.h"
#define QSIZE 20 /* 160 bit */
/* This is just a test */
#ifdef DROPBEAR_DSS
static void getq(dropbear_dss_key *key);
static void getp(dropbear_dss_key *key, unsigned int size);
static void getg(dropbear_dss_key *key);
static void getx(dropbear_dss_key *key);
static void gety(dropbear_dss_key *key);
dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
dropbear_dss_key *key;
if (size != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits");
}
key = m_malloc(sizeof(*key));
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
getq(key);
getp(key, size/8);
getg(key);
getx(key);
gety(key);
return key;
}
static void getq(dropbear_dss_key *key) {
char buf[QSIZE];
/* 160 bit prime */
genrandom(buf, QSIZE);
buf[0] |= 0x80; /* top bit high */
buf[QSIZE-1] |= 0x01; /* bottom bit high */
bytes_to_mp(key->q, buf, QSIZE);
/* 18 rounds are required according to HAC */
if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
}
static void getp(dropbear_dss_key *key, unsigned int size) {
DEF_MP_INT(tempX);
DEF_MP_INT(tempC);
DEF_MP_INT(tempP);
DEF_MP_INT(temp2q);
int result;
unsigned char *buf;
m_mp_init_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
/* 2*q */
if (mp_mul_d(key->q, 2, &temp2q) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
buf = (unsigned char*)m_malloc(size);
result = 0;
do {
genrandom(buf, size);
buf[0] |= 0x80; /* set the top bit high */
/* X is a random mp_int */
bytes_to_mp(&tempX, buf, size);
/* C = X mod 2q */
if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
/* P = X - (C - 1) = X - C + 1*/
if (mp_sub(&tempX, &tempC, &tempP) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
if (mp_add_d(&tempP, 1, key->p) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
/* now check for prime, 5 rounds is enough according to HAC */
/* result == 1 => p is prime */
if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
} while (!result);
mp_clear_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
m_burn(buf, size);
m_free(buf);
}
static void getg(dropbear_dss_key * key) {
DEF_MP_INT(div);
DEF_MP_INT(h);
DEF_MP_INT(val);
m_mp_init_multi(&div, &h, &val, NULL);
/* get div=(p-1)/q */
if (mp_sub_d(key->p, 1, &val) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
if (mp_div(&val, key->q, &div, NULL) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
/* initialise h=1 */
mp_set(&h, 1);
do {
/* now keep going with g=h^div mod p, until g > 1 */
if (mp_exptmod(&h, &div, key->p, key->g) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
if (mp_add_d(&h, 1, &h) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
} while (mp_cmp_d(key->g, 1) != MP_GT);
mp_clear_multi(&div, &h, &val, NULL);
}
static void getx(dropbear_dss_key *key) {
gen_random_mpint(key->q, key->x);
}
static void gety(dropbear_dss_key *key) {
if (mp_exptmod(key->g, key->x, key->p, key->y) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
}
#endif /* DROPBEAR_DSS */

36
dropbear/gendss.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _GENDSS_H_
#define _GENDSS_H_
#include "dss.h"
#ifdef DROPBEAR_DSS
dropbear_dss_key * gen_dss_priv_key(unsigned int size);
#endif /* DROPBEAR_DSS */
#endif /* _GENDSS_H_ */

135
dropbear/genrsa.c Normal file
View File

@ -0,0 +1,135 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
#include "bignum.h"
#include "dbrandom.h"
#include "rsa.h"
#include "genrsa.h"
#define RSA_E 65537
#ifdef DROPBEAR_RSA
static void getrsaprime(mp_int* prime, mp_int *primeminus,
mp_int* rsa_e, unsigned int size_bytes);
/* mostly taken from libtomcrypt's rsa key generation routine */
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
dropbear_rsa_key * key;
DEF_MP_INT(pminus);
DEF_MP_INT(qminus);
DEF_MP_INT(lcm);
if (size < 512 || size > 4096 || (size % 8 != 0)) {
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
" multiple of 8");
}
key = m_malloc(sizeof(*key));
m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
m_mp_init_multi(&pminus, &lcm, &qminus, NULL);
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
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 ((unsigned int)mp_count_bits(key->n) == size) {
break;
}
}
/* lcm(p-1, q-1) */
if (mp_lcm(&pminus, &qminus, &lcm) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
/* de = 1 mod lcm(p-1,q-1) */
/* therefore d = (e^-1) mod lcm(p-1,q-1) */
if (mp_invmod(key->e, &lcm, key->d) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
mp_clear_multi(&pminus, &qminus, &lcm, NULL);
return key;
}
/* return a prime suitable for p or q */
static void getrsaprime(mp_int* prime, mp_int *primeminus,
mp_int* rsa_e, unsigned int size_bytes) {
unsigned char *buf;
DEF_MP_INT(temp_gcd);
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);
buf[0] |= 0x80;
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) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
/* subtract one to get p-1 */
if (mp_sub_d(prime, 1, primeminus) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
/* check relative primality to e */
if (mp_gcd(primeminus, rsa_e, &temp_gcd) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
} while (mp_cmp_d(&temp_gcd, 1) != MP_EQ); /* while gcd(p-1, e) != 1 */
/* now we have a good value for result */
mp_clear(&temp_gcd);
m_burn(buf, size_bytes);
m_free(buf);
}
#endif /* DROPBEAR_RSA */

36
dropbear/genrsa.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _GENRSA_H_
#define _GENRSA_H_
#include "rsa.h"
#ifdef DROPBEAR_RSA
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size);
#endif /* DROPBEAR_RSA */
#endif /* _GENRSA_H_ */

132
dropbear/gensignkey.c Normal file
View File

@ -0,0 +1,132 @@
#include "includes.h"
#include "dbutil.h"
#include "buffer.h"
#include "ecdsa.h"
#include "genrsa.h"
#include "gendss.h"
#include "signkey.h"
#include "dbrandom.h"
#define RSA_DEFAULT_SIZE 2048
#define DSS_DEFAULT_SIZE 1024
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int buf_writefile(buffer * buf, const char * filename) {
int ret = DROPBEAR_FAILURE;
int fd = -1;
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
filename, strerror(errno));
goto out;
}
/* write the file now */
while (buf->pos != buf->len) {
int len = write(fd, buf_getptr(buf, buf->len - buf->pos),
buf->len - buf->pos);
if (len == -1 && errno == EINTR) {
continue;
}
if (len <= 0) {
dropbear_log(LOG_ERR, "Failed writing file %s: %s",
filename, strerror(errno));
goto out;
}
buf_incrpos(buf, len);
}
ret = DROPBEAR_SUCCESS;
out:
if (fd >= 0) {
m_close(fd);
}
return ret;
}
/* returns 0 on failure */
static int get_default_bits(enum signkey_type keytype)
{
switch (keytype) {
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
return RSA_DEFAULT_SIZE;
#endif
#ifdef DROPBEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
return DSS_DEFAULT_SIZE;
#endif
#ifdef DROPBEAR_ECDSA
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
return ECDSA_DEFAULT_SIZE;
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
return 521;
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
return 384;
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
return 256;
#endif
default:
return 0;
}
}
int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
{
sign_key * key = NULL;
buffer *buf = NULL;
int ret = DROPBEAR_FAILURE;
if (bits == 0)
{
bits = get_default_bits(keytype);
}
/* now we can generate the key */
key = new_sign_key();
seedrandom();
switch(keytype) {
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
key->rsakey = gen_rsa_priv_key(bits);
break;
#endif
#ifdef DROPBEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
key->dsskey = gen_dss_priv_key(bits);
break;
#endif
#ifdef DROPBEAR_ECDSA
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
{
ecc_key *ecckey = gen_ecdsa_priv_key(bits);
keytype = ecdsa_signkey_type(ecckey);
*signkey_key_ptr(key, keytype) = ecckey;
}
break;
#endif
default:
dropbear_exit("Internal error");
}
seedrandom();
buf = buf_new(MAX_PRIVKEY_SIZE);
buf_put_priv_key(buf, key, keytype);
sign_key_free(key);
key = NULL;
buf_setpos(buf, 0);
ret = buf_writefile(buf, filename);
buf_burn(buf);
buf_free(buf);
buf = NULL;
return ret;
}

8
dropbear/gensignkey.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _GENSIGNKEY_H
#define _GENSIGNKEY_H
#include "signkey.h"
int signkey_generate(enum signkey_type type, int bits, const char* filename);
#endif

180
dropbear/includes.h Normal file
View File

@ -0,0 +1,180 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _INCLUDES_H_
#define _INCLUDES_H_
#include "config.h"
#include "options.h"
#include "debug.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h> /* required for BSD4_4 define */
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <syslog.h>
#include <netdb.h>
#include <ctype.h>
#include <stdarg.h>
#include <dirent.h>
#include <time.h>
#ifdef HAVE_UTMP_H
#include <utmp.h>
#endif
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef HAVE_LASTLOG_H
#include <lastlog.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include <arpa/inet.h>
/* netbsd 1.6 needs this to be included before netinet/ip.h for some
* undocumented reason */
#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#include <netinet/ip.h>
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#ifndef DISABLE_ZLIB
#include <zlib.h>
#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
#ifdef HAVE_SHADOW_H
#include <shadow.h>
#endif
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
#endif
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#ifdef BUNDLED_LIBTOM
#include "libtomcrypt/src/headers/tomcrypt.h"
#include "libtommath/tommath.h"
#else
#include <tomcrypt.h>
#include <tommath.h>
#endif
#include "compat.h"
#ifndef HAVE_U_INT8_T
typedef unsigned char u_int8_t;
#endif /* HAVE_U_INT8_T */
#ifndef HAVE_UINT8_T
typedef u_int8_t uint8_t;
#endif /* HAVE_UINT8_T */
#ifndef HAVE_U_INT16_T
typedef unsigned short u_int16_t;
#endif /* HAVE_U_INT16_T */
#ifndef HAVE_UINT16_T
typedef u_int16_t uint16_t;
#endif /* HAVE_UINT16_T */
#ifndef HAVE_U_INT32_T
typedef unsigned int u_int32_t;
#endif /* HAVE_U_INT32_T */
#ifndef HAVE_UINT32_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
#define LOG_AUTHPRIV LOG_AUTH
#endif
/* so we can avoid warnings about unused params (ie in signal handlers etc) */
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*@unused@*/ x
#else
# define UNUSED(x) x
#endif
#endif /* _INCLUDES_H_ */

251
dropbear/install-sh Normal file
View File

@ -0,0 +1,251 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
chmodcmd=""
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

Some files were not shown because too many files have changed in this diff Show More