mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
9 Commits
DROPBEAR_2
...
matt-sk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cafebe2d30 | ||
|
|
cc481a646d | ||
|
|
2634c4586b | ||
|
|
712d529164 | ||
|
|
2ad020ff30 | ||
|
|
0c62c0db7f | ||
|
|
2993eedaba | ||
|
|
c66f0e98c9 | ||
|
|
c8fcc08fe0 |
9
.github/multiwrapper
vendored
9
.github/multiwrapper
vendored
@@ -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 "$@"
|
||||
|
||||
25
.github/workflows/autoconf.yml
vendored
25
.github/workflows/autoconf.yml
vendored
@@ -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
|
||||
81
.github/workflows/build.yml
vendored
81
.github/workflows/build.yml
vendored
@@ -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,11 +22,6 @@ jobs:
|
||||
|
||||
- name: multi binary
|
||||
multi: 1
|
||||
multilink: 1
|
||||
|
||||
- name: multi binary, dropbearmulti argv0
|
||||
multi: 1
|
||||
multiwrapper: 1
|
||||
|
||||
- name: bundled libtom, bionic , no writev()
|
||||
# test can use an older distro with bundled libtommath
|
||||
@@ -44,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:
|
||||
@@ -65,29 +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
|
||||
|
||||
# # 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
|
||||
|
||||
@@ -97,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
|
||||
|
||||
@@ -110,18 +81,13 @@ jobs:
|
||||
# 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
|
||||
|
||||
@@ -132,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
|
||||
|
||||
- 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 }}
|
||||
@@ -174,14 +116,7 @@ jobs:
|
||||
- name: keys
|
||||
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
|
||||
|
||||
|
||||
36
.github/workflows/tarball.yml
vendored
36
.github/workflows/tarball.yml
vendored
@@ -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
3
.gitignore
vendored
@@ -19,10 +19,9 @@
|
||||
/fuzzer-*.options
|
||||
/scp
|
||||
/scp-progress
|
||||
Makefile
|
||||
config.h
|
||||
default_options_guard.h
|
||||
localoptions.h
|
||||
Makefile
|
||||
tags
|
||||
.pytest*
|
||||
*.pyc
|
||||
|
||||
240
CHANGES
240
CHANGES
@@ -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
|
||||
|
||||
2
INSTALL
2
INSTALL
@@ -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
|
||||
|
||||
19
Makefile.in
19
Makefile.in
@@ -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
2
README
@@ -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
11
SMALL
@@ -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
19
auth.h
@@ -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
|
||||
|
||||
|
||||
2
bignum.c
2
bignum.c
@@ -100,5 +100,5 @@ void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
plus header + some leeway*/
|
||||
buf_putmpint(buf, mp);
|
||||
hash_desc->process(hs, buf->data, buf->len);
|
||||
buf_burn_free(buf);
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
6
buffer.c
6
buffer.c
@@ -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) {
|
||||
|
||||
2
buffer.h
2
buffer.h
@@ -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);
|
||||
|
||||
10
channel.h
10
channel.h
@@ -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 {
|
||||
|
||||
31
cli-auth.c
31
cli-auth.c
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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: ",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
14
cli-main.c
14
cli-main.c
@@ -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");
|
||||
|
||||
111
cli-runopts.c
111
cli-runopts.c
@@ -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. */
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
|
||||
24
common-kex.c
24
common-kex.c
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
}
|
||||
|
||||
@@ -666,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
compat.c
3
compat.c
@@ -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
1270
config.guess
vendored
File diff suppressed because it is too large
Load Diff
23
config.h.in
23
config.h.in
@@ -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
113
config.sub
vendored
@@ -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)
|
||||
|
||||
83
configure.ac
83
configure.ac
@@ -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
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
23
dbclient.1
23
dbclient.1
@@ -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
|
||||
|
||||
19
dbmulti.c
19
dbmulti.c
@@ -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;
|
||||
}
|
||||
|
||||
47
dbrandom.c
47
dbrandom.c
@@ -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;
|
||||
|
||||
100
dbutil.c
100
dbutil.c
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
15
dbutil.h
15
dbutil.h
@@ -47,11 +47,8 @@ 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, mp_int *mp);
|
||||
void debug_start_net(void);
|
||||
@@ -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
12
debian/changelog
vendored
@@ -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.
|
||||
|
||||
2
debian/dropbear.init
vendored
2
debian/dropbear.init
vendored
@@ -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
38
debug.h
@@ -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. */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
15
dropbear.8
15
dropbear.8
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -127,13 +127,13 @@ 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");
|
||||
@@ -195,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:
|
||||
@@ -309,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);
|
||||
@@ -341,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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
1107
keyimport.c
1107
keyimport.c
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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} $@"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -829,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;
|
||||
}
|
||||
|
||||
57
netio.c
57
netio.c
@@ -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)))
|
||||
}
|
||||
|
||||
8
netio.h
8
netio.h
@@ -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);
|
||||
|
||||
54
packet.c
54
packet.c
@@ -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
|
||||
|
||||
|
||||
60
release.sh
60
release.sh
@@ -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"
|
||||
|
||||
16
runopts.h
16
runopts.h
@@ -33,7 +33,6 @@
|
||||
|
||||
typedef struct runopts {
|
||||
|
||||
int disable_ip_tos;
|
||||
#if DROPBEAR_SVR_REMOTETCPFWD || DROPBEAR_CLI_LOCALTCPFWD \
|
||||
|| DROPBEAR_CLI_REMOTETCPFWD
|
||||
int listen_fwd_all;
|
||||
@@ -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_ */
|
||||
|
||||
119
signkey.c
119
signkey.c
@@ -534,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,
|
||||
@@ -587,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));
|
||||
@@ -641,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);
|
||||
@@ -688,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
|
||||
@@ -696,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
|
||||
|
||||
@@ -127,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
|
||||
};
|
||||
|
||||
|
||||
161
signkey_ossh.c
161
signkey_ossh.c
@@ -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 */
|
||||
@@ -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_ */
|
||||
18
sk-ecdsa.c
18
sk-ecdsa.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
22
sk-ed25519.c
22
sk-ed25519.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
5
ssh.h
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
177
svr-authpubkey.c
177
svr-authpubkey.c
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
21
svr-kex.c
21
svr-kex.c
@@ -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
|
||||
|
||||
|
||||
133
svr-main.c
133
svr-main.c
@@ -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 */
|
||||
|
||||
142
svr-runopts.c
142
svr-runopts.c
@@ -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) {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
12
svr-tcpfwd.c
12
svr-tcpfwd.c
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
80
sysoptions.h
80
sysoptions.h
@@ -1,10 +1,10 @@
|
||||
/*******************************************************************
|
||||
* 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
|
||||
@@ -29,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". */
|
||||
@@ -68,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 */
|
||||
@@ -79,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
|
||||
@@ -111,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
|
||||
@@ -133,6 +119,19 @@
|
||||
#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 */
|
||||
@@ -158,38 +157,21 @@
|
||||
#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)))
|
||||
@@ -246,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))
|
||||
@@ -289,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
|
||||
|
||||
@@ -374,18 +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 defined(DROPBEAR_DSS)
|
||||
#undef DROPBEAR_DSS
|
||||
#endif
|
||||
#define DROPBEAR_DSS 1
|
||||
|
||||
/* no include guard for this 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;
|
||||
|
||||
1
tcpfwd.h
1
tcpfwd.h
@@ -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
|
||||
|
||||
@@ -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 $@
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -6,4 +6,3 @@ py==1.10.0
|
||||
pyparsing==2.4.7
|
||||
pytest==6.2.5
|
||||
toml==0.10.2
|
||||
psutil==5.9.0
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -19,8 +19,7 @@ def dropbear(request):
|
||||
yield None
|
||||
return
|
||||
|
||||
# split so that "dropbearmulti dropbear" works
|
||||
args = opt.dropbear.split() + [
|
||||
args = [opt.dropbear,
|
||||
"-p", LOCALADDR, # bind locally only
|
||||
"-r", opt.hostkey,
|
||||
"-p", opt.port,
|
||||
@@ -44,10 +43,9 @@ def dropbear(request):
|
||||
def dbclient(request, *args, **kwargs):
|
||||
opt = request.config.option
|
||||
host = opt.remote or LOCALADDR
|
||||
# split so that "dropbearmulti dbclient" works
|
||||
base_args = opt.dbclient.split() + ["-y", host, "-p", opt.port]
|
||||
base_args = [opt.dbclient, "-y", host, "-p", opt.port]
|
||||
if opt.user:
|
||||
base_args.extend(['-l', opt.user])
|
||||
full_args.extend(['-l', opt.user])
|
||||
full_args = base_args + list(args)
|
||||
bg = kwargs.get("background")
|
||||
if "background" in kwargs:
|
||||
@@ -59,23 +57,7 @@ def dbclient(request, *args, **kwargs):
|
||||
# wait for response
|
||||
return subprocess.run(full_args, **kwargs)
|
||||
|
||||
def own_venv_command():
|
||||
""" Returns a command to run as a prefix to get the same venv
|
||||
as the current running Python. Returns '' on not a virtualenv
|
||||
"""
|
||||
try:
|
||||
venv = os.environ['VIRTUAL_ENV']
|
||||
except KeyError:
|
||||
return ""
|
||||
|
||||
# note: bash/zsh unix specific
|
||||
return f"source {venv}/bin/activate"
|
||||
|
||||
class HandleTcp(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
|
||||
# override TCPServer's default, avoids TIME_WAIT
|
||||
allow_reuse_addr = True
|
||||
|
||||
""" Listens for a single incoming request, sends a response if given,
|
||||
and returns the inbound data.
|
||||
Reponse can be a queue object, in which case each item in the queue will
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
keytypes = [
|
||||
"rsa", "rsa-4096",
|
||||
"ed25519",
|
||||
"ecdsa", "ecdsa-256", "ecdsa-384", "ecdsa-521",
|
||||
"dss",
|
||||
]
|
||||
|
||||
def parse_keytype(kt):
|
||||
if '-' in kt:
|
||||
return kt.split('-')
|
||||
else:
|
||||
return (kt, None)
|
||||
|
||||
@pytest.mark.parametrize("keytype", keytypes)
|
||||
@pytest.mark.parametrize("keyformat", [None, "PEM"])
|
||||
def test_from_openssh(request, tmp_path, keytype, keyformat):
|
||||
"""
|
||||
Convert OpenSSH to Dropbear format,
|
||||
PEM and OpenSSH internal
|
||||
"""
|
||||
opt = request.config.option
|
||||
kt, keybits = parse_keytype(keytype)
|
||||
|
||||
if kt == 'dss' and keyformat is None:
|
||||
pytest.skip("dss doesn't support openssh format")
|
||||
|
||||
os_kt = kt
|
||||
if os_kt == 'dss':
|
||||
# OpenSSH calls it 'dsa', Dropbear calls it 'dss'
|
||||
os_kt = 'dsa'
|
||||
|
||||
os_key = tmp_path / 'oskey1'
|
||||
db_key = tmp_path / 'dbkey1'
|
||||
|
||||
# Generate an OpenSSH key
|
||||
args = [
|
||||
opt.ssh_keygen,
|
||||
'-f', os_key,
|
||||
'-t', os_kt,
|
||||
'-N', '', # no password
|
||||
]
|
||||
if keybits is not None:
|
||||
args += ['-b', keybits]
|
||||
if keyformat:
|
||||
args += ['-m', keyformat]
|
||||
p = subprocess.run(args, check=True)
|
||||
|
||||
# Convert to dropbear format
|
||||
args = [
|
||||
opt.dropbearconvert,
|
||||
'openssh', 'dropbear',
|
||||
os_key, db_key,
|
||||
]
|
||||
p = subprocess.run(args, check=True)
|
||||
|
||||
# Compare pubkeys
|
||||
args = [
|
||||
opt.dropbearkey,
|
||||
'-f', db_key,
|
||||
'-y'
|
||||
]
|
||||
p = subprocess.run(args, check=True, stdout=subprocess.PIPE, text=True)
|
||||
db_pubkey = p.stdout.splitlines()[1].strip()
|
||||
os_pubkey = os_key.with_suffix('.pub').open().read().strip()
|
||||
# we compare the whole key including comment since it currently matches
|
||||
assert db_pubkey == os_pubkey
|
||||
|
||||
@pytest.mark.parametrize("keytype", keytypes)
|
||||
def test_roundtrip(request, tmp_path, keytype):
|
||||
"""
|
||||
Dropbear's private key format is deterministic so
|
||||
we can compare round trip conversion. (OpenSSH's
|
||||
format has more variable comments and other fields).
|
||||
"""
|
||||
opt = request.config.option
|
||||
kt, keybits = parse_keytype(keytype)
|
||||
|
||||
os_key = tmp_path / 'oskey1'
|
||||
db_key1 = tmp_path / 'dbkey1'
|
||||
db_key2 = tmp_path / 'dbkey2'
|
||||
|
||||
# generate a key
|
||||
args = [
|
||||
opt.dropbearkey,
|
||||
'-t', kt,
|
||||
'-f', db_key1,
|
||||
]
|
||||
if keybits is not None:
|
||||
args += ['-s', keybits]
|
||||
p = subprocess.run(args, check=True)
|
||||
|
||||
# convert to openssh
|
||||
args = [
|
||||
opt.dropbearconvert,
|
||||
'dropbear', 'openssh',
|
||||
db_key1, os_key,
|
||||
]
|
||||
p = subprocess.run(args, check=True)
|
||||
|
||||
# Check ssh-keygen can read it
|
||||
args = [
|
||||
opt.ssh_keygen,
|
||||
'-f', os_key,
|
||||
'-y',
|
||||
]
|
||||
p = subprocess.run(args, check=True, text=True, stdout=subprocess.PIPE)
|
||||
os_pubkey = p.stdout.strip()
|
||||
|
||||
# Compare public keys
|
||||
args = [
|
||||
opt.dropbearkey,
|
||||
'-f', db_key1,
|
||||
'-y',
|
||||
]
|
||||
p = subprocess.run(args, check=True, text=True, stdout=subprocess.PIPE)
|
||||
db_pubkey = p.stdout.splitlines()[1].strip()
|
||||
# comment may differ
|
||||
db_pubkey = db_pubkey.split(' ')[:2]
|
||||
os_pubkey = os_pubkey.split(' ')[:2]
|
||||
assert db_pubkey == os_pubkey
|
||||
|
||||
# convert back to dropbear
|
||||
args = [
|
||||
opt.dropbearconvert,
|
||||
'openssh', 'dropbear',
|
||||
os_key, db_key2,
|
||||
]
|
||||
p = subprocess.run(args, check=True)
|
||||
# check the round trip is identical
|
||||
assert db_key1.open('rb').read() == db_key2.open('rb').read()
|
||||
@@ -1,30 +0,0 @@
|
||||
from test_dropbear import *
|
||||
import signal
|
||||
import queue
|
||||
import socket
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Tests for server side authentication
|
||||
|
||||
# Requires keyfile and authorized_keys set up in github action build.yml
|
||||
@pytest.mark.skipif('DBTEST_IN_ACTION' not in os.environ, reason="DBTEST_IN_ACTION not set")
|
||||
def test_pubkeyinfo(request, dropbear):
|
||||
kf = str(Path.home() / ".ssh/id_dropbear_key2")
|
||||
r = dbclient(request, "-i", kf, "echo -n $SSH_PUBKEYINFO", capture_output=True)
|
||||
# stop at first space
|
||||
assert r.stdout.decode() == "key2"
|
||||
|
||||
@pytest.mark.skipif('DBTEST_IN_ACTION' not in os.environ, reason="DBTEST_IN_ACTION not set")
|
||||
def test_pubkeyinfo_special(request, dropbear):
|
||||
kf = str(Path.home() / ".ssh/id_dropbear_key3")
|
||||
r = dbclient(request, "-i", kf, "echo -n $SSH_PUBKEYINFO", capture_output=True)
|
||||
# comment contains special characters so the SSH_PUBKEYINFO should not be set
|
||||
assert r.stdout.decode() == ""
|
||||
|
||||
@pytest.mark.skipif('DBTEST_IN_ACTION' not in os.environ, reason="DBTEST_IN_ACTION not set")
|
||||
def test_pubkeyinfo_okchar(request, dropbear):
|
||||
kf = str(Path.home() / ".ssh/id_dropbear_key4")
|
||||
r = dbclient(request, "-i", kf, "echo -n $SSH_PUBKEYINFO", capture_output=True)
|
||||
# comment contains special characters so the SSH_PUBKEYINFO should not be set
|
||||
assert r.stdout.decode() == "key4,char"
|
||||
Reference in New Issue
Block a user