dropbear: cherry-pick upstream patches

critical fixes:
- libtommath: possible integer overflow (CVE-2023-36328)
- implement Strict KEX mode (CVE-2023-48795)

various fixes:
- fix DROPBEAR_DSS and DROPBEAR_RSA config options
- y2038 issues
- remove SO_LINGER socket option
- make banner reading failure non-fatal
- fix "noremotetcp" behavior
- don't try to shutdown a pty
- fix test for multiuser kernels

adds new features:
- option to bind to interface
- allow inetd with non-syslog
- ignore unsupported command line options with dropbearkey

Signed-off-by: Konstantin Demin <rockdrilla@gmail.com>
This commit is contained in:
Konstantin Demin 2024-01-09 03:40:01 +03:00 committed by Rui Salvaterra
parent d4dfb566e2
commit b5cde26048
23 changed files with 1520 additions and 2 deletions

View File

@ -114,7 +114,6 @@ DB_OPT_COMMON = \
DEFAULT_PATH|"$(TARGET_INIT_PATH)" \ DEFAULT_PATH|"$(TARGET_INIT_PATH)" \
!!LOCAL_IDENT|"SSH-2.0-dropbear" \ !!LOCAL_IDENT|"SSH-2.0-dropbear" \
DROPBEAR_CLI_NETCAT|0 \ DROPBEAR_CLI_NETCAT|0 \
!!DROPBEAR_DSS|0 \
DROPBEAR_DSS|0 \ DROPBEAR_DSS|0 \
DO_MOTD|0 \ DO_MOTD|0 \

View File

@ -0,0 +1,104 @@
From 36a03132634a17c667c0fac0a8e1519b3d1b71c6 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 28 Nov 2022 21:12:23 +0800
Subject: Add #if DROPBEAR_RSA guards
Fixes building with DROPBEAR_RSA disabled.
Closes #197
---
signkey.c | 8 +++++++-
signkey.h | 2 ++
sysoptions.h | 5 +----
3 files changed, 10 insertions(+), 5 deletions(-)
--- a/signkey.c
+++ b/signkey.c
@@ -120,6 +120,7 @@ enum signkey_type signkey_type_from_name
/* Special case for rsa-sha2-256. This could be generalised if more
signature names are added that aren't 1-1 with public key names */
const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) {
+#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
if (type == DROPBEAR_SIGNATURE_RSA_SHA256) {
if (namelen) {
@@ -136,11 +137,13 @@ const char* signature_name_from_type(enu
return SSH_SIGNKEY_RSA;
}
#endif
+#endif /* DROPBEAR_RSA */
return signkey_name_from_type((enum signkey_type)type, namelen);
}
/* Returns DROPBEAR_SIGNATURE_NONE if none match */
enum signature_type signature_type_from_name(const char* name, unsigned int namelen) {
+#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256)
&& memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) {
@@ -153,10 +156,11 @@ enum signature_type signature_type_from_
return DROPBEAR_SIGNATURE_RSA_SHA1;
}
#endif
+#endif /* DROPBEAR_RSA */
return (enum signature_type)signkey_type_from_name(name, namelen);
}
-/* Returns the signature type from a key type. Must not be called
+/* Returns the signature type from a key type. Must not be called
with RSA keytype */
enum signature_type signature_type_from_signkey(enum signkey_type keytype) {
#if DROPBEAR_RSA
@@ -167,6 +171,7 @@ enum signature_type signature_type_from_
}
enum signkey_type signkey_type_from_signature(enum signature_type sigtype) {
+#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
return DROPBEAR_SIGNKEY_RSA;
@@ -177,6 +182,7 @@ enum signkey_type signkey_type_from_sign
return DROPBEAR_SIGNKEY_RSA;
}
#endif
+#endif /* DROPBEAR_RSA */
assert((int)sigtype < (int)DROPBEAR_SIGNKEY_NUM_NAMED);
return (enum signkey_type)sigtype;
}
--- a/signkey.h
+++ b/signkey.h
@@ -79,12 +79,14 @@ enum signature_type {
DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519,
#endif
#endif
+#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA1
DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */
#endif
#if DROPBEAR_RSA_SHA256
DROPBEAR_SIGNATURE_RSA_SHA256 = 101, /* rsa-sha2-256 signature. has a ssh-rsa key */
#endif
+#endif /* DROPBEAR_RSA */
DROPBEAR_SIGNATURE_NONE = DROPBEAR_SIGNKEY_NONE,
};
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -137,7 +137,7 @@
/* Debian doesn't define this in system headers */
#if !defined(LTM_DESC) && (DROPBEAR_ECC)
-#define LTM_DESC
+#define LTM_DESC
#endif
#define DROPBEAR_ECC_256 (DROPBEAR_ECC)
@@ -151,9 +151,6 @@
* signing operations slightly slower. */
#define DROPBEAR_RSA_BLINDING 1
-#ifndef DROPBEAR_RSA_SHA1
-#define DROPBEAR_RSA_SHA1 DROPBEAR_RSA
-#endif
#ifndef DROPBEAR_RSA_SHA256
#define DROPBEAR_RSA_SHA256 DROPBEAR_RSA
#endif

View File

@ -0,0 +1,198 @@
From ec2215726cffb976019d08ebf569edd2229e9dba Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Thu, 1 Dec 2022 11:34:43 +0800
Subject: Fix y2038 issues with time_t conversion
These changes were identified by building with and without
-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
on 32-bit arm, logging warnings to files.
-Wconversion was added to CFLAGS in both builds.
Then a "diff -I Wconversion log1 log2" shows new warnings that appear
with the 64-bit time_t. There are a few false positives that have been
fixed for quietness.
struct logininfo and struct wtmp are still problematic, those will
need to be handled by libc.
---
common-session.c | 43 +++++++++++++++++++++++++++----------------
dbutil.c | 2 +-
loginrec.c | 2 ++
loginrec.h | 4 ++--
runopts.h | 4 ++--
svr-auth.c | 2 +-
6 files changed, 35 insertions(+), 22 deletions(-)
--- a/common-session.c
+++ b/common-session.c
@@ -519,15 +519,24 @@ static void send_msg_keepalive() {
ses.last_packet_time_idle = old_time_idle;
}
+/* Returns the difference in seconds, clamped to LONG_MAX */
+static long elapsed(time_t now, time_t prev) {
+ time_t del = now - prev;
+ if (del > LONG_MAX) {
+ return LONG_MAX;
+ }
+ return (long)del;
+}
+
/* Check all timeouts which are required. Currently these are the time for
* user authentication, and the automatic rekeying. */
static void checktimeouts() {
time_t now;
now = monotonic_now();
-
+
if (IS_DROPBEAR_SERVER && ses.connect_time != 0
- && now - ses.connect_time >= AUTH_TIMEOUT) {
+ && elapsed(now, ses.connect_time) >= AUTH_TIMEOUT) {
dropbear_close("Timeout before auth");
}
@@ -537,45 +546,47 @@ static void checktimeouts() {
}
if (!ses.kexstate.sentkexinit
- && (now - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
+ && (elapsed(now, ses.kexstate.lastkextime) >= KEX_REKEY_TIMEOUT
|| ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) {
TRACE(("rekeying after timeout or max data reached"))
send_msg_kexinit();
}
-
+
if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
/* Avoid sending keepalives prior to auth - those are
not valid pre-auth packet types */
/* Send keepalives if we've been idle */
- if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
+ if (elapsed(now, ses.last_packet_time_any_sent) >= opts.keepalive_secs) {
send_msg_keepalive();
}
/* Also send an explicit keepalive message to trigger a response
if the remote end hasn't sent us anything */
- if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
- && now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
+ if (elapsed(now, ses.last_packet_time_keepalive_recv) >= opts.keepalive_secs
+ && elapsed(now, ses.last_packet_time_keepalive_sent) >= opts.keepalive_secs) {
send_msg_keepalive();
}
- if (now - ses.last_packet_time_keepalive_recv
+ if (elapsed(now, ses.last_packet_time_keepalive_recv)
>= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
dropbear_exit("Keepalive timeout");
}
}
- if (opts.idle_timeout_secs > 0
- && now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
+ if (opts.idle_timeout_secs > 0
+ && elapsed(now, ses.last_packet_time_idle) >= opts.idle_timeout_secs) {
dropbear_close("Idle timeout");
}
}
-static void update_timeout(long limit, long now, long last_event, long * timeout) {
- TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
- limit, now, last_event, *timeout))
+static void update_timeout(long limit, time_t now, time_t last_event, long * timeout) {
+ TRACE2(("update_timeout limit %ld, now %llu, last %llu, timeout %ld",
+ limit,
+ (unsigned long long)now,
+ (unsigned long long)last_event, *timeout))
if (last_event > 0 && limit > 0) {
- *timeout = MIN(*timeout, last_event+limit-now);
+ *timeout = MIN(*timeout, elapsed(now, last_event) + limit);
TRACE2(("new timeout %ld", *timeout))
}
}
@@ -584,7 +595,7 @@ static long select_timeout() {
/* determine the minimum timeout that might be required, so
as to avoid waking when unneccessary */
long timeout = KEX_REKEY_TIMEOUT;
- long now = monotonic_now();
+ time_t now = monotonic_now();
if (!ses.kexstate.sentkexinit) {
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
@@ -596,7 +607,7 @@ static long select_timeout() {
}
if (ses.authstate.authdone) {
- update_timeout(opts.keepalive_secs, now,
+ update_timeout(opts.keepalive_secs, now,
MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
&timeout);
}
--- a/dbutil.c
+++ b/dbutil.c
@@ -724,7 +724,7 @@ void gettime_wrapper(struct timespec *no
/* Fallback for everything else - this will sometimes go backwards */
gettimeofday(&tv, NULL);
now->tv_sec = tv.tv_sec;
- now->tv_nsec = 1000*tv.tv_usec;
+ now->tv_nsec = 1000*(long)tv.tv_usec;
}
/* second-resolution monotonic timestamp */
--- a/loginrec.c
+++ b/loginrec.c
@@ -459,6 +459,7 @@ line_abbrevname(char *dst, const char *s
void
set_utmp_time(struct logininfo *li, struct utmp *ut)
{
+ /* struct utmp in glibc isn't y2038 safe yet */
# ifdef HAVE_STRUCT_UTMP_UT_TV
ut->ut_tv.tv_sec = li->tv_sec;
ut->ut_tv.tv_usec = li->tv_usec;
@@ -1272,6 +1273,7 @@ lastlog_construct(struct logininfo *li,
(void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
strlcpy(last->ll_host, li->hostname,
MIN_SIZEOF(last->ll_host, li->hostname));
+ /* struct lastlog in glibc isn't y2038 safe yet */
last->ll_time = li->tv_sec;
}
--- a/loginrec.h
+++ b/loginrec.h
@@ -139,8 +139,8 @@ struct logininfo {
/* struct timeval (sys/time.h) isn't always available, if it isn't we'll
* use time_t's value as tv_sec and set tv_usec to 0
*/
- unsigned int tv_sec;
- unsigned int tv_usec;
+ time_t tv_sec;
+ suseconds_t tv_usec;
union login_netinfo hostaddr; /* caller's host address(es) */
}; /* struct logininfo */
--- a/runopts.h
+++ b/runopts.h
@@ -39,8 +39,8 @@ typedef struct runopts {
int listen_fwd_all;
#endif
unsigned int recv_window;
- time_t keepalive_secs; /* Time between sending keepalives. 0 is off */
- time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
+ long keepalive_secs; /* Time between sending keepalives. 0 is off */
+ long idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
int usingsyslog;
#ifndef DISABLE_ZLIB
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -389,7 +389,7 @@ void send_msg_userauth_failure(int parti
Beware of integer overflow if increasing these values */
const unsigned int mindelay = 250000000;
const unsigned int vardelay = 100000000;
- unsigned int rand_delay;
+ suseconds_t rand_delay;
struct timespec delay;
gettime_wrapper(&delay);

View File

@ -0,0 +1,25 @@
From c043efb47c3173072fa636ca0da0d19875d4511f Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Tue, 6 Dec 2022 22:34:11 +0800
Subject: Fix so DROPBEAR_DSS is only forced for fuzzing
Regression from 787391ea3b5af2acf5e3c83372510f0c79477ad7,
was missing fuzzing conditional
---
sysoptions.h | 2 ++
1 file changed, 2 insertions(+)
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -380,9 +380,11 @@
#endif
/* Fuzzing expects all key types to be enabled */
+#if DROPBEAR_FUZZ
#if defined(DROPBEAR_DSS)
#undef DROPBEAR_DSS
#endif
#define DROPBEAR_DSS 1
+#endif
/* no include guard for this file */

View File

@ -0,0 +1,24 @@
From 860721558837441ab45019858e710a2625ffa46e Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Wed, 7 Dec 2022 13:04:10 +0800
Subject: Allow users's own gid in pty permission check
This allows non-root Dropbear to work even without devpts gid=5 mount
option on Linux.
---
sshpty.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/sshpty.c
+++ b/sshpty.c
@@ -380,7 +380,9 @@ pty_setowner(struct passwd *pw, const ch
tty_name, strerror(errno));
}
- if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
+ /* Allow either "tty" gid or user's own gid. On Linux with openpty()
+ * this varies depending on the devpts mount options */
+ if (st.st_uid != pw->pw_uid || !(st.st_gid == gid || st.st_gid == pw->pw_gid)) {
if (chown(tty_name, pw->pw_uid, gid) < 0) {
if (errno == EROFS &&
(st.st_uid == pw->pw_uid || st.st_uid == 0)) {

View File

@ -0,0 +1,123 @@
From 01415ef8269e594a647f67ea0729ca8b590679de Mon Sep 17 00:00:00 2001
From: Francois Perrad <francois.perrad@gadz.org>
Date: Thu, 22 Dec 2022 10:19:54 +0100
Subject: const parameter mp_int
---
bignum.c | 2 +-
bignum.h | 2 +-
buffer.c | 2 +-
buffer.h | 2 +-
dbrandom.c | 2 +-
dbrandom.h | 2 +-
dbutil.c | 2 +-
dbutil.h | 2 +-
genrsa.c | 4 ++--
9 files changed, 10 insertions(+), 10 deletions(-)
--- a/bignum.c
+++ b/bignum.c
@@ -93,7 +93,7 @@ void bytes_to_mp(mp_int *mp, const unsig
/* hash the ssh representation of the mp_int mp */
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
- hash_state *hs, mp_int *mp) {
+ hash_state *hs, const mp_int *mp) {
buffer * buf;
buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
--- a/bignum.h
+++ b/bignum.h
@@ -33,6 +33,6 @@ void m_mp_alloc_init_multi(mp_int **mp,
void m_mp_free_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
- hash_state *hs, mp_int *mp);
+ hash_state *hs, const mp_int *mp);
#endif /* DROPBEAR_BIGNUM_H_ */
--- a/buffer.c
+++ b/buffer.c
@@ -299,7 +299,7 @@ void buf_putbytes(buffer *buf, const uns
/* for our purposes we only need positive (or 0) numbers, so will
* fail if we get negative numbers */
-void buf_putmpint(buffer* buf, mp_int * mp) {
+void buf_putmpint(buffer* buf, const mp_int * mp) {
size_t written;
unsigned int len, pad = 0;
TRACE2(("enter buf_putmpint"))
--- a/buffer.h
+++ b/buffer.h
@@ -65,7 +65,7 @@ void buf_putint(buffer* buf, unsigned in
void buf_putstring(buffer* buf, const char* str, unsigned int len);
void buf_putbufstring(buffer *buf, const buffer* buf_str);
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
-void buf_putmpint(buffer* buf, mp_int * mp);
+void buf_putmpint(buffer* buf, const mp_int * mp);
int buf_getmpint(buffer* buf, mp_int* mp);
unsigned int buf_getint(buffer* buf);
--- a/dbrandom.c
+++ b/dbrandom.c
@@ -347,7 +347,7 @@ void genrandom(unsigned char* buf, unsig
* rand must be an initialised *mp_int for the result.
* the result rand satisfies: 0 < rand < max
* */
-void gen_random_mpint(mp_int *max, mp_int *rand) {
+void gen_random_mpint(const mp_int *max, mp_int *rand) {
unsigned char *randbuf = NULL;
unsigned int len = 0;
--- a/dbrandom.h
+++ b/dbrandom.h
@@ -30,6 +30,6 @@
void seedrandom(void);
void genrandom(unsigned char* buf, unsigned int len);
void addrandom(const unsigned char * buf, unsigned int len);
-void gen_random_mpint(mp_int *max, mp_int *rand);
+void gen_random_mpint(const mp_int *max, mp_int *rand);
#endif /* DROPBEAR_RANDOM_H_ */
--- a/dbutil.c
+++ b/dbutil.c
@@ -442,7 +442,7 @@ void printhex(const char * label, const
}
}
-void printmpint(const char *label, mp_int *mp) {
+void printmpint(const char *label, const mp_int *mp) {
buffer *buf = buf_new(1000);
buf_putmpint(buf, mp);
fprintf(stderr, "%d bits ", mp_count_bits(mp));
--- a/dbutil.h
+++ b/dbutil.h
@@ -53,7 +53,7 @@ void dropbear_trace3(const char* format,
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 printmpint(const char *label, const mp_int *mp);
void debug_start_net(void);
extern int debug_trace;
#endif
--- a/genrsa.c
+++ b/genrsa.c
@@ -34,7 +34,7 @@
#if DROPBEAR_RSA
static void getrsaprime(mp_int* prime, mp_int *primeminus,
- mp_int* rsa_e, unsigned int size_bytes);
+ const mp_int* rsa_e, unsigned int size_bytes);
/* mostly taken from libtomcrypt's rsa key generation routine */
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
@@ -89,7 +89,7 @@ dropbear_rsa_key * gen_rsa_priv_key(unsi
/* return a prime suitable for p or q */
static void getrsaprime(mp_int* prime, mp_int *primeminus,
- mp_int* rsa_e, unsigned int size_bytes) {
+ const mp_int* rsa_e, unsigned int size_bytes) {
unsigned char *buf;
int trials;

View File

@ -0,0 +1,21 @@
From 39d955c49f31fc155e885447ee2be61c869d8c2d Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Tue, 3 Jan 2023 22:05:14 +0800
Subject: Add missing break in switch
Has no effect on execution, the fallthrough does nothing
Closes #208
---
dropbearkey.c | 1 +
1 file changed, 1 insertion(+)
--- a/dropbearkey.c
+++ b/dropbearkey.c
@@ -139,6 +139,7 @@ static void check_signkey_bits(enum sign
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
exit(EXIT_FAILURE);
}
+ break;
#endif
default:
(void)0; /* quiet, compiler. ecdsa handles checks itself */

View File

@ -0,0 +1,29 @@
From 7a53c7f0f4b3eb23e002819553cb45558642c01d Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Wed, 4 Jan 2023 20:32:23 +0800
Subject: Fix building only client or server
Regressed when -Wundef was added
Fixes #210
---
sysoptions.h | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -10,6 +10,14 @@
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
#define PROGNAME "dropbear"
+#ifndef DROPBEAR_CLIENT
+#define DROPBEAR_CLIENT 0
+#endif
+
+#ifndef DROPBEAR_SERVER
+#define DROPBEAR_SERVER 0
+#endif
+
/* Spec recommends after one hour or 1 gigabyte of data. One hour
* is a bit too verbose, so we try 8 hours */
#ifndef KEX_REKEY_TIMEOUT

View File

@ -0,0 +1,94 @@
From a113381c12a2da3c9b7bd594f47a1b2657bdfdf2 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sun, 12 Feb 2023 22:44:32 +0800
Subject: Disable rsa signatures when no rsa hostkey
Otherwise Dropbear will offer RSA as a hostkey signature option, but the
session will exit with an assertion or NULL pointer dereference once
that algorithm is negotiated.
This likely regressed in 2020.79 when signature vs key type enums were
split, for rsa-sha256.
Fixes #219 on github
---
svr-runopts.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -505,11 +505,11 @@ static void addportandaddress(const char
svr_opts.portcount++;
}
-static void disablekey(int type) {
+static void disablekey(enum signature_type type) {
int i;
TRACE(("Disabling key type %d", type))
for (i = 0; sigalgs[i].name != NULL; i++) {
- if (sigalgs[i].val == type) {
+ if ((int)sigalgs[i].val == (int)type) {
sigalgs[i].usable = 0;
break;
}
@@ -624,7 +624,8 @@ void load_all_hostkeys() {
#if DROPBEAR_RSA
if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) {
- disablekey(DROPBEAR_SIGNKEY_RSA);
+ disablekey(DROPBEAR_SIGNATURE_RSA_SHA256);
+ disablekey(DROPBEAR_SIGNATURE_RSA_SHA1);
} else {
any_keys = 1;
}
@@ -632,7 +633,7 @@ void load_all_hostkeys() {
#if DROPBEAR_DSS
if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) {
- disablekey(DROPBEAR_SIGNKEY_DSS);
+ disablekey(DROPBEAR_SIGNATURE_DSS);
} else {
any_keys = 1;
}
@@ -666,35 +667,35 @@ void load_all_hostkeys() {
#if DROPBEAR_ECC_256
if (!svr_opts.hostkey->ecckey256
&& (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) {
- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
+ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP256);
}
#endif
#if DROPBEAR_ECC_384
if (!svr_opts.hostkey->ecckey384
&& (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) {
- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
+ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP384);
}
#endif
#if DROPBEAR_ECC_521
if (!svr_opts.hostkey->ecckey521
&& (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) {
- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
+ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP521);
}
#endif
#endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519
if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) {
- disablekey(DROPBEAR_SIGNKEY_ED25519);
+ disablekey(DROPBEAR_SIGNATURE_ED25519);
} else {
any_keys = 1;
}
#endif
#if DROPBEAR_SK_ECDSA
- disablekey(DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256);
+ disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256);
#endif
#if DROPBEAR_SK_ED25519
- disablekey(DROPBEAR_SIGNKEY_SK_ED25519);
+ disablekey(DROPBEAR_SIGNATURE_SK_ED25519);
#endif
if (!any_keys) {

View File

@ -0,0 +1,27 @@
From 3292b8c6f1e5fcc405fa0f7a20e90a60f74037b2 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sun, 12 Feb 2023 23:00:00 +0800
Subject: Use write() rather than fprintf() in segv handler
fprintf isn't guaranteed safe (though hasn't had any problems reported).
---
svr-main.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
--- a/svr-main.c
+++ b/svr-main.c
@@ -420,8 +420,12 @@ static void sigchld_handler(int UNUSED(u
/* catch any segvs */
static void sigsegv_handler(int UNUSED(unused)) {
- fprintf(stderr, "Aiee, segfault! You should probably report "
- "this as a bug to the developer\n");
+ int i;
+ const char *msg = "Aiee, segfault! You should probably report "
+ "this as a bug to the developer\n";
+ i = write(STDERR_FILENO, msg, strlen(msg));
+ /* ignore short writes */
+ (void)i;
_exit(EXIT_FAILURE);
}

View File

@ -0,0 +1,39 @@
From 5040f21cb4ee6ade966e60c6d5a3c270d03de1f1 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 1 May 2023 22:05:43 +0800
Subject: Remove SO_LINGER
It could cause channels to take up to 5 seconds to close(), which would block
the entire process. On busy TCP forwarding sessions this would result in
channels seeming stuck and new connections not being accepted.
We don't need to monitor for flushing failures since we can't report errors, so
SO_LINGER wasn't useful.
Thanks to GektorUA for reporting and testing
Fixes #230
---
netio.c | 4 ----
1 file changed, 4 deletions(-)
--- a/netio.c
+++ b/netio.c
@@ -472,7 +472,6 @@ int dropbear_listen(const char* address,
struct addrinfo hints, *res = NULL, *res0 = NULL;
int err;
unsigned int nsock;
- struct linger linger;
int val;
int sock;
uint16_t *allocated_lport_p = NULL;
@@ -551,9 +550,6 @@ int dropbear_listen(const char* address,
val = 1;
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
- linger.l_onoff = 1;
- linger.l_linger = 5;
- setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {

View File

@ -0,0 +1,147 @@
From fb64db9eac3fdc6434f2dc7b5ea407fe5df76e6f Mon Sep 17 00:00:00 2001
From: Diederik De Coninck <diederik.deconinck_ext@softathome.com>
Date: Tue, 11 Apr 2023 15:38:04 +0200
Subject: Add option to bind to interface
---
netio.c | 13 +++++++++++--
netio.h | 2 +-
runopts.h | 1 +
svr-main.c | 2 +-
svr-runopts.c | 9 +++++++++
svr-tcpfwd.c | 1 +
tcp-accept.c | 2 +-
tcpfwd.h | 1 +
8 files changed, 26 insertions(+), 5 deletions(-)
--- a/netio.c
+++ b/netio.c
@@ -467,7 +467,7 @@ int get_sock_port(int sock) {
* failure, if errstring wasn't NULL, it'll be a newly malloced error
* string.*/
int dropbear_listen(const char* address, const char* port,
- int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
+ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface) {
struct addrinfo hints, *res = NULL, *res0 = NULL;
int err;
@@ -497,7 +497,11 @@ int dropbear_listen(const char* address,
TRACE(("dropbear_listen: local loopback"))
} else {
if (address[0] == '\0') {
- TRACE(("dropbear_listen: all interfaces"))
+ if (interface) {
+ TRACE(("dropbear_listen: %s", interface))
+ } else {
+ TRACE(("dropbear_listen: all interfaces"))
+ }
address = NULL;
}
hints.ai_flags = AI_PASSIVE;
@@ -551,6 +555,11 @@ int dropbear_listen(const char* address,
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+ if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) {
+ dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE");
+ TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno)))
+ }
+
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {
int on = 1;
--- a/netio.h
+++ b/netio.h
@@ -19,7 +19,7 @@ void get_socket_address(int fd, char **l
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port, int host_lookup);
int dropbear_listen(const char* address, const char* port,
- int *socks, unsigned int sockcount, char **errstring, int *maxfd);
+ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface);
struct dropbear_progress_connection;
--- a/runopts.h
+++ b/runopts.h
@@ -128,6 +128,7 @@ typedef struct svr_runopts {
char * pidfile;
char * forced_command;
+ char* interface;
#if DROPBEAR_PLUGIN
/* malloced */
--- a/svr-main.c
+++ b/svr-main.c
@@ -488,7 +488,7 @@ static size_t listensockets(int *socks,
nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &socks[sockpos],
sockcount - sockpos,
- &errstring, maxfd);
+ &errstring, maxfd, svr_opts.interface);
if (nsock < 0) {
dropbear_log(LOG_WARNING, "Failed listening on '%s': %s",
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -98,6 +98,8 @@ static void printhelp(const char * progn
" (default port is %s if none specified)\n"
"-P PidFile Create pid file PidFile\n"
" (default %s)\n"
+ "-l <interface>\n"
+ " interface to bind on\n"
#if INETD_MODE
"-i Start for inetd\n"
#endif
@@ -265,6 +267,9 @@ void svr_getopts(int argc, char ** argv)
case 'P':
next = &svr_opts.pidfile;
break;
+ case 'l':
+ next = &svr_opts.interface;
+ break;
#if DO_MOTD
/* motd is displayed by default, -m turns it off */
case 'm':
@@ -438,6 +443,10 @@ void svr_getopts(int argc, char ** argv)
dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
}
+ if (svr_opts.interface) {
+ dropbear_log(LOG_INFO, "Binding to interface '%s'", svr_opts.interface);
+ }
+
if (reexec_fd_arg) {
if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
|| svr_opts.reexec_childpipe < 0) {
--- a/svr-tcpfwd.c
+++ b/svr-tcpfwd.c
@@ -205,6 +205,7 @@ static int svr_remotetcpreq(int *allocat
tcpinfo->listenport = port;
tcpinfo->chantype = &svr_chan_tcpremote;
tcpinfo->tcp_type = forwarded;
+ tcpinfo->interface = svr_opts.interface;
tcpinfo->request_listenaddr = request_addr;
if (!opts.listen_fwd_all || (strcmp(request_addr, "localhost") == 0) ) {
--- a/tcp-accept.c
+++ b/tcp-accept.c
@@ -117,7 +117,7 @@ int listen_tcpfwd(struct TCPListener* tc
snprintf(portstring, sizeof(portstring), "%u", tcpinfo->listenport);
nsocks = dropbear_listen(tcpinfo->listenaddr, portstring, socks,
- DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd);
+ DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd, tcpinfo->interface);
if (nsocks < 0) {
dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
m_free(errstring);
--- a/tcpfwd.h
+++ b/tcpfwd.h
@@ -42,6 +42,7 @@ struct TCPListener {
unsigned int listenport;
/* The address that the remote host asked to listen on */
char *request_listenaddr;
+ char* interface;
const struct ChanType *chantype;
enum {direct, forwarded} tcp_type;

View File

@ -0,0 +1,50 @@
From 031d09b47912b2401f4934667c0b6f857ede61ee Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Tue, 18 Jul 2023 23:20:16 +0800
Subject: Add ifdef guards for SO_BINDTODEVICE
---
netio.c | 2 ++
svr-runopts.c | 4 ++++
2 files changed, 6 insertions(+)
--- a/netio.c
+++ b/netio.c
@@ -555,10 +555,12 @@ int dropbear_listen(const char* address,
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+#ifdef SO_BINDTODEVICE
if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) {
dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE");
TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno)))
}
+#endif
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -98,8 +98,10 @@ static void printhelp(const char * progn
" (default port is %s if none specified)\n"
"-P PidFile Create pid file PidFile\n"
" (default %s)\n"
+#ifdef SO_BINDTODEVICE
"-l <interface>\n"
" interface to bind on\n"
+#endif
#if INETD_MODE
"-i Start for inetd\n"
#endif
@@ -267,9 +269,11 @@ void svr_getopts(int argc, char ** argv)
case 'P':
next = &svr_opts.pidfile;
break;
+#ifdef SO_BINDTODEVICE
case 'l':
next = &svr_opts.interface;
break;
+#endif
#if DO_MOTD
/* motd is displayed by default, -m turns it off */
case 'm':

View File

@ -0,0 +1,74 @@
From 62a06cd95f58060a59359f8769c3f35cd680d4fd Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sun, 23 Jul 2023 21:01:48 +0800
Subject: Make banner reading failure non-fatal
---
svr-runopts.c | 45 ++++++++++++++++++++++++++++-----------------
1 file changed, 28 insertions(+), 17 deletions(-)
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -38,6 +38,7 @@ static void printhelp(const char * progn
static void addportandaddress(const char* spec);
static void loadhostkey(const char *keyfile, int fatal_duplicate);
static void addhostkey(const char *keyfile);
+static void load_banner();
static void printhelp(const char * progname) {
@@ -382,23 +383,7 @@ void svr_getopts(int argc, char ** argv)
}
if (svr_opts.bannerfile) {
- struct stat buf;
- if (stat(svr_opts.bannerfile, &buf) != 0) {
- dropbear_exit("Error opening banner file '%s'",
- svr_opts.bannerfile);
- }
-
- if (buf.st_size > MAX_BANNER_SIZE) {
- dropbear_exit("Banner file too large, max is %d bytes",
- MAX_BANNER_SIZE);
- }
-
- svr_opts.banner = buf_new(buf.st_size);
- if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) {
- dropbear_exit("Error reading banner file '%s'",
- svr_opts.bannerfile);
- }
- buf_setpos(svr_opts.banner, 0);
+ load_banner();
}
#ifdef HAVE_GETGROUPLIST
@@ -715,3 +700,29 @@ void load_all_hostkeys() {
dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
}
}
+
+static void load_banner() {
+ struct stat buf;
+ if (stat(svr_opts.bannerfile, &buf) != 0) {
+ dropbear_log(LOG_WARNING, "Error opening banner file '%s'",
+ svr_opts.bannerfile);
+ return;
+ }
+
+ if (buf.st_size > MAX_BANNER_SIZE) {
+ dropbear_log(LOG_WARNING, "Banner file too large, max is %d bytes",
+ MAX_BANNER_SIZE);
+ return;
+ }
+
+ svr_opts.banner = buf_new(buf.st_size);
+ if (buf_readfile(svr_opts.banner, svr_opts.bannerfile) != DROPBEAR_SUCCESS) {
+ dropbear_log(LOG_WARNING, "Error reading banner file '%s'",
+ svr_opts.bannerfile);
+ buf_free(svr_opts.banner);
+ svr_opts.banner = NULL;
+ return;
+ }
+ buf_setpos(svr_opts.banner, 0);
+
+}

View File

@ -0,0 +1,60 @@
From ec26975d442163b66d1646a48e022bc8c2f1607a Mon Sep 17 00:00:00 2001
From: Sergey Ponomarev <stokito@gmail.com>
Date: Sun, 27 Aug 2023 00:07:05 +0300
Subject: dropbearkey.c Ignore unsupported command line options
To generate non interactively a key with OpenSSH the simplest command is:
ssh-keygen -t ed25519 -q -N '' -f ~/.ssh/id_ed25519
The command has two options -q quiet and -N passphrase which aren't supported by the dropbearkey.
To improve interoperability add explicit ignoring of the -q and -N with empty passphrase.
Also ignore the -v even if the DEBUG_TRACE is not set.
Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
---
dropbearkey.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
--- a/dropbearkey.c
+++ b/dropbearkey.c
@@ -159,6 +159,7 @@ int main(int argc, char ** argv) {
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
char * typetext = NULL;
char * sizetext = NULL;
+ char * passphrase = NULL;
unsigned int bits = 0, genbits;
int printpub = 0;
@@ -194,11 +195,16 @@ int main(int argc, char ** argv) {
printhelp(argv[0]);
exit(EXIT_SUCCESS);
break;
-#if DEBUG_TRACE
case 'v':
+#if DEBUG_TRACE
debug_trace = DROPBEAR_VERBOSE_LEVEL;
- break;
#endif
+ break;
+ case 'q':
+ break; /* quiet is default */
+ case 'N':
+ next = &passphrase;
+ break;
default:
fprintf(stderr, "Unknown argument %s\n", argv[i]);
printhelp(argv[0]);
@@ -266,6 +272,11 @@ int main(int argc, char ** argv) {
check_signkey_bits(keytype, bits);;
}
+ if (passphrase && *passphrase != '\0') {
+ fprintf(stderr, "Only empty passphrase is supported\n");
+ exit(EXIT_FAILURE);
+ }
+
genbits = signkey_generate_get_bits(keytype, bits);
fprintf(stderr, "Generating %u bit %s key, this may take a while...\n", genbits, typetext);
if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE)

View File

@ -0,0 +1,121 @@
From 3b576d95dcf791d7b945e75f639da8f89c1685a2 Mon Sep 17 00:00:00 2001
From: czurnieden <czurnieden@gmx.de>
Date: Tue, 9 May 2023 17:17:12 +0200
Subject: Fix possible integer overflow
---
libtommath/bn_mp_2expt.c | 4 ++++
libtommath/bn_mp_grow.c | 4 ++++
libtommath/bn_mp_init_size.c | 5 +++++
libtommath/bn_mp_mul_2d.c | 4 ++++
libtommath/bn_s_mp_mul_digs.c | 4 ++++
libtommath/bn_s_mp_mul_digs_fast.c | 4 ++++
libtommath/bn_s_mp_mul_high_digs.c | 4 ++++
libtommath/bn_s_mp_mul_high_digs_fast.c | 4 ++++
8 files changed, 33 insertions(+)
--- a/libtommath/bn_mp_2expt.c
+++ b/libtommath/bn_mp_2expt.c
@@ -12,6 +12,10 @@ mp_err mp_2expt(mp_int *a, int b)
{
mp_err err;
+ if (b < 0) {
+ return MP_VAL;
+ }
+
/* zero a as per default */
mp_zero(a);
--- a/libtommath/bn_mp_grow.c
+++ b/libtommath/bn_mp_grow.c
@@ -9,6 +9,10 @@ mp_err mp_grow(mp_int *a, int size)
int i;
mp_digit *tmp;
+ if (size < 0) {
+ return MP_VAL;
+ }
+
/* if the alloc size is smaller alloc more ram */
if (a->alloc < size) {
/* reallocate the array a->dp
--- a/libtommath/bn_mp_init_size.c
+++ b/libtommath/bn_mp_init_size.c
@@ -6,6 +6,11 @@
/* init an mp_init for a given size */
mp_err mp_init_size(mp_int *a, int size)
{
+
+ if (size < 0) {
+ return MP_VAL;
+ }
+
size = MP_MAX(MP_MIN_PREC, size);
/* alloc mem */
--- a/libtommath/bn_mp_mul_2d.c
+++ b/libtommath/bn_mp_mul_2d.c
@@ -9,6 +9,10 @@ mp_err mp_mul_2d(const mp_int *a, int b,
mp_digit d;
mp_err err;
+ if (b < 0) {
+ return MP_VAL;
+ }
+
/* copy */
if (a != c) {
if ((err = mp_copy(a, c)) != MP_OKAY) {
--- a/libtommath/bn_s_mp_mul_digs.c
+++ b/libtommath/bn_s_mp_mul_digs.c
@@ -16,6 +16,10 @@ mp_err s_mp_mul_digs(const mp_int *a, co
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
/* can we use the fast multiplier? */
if ((digs < MP_WARRAY) &&
(MP_MIN(a->used, b->used) < MP_MAXFAST)) {
--- a/libtommath/bn_s_mp_mul_digs_fast.c
+++ b/libtommath/bn_s_mp_mul_digs_fast.c
@@ -26,6 +26,10 @@ mp_err s_mp_mul_digs_fast(const mp_int *
mp_digit W[MP_WARRAY];
mp_word _W;
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
/* grow the destination as required */
if (c->alloc < digs) {
if ((err = mp_grow(c, digs)) != MP_OKAY) {
--- a/libtommath/bn_s_mp_mul_high_digs.c
+++ b/libtommath/bn_s_mp_mul_high_digs.c
@@ -15,6 +15,10 @@ mp_err s_mp_mul_high_digs(const mp_int *
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
/* can we use the fast multiplier? */
if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)
&& ((a->used + b->used + 1) < MP_WARRAY)
--- a/libtommath/bn_s_mp_mul_high_digs_fast.c
+++ b/libtommath/bn_s_mp_mul_high_digs_fast.c
@@ -19,6 +19,10 @@ mp_err s_mp_mul_high_digs_fast(const mp_
mp_digit W[MP_WARRAY];
mp_word _W;
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
/* grow the destination as required */
pa = a->used + b->used;
if (c->alloc < pa) {

View File

@ -0,0 +1,35 @@
From 3cf8344769eda55e26eee53c1898b2c66544f188 Mon Sep 17 00:00:00 2001
From: Justin Chen <justin.chen@broadcom.com>
Date: Fri, 8 Sep 2023 11:35:18 -0700
Subject: src: svr-tcpfwd: Fix noremotetcp behavior
If noremotetcp is set, we should still reply with
send_msg_request_failed. This matches the behavior
of !DROPBEAR_SVR_REMOTETCPFWD.
We were seeing keepalive packets being ignored when
the "-k" option was used.
---
svr-tcpfwd.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/svr-tcpfwd.c
+++ b/svr-tcpfwd.c
@@ -79,14 +79,14 @@ void recv_msg_global_request_remotetcp()
TRACE(("enter recv_msg_global_request_remotetcp"))
+ reqname = buf_getstring(ses.payload, &namelen);
+ wantreply = buf_getbool(ses.payload);
+
if (svr_opts.noremotetcp || !svr_pubkey_allows_tcpfwd()) {
TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"))
goto out;
}
- reqname = buf_getstring(ses.payload, &namelen);
- wantreply = buf_getbool(ses.payload);
-
if (namelen > MAX_NAME_LEN) {
TRACE(("name len is wrong: %d", namelen))
goto out;

View File

@ -0,0 +1,32 @@
From e28ba1b9975eab48799aa3ed77d3cd91627d7b27 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sat, 9 Dec 2023 23:10:41 +0800
Subject: Don't try to shutdown() a pty
shutdown() of a pty doesn't work (ENOTSOCK), so we should close
it instead.
This will ensure that PTY controlling terminals are closed when a
session exits, including when multiple sessions run over a single SSH
connection. In the normal case of a single session, the PTY controlling
terminal would be closed when the Dropbear server process exits anyway.
This possibly fixes #264 on github
It is possible that there could be subtle changes to PTY flushing
behaviour, though nothing caught by tests at present.
---
svr-chansession.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -910,7 +910,7 @@ static int ptycommand(struct Channel *ch
channel->readfd = chansess->master;
/* don't need to set stderr here */
ses.maxfd = MAX(ses.maxfd, chansess->master);
- channel->bidir_fd = 1;
+ channel->bidir_fd = 0;
setnonblocking(chansess->master);

View File

@ -0,0 +1,33 @@
From 806586b585806cbe32013bcd3af3847278972060 Mon Sep 17 00:00:00 2001
From: Sergey Ponomarev <stokito@gmail.com>
Date: Sun, 10 Dec 2023 10:31:56 +0200
Subject: dropbearkey: add alias to ssh-keygen
The dropbearkey is partially compatible with ssh-keygen and can be used as an alias.
Closes: #263
---
dbmulti.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/dbmulti.c
+++ b/dbmulti.c
@@ -41,7 +41,8 @@ static int runprog(const char *multipath
}
#endif
#ifdef DBMULTI_dropbearkey
- if (strcmp(progname, "dropbearkey") == 0) {
+ if (strcmp(progname, "dropbearkey") == 0
+ || strcmp(progname, "ssh-keygen") == 0) {
return dropbearkey_main(argc, argv);
}
#endif
@@ -88,7 +89,7 @@ int main(int argc, char ** argv) {
"'dbclient' or 'ssh' - the Dropbear client\n"
#endif
#ifdef DBMULTI_dropbearkey
- "'dropbearkey' - the key generator\n"
+ "'dropbearkey' or 'ssh-keygen' - the key generator\n"
#endif
#ifdef DBMULTI_dropbearconvert
"'dropbearconvert' - the key converter\n"

View File

@ -0,0 +1,34 @@
From 383cc8c97a9420aad9cf93d88e77ec636b183a9d Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 11 Dec 2023 23:18:09 +0800
Subject: Allow inetd with non-syslog
An inetd-alike should be able to distinguish stdout and stderr, so
it's a valid configuration.
Fixes #218 on github
---
svr-runopts.c | 12 ------------
1 file changed, 12 deletions(-)
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -443,18 +443,6 @@ void svr_getopts(int argc, char ** argv)
}
}
-#if INETD_MODE
- if (svr_opts.inetdmode && (
- opts.usingsyslog == 0
-#if DEBUG_TRACE
- || debug_trace
-#endif
- )) {
- /* log output goes to stderr which would get sent over the inetd network socket */
- dropbear_exit("Dropbear inetd mode is incompatible with debug -v or non-syslog");
- }
-#endif
-
if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
dropbear_exit("-t and -s are incompatible");
}

View File

@ -0,0 +1,33 @@
From 9ac650401ffc2fb05c9328d26e76a5e7ae39152a Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 11 Dec 2023 23:31:22 +0800
Subject: Fix test for multiuser kernels
getuid() succeeds even on non-multiuser kernels. Instead
getgroups() is a valid test.
Fixes #214 on github
---
common-session.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
--- a/common-session.c
+++ b/common-session.c
@@ -71,10 +71,13 @@ void common_session_init(int sock_in, in
#if !DROPBEAR_SVR_MULTIUSER
/* A sanity check to prevent an accidental configuration option
leaving multiuser systems exposed */
- errno = 0;
- getuid();
- if (errno != ENOSYS) {
- dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
+ {
+ int ret;
+ errno = 0;
+ ret = getgroups(0, NULL);
+ if (!(ret == -1 && errno == ENOSYS)) {
+ dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
+ }
}
#endif

View File

@ -0,0 +1,216 @@
From 6e43be5c7b99dbee49dc72b6f989f29fdd7e9356 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 20 Nov 2023 14:02:47 +0800
Subject: Implement Strict KEX mode
As specified by OpenSSH with kex-strict-c-v00@openssh.com and
kex-strict-s-v00@openssh.com.
---
cli-session.c | 11 +++++++++++
common-algo.c | 6 ++++++
common-kex.c | 26 +++++++++++++++++++++++++-
kex.h | 3 +++
process-packet.c | 34 +++++++++++++++++++---------------
ssh.h | 4 ++++
svr-session.c | 3 +++
7 files changed, 71 insertions(+), 16 deletions(-)
--- a/cli-session.c
+++ b/cli-session.c
@@ -46,6 +46,7 @@ static void cli_finished(void) ATTRIB_NO
static void recv_msg_service_accept(void);
static void cli_session_cleanup(void);
static void recv_msg_global_request_cli(void);
+static void cli_algos_initialise(void);
struct clientsession cli_ses; /* GLOBAL */
@@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_o
}
chaninitialise(cli_chantypes);
+ cli_algos_initialise();
/* Set up cli_ses vars */
cli_session_init(proxy_cmd_pid);
@@ -487,3 +489,12 @@ void cli_dropbear_log(int priority, cons
fflush(stderr);
}
+static void cli_algos_initialise(void) {
+ algo_type *algo;
+ for (algo = sshkex; algo->name; algo++) {
+ if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) {
+ algo->usable = 0;
+ }
+ }
+}
+
--- a/common-algo.c
+++ b/common-algo.c
@@ -308,6 +308,12 @@ algo_type sshkex[] = {
{SSH_EXT_INFO_C, 0, NULL, 1, NULL},
#endif
#endif
+#if DROPBEAR_CLIENT
+ {SSH_STRICT_KEX_C, 0, NULL, 1, NULL},
+#endif
+#if DROPBEAR_SERVER
+ {SSH_STRICT_KEX_S, 0, NULL, 1, NULL},
+#endif
{NULL, 0, NULL, 0, NULL}
};
--- a/common-kex.c
+++ b/common-kex.c
@@ -183,6 +183,10 @@ void send_msg_newkeys() {
gen_new_keys();
switch_keys();
+ if (ses.kexstate.strict_kex) {
+ ses.transseq = 0;
+ }
+
TRACE(("leave send_msg_newkeys"))
}
@@ -193,7 +197,11 @@ void recv_msg_newkeys() {
ses.kexstate.recvnewkeys = 1;
switch_keys();
-
+
+ if (ses.kexstate.strict_kex) {
+ ses.recvseq = 0;
+ }
+
TRACE(("leave recv_msg_newkeys"))
}
@@ -550,6 +558,10 @@ void recv_msg_kexinit() {
ses.kexstate.recvkexinit = 1;
+ if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) {
+ dropbear_exit("First packet wasn't kexinit");
+ }
+
TRACE(("leave recv_msg_kexinit"))
}
@@ -859,6 +871,18 @@ static void read_kex_algos() {
}
#endif
+ if (!ses.kexstate.donefirstkex) {
+ const char* strict_name;
+ if (IS_DROPBEAR_CLIENT) {
+ strict_name = SSH_STRICT_KEX_S;
+ } else {
+ strict_name = SSH_STRICT_KEX_C;
+ }
+ if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) {
+ ses.kexstate.strict_kex = 1;
+ }
+ }
+
algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL || algo->data == NULL) {
--- a/kex.h
+++ b/kex.h
@@ -83,6 +83,9 @@ struct KEXState {
unsigned our_first_follows_matches : 1;
+ /* Boolean indicating that strict kex mode is in use */
+ unsigned int strict_kex;
+
time_t lastkextime; /* time of the last kex */
unsigned int datatrans; /* data transmitted since last kex */
unsigned int datarecv; /* data received since last kex */
--- a/process-packet.c
+++ b/process-packet.c
@@ -44,6 +44,7 @@ void process_packet() {
unsigned char type;
unsigned int i;
+ unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex;
time_t now;
TRACE2(("enter process_packet"))
@@ -54,22 +55,24 @@ void process_packet() {
now = monotonic_now();
ses.last_packet_time_keepalive_recv = now;
- /* These packets we can receive at any time */
- switch(type) {
- case SSH_MSG_IGNORE:
- goto out;
- case SSH_MSG_DEBUG:
- goto out;
-
- case SSH_MSG_UNIMPLEMENTED:
- /* debugging XXX */
- TRACE(("SSH_MSG_UNIMPLEMENTED"))
- goto out;
-
- case SSH_MSG_DISCONNECT:
- /* TODO cleanup? */
- dropbear_close("Disconnect received");
+ if (type == SSH_MSG_DISCONNECT) {
+ /* Allowed at any time */
+ dropbear_close("Disconnect received");
+ }
+
+ /* These packets may be received at any time,
+ except during first kex with strict kex */
+ if (!first_strict_kex) {
+ switch(type) {
+ case SSH_MSG_IGNORE:
+ goto out;
+ case SSH_MSG_DEBUG:
+ goto out;
+ case SSH_MSG_UNIMPLEMENTED:
+ TRACE(("SSH_MSG_UNIMPLEMENTED"))
+ goto out;
+ }
}
/* Ignore these packet types so that keepalives don't interfere with
@@ -98,7 +101,8 @@ void process_packet() {
if (type >= 1 && type <= 49
&& type != SSH_MSG_SERVICE_REQUEST
&& type != SSH_MSG_SERVICE_ACCEPT
- && type != SSH_MSG_KEXINIT)
+ && type != SSH_MSG_KEXINIT
+ && !first_strict_kex)
{
TRACE(("unknown allowed packet during kexinit"))
recv_unimplemented();
--- a/ssh.h
+++ b/ssh.h
@@ -100,6 +100,10 @@
#define SSH_EXT_INFO_C "ext-info-c"
#define SSH_SERVER_SIG_ALGS "server-sig-algs"
+/* OpenSSH strict KEX feature */
+#define SSH_STRICT_KEX_S "kex-strict-s-v00@openssh.com"
+#define SSH_STRICT_KEX_C "kex-strict-c-v00@openssh.com"
+
/* service types */
#define SSH_SERVICE_USERAUTH "ssh-userauth"
#define SSH_SERVICE_USERAUTH_LEN 12
--- a/svr-session.c
+++ b/svr-session.c
@@ -370,6 +370,9 @@ static void svr_algos_initialise(void) {
algo->usable = 0;
}
#endif
+ if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) {
+ algo->usable = 0;
+ }
}
}

View File

@ -21,7 +21,7 @@ Signed-off-by: Petr Štetiar <ynezz@true.cz>
--- a/signkey.c --- a/signkey.c
+++ b/signkey.c +++ b/signkey.c
@@ -646,8 +646,12 @@ int buf_verify(buffer * buf, sign_key *k @@ -652,8 +652,12 @@ int buf_verify(buffer * buf, sign_key *k
sigtype = signature_type_from_name(type_name, type_name_len); sigtype = signature_type_from_name(type_name, type_name_len);
m_free(type_name); m_free(type_name);