Compare commits

..

9 Commits

Author SHA1 Message Date
Matt Johnston
cafebe2d30 Reduce sk specific code
The application id can be stored in signkey, then we don't need
to call sk-specific functions from svr-authpubkey
2022-01-22 15:45:07 +08:00
Matt Johnston
cc481a646d Make sk-ecdsa call buf_ecdsa_verify
This reduces code duplication, the SK code just handles the
different message format.
2022-01-22 14:50:42 +08:00
Egor Duda
2634c4586b fix typo 2022-01-17 20:41:56 +03:00
Egor Duda
712d529164 Keys with type sk-* make no sense as host keys, so they should be
disabled
2022-01-17 18:33:24 +03:00
Egor Duda
2ad020ff30 Implement server-side support for sk-ed25519 FIDO2-backed keys 2022-01-16 00:50:39 +03:00
Egor Duda
0c62c0db7f Check if nistp256 curve is used in sk-ecdsa-sha2- key
It's the only allowed curve per PROTOCOL.u2f specification
2021-12-24 14:26:09 +03:00
Egor Duda
2993eedaba Fix one more potential out-of-bounds read 2021-12-24 12:26:31 +03:00
Egor Duda
c66f0e98c9 Fix out-of-bounds read on normal ecdsa-sha2-[identifier] keys 2021-12-24 12:10:36 +03:00
Egor Duda
c8fcc08fe0 Implement server-side support for sk-ecdsa U2F-backed keys 2021-12-23 09:23:34 +03:00
103 changed files with 5473 additions and 7384 deletions

View File

@@ -1,9 +0,0 @@
#!/bin/sh
# symlink this to dropbear/dbclient/dropbearkey next to dropbearmulti
# good enough for testing purposes.
DIR=$(dirname $0)
PROG=$(basename $0)
exec $DIR/dropbearmulti $PROG "$@"

View File

@@ -1,25 +0,0 @@
# Checks that autoconf has been run if configure.ac was updated
# Assumes that autoconf 2.69 was run, the same as ubuntu 20.04
name: Autoconf Up To Date
on:
pull_request:
push:
branches:
- master
jobs:
autoconf:
runs-on: 'ubuntu-22.04'
steps:
- name: deps
run: |
sudo apt-get -y update
sudo apt-get -y install autoconf
- uses: actions/checkout@v2
- name: run autoconf
run: autoconf && autoheader
- name: check no difference
run: git diff --exit-code

View File

@@ -1,5 +1,4 @@
# Can be used locally with https://github.com/nektos/act
# Note the XXX line below.
name: BuildTest
on:
@@ -9,12 +8,9 @@ on:
- master
jobs:
build:
runs-on: ${{ matrix.os || 'ubuntu-22.04' }}
runs-on: ${{ matrix.os || 'ubuntu-20.04' }}
strategy:
matrix:
# XXX uncomment the line below to work with act, see https://github.com/nektos/act/issues/996
# name: []
# Rather than a boolean False we use eg
# runcheck: 'no'
# Otherwise GH expressions will make a None var
@@ -26,19 +22,6 @@ jobs:
- name: multi binary
multi: 1
multilink: 1
- name: multi binary, dropbearmulti argv0
multi: 1
multiwrapper: 1
- name: client only
runcheck: 'no'
make_target: PROGRAMS=dbclient
- name: server only
runcheck: 'no'
make_target: PROGRAMS=dropbear
- name: bundled libtom, bionic , no writev()
# test can use an older distro with bundled libtommath
@@ -52,18 +35,11 @@ jobs:
- name: linux clang
cc: clang
# Some platforms only have old compilers, we try to keep
# compatibilty. For some reason -std=c89 doesn't enforce
# early declarations so we specify it anyway.
- name: c89
extracflags: -std=c89 -Wdeclaration-after-statement
- name: macos 12
os: macos-12
- name: macos 10.15
os: macos-10.15
cc: clang
# OS X says daemon() and utmp are deprecated.
# OS X tests for undefined TARGET_OS_EMBEDDED in libc headers
extracflags: -Wno-deprecated-declarations -Wno-undef
# OS X says daemon() and utmp are deprecated
extracflags: -Wno-deprecated-declarations
runcheck: 'no'
apt: 'no'
# fails with:
@@ -73,65 +49,17 @@ jobs:
- name: macos 11
os: macos-11
cc: clang
extracflags: -Wno-deprecated-declarations -Wno-undef
extracflags: -Wno-deprecated-declarations
runcheck: 'no'
apt: 'no'
ranlib: ranlib -no_warning_for_no_symbols
# Check that debug code doesn't bitrot
- name: DEBUG_TRACE
localoptions: |
#define DEBUG_TRACE 5
# Check off-by-default options don't bitrot
- name: nondefault options
nondefault: 1
configure_flags: --enable-pam
- name: most options disabled
configure_flags: --disable-harden --disable-zlib --disable-openpty --disable-lastlog
runcheck: 'no'
localoptions: |
#define DROPBEAR_RSA 0
#define INETD_MODE 0
#define DROPBEAR_REEXEC 0
#define DROPBEAR_SMALL_CODE 0
#define DROPBEAR_CLI_LOCALTCPFWD 0
#define DROPBEAR_CLI_REMOTETCPFWD 0
#define DROPBEAR_SVR_LOCALTCPFWD 0
#define DROPBEAR_SVR_REMOTETCPFWD 0
#define DROPBEAR_SVR_AGENTFWD 0
#define DROPBEAR_CLI_AGENTFWD 0
#define DROPBEAR_CLI_PROXYCMD 0
#define DROPBEAR_USER_ALGO_LIST 0
#define DROPBEAR_AES128 0
#define DROPBEAR_AES256 0
#define DROPBEAR_ENABLE_CTR_MODE 0
#define DROPBEAR_SHA1_HMAC 0
#define DROPBEAR_SHA2_256_HMAC 0
#define DROPBEAR_RSA 0
#define DROPBEAR_ECDSA 0
#define DROPBEAR_SK_KEYS 0
#define DROPBEAR_DELAY_HOSTKEY 0
#define DROPBEAR_DH_GROUP14_SHA1 0
#define DROPBEAR_DH_GROUP14_SHA256 0
#define DROPBEAR_ECDH 0
#define DROPBEAR_DH_GROUP1_CLIENTONLY 0
#define DO_MOTD 0
#define DROPBEAR_SVR_PUBKEY_AUTH 0
#define DROPBEAR_CLI_PASSWORD_AUTH 0
#define DROPBEAR_CLI_PUBKEY_AUTH 0
#define DROPBEAR_USE_PASSWORD_ENV 0
#define DROPBEAR_SFTPSERVER 0
# # Fuzzers run standalone. A bit superfluous with cifuzz, but
# # good to run the whole corpus to keep it working.
# - name: fuzzing with address sanitizer
# configure_flags: --enable-fuzz --disable-harden --enable-bundled-libtom --enable-werror
# ldflags: -fsanitize=address
# extracflags: -fsanitize=address
# # -fsanitize=address prevents aslr, don't test it
# pytest_addopts: -k "not aslr"
# fuzz: True
# cc: clang
@@ -141,7 +69,6 @@ jobs:
# ldflags: -fsanitize=undefined
# # don't fail with alignment due to https://github.com/libtom/libtomcrypt/issues/549
# extracflags: -fsanitize=undefined -fno-sanitize-recover=undefined -fsanitize-recover=alignment
# pytest_addopts: -k "not aslr"
# fuzz: True
# cc: clang
@@ -151,22 +78,16 @@ jobs:
LDFLAGS: ${{ matrix.ldflags }}
EXTRACFLAGS: ${{ matrix.extracflags }}
CONFIGURE_FLAGS: ${{ matrix.configure_flags || '--enable-werror' }}
MAKE_TARGET: ${{ matrix.make_target }}
# for fuzzing
CXX: clang++
RANLIB: ${{ matrix.ranlib || 'ranlib' }}
# pytest in "make check" recognises this for extra arguments
PYTEST_ADDOPTS: ${{ matrix.pytest_addopts }}
# some pytests depend on special setup from this file. see authorized_keys below.
DBTEST_IN_ACTION: true
LOCALOPTIONS: ${{ matrix.localoptions }}
steps:
- name: deps
if: ${{ matrix.apt != 'no' }}
run: |
sudo apt-get -y update
sudo apt-get -y install zlib1g-dev libtomcrypt-dev libtommath-dev mercurial python3-venv libpam0g-dev $CC
sudo apt-get -y install zlib1g-dev libtomcrypt-dev libtommath-dev mercurial python3-venv $CC
- uses: actions/checkout@v2
@@ -177,37 +98,13 @@ jobs:
if: ${{ matrix.nowritev }}
run: sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h
- name: localoptions
run: |
echo "$LOCALOPTIONS" > localoptions.h
echo "#define DROPBEAR_DSS 1" >> localoptions.h
cat localoptions.h
- name: nondefault
if: ${{ matrix.nondefault }}
run: |
# Turn on anything that's off by default. Rough but seems sufficient
grep ' 0$' default_options.h | sed 's/0$/1/' > localoptions.h
# PAM clashes with password
echo "#define DROPBEAR_SVR_PASSWORD_AUTH 0" >> localoptions.h
# 1 second timeout is too short
sed -i "s/DEFAULT_IDLE_TIMEOUT 1/DEFAULT_IDLE_TIMEOUT 99/" localoptions.h
- name: make
run: make -j3 $MAKE_TARGET
run: make -j3
- name: multilink
if: ${{ matrix.multilink }}
if: ${{ matrix.multi }}
run: make multilink
- name: multi wrapper script
if: ${{ matrix.multiwrapper }}
run: |
cp .github/multiwrapper dropbear
cp .github/multiwrapper dbclient
cp .github/multiwrapper dropbearkey
cp .github/multiwrapper dropbearconvert
- name: makefuzz
run: make fuzzstandalone
if: ${{ matrix.fuzz }}
@@ -217,17 +114,9 @@ jobs:
run: make install
- name: keys
if: ${{ matrix.runcheck != 'no' }}
run: |
mkdir -p ~/.ssh
# remove old files so we can rerun in-place with "act -r" during test development
rm -vf ~/.ssh/id_dropbear*
~/inst/bin/dropbearkey -t ecdsa -f ~/.ssh/id_dropbear | grep ^ecdsa > ~/.ssh/authorized_keys
# to test setting SSH_PUBKEYINFO, replace the trailing comment
~/inst/bin/dropbearkey -t ecdsa -f ~/.ssh/id_dropbear_key2 | grep ^ecdsa | sed 's/[^ ]*$/key2 extra/' >> ~/.ssh/authorized_keys
~/inst/bin/dropbearkey -t ecdsa -f ~/.ssh/id_dropbear_key3 | grep ^ecdsa | sed 's/[^ ]*$/key3%char/' >> ~/.ssh/authorized_keys
~/inst/bin/dropbearkey -t ecdsa -f ~/.ssh/id_dropbear_key4 | grep ^ecdsa | sed 's/[^ ]*$/key4,char/' >> ~/.ssh/authorized_keys
chmod 700 ~ ~/.ssh ~/.ssh/authorized_keys
ls -ld ~ ~/.ssh ~/.ssh/authorized_keys
@@ -245,22 +134,16 @@ jobs:
# Sanity check that the binary runs
- name: genrsa
if: ${{ matrix.runcheck != 'no' }}
run: ~/inst/bin/dropbearkey -t rsa -f testrsa
- name: gendss
if: ${{ matrix.runcheck != 'no' }}
run: ~/inst/bin/dropbearkey -t dss -f testdss
- name: genecdsa256
if: ${{ matrix.runcheck != 'no' }}
run: ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
- name: genecdsa384
if: ${{ matrix.runcheck != 'no' }}
run: ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
- name: genecdsa521
if: ${{ matrix.runcheck != 'no' }}
run: ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
- name: gened25519
if: ${{ matrix.runcheck != 'no' }}
run: ~/inst/bin/dropbearkey -t ed25519 -f tested25519
- name: fuzz

View File

@@ -1,36 +0,0 @@
name: tarball sha256sum
on:
push:
branches:
- master
jobs:
tarball:
runs-on: 'ubuntu-22.04'
steps:
- uses: actions/checkout@v2
- name: release.sh
run: ./release.sh --testrel | tee log1.txt
- name: extract output
run: |
grep ^SHA256 log1.txt > sha256sum.txt
sed 's/.*= *//' < sha256sum.txt > hash.txt
mv `tail -n1 log1.txt` rel.tar.bz2
- name: sha256sum
uses: actions/upload-artifact@v3
with:
name: sha256sum
path: |
sha256sum.txt
hash.txt
- name: tarball
uses: actions/upload-artifact@v3
with:
name: tarball
# only keep for debugging
retention-days: 3
path: rel.tar.bz2

3
.gitignore vendored
View File

@@ -19,10 +19,9 @@
/fuzzer-*.options
/scp
/scp-progress
Makefile
config.h
default_options_guard.h
localoptions.h
Makefile
tags
.pytest*
*.pyc

240
CHANGES
View File

@@ -1,243 +1,3 @@
2022.83 - 14 November 2022
Features and Changes:
Note >> for compatibility/configuration changes
- >> Disable DROPBEAR_DSS by default
It is only 1024 bit and uses sha1, most distros disable it by default already.
- Added DROPBEAR_RSA_SHA1 option to allow disabling sha1 rsa signatures.
>> RSA with sha1 will be disabled in a future release (rsa keys will continue
to work OK, with sha256 signatures used instead).
- Add option for requiring both password and pubkey (-t)
Patch from Jackkal
- Add 'no-touch-required' and 'verify-required' options for sk keys
Patch from Egor Duda
- >> DROPBEAR_SK_KEYS config option now replaces separate DROPBEAR_SK_ECDSA
and DROPBEAR_SK_ED25519 options.
- Add 'permitopen' option for authorized_keys to restrict forwarded ports
Patch from Tuomas Haikarainen
- >> Added LTM_CFLAGS configure argument to set flags for building
bundled libtommath. This also restores the previous arguments used
in 2020.81 (-O3 -funroll-loops). That gives a big speedup for RSA
key generation, which regressed in 2022.82.
There is a tradeoff with code size, so -Os can be used if required.
https://github.com/mkj/dropbear/issues/174
Reported by David Bernard
- Add '-z' flag to disable setting QoS traffic class. This may be necessary
to work with broken networks or network drivers, exposed after changes to use
AF21 in 2022.82
https://github.com/mkj/dropbear/issues/193
Reported by yuhongwei380, patch from Petr Štetiar
- Allow overriding user shells with COMPAT_USER_SHELLS
Based on a patch from Matt Robinson
- Improve permission error message
Patch from k-kurematsu
- >> Remove HMAC_MD5 entirely
Regression fixes from 2022.82:
- Fix X11 build
- Fix build warning
- Fix compilation when disabling pubkey authentication
Patch from MaxMougg
- Fix MAX_UNAUTH_CLIENTS regression
Reported by ptpt52
- Avoid using slower prime testing in bundled libtomcrypt when DSS is disabled
https://github.com/mkj/dropbear/issues/174
Suggested by Steffen Jaeckel
- Fix Dropbear plugin support
https://github.com/mkj/dropbear/issues/194
Reported by Struan Bartlett
Other fixes:
- Fix long standing incorrect compression size check. Dropbear
(client or server) would erroneously exit with
"bad packet, oversized decompressed"
when receiving a compressed packet of exactly the maximum size.
- Fix missing setsid() removed in 2020.79
https://github.com/mkj/dropbear/issues/180
Reported and debugged by m5jt and David Bernard
- Try keyboard-interactive auth before password, in dbclient.
This was unintentionally changed back in 2013
https://github.com/mkj/dropbear/pull/190
Patch from Michele Giacomoli
- Drain the terminal when reading the fingerprint confirmation response
https://github.com/mkj/dropbear/pull/191
Patch from Michele Giacomoli
- Fix utx wtmp variable typo. This has been wrong for a long time but
only recently became a problem when wtmp was detected.
https://github.com/mkj/dropbear/pull/189
Patch from Michele Giacomoli
- Improve configure test for hardening options.
Fixes building on AIX
https://github.com/mkj/dropbear/issues/158
- Fix debian/dropbear.init newline
From wulei-student
Infrastructure:
- Test off-by-default compile options
- Set -Wundef to catch typos in #if statements
2022.82 - 1 April 2022
Features and Changes:
Note >> for compatibility/configuration changes
- Implemented OpenSSH format private key handling for dropbearconvert.
Keys can be read in OpenSSH format or the old PEM format.
>> Keys are now written in OpenSSH format rather than PEM.
ED25519 support is now correct. DSS keys are still PEM format.
- Use SHA256 for key fingerprints
- >> Reworked -v verbose printing, specifying multiple times will increase
verbosity. -vvvv is equivalent to the old DEBUG_TRACE -v level, it
can be configured at compile time in localoptions.h (see default_options.h)
Lower -v options can be used to check connection progress or algorithm
negotiation.
Thanks to Hans Harder for the implementation
localoptions.h DEBUG_TRACE should be set to 4 for the same result as the
previous DEBUG_TRACE 1.
- Added server support for U2F/FIDO keys (ecdsa-sk and ed25519-sk) in
authorized_keys. no-touch-required option isn't allowed yet.
Thanks to Egor Duda for the implementation
- autoconf output (configure script etc) is now committed to version control.
>> It isn't necessary to run "autoconf" any more on a checkout.
- sha1 will be omitted from the build if KEX/signing/MAC algorithms don't
require it. Instead sha256 is used for random number generation.
See sysoptions.h to see which algorithms require which hashes.
- Set SSH_PUBKEYINFO environment variable based on the authorized_keys
entry used for auth. The first word of the comment after the key is used
(must only have characters a-z A-Z 0-9 .,_-+@)
Patch from Hans Harder, modified by Matt Johnston
- Let dbclient multihop mode be used with '-J'.
Patch from Hans Harder
- Allow home-directory relative paths ~/path for various settings
and command line options.
*_PRIV_FILENAME DROPBEAR_PIDFILE SFTPSERVER_PATH MOTD_FILENAME
Thanks to Begley Brothers Inc
>> The default DROPBEAR_DEFAULT_CLI_AUTHKEY has now changed, it now needs
a tilde prefix.
- LANG environment variable is carried over from the Dropbear server process
From Maxim Kochetkov
- Add /usr/sbin and /sbin to $PATH when logging in as root.
Patch from Raphaël Hertzog
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=903403
- Added client option "-o DisableTrivialAuth". It disallows a server immediately
giving successful authentication (without presenting any password/pubkey prompt).
This avoids a UI confusion issue where it may appear that the user is accepting
a SSH agent prompt from their local machine, but are actually accepting a prompt
sent immediately by the remote server.
CVE-2021-36369 though the description there is a bit confused. It only applies
to Dropbear as a client.
Thanks to Manfred Kaiser from Austrian MilCERT
- Add -q client option to hide remote banner, from Hans Harder
- Add -e option to pass all server environment variables to child processes.
This should be used with caution.
Patch from Roland Vollgraf (github #118)
- >> Use DSCP for QoS traffic classes. Priority (tty) traffic is now set to
AF21 "interactive". Previously TOS classes were used, they are not used by
modern traffic classifiers. Non-tty traffic is left at default priority.
- >> Disable dh-group1 key exchange by default. It has been disabled server
side by default since 2018.
- >> Removed Twofish cipher
Fixes:
- Fix flushing channel data when pty was allocated (github #85)
Data wasn't completely transmitted at channel close.
Reported and initial patch thanks to Yousong Zhou
- Dropbear now re-executes itself rather than just forking for each connection
(only on Linux). This allows ASLR to randomise address space for each
connection as a security mitigation. It should not have any visible impact
- if there are any performance impacts in the wild please report it.
- Check authorized_keys permissions as the user, fixes NFS squash root.
Patch from Chris Dragan (github #107)
- A missing home directory is now non-fatal, starting in / instead
- Fixed IPv6 [address]:port parsing for dbclient -b
Reported by Fabio Molinari
- Improve error logging so that they are logged on the server rather than being
sent to the client over the connection
- Max window size is increased to 10MB, more graceful fallback if it's invalid.
- Fix correctness of Dropbear's handling of global requests.
Patch from Dirkjan Bussink
- Fix some small bugs found by fuzzers, null pointer dereference crash and leaks
(post authentication)
- $HOME variable is used before /etc/passwd when expanding paths such as
~/.ssh/id_dropbear (for the client). Patch from Matt Robinson
- C89 build fixes from Guillaume Picquet
Infrastructure:
- Improvements to fuzzers. Added post-auth fuzzer, and a mutator that can
handle the structure of SSH packet streams. Added cifuzz to run on commits
and pull requests.
Thanks to OSS-Fuzz for the tools/clusters and reward funding.
- Dropbear source tarballs generated by release.sh are now reproducible from a
Git or Mercurial checkout, they will be identical on any system. Tested
on ubuntu and macos.
- Added some integration testing using pytest. Currently this has tests
for various channel handling edge cases, ASLR fork randomisation,
dropbearconvert, and SSH_PUBKEYINFO
- Set up github actions. This runs the pytest suite and other checks.
- build matrix includes c89, dropbearmulti, bundled libtom, macos, DEBUG_TRACE
- test for configure script regeneration
- build a tarball for external reproducibility
2020.81 - 29 October 2020
- Fix regression in 2020.79 which prevented connecting with some SSH

View File

@@ -58,7 +58,7 @@ 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 algorithms, by editing localoptions.h
you should remove unneeded ciphers and MD5, by editing localoptions.h
It is possible to compile zlib in, by copying zlib.h and zconf.h into a
subdirectory (ie zlibincludes), and

View File

@@ -20,13 +20,13 @@ LIBTOM_LIBS=@LIBTOM_LIBS@
ifeq (@BUNDLED_LIBTOM@, 1)
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
LIBTOM_CLEAN=ltc-clean ltm-clean
CPPFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
endif
OPTION_HEADERS = default_options_guard.h sysoptions.h
ifneq ($(wildcard localoptions.h),)
CPPFLAGS+=-DLOCALOPTIONS_H_EXISTS
CFLAGS+=-DLOCALOPTIONS_H_EXISTS
OPTION_HEADERS += localoptions.h
endif
@@ -57,7 +57,7 @@ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
KEYOBJS=dropbearkey.o
CONVERTOBJS=dropbearconvert.o keyimport.o signkey_ossh.o
CONVERTOBJS=dropbearconvert.o keyimport.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
@@ -107,8 +107,8 @@ AR=@AR@
RANLIB=@RANLIB@
STRIP=@STRIP@
INSTALL=@INSTALL@
CPPFLAGS+=@CPPFLAGS@ -I. -I$(srcdir)
CFLAGS+=@CFLAGS@
CPPFLAGS=@CPPFLAGS@
CFLAGS+=-I. -I$(srcdir) $(CPPFLAGS) @CFLAGS@
LIBS+=@LIBS@
LDFLAGS=@LDFLAGS@
@@ -119,16 +119,15 @@ STATIC=@STATIC@
# whether we're building client, server, or both for the common objects.
# evilness so we detect 'dropbear' by itself as a word
ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z))))
CPPFLAGS+= -DDROPBEAR_SERVER
CFLAGS+= -DDROPBEAR_SERVER
endif
ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdbclientZ, Z$(prog)Z))))
CPPFLAGS+= -DDROPBEAR_CLIENT
CFLAGS+= -DDROPBEAR_CLIENT
endif
# these are exported so that libtomcrypt's makefile will use them
export CC
export CFLAGS
export CPPFLAGS
export RANLIB AR STRIP
ifeq ($(STATIC), 1)
@@ -143,7 +142,7 @@ endif
# for the scp progress meter. The -D doesn't affect anything else.
ifeq ($(SCPPROGRESS), 1)
CPPFLAGS+=-DPROGRESS_METER
CFLAGS+=-DPROGRESS_METER
endif
all: $(TARGETS)
@@ -217,7 +216,7 @@ scp: $(SCPOBJS) $(HEADERS) Makefile
MULTIOBJS=
ifeq ($(MULTI),1)
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
CPPFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
endif
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile

2
README
View File

@@ -8,8 +8,6 @@ which performs multiple tasks, to save disk space)
SMALL has some tips on creating small binaries.
A mirror of the Dropbear website and tarballs is available at https://dropbear.nl/mirror/
Please contact me if you have any questions/bugs found/features/ideas/comments etc :)
There is also a mailing list http://lists.ucc.gu.uwa.edu.au/mailman/listinfo/dropbear

11
SMALL
View File

@@ -9,7 +9,10 @@ The same applies if you are compiling just a client.
---
The following are set in localoptions.h:
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
@@ -47,10 +50,4 @@ deciding.
Of course using small C libraries such as uClibc and dietlibc can also help.
---
Libtommath has its own default CFLAGS to improve speed. You can use
./configure LTM_CFLAGS=-Os
to reduce size at the expense of speed.
If you have any queries, mail me and I'll see if I can help.

19
auth.h
View File

@@ -28,7 +28,6 @@
#include "includes.h"
#include "signkey.h"
#include "chansession.h"
#include "list.h"
void svr_authinitialise(void);
@@ -46,7 +45,6 @@ int svr_pubkey_allows_agentfwd(void);
int svr_pubkey_allows_tcpfwd(void);
int svr_pubkey_allows_x11fwd(void);
int svr_pubkey_allows_pty(void);
int svr_pubkey_allows_local_tcpfwd(const char *host, unsigned int port);
void svr_pubkey_set_forced_command(struct ChanSess *chansess);
void svr_pubkey_options_cleanup(void);
int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filename);
@@ -56,9 +54,6 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
#define svr_pubkey_allows_tcpfwd() 1
#define svr_pubkey_allows_x11fwd() 1
#define svr_pubkey_allows_pty() 1
static inline int svr_pubkey_allows_local_tcpfwd(const char *host, unsigned int port)
{ (void)host; (void)port; return 1; }
static inline void svr_pubkey_set_forced_command(struct ChanSess *chansess) { }
static inline void svr_pubkey_options_cleanup(void) { }
#define svr_add_pubkey_options(x,y,z) DROPBEAR_SUCCESS
@@ -98,7 +93,6 @@ void cli_auth_pubkey_cleanup(void);
#define AUTH_METHOD_INTERACT "keyboard-interactive"
#define AUTH_METHOD_INTERACT_LEN 20
#define PUBKEY_OPTIONS_ANY_PORT UINT_MAX
/* This structure is shared between server and client - it contains
@@ -131,7 +125,6 @@ struct AuthState {
char *pw_passwd;
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
struct PubKeyOptions* pubkey_options;
char *pubkey_info;
#endif
};
@@ -145,18 +138,6 @@ struct PubKeyOptions {
int no_pty_flag;
/* "command=" option. */
char * forced_command;
/* "permitopen=" option */
m_list *permit_open_destinations;
#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
int no_touch_required_flag;
int verify_required_flag;
#endif
};
struct PermitTCPFwdEntry {
char *host;
unsigned int port;
};
#endif

View File

@@ -93,12 +93,12 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
/* hash the ssh representation of the mp_int mp */
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
hash_state *hs, const mp_int *mp) {
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_burn_free(buf);
buf_free(buf);
}

View File

@@ -33,6 +33,6 @@ void m_mp_alloc_init_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
void m_mp_free_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, const mp_int *mp);
hash_state *hs, mp_int *mp);
#endif /* DROPBEAR_BIGNUM_H_ */

View File

@@ -55,13 +55,11 @@ void buf_free(buffer* buf) {
m_free(buf);
}
/* overwrite the contents of the buffer then free it */
void buf_burn_free(buffer* buf) {
/* overwrite the contents of the buffer to clear it */
void buf_burn(const buffer* buf) {
m_burn(buf->data, buf->size);
m_free(buf);
}
/* resize a buffer, pos and len will be repositioned if required when
* downsizing */
buffer* buf_resize(buffer *buf, unsigned int newsize) {
@@ -299,7 +297,7 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
/* for our purposes we only need positive (or 0) numbers, so will
* fail if we get negative numbers */
void buf_putmpint(buffer* buf, const mp_int * mp) {
void buf_putmpint(buffer* buf, mp_int * mp) {
size_t written;
unsigned int len, pad = 0;
TRACE2(("enter buf_putmpint"))

View File

@@ -44,7 +44,7 @@ buffer * buf_new(unsigned int size);
/* Possibly returns a new buffer*, like realloc() */
buffer * buf_resize(buffer *buf, unsigned int newsize);
void buf_free(buffer* buf);
void buf_burn_free(buffer* buf);
void buf_burn(const buffer* buf);
buffer* buf_newcopy(const buffer* buf);
void buf_setlen(buffer* buf, unsigned int len);
void buf_incrlen(buffer* buf, unsigned int incr);
@@ -65,7 +65,7 @@ void buf_putint(buffer* buf, unsigned int val);
void buf_putstring(buffer* buf, const 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, const mp_int * mp);
void buf_putmpint(buffer* buf, mp_int * mp);
int buf_getmpint(buffer* buf, mp_int* mp);
unsigned int buf_getint(buffer* buf);

View File

@@ -28,7 +28,6 @@
#include "includes.h"
#include "buffer.h"
#include "circbuffer.h"
#include "netio.h"
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
#define SSH_OPEN_CONNECT_FAILED 2
@@ -42,6 +41,13 @@
struct ChanType;
enum dropbear_channel_prio {
DROPBEAR_CHANNEL_PRIO_INTERACTIVE, /* pty shell, x11 */
DROPBEAR_CHANNEL_PRIO_UNKNOWABLE, /* tcp - can't know what's being forwarded */
DROPBEAR_CHANNEL_PRIO_BULK, /* the rest - probably scp or something */
DROPBEAR_CHANNEL_PRIO_EARLY, /* channel is still being set up */
};
struct Channel {
unsigned int index; /* the local channel index */
@@ -82,7 +88,7 @@ struct Channel {
const struct ChanType* type;
enum dropbear_prio prio;
enum dropbear_channel_prio prio;
};
struct ChanType {

View File

@@ -82,11 +82,6 @@ void recv_msg_userauth_banner() {
return;
}
if (cli_opts.quiet) {
TRACE(("not showing banner"))
return;
}
banner = buf_getstring(ses.payload, &bannerlen);
buf_eatstring(ses.payload); /* The language string */
@@ -265,7 +260,7 @@ void recv_msg_userauth_success() {
/* This function can validly get called multiple times
if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
DEBUG1(("received msg_userauth_success"))
TRACE(("received msg_userauth_success"))
if (cli_opts.disable_trivial_auth && cli_ses.is_trivial_auth) {
dropbear_exit("trivial authentication not allowed");
}
@@ -296,6 +291,18 @@ int cli_auth_try() {
}
#endif
#if DROPBEAR_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
#if DROPBEAR_CLI_INTERACT_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
@@ -310,18 +317,6 @@ int cli_auth_try() {
}
#endif
#if DROPBEAR_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
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
if (finished) {

View File

@@ -114,8 +114,8 @@ void recv_msg_userauth_info_request() {
m_free(instruction);
for (i = 0; i < num_prompts; i++) {
unsigned int response_len = 0;
cli_ses.is_trivial_auth = 0;
unsigned int response_len = 0;
prompt = buf_getstring(ses.payload, NULL);
cleantext(prompt);

View File

@@ -120,7 +120,7 @@ void cli_auth_password() {
char* password = NULL;
char prompt[80];
DEBUG1(("enter cli_auth_password"))
TRACE(("enter cli_auth_password"))
CHECKCLEARTOWRITE();
snprintf(prompt, sizeof(prompt), "%s@%s's password: ",

View File

@@ -147,7 +147,7 @@ static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype,
buffer* sigbuf = NULL;
enum signkey_type keytype = signkey_type_from_signature(sigtype);
DEBUG1(("enter send_msg_userauth_pubkey %s", signature_name_from_type(sigtype, NULL)))
TRACE(("enter send_msg_userauth_pubkey sigtype %d", sigtype))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);

View File

@@ -348,6 +348,7 @@ static int cli_init_stdpipe_sess(struct Channel *channel) {
}
static int cli_init_netcat(struct Channel *channel) {
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
return cli_init_stdpipe_sess(channel);
}
@@ -360,9 +361,12 @@ static int cli_initchansess(struct Channel *channel) {
cli_setup_agent(channel);
}
#endif
if (cli_opts.wantpty) {
send_chansess_pty_req(channel);
channel->prio = DROPBEAR_PRIO_LOWDELAY;
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
} else {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
send_chansess_shell_req(channel);
@@ -371,7 +375,7 @@ static int cli_initchansess(struct Channel *channel) {
cli_tty_setup();
channel->read_mangler = cli_escape_handler;
cli_ses.last_char = '\r';
}
}
return 0; /* Success */
}

View File

@@ -229,8 +229,6 @@ static void ask_to_confirm(const unsigned char* keyblob, unsigned int keybloblen
fclose(tty);
} else {
response = getc(stdin);
/* flush stdin buffer */
while ((getchar()) != '\n');
}
if (response == 'y') {
@@ -373,7 +371,7 @@ static void checkhostkey(const unsigned char* keyblob, unsigned int keybloblen)
if (ret == DROPBEAR_SUCCESS) {
/* Good matching key */
DEBUG1(("server match %s", fingerprint))
TRACE(("good matching key"))
goto out;
}

View File

@@ -65,12 +65,8 @@ int main(int argc, char ** argv) {
}
#endif
if (cli_opts.bind_address) {
DEBUG1(("connect to: user=%s host=%s/%s bind_address=%s:%s", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport, cli_opts.bind_address, cli_opts.bind_port))
} else {
DEBUG1(("connect to: user=%s host=%s/%s",cli_opts.username,cli_opts.remotehost,cli_opts.remoteport))
}
TRACE(("user='%s' host='%s' port='%s' bind_address='%s' bind_port='%s'", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport, cli_opts.bind_address, cli_opts.bind_port))
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
dropbear_exit("signal() error");
@@ -88,9 +84,8 @@ int main(int argc, char ** argv) {
} else
#endif
{
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
cli_connected, &ses, cli_opts.bind_address, cli_opts.bind_port,
DROPBEAR_PRIO_LOWDELAY);
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
cli_connected, &ses, cli_opts.bind_address, cli_opts.bind_port);
sock_in = sock_out = -1;
}
@@ -139,7 +134,6 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out) {
ret = spawn_command(exec_proxy_cmd, ex_cmd,
sock_out, sock_in, NULL, pid_out);
DEBUG1(("cmd: %s pid=%d", ex_cmd,*pid_out))
m_free(ex_cmd);
if (ret == DROPBEAR_FAILURE) {
dropbear_exit("Failed running proxy command");

View File

@@ -62,7 +62,6 @@ static void printhelp() {
"-T Don't allocate a pty\n"
"-N Don't run a remote command\n"
"-f Run in background after auth\n"
"-q quiet, don't show remote banner\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"
@@ -83,7 +82,6 @@ static void printhelp() {
"-W <receive_window_buffer> (default %d, larger may be faster, max 10MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
"-I <idle_timeout> (0 is never, default %d)\n"
"-z disable QoS\n"
#if DROPBEAR_CLI_NETCAT
"-B <endhost:endport> Netcat-alike forwarding\n"
#endif
@@ -97,7 +95,7 @@ static void printhelp() {
"-b [bind_address][:bind_port]\n"
"-V Version\n"
#if DEBUG_TRACE
"-v verbose (repeat for more verbose)\n"
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
,DROPBEAR_VERSION, cli_opts.progname,
#if DROPBEAR_CLI_PUBKEY_AUTH
@@ -143,7 +141,6 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.username = NULL;
cli_opts.cmd = NULL;
cli_opts.no_cmd = 0;
cli_opts.quiet = 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;
@@ -217,9 +214,6 @@ void cli_getopts(int argc, char ** argv) {
}
cli_opts.always_accept_key = 1;
break;
case 'q': /* quiet */
cli_opts.quiet = 1;
break;
case 'p': /* remoteport */
next = (char**)&cli_opts.remoteport;
break;
@@ -303,7 +297,7 @@ void cli_getopts(int argc, char ** argv) {
#endif
#if DEBUG_TRACE
case 'v':
debug_trace++;
debug_trace = 1;
break;
#endif
case 'F':
@@ -326,9 +320,6 @@ void cli_getopts(int argc, char ** argv) {
case 'b':
next = &bind_arg;
break;
case 'z':
opts.disable_ip_tos = 1;
break;
default:
fprintf(stderr,
"WARNING: Ignoring unknown option -%c\n", c);
@@ -423,7 +414,7 @@ void cli_getopts(int argc, char ** argv) {
/* And now a few sanity checks and setup */
#if DROPBEAR_CLI_PROXYCMD
#if DROPBEAR_CLI_PROXYCMD
if (cli_opts.proxycmd) {
/* To match the common path of m_freeing it */
cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
@@ -435,10 +426,14 @@ void cli_getopts(int argc, char ** argv) {
}
if (bind_arg) {
if (split_address_port(bind_arg,
&cli_opts.bind_address, &cli_opts.bind_port)
== DROPBEAR_FAILURE) {
dropbear_exit("Bad -b argument");
/* split [host][:port] */
char *port = strrchr(bind_arg, ':');
if (port) {
cli_opts.bind_port = m_strdup(port+1);
*port = '\0';
}
if (strlen(bind_arg) > 0) {
cli_opts.bind_address = m_strdup(bind_arg);
}
}
@@ -482,17 +477,6 @@ void cli_getopts(int argc, char ** argv) {
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
#if DROPBEAR_CLI_MULTIHOP
parse_multihop_hostname(host_arg, argv[0]);
#else
parse_hostname(host_arg);
#endif
/* We don't want to include default id_dropbear as a
-i argument for multihop, so handle it later. */
#if (DROPBEAR_CLI_PUBKEY_AUTH)
{
char *expand_path = expand_homedir_path(DROPBEAR_DEFAULT_CLI_AUTHKEY);
@@ -501,6 +485,14 @@ void cli_getopts(int argc, char ** argv) {
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
#if DROPBEAR_CLI_MULTIHOP
parse_multihop_hostname(host_arg, argv[0]);
#else
parse_hostname(host_arg);
#endif
}
#if DROPBEAR_CLI_PUBKEY_AUTH
@@ -531,11 +523,11 @@ static void loadidentityfile(const char* filename, int warnfail) {
static char*
multihop_passthrough_args() {
char *ret;
unsigned int len, total;
int total;
unsigned int len = 0;
m_list_elem *iter;
/* Fill out -i, -y, -W options that make sense for all
* the intermediate processes */
len = 30; /* space for "-q -y -y -W <size>\0" */
#if DROPBEAR_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
@@ -543,40 +535,45 @@ multihop_passthrough_args() {
len += 3 + strlen(key->filename);
}
#endif /* DROPBEAR_CLI_PUBKEY_AUTH */
if (cli_opts.proxycmd) {
/* "-J 'cmd'" */
len += 6 + strlen(cli_opts.proxycmd);
}
len += 30; /* space for -W <size>, terminator. */
ret = m_malloc(len);
total = 0;
if (cli_opts.quiet) {
total += m_snprintf(ret+total, len-total, "-q ");
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 (cli_opts.no_hostkey_check) {
total += m_snprintf(ret+total, len-total, "-y -y ");
} else if (cli_opts.always_accept_key) {
total += m_snprintf(ret+total, len-total, "-y ");
}
if (cli_opts.proxycmd) {
total += m_snprintf(ret+total, len-total, "-J '%s' ", cli_opts.proxycmd);
}
if (opts.recv_window != DEFAULT_RECV_WINDOW) {
total += m_snprintf(ret+total, len-total, "-W %u ", opts.recv_window);
if (opts.recv_window != DEFAULT_RECV_WINDOW)
{
int written = snprintf(ret+total, len-total, "-W %u ", opts.recv_window);
total += written;
}
#if DROPBEAR_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
total += m_snprintf(ret+total, len-total, "-i %s ", key->filename);
const size_t size = len - total;
int written = snprintf(ret+total, size, "-i %s ", key->filename);
dropbear_assert((unsigned int)written < size);
total += written;
}
#endif /* DROPBEAR_CLI_PUBKEY_AUTH */
/* 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;
}
@@ -590,9 +587,6 @@ multihop_passthrough_args() {
* dbclient -J "dbclient -B madako:22 wrt" madako
* etc for as many hosts as we want.
*
* Note that "-J" arguments aren't actually used, instead
* below sets cli_opts.proxycmd directly.
*
* Ports for hosts can be specified as host/port.
*/
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
@@ -611,7 +605,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
&& strchr(cli_opts.username, '@')) {
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
hostbuf = m_malloc(len);
m_snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
} else {
hostbuf = m_strdup(orighostarg);
}
@@ -634,18 +628,19 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
/* 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)
cmd_len = strlen(argv0) + strlen(remainder)
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
+ strlen(passthrough_args)
+ 30;
/* replace proxycmd. old -J arguments have been copied
to passthrough_args */
cli_opts.proxycmd = m_realloc(cli_opts.proxycmd, cmd_len);
m_snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport,
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. */

View File

@@ -102,9 +102,6 @@ void cli_connected(int result, int sock, void* userdata, const char *errstring)
dropbear_exit("Connect failed: %s", errstring);
}
myses->sock_in = myses->sock_out = sock;
DEBUG1(("cli_connected"))
ses.socket_prio = DROPBEAR_PRIO_NORMAL;
/* switches to lowdelay */
update_channel_prio();
}

View File

@@ -51,7 +51,7 @@ static int cli_localtcp(const char* listenaddr,
unsigned int remoteport);
static const struct ChanType cli_chan_tcplocal = {
"direct-tcpip",
NULL,
tcp_prio_inithandler,
NULL,
NULL,
NULL,
@@ -272,9 +272,10 @@ static int newtcpforwarded(struct Channel * channel) {
goto out;
}
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
snprintf(portstring, sizeof(portstring), "%u", fwd->connectport);
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done,
channel, NULL, NULL, DROPBEAR_PRIO_NORMAL);
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel, NULL, NULL);
err = SSH_OPEN_IN_PROGRESS;

View File

@@ -64,6 +64,14 @@ static const struct dropbear_cipher dropbear_aes256 =
static const struct dropbear_cipher dropbear_aes128 =
{&aes_desc, 16, 16};
#endif
#if DROPBEAR_TWOFISH256
static const struct dropbear_cipher dropbear_twofish256 =
{&twofish_desc, 32, 16};
#endif
#if DROPBEAR_TWOFISH128
static const struct dropbear_cipher dropbear_twofish128 =
{&twofish_desc, 16, 16};
#endif
#if DROPBEAR_3DES
static const struct dropbear_cipher dropbear_3des =
{&des3_desc, 24, 8};
@@ -114,6 +122,10 @@ static const struct dropbear_hash dropbear_sha2_256 =
static const struct dropbear_hash dropbear_sha2_512 =
{&sha512_desc, 64, 64};
#endif
#if 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 */
@@ -144,6 +156,15 @@ algo_type sshciphers[] = {
#if DROPBEAR_AES256
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
#endif
#if DROPBEAR_TWOFISH_CTR
/* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
#if DROPBEAR_TWOFISH256
{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
#endif
#if DROPBEAR_TWOFISH128
{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
#endif
#endif /* DROPBEAR_TWOFISH_CTR */
#endif /* DROPBEAR_ENABLE_CTR_MODE */
#if DROPBEAR_ENABLE_CBC_MODE
@@ -153,6 +174,13 @@ algo_type sshciphers[] = {
#if DROPBEAR_AES256
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
#endif
#if DROPBEAR_TWOFISH256
{"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
{"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
#endif
#if DROPBEAR_TWOFISH128
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
#endif
#endif /* DROPBEAR_ENABLE_CBC_MODE */
#if DROPBEAR_3DES
@@ -181,6 +209,9 @@ algo_type sshhashes[] = {
#endif
#if DROPBEAR_SHA2_512_HMAC
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
#endif
#if DROPBEAR_MD5_HMAC
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
#endif
{NULL, 0, NULL, 0, NULL}
};
@@ -334,7 +365,7 @@ void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall
len = buf->pos - startpos - 4;
buf_setpos(buf, startpos);
buf_putint(buf, len);
TRACE(("algolist add %d '%.*s'", len, len, buf_getptr(buf, len)))
TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
buf_incrwritepos(buf, len);
}
@@ -438,7 +469,7 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
DEBUG3(("buf_match_algo: %s", algolist))
TRACE(("buf_match_algo: %s", algolist))
remotecount = MAX_PROPOSED_ALGO;
get_algolist(algolist, len, remotenames, &remotecount);

View File

@@ -162,7 +162,7 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->recvdonelen = 0;
newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN;
newchan->prio = DROPBEAR_PRIO_NORMAL;
newchan->prio = DROPBEAR_CHANNEL_PRIO_EARLY; /* inithandler sets it */
ses.channels[i] = newchan;
ses.chancount++;
@@ -955,7 +955,9 @@ void recv_msg_channel_open() {
}
}
update_channel_prio();
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
/* success */
send_msg_channel_open_confirmation(channel, channel->recvwindow,
@@ -968,6 +970,8 @@ failure:
cleanup:
m_free(type);
update_channel_prio();
TRACE(("leave recv_msg_channel_open"))
}
@@ -1162,8 +1166,11 @@ void recv_msg_channel_open_confirmation() {
}
}
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
update_channel_prio();
TRACE(("leave recv_msg_channel_open_confirmation"))
}

View File

@@ -249,7 +249,7 @@ static void kexinitialise() {
/* 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(hash_size, outlen) bytes allocated.
* 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,
@@ -306,7 +306,8 @@ static void gen_new_keys() {
mp_clear(ses.dh_K);
m_free(ses.dh_K);
hash_desc->process(&hs, ses.hash->data, ses.hash->len);
buf_burn_free(ses.hash);
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
if (IS_DROPBEAR_CLIENT) {
@@ -802,7 +803,8 @@ void finish_kexhashbuf(void) {
}
#endif
buf_burn_free(ses.kexhashbuf);
buf_burn(ses.kexhashbuf);
buf_free(ses.kexhashbuf);
m_burn(&hs, sizeof(hash_state));
ses.kexhashbuf = NULL;
@@ -867,7 +869,7 @@ static void read_kex_algos() {
goto error;
}
TRACE(("kexguess2 %d", kexguess2))
DEBUG3(("kex algo %s", algo->name))
TRACE(("kex algo %s", algo->name))
ses.newkeys->algo_kex = algo->data;
/* server_host_key_algorithms */
@@ -877,7 +879,7 @@ static void read_kex_algos() {
erralgo = "hostkey";
goto error;
}
DEBUG2(("hostkey algo %s", algo->name))
TRACE(("signature algo %s", algo->name))
ses.newkeys->algo_signature = algo->val;
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
@@ -887,7 +889,7 @@ static void read_kex_algos() {
erralgo = "enc c->s";
goto error;
}
DEBUG2(("enc c2s is %s", c2s_cipher_algo->name))
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
@@ -895,7 +897,7 @@ static void read_kex_algos() {
erralgo = "enc s->c";
goto error;
}
DEBUG2(("enc s2c is %s", s2c_cipher_algo->name))
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
@@ -908,7 +910,7 @@ static void read_kex_algos() {
erralgo = "mac c->s";
goto error;
}
DEBUG2(("hmac c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
/* mac_algorithms_server_to_client */
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
@@ -921,7 +923,7 @@ static void read_kex_algos() {
erralgo = "mac s->c";
goto error;
}
DEBUG2(("hmac s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
/* compression_algorithms_client_to_server */
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
@@ -929,7 +931,7 @@ static void read_kex_algos() {
erralgo = "comp c->s";
goto error;
}
DEBUG2(("comp c2s is %s", c2s_comp_algo->name))
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, 0, NULL);
@@ -937,7 +939,7 @@ static void read_kex_algos() {
erralgo = "comp s->c";
goto error;
}
DEBUG2(("comp s2c is %s", s2c_comp_algo->name))
TRACE(("hash s2c is %s", s2c_comp_algo->name))
/* languages_client_to_server */
buf_eatstring(ses.payload);

View File

@@ -1,19 +1,19 @@
/*
* 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
@@ -35,7 +35,7 @@ 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,
int readhostkey(const char * filename, sign_key * hostkey,
enum signkey_type *type) {
int ret = DROPBEAR_FAILURE;
@@ -57,7 +57,8 @@ int readhostkey(const char * filename, sign_key * hostkey,
ret = DROPBEAR_SUCCESS;
out:
buf_burn_free(buf);
buf_burn(buf);
buf_free(buf);
return ret;
}
@@ -117,57 +118,3 @@ void parse_recv_window(const char* recv_window_arg) {
}
/* Splits addr:port. Handles IPv6 [2001:0011::4]:port style format.
Returns first/second parts as malloced strings, second will
be NULL if no separator is found.
:port -> (NULL, "port")
port -> (port, NULL)
addr:port (addr, port)
addr: -> (addr, "")
Returns DROPBEAR_SUCCESS/DROPBEAR_FAILURE */
int split_address_port(const char* spec, char **first, char ** second) {
char *spec_copy = NULL, *addr = NULL, *colon = NULL;
int ret = DROPBEAR_FAILURE;
*first = NULL;
*second = NULL;
spec_copy = m_strdup(spec);
addr = spec_copy;
if (*addr == '[') {
addr++;
colon = strchr(addr, ']');
if (!colon) {
dropbear_log(LOG_WARNING, "Bad address '%s'", spec);
goto out;
}
*colon = '\0';
colon++;
if (*colon == '\0') {
/* No port part */
colon = NULL;
} else if (*colon != ':') {
dropbear_log(LOG_WARNING, "Bad address '%s'", spec);
goto out;
}
} else {
/* search for ':', that separates address and port */
colon = strrchr(addr, ':');
}
/* colon points to ':' now, or is NULL */
if (colon) {
/* Split the address/port */
*colon = '\0';
colon++;
*second = m_strdup(colon);
}
if (strlen(addr)) {
*first = m_strdup(addr);
}
ret = DROPBEAR_SUCCESS;
out:
m_free(spec_copy);
return ret;
}

View File

@@ -64,7 +64,7 @@ void common_session_init(int sock_in, int sock_out) {
setnonblocking(sock_out);
}
ses.socket_prio = DROPBEAR_PRIO_NORMAL;
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
/* Sets it to lowdelay */
update_channel_prio();
@@ -285,7 +285,8 @@ static void cleanup_buf(buffer **buf) {
if (!*buf) {
return;
}
buf_burn_free(*buf);
buf_burn(*buf);
buf_free(*buf);
*buf = NULL;
}
@@ -403,7 +404,7 @@ static void read_session_identification() {
dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
}
DEBUG1(("remoteident: %s", ses.remoteident))
TRACE(("remoteident: %s", ses.remoteident))
}
@@ -519,24 +520,15 @@ static void send_msg_keepalive() {
ses.last_packet_time_idle = old_time_idle;
}
/* Returns the difference in seconds, clamped to LONG_MAX */
static long elapsed(time_t now, time_t prev) {
time_t del = now - prev;
if (del > LONG_MAX) {
return LONG_MAX;
}
return (long)del;
}
/* 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();
if (IS_DROPBEAR_SERVER && ses.connect_time != 0
&& elapsed(now, ses.connect_time) >= AUTH_TIMEOUT) {
&& now - ses.connect_time >= AUTH_TIMEOUT) {
dropbear_close("Timeout before auth");
}
@@ -546,47 +538,45 @@ static void checktimeouts() {
}
if (!ses.kexstate.sentkexinit
&& (elapsed(now, ses.kexstate.lastkextime) >= KEX_REKEY_TIMEOUT
&& (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 (elapsed(now, ses.last_packet_time_any_sent) >= opts.keepalive_secs) {
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 (elapsed(now, ses.last_packet_time_keepalive_recv) >= opts.keepalive_secs
&& elapsed(now, ses.last_packet_time_keepalive_sent) >= opts.keepalive_secs) {
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 (elapsed(now, ses.last_packet_time_keepalive_recv)
if (now - ses.last_packet_time_keepalive_recv
>= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
dropbear_exit("Keepalive timeout");
}
}
if (opts.idle_timeout_secs > 0
&& elapsed(now, ses.last_packet_time_idle) >= opts.idle_timeout_secs) {
if (opts.idle_timeout_secs > 0
&& now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
dropbear_close("Idle timeout");
}
}
static void update_timeout(long limit, time_t now, time_t last_event, long * timeout) {
TRACE2(("update_timeout limit %ld, now %llu, last %llu, timeout %ld",
limit,
(unsigned long long)now,
(unsigned long long)last_event, *timeout))
static void update_timeout(long limit, long now, long last_event, long * timeout) {
TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
limit, now, last_event, *timeout))
if (last_event > 0 && limit > 0) {
*timeout = MIN(*timeout, elapsed(now, last_event) + limit);
*timeout = MIN(*timeout, last_event+limit-now);
TRACE2(("new timeout %ld", *timeout))
}
}
@@ -595,7 +585,7 @@ static long select_timeout() {
/* determine the minimum timeout that might be required, so
as to avoid waking when unneccessary */
long timeout = KEX_REKEY_TIMEOUT;
time_t now = monotonic_now();
long now = monotonic_now();
if (!ses.kexstate.sentkexinit) {
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
@@ -607,7 +597,7 @@ static long select_timeout() {
}
if (ses.authstate.authdone) {
update_timeout(opts.keepalive_secs, now,
update_timeout(opts.keepalive_secs, now,
MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
&timeout);
}
@@ -677,16 +667,26 @@ void update_channel_prio() {
return;
}
new_prio = DROPBEAR_PRIO_NORMAL;
new_prio = DROPBEAR_PRIO_BULK;
for (i = 0; i < ses.chansize; i++) {
struct Channel *channel = ses.channels[i];
if (!channel) {
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_PRIO_LOWDELAY) {
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;
}
}

View File

@@ -231,7 +231,8 @@ void setusershell() {
}
static char **initshells() {
static const char *okshells[] = { COMPAT_USER_SHELLS, NULL };
/* don't touch this list. */
static const char *okshells[] = { "/bin/sh", "/bin/csh", NULL };
register char **sp, *cp;
register FILE *fp;
struct stat statb;

1270
config.guess vendored

File diff suppressed because it is too large Load Diff

View File

@@ -93,9 +93,6 @@
/* Define to 1 if you have the `explicit_bzero' function. */
#undef HAVE_EXPLICIT_BZERO
/* Define to 1 if you have the `fexecve' function. */
#undef HAVE_FEXECVE
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
@@ -180,6 +177,9 @@
/* 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_s' function. */
#undef HAVE_MEMSET_S
@@ -234,9 +234,6 @@
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
@@ -321,9 +318,6 @@
/* 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/prctl.h> header file. */
#undef HAVE_SYS_PRCTL_H
/* Define to 1 if you have the <sys/random.h> header file. */
#undef HAVE_SYS_RANDOM_H
@@ -417,14 +411,17 @@
/* Define to the type of arg 5 for `select'. */
#undef SELECT_TYPE_ARG5
/* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* 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
@@ -443,7 +440,7 @@
/* Define to `int' if <sys/types.h> does not define. */
#undef mode_t
/* Define as a signed integer type capable of holding a process identifier. */
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to `unsigned int' if <sys/types.h> does not define. */

113
config.sub vendored
View File

@@ -1,14 +1,12 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright 1992-2022 Free Software Foundation, Inc.
# Copyright 1992-2021 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale
timestamp='2022-09-17'
timestamp='2021-03-10'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -52,14 +50,7 @@ timestamp='2022-09-17'
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.
# The "shellcheck disable" line above the timestamp inhibits complaints
# about features and limitations of the classic Bourne shell that were
# superseded or lifted in POSIX. However, this script identifies a wide
# variety of pre-POSIX systems that do not have POSIX shells at all, and
# even some reasonably current systems (Solaris 10 as case-in-point) still
# have a pre-POSIX /bin/sh.
me=`echo "$0" | sed -e 's,.*/,,'`
me=$(echo "$0" | sed -e 's,.*/,,')
usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
@@ -76,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright 1992-2022 Free Software Foundation, Inc.
Copyright 1992-2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -121,11 +112,9 @@ esac
# Split fields of configuration type
# shellcheck disable=SC2162
saved_IFS=$IFS
IFS="-" read field1 field2 field3 field4 <<EOF
$1
EOF
IFS=$saved_IFS
# Separate into logical components for further validation
case $1 in
@@ -145,7 +134,7 @@ case $1 in
nto-qnx* | linux-* | uclinux-uclibc* \
| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
| storm-chaos* | os2-emx* | rtmk-nova* | managarm-*)
| storm-chaos* | os2-emx* | rtmk-nova*)
basic_machine=$field1
basic_os=$maybe_os
;;
@@ -174,10 +163,6 @@ case $1 in
basic_machine=$field1
basic_os=$field2
;;
zephyr*)
basic_machine=$field1-unknown
basic_os=$field2
;;
# Manufacturers
dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
@@ -784,22 +769,22 @@ case $basic_machine in
vendor=hp
;;
i*86v32)
cpu=`echo "$1" | sed -e 's/86.*/86/'`
cpu=$(echo "$1" | sed -e 's/86.*/86/')
vendor=pc
basic_os=sysv32
;;
i*86v4*)
cpu=`echo "$1" | sed -e 's/86.*/86/'`
cpu=$(echo "$1" | sed -e 's/86.*/86/')
vendor=pc
basic_os=sysv4
;;
i*86v)
cpu=`echo "$1" | sed -e 's/86.*/86/'`
cpu=$(echo "$1" | sed -e 's/86.*/86/')
vendor=pc
basic_os=sysv
;;
i*86sol2)
cpu=`echo "$1" | sed -e 's/86.*/86/'`
cpu=$(echo "$1" | sed -e 's/86.*/86/')
vendor=pc
basic_os=solaris2
;;
@@ -932,16 +917,14 @@ case $basic_machine in
;;
leon-*|leon[3-9]-*)
cpu=sparc
vendor=`echo "$basic_machine" | sed 's/-.*//'`
vendor=$(echo "$basic_machine" | sed 's/-.*//')
;;
*-*)
# shellcheck disable=SC2162
saved_IFS=$IFS
IFS="-" read cpu vendor <<EOF
$basic_machine
EOF
IFS=$saved_IFS
;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
@@ -1020,11 +1003,6 @@ case $cpu-$vendor in
;;
# Here we normalize CPU types with a missing or matching vendor
armh-unknown | armh-alt)
cpu=armv7l
vendor=alt
basic_os=${basic_os:-linux-gnueabihf}
;;
dpx20-unknown | dpx20-bull)
cpu=rs6000
vendor=bull
@@ -1106,7 +1084,7 @@ case $cpu-$vendor in
cpu=mipsisa64sb1el
;;
sh5e[lb]-*)
cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
cpu=$(echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/')
;;
spur-*)
cpu=spur
@@ -1124,9 +1102,9 @@ case $cpu-$vendor in
cpu=x86_64
;;
xscale-* | xscalee[bl]-*)
cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
cpu=$(echo "$cpu" | sed 's/^xscale/arm/')
;;
arm64-* | aarch64le-*)
arm64-*)
cpu=aarch64
;;
@@ -1187,7 +1165,7 @@ case $cpu-$vendor in
| alphapca5[67] | alpha64pca5[67] \
| am33_2.0 \
| amdgcn \
| arc | arceb | arc32 | arc64 \
| arc | arceb \
| arm | arm[lb]e | arme[lb] | armv* \
| avr | avr32 \
| asmjs \
@@ -1207,7 +1185,7 @@ case $cpu-$vendor in
| k1om \
| le32 | le64 \
| lm32 \
| loongarch32 | loongarch64 \
| loongarch32 | loongarch64 | loongarchx32 \
| m32c | m32r | m32rle \
| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
@@ -1226,13 +1204,9 @@ case $cpu-$vendor in
| mips64vr5900 | mips64vr5900el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa32r3 | mipsisa32r3el \
| mipsisa32r5 | mipsisa32r5el \
| mipsisa32r6 | mipsisa32r6el \
| mipsisa64 | mipsisa64el \
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64r3 | mipsisa64r3el \
| mipsisa64r5 | mipsisa64r5el \
| mipsisa64r6 | mipsisa64r6el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
@@ -1309,41 +1283,35 @@ esac
if test x$basic_os != x
then
# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
# set os.
case $basic_os in
gnu/linux*)
kernel=linux
os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|')
;;
os2-emx)
kernel=os2
os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'`
os=$(echo $basic_os | sed -e 's|os2-emx|emx|')
;;
nto-qnx*)
kernel=nto
os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|')
;;
*-*)
# shellcheck disable=SC2162
saved_IFS=$IFS
IFS="-" read kernel os <<EOF
$basic_os
EOF
IFS=$saved_IFS
;;
# Default OS when just kernel was specified
nto*)
kernel=nto
os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
os=$(echo $basic_os | sed -e 's|nto|qnx|')
;;
linux*)
kernel=linux
os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
;;
managarm*)
kernel=managarm
os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
os=$(echo $basic_os | sed -e 's|linux|gnu|')
;;
*)
kernel=
@@ -1364,7 +1332,7 @@ case $os in
os=cnk
;;
solaris1 | solaris1.*)
os=`echo "$os" | sed -e 's|solaris1|sunos4|'`
os=$(echo $os | sed -e 's|solaris1|sunos4|')
;;
solaris)
os=solaris2
@@ -1393,7 +1361,7 @@ case $os in
os=sco3.2v4
;;
sco3.2.[4-9]*)
os=`echo "$os" | sed -e 's/sco3.2./sco3.2v/'`
os=$(echo $os | sed -e 's/sco3.2./sco3.2v/')
;;
sco*v* | scout)
# Don't match below
@@ -1423,7 +1391,7 @@ case $os in
os=lynxos
;;
mac[0-9]*)
os=`echo "$os" | sed -e 's|mac|macos|'`
os=$(echo "$os" | sed -e 's|mac|macos|')
;;
opened*)
os=openedition
@@ -1432,10 +1400,10 @@ case $os in
os=os400
;;
sunos5*)
os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
os=$(echo "$os" | sed -e 's|sunos5|solaris2|')
;;
sunos6*)
os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
os=$(echo "$os" | sed -e 's|sunos6|solaris3|')
;;
wince*)
os=wince
@@ -1469,7 +1437,7 @@ case $os in
;;
# Preserve the version number of sinix5.
sinix5.*)
os=`echo "$os" | sed -e 's|sinix|sysv|'`
os=$(echo $os | sed -e 's|sinix|sysv|')
;;
sinix*)
os=sysv4
@@ -1716,7 +1684,7 @@ fi
# Now, validate our (potentially fixed-up) OS.
case $os in
# Sometimes we do "kernel-libc", so those need to count as OSes.
musl* | newlib* | relibc* | uclibc*)
musl* | newlib* | uclibc*)
;;
# Likewise for "kernel-abi"
eabi* | gnueabi*)
@@ -1739,7 +1707,7 @@ case $os in
| nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
| clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
| mirbsd* | netbsd* | dicos* | openedition* | ose* \
| bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
| bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \
| ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
| bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
| ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
@@ -1757,8 +1725,7 @@ case $os in
| skyos* | haiku* | rdos* | toppers* | drops* | es* \
| onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
| midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
| nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
| fiwix* | mlibc* )
| nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@@ -1766,9 +1733,6 @@ case $os in
;;
none)
;;
kernel* )
# Restricted further below
;;
*)
echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
exit 1
@@ -1778,27 +1742,16 @@ esac
# As a final step for OS-related things, validate the OS-kernel combination
# (given a valid OS), if there is a kernel.
case $kernel-$os in
linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
| linux-musl* | linux-relibc* | linux-uclibc* | linux-mlibc* )
linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
;;
uclinux-uclibc* )
;;
managarm-mlibc* | managarm-kernel* )
;;
-dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* | -mlibc* )
-dietlibc* | -newlib* | -musl* | -uclibc* )
# These are just libc implementations, not actual OSes, and thus
# require a kernel.
echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
exit 1
;;
-kernel* )
echo "Invalid configuration \`$1': \`$os' needs explicit kernel." 1>&2
exit 1
;;
*-kernel* )
echo "Invalid configuration \`$1': \`$kernel' does not support \`$os'." 1>&2
exit 1
;;
kfreebsd*-gnu* | kopensolaris*-gnu*)
;;
vxworks-simlinux | vxworks-simwindows | vxworks-spe)

7230
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -23,15 +23,15 @@ AC_PROG_CC
if test -z "$LD" ; then
LD=$CC
fi
AC_SUBST(LD)
AC_SUBST(LD)
AC_DEFUN(DB_TRYADDCFLAGS,
AC_DEFUN(DB_TRYADDCFLAGS,
[{
OLDFLAGS="$CFLAGS"
TESTFLAGS="$1"
CFLAGS="$TESTFLAGS $CFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
CFLAGS="$CFLAGS $TESTFLAGS"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); CFLAGS="$OLDFLAGS" ]
)
}])
@@ -42,25 +42,12 @@ if test -z "$ORIGCFLAGS" && test "$GCC" = "yes"; then
CFLAGS="-Os -W -Wall"
fi
# LTM_CFLAGS is given to ./configure by the user,
# DROPBEAR_LTM_CFLAGS is substituted in the LTM Makefile.in
DROPBEAR_LTM_CFLAGS="$LTM_CFLAGS"
if test -z "$DROPBEAR_LTM_CFLAGS"; then
DROPBEAR_LTM_CFLAGS="-O3 -funroll-loops -fomit-frame-pointer"
fi
AC_MSG_NOTICE(Setting LTM_CFLAGS to $DROPBEAR_LTM_CFLAGS)
AC_ARG_VAR(LTM_CFLAGS, CFLAGS for bundled libtommath. Default -O3 -funroll-loops -fomit-frame-pointer)
AC_SUBST(DROPBEAR_LTM_CFLAGS)
AC_MSG_NOTICE([Checking if compiler '$CC' supports -Wno-pointer-sign])
DB_TRYADDCFLAGS([-Wno-pointer-sign])
AC_MSG_NOTICE([Checking if compiler '$CC' supports -fno-strict-overflow])
DB_TRYADDCFLAGS([-fno-strict-overflow])
AC_MSG_NOTICE([Checking if compiler '$CC' supports -Wundef])
DB_TRYADDCFLAGS([-Wundef])
# needed for various extensions. define early before autoconf tests
AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions if glibc])
@@ -94,15 +81,15 @@ if test "$hardenbuild" -eq 1; then
OLDLDFLAGS="$LDFLAGS"
TESTFLAGS="-Wl,-pie"
LDFLAGS="$TESTFLAGS $LDFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
LDFLAGS="$LDFLAGS $TESTFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[
LDFLAGS="$OLDLDFLAGS"
TESTFLAGS="-pie"
LDFLAGS="$TESTFLAGS $LDFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
LDFLAGS="$LDFLAGS $TESTFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
)
]
@@ -110,24 +97,24 @@ if test "$hardenbuild" -eq 1; then
# readonly elf relocation sections (relro)
OLDLDFLAGS="$LDFLAGS"
TESTFLAGS="-Wl,-z,now -Wl,-z,relro"
LDFLAGS="$TESTFLAGS $LDFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
LDFLAGS="$LDFLAGS $TESTFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
)
fi # non-static
# stack protector. -strong is good but only in gcc 4.9 or later
OLDCFLAGS="$CFLAGS"
TESTFLAGS="-fstack-protector-strong"
CFLAGS="$TESTFLAGS $CFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
CFLAGS="$CFLAGS $TESTFLAGS"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[
CFLAGS="$OLDCFLAGS"
TESTFLAGS="-fstack-protector --param=ssp-buffer-size=4"
CFLAGS="$TESTFLAGS $CFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
CFLAGS="$CFLAGS $TESTFLAGS"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_NOTICE([Setting $TESTFLAGS])],
[AC_MSG_NOTICE([Not setting $TESTFLAGS]); CFLAGS="$OLDCFLAGS" ]
)
]
@@ -187,7 +174,7 @@ case "$host" in
# OpenSSH thinks it's broken. If it isn't, let me know.
AC_DEFINE(BROKEN_GETADDRINFO,1,Broken getaddrinfo)
;;
*-*-hpux*)
LIBS="$LIBS -lsec"
# It's probably broken.
@@ -204,7 +191,7 @@ AC_CHECK_TOOL(STRIP, strip, :)
AC_CHECK_TOOL(INSTALL, install, :)
dnl Can't use login() or logout() with uclibc
AC_CHECK_DECL(__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.])
@@ -212,14 +199,14 @@ AC_CHECK_DECL(__UCLIBC__,
dnl We test for crypt() specially. On Linux (and others?) it resides in libcrypt
dnl but we don't want link all binaries to -lcrypt, just dropbear server.
dnl OS X doesn't need -lcrypt
dnl OS X doesn't need -lcrypt
AC_CHECK_FUNC(crypt, found_crypt_func=here)
AC_CHECK_LIB(crypt, crypt,
AC_CHECK_LIB(crypt, crypt,
[
CRYPTLIB="-lcrypt"
found_crypt_func=here
])
AC_SUBST(CRYPTLIB)
AC_SUBST(CRYPTLIB)
if test "t$found_crypt_func" = there; then
AC_DEFINE(HAVE_CRYPT, 1, [crypt() function])
fi
@@ -399,7 +386,7 @@ AC_CHECK_HEADERS([netinet/in.h netinet/tcp.h \
pty.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 linux/pkt_sched.h \
sys/random.h sys/prctl.h])
sys/random.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -581,7 +568,7 @@ AC_ARG_ENABLE(bundled-libtom,
)
if test $BUNDLED_LIBTOM = 1 ; then
AC_DEFINE(BUNDLED_LIBTOM,1,Use bundled libtom)
AC_DEFINE(BUNDLED_LIBTOM,1,Use bundled libtom)
fi
AC_SUBST(LIBTOM_LIBS)
@@ -654,7 +641,7 @@ AC_ARG_ENABLE(pututxline,
AC_ARG_WITH(lastlog,
[ --with-lastlog=FILE|DIR specify lastlog location [common locations]],
[
if test "x$withval" = "xno" ; then
if test "x$withval" = "xno" ; then
AC_DEFINE(DISABLE_LASTLOG)
else
conf_lastlog_location=$withval
@@ -729,7 +716,7 @@ fi
if test -n "$conf_lastlog_location"; then
AC_DEFINE_UNQUOTED(CONF_LASTLOG_FILE, "$conf_lastlog_location", lastlog file location)
fi
fi
dnl utmp detection
AC_MSG_CHECKING([if your system defines UTMP_FILE])
@@ -759,7 +746,7 @@ if test -z "$conf_utmp_location"; then
fi
if test -n "$conf_utmp_location"; then
AC_DEFINE_UNQUOTED(CONF_UTMP_FILE, "$conf_utmp_location", utmp file location)
fi
fi
dnl wtmp detection
AC_MSG_CHECKING([if your system defines WTMP_FILE])
@@ -791,7 +778,7 @@ if test -z "$conf_wtmp_location"; then
fi
if test -n "$conf_wtmp_location"; then
AC_DEFINE_UNQUOTED(CONF_WTMP_FILE, "$conf_wtmp_location", wtmp file location)
fi
fi
dnl utmpx detection - I don't know any system so perverse as to require
@@ -819,7 +806,7 @@ if test -z "$conf_utmpx_location"; then
fi
else
AC_DEFINE_UNQUOTED(CONF_UTMPX_FILE, "$conf_utmpx_location", utmpx file location)
fi
fi
dnl wtmpx detection
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
@@ -846,7 +833,7 @@ if test -z "$conf_wtmpx_location"; then
fi
else
AC_DEFINE_UNQUOTED(CONF_WTMPX_FILE, "$conf_wtmpx_location", wtmpx file location)
fi
fi
# Checks for library functions.
AC_PROG_GCC_TRADITIONAL
@@ -854,7 +841,7 @@ AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([getpass getspnam getusershell putenv])
AC_CHECK_FUNCS([clearenv strlcpy strlcat daemon basename _getpty getaddrinfo ])
AC_CHECK_FUNCS([freeaddrinfo getnameinfo fork writev getgrouplist fexecve])
AC_CHECK_FUNCS([freeaddrinfo getnameinfo fork writev getgrouplist])
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
@@ -882,7 +869,7 @@ fi
AC_EXEEXT
if test $BUNDLED_LIBTOM = 1 ; then
(cd $srcdir; find libtomcrypt -type d) | xargs mkdir -pv
(cd $srcdir; find libtomcrypt -type d) | xargs mkdir -pv
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
fi

View File

@@ -24,6 +24,12 @@ void crypto_init() {
#if DROPBEAR_AES
&aes_desc,
#endif
#if DROPBEAR_BLOWFISH
&blowfish_desc,
#endif
#if DROPBEAR_TWOFISH
&twofish_desc,
#endif
#if DROPBEAR_3DES
&des3_desc,
#endif
@@ -31,8 +37,10 @@ void crypto_init() {
};
const struct ltc_hash_descriptor *reghashes[] = {
#if DROPBEAR_SHA1_HMAC
/* we need sha1 for hostkey stuff regardless */
&sha1_desc,
#if DROPBEAR_MD5_HMAC
&md5_desc,
#endif
#if DROPBEAR_SHA256
&sha256_desc,
@@ -44,9 +52,9 @@ void crypto_init() {
&sha512_desc,
#endif
NULL
};
};
int i;
for (i = 0; regciphers[i] != NULL; i++) {
if (register_cipher(regciphers[i]) == -1) {
dropbear_exit("Error registering crypto");

View File

@@ -94,18 +94,7 @@ is performed at all, this is usually undesirable.
.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 \fI-A\fR is specified.
Beware that a forwarded agent connection will allow the remote server to have
the same authentication credentials as you have used locally. A compromised
remote server could use that to log in to other servers.
In many situations Dropbear's multi-hop mode is a better and more secure alternative
to agent forwarding, avoiding having to trust the intermediate server.
If the SSH agent program is set to prompt when a key is used, the
\fI-o DisableTrivialAuth\fR option can prevent UI confusion.
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
@@ -122,9 +111,6 @@ if 0 disables keepalives. If no response is received for 3 consecutive keepalive
.B \-I \fIidle_timeout
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
.TP
.B \-z
By default Dropbear will send network traffic with the \fBAF21\fR setting for QoS, letting network devices give it higher priority. Some devices may have problems with that, \fI-z\fR can be used to disable it.
.TP
.\" TODO: how to avoid a line break between these two -J arguments?
.B \-J \fIproxy_command
@@ -170,13 +156,6 @@ Send dbclient log messages to syslog in addition to stderr.
.TP
.B Port
Specify a listening port, like the \fI-p\fR argument.
.TP
.B DisableTrivialAuth
Disallow a server immediately
giving successful authentication (without presenting any password/pubkey prompt).
This avoids a UI confusion issue where it may appear that the user is accepting
a SSH agent prompt from their local machine, but are actually accepting a prompt
sent immediately by the remote server.
.RE
.TP
.B \-s

View File

@@ -23,15 +23,20 @@
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
static int runprog(const char *multipath,
const char *progname, int argc, char ** argv, int *match) {
/* definitions are cleanest if we just put them here */
int dropbear_main(int argc, char ** argv);
int cli_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);
static int runprog(const char *progname, int argc, char ** argv, int *match) {
*match = DROPBEAR_SUCCESS;
#ifdef DBMULTI_dropbear
if (strcmp(progname, "dropbear") == 0) {
return dropbear_main(argc, argv, multipath);
return dropbear_main(argc, argv);
}
#endif
#ifdef DBMULTI_dbclient
@@ -62,16 +67,12 @@ static int runprog(const char *multipath,
int main(int argc, char ** argv) {
int i;
for (i = 0; i < 2; i++) {
const char* multipath = NULL;
if (i == 1) {
multipath = argv[0];
}
/* Try symlink first, then try as an argument eg "dropbearmulti dbclient host ..." */
if (argc > i) {
int match, res;
/* figure which form we're being called as */
const char* progname = basename(argv[i]);
res = runprog(multipath, progname, argc-i, &argv[i], &match);
res = runprog(progname, argc-i, &argv[i], &match);
if (match == DROPBEAR_SUCCESS) {
return res;
}

View File

@@ -34,7 +34,7 @@ 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[SHA256_HASH_SIZE] = {0};
static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
static int donerandinit = 0;
#define INIT_SEED_SIZE 32 /* 256 bits */
@@ -100,7 +100,7 @@ process_file(hash_state *hs, const char *filename,
}
goto out;
}
sha256_process(hs, readbuf, readlen);
sha1_process(hs, readbuf, readlen);
readcount += readlen;
}
ret = DROPBEAR_SUCCESS;
@@ -120,13 +120,13 @@ void addrandom(const unsigned char * buf, unsigned int len)
#endif
/* hash in the new seed data */
sha256_init(&hs);
sha1_init(&hs);
/* existing state (zeroes on startup) */
sha256_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
/* new */
sha256_process(&hs, buf, len);
sha256_done(&hs, hashpool);
sha1_process(&hs, buf, len);
sha1_done(&hs, hashpool);
}
static void write_urandom()
@@ -152,10 +152,10 @@ static void write_urandom()
#if DROPBEAR_FUZZ
void fuzz_seed(const unsigned char* dat, unsigned int len) {
hash_state hs;
sha256_init(&hs);
sha256_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
sha256_process(&hs, dat, len);
sha256_done(&hs, hashpool);
sha1_init(&hs);
sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
sha1_process(&hs, dat, len);
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
}
@@ -209,7 +209,7 @@ static int process_getrandom(hash_state *hs) {
if (ret == sizeof(buf)) {
/* Success, stir in the entropy */
sha256_process(hs, (void*)buf, sizeof(buf));
sha1_process(hs, (void*)buf, sizeof(buf));
return DROPBEAR_SUCCESS;
}
@@ -221,6 +221,7 @@ static int process_getrandom(hash_state *hs) {
/* Initialise the prng from /dev/urandom or prngd. This function can
* be called multiple times */
void seedrandom() {
hash_state hs;
pid_t pid;
@@ -235,10 +236,10 @@ void seedrandom() {
#endif
/* hash in the new seed data */
sha256_init(&hs);
sha1_init(&hs);
/* existing state */
sha256_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
#ifdef HAVE_GETRANDOM
if (process_getrandom(&hs) == DROPBEAR_SUCCESS) {
@@ -288,21 +289,21 @@ void seedrandom() {
#endif
pid = getpid();
sha256_process(&hs, (void*)&pid, sizeof(pid));
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);
sha256_process(&hs, (void*)&tv, sizeof(tv));
sha1_process(&hs, (void*)&tv, sizeof(tv));
clockval = clock();
sha256_process(&hs, (void*)&clockval, sizeof(clockval));
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 */
sha256_done(&hs, hashpool);
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
@@ -316,7 +317,7 @@ void seedrandom() {
void genrandom(unsigned char* buf, unsigned int len) {
hash_state hs;
unsigned char hash[SHA256_HASH_SIZE];
unsigned char hash[SHA1_HASH_SIZE];
unsigned int copylen;
if (!donerandinit) {
@@ -324,17 +325,17 @@ void genrandom(unsigned char* buf, unsigned int len) {
}
while (len > 0) {
sha256_init(&hs);
sha256_process(&hs, (void*)hashpool, sizeof(hashpool));
sha256_process(&hs, (void*)&counter, sizeof(counter));
sha256_done(&hs, hash);
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, SHA256_HASH_SIZE);
copylen = MIN(len, SHA1_HASH_SIZE);
memcpy(buf, hash, copylen);
len -= copylen;
buf += copylen;
@@ -347,7 +348,7 @@ void genrandom(unsigned char* buf, unsigned int len) {
* rand must be an initialised *mp_int for the result.
* the result rand satisfies: 0 < rand < max
* */
void gen_random_mpint(const mp_int *max, mp_int *rand) {
void gen_random_mpint(mp_int *max, mp_int *rand) {
unsigned char *randbuf = NULL;
unsigned int len = 0;

View File

@@ -30,6 +30,6 @@
void seedrandom(void);
void genrandom(unsigned char* buf, unsigned int len);
void addrandom(const unsigned char * buf, unsigned int len);
void gen_random_mpint(const mp_int *max, mp_int *rand);
void gen_random_mpint(mp_int *max, mp_int *rand);
#endif /* DROPBEAR_RANDOM_H_ */

104
dbutil.c
View File

@@ -155,7 +155,7 @@ void dropbear_log(int priority, const char* format, ...) {
}
#if DEBUG_TRACE
#if DEBUG_TRACE
static double debug_start_time = -1;
@@ -185,63 +185,39 @@ static double time_since_start()
return nowf - debug_start_time;
}
static void dropbear_tracelevel(int level, const char *format, va_list param)
{
if (debug_trace == 0 || debug_trace < level) {
void dropbear_trace(const char* format, ...) {
va_list param;
if (!debug_trace) {
return;
}
fprintf(stderr, "TRACE%d (%d) %f: ", level, getpid(), time_since_start());
va_start(param, format);
fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
}
#if (DEBUG_TRACE>=1)
void dropbear_trace1(const char* format, ...) {
va_list param;
va_start(param, format);
dropbear_tracelevel(1, format, param);
va_end(param);
}
#endif
#if (DEBUG_TRACE>=2)
void dropbear_trace2(const char* format, ...) {
static int trace_env = -1;
va_list param;
va_start(param, format);
dropbear_tracelevel(2, format, param);
va_end(param);
}
#endif
#if (DEBUG_TRACE>=3)
void dropbear_trace3(const char* format, ...) {
va_list param;
if (trace_env == -1) {
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
}
if (!(debug_trace && trace_env)) {
return;
}
va_start(param, format);
dropbear_tracelevel(3, format, param);
fprintf(stderr, "TRACE2 (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
}
#endif
#if (DEBUG_TRACE>=4)
void dropbear_trace4(const char* format, ...) {
va_list param;
va_start(param, format);
dropbear_tracelevel(4, format, param);
va_end(param);
}
#endif
#if (DEBUG_TRACE>=5)
void dropbear_trace5(const char* format, ...) {
va_list param;
va_start(param, format);
dropbear_tracelevel(5, format, param);
va_end(param);
}
#endif
#endif
#endif /* DEBUG_TRACE */
/* Connect to a given unix socket. The socket is blocking */
#if ENABLE_CONNECT_UNIX
@@ -442,7 +418,7 @@ void printhex(const char * label, const unsigned char * buf, int len) {
}
}
void printmpint(const char *label, const mp_int *mp) {
void printmpint(const char *label, mp_int *mp) {
buffer *buf = buf_new(1000);
buf_putmpint(buf, mp);
fprintf(stderr, "%d bits ", mp_count_bits(mp));
@@ -599,14 +575,9 @@ void setnonblocking(int fd) {
}
void disallow_core() {
struct rlimit lim = {0};
if (getrlimit(RLIMIT_CORE, &lim) < 0) {
TRACE(("getrlimit(RLIMIT_CORE) failed"));
}
lim.rlim_cur = 0;
if (setrlimit(RLIMIT_CORE, &lim) < 0) {
TRACE(("setrlimit(RLIMIT_CORE) failed"));
}
struct rlimit lim;
lim.rlim_cur = lim.rlim_max = 0;
setrlimit(RLIMIT_CORE, &lim);
}
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE, with the result in *val */
@@ -617,7 +588,7 @@ int m_str_to_uint(const char* str, unsigned int *val) {
l = strtoul(str, &endp, 10);
if (endp == str || *endp != '\0') {
/* parse error */
// parse error
return DROPBEAR_FAILURE;
}
@@ -633,11 +604,11 @@ int m_str_to_uint(const char* str, unsigned int *val) {
}
}
/* Returns malloced path. inpath beginning with '~/' expanded,
otherwise returned as-is */
/* Returns malloced path. inpath beginning with '/' is returned as-is,
otherwise home directory is prepended */
char * expand_homedir_path(const char *inpath) {
struct passwd *pw = NULL;
if (strncmp(inpath, "~/", 2) == 0) {
if (inpath[0] != '/') {
char *homedir = getenv("HOME");
if (!homedir) {
@@ -648,9 +619,9 @@ char * expand_homedir_path(const char *inpath) {
}
if (homedir) {
int len = strlen(inpath)-2 + strlen(homedir) + 2;
int len = strlen(inpath) + strlen(homedir) + 2;
char *buf = m_malloc(len);
snprintf(buf, len, "%s/%s", homedir, inpath+2);
snprintf(buf, len, "%s/%s", homedir, inpath);
return buf;
}
}
@@ -724,7 +695,7 @@ void gettime_wrapper(struct timespec *now) {
/* Fallback for everything else - this will sometimes go backwards */
gettimeofday(&tv, NULL);
now->tv_sec = tv.tv_sec;
now->tv_nsec = 1000*(long)tv.tv_usec;
now->tv_nsec = 1000*tv.tv_usec;
}
/* second-resolution monotonic timestamp */
@@ -771,16 +742,3 @@ int fd_read_pending(int fd) {
return FD_ISSET(fd, &fds);
}
}
int m_snprintf(char *str, size_t size, const char *format, ...) {
va_list param;
int ret;
va_start(param, format);
ret = vsnprintf(str, size, format, param);
va_end(param);
if (ret < 0) {
dropbear_exit("snprintf failed");
}
return ret;
}

View File

@@ -47,13 +47,10 @@ 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;
#if DEBUG_TRACE
void dropbear_trace1(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace3(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace4(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace5(const char* format, ...) ATTRIB_PRINTF(1,2);
void printhex(const char * label, const unsigned char * buf, int len);
void printmpint(const char *label, const mp_int *mp);
void printmpint(const char *label, mp_int *mp);
void debug_start_net(void);
extern int debug_trace;
#endif
@@ -73,8 +70,6 @@ void m_close(int fd);
void setnonblocking(int fd);
void disallow_core(void);
int m_str_to_uint(const char* str, unsigned int *val);
/* The same as snprintf() but exits rather than returning negative */
int m_snprintf(char *str, size_t size, const char *format, ...);
/* Used to force mp_ints to be initialised */
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
@@ -104,12 +99,4 @@ int fd_read_pending(int fd);
#define DROPBEAR_FD_ZERO(fds) FD_ZERO(fds)
#endif
/* dropbearmulti entry points */
int dropbear_main(int argc, char ** argv, const char * multipath);
int cli_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);
#endif /* DROPBEAR_DBUTIL_H_ */

12
debian/changelog vendored
View File

@@ -1,15 +1,3 @@
dropbear (2022.83-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Mon, 14 Nov 2022 22:51:57 +0800
dropbear (2022.82-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Fri, 1 Apr 2022 22:51:57 +0800
dropbear (2020.81-0.1) unstable; urgency=low
* New upstream release.

View File

@@ -25,7 +25,7 @@ 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 || \
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" || \

38
debug.h
View File

@@ -48,43 +48,15 @@
/*#define DEBUG_KEXHASH*/
/*#define DEBUG_RSA*/
/* The level of TRACE() statements */
#define DROPBEAR_VERBOSE_LEVEL 4
/* you don't need to touch this block */
#if DEBUG_TRACE
extern int debug_trace;
#endif
/* Enable debug trace levels.
We can't use __VA_ARGS_ here because Dropbear supports
old ~C89 compilers */
/* Default is to discard output ... */
#define DEBUG1(X)
#define DEBUG2(X)
#define DEBUG3(X)
#define TRACE(X) dropbear_trace X;
#define TRACE2(X) dropbear_trace2 X;
#else /*DEBUG_TRACE*/
#define TRACE(X)
#define TRACE2(X)
/* ... unless DEBUG_TRACE is high enough */
#if (DEBUG_TRACE>=1)
#undef DEBUG1
#define DEBUG1(X) dropbear_trace1 X;
#endif
#if (DEBUG_TRACE>=2)
#undef DEBUG2
#define DEBUG2(X) dropbear_trace2 X;
#endif
#if (DEBUG_TRACE>=3)
#undef DEBUG3
#define DEBUG3(X) dropbear_trace3 X;
#endif
#if (DEBUG_TRACE>=4)
#undef TRACE
#define TRACE(X) dropbear_trace4 X;
#endif
#if (DEBUG_TRACE>=5)
#undef TRACE2
#define TRACE2(X) dropbear_trace5 X;
#endif
#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. */

View File

@@ -6,7 +6,7 @@
default_options.h documents compile-time options, and provides default values.
Local customisation should be added to localoptions.h which is
used if it exists in the build directory. Options defined there will override
used if it exists in the build directory. Options defined there will override
any options in this file.
Options can also be defined with -DDROPBEAR_XXX=[0,1] in Makefile CFLAGS
@@ -18,9 +18,7 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Listen on all interfaces */
#define DROPBEAR_DEFADDRESS ""
/* Default hostkey paths - these can be specified on the command line.
* Homedir is prepended if path begins with ~/
*/
/* Default hostkey paths - these can be specified on the command line */
#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key"
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
@@ -39,18 +37,8 @@ IMPORTANT: Some options will require "make clean" after changes */
#define NON_INETD_MODE 1
#define INETD_MODE 1
/* By default Dropbear will re-execute itself for each incoming connection so
that memory layout may be re-randomised (ASLR) - exploiting
vulnerabilities becomes harder. Re-exec causes slightly more memory use
per connection.
This option is ignored on non-Linux platforms at present */
#define DROPBEAR_REEXEC 1
/* Include verbose debug output, enabled with -v at runtime (repeat to increase).
* define which level of debug output you compile in
* TRACE1 - TRACE3 = approx 4 Kb (connection, remote identity, algos, auth type info)
* TRACE4 = approx 17 Kb (detailed before connection)
* TRACE5 = approx 8 Kb (detailed after connection) */
/* Include verbose debug output, enabled with -v at runtime.
* This will add a reasonable amount to your executable size. */
#define DEBUG_TRACE 0
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
@@ -78,7 +66,7 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Note: Both DROPBEAR_CLI_PROXYCMD and DROPBEAR_CLI_NETCAT must be set to
* allow multihop dbclient connections */
/* Allow using -J <proxycommand> to run the connection through a
/* Allow using -J <proxycommand> to run the connection through a
pipe to a program, rather the normal TCP connection */
#define DROPBEAR_CLI_PROXYCMD 1
@@ -92,11 +80,13 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Encryption - at least one required.
* AES128 should be enabled, some very old implementations might only
* support 3DES.
* Including both AES keysize variants (128 and 256) will result in
* Including both AES keysize variants (128 and 256) will result in
* a minimal size increase */
#define DROPBEAR_AES128 1
#define DROPBEAR_AES256 1
#define DROPBEAR_3DES 0
#define DROPBEAR_TWOFISH256 0
#define DROPBEAR_TWOFISH128 0
/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
* generally faster than AES256 on CPU w/o dedicated AES instructions,
@@ -118,47 +108,29 @@ IMPORTANT: Some options will require "make clean" after changes */
* Compiling in will add ~6kB to binary size on x86-64 */
#define DROPBEAR_ENABLE_GCM_MODE 0
/* Message integrity. sha2-256 is recommended as a default,
/* Message integrity. sha2-256 is recommended as a default,
sha1 for compatibility */
#define DROPBEAR_SHA1_HMAC 1
#define DROPBEAR_SHA2_256_HMAC 1
#define DROPBEAR_SHA2_512_HMAC 0
#define DROPBEAR_SHA1_96_HMAC 0
/* Hostkey/public key algorithms - at least one required, these are used
* for hostkey as well as for verifying signatures with pubkey auth.
* RSA is recommended.
*
* See: RSA_PRIV_FILENAME and DSS_PRIV_FILENAME */
* Removing either of these won't save very much space.
* RSA is recommended
* DSS may be necessary to connect to some systems though
is not recommended for new keys */
#define DROPBEAR_RSA 1
/* Newer SSH implementations use SHA256 for RSA signatures. SHA1
* support is required to communicate with some older implementations.
* It will be removed in future due to SHA1 insecurity, it can be
* disabled with DROPBEAR_RSA_SHA1 set to 0 */
#define DROPBEAR_RSA_SHA1 1
/* DSS may be necessary to connect to some systems but is not
* recommended for new keys (1024 bits is small, and it uses SHA1).
* RSA key generation will be faster with bundled libtommath
* if DROPBEAR_DSS is disabled.
* https://github.com/mkj/dropbear/issues/174#issuecomment-1267374858 */
#define DROPBEAR_DSS 0
#define DROPBEAR_DSS 1
/* ECDSA is significantly faster than RSA or DSS. Compiling in ECC
* code (either ECDSA or ECDH) increases binary size - around 30kB
* on x86-64.
* See: ECDSA_PRIV_FILENAME */
* on x86-64 */
#define DROPBEAR_ECDSA 1
#define DROPBEAR_SK_ECDSA 1
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
* binary size - around 7,5kB on x86-64.
* See: ED25519_PRIV_FILENAME */
binary size - around 7,5kB on x86-64 */
#define DROPBEAR_ED25519 1
/* Allow U2F security keys for public key auth, with
* sk-ecdsa-sha2-nistp256@openssh.com or sk-ssh-ed25519@openssh.com keys.
* The corresponding DROPBEAR_ECDSA or DROPBEAR_ED25519 also needs to be set.
* This is currently server-only. */
#define DROPBEAR_SK_KEYS 1
#define DROPBEAR_SK_ED25519 1
/* RSA must be >=1024 */
#define DROPBEAR_DEFAULT_RSA_SIZE 2048
@@ -192,13 +164,13 @@ IMPORTANT: Some options will require "make clean" after changes */
* Small systems should generally include either curve25519 or ecdh for performance.
* curve25519 is less widely supported but is faster
*/
*/
#define DROPBEAR_DH_GROUP14_SHA1 1
#define DROPBEAR_DH_GROUP14_SHA256 1
#define DROPBEAR_DH_GROUP16 0
#define DROPBEAR_CURVE25519 1
#define DROPBEAR_ECDH 1
#define DROPBEAR_DH_GROUP1 0
#define DROPBEAR_DH_GROUP1 1
/* When group1 is enabled it will only be allowed by Dropbear client
not as a server, due to concerns over its strength. Set to 0 to allow
@@ -233,8 +205,7 @@ group1 in Dropbear server too */
* You can't enable both PASSWORD and PAM. */
#define DROPBEAR_SVR_PAM_AUTH 0
/* ~/.ssh/authorized_keys authentication.
* You must define DROPBEAR_SVR_PUBKEY_AUTH in order to use plugins. */
/* ~/.ssh/authorized_keys authentication */
#define DROPBEAR_SVR_PUBKEY_AUTH 1
/* Whether to take public key options in
@@ -250,10 +221,9 @@ group1 in Dropbear server too */
#define DROPBEAR_CLI_PASSWORD_AUTH 1
#define DROPBEAR_CLI_PUBKEY_AUTH 1
/* A default argument for dbclient -i <privatekey>.
* Homedir is prepended if path begins with ~/
*/
#define DROPBEAR_DEFAULT_CLI_AUTHKEY "~/.ssh/id_dropbear"
/* A default argument for dbclient -i <privatekey>.
Homedir is prepended unless path begins with / */
#define DROPBEAR_DEFAULT_CLI_AUTHKEY ".ssh/id_dropbear"
/* Allow specifying the password for dbclient via the DROPBEAR_PASSWORD
* environment variable. */
@@ -295,9 +265,7 @@ group1 in Dropbear server too */
#define UNAUTH_CLOSE_DELAY 0
/* The default file to store the daemon's process ID, for shutdown
* scripts etc. This can be overridden with the -P flag.
* Homedir is prepended if path begins with ~/
*/
scripts etc. This can be overridden with the -P flag */
#define DROPBEAR_PIDFILE "/var/run/dropbear.pid"
/* The command to invoke for xauth when using X11 forwarding.
@@ -305,11 +273,9 @@ group1 in Dropbear server too */
#define XAUTH_COMMAND "/usr/bin/xauth -q"
/* If you want to enable running an sftp server (such as the one included with
* OpenSSH), set the path below and set DROPBEAR_SFTPSERVER.
* The sftp-server program is not provided by Dropbear itself.
* Homedir is prepended if path begins with ~/
*/
/* if you want to enable running an sftp server (such as the one included with
* OpenSSH), set the path below and set DROPBEAR_SFTPSERVER.
* The sftp-server program is not provided by Dropbear itself */
#define DROPBEAR_SFTPSERVER 1
#define SFTPSERVER_PATH "/usr/libexec/sftp-server"
@@ -352,6 +318,5 @@ be overridden at runtime with -I. 0 disables idle timeouts */
/* The default path. This will often get replaced by the shell */
#define DEFAULT_PATH "/usr/bin:/bin"
#define DEFAULT_ROOT_PATH "/usr/sbin:/usr/bin:/sbin:/bin"
#endif /* DROPBEAR_DEFAULT_OPTIONS_H_ */

View File

@@ -53,10 +53,6 @@ Disable password logins.
.B \-g
Disable password logins for root.
.TP
.B \-t
Enable two-factor authentication. Both password login and public key authentication are
required. Should not be used with the '-s' option.
.TP
.B \-j
Disable local port forwarding.
.TP
@@ -101,9 +97,6 @@ of 0 disables keepalives. If no response is received for 3 consecutive keepalive
.B \-I \fIidle_timeout
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
.TP
.B \-z
By default Dropbear will send network traffic with the \fBAF21\fR setting for QoS, letting network devices give it higher priority. Some devices may have problems with that, \fI-z\fR can be used to disable it.
.TP
.B \-T \fImax_authentication_attempts
Set the number of authentication attempts allowed per connection. If unspecified the default is 10 (MAX_AUTH_TRIES)
.TP
@@ -151,14 +144,6 @@ same functionality with other means even if no-pty is set.
.B restrict
Applies all the no- restrictions listed above.
.TP
.B permitopen=\fR"\fIhost:port\fR"
Restrict local port forwarding so that connection is allowed only to the
specified host and port. Multiple permitopen options separated by commas
can be set in authorized_keys. Wildcard character ('*') may be used in
port specification for matching any port. Hosts must be literal domain names or
IP addresses.
.TP
.B command=\fR"\fIforced_command\fR"
Disregard the command provided by the user and always run \fIforced_command\fR.

View File

@@ -3,6 +3,6 @@
EXITCODE=0
# #ifdef instead of #if
grep '#ifdef DROPBEAR' -I -- *.c *.h && EXITCODE=1
grep '#ifdef DROPBEAR' -I *.c *.h && EXITCODE=1
exit $EXITCODE

View File

@@ -9,7 +9,7 @@ dropbearconvert \- convert between Dropbear and OpenSSH private key formats
.I output_file
.SH DESCRIPTION
.B Dropbear
and
and
.B OpenSSH
SSH implementations have different private key formats.
.B dropbearconvert
@@ -24,15 +24,15 @@ first.
.SH ARGUMENTS
.TP
.I input_type
Either
Either
.I dropbear
or
or
.I openssh
.TP
.I output_type
Either
Either
.I dropbear
or
or
.I openssh
.TP
.I input_file
@@ -40,15 +40,6 @@ An existing Dropbear or OpenSSH private key file
.TP
.I output_file
The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
.SH SUPPORTED FORMATS
.B dropbearconvert
can read OpenSSH format files, and older PEM format files (
.B ssh-keygen
.I -m PEM
).
.B dropbearconvert
will write OpenSSH format files, usable with OpenSSH 6.5 and later.
Reading OpenSSH format DSS files or PKCS8 files is not currently supported.
.SH EXAMPLE
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear
.SH AUTHOR

View File

@@ -69,7 +69,7 @@ int main(int argc, char ** argv) {
#if DEBUG_TRACE
/* It's hard for it to get in the way _too_ much */
debug_trace = DROPBEAR_VERBOSE_LEVEL;
debug_trace = 1;
#endif
/* get the commandline options */

View File

@@ -127,19 +127,18 @@ static void check_signkey_bits(enum signkey_type type, int bits)
#endif
#if DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
if (bits < 1024 || bits > 4096 || (bits % 8 != 0)) {
dropbear_exit("Bits must satisfy 1024 <= bits <= 4096, and be a"
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
#if DROPBEAR_DSS
#if DROPEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
if (bits != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
exit(EXIT_FAILURE);
}
break;
#endif
default:
(void)0; /* quiet, compiler. ecdsa handles checks itself */
@@ -196,7 +195,7 @@ int main(int argc, char ** argv) {
break;
#if DEBUG_TRACE
case 'v':
debug_trace = DROPBEAR_VERBOSE_LEVEL;
debug_trace = 1;
break;
#endif
default:
@@ -310,7 +309,8 @@ static int printpubfile(const char* filename) {
err = DROPBEAR_SUCCESS;
out:
buf_burn_free(buf);
buf_burn(buf);
buf_free(buf);
buf = NULL;
if (key) {
sign_key_free(key);
@@ -342,7 +342,7 @@ static void printpubkey(sign_key * key, int keytype) {
err = base64_encode(buf_getptr(buf, len), len, base64key, &base64len);
if (err != CRYPT_OK) {
dropbear_exit("base64 failed");
fprintf(stderr, "base64 failed");
}
typestring = signkey_name_from_type(keytype, NULL);

View File

@@ -12,8 +12,8 @@ int main(int argc, char ** argv) {
for (i = 1; i < argc; i++) {
#if DEBUG_TRACE
if (strcmp(argv[i], "-v") == 0) {
debug_trace++;
fprintf(stderr, "debug level -> %d\n", debug_trace);
debug_trace = 1;
TRACE(("debug printing on"))
}
#endif
if (strcmp(argv[i], "-q") == 0) {

View File

@@ -3,7 +3,6 @@
#include "fuzz-wrapfd.h"
#include "debug.h"
#include "dss.h"
#include "ed25519.h"
static void setup_fuzzer(void) {
fuzz_common_setup();
@@ -60,21 +59,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
/* Could also check g**q mod p == 1 */
}
if (keytype == DROPBEAR_SIGNKEY_SK_ED25519 || keytype == DROPBEAR_SIGNKEY_ED25519) {
dropbear_ed25519_key **eck = (dropbear_ed25519_key**)signkey_key_ptr(key, keytype);
if (eck && *eck) {
int i;
/* we've seen all-zero keys validate */
boguskey = 1;
for (i = 0; i < CURVE25519_LEN; i++) {
if ((*eck)->priv[i] != 0x00 || (*eck)->pub[i] != 0x00) {
boguskey = 0;
}
}
}
}
if (!boguskey) {
printf("Random key/signature managed to verify!\n");
abort();

View File

@@ -34,7 +34,7 @@
#if DROPBEAR_RSA
static void getrsaprime(mp_int* prime, mp_int *primeminus,
const mp_int* rsa_e, unsigned int size_bytes);
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) {
@@ -89,7 +89,7 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
/* return a prime suitable for p or q */
static void getrsaprime(mp_int* prime, mp_int *primeminus,
const mp_int* rsa_e, unsigned int size_bytes) {
mp_int* rsa_e, unsigned int size_bytes) {
unsigned char *buf;
int trials;

View File

@@ -181,7 +181,8 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
out:
if (buf) {
buf_burn_free(buf);
buf_burn(buf);
buf_free(buf);
}
if (fn_temp) {

View File

@@ -127,10 +127,6 @@
#include <sys/random.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
#ifdef BUNDLED_LIBTOM
#include "libtomcrypt/src/headers/tomcrypt.h"
#include "libtommath/tommath.h"
@@ -175,8 +171,6 @@ typedef u_int32_t uint32_t;
#include <dlfcn.h>
#endif
extern char** environ;
#include "fake-rfc2553.h"
#include "fuzz.h"

File diff suppressed because it is too large Load Diff

View File

@@ -42,7 +42,7 @@ ARFLAGS = r
EXTRALIBS = ../libtommath/libtommath.a
#Compilation flags
LTC_CFLAGS = -Isrc/headers/ -I$(srcdir)/src/headers/ -I../ -I$(srcdir)/../ -DLTC_SOURCE -I../libtommath/ -I$(srcdir)/../libtommath/ $(CFLAGS) $(CPPFLAGS)
LTC_CFLAGS = -Isrc/headers/ -I$(srcdir)/src/headers/ -I../ -I$(srcdir)/../ -DLTC_SOURCE -I../libtommath/ -I$(srcdir)/../libtommath/ $(CFLAGS)
LTC_LDFLAGS = $(LDFLAGS) $(EXTRALIBS)
VERSION=1.18.1

View File

@@ -16,6 +16,12 @@
#if DROPBEAR_AES
#define LTC_RIJNDAEL
#endif
/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format
* (saves 4KB of ram), _ALL_TABLES enables all tables during setup */
#if DROPBEAR_TWOFISH
#define LTC_TWOFISH
#define LTC_TWOFISH_SMALL
#endif
#if DROPBEAR_3DES
#define LTC_DES
@@ -50,8 +56,10 @@
#define LTC_SHA256
#endif
#if DROPBEAR_SHA1
#define LTC_SHA1
#if DROPBEAR_MD5
#define LTC_MD5
#endif
/* ECC */

View File

@@ -8,7 +8,6 @@ srcdir=@srcdir@
# So that libtommath can include Dropbear headers for options and m_burn()
CFLAGS += -I$(srcdir) -I../libtomcrypt/src/headers/ -I$(srcdir)/../libtomcrypt/src/headers/ -I../ -I$(srcdir)/../
CFLAGS += -Wno-deprecated
CFLAGS += $(CPPFLAGS)
V = 1
@@ -25,14 +24,8 @@ endif
coverage: LIBNAME:=-Wl,--whole-archive $(LIBNAME) -Wl,--no-whole-archive
# Dropbear sets its own flags below
IGNORE_SPEED=1
include $(srcdir)/makefile_include.mk
# override makefile_include.mk flags
LTM_CFLAGS += @DROPBEAR_LTM_CFLAGS@
%.o: %.c $(HEADERS)
ifneq ($V,1)
@echo " * ${CC} $@"

View File

@@ -104,7 +104,7 @@ LIBTOOLFLAGS += -no-undefined
endif
# add in the standard FLAGS
LTM_CFLAGS := $(CFLAGS) $(LTM_CFLAGS)
LTM_CFLAGS += $(CFLAGS)
LTM_LFLAGS += $(LFLAGS)
LTM_LDFLAGS += $(LDFLAGS)
LTM_LIBTOOLFLAGS += $(LIBTOOLFLAGS)

View File

@@ -459,7 +459,6 @@ line_abbrevname(char *dst, const char *src, size_t dstsize)
void
set_utmp_time(struct logininfo *li, struct utmp *ut)
{
/* struct utmp in glibc isn't y2038 safe yet */
# ifdef HAVE_STRUCT_UTMP_UT_TV
ut->ut_tv.tv_sec = li->tv_sec;
ut->ut_tv.tv_usec = li->tv_usec;
@@ -830,7 +829,7 @@ utmpx_perform_login(struct logininfo *li)
return 0;
}
# else
if (!utmpx_write_direct(li, &utx)) {
if (!utmpx_write_direct(li, &ut)) {
dropbear_log(LOG_WARNING, "utmpx_perform_login: utmp_write_direct() failed");
return 0;
}
@@ -1273,7 +1272,6 @@ lastlog_construct(struct logininfo *li, struct lastlog *last)
(void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
strlcpy(last->ll_host, li->hostname,
MIN_SIZEOF(last->ll_host, li->hostname));
/* struct lastlog in glibc isn't y2038 safe yet */
last->ll_time = li->tv_sec;
}

View File

@@ -139,8 +139,8 @@ struct logininfo {
/* struct timeval (sys/time.h) isn't always available, if it isn't we'll
* use time_t's value as tv_sec and set tv_usec to 0
*/
time_t tv_sec;
suseconds_t tv_usec;
unsigned int tv_sec;
unsigned int tv_usec;
union login_netinfo hostaddr; /* caller's host address(es) */
}; /* struct logininfo */

57
netio.c
View File

@@ -3,7 +3,6 @@
#include "dbutil.h"
#include "session.h"
#include "debug.h"
#include "runopts.h"
struct dropbear_progress_connection {
struct addrinfo *res;
@@ -21,7 +20,6 @@ struct dropbear_progress_connection {
char* errstring;
char *bind_address, *bind_port;
enum dropbear_prio prio;
};
/* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
@@ -112,7 +110,6 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
ses.maxfd = MAX(ses.maxfd, c->sock);
set_sock_nodelay(c->sock);
set_sock_priority(c->sock, c->prio);
setnonblocking(c->sock);
#if DROPBEAR_CLIENT_TCP_FAST_OPEN
@@ -175,8 +172,8 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
/* Connect via TCP to a host. */
struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport,
connect_callback cb, void* cb_data,
const char* bind_address, const char* bind_port, enum dropbear_prio prio)
connect_callback cb, void* cb_data,
const char* bind_address, const char* bind_port)
{
struct dropbear_progress_connection *c = NULL;
int err;
@@ -188,7 +185,6 @@ struct dropbear_progress_connection *connect_remote(const char* remotehost, cons
c->sock = -1;
c->cb = cb;
c->cb_data = cb_data;
c->prio = prio;
list_append(&ses.conn_pending, c);
@@ -367,7 +363,12 @@ void set_listen_fast_open(int sock) {
void set_sock_priority(int sock, enum dropbear_prio prio) {
int rc;
int val;
#ifdef IPTOS_LOWDELAY
int iptos_val = 0;
#endif
#ifdef HAVE_LINUX_PKT_SCHED_H
int so_prio_val = 0;
#endif
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
@@ -375,53 +376,37 @@ void set_sock_priority(int sock, enum dropbear_prio prio) {
return;
}
#endif
/* Don't log ENOTSOCK errors so that this can harmlessly be called
* on a client '-J' proxy pipe */
if (opts.disable_ip_tos == 0) {
#ifdef IP_TOS
/* Set the DSCP field for outbound IP packet priority.
rfc4594 has some guidance to meanings.
We set AF21 as "Low-Latency" class for interactive (tty session,
also handshake/setup packets). Other traffic is left at the default.
OpenSSH at present uses AF21/CS1, rationale
https://cvsweb.openbsd.org/src/usr.bin/ssh/readconf.c#rev1.284
Old Dropbear/OpenSSH and Debian/Ubuntu OpenSSH (at Jan 2022) use
IPTOS_LOWDELAY/IPTOS_THROUGHPUT
DSCP constants are from Linux headers, applicable to other platforms
such as macos.
*/
/* set the TOS bit for either ipv4 or ipv6 */
#ifdef IPTOS_LOWDELAY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
val = 0x48; /* IPTOS_DSCP_AF21 */
} else {
val = 0; /* default */
iptos_val = IPTOS_LOWDELAY;
} else if (prio == DROPBEAR_PRIO_BULK) {
iptos_val = IPTOS_THROUGHPUT;
}
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
#endif /* IP_TOS */
}
#endif
#ifdef HAVE_LINUX_PKT_SCHED_H
/* Set scheduling priority within the local Linux network stack */
if (prio == DROPBEAR_PRIO_LOWDELAY) {
val = TC_PRIO_INTERACTIVE;
} else {
val = 0;
so_prio_val = TC_PRIO_INTERACTIVE;
} else if (prio == DROPBEAR_PRIO_BULK) {
so_prio_val = TC_PRIO_BULK;
}
/* linux specific, sets QoS class. see tc-prio(8) */
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &val, sizeof(val));
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set SO_PRIORITY (%s)", strerror(errno)))
}

View File

@@ -6,8 +6,9 @@
#include "queue.h"
enum dropbear_prio {
DROPBEAR_PRIO_NORMAL = 0, /* the rest - tcp-fwd, scp, rsync, git, etc */
DROPBEAR_PRIO_LOWDELAY, /* pty shell, x11 */
DROPBEAR_PRIO_DEFAULT = 10,
DROPBEAR_PRIO_LOWDELAY = 11,
DROPBEAR_PRIO_BULK = 12,
};
void set_sock_nodelay(int sock);
@@ -29,8 +30,7 @@ typedef void(*connect_callback)(int result, int sock, void* data, const char* er
/* Always returns a progress connection, if it fails it will call the callback at a later point */
struct dropbear_progress_connection * connect_remote (const char* remotehost, const char* remoteport,
connect_callback cb, void *cb_data, const char* bind_address, const char* bind_port,
enum dropbear_prio prio);
connect_callback cb, void *cb_data, const char* bind_address, const char* bind_port);
/* Sets up for select() */
void set_connect_fds(fd_set *writefd);

View File

@@ -430,32 +430,44 @@ static buffer* buf_decompress(const buffer* buf, unsigned int len) {
z_streamp zstream;
zstream = ses.keys->recv.zstream;
/* We use RECV_MAX_PAYLOAD_LEN+1 here to ensure that
we can detect an oversized payload after inflate() */
ret = buf_new(RECV_MAX_PAYLOAD_LEN+1);
ret = buf_new(len);
zstream->avail_in = len;
zstream->next_in = buf_getptr(buf, len);
zstream->avail_out = ret->size;
zstream->next_out = ret->data;
result = inflate(zstream, Z_SYNC_FLUSH);
if (result != Z_OK) {
dropbear_exit("zlib error");
/* decompress the payload, incrementally resizing the output buffer */
while (1) {
zstream->avail_out = ret->size - ret->pos;
zstream->next_out = buf_getwriteptr(ret, zstream->avail_out);
result = inflate(zstream, Z_SYNC_FLUSH);
buf_setlen(ret, ret->size - zstream->avail_out);
buf_setpos(ret, ret->len);
if (result != Z_BUF_ERROR && result != Z_OK) {
dropbear_exit("zlib error");
}
if (zstream->avail_in == 0 &&
(zstream->avail_out != 0 || result == Z_BUF_ERROR)) {
/* we can only exit if avail_out hasn't all been used,
* and there's no remaining input */
return ret;
}
if (zstream->avail_out == 0) {
int new_size = 0;
if (ret->size >= RECV_MAX_PAYLOAD_LEN) {
/* Already been increased as large as it can go,
* yet didn't finish up the decompression */
dropbear_exit("bad packet, oversized decompressed");
}
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
ret = buf_resize(ret, new_size);
}
}
buf_setlen(ret, ret->size - zstream->avail_out);
if (zstream->avail_in > 0 || ret->len > RECV_MAX_PAYLOAD_LEN) {
/* The remote side sent larger than a payload size
* of uncompressed data.
*/
dropbear_exit("bad packet, oversized decompressed");
}
/* Success. All input was consumed and avail_out > 0 */
return ret;
}
#endif

View File

@@ -2,38 +2,18 @@
set -e
if [ "$1" = '--testrel' ]; then
# --testrel won't check changelog version correctness and will build in a temporary dir
TESTREL=1
else
TESTREL=0
VERSION=$(echo '#include "sysoptions.h"\necho DROPBEAR_VERSION' | cpp - | sh)
echo Releasing version "$VERSION" ...
if ! head -n1 CHANGES | grep -q $VERSION ; then
echo "CHANGES needs updating"
exit 1
fi
VERSION=$(echo '#include "default_options.h"\n#include "sysoptions.h"\necho DROPBEAR_VERSION' | cpp -DHAVE_CRYPT - | sh)
if [ $TESTREL -eq 1 ]; then
echo Making test tarball for "$VERSION" ...
echo Not checking version mismatches.
WORKDIR=$(mktemp -d)
TARSUFFIX="-testrel"
else
echo Releasing version "$VERSION" ...
if ! head -n1 CHANGES | grep -q $VERSION ; then
echo "CHANGES needs updating"
exit 1
fi
if ! head -n1 debian/changelog | grep -q $VERSION ; then
echo "debian/changelog needs updating"
exit 1
fi
WORKDIR=$PWD/..
TARSUFFIX=""
if ! head -n1 debian/changelog | grep -q $VERSION ; then
echo "debian/changelog needs updating"
exit 1
fi
RELDIR=$WORKDIR/dropbear-$VERSION
ARCHIVE=${RELDIR}${TARSUFFIX}.tar.bz2
head -n1 CHANGES
if tar --version | grep -q 'GNU tar'; then
@@ -42,6 +22,8 @@ else
TAR=gtar
fi
RELDIR=$PWD/../dropbear-$VERSION
ARCHIVE=${RELDIR}.tar.bz2
if test -e $RELDIR; then
echo "$RELDIR exists"
exit 1
@@ -52,18 +34,11 @@ if test -e $ARCHIVE; then
exit 1
fi
if [ -d .hg ]; then
hg archive "$RELDIR" || exit 2
# .hg_archival.txt seems to differ between hg versions, isn't good for reproducibility
rm "$RELDIR/.hg_archival.txt"
elif [ -d .git ]; then
git -c tar.umask=0022 archive --format tar -o /dev/stdout --prefix=dropbear-$VERSION/ HEAD | tar xf - -C $WORKDIR || exit 2
else
echo "This isn't a hg or git checkout"
exit 1
fi
hg archive "$RELDIR" || exit 2
chmod -R a+rX $RELDIR
rm "$RELDIR/.hgtags"
# .hg_archival.txt seems to differ between hg versions, isn't good for reproducibility
rm "$RELDIR/.hg_archival.txt"
RELDATE=$(head -n1 CHANGES | cut -d - -f 2)
# timezone keeps it consistent, choose a plausible release time
@@ -77,8 +52,5 @@ ls -l $ARCHIVE
openssl sha256 $ARCHIVE
echo Done to
echo "$ARCHIVE"
if [ $TESTREL -eq 0 ]; then
echo Sign it with
echo gpg2 --detach-sign -a -u F29C6773 "$ARCHIVE"
fi
echo Sign it with
echo gpg2 --detach-sign -a -u F29C6773 "$ARCHIVE"

View File

@@ -33,14 +33,13 @@
typedef struct runopts {
int disable_ip_tos;
#if DROPBEAR_SVR_REMOTETCPFWD || DROPBEAR_CLI_LOCALTCPFWD \
|| DROPBEAR_CLI_REMOTETCPFWD
int listen_fwd_all;
#endif
unsigned int recv_window;
long keepalive_secs; /* Time between sending keepalives. 0 is off */
long idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
time_t keepalive_secs; /* Time between sending keepalives. 0 is off */
time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
int usingsyslog;
#ifndef DISABLE_ZLIB
@@ -73,16 +72,13 @@ typedef struct svr_runopts {
int forkbg;
/* ports and addresses are arrays of the portcount
/* ports and addresses are arrays of the portcount
listening ports. strings are malloced. */
char *ports[DROPBEAR_MAX_PORTS];
unsigned int portcount;
char *addresses[DROPBEAR_MAX_PORTS];
int inetdmode;
/* Hidden "-2 childpipe_fd" flag indicates it's re-executing itself,
stores the childpipe preauth file descriptor. Set to -1 otherwise. */
int reexec_childpipe;
/* Flags indicating whether to use ipv4 and ipv6 */
/* not used yet
@@ -94,6 +90,7 @@ typedef struct svr_runopts {
/* whether to print the MOTD */
int domotd;
#endif
int norootlogin;
#ifdef HAVE_GETGROUPLIST
@@ -107,7 +104,6 @@ typedef struct svr_runopts {
int noauthpass;
int norootpass;
int allowblankpass;
int multiauthmethod;
unsigned int maxauthtries;
#if DROPBEAR_SVR_REMOTETCPFWD
@@ -130,10 +126,8 @@ typedef struct svr_runopts {
char * forced_command;
#if DROPBEAR_PLUGIN
/* malloced */
char *pubkey_plugin;
/* points into pubkey_plugin */
char *pubkey_plugin_options;
char *pubkey_plugin;
char *pubkey_plugin_options;
#endif
int pass_on_env;
@@ -159,7 +153,6 @@ typedef struct cli_runopts {
int always_accept_key;
int no_hostkey_check;
int no_cmd;
int quiet;
int backgrounded;
int is_subsystem;
#if DROPBEAR_CLI_PUBKEY_AUTH
@@ -203,6 +196,5 @@ void parse_ciphers_macs(void);
void print_version(void);
void parse_recv_window(const char* recv_window_arg);
int split_address_port(const char* spec, char **first, char ** second);
#endif /* DROPBEAR_RUNOPTS_H_ */

127
signkey.c
View File

@@ -120,7 +120,6 @@ enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen)
/* Special case for rsa-sha2-256. This could be generalised if more
signature names are added that aren't 1-1 with public key names */
const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) {
#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
if (type == DROPBEAR_SIGNATURE_RSA_SHA256) {
if (namelen) {
@@ -137,13 +136,11 @@ const char* signature_name_from_type(enum signature_type type, unsigned int *nam
return SSH_SIGNKEY_RSA;
}
#endif
#endif /* DROPBEAR_RSA */
return signkey_name_from_type((enum signkey_type)type, namelen);
}
/* Returns DROPBEAR_SIGNATURE_NONE if none match */
enum signature_type signature_type_from_name(const char* name, unsigned int namelen) {
#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256)
&& memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) {
@@ -156,11 +153,10 @@ enum signature_type signature_type_from_name(const char* name, unsigned int name
return DROPBEAR_SIGNATURE_RSA_SHA1;
}
#endif
#endif /* DROPBEAR_RSA */
return (enum signature_type)signkey_type_from_name(name, namelen);
}
/* Returns the signature type from a key type. Must not be called
/* Returns the signature type from a key type. Must not be called
with RSA keytype */
enum signature_type signature_type_from_signkey(enum signkey_type keytype) {
#if DROPBEAR_RSA
@@ -171,7 +167,6 @@ enum signature_type signature_type_from_signkey(enum signkey_type keytype) {
}
enum signkey_type signkey_type_from_signature(enum signature_type sigtype) {
#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
return DROPBEAR_SIGNKEY_RSA;
@@ -182,7 +177,6 @@ enum signkey_type signkey_type_from_signature(enum signature_type sigtype) {
return DROPBEAR_SIGNKEY_RSA;
}
#endif
#endif /* DROPBEAR_RSA */
assert((int)sigtype < (int)DROPBEAR_SIGNKEY_NUM_NAMED);
return (enum signkey_type)sigtype;
}
@@ -540,52 +534,104 @@ void sign_key_free(sign_key *key) {
#endif
m_free(key->filename);
#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
if (key->sk_app) {
m_free(key->sk_app);
}
#endif
m_free(key->sk_app);
m_free(key);
TRACE2(("leave sign_key_free"))
}
static char * sign_key_sha256_fingerprint(const unsigned char* keyblob,
static char hexdig(unsigned char x) {
if (x > 0xf)
return 'X';
if (x < 10)
return '0' + x;
else
return 'a' + x - 10;
}
/* Since we're not sure if we'll have md5 or sha1, we present both.
* MD5 is used in preference, but sha1 could still be useful */
#if DROPBEAR_MD5_HMAC
static char * sign_key_md5_fingerprint(const unsigned char* keyblob,
unsigned int keybloblen) {
char * ret;
hash_state hs;
unsigned char hash[SHA256_HASH_SIZE];
unsigned int b64chars, start;
unsigned long b64size;
const char *prefix = "SHA256:";
int err;
unsigned char hash[MD5_HASH_SIZE];
unsigned int i;
unsigned int buflen;
sha256_init(&hs);
sha256_process(&hs, keyblob, keybloblen);
sha256_done(&hs, hash);
md5_init(&hs);
/* eg "SHA256:P9szN0L2ls6KxkVv7Bppv3asnZCn03rY7Msm/c8+ZgA"
* 256/6 = 42.66 => 43 base64 chars. OpenSSH discards
* base64 padding output. */
start = strlen(prefix);
b64chars = 43;
/* space for discarded b64 padding and null terminator */
b64size = b64chars + 4;
ret = m_malloc(start + b64size);
/* skip the size int of the string - this is a bit messy */
md5_process(&hs, keyblob, keybloblen);
memcpy(ret, prefix, start);
err = base64_encode(hash, SHA256_HASH_SIZE, &ret[start], &b64size);
if (err != CRYPT_OK) {
dropbear_exit("base64 failed");
md5_done(&hs, hash);
/* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */
buflen = 4 + 3*MD5_HASH_SIZE;
ret = (char*)m_malloc(buflen);
memset(ret, 'Z', buflen);
strcpy(ret, "md5 ");
for (i = 0; i < MD5_HASH_SIZE; i++) {
unsigned int pos = 4 + i*3;
ret[pos] = hexdig(hash[i] >> 4);
ret[pos+1] = hexdig(hash[i] & 0x0f);
ret[pos+2] = ':';
}
ret[start + b64chars] = '\0';
ret[buflen-1] = 0x0;
return ret;
}
/* This will return a freshly malloced string */
#else /* use SHA1 rather than MD5 for fingerprint */
static char * sign_key_sha1_fingerprint(const unsigned char* keyblob,
unsigned int keybloblen) {
char * ret;
hash_state hs;
unsigned char hash[SHA1_HASH_SIZE];
unsigned int i;
unsigned int buflen;
sha1_init(&hs);
/* skip the size int of the string - this is a bit messy */
sha1_process(&hs, keyblob, keybloblen);
sha1_done(&hs, hash);
/* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */
buflen = 7 + 3*SHA1_HASH_SIZE;
ret = (char*)m_malloc(buflen);
strcpy(ret, "sha1 ");
for (i = 0; i < SHA1_HASH_SIZE; i++) {
unsigned int pos = 7 + 3*i;
ret[pos] = hexdig(hash[i] >> 4);
ret[pos+1] = hexdig(hash[i] & 0x0f);
ret[pos+2] = ':';
}
ret[buflen-1] = 0x0;
return ret;
}
#endif /* MD5/SHA1 switch */
/* This will return a freshly malloced string, containing a fingerprint
* in either sha1 or md5 */
char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen) {
return sign_key_sha256_fingerprint(keyblob, keybloblen);
#if DROPBEAR_MD5_HMAC
return sign_key_md5_fingerprint(keyblob, keybloblen);
#else
return sign_key_sha1_fingerprint(keyblob, keybloblen);
#endif
}
void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
@@ -593,7 +639,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
buffer *sigblob = buf_new(MAX_PUBKEY_SIZE);
enum signkey_type keytype = signkey_type_from_signature(sigtype);
#if DEBUG_TRACE > DROPBEAR_VERBOSE_LEVEL
#if DEBUG_TRACE
{
const char* signame = signature_name_from_type(sigtype, NULL);
TRACE(("buf_put_sign type %d %s", sigtype, signame));
@@ -647,6 +693,9 @@ int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype,
TRACE(("enter buf_verify"))
printhex("buf", buf->data, buf->pos);
printhex("remw", &buf->data[buf->pos], buf->len-buf->pos);
buf_getint(buf); /* blob length */
type_name = buf_getstring(buf, &type_name_len);
sigtype = signature_type_from_name(type_name, type_name_len);
@@ -694,7 +743,7 @@ int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype,
if (keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
if (eck && *eck) {
return buf_sk_ecdsa_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen, key->sk_flags_mask);
return buf_sk_ecdsa_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen);
}
}
#endif
@@ -702,7 +751,7 @@ int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype,
if (keytype == DROPBEAR_SIGNKEY_SK_ED25519) {
dropbear_ed25519_key **eck = (dropbear_ed25519_key**)signkey_key_ptr(key, keytype);
if (eck && *eck) {
return buf_sk_ed25519_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen, key->sk_flags_mask);
return buf_sk_ed25519_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen);
}
}
#endif

View File

@@ -79,14 +79,12 @@ enum signature_type {
DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519,
#endif
#endif
#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA1
DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */
#endif
#if DROPBEAR_RSA_SHA256
DROPBEAR_SIGNATURE_RSA_SHA256 = 101, /* rsa-sha2-256 signature. has a ssh-rsa key */
#endif
#endif /* DROPBEAR_RSA */
DROPBEAR_SIGNATURE_NONE = DROPBEAR_SIGNKEY_NONE,
};
@@ -129,7 +127,6 @@ struct SIGN_key {
/* application ID for U2F/FIDO key types, a malloced string */
char * sk_app;
unsigned int sk_applen;
unsigned char sk_flags_mask;
#endif
};

View File

@@ -1,161 +0,0 @@
#include "includes.h"
#include "dbutil.h"
#include "ssh.h"
#include "signkey_ossh.h"
#include "bignum.h"
#include "ecdsa.h"
#include "sk-ecdsa.h"
#include "sk-ed25519.h"
#include "rsa.h"
#include "dss.h"
#include "ed25519.h"
#if DROPBEAR_RSA
/* OpenSSH raw private RSA format is
string "ssh-rsa"
mpint n
mpint e
mpint d
mpint iqmp (q^-1) mod p
mpint p
mpint q
*/
void buf_put_rsa_priv_ossh(buffer *buf, const sign_key *akey) {
const dropbear_rsa_key *key = akey->rsakey;
mp_int iqmp;
dropbear_assert(key != NULL);
if (!(key->p && key->q)) {
dropbear_exit("Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
}
m_mp_init(&iqmp);
/* iqmp = (q^-1) mod p */
if (mp_invmod(key->q, key->p, &iqmp) != MP_OKAY) {
dropbear_exit("Bignum error for iqmp\n");
}
buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
buf_putmpint(buf, key->n);
buf_putmpint(buf, key->e);
buf_putmpint(buf, key->d);
buf_putmpint(buf, &iqmp);
buf_putmpint(buf, key->p);
buf_putmpint(buf, key->q);
mp_clear(&iqmp);
}
int buf_get_rsa_priv_ossh(buffer *buf, sign_key *akey) {
int ret = DROPBEAR_FAILURE;
dropbear_rsa_key *key = NULL;
mp_int iqmp;
rsa_key_free(akey->rsakey);
akey->rsakey = m_malloc(sizeof(*akey->rsakey));
key = akey->rsakey;
m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
buf_eatstring(buf);
m_mp_init(&iqmp);
if (buf_getmpint(buf, key->n) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, key->e) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, key->d) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, &iqmp) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, key->p) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, key->q) == DROPBEAR_SUCCESS) {
ret = DROPBEAR_SUCCESS;
}
mp_clear(&iqmp);
return ret;
}
#endif /* DROPBEAR_RSA */
#if DROPBEAR_ED25519
/* OpenSSH raw private ed25519 format is
string "ssh-ed25519"
uint32 32
byte[32] pubkey
uint32 64
byte[32] privkey
byte[32] pubkey
*/
void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey) {
const dropbear_ed25519_key *key = akey->ed25519key;
dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
buf_putint(buf, CURVE25519_LEN);
buf_putbytes(buf, key->pub, CURVE25519_LEN);
buf_putint(buf, CURVE25519_LEN*2);
buf_putbytes(buf, key->priv, CURVE25519_LEN);
buf_putbytes(buf, key->pub, CURVE25519_LEN);
}
int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey) {
dropbear_ed25519_key *key = NULL;
uint32_t len;
ed25519_key_free(akey->ed25519key);
akey->ed25519key = m_malloc(sizeof(*akey->ed25519key));
key = akey->ed25519key;
/* Parse past the first string and pubkey */
if (buf_get_ed25519_pub_key(buf, key, DROPBEAR_SIGNKEY_ED25519)
== DROPBEAR_FAILURE) {
dropbear_log(LOG_ERR, "Error parsing ed25519 key, pubkey");
return DROPBEAR_FAILURE;
}
len = buf_getint(buf);
if (len != 2*CURVE25519_LEN) {
dropbear_log(LOG_ERR, "Error parsing ed25519 key, bad length");
return DROPBEAR_FAILURE;
}
memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
buf_incrpos(buf, CURVE25519_LEN);
/* Sanity check */
if (memcmp(buf_getptr(buf, CURVE25519_LEN), key->pub,
CURVE25519_LEN) != 0) {
dropbear_log(LOG_ERR, "Error parsing ed25519 key, mismatch pubkey");
return DROPBEAR_FAILURE;
}
return DROPBEAR_SUCCESS;
}
#endif /* DROPBEAR_ED255219 */
#if DROPBEAR_ECDSA
/* OpenSSH raw private ecdsa format is the same as Dropbear's.
# First part is the same as the SSH wire pubkey format
string "ecdsa-sha2-[identifier]"
string [identifier]
string Q
# With private part appended
mpint d
*/
void buf_put_ecdsa_priv_ossh(buffer *buf, const sign_key *key) {
ecc_key **eck = (ecc_key**)signkey_key_ptr((sign_key*)key, key->type);
if (eck && *eck) {
buf_put_ecdsa_priv_key(buf, *eck);
return;
}
dropbear_exit("ecdsa key is not set");
}
int buf_get_ecdsa_priv_ossh(buffer *buf, sign_key *key) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, key->type);
if (eck) {
if (*eck) {
ecc_free(*eck);
m_free(*eck);
*eck = NULL;
}
*eck = buf_get_ecdsa_priv_key(buf);
if (*eck) {
return DROPBEAR_SUCCESS;
}
}
return DROPBEAR_FAILURE;
}
#endif /* DROPBEAR_ECDSA */

View File

@@ -1,15 +0,0 @@
#ifndef DROPBEAR_SIGNKEY_OSSH_H_
#define DROPBEAR_SIGNKEY_OSSH_H_
#include "signkey.h"
/* Helpers for OpenSSH format keys in dropbearconvert */
void buf_put_rsa_priv_ossh(buffer *buf, const sign_key *akey);
int buf_get_rsa_priv_ossh(buffer *buf, sign_key *akey);
void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey);
int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey);
void buf_put_ecdsa_priv_ossh(buffer *buf, const sign_key *akey);
int buf_get_ecdsa_priv_ossh(buffer *buf, sign_key *akey);
#endif /* DROPBEAR_SIGNKEY_OSSH_H_ */

View File

@@ -6,11 +6,8 @@
#include "ecc.h"
#include "ecdsa.h"
#include "sk-ecdsa.h"
#include "ssh.h"
int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf,
const char* app, unsigned int applen,
unsigned char sk_flags_mask) {
int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, const char* app, unsigned int applen) {
hash_state hs;
unsigned char subhash[SHA256_HASH_SIZE];
buffer *sk_buffer = NULL, *sig_buffer = NULL;
@@ -43,19 +40,6 @@ int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf,
buf_free(sk_buffer);
buf_free(sig_buffer);
if (~flags & sk_flags_mask & SSH_SK_USER_PRESENCE_REQD) {
if (ret == DROPBEAR_SUCCESS) {
dropbear_log(LOG_WARNING, "Rejecting, user-presence not set");
}
ret = DROPBEAR_FAILURE;
}
if (~flags & sk_flags_mask & SSH_SK_USER_VERIFICATION_REQD) {
if (ret == DROPBEAR_SUCCESS) {
dropbear_log(LOG_WARNING, "Rejecting, user-verification not set");
}
ret = DROPBEAR_FAILURE;
}
TRACE(("leave buf_sk_ecdsa_verify, ret=%d", ret))
return ret;
}

View File

@@ -8,9 +8,7 @@
#include "buffer.h"
#include "signkey.h"
int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf,
const char* app, unsigned int applen,
unsigned char sk_flags_mask);
int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, const char* app, unsigned int applen);
#endif

View File

@@ -6,11 +6,8 @@
#include "buffer.h"
#include "curve25519.h"
#include "ed25519.h"
#include "ssh.h"
int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf,
const char* app, unsigned int applen,
unsigned char sk_flags_mask) {
int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, const char* app, unsigned int applen) {
int ret = DROPBEAR_FAILURE;
unsigned char *s;
@@ -34,7 +31,6 @@ int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const bu
flags = buf_getbyte (buf);
counter = buf_getint (buf);
/* create the message to be signed */
sk_buffer = buf_new (2*SHA256_HASH_SIZE+5);
sha256_init (&hs);
sha256_process (&hs, app, applen);
@@ -54,20 +50,10 @@ int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const bu
ret = DROPBEAR_SUCCESS;
}
if (~flags & sk_flags_mask & SSH_SK_USER_PRESENCE_REQD) {
if (ret == DROPBEAR_SUCCESS) {
dropbear_log(LOG_WARNING, "Rejecting, user-presence not set");
}
ret = DROPBEAR_FAILURE;
}
if (~flags & sk_flags_mask & SSH_SK_USER_VERIFICATION_REQD) {
if (ret == DROPBEAR_SUCCESS) {
dropbear_log(LOG_WARNING, "Rejecting, user-verification not set");
}
ret = DROPBEAR_FAILURE;
}
out:
buf_free(sk_buffer);
if (sk_buffer) {
buf_free(sk_buffer);
}
TRACE(("leave buf_sk_ed25519_verify: ret %d", ret))
return ret;
}

View File

@@ -8,9 +8,7 @@
#include "buffer.h"
#include "ed25519.h"
int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf,
const char* app, unsigned int applen,
unsigned char sk_flags_mask);
int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, const char* app, unsigned int applen);
#endif

5
ssh.h
View File

@@ -126,8 +126,3 @@
#define SSH2_AGENT_SIGN_RESPONSE 14
#define SSH2_AGENT_FAILURE 30
/* Flags defined by OpenSSH U2F key/signature format */
#define SSH_SK_USER_PRESENCE_REQD 0x01
#define SSH_SK_USER_VERIFICATION_REQD 0x04
#define SSH_SK_RESIDENT_KEY 0x20

View File

@@ -380,9 +380,7 @@ pty_setowner(struct passwd *pw, const char *tty_name)
tty_name, strerror(errno));
}
/* Allow either "tty" gid or user's own gid. On Linux with openpty()
* this varies depending on the devpts mount options */
if (st.st_uid != pw->pw_uid || !(st.st_gid == gid || st.st_gid == pw->pw_gid)) {
if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
if (chown(tty_name, pw->pw_uid, gid) < 0) {
if (errno == EROFS &&
(st.st_uid == pw->pw_uid || st.st_uid == 0)) {

View File

@@ -389,7 +389,7 @@ void send_msg_userauth_failure(int partial, int incrfail) {
Beware of integer overflow if increasing these values */
const unsigned int mindelay = 250000000;
const unsigned int vardelay = 100000000;
suseconds_t rand_delay;
unsigned int rand_delay;
struct timespec delay;
gettime_wrapper(&delay);

View File

@@ -30,7 +30,6 @@
#include "buffer.h"
#include "dbutil.h"
#include "auth.h"
#include "runopts.h"
#if DROPBEAR_SVR_PAM_AUTH
@@ -279,22 +278,12 @@ void svr_auth_pam(int valid_user) {
goto cleanup;
}
if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PASSWORD)) {
/* successful PAM password authentication, but extra auth required */
dropbear_log(LOG_NOTICE,
"PAM password auth succeeded for '%s' from %s, extra auth required",
ses.authstate.pw_name,
svr_ses.addrstring);
ses.authstate.authtypes &= ~AUTH_TYPE_PASSWORD; /* PAM password auth ok, delete the method flag */
send_msg_userauth_failure(1, 0); /* Send partial success */
} else {
/* successful authentication */
dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_success();
}
/* successful authentication */
dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_success();
cleanup:
if (password != NULL) {
m_burn(password, passwordlen);

View File

@@ -106,22 +106,12 @@ void svr_auth_password(int valid_user) {
}
if (constant_time_strcmp(testcrypt, passwdcrypt) == 0) {
if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PASSWORD)) {
/* successful password authentication, but extra auth required */
dropbear_log(LOG_NOTICE,
"Password auth succeeded for '%s' from %s, extra auth required",
ses.authstate.pw_name,
svr_ses.addrstring);
ses.authstate.authtypes &= ~AUTH_TYPE_PASSWORD; /* password auth ok, delete the method flag */
send_msg_userauth_failure(1, 0); /* Send partial success */
} else {
/* successful authentication */
dropbear_log(LOG_NOTICE,
"Password auth succeeded for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_success();
}
/* successful authentication */
dropbear_log(LOG_NOTICE,
"Password auth succeeded for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_success();
} else {
dropbear_log(LOG_WARNING,
"Bad password attempt for '%s' from %s",

View File

@@ -1,19 +1,19 @@
/*
* 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
@@ -22,11 +22,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
/*
* This file incorporates work covered by the following copyright and
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,7 +35,7 @@
* 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.
@@ -48,7 +48,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This copyright and permission notice applies to the code parsing public keys
* options string which can also be found in OpenSSH auth2-pubkey.c file
* options string which can also be found in OpenSSH auth2-pubkey.c file
* (user_key_allowed2). It has been adapted to work with buffers.
*
*/
@@ -64,7 +64,6 @@
#include "ssh.h"
#include "packet.h"
#include "algo.h"
#include "runopts.h"
#if DROPBEAR_SVR_PUBKEY_AUTH
@@ -109,7 +108,7 @@ void svr_auth_pubkey(int valid_user) {
if (!valid_user) {
/* Return failure once we have read the contents of the packet
required to validate a public key.
required to validate a public key.
Avoids blind user enumeration though it isn't possible to prevent
testing for user existence if the public key is known */
send_msg_userauth_failure(0, 0);
@@ -131,9 +130,9 @@ void svr_auth_pubkey(int valid_user) {
if (svr_ses.plugin_instance->checkpubkey(
svr_ses.plugin_instance,
&ses.plugin_session,
keyalgo,
keyalgolen,
keyblob,
keyalgo,
keyalgolen,
keyblob,
keybloblen,
ses.authstate.username) == DROPBEAR_SUCCESS) {
/* Success */
@@ -142,7 +141,7 @@ void svr_auth_pubkey(int valid_user) {
/* Options provided? */
options_buf = ses.plugin_session->get_options(ses.plugin_session);
if (options_buf) {
struct buf temp_buf = {
struct buf temp_buf = {
.data = (unsigned char *)options_buf,
.len = strlen(options_buf),
.pos = 0,
@@ -175,7 +174,7 @@ void svr_auth_pubkey(int valid_user) {
}
/* now we can actually verify the signature */
/* get the key */
key = new_sign_key();
if (buf_get_pub_key(ses.payload, key, &keytype) == DROPBEAR_FAILURE) {
@@ -183,16 +182,6 @@ void svr_auth_pubkey(int valid_user) {
goto out;
}
#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
key->sk_flags_mask = SSH_SK_USER_PRESENCE_REQD;
if (ses.authstate.pubkey_options && ses.authstate.pubkey_options->no_touch_required_flag) {
key->sk_flags_mask &= ~SSH_SK_USER_PRESENCE_REQD;
}
if (ses.authstate.pubkey_options && ses.authstate.pubkey_options->verify_required_flag) {
key->sk_flags_mask |= SSH_SK_USER_VERIFICATION_REQD;
}
#endif
/* create the data which has been signed - this a string containing
* session_id, concatenated with the payload packet up to the signature */
assert(ses.payload_beginning <= ses.payload->pos);
@@ -202,7 +191,7 @@ void svr_auth_pubkey(int valid_user) {
/* The entire contents of the payload prior. */
buf_setpos(ses.payload, ses.payload_beginning);
buf_putbytes(signbuf,
buf_putbytes(signbuf,
buf_getptr(ses.payload, sign_payload_length),
sign_payload_length);
buf_incrpos(ses.payload, sign_payload_length);
@@ -212,30 +201,17 @@ void svr_auth_pubkey(int valid_user) {
/* ... and finally verify the signature */
fp = sign_key_fingerprint(keyblob, keybloblen);
if (buf_verify(ses.payload, key, sigtype, signbuf) == DROPBEAR_SUCCESS) {
if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PUBKEY)) {
/* successful pubkey authentication, but extra auth required */
dropbear_log(LOG_NOTICE,
"Pubkey auth succeeded for '%s' with %s key %s from %s, extra auth required",
ses.authstate.pw_name,
signkey_name_from_type(keytype, NULL), fp,
svr_ses.addrstring);
ses.authstate.authtypes &= ~AUTH_TYPE_PUBKEY; /* pubkey auth ok, delete the method flag */
send_msg_userauth_failure(1, 0); /* Send partial success */
} else {
/* successful authentication */
dropbear_log(LOG_NOTICE,
"Pubkey auth succeeded for '%s' with %s key %s from %s",
ses.authstate.pw_name,
signkey_name_from_type(keytype, NULL), fp,
svr_ses.addrstring);
send_msg_userauth_success();
}
dropbear_log(LOG_NOTICE,
"Pubkey auth succeeded for '%s' with key %s from %s",
ses.authstate.pw_name, fp, svr_ses.addrstring);
send_msg_userauth_success();
#if DROPBEAR_PLUGIN
if ((ses.plugin_session != NULL) && (svr_ses.plugin_instance->auth_success != NULL)) {
/* Was authenticated through the external plugin. tell plugin that signature verification was ok */
svr_ses.plugin_instance->auth_success(ses.plugin_session);
}
#endif
} else {
dropbear_log(LOG_WARNING,
"Pubkey auth bad signature for '%s' with key %s from %s",
@@ -281,15 +257,11 @@ static void send_msg_userauth_pk_ok(const char* sigalgo, unsigned int sigalgolen
}
/* Content for SSH_PUBKEYINFO is optionally returned malloced in ret_info (will be
freed if already set */
static int checkpubkey_line(buffer* line, int line_num, const char* filename,
const char* algo, unsigned int algolen,
const unsigned char* keyblob, unsigned int keybloblen,
char ** ret_info) {
const unsigned char* keyblob, unsigned int keybloblen) {
buffer *options_buf = NULL;
char *info_str = NULL;
unsigned int pos, len, infopos, infolen;
unsigned int pos, len;
int ret = DROPBEAR_FAILURE;
if (line->len < MIN_AUTHKEYS_LINE || line->len > MAX_AUTHKEYS_LINE) {
@@ -312,7 +284,7 @@ static int checkpubkey_line(buffer* line, int line_num, const char* filename,
unsigned char *options_start = NULL;
int options_len = 0;
int escape, quoted;
/* skip over any comments or leading whitespace */
while (line->pos < line->len) {
const char c = buf_getbyte(line);
@@ -335,7 +307,7 @@ static int checkpubkey_line(buffer* line, int line_num, const char* filename,
quoted = 0;
escape = 0;
options_len = 0;
/* figure out where the options are */
while (line->pos < line->len) {
const char c = buf_getbyte(line);
@@ -360,43 +332,18 @@ static int checkpubkey_line(buffer* line, int line_num, const char* filename,
}
}
buf_incrpos(line, algolen);
/* check for space (' ') character */
if (buf_getbyte(line) != ' ') {
TRACE(("checkpubkey_line: space character expected, isn't there"))
goto out;
}
/* find the length of base64 data */
/* truncate the line at the space after the base64 data */
pos = line->pos;
for (len = 0; line->pos < line->len; len++) {
if (buf_getbyte(line) == ' ') {
break;
}
}
/* find out the length of the public key info, stop at the first space */
infopos = line->pos;
for (infolen = 0; line->pos < line->len; infolen++) {
const char c = buf_getbyte(line);
if (c == ' ') {
break;
}
/* We have an allowlist - authorized_keys lines can't be fully trusted,
some shell scripts may do unsafe things with env var values */
if (!(isalnum(c) || strchr(".,_-+@", c))) {
TRACE(("Not setting SSH_PUBKEYINFO, special characters"))
infolen = 0;
break;
}
}
if (infolen > 0) {
info_str = m_malloc(infolen + 1);
buf_setpos(line, infopos);
strncpy(info_str, buf_getptr(line, infolen), infolen);
}
/* truncate to base64 data length */
if (buf_getbyte(line) == ' ') break;
}
buf_setpos(line, pos);
buf_setlen(line, line->pos + len);
@@ -404,30 +351,14 @@ static int checkpubkey_line(buffer* line, int line_num, const char* filename,
ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algo, algolen, line, NULL);
/* free pubkey_info if it is filled */
if (ret_info && *ret_info) {
m_free(*ret_info);
*ret_info = NULL;
}
if (ret == DROPBEAR_SUCCESS) {
if (options_buf) {
ret = svr_add_pubkey_options(options_buf, line_num, filename);
}
if (ret_info) {
/* take the (optional) public key information */
*ret_info = info_str;
info_str = NULL;
}
if (ret == DROPBEAR_SUCCESS && options_buf) {
ret = svr_add_pubkey_options(options_buf, line_num, filename);
}
out:
if (options_buf) {
buf_free(options_buf);
}
if (info_str) {
m_free(info_str);
}
return ret;
}
@@ -449,8 +380,23 @@ static int checkpubkey(const char* keyalgo, unsigned int keyalgolen,
TRACE(("enter checkpubkey"))
/* check file permissions, also whether file exists */
if (checkpubkeyperms() == DROPBEAR_FAILURE) {
TRACE(("bad authorized_keys permissions, or file doesn't exist"))
goto out;
}
/* we don't need to check pw and pw_dir for validity, since
* its been done in checkpubkeyperms. */
len = strlen(ses.authstate.pw_dir);
/* allocate max required pathname storage,
* = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
filename = m_malloc(len + 22);
snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
ses.authstate.pw_dir);
#if DROPBEAR_SVR_MULTIUSER
/* access the file as the authenticating user. */
/* open the file as the authenticating user. */
origuid = getuid();
origgid = getgid();
if ((setegid(ses.authstate.pw_gid)) < 0 ||
@@ -458,24 +404,9 @@ static int checkpubkey(const char* keyalgo, unsigned int keyalgolen,
dropbear_exit("Failed to set euid");
}
#endif
/* check file permissions, also whether file exists */
if (checkpubkeyperms() == DROPBEAR_FAILURE) {
TRACE(("bad authorized_keys permissions, or file doesn't exist"))
} else {
/* we don't need to check pw and pw_dir for validity, since
* its been done in checkpubkeyperms. */
len = strlen(ses.authstate.pw_dir);
/* allocate max required pathname storage,
* = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
filename = m_malloc(len + 22);
snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
ses.authstate.pw_dir);
authfile = fopen(filename, "r");
if (!authfile) {
TRACE(("checkpubkey: failed opening %s: %s", filename, strerror(errno)))
}
}
authfile = fopen(filename, "r");
#if DROPBEAR_SVR_MULTIUSER
if ((seteuid(origuid)) < 0 ||
(setegid(origgid)) < 0) {
@@ -500,13 +431,13 @@ static int checkpubkey(const char* keyalgo, unsigned int keyalgolen,
}
line_num++;
ret = checkpubkey_line(line, line_num, filename, keyalgo, keyalgolen,
keyblob, keybloblen, &ses.authstate.pubkey_info);
ret = checkpubkey_line(line, line_num, filename, keyalgo, keyalgolen, keyblob, keybloblen);
if (ret == DROPBEAR_SUCCESS) {
break;
}
/* We continue to the next line otherwise */
} while (1);
out:
@@ -529,7 +460,7 @@ out:
* g-w, o-w */
static int checkpubkeyperms() {
char* filename = NULL;
char* filename = NULL;
int ret = DROPBEAR_FAILURE;
unsigned int len;
@@ -568,7 +499,7 @@ static int checkpubkeyperms() {
/* file looks ok, return success */
ret = DROPBEAR_SUCCESS;
out:
m_free(filename);
@@ -603,7 +534,7 @@ static int checkfileperm(char * filename) {
if (badperm) {
if (!ses.authstate.perm_warn) {
ses.authstate.perm_warn = 1;
dropbear_log(LOG_INFO, "%s must be owned by user or root, and not writable by group or others", filename);
dropbear_log(LOG_INFO, "%s must be owned by user or root, and not writable by others", filename);
}
TRACE(("leave checkfileperm: failure perms/owner"))
return DROPBEAR_FAILURE;
@@ -617,7 +548,7 @@ static int checkfileperm(char * filename) {
int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
const char* algo, unsigned int algolen,
const unsigned char* keyblob, unsigned int keybloblen) {
return checkpubkey_line(line, line_num, filename, algo, algolen, keyblob, keybloblen, NULL);
return checkpubkey_line(line, line_num, filename, algo, algolen, keyblob, keybloblen);
}
#endif

View File

@@ -46,7 +46,6 @@
#include "dbutil.h"
#include "signkey.h"
#include "auth.h"
#include "runopts.h"
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
@@ -89,29 +88,6 @@ int svr_pubkey_allows_pty() {
return 1;
}
/* Returns 1 if pubkey allows local tcp fowarding to the provided destination,
* 0 otherwise */
int svr_pubkey_allows_local_tcpfwd(const char *host, unsigned int port) {
if (ses.authstate.pubkey_options
&& ses.authstate.pubkey_options->permit_open_destinations) {
m_list_elem *iter = ses.authstate.pubkey_options->permit_open_destinations->first;
while (iter) {
struct PermitTCPFwdEntry *entry = (struct PermitTCPFwdEntry*)iter->item;
if (strcmp(entry->host, host) == 0) {
if ((entry->port == PUBKEY_OPTIONS_ANY_PORT) || (entry->port == port)) {
return 1;
}
}
iter = iter->next;
}
return 0;
}
return 1;
}
/* Set chansession command to the one forced
* by any 'command' public key option. */
void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
@@ -137,21 +113,8 @@ void svr_pubkey_options_cleanup() {
if (ses.authstate.pubkey_options->forced_command) {
m_free(ses.authstate.pubkey_options->forced_command);
}
if (ses.authstate.pubkey_options->permit_open_destinations) {
m_list_elem *iter = ses.authstate.pubkey_options->permit_open_destinations->first;
while (iter) {
struct PermitTCPFwdEntry *entry = (struct PermitTCPFwdEntry*)list_remove(iter);
m_free(entry->host);
m_free(entry);
iter = ses.authstate.pubkey_options->permit_open_destinations->first;
}
m_free(ses.authstate.pubkey_options->permit_open_destinations);
}
m_free(ses.authstate.pubkey_options);
}
if (ses.authstate.pubkey_info) {
m_free(ses.authstate.pubkey_info);
}
}
/* helper for svr_add_pubkey_options. returns DROPBEAR_SUCCESS if the option is matched,
@@ -240,69 +203,6 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
goto bad_option;
}
if (match_option(options_buf, "permitopen=\"") == DROPBEAR_SUCCESS) {
int valid_option = 0;
const unsigned char* permitopen_start = buf_getptr(options_buf, 0);
if (!ses.authstate.pubkey_options->permit_open_destinations) {
ses.authstate.pubkey_options->permit_open_destinations = list_new();
}
while (options_buf->pos < options_buf->len) {
const char c = buf_getbyte(options_buf);
if (c == '"') {
char *spec = NULL;
char *portstring = NULL;
const int permitopen_len = buf_getptr(options_buf, 0) - permitopen_start;
struct PermitTCPFwdEntry *entry =
(struct PermitTCPFwdEntry*)m_malloc(sizeof(struct PermitTCPFwdEntry));
list_append(ses.authstate.pubkey_options->permit_open_destinations, entry);
spec = m_malloc(permitopen_len);
memcpy(spec, permitopen_start, permitopen_len - 1);
spec[permitopen_len - 1] = '\0';
if ((split_address_port(spec, &entry->host, &portstring) == DROPBEAR_SUCCESS)
&& entry->host && portstring) {
if (strcmp(portstring, "*") == 0) {
valid_option = 1;
entry->port = PUBKEY_OPTIONS_ANY_PORT;
TRACE(("local port forwarding allowed to host '%s'", entry->host));
} else if (m_str_to_uint(portstring, &entry->port) == DROPBEAR_SUCCESS) {
valid_option = 1;
TRACE(("local port forwarding allowed to host '%s' and port '%u'",
entry->host, entry->port));
}
}
m_free(spec);
m_free(portstring);
break;
}
}
if (valid_option) {
goto next_option;
} else {
dropbear_log(LOG_WARNING, "Badly formatted permitopen= authorized_keys option");
goto bad_option;
}
}
if (match_option(options_buf, "no-touch-required") == DROPBEAR_SUCCESS) {
#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
dropbear_log(LOG_WARNING, "No user presence check required for U2F/FIDO key.");
ses.authstate.pubkey_options->no_touch_required_flag = 1;
#endif
goto next_option;
}
if (match_option(options_buf, "verify-required") == DROPBEAR_SUCCESS) {
#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
dropbear_log(LOG_WARNING, "User verification required for U2F/FIDO key.");
ses.authstate.pubkey_options->verify_required_flag = 1;
#endif
goto next_option;
}
next_option:
/*
* Skip the comma, and move to the next option

View File

@@ -72,6 +72,9 @@ const struct ChanType svrchansess = {
cleanupchansess /* cleanup */
};
/* required to clear environment */
extern char** environ;
/* Returns whether the channel is ready to close. The child process
must not be running (has never started, or has exited) */
static int sesscheckclose(struct Channel *channel) {
@@ -274,8 +277,7 @@ static int newchansess(struct Channel *channel) {
chansess->agentdir = NULL;
#endif
/* Will drop to DROPBEAR_PRIO_NORMAL if a non-tty command starts */
channel->prio = DROPBEAR_PRIO_LOWDELAY;
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
return 0;
@@ -685,10 +687,8 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
if (issubsys) {
#if DROPBEAR_SFTPSERVER
if ((cmdlen == 4) && strncmp(chansess->cmd, "sftp", 4) == 0) {
char *expand_path = expand_homedir_path(SFTPSERVER_PATH);
m_free(chansess->cmd);
chansess->cmd = m_strdup(expand_path);
m_free(expand_path);
chansess->cmd = m_strdup(SFTPSERVER_PATH);
} else
#endif
{
@@ -734,7 +734,7 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
/* no pty */
ret = noptycommand(channel, chansess);
if (ret == DROPBEAR_SUCCESS) {
channel->prio = DROPBEAR_PRIO_NORMAL;
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
update_channel_prio();
}
} else {
@@ -851,6 +851,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
* the wtmp login will not be recorded */
li = chansess_login_alloc(chansess);
login_login(li);
dropbear_log(LOG_WARNING, "bad thing happened");
login_free_entry(li);
/* Can now dup2 stderr. Messages from login_login() have gone
@@ -873,11 +874,9 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
snprintf(hushpath, len, "%s/.hushlogin", ses.authstate.pw_dir);
if (stat(hushpath, &sb) < 0) {
char *expand_path = NULL;
/* more than a screenful is stupid IMHO */
motdbuf = buf_new(80 * 25);
expand_path = expand_homedir_path(MOTD_FILENAME);
if (buf_readfile(motdbuf, expand_path) == DROPBEAR_SUCCESS) {
if (buf_readfile(motdbuf, MOTD_FILENAME) == DROPBEAR_SUCCESS) {
buf_setpos(motdbuf, 0);
while (motdbuf->pos != motdbuf->len) {
len = motdbuf->len - motdbuf->pos;
@@ -886,9 +885,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
buf_incrpos(motdbuf, len);
}
}
m_free(expand_path);
buf_free(motdbuf);
}
m_free(hushpath);
}
@@ -1012,11 +1009,7 @@ static void execchild(const void *user_data) {
addnewvar("LOGNAME", ses.authstate.pw_name);
addnewvar("HOME", ses.authstate.pw_dir);
addnewvar("SHELL", get_user_shell());
if (getuid() == 0) {
addnewvar("PATH", DEFAULT_ROOT_PATH);
} else {
addnewvar("PATH", DEFAULT_PATH);
}
addnewvar("PATH", DEFAULT_PATH);
if (cp != NULL) {
addnewvar("LANG", cp);
m_free(cp);
@@ -1040,22 +1033,12 @@ static void execchild(const void *user_data) {
if (chansess->original_command) {
addnewvar("SSH_ORIGINAL_COMMAND", chansess->original_command);
}
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
if (ses.authstate.pubkey_info != NULL) {
addnewvar("SSH_PUBKEYINFO", ses.authstate.pubkey_info);
}
#endif
/* change directory */
if (chdir(ses.authstate.pw_dir) < 0) {
int e = errno;
if (chdir("/") < 0) {
dropbear_exit("chdir(\"/\") failed");
}
fprintf(stderr, "Failed chdir '%s': %s\n", ses.authstate.pw_dir, strerror(e));
dropbear_exit("Error changing directory");
}
#if DROPBEAR_X11FWD
/* set up X11 forwarding if enabled */
x11setauth(chansess);

View File

@@ -106,7 +106,6 @@ void recv_msg_kexdh_init() {
static void svr_ensure_hostkey() {
const char* fn = NULL;
char *expand_fn = NULL;
enum signkey_type type = ses.newkeys->algo_hostkey;
void **hostkey = signkey_key_ptr(svr_opts.hostkey, type);
int ret = DROPBEAR_FAILURE;
@@ -143,19 +142,15 @@ static void svr_ensure_hostkey() {
dropbear_assert(0);
}
expand_fn = expand_homedir_path(fn);
ret = readhostkey(expand_fn, svr_opts.hostkey, &type);
if (ret == DROPBEAR_SUCCESS) {
goto out;
if (readhostkey(fn, svr_opts.hostkey, &type) == DROPBEAR_SUCCESS) {
return;
}
if (signkey_generate(type, 0, expand_fn, 1) == DROPBEAR_FAILURE) {
if (signkey_generate(type, 0, fn, 1) == DROPBEAR_FAILURE) {
goto out;
}
/* Read what we just generated (or another process raced us) */
ret = readhostkey(expand_fn, svr_opts.hostkey, &type);
ret = readhostkey(fn, svr_opts.hostkey, &type);
if (ret == DROPBEAR_SUCCESS) {
char *fp = NULL;
@@ -166,16 +161,16 @@ static void svr_ensure_hostkey() {
len = key_buf->len - key_buf->pos;
fp = sign_key_fingerprint(buf_getptr(key_buf, len), len);
dropbear_log(LOG_INFO, "Generated hostkey %s, fingerprint is %s",
expand_fn, fp);
fn, fp);
m_free(fp);
buf_free(key_buf);
}
out:
if (ret == DROPBEAR_FAILURE) {
dropbear_exit("Couldn't read or generate hostkey %s", expand_fn);
if (ret == DROPBEAR_FAILURE)
{
dropbear_exit("Couldn't read or generate hostkey %s", fn);
}
m_free(expand_fn);
}
#endif

View File

@@ -35,30 +35,26 @@ static size_t listensockets(int *sock, size_t sockcount, int *maxfd);
static void sigchld_handler(int dummy);
static void sigsegv_handler(int);
static void sigintterm_handler(int fish);
#if INETD_MODE
static void main_inetd(void);
static void main_noinetd(int argc, char ** argv, const char* multipath);
#endif
#if NON_INETD_MODE
static void main_noinetd(void);
#endif
static void commonsetup(void);
#if defined(DBMULTI_dropbear) || !DROPBEAR_MULTI
#if defined(DBMULTI_dropbear) && DROPBEAR_MULTI
int dropbear_main(int argc, char ** argv, const char* multipath)
int dropbear_main(int argc, char ** argv)
#else
int main(int argc, char ** argv)
#endif
{
#if !DROPBEAR_MULTI
const char* multipath = NULL;
#endif
_dropbear_exit = svr_dropbear_exit;
_dropbear_log = svr_dropbear_log;
disallow_core();
if (argc < 1) {
dropbear_exit("Bad argc");
}
/* get commandline options */
svr_getopts(argc, argv);
@@ -70,21 +66,8 @@ int main(int argc, char ** argv)
}
#endif
#if DROPBEAR_DO_REEXEC
if (svr_opts.reexec_childpipe >= 0) {
#ifdef PR_SET_NAME
/* Fix the "Name:" in /proc/pid/status, otherwise it's
a FD number from fexecve.
Failure doesn't really matter, it's mostly aesthetic */
prctl(PR_SET_NAME, basename(argv[0]), 0, 0);
#endif
main_inetd();
/* notreached */
}
#endif
#if NON_INETD_MODE
main_noinetd(argc, argv, multipath);
main_noinetd();
/* notreached */
#endif
@@ -93,7 +76,7 @@ int main(int argc, char ** argv)
}
#endif
#if INETD_MODE || DROPBEAR_DO_REEXEC
#if INETD_MODE
static void main_inetd() {
char *host, *port = NULL;
@@ -102,28 +85,35 @@ static void main_inetd() {
seedrandom();
if (svr_opts.reexec_childpipe < 0) {
/* In case our inetd was lax in logging source addresses */
get_socket_address(0, NULL, NULL, &host, &port, 0);
dropbear_log(LOG_INFO, "Child connection from %s:%s", host, port);
m_free(host);
m_free(port);
/* Don't check the return value - it may just fail since inetd has
* already done setsid() after forking (xinetd on Darwin appears to do
* this */
setsid();
#if DEBUG_TRACE
if (debug_trace) {
/* -v output goes to stderr which would get sent over the inetd network socket */
dropbear_exit("Dropbear inetd mode is incompatible with debug -v");
}
#endif
/* -1 for childpipe in the inetd case is discarded */
svr_session(0, svr_opts.reexec_childpipe);
/* In case our inetd was lax in logging source addresses */
get_socket_address(0, NULL, NULL, &host, &port, 0);
dropbear_log(LOG_INFO, "Child connection from %s:%s", host, port);
m_free(host);
m_free(port);
/* Don't check the return value - it may just fail since inetd has
* already done setsid() after forking (xinetd on Darwin appears to do
* this */
setsid();
/* Start service program
* -1 is a dummy childpipe, just something we can close() without
* mattering. */
svr_session(0, -1);
/* notreached */
}
#endif /* INETD_MODE */
#if NON_INETD_MODE
static void main_noinetd(int argc, char ** argv, const char* multipath) {
static void main_noinetd() {
fd_set fds;
unsigned int i, j;
int val;
@@ -131,7 +121,6 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) {
int listensocks[MAX_LISTEN_ADDR];
size_t listensockcount = 0;
FILE *pidfile = NULL;
int execfd = -1;
int childpipes[MAX_UNAUTH_CLIENTS];
char * preauth_addrs[MAX_UNAUTH_CLIENTS];
@@ -139,10 +128,6 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) {
int childsock;
int childpipe[2];
(void)argc;
(void)argv;
(void)multipath;
/* Note: commonsetup() must happen before we daemon()ise. Otherwise
daemon() will chdir("/"), and we won't be able to find local-dir
hostkeys. */
@@ -153,7 +138,7 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) {
childpipes[i] = -1;
}
memset(preauth_addrs, 0x0, sizeof(preauth_addrs));
/* Set up the listening sockets */
listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock);
if (listensockcount == 0)
@@ -165,18 +150,6 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) {
FD_SET(listensocks[i], &fds);
}
#if DROPBEAR_DO_REEXEC
if (multipath) {
execfd = open(multipath, O_CLOEXEC|O_RDONLY);
} else {
execfd = open(argv[0], O_CLOEXEC|O_RDONLY);
}
if (execfd < 0) {
/* Just fallback to straight fork */
TRACE(("Couldn't open own binary %s, disabling re-exec: %s", argv[0], strerror(errno)))
}
#endif
/* fork */
if (svr_opts.forkbg) {
int closefds = 0;
@@ -208,7 +181,7 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) {
for(;;) {
DROPBEAR_FD_ZERO(&fds);
/* listening sockets */
for (i = 0; i < listensockcount; i++) {
FD_SET(listensocks[i], &fds);
@@ -228,7 +201,7 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) {
unlink(svr_opts.pidfile);
dropbear_exit("Terminated by signal");
}
if (val == 0) {
/* timeout reached - shouldn't happen. eh */
continue;
@@ -313,7 +286,7 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) {
}
addrandom((void*)&fork_ret, sizeof(fork_ret));
if (fork_ret > 0) {
/* parent */
@@ -330,7 +303,7 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) {
m_free(remote_host);
m_free(remote_port);
#if !DEBUG_NOFORK
#ifndef DEBUG_NOFORK
if (setsid() < 0) {
dropbear_exit("setsid: %s", strerror(errno));
}
@@ -343,44 +316,6 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) {
m_close(childpipe[0]);
if (execfd >= 0) {
#if DROPBEAR_DO_REEXEC
/* Add "-2 childpipe[1]" to the args and re-execute ourself. */
char **new_argv = m_malloc(sizeof(char*) * (argc+4));
char buf[10];
int pos0 = 0, new_argc = argc+2;
/* We need to specially handle "dropbearmulti dropbear". */
if (multipath) {
new_argv[0] = (char*)multipath;
pos0 = 1;
new_argc++;
}
memcpy(&new_argv[pos0], argv, sizeof(char*) * argc);
new_argv[new_argc-2] = "-2";
snprintf(buf, sizeof(buf), "%d", childpipe[1]);
new_argv[new_argc-1] = buf;
new_argv[new_argc] = NULL;
if ((dup2(childsock, STDIN_FILENO) < 0)) {
dropbear_exit("dup2 failed: %s", strerror(errno));
}
if (fcntl(childsock, F_SETFD, FD_CLOEXEC) < 0) {
TRACE(("cloexec for childsock %d failed: %s", childsock, strerror(errno)))
}
/* Re-execute ourself */
fexecve(execfd, new_argv, environ);
/* Not reached on success */
/* Fall back on plain fork otherwise.
* To be removed in future once re-exec has been well tested */
dropbear_log(LOG_WARNING, "fexecve failed, disabling re-exec: %s", strerror(errno));
m_close(STDIN_FILENO);
m_free(new_argv);
#endif /* DROPBEAR_DO_REEXEC */
}
/* start the session */
svr_session(childsock, childpipe[1]);
/* don't return */

View File

@@ -81,7 +81,6 @@ static void printhelp(const char * progname) {
"-s Disable password logins\n"
"-g Disable password logins for root\n"
"-B Allow blank password logins\n"
"-t Enable two-factor authentication (both password and public key required)\n"
#endif
"-T Maximum authentication tries (default %d)\n"
#if DROPBEAR_SVR_LOCALTCPFWD
@@ -104,14 +103,13 @@ static void printhelp(const char * progname) {
"-W <receive_window_buffer> (default %d, larger may be faster, max 10MB)\n"
"-K <keepalive> (0 is never, default %d, in seconds)\n"
"-I <idle_timeout> (0 is never, default %d, in seconds)\n"
"-z disable QoS\n"
#if DROPBEAR_PLUGIN
"-A <authplugin>[,<options>]\n"
" Enable external public key auth through <authplugin>\n"
#endif
"-V Version\n"
#if DEBUG_TRACE
"-v verbose (repeat for more verbose)\n"
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
,DROPBEAR_VERSION, progname,
#if DROPBEAR_DSS
@@ -140,7 +138,6 @@ void svr_getopts(int argc, char ** argv) {
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char* maxauthtries_arg = NULL;
char* reexec_fd_arg = NULL;
char* keyfile = NULL;
char c;
#if DROPBEAR_PLUGIN
@@ -161,13 +158,12 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.noauthpass = 0;
svr_opts.norootpass = 0;
svr_opts.allowblankpass = 0;
svr_opts.multiauthmethod = 0;
svr_opts.maxauthtries = MAX_AUTH_TRIES;
svr_opts.inetdmode = 0;
svr_opts.portcount = 0;
svr_opts.hostkey = NULL;
svr_opts.delay_hostkey = 0;
svr_opts.pidfile = expand_homedir_path(DROPBEAR_PIDFILE);
svr_opts.pidfile = DROPBEAR_PIDFILE;
#if DROPBEAR_SVR_LOCALTCPFWD
svr_opts.nolocaltcp = 0;
#endif
@@ -179,7 +175,6 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.pubkey_plugin_options = NULL;
#endif
svr_opts.pass_on_env = 0;
svr_opts.reexec_childpipe = -1;
#ifndef DISABLE_ZLIB
opts.compress_mode = DROPBEAR_COMPRESS_DELAYED;
@@ -202,7 +197,6 @@ void svr_getopts(int argc, char ** argv) {
#if DROPBEAR_SVR_REMOTETCPFWD
opts.listen_fwd_all = 0;
#endif
opts.disable_ip_tos = 0;
for (i = 1; i < (unsigned int)argc; i++) {
if (argv[i][0] != '-' || argv[i][1] == '\0')
@@ -252,16 +246,10 @@ void svr_getopts(int argc, char ** argv) {
case 'i':
svr_opts.inetdmode = 1;
break;
#endif
#if DROPBEAR_DO_REEXEC && NON_INETD_MODE
/* For internal use by re-exec */
case '2':
next = &reexec_fd_arg;
break;
#endif
case 'p':
nextisport = 1;
break;
nextisport = 1;
break;
case 'P':
next = &svr_opts.pidfile;
break;
@@ -301,9 +289,6 @@ void svr_getopts(int argc, char ** argv) {
case 'B':
svr_opts.allowblankpass = 1;
break;
case 't':
svr_opts.multiauthmethod = 1;
break;
#endif
case 'h':
printhelp(argv[0]);
@@ -319,16 +304,13 @@ void svr_getopts(int argc, char ** argv) {
#endif
#if DEBUG_TRACE
case 'v':
debug_trace++;
debug_trace = 1;
break;
#endif
case 'V':
print_version();
exit(EXIT_SUCCESS);
break;
case 'z':
opts.disable_ip_tos = 1;
break;
default:
fprintf(stderr, "Invalid option -%c\n", c);
printhelp(argv[0]);
@@ -437,72 +419,70 @@ void svr_getopts(int argc, char ** argv) {
if (svr_opts.forced_command) {
dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
}
if (reexec_fd_arg) {
if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
|| svr_opts.reexec_childpipe < 0) {
dropbear_exit("Bad -2");
}
}
#if INETD_MODE
if (svr_opts.inetdmode && (
opts.usingsyslog == 0
#if DEBUG_TRACE
|| debug_trace
#endif
)) {
/* log output goes to stderr which would get sent over the inetd network socket */
dropbear_exit("Dropbear inetd mode is incompatible with debug -v or non-syslog");
}
#endif
if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
dropbear_exit("-t and -s are incompatible");
}
#if DROPBEAR_PLUGIN
if (pubkey_plugin) {
svr_opts.pubkey_plugin = m_strdup(pubkey_plugin);
char *args = strchr(svr_opts.pubkey_plugin, ',');
if (args) {
*args='\0';
++args;
}
svr_opts.pubkey_plugin_options = args;
}
if (pubkey_plugin) {
char *args = strchr(pubkey_plugin, ',');
if (args) {
*args='\0';
++args;
}
svr_opts.pubkey_plugin = pubkey_plugin;
svr_opts.pubkey_plugin_options = args;
}
#endif
}
static void addportandaddress(const char* spec) {
char *port = NULL, *address = NULL;
char *spec_copy = NULL, *myspec = NULL, *port = NULL, *address = NULL;
if (svr_opts.portcount >= DROPBEAR_MAX_PORTS) {
return;
}
if (svr_opts.portcount < DROPBEAR_MAX_PORTS) {
if (split_address_port(spec, &address, &port) == DROPBEAR_FAILURE) {
dropbear_exit("Bad -p argument");
}
/* We don't free it, it becomes part of the runopt state */
spec_copy = m_strdup(spec);
myspec = spec_copy;
/* A bare port */
if (!port) {
port = address;
address = NULL;
}
if (myspec[0] == '[') {
myspec++;
port = strchr(myspec, ']');
if (!port) {
/* Unmatched [ -> exit */
dropbear_exit("Bad listen address");
}
port[0] = '\0';
port++;
if (port[0] != ':') {
/* Missing port -> exit */
dropbear_exit("Missing port");
}
} else {
/* search for ':', that separates address and port */
port = strrchr(myspec, ':');
}
if (!address) {
/* no address given -> fill in the default address */
address = m_strdup(DROPBEAR_DEFADDRESS);
}
if (!port) {
/* no ':' -> the whole string specifies just a port */
port = myspec;
} else {
/* Split the address/port */
port[0] = '\0';
port++;
address = myspec;
}
if (port[0] == '\0') {
/* empty port -> exit */
dropbear_exit("Bad port");
if (!address) {
/* no address given -> fill in the default address */
address = DROPBEAR_DEFADDRESS;
}
if (port[0] == '\0') {
/* empty port -> exit */
dropbear_exit("Bad port");
}
svr_opts.ports[svr_opts.portcount] = m_strdup(port);
svr_opts.addresses[svr_opts.portcount] = m_strdup(address);
svr_opts.portcount++;
m_free(spec_copy);
}
svr_opts.ports[svr_opts.portcount] = port;
svr_opts.addresses[svr_opts.portcount] = address;
svr_opts.portcount++;
}
static void disablekey(int type) {
@@ -531,14 +511,12 @@ static void loadhostkey_helper(const char *name, void** src, void** dst, int fat
/* Must be called after syslog/etc is working */
static void loadhostkey(const char *keyfile, int fatal_duplicate) {
sign_key * read_key = new_sign_key();
char *expand_path = expand_homedir_path(keyfile);
enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
if (readhostkey(expand_path, read_key, &type) == DROPBEAR_FAILURE) {
if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) {
if (!svr_opts.delay_hostkey) {
dropbear_log(LOG_WARNING, "Failed loading %s", expand_path);
dropbear_log(LOG_WARNING, "Failed loading %s", keyfile);
}
}
m_free(expand_path);
#if DROPBEAR_RSA
if (type == DROPBEAR_SIGNKEY_RSA) {

View File

@@ -208,7 +208,7 @@ void svr_session(int sock, int childpipe) {
}
/* cleanup and exit - format must be <= 100 chars */
/* failure exit - format must be <= 100 chars */
void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
char exitmsg[150];
char fullmsg[300];
@@ -217,12 +217,10 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
int add_delay = 0;
#if DROPBEAR_PLUGIN
if ((ses.plugin_session != NULL)) {
svr_ses.plugin_instance->delete_session(ses.plugin_session);
}
ses.plugin_session = NULL;
svr_opts.pubkey_plugin_options = NULL;
m_free(svr_opts.pubkey_plugin);
if ((ses.plugin_session != NULL)) {
svr_ses.plugin_instance->delete_session(ses.plugin_session);
}
ses.plugin_session = NULL;
#endif
/* Render the formatted exit message */

View File

@@ -60,7 +60,7 @@ static int newtcpdirect(struct Channel * channel);
#if DROPBEAR_SVR_REMOTETCPFWD
static const struct ChanType svr_chan_tcpremote = {
"forwarded-tcpip",
NULL,
tcp_prio_inithandler,
NULL,
NULL,
NULL,
@@ -289,15 +289,11 @@ static int newtcpdirect(struct Channel * channel) {
goto out;
}
if (!svr_pubkey_allows_local_tcpfwd(desthost, destport)) {
TRACE(("leave newtcpdirect: local tcp forwarding not permitted to requested destination"));
goto out;
}
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
snprintf(portstring, sizeof(portstring), "%u", destport);
channel->conn_pending = connect_remote(desthost, portstring, channel_connect_done,
channel, NULL, NULL, DROPBEAR_PRIO_NORMAL);
channel->conn_pending = connect_remote(desthost, portstring, channel_connect_done, channel, NULL, NULL);
err = SSH_OPEN_IN_PROGRESS;
out:

View File

@@ -206,7 +206,7 @@ void x11cleanup(struct ChanSess *chansess) {
}
static int x11_inithandler(struct Channel *channel) {
channel->prio = DROPBEAR_PRIO_LOWDELAY;
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
return 0;
}

View File

@@ -1,23 +1,15 @@
/*******************************************************************
* You shouldn't edit this file unless you know you need to.
* You shouldn't edit this file unless you know you need to.
* This file is only included from options.h
*******************************************************************/
#ifndef DROPBEAR_VERSION
#define DROPBEAR_VERSION "2022.83"
#define DROPBEAR_VERSION "2020.81"
#endif
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
#define PROGNAME "dropbear"
#ifndef DROPBEAR_CLIENT
#define DROPBEAR_CLIENT 0
#endif
#ifndef DROPBEAR_SERVER
#define DROPBEAR_SERVER 0
#endif
/* Spec recommends after one hour or 1 gigabyte of data. One hour
* is a bit too verbose, so we try 8 hours */
#ifndef KEX_REKEY_TIMEOUT
@@ -37,13 +29,6 @@
#error "NON_INETD_MODE or INETD_MODE (or both) must be enabled."
#endif
/* Would probably work on freebsd but hasn't been tested */
#if defined(HAVE_FEXECVE) && DROPBEAR_REEXEC && defined(__linux__)
#define DROPBEAR_DO_REEXEC 1
#else
#define DROPBEAR_DO_REEXEC 0
#endif
/* A client should try and send an initial key exchange packet guessing
* the algorithm that will match - saves a round trip connecting, has little
* overhead if the guess was "wrong". */
@@ -76,6 +61,7 @@
#define MAX_TERM_LEN 200 /* max length of TERM name */
#define MAX_HOST_LEN 254 /* max hostname len for tcp fwding */
#define MAX_IP_LEN 15 /* strlen("255.255.255.255") == 15 */
#define DROPBEAR_MAX_PORTS 10 /* max number of ports which can be specified,
ipv4 and ipv6 don't count twice */
@@ -87,21 +73,12 @@
#define _PATH_CP "/bin/cp"
/* Default contents of /etc/shells if system getusershell() doesn't exist.
* Paths taken from getusershell(3) manpage. These can be customised
* on other platforms. One the commandline for CFLAGS it would look like eg
-DCOMPAT_USER_SHELLS='"/bin/sh","/apps/bin/sh","/data/bin/zsh"'
*/
#ifndef COMPAT_USER_SHELLS
#define COMPAT_USER_SHELLS "/bin/sh","/bin/csh"
#endif
#define DROPBEAR_ESCAPE_CHAR '~'
/* success/failure defines */
#define DROPBEAR_SUCCESS 0
#define DROPBEAR_FAILURE -1
#define DROPBEAR_PASSWORD_ENV "DROPBEAR_PASSWORD"
#define DROPBEAR_NGROUP_MAX 1024
@@ -119,6 +96,7 @@
#define SHA1_HASH_SIZE 20
#define SHA256_HASH_SIZE 32
#define MD5_HASH_SIZE 16
#define MAX_HASH_SIZE 64 /* sha512 */
#if DROPBEAR_CHACHA20POLY1305
@@ -141,11 +119,24 @@
#define DROPBEAR_SHA2_512_HMAC 0
#endif
/* might be needed for compatibility with very old implementations */
#ifndef DROPBEAR_MD5_HMAC
#define DROPBEAR_MD5_HMAC 0
#endif
/* Twofish counter mode is disabled by default because it
has not been tested for interoperability with other SSH implementations.
If you test it please contact the Dropbear author */
#ifndef DROPBEAR_TWOFISH_CTR
#define DROPBEAR_TWOFISH_CTR 0
#endif
#define DROPBEAR_ECC ((DROPBEAR_ECDH) || (DROPBEAR_ECDSA))
/* Debian doesn't define this in system headers */
#if !defined(LTM_DESC) && (DROPBEAR_ECC)
#define LTM_DESC
#define LTM_DESC
#endif
#define DROPBEAR_ECC_256 (DROPBEAR_ECC)
@@ -159,42 +150,28 @@
* signing operations slightly slower. */
#define DROPBEAR_RSA_BLINDING 1
#ifndef DROPBEAR_RSA_SHA1
#define DROPBEAR_RSA_SHA1 DROPBEAR_RSA
#endif
#ifndef DROPBEAR_RSA_SHA256
#define DROPBEAR_RSA_SHA256 DROPBEAR_RSA
#endif
/* Miller-Rabin primality testing is sufficient for RSA but not DSS.
* It's a compile-time setting for libtommath, we can get a speedup
* for key generation if DSS is disabled.
* https://github.com/mkj/dropbear/issues/174#issuecomment-1267374858
*/
#if !DROPBEAR_DSS
#define LTM_USE_ONLY_MR 1
#endif
/* hashes which will be linked and registered */
#define DROPBEAR_SHA1 (DROPBEAR_RSA_SHA1 || DROPBEAR_DSS \
|| DROPBEAR_SHA1_HMAC || DROPBEAR_SHA1_96_HMAC \
|| DROPBEAR_DH_GROUP1 || DROPBEAR_DH_GROUP14_SHA1 )
/* sha256 is always used for fingerprints and dbrandom */
#define DROPBEAR_SHA256 1
#define DROPBEAR_SHA256 ((DROPBEAR_SHA2_256_HMAC) || (DROPBEAR_ECC_256) \
|| (DROPBEAR_CURVE25519) || (DROPBEAR_DH_GROUP14_SHA256) \
|| (DROPBEAR_RSA_SHA256))
#define DROPBEAR_SHA384 (DROPBEAR_ECC_384)
/* LTC SHA384 depends on SHA512 */
#define DROPBEAR_SHA512 ((DROPBEAR_SHA2_512_HMAC) || (DROPBEAR_ECC_521) \
|| (DROPBEAR_SHA384) || (DROPBEAR_DH_GROUP16) \
|| (DROPBEAR_ED25519))
#define DROPBEAR_MD5 (DROPBEAR_MD5_HMAC)
#define DROPBEAR_DH_GROUP14 ((DROPBEAR_DH_GROUP14_SHA256) || (DROPBEAR_DH_GROUP14_SHA1))
#define DROPBEAR_NORMAL_DH ((DROPBEAR_DH_GROUP1) || (DROPBEAR_DH_GROUP14) || (DROPBEAR_DH_GROUP16))
#ifndef DROPBEAR_SK_ECDSA
#define DROPBEAR_SK_ECDSA DROPBEAR_SK_KEYS
#endif
#ifndef DROPBEAR_SK_ED25519
#define DROPBEAR_SK_ED25519 DROPBEAR_SK_KEYS
#endif
/* Dropbear only uses server-sig-algs, only needed if we have rsa-sha256 pubkey auth */
#define DROPBEAR_EXT_INFO ((DROPBEAR_RSA_SHA256) \
&& ((DROPBEAR_CLI_PUBKEY_AUTH) || (DROPBEAR_SVR_PUBKEY_AUTH)))
@@ -251,6 +228,8 @@
#define DROPBEAR_AES ((DROPBEAR_AES256) || (DROPBEAR_AES128))
#define DROPBEAR_TWOFISH ((DROPBEAR_TWOFISH256) || (DROPBEAR_TWOFISH128))
#define DROPBEAR_AEAD_MODE ((DROPBEAR_CHACHA20POLY1305) || (DROPBEAR_ENABLE_GCM_MODE))
#define DROPBEAR_CLI_ANYTCPFWD ((DROPBEAR_CLI_REMOTETCPFWD) || (DROPBEAR_CLI_LOCALTCPFWD))
@@ -294,7 +273,8 @@
#error "You must define DROPBEAR_SVR_PUBKEY_AUTH in order to use plugins"
#endif
#if !(DROPBEAR_AES128 || DROPBEAR_3DES || DROPBEAR_AES256 || DROPBEAR_CHACHA20POLY1305)
#if !(DROPBEAR_AES128 || DROPBEAR_3DES || DROPBEAR_AES256 || DROPBEAR_BLOWFISH \
|| DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128 || DROPBEAR_CHACHA20POLY1305)
#error "At least one encryption algorithm must be enabled. AES128 is recommended."
#endif
@@ -379,20 +359,5 @@
#define DROPBEAR_MSAN 0
#endif
#ifndef DEBUG_DSS_VERIFY
#define DEBUG_DSS_VERIFY 0
#endif
#ifndef DROPBEAR_MULTI
#define DROPBEAR_MULTI 0
#endif
/* Fuzzing expects all key types to be enabled */
#if DROPBEAR_FUZZ
#if defined(DROPBEAR_DSS)
#undef DROPBEAR_DSS
#endif
#define DROPBEAR_DSS 1
#endif
/* no include guard for this file */

View File

@@ -45,6 +45,13 @@ static void cleanup_tcp(const struct Listener *listener) {
m_free(tcpinfo);
}
int tcp_prio_inithandler(struct Channel* channel)
{
TRACE(("tcp_prio_inithandler channel %d", channel->index))
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
return 0;
}
static void tcp_acceptor(const struct Listener *listener, int sock) {
int fd;

View File

@@ -71,6 +71,7 @@ void cli_recv_msg_request_failure(void);
/* Common */
int listen_tcpfwd(struct TCPListener* tcpinfo, struct Listener **ret_listener);
int tcp_prio_inithandler(struct Channel* chan);
/* A random identifier */
#define CHANNEL_ID_TCPFORWARDED 0x43612c67

View File

@@ -1,14 +1,12 @@
srcdir=@srcdir@
SHELL=bash
all: test
test: venv/bin/pytest fakekey
(source ./venv/bin/activate; pytest --hostkey=fakekey --dbclient=../dbclient --dropbear=../dropbear $(srcdir) )
./venv/bin/pytest --hostkey=fakekey --dbclient=../dbclient --dropbear=../dropbear $(srcdir)
one: venv/bin/pytest fakekey
(source ./venv/bin/activate; pytest --hostkey=fakekey --dbclient=../dbclient --dropbear=../dropbear $(srcdir) -k exit)
./venv/bin/pytest --hostkey=fakekey --dbclient=../dbclient --dropbear=../dropbear $(srcdir) -k exit
fakekey:
../dropbearkey -t ecdsa -f $@

View File

@@ -2,12 +2,9 @@ def pytest_addoption(parser):
parser.addoption("--port", type=str, help="default is 2244 local, 22 remote")
parser.addoption("--dbclient", type=str, default="../dbclient")
parser.addoption("--dropbear", type=str, default="../dropbear")
parser.addoption("--dropbearconvert", type=str, default="../dropbearconvert")
parser.addoption("--dropbearkey", type=str, default="../dropbearkey")
parser.addoption("--hostkey", type=str, help="required unless --remote")
parser.addoption("--remote", type=str, help="remote host")
parser.addoption("--user", type=str, help="optional username")
parser.addoption("--ssh-keygen", type=str, default="ssh-keygen")
def pytest_configure(config):
opt = config.option

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env python3
import os
import sys
import time
import psutil
from pathlib import Path
want_name = "dropbear"
# Walks up the parent process tree, prints a r-xp line of /proc/pid/maps when
# it finds the wanted name
def main():
try:
for p in psutil.Process().parents():
print(p.pid, file=sys.stderr)
print(p.name(), file=sys.stderr)
print(p.cmdline(), file=sys.stderr)
if want_name in p.name():
with (Path('/proc') / str(p.pid) / "maps").open() as f:
for i, l in enumerate(f, 1):
if ' r-xp ' in l:
print(l.rstrip())
break
return
raise RuntimeError(f"Couldn't find parent {want_name} process")
except Exception as e:
print(psutil.Process().parents())
for p in psutil.Process().parents():
print(p.name())
print(e)
# time.sleep(100)
raise
if __name__ == "__main__":
main()

View File

@@ -6,4 +6,3 @@ py==1.10.0
pyparsing==2.4.7
pytest==6.2.5
toml==0.10.2
psutil==5.9.0

View File

@@ -1,37 +0,0 @@
from pathlib import Path
import sys
from test_dropbear import *
def test_reexec(request, dropbear):
"""
Tests that two consecutive connections have different address layouts.
This indicates that re-exec makes ASLR work
"""
map_script = (Path(request.node.fspath).parent / "parent_dropbear_map.py").resolve()
# run within the same venv, for python deps
activate = own_venv_command()
cmd = f"{activate}; {map_script}"
print(cmd)
r = dbclient(request, cmd, capture_output=True, text=True)
map1 = r.stdout.rstrip()
print(r.stderr, file=sys.stderr)
r.check_returncode()
r = dbclient(request, cmd, capture_output=True, text=True)
map2 = r.stdout.rstrip()
print(r.stderr, file=sys.stderr)
r.check_returncode()
print(map1)
print(map2)
# expect something like
# "563174d59000-563174d5d000 r--p 00000000 00:29 4242372 /home/matt/src/dropbear/build/dropbear"
assert map1.endswith('/dropbear') or map1.endswith('/dropbearmulti')
a1 = map1.split()[0]
a2 = map2.split()[0]
print(a1)
print(a2)
# relocation addresses should differ
assert a1 != a2

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