Compare commits

..

9 Commits

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

View File

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

View File

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

View File

@@ -1,5 +1,4 @@
# Can be used locally with https://github.com/nektos/act
# Note the XXX line below.
name: BuildTest
on:
@@ -12,9 +11,6 @@ jobs:
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,12 +35,6 @@ 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 10.15
os: macos-10.15
cc: clang
@@ -69,19 +54,12 @@ jobs:
apt: 'no'
ranlib: ranlib -no_warning_for_no_symbols
# Check that debug code doesn't bitrot
- name: DEBUG_TRACE
localoptions: |
#define DEBUG_TRACE 5
# # 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
@@ -91,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
@@ -104,11 +81,6 @@ 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
@@ -126,26 +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
cat 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 }}
@@ -157,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

View File

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

3
.gitignore vendored
View File

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

132
CHANGES
View File

@@ -1,135 +1,3 @@
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". This can be used to prevent
the server immediately accepting successful authentication (before any auth
request) which could cause UI confusion and security issues with agent
forwarding - it isn't clear which host is prompting to use a key.
Thanks to Manfred Kaiser from Austrian MilCERT
- Add -q client option to hide remote banner, from Hans Harder
- Add -e option to pass all server environment variables to child processes.
This should be used with caution.
Patch from Roland Vollgraf (github #118)
- >> Use DSCP for QoS traffic classes. Priority (tty) traffic is now set to
AF21 "interactive". Previously TOS classes were used, they are not used by
modern traffic classifiers. Non-tty traffic is left at default priority.
- >> Disable dh-group1 key exchange by default. It has been disabled server
side by default since 2018.
- >> Removed Twofish cipher
Fixes:
- Fix flushing channel data when pty was allocated (github #85)
Data wasn't completely transmitted at channel close.
Reported and initial patch thanks to Yousong Zhou
- Dropbear now re-executes itself rather than just forking for each connection
(only on Linux). This allows ASLR to randomise address space for each
connection as a security mitigation. It should not have any visible impact
- if there are any performance impacts in the wild please report it.
- Check authorized_keys permissions as the user, fixes NFS squash root.
Patch from Chris Dragan (github #107)
- A missing home directory is now non-fatal, starting in / instead
- Fixed IPv6 [address]:port parsing for dbclient -b
Reported by Fabio Molinari
- Improve error logging so that they are logged on the server rather than being
sent to the client over the connection
- Max window size is increased to 10MB, more graceful fallback if it's invalid.
- Fix correctness of Dropbear's handling of global requests.
Patch from Dirkjan Bussink
- Fix some small bugs found by fuzzers, null pointer dereference crash and leaks
(post authentication)
- $HOME variable is used before /etc/passwd when expanding paths such as
~/.ssh/id_dropbear (for the client). Patch from Matt Robinson
- C89 build fixes from Guillaume Picquet
Infrastructure:
- Improvements to fuzzers. Added post-auth fuzzer, and a mutator that can
handle the structure of SSH packet streams. Added cifuzz to run on commits
and pull requests.
Thanks to OSS-Fuzz for the tools/clusters and reward funding.
- Dropbear source tarballs generated by release.sh are now reproducible from a
Git or Mercurial checkout, they will be identical on any system. Tested
on ubuntu and macos.
- Added some integration testing using pytest. Currently this has tests
for various channel handling edge cases, ASLR fork randomisation,
dropbearconvert, and SSH_PUBKEYINFO
- Set up github actions. This runs the pytest suite and other checks.
- build matrix includes c89, dropbearmulti, bundled libtom, macos, DEBUG_TRACE
- test for configure script regeneration
- build a tarball for external reproducibility
2020.81 - 29 October 2020
- Fix regression in 2020.79 which prevented connecting with some SSH

View File

@@ -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
@@ -43,7 +43,7 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
svr-tcpfwd.o svr-authpam.o @CRYPTLIB@
svr-tcpfwd.o svr-authpam.o
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-runopts.o cli-chansession.o \
@@ -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

5
SMALL
View File

@@ -9,7 +9,10 @@ The same applies if you are compiling just a client.
---
The following are set in localoptions.h:
The following are set in options.h:
- You can safely disable blowfish and twofish ciphers, and MD5 hmac, without
affecting interoperability
- If you're compiling statically, you can turn off host lookups

1
auth.h
View File

@@ -125,7 +125,6 @@ struct AuthState {
char *pw_passwd;
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
struct PubKeyOptions* pubkey_options;
char *pubkey_info;
#endif
};

View File

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

View File

@@ -55,13 +55,11 @@ void buf_free(buffer* buf) {
m_free(buf);
}
/* overwrite the contents of the buffer then free it */
void buf_burn_free(buffer* buf) {
/* overwrite the contents of the buffer to clear it */
void buf_burn(const buffer* buf) {
m_burn(buf->data, buf->size);
m_free(buf);
}
/* resize a buffer, pos and len will be repositioned if required when
* downsizing */
buffer* buf_resize(buffer *buf, unsigned int newsize) {

View File

@@ -44,7 +44,7 @@ buffer * buf_new(unsigned int size);
/* Possibly returns a new buffer*, like realloc() */
buffer * buf_resize(buffer *buf, unsigned int newsize);
void buf_free(buffer* buf);
void buf_burn_free(buffer* buf);
void buf_burn(const buffer* buf);
buffer* buf_newcopy(const buffer* buf);
void buf_setlen(buffer* buf, unsigned int len);
void buf_incrlen(buffer* buf, unsigned int incr);

View File

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

View File

@@ -82,11 +82,6 @@ void recv_msg_userauth_banner() {
return;
}
if (cli_opts.quiet) {
TRACE(("not showing banner"))
return;
}
banner = buf_getstring(ses.payload, &bannerlen);
buf_eatstring(ses.payload); /* The language string */
@@ -265,7 +260,7 @@ void recv_msg_userauth_success() {
/* This function can validly get called multiple times
if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
DEBUG1(("received msg_userauth_success"))
TRACE(("received msg_userauth_success"))
if (cli_opts.disable_trivial_auth && cli_ses.is_trivial_auth) {
dropbear_exit("trivial authentication not allowed");
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -371,7 +371,7 @@ static void checkhostkey(const unsigned char* keyblob, unsigned int keybloblen)
if (ret == DROPBEAR_SUCCESS) {
/* Good matching key */
DEBUG1(("server match %s", fingerprint))
TRACE(("good matching key"))
goto out;
}

View File

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

View File

@@ -62,7 +62,6 @@ static void printhelp() {
"-T Don't allocate a pty\n"
"-N Don't run a remote command\n"
"-f Run in background after auth\n"
"-q quiet, don't show remote banner\n"
"-y Always accept remote host key if unknown\n"
"-y -y Don't perform any remote host key checking (caution)\n"
"-s Request a subsystem (use by external sftp)\n"
@@ -96,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
@@ -142,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;
@@ -216,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;
@@ -302,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':
@@ -419,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);
@@ -431,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);
}
}
@@ -478,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);
@@ -497,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
@@ -527,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)
{
@@ -539,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;
}
@@ -586,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) {
@@ -607,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);
}
@@ -630,18 +628,19 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
/* Set up the proxycmd */
unsigned int cmd_len = 0;
char *passthrough_args = multihop_passthrough_args();
if (cli_opts.proxycmd) {
dropbear_exit("-J can't be used with multihop mode");
}
if (cli_opts.remoteport == NULL) {
cli_opts.remoteport = "22";
}
cmd_len = strlen(argv0) + strlen(remainder)
cmd_len = strlen(argv0) + strlen(remainder)
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
+ strlen(passthrough_args)
+ 30;
/* replace proxycmd. old -J arguments have been copied
to passthrough_args */
cli_opts.proxycmd = m_realloc(cli_opts.proxycmd, cmd_len);
m_snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport,
cli_opts.proxycmd = m_malloc(cmd_len);
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport,
passthrough_args, remainder);
#ifndef DISABLE_ZLIB
/* The stream will be incompressible since it's encrypted. */

View File

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

View File

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

View File

@@ -64,6 +64,14 @@ static const struct dropbear_cipher dropbear_aes256 =
static const struct dropbear_cipher dropbear_aes128 =
{&aes_desc, 16, 16};
#endif
#if DROPBEAR_TWOFISH256
static const struct dropbear_cipher dropbear_twofish256 =
{&twofish_desc, 32, 16};
#endif
#if DROPBEAR_TWOFISH128
static const struct dropbear_cipher dropbear_twofish128 =
{&twofish_desc, 16, 16};
#endif
#if DROPBEAR_3DES
static const struct dropbear_cipher dropbear_3des =
{&des3_desc, 24, 8};
@@ -148,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
@@ -157,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
@@ -341,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);
}
@@ -445,7 +469,7 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
DEBUG3(("buf_match_algo: %s", algolist))
TRACE(("buf_match_algo: %s", algolist))
remotecount = MAX_PROPOSED_ALGO;
get_algolist(algolist, len, remotenames, &remotecount);

View File

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

View File

@@ -249,7 +249,7 @@ static void kexinitialise() {
/* Helper function for gen_new_keys, creates a hash. It makes a copy of the
* already initialised hash_state hs, which should already have processed
* the dh_K and hash, since these are common. X is the letter 'A', 'B' etc.
* out must have at least min(hash_size, outlen) bytes allocated.
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
*
* See Section 7.2 of rfc4253 (ssh transport) for details */
static void hashkeys(unsigned char *out, unsigned int outlen,
@@ -306,7 +306,8 @@ static void gen_new_keys() {
mp_clear(ses.dh_K);
m_free(ses.dh_K);
hash_desc->process(&hs, ses.hash->data, ses.hash->len);
buf_burn_free(ses.hash);
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
if (IS_DROPBEAR_CLIENT) {
@@ -802,7 +803,8 @@ void finish_kexhashbuf(void) {
}
#endif
buf_burn_free(ses.kexhashbuf);
buf_burn(ses.kexhashbuf);
buf_free(ses.kexhashbuf);
m_burn(&hs, sizeof(hash_state));
ses.kexhashbuf = NULL;
@@ -867,7 +869,7 @@ static void read_kex_algos() {
goto error;
}
TRACE(("kexguess2 %d", kexguess2))
DEBUG3(("kex algo %s", algo->name))
TRACE(("kex algo %s", algo->name))
ses.newkeys->algo_kex = algo->data;
/* server_host_key_algorithms */
@@ -877,7 +879,7 @@ static void read_kex_algos() {
erralgo = "hostkey";
goto error;
}
DEBUG2(("hostkey algo %s", algo->name))
TRACE(("signature algo %s", algo->name))
ses.newkeys->algo_signature = algo->val;
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
@@ -887,7 +889,7 @@ static void read_kex_algos() {
erralgo = "enc c->s";
goto error;
}
DEBUG2(("enc c2s is %s", c2s_cipher_algo->name))
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
@@ -895,7 +897,7 @@ static void read_kex_algos() {
erralgo = "enc s->c";
goto error;
}
DEBUG2(("enc s2c is %s", s2c_cipher_algo->name))
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
@@ -908,7 +910,7 @@ static void read_kex_algos() {
erralgo = "mac c->s";
goto error;
}
DEBUG2(("hmac c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
/* mac_algorithms_server_to_client */
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
@@ -921,7 +923,7 @@ static void read_kex_algos() {
erralgo = "mac s->c";
goto error;
}
DEBUG2(("hmac s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
/* compression_algorithms_client_to_server */
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
@@ -929,7 +931,7 @@ static void read_kex_algos() {
erralgo = "comp c->s";
goto error;
}
DEBUG2(("comp c2s is %s", c2s_comp_algo->name))
TRACE(("hash c2s is %s", c2s_comp_algo->name))
/* compression_algorithms_server_to_client */
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
@@ -937,7 +939,7 @@ static void read_kex_algos() {
erralgo = "comp s->c";
goto error;
}
DEBUG2(("comp s2c is %s", s2c_comp_algo->name))
TRACE(("hash s2c is %s", s2c_comp_algo->name))
/* languages_client_to_server */
buf_eatstring(ses.payload);

View File

@@ -1,19 +1,19 @@
/*
* Dropbear - a SSH2 server
*
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -35,7 +35,7 @@ runopts opts; /* GLOBAL */
/* returns success or failure, and the keytype in *type. If we want
* to restrict the type, type can contain a type to return */
int readhostkey(const char * filename, sign_key * hostkey,
int readhostkey(const char * filename, sign_key * hostkey,
enum signkey_type *type) {
int ret = DROPBEAR_FAILURE;
@@ -57,7 +57,8 @@ int readhostkey(const char * filename, sign_key * hostkey,
ret = DROPBEAR_SUCCESS;
out:
buf_burn_free(buf);
buf_burn(buf);
buf_free(buf);
return ret;
}
@@ -117,57 +118,3 @@ void parse_recv_window(const char* recv_window_arg) {
}
/* Splits addr:port. Handles IPv6 [2001:0011::4]:port style format.
Returns first/second parts as malloced strings, second will
be NULL if no separator is found.
:port -> (NULL, "port")
port -> (port, NULL)
addr:port (addr, port)
addr: -> (addr, "")
Returns DROPBEAR_SUCCESS/DROPBEAR_FAILURE */
int split_address_port(const char* spec, char **first, char ** second) {
char *spec_copy = NULL, *addr = NULL, *colon = NULL;
int ret = DROPBEAR_FAILURE;
*first = NULL;
*second = NULL;
spec_copy = m_strdup(spec);
addr = spec_copy;
if (*addr == '[') {
addr++;
colon = strchr(addr, ']');
if (!colon) {
dropbear_log(LOG_WARNING, "Bad address '%s'", spec);
goto out;
}
*colon = '\0';
colon++;
if (*colon == '\0') {
/* No port part */
colon = NULL;
} else if (*colon != ':') {
dropbear_log(LOG_WARNING, "Bad address '%s'", spec);
goto out;
}
} else {
/* search for ':', that separates address and port */
colon = strrchr(addr, ':');
}
/* colon points to ':' now, or is NULL */
if (colon) {
/* Split the address/port */
*colon = '\0';
colon++;
*second = m_strdup(colon);
}
if (strlen(addr)) {
*first = m_strdup(addr);
}
ret = DROPBEAR_SUCCESS;
out:
m_free(spec_copy);
return ret;
}

View File

@@ -64,7 +64,7 @@ void common_session_init(int sock_in, int sock_out) {
setnonblocking(sock_out);
}
ses.socket_prio = DROPBEAR_PRIO_NORMAL;
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
/* Sets it to lowdelay */
update_channel_prio();
@@ -285,7 +285,8 @@ static void cleanup_buf(buffer **buf) {
if (!*buf) {
return;
}
buf_burn_free(*buf);
buf_burn(*buf);
buf_free(*buf);
*buf = NULL;
}
@@ -403,7 +404,7 @@ static void read_session_identification() {
dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
}
DEBUG1(("remoteident: %s", ses.remoteident))
TRACE(("remoteident: %s", ses.remoteident))
}
@@ -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;
}
}

1236
config.guess vendored

File diff suppressed because it is too large Load Diff

View File

@@ -93,9 +93,6 @@
/* Define to 1 if you have the `explicit_bzero' function. */
#undef HAVE_EXPLICIT_BZERO
/* Define to 1 if you have the `fexecve' function. */
#undef HAVE_FEXECVE
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
@@ -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

92
config.sub vendored
View File

@@ -1,14 +1,12 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright 1992-2022 Free Software Foundation, Inc.
# Copyright 1992-2021 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale
timestamp='2022-01-03'
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-01-03'
# 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
@@ -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 \
@@ -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,37 +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|'`
os=$(echo $basic_os | sed -e 's|linux|gnu|')
;;
*)
kernel=
@@ -1360,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
@@ -1389,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
@@ -1419,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
@@ -1428,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
@@ -1465,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
@@ -1712,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*)
@@ -1735,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* \
@@ -1753,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* )
| nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@@ -1771,12 +1742,11 @@ 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-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
;;
uclinux-uclibc* )
;;
-dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* )
-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

4
configure vendored
View File

@@ -5608,7 +5608,7 @@ for ac_header in 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
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -7352,7 +7352,7 @@ _ACEOF
fi
done
for ac_func in freeaddrinfo getnameinfo fork writev getgrouplist fexecve
for ac_func in freeaddrinfo getnameinfo fork writev getgrouplist
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

View File

@@ -386,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
@@ -841,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))

View File

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

View File

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

View File

@@ -34,7 +34,7 @@ static uint32_t counter = 0;
/* the max value for the counter, so it won't integer overflow */
#define MAX_COUNTER (1<<30)
static unsigned char hashpool[SHA256_HASH_SIZE] = {0};
static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
static int donerandinit = 0;
#define INIT_SEED_SIZE 32 /* 256 bits */
@@ -100,7 +100,7 @@ process_file(hash_state *hs, const char *filename,
}
goto out;
}
sha256_process(hs, readbuf, readlen);
sha1_process(hs, readbuf, readlen);
readcount += readlen;
}
ret = DROPBEAR_SUCCESS;
@@ -120,13 +120,13 @@ void addrandom(const unsigned char * buf, unsigned int len)
#endif
/* hash in the new seed data */
sha256_init(&hs);
sha1_init(&hs);
/* existing state (zeroes on startup) */
sha256_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
/* new */
sha256_process(&hs, buf, len);
sha256_done(&hs, hashpool);
sha1_process(&hs, buf, len);
sha1_done(&hs, hashpool);
}
static void write_urandom()
@@ -152,10 +152,10 @@ static void write_urandom()
#if DROPBEAR_FUZZ
void fuzz_seed(const unsigned char* dat, unsigned int len) {
hash_state hs;
sha256_init(&hs);
sha256_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
sha256_process(&hs, dat, len);
sha256_done(&hs, hashpool);
sha1_init(&hs);
sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
sha1_process(&hs, dat, len);
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
}
@@ -209,7 +209,7 @@ static int process_getrandom(hash_state *hs) {
if (ret == sizeof(buf)) {
/* Success, stir in the entropy */
sha256_process(hs, (void*)buf, sizeof(buf));
sha1_process(hs, (void*)buf, sizeof(buf));
return DROPBEAR_SUCCESS;
}
@@ -221,6 +221,7 @@ static int process_getrandom(hash_state *hs) {
/* Initialise the prng from /dev/urandom or prngd. This function can
* be called multiple times */
void seedrandom() {
hash_state hs;
pid_t pid;
@@ -235,10 +236,10 @@ void seedrandom() {
#endif
/* hash in the new seed data */
sha256_init(&hs);
sha1_init(&hs);
/* existing state */
sha256_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
#ifdef HAVE_GETRANDOM
if (process_getrandom(&hs) == DROPBEAR_SUCCESS) {
@@ -288,21 +289,21 @@ void seedrandom() {
#endif
pid = getpid();
sha256_process(&hs, (void*)&pid, sizeof(pid));
sha1_process(&hs, (void*)&pid, sizeof(pid));
/* gettimeofday() doesn't completely fill out struct timeval on
OS X (10.8.3), avoid valgrind warnings by clearing it first */
memset(&tv, 0x0, sizeof(tv));
gettimeofday(&tv, NULL);
sha256_process(&hs, (void*)&tv, sizeof(tv));
sha1_process(&hs, (void*)&tv, sizeof(tv));
clockval = clock();
sha256_process(&hs, (void*)&clockval, sizeof(clockval));
sha1_process(&hs, (void*)&clockval, sizeof(clockval));
/* When a private key is read by the client or server it will
* be added to the hashpool - see runopts.c */
sha256_done(&hs, hashpool);
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
@@ -316,7 +317,7 @@ void seedrandom() {
void genrandom(unsigned char* buf, unsigned int len) {
hash_state hs;
unsigned char hash[SHA256_HASH_SIZE];
unsigned char hash[SHA1_HASH_SIZE];
unsigned int copylen;
if (!donerandinit) {
@@ -324,17 +325,17 @@ void genrandom(unsigned char* buf, unsigned int len) {
}
while (len > 0) {
sha256_init(&hs);
sha256_process(&hs, (void*)hashpool, sizeof(hashpool));
sha256_process(&hs, (void*)&counter, sizeof(counter));
sha256_done(&hs, hash);
sha1_init(&hs);
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)&counter, sizeof(counter));
sha1_done(&hs, hash);
counter++;
if (counter > MAX_COUNTER) {
seedrandom();
}
copylen = MIN(len, SHA256_HASH_SIZE);
copylen = MIN(len, SHA1_HASH_SIZE);
memcpy(buf, hash, copylen);
len -= copylen;
buf += copylen;

100
dbutil.c
View File

@@ -155,7 +155,7 @@ void dropbear_log(int priority, const char* format, ...) {
}
#if DEBUG_TRACE
#if DEBUG_TRACE
static double debug_start_time = -1;
@@ -185,63 +185,39 @@ static double time_since_start()
return nowf - debug_start_time;
}
static void dropbear_tracelevel(int level, const char *format, va_list param)
{
if (debug_trace == 0 || debug_trace < level) {
void dropbear_trace(const char* format, ...) {
va_list param;
if (!debug_trace) {
return;
}
fprintf(stderr, "TRACE%d (%d) %f: ", level, getpid(), time_since_start());
va_start(param, format);
fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
}
#if (DEBUG_TRACE>=1)
void dropbear_trace1(const char* format, ...) {
va_list param;
va_start(param, format);
dropbear_tracelevel(1, format, param);
va_end(param);
}
#endif
#if (DEBUG_TRACE>=2)
void dropbear_trace2(const char* format, ...) {
static int trace_env = -1;
va_list param;
va_start(param, format);
dropbear_tracelevel(2, format, param);
va_end(param);
}
#endif
#if (DEBUG_TRACE>=3)
void dropbear_trace3(const char* format, ...) {
va_list param;
if (trace_env == -1) {
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
}
if (!(debug_trace && trace_env)) {
return;
}
va_start(param, format);
dropbear_tracelevel(3, format, param);
fprintf(stderr, "TRACE2 (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
}
#endif
#if (DEBUG_TRACE>=4)
void dropbear_trace4(const char* format, ...) {
va_list param;
va_start(param, format);
dropbear_tracelevel(4, format, param);
va_end(param);
}
#endif
#if (DEBUG_TRACE>=5)
void dropbear_trace5(const char* format, ...) {
va_list param;
va_start(param, format);
dropbear_tracelevel(5, format, param);
va_end(param);
}
#endif
#endif
#endif /* DEBUG_TRACE */
/* Connect to a given unix socket. The socket is blocking */
#if ENABLE_CONNECT_UNIX
@@ -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;
}

View File

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

24
debian/changelog vendored
View File

@@ -1,9 +1,3 @@
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.
@@ -173,24 +167,6 @@ dropbear (0.53-0.1) unstable; urgency=low
-- Matt Johnston <matt@ucc.asn.au> Thu, 24 Feb 2011 22:54:00 +0900
dropbear (0.52-2) unstable; urgency=low
* Make key utils part of dropbear-server package (since it's
required anyway, single binary saves space), rename -common to
-keyutils
* Don't make clean between builds, just rm *.o since only
top-level files change
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Nov 2008 21:54:00 +0900
dropbear (0.52-1) unstable; urgency=low
* Maemo port, split into 5 packages
(dropbear, dropbear-server, dropbear-client, dropbear-common, dropbear-scp).
This avoids conflicts with openssh package.
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Nov 2008 20:54:00 +0900
dropbear (0.52-0.1) unstable; urgency=low
* New upstream release.

79
debian/control vendored
View File

@@ -1,7 +1,7 @@
Source: dropbear
Section: user/network
Section: net
Priority: optional
Maintainer: Matt Johnston <matt@ucc.asn.au>
Maintainer: Gerrit Pape <pape@smarden.org>
Build-Depends: libz-dev
Standards-Version: 3.7.3.0
@@ -9,9 +9,6 @@ Package: dropbear
Architecture: any
Depends: ${shlibs:Depends}
Suggests: openssh-client, runit
Section: user/network
Conflicts: dropbear-server, dropbear-client, dropbear-keyutils, dropbear-scp
XB-Maemo-Display-Name: Dropbear SSH Client and Server
Description: lightweight SSH2 server and client
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
@@ -20,76 +17,4 @@ Description: lightweight SSH2 server and client
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
This package provides Dropbear client and server as a single binary,
as well as key utilities and SCP.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-server
Architecture: any
Depends: ${shlibs:Depends}
Section: user/network
Conflicts: dropbear, dropbear-keyutils
Provides: dropbear-keyutils
Recommends: dropbear-scp
XB-Maemo-Display-Name: Dropbear SSH Server
Description: lightweight SSH2 server
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
This package provides only the Dropbear server.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-client
Architecture: any
Conflicts: dropbear
Section: user/network
Depends: ${shlibs:Depends}
Recommends: dropbear-scp
Suggests: dropbear-keyutils
XB-Maemo-Display-Name: Dropbear SSH Client
Description: lightweight SSH2 client
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
This package provides only the Dropbear client.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-keyutils
Architecture: any
Conflicts: dropbear, dropbear-server
Section: user/network
XB-Maemo-Display-Name: Dropbear SSH Key Utils
Depends: ${shlibs:Depends}
Description: lightweight SSH2, key management utilities
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
This package provides dropbearkey and dropbearconvert programs,
for generating keys and converting to/from OpenSSH keys.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-scp
Architecture: any
Section: user/network
Conflicts: dropbear
XB-Maemo-Display-Name: Dropbear SCP
Depends: ${shlibs:Depends}
Description: lightweight SSH2 scp
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
This dropbear-scp package provides /usr/bin/scp.

View File

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

View File

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

View File

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

View File

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

View File

@@ -39,7 +39,7 @@ test -n "$DROPBEAR_RECEIVE_WINDOW" || \
case "$1" in
start)
test "$NO_START" = "0" || cancel '/etc/default/dropbear NO_START is set, Dropbear will not run.'
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /var/run/"$NAME".pid \
--exec "$DAEMON" -- -d "$DROPBEAR_DSSKEY" -r "$DROPBEAR_RSAKEY" \
@@ -52,7 +52,7 @@ case "$1" in
echo "$NAME."
;;
restart|force-reload)
test "$NO_START" = "0" || cancel '/etc/default/dropbear NO_START is set, Dropbear will not run.'
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/"$NAME".pid
sleep 1

144
debian/rules vendored
View File

@@ -20,6 +20,8 @@ ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
CC =diet -v -Os gcc -nostdinc
endif
DIR =$(shell pwd)/debian/dropbear
patch: deb-checkdir patch-stamp
patch-stamp:
for i in `ls -1 debian/diff/*.diff || :`; do \
@@ -34,15 +36,13 @@ config.status: patch-stamp configure
--build='$(DEB_BUILD_GNU_TYPE)' --prefix=/usr \
--mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info \
$(CONFFLAGS)
$(MAKE) clean
build: deb-checkdir build-stamp
build-stamp: config.status
$(MAKE) CC='$(CC)' LD='$(CC)'
touch build-stamp
clean: DIR=$(shell pwd)/debian/dropbear
clean: deb-checkdir deb-checkuid
clean: deb-checkdir deb-checkuid
test ! -r Makefile || $(MAKE) distclean
rm -f libtomcrypt/Makefile libtommath/Makefile
test ! -e patch-stamp || \
@@ -51,117 +51,22 @@ clean: deb-checkdir deb-checkuid
done
rm -f patch-stamp build-stamp config.log config.status
rm -rf '$(DIR)'
rm -rf '$(DIR)'-client
rm -rf '$(DIR)'-server
rm -rf '$(DIR)'-keyutils
rm -rf '$(DIR)'-scp
rm -f debian/files debian/substvars debian/copyright changelog
install-server: DIR=$(shell pwd)/debian/dropbear-server
install-server: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="dropbear dropbearkey dropbearconvert" MULTI=1
install: deb-checkdir deb-checkuid build-stamp
rm -rf '$(DIR)'
install -d -m0755 '$(DIR)'/etc/dropbear
# programs
install -d -m0755 '$(DIR)'/usr/bin
install -d -m0755 '$(DIR)'/usr/sbin
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearmulti \
'$(DIR)'/usr/lib/dropbear/dropbearmulti
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dropbearkey
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/sbin/dropbear
ln -s dropbearmulti '$(DIR)'/usr/lib/dropbear/dropbearconvert
# init and run scripts
install -d -m0755 '$(DIR)'/etc/init.d
install -m0755 debian/dropbear.init '$(DIR)'/etc/init.d/dropbear
install -m0755 debian/service/run '$(DIR)'/etc/dropbear/run
install -d -m0755 '$(DIR)'/etc/dropbear/log
install -m0755 debian/service/log '$(DIR)'/etc/dropbear/log/run
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
install -d -m0755 '$(DIR)'/usr/share/man/man8
for i in dropbear.8 ; do \
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
done
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
# copyright, changelog
cat debian/copyright.in LICENSE > debian/copyright
test -r changelog || ln -s CHANGES changelog
$(STRIP) -R .comment -R .note '$(DIR)'/usr/lib/dropbear/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/lib/dropbear/*
install-client: DIR=$(shell pwd)/debian/dropbear-client
install-client: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS=dbclient dbclient
install -m0755 dropbear '$(DIR)'/usr/sbin/dropbear
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 dbclient '$(DIR)'/usr/bin/dbclient
install -d -m0755 '$(DIR)'/usr/share/man/man1
install -m644 dbclient.1 '$(DIR)'/usr/share/man/man1/
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
$(STRIP) -R .comment -R .note '$(DIR)'/usr/bin/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/bin/*
install-keyutils: DIR=$(shell pwd)/debian/dropbear-keyutils
install-keyutils: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="dropbearkey dropbearconvert" MULTI=1
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 dropbearkey '$(DIR)'/usr/bin/dropbearkey
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearmulti \
'$(DIR)'/usr/lib/dropbear/dropbearmulti
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dropbearkey
ln -s dropbearmulti '$(DIR)'/usr/lib/dropbear/dropbearconvert
install -d -m0755 '$(DIR)'/usr/share/man/man8
for i in dropbearkey.8; do \
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
done
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
$(STRIP) -R .comment -R .note \
'$(DIR)'/usr/lib/dropbear/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/lib/dropbear/*
install-scp: DIR=$(shell pwd)/debian/dropbear-scp
install-scp: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="scp" scp
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 scp '$(DIR)'/usr/bin/scp
$(STRIP) -R .comment -R .note '$(DIR)'/usr/bin/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/bin/*
install-multi: DIR=$(shell pwd)/debian/dropbear
install-multi: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="dropbearkey dropbearconvert scp dropbear dbclient" MULTI=1
install -d -m0755 '$(DIR)'/etc/dropbear
# programs
install -d -m0755 '$(DIR)'/usr/bin
install -d -m0755 '$(DIR)'/usr/sbin
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearmulti \
'$(DIR)'/usr/lib/dropbear/dropbearmulti
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dropbearkey
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dbclient
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/scp
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/sbin/dropbear
ln -s dropbearmulti '$(DIR)'/usr/lib/dropbear/dropbearconvert
install -m0755 dropbearconvert \
'$(DIR)'/usr/lib/dropbear/dropbearconvert
$(STRIP) -R .comment -R .note '$(DIR)'/usr/sbin/* \
'$(DIR)'/usr/bin/* '$(DIR)'/usr/lib/dropbear/*
# init and run scripts
install -d -m0755 '$(DIR)'/etc/init.d
install -m0755 debian/dropbear.init '$(DIR)'/etc/init.d/dropbear
@@ -169,6 +74,7 @@ install-multi: deb-checkdir deb-checkuid config.status
install -d -m0755 '$(DIR)'/etc/dropbear/log
install -m0755 debian/service/log '$(DIR)'/etc/dropbear/log/run
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
# man pages
install -d -m0755 '$(DIR)'/usr/share/man/man8
install -d -m0755 '$(DIR)'/usr/share/man/man1
install -m644 dropbear.8 '$(DIR)'/usr/share/man/man8/
@@ -177,26 +83,18 @@ install-multi: deb-checkdir deb-checkuid config.status
done
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
$(STRIP) -R .comment -R .note '$(DIR)'/usr/lib/dropbear/*
# copyright, changelog
cat debian/copyright.in LICENSE >debian/copyright
test -r changelog || ln -s CHANGES changelog
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/lib/dropbear/*
install: install-client install-server install-keyutils install-multi install-scp
binary-indep:
binary-arch: install dropbear.deb dropbear-server.deb dropbear-keyutils.deb dropbear-scp.deb dropbear-client.deb
dpkg-gencontrol -isp -pdropbear -P'$(shell pwd)/debian'/dropbear
dpkg-gencontrol -isp -pdropbear-server -P'$(shell pwd)/debian'/dropbear-server
dpkg-gencontrol -isp -pdropbear-client -P'$(shell pwd)/debian'/dropbear-client
dpkg-gencontrol -isp -pdropbear-keyutils -P'$(shell pwd)/debian'/dropbear-keyutils
dpkg-gencontrol -isp -pdropbear-scp -P'$(shell pwd)/debian'/dropbear-scp
dpkg -b '$(shell pwd)/debian'/dropbear ..
dpkg -b '$(shell pwd)/debian'/dropbear-server ..
dpkg -b '$(shell pwd)/debian'/dropbear-keyutils ..
dpkg -b '$(shell pwd)/debian'/dropbear-scp ..
dpkg -b '$(shell pwd)/debian'/dropbear-client ..
binary-arch: install dropbear.deb
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/sbin/* '$(DIR)'/usr/bin/* \
'$(DIR)'/usr/lib/dropbear/*
dpkg-gencontrol -isp -pdropbear -P'$(DIR)'
dpkg -b '$(DIR)' ..
binary: binary-arch binary-indep

38
debug.h
View File

@@ -48,43 +48,15 @@
/*#define DEBUG_KEXHASH*/
/*#define DEBUG_RSA*/
/* The level of TRACE() statements */
#define DROPBEAR_VERBOSE_LEVEL 4
/* you don't need to touch this block */
#if DEBUG_TRACE
extern int debug_trace;
#endif
/* Enable debug trace levels.
We can't use __VA_ARGS_ here because Dropbear supports
old ~C89 compilers */
/* Default is to discard output ... */
#define DEBUG1(X)
#define DEBUG2(X)
#define DEBUG3(X)
#define TRACE(X) dropbear_trace X;
#define TRACE2(X) dropbear_trace2 X;
#else /*DEBUG_TRACE*/
#define TRACE(X)
#define TRACE2(X)
/* ... unless DEBUG_TRACE is high enough */
#if (DEBUG_TRACE>=1)
#undef DEBUG1
#define DEBUG1(X) dropbear_trace1 X;
#endif
#if (DEBUG_TRACE>=2)
#undef DEBUG2
#define DEBUG2(X) dropbear_trace2 X;
#endif
#if (DEBUG_TRACE>=3)
#undef DEBUG3
#define DEBUG3(X) dropbear_trace3 X;
#endif
#if (DEBUG_TRACE>=4)
#undef TRACE
#define TRACE(X) dropbear_trace4 X;
#endif
#if (DEBUG_TRACE>=5)
#undef TRACE2
#define TRACE2(X) dropbear_trace5 X;
#endif
#endif /*DEBUG_TRACE*/
/* To debug with GDB it is easier to run with no forking of child processes.
You will need to pass "-F" as well. */

View File

@@ -6,7 +6,7 @@
default_options.h documents compile-time options, and provides default values.
Local customisation should be added to localoptions.h which is
used if it exists in the build directory. Options defined there will override
used if it exists in the build directory. Options defined there will override
any options in this file.
Options can also be defined with -DDROPBEAR_XXX=[0,1] in Makefile CFLAGS
@@ -18,9 +18,7 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Listen on all interfaces */
#define DROPBEAR_DEFADDRESS ""
/* Default hostkey paths - these can be specified on the command line.
* Homedir is prepended if path begins with ~/
*/
/* Default hostkey paths - these can be specified on the command line */
#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key"
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
@@ -39,18 +37,8 @@ IMPORTANT: Some options will require "make clean" after changes */
#define NON_INETD_MODE 1
#define INETD_MODE 1
/* By default Dropbear will re-execute itself for each incoming connection so
that memory layout may be re-randomised (ASLR) - exploiting
vulnerabilities becomes harder. Re-exec causes slightly more memory use
per connection.
This option is ignored on non-Linux platforms at present */
#define DROPBEAR_REEXEC 1
/* Include verbose debug output, enabled with -v at runtime (repeat to increase).
* define which level of debug output you compile in
* TRACE1 - TRACE3 = approx 4 Kb (connection, remote identity, algos, auth type info)
* TRACE4 = approx 17 Kb (detailed before connection)
* TRACE5 = approx 8 Kb (detailed after connection) */
/* Include verbose debug output, enabled with -v at runtime.
* This will add a reasonable amount to your executable size. */
#define DEBUG_TRACE 0
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
@@ -78,7 +66,7 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Note: Both DROPBEAR_CLI_PROXYCMD and DROPBEAR_CLI_NETCAT must be set to
* allow multihop dbclient connections */
/* Allow using -J <proxycommand> to run the connection through a
/* Allow using -J <proxycommand> to run the connection through a
pipe to a program, rather the normal TCP connection */
#define DROPBEAR_CLI_PROXYCMD 1
@@ -92,11 +80,13 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Encryption - at least one required.
* AES128 should be enabled, some very old implementations might only
* support 3DES.
* Including both AES keysize variants (128 and 256) will result in
* Including both AES keysize variants (128 and 256) will result in
* a minimal size increase */
#define DROPBEAR_AES128 1
#define DROPBEAR_AES256 1
#define DROPBEAR_3DES 0
#define DROPBEAR_TWOFISH256 0
#define DROPBEAR_TWOFISH128 0
/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
* generally faster than AES256 on CPU w/o dedicated AES instructions,
@@ -118,7 +108,7 @@ 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
@@ -127,24 +117,19 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Hostkey/public key algorithms - at least one required, these are used
* for hostkey as well as for verifying signatures with pubkey auth.
* Removing either of these won't save very much space.
* RSA is recommended.
* RSA is recommended
* DSS may be necessary to connect to some systems though
* is not recommended for new keys.
* See: RSA_PRIV_FILENAME and DSS_PRIV_FILENAME */
is not recommended for new keys */
#define DROPBEAR_RSA 1
#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
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
* binary size - around 7,5kB on x86-64.
* See: ED25519_PRIV_FILENAME */
#define DROPBEAR_ED25519 1
/* SK_ECDSA/SK_ED25519 allows u2f security keys for public key auth.
* This is currently server-only. */
#define DROPBEAR_SK_ECDSA 1
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
binary size - around 7,5kB on x86-64 */
#define DROPBEAR_ED25519 1
#define DROPBEAR_SK_ED25519 1
/* RSA must be >=1024 */
@@ -179,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
@@ -220,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
@@ -237,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. */
@@ -282,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.
@@ -292,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"
@@ -339,6 +318,5 @@ be overridden at runtime with -I. 0 disables idle timeouts */
/* The default path. This will often get replaced by the shell */
#define DEFAULT_PATH "/usr/bin:/bin"
#define DEFAULT_ROOT_PATH "/usr/sbin:/usr/bin:/sbin:/bin"
#endif /* DROPBEAR_DEFAULT_OPTIONS_H_ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -8,7 +8,6 @@ srcdir=@srcdir@
# So that libtommath can include Dropbear headers for options and m_burn()
CFLAGS += -I$(srcdir) -I../libtomcrypt/src/headers/ -I$(srcdir)/../libtomcrypt/src/headers/ -I../ -I$(srcdir)/../
CFLAGS += -Wno-deprecated
CFLAGS += $(CPPFLAGS)
V = 1

54
netio.c
View File

@@ -20,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.
@@ -111,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
@@ -174,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;
@@ -187,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);
@@ -366,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) {
@@ -374,51 +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 */
#ifdef IP_TOS
/* Set the DSCP field for outbound IP packet priority.
rfc4594 has some guidance to meanings.
We set AF21 as "Low-Latency" class for interactive (tty session,
also handshake/setup packets). Other traffic is left at the default.
OpenSSH at present uses AF21/CS1, rationale
https://cvsweb.openbsd.org/src/usr.bin/ssh/readconf.c#rev1.284
Old Dropbear/OpenSSH and Debian/Ubuntu OpenSSH (at Jan 2022) use
IPTOS_LOWDELAY/IPTOS_THROUGHPUT
DSCP constants are from Linux headers, applicable to other platforms
such as macos.
*/
/* set the TOS bit for either ipv4 or ipv6 */
#ifdef IPTOS_LOWDELAY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
val = 0x48; /* IPTOS_DSCP_AF21 */
} else {
val = 0; /* default */
iptos_val = IPTOS_LOWDELAY;
} else if (prio == DROPBEAR_PRIO_BULK) {
iptos_val = IPTOS_THROUGHPUT;
}
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
#endif /* IP_TOS */
#endif
#ifdef HAVE_LINUX_PKT_SCHED_H
/* Set scheduling priority within the local Linux network stack */
if (prio == DROPBEAR_PRIO_LOWDELAY) {
val = TC_PRIO_INTERACTIVE;
} else {
val = 0;
so_prio_val = TC_PRIO_INTERACTIVE;
} else if (prio == DROPBEAR_PRIO_BULK) {
so_prio_val = TC_PRIO_BULK;
}
/* linux specific, sets QoS class. see tc-prio(8) */
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &val, sizeof(val));
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set SO_PRIORITY (%s)", strerror(errno)))
}

View File

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

View File

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

View File

@@ -72,15 +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" flag indicates it's re-executing itself */
int reexec_child;
/* Flags indicating whether to use ipv4 and ipv6 */
/* not used yet
@@ -92,6 +90,7 @@ typedef struct svr_runopts {
/* whether to print the MOTD */
int domotd;
#endif
int norootlogin;
#ifdef HAVE_GETGROUPLIST
@@ -154,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
@@ -198,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_ */

113
signkey.c
View File

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

View File

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

View File

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

View File

@@ -6,7 +6,6 @@
#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) {
hash_state hs;
@@ -41,14 +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);
/* TODO: allow "no-touch-required" or "verify-required" authorized_keys options */
if (!(flags & SSH_SK_USER_PRESENCE_REQD)) {
if (ret == DROPBEAR_SUCCESS) {
dropbear_log(LOG_WARNING, "Rejecting, user-presence not set");
}
ret = DROPBEAR_FAILURE;
}
TRACE(("leave buf_sk_ecdsa_verify, ret=%d", ret))
return ret;
}

View File

@@ -6,7 +6,6 @@
#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) {
@@ -32,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);
@@ -52,15 +50,10 @@ int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const bu
ret = DROPBEAR_SUCCESS;
}
/* TODO: allow "no-touch-required" or "verify-required" authorized_keys options */
if (!(flags & SSH_SK_USER_PRESENCE_REQD)) {
if (ret == DROPBEAR_SUCCESS) {
dropbear_log(LOG_WARNING, "Rejecting, user-presence 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;
}

5
ssh.h
View File

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

View File

@@ -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.
*
*/
@@ -108,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);
@@ -130,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 */
@@ -141,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,
@@ -174,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) {
@@ -191,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);
@@ -202,10 +202,8 @@ void svr_auth_pubkey(int valid_user) {
fp = sign_key_fingerprint(keyblob, keybloblen);
if (buf_verify(ses.payload, key, sigtype, signbuf) == DROPBEAR_SUCCESS) {
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);
"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)) {
@@ -213,6 +211,7 @@ void svr_auth_pubkey(int valid_user) {
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",
@@ -258,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) {
@@ -289,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);
@@ -312,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);
@@ -337,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);
@@ -381,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;
}
@@ -426,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 ||
@@ -435,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) {
@@ -477,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:
@@ -506,7 +460,7 @@ out:
* g-w, o-w */
static int checkpubkeyperms() {
char* filename = NULL;
char* filename = NULL;
int ret = DROPBEAR_FAILURE;
unsigned int len;
@@ -545,7 +499,7 @@ static int checkpubkeyperms() {
/* file looks ok, return success */
ret = DROPBEAR_SUCCESS;
out:
m_free(filename);
@@ -594,7 +548,7 @@ static int checkfileperm(char * filename) {
int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
const char* algo, unsigned int algolen,
const unsigned char* keyblob, unsigned int keybloblen) {
return checkpubkey_line(line, line_num, filename, algo, algolen, keyblob, keybloblen, NULL);
return checkpubkey_line(line, line_num, filename, algo, algolen, keyblob, keybloblen);
}
#endif

View File

@@ -115,9 +115,6 @@ void svr_pubkey_options_cleanup() {
}
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,

View File

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

View File

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

View File

@@ -35,30 +35,26 @@ static size_t listensockets(int *sock, size_t sockcount, int *maxfd);
static void sigchld_handler(int dummy);
static void sigsegv_handler(int);
static void sigintterm_handler(int fish);
#if INETD_MODE
static void main_inetd(void);
static void main_noinetd(int argc, char ** argv, const char* multipath);
#endif
#if NON_INETD_MODE
static void main_noinetd(void);
#endif
static void commonsetup(void);
#if defined(DBMULTI_dropbear) || !DROPBEAR_MULTI
#if defined(DBMULTI_dropbear) && DROPBEAR_MULTI
int dropbear_main(int argc, char ** argv, const char* multipath)
int dropbear_main(int argc, char ** argv)
#else
int main(int argc, char ** argv)
#endif
{
#if !DROPBEAR_MULTI
const char* multipath = NULL;
#endif
_dropbear_exit = svr_dropbear_exit;
_dropbear_log = svr_dropbear_log;
disallow_core();
if (argc < 1) {
dropbear_exit("Bad argc");
}
/* get commandline options */
svr_getopts(argc, argv);
@@ -70,21 +66,8 @@ int main(int argc, char ** argv)
}
#endif
#if DROPBEAR_DO_REEXEC
if (svr_opts.reexec_child) {
#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,18 +85,23 @@ static void main_inetd() {
seedrandom();
if (!svr_opts.reexec_child) {
/* 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
/* 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
@@ -125,7 +113,7 @@ static void main_inetd() {
#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;
@@ -133,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];
@@ -141,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. */
@@ -155,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)
@@ -167,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;
@@ -210,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);
@@ -230,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;
@@ -315,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 */
@@ -345,41 +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" to the args and re-execute ourself. */
char **new_argv = m_malloc(sizeof(char*) * (argc+3));
int pos0 = 0, new_argc = argc+1;
/* 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-1] = "-2";
new_argv[new_argc] = NULL;
if ((dup2(childsock, STDIN_FILENO) < 0)) {
dropbear_exit("dup2 failed: %s", strerror(errno));
}
if (fcntl(childsock, F_SETFD, FD_CLOEXEC) < 0) {
TRACE(("cloexec for childsock %d failed: %s", childsock, strerror(errno)))
}
/* Re-execute ourself */
fexecve(execfd, new_argv, environ);
/* Not reached on success */
/* Fall back on plain fork otherwise.
* To be removed in future once re-exec has been well tested */
dropbear_log(LOG_WARNING, "fexecve failed, disabling re-exec: %s", strerror(errno));
m_close(STDIN_FILENO);
m_free(new_argv);
#endif /* DROPBEAR_DO_REEXEC */
}
/* start the session */
svr_session(childsock, childpipe[1]);
/* don't return */

View File

@@ -109,7 +109,7 @@ static void printhelp(const char * progname) {
#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
@@ -163,7 +163,7 @@ void svr_getopts(int argc, char ** argv) {
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
@@ -246,12 +246,6 @@ 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':
svr_opts.reexec_child = 1;
break;
#endif
case 'p':
nextisport = 1;
@@ -310,7 +304,7 @@ void svr_getopts(int argc, char ** argv) {
#endif
#if DEBUG_TRACE
case 'v':
debug_trace++;
debug_trace = 1;
break;
#endif
case 'V':
@@ -425,19 +419,6 @@ 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 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 DROPBEAR_PLUGIN
if (pubkey_plugin) {
char *args = strchr(pubkey_plugin, ',');
@@ -452,34 +433,56 @@ void svr_getopts(int argc, char ** argv) {
}
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) {
@@ -508,14 +511,12 @@ static void loadhostkey_helper(const char *name, void** src, void** dst, int fat
/* Must be called after syslog/etc is working */
static void loadhostkey(const char *keyfile, int fatal_duplicate) {
sign_key * read_key = new_sign_key();
char *expand_path = expand_homedir_path(keyfile);
enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
if (readhostkey(expand_path, read_key, &type) == DROPBEAR_FAILURE) {
if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) {
if (!svr_opts.delay_hostkey) {
dropbear_log(LOG_WARNING, "Failed loading %s", expand_path);
dropbear_log(LOG_WARNING, "Failed loading %s", keyfile);
}
}
m_free(expand_path);
#if DROPBEAR_RSA
if (type == DROPBEAR_SIGNKEY_RSA) {

View File

@@ -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,10 +289,11 @@ static int newtcpdirect(struct Channel * channel) {
goto out;
}
snprintf(portstring, sizeof(portstring), "%u", destport);
channel->conn_pending = connect_remote(desthost, portstring, channel_connect_done,
channel, NULL, NULL, DROPBEAR_PRIO_NORMAL);
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);
err = SSH_OPEN_IN_PROGRESS;
out:

View File

@@ -4,7 +4,7 @@
*******************************************************************/
#ifndef DROPBEAR_VERSION
#define DROPBEAR_VERSION "2022.82"
#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". */
@@ -131,6 +124,14 @@
#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 */
@@ -157,11 +158,9 @@
#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) \
@@ -229,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))
@@ -272,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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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