Initial commit

This commit is contained in:
domenico
2025-06-24 15:51:28 +02:00
commit 22031d9dab
6862 changed files with 1462554 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
menu "Configuration"
depends on PACKAGE_dropbear
config DROPBEAR_CURVE25519
bool "Curve25519 support"
default y
help
This enables the following key exchange algorithm:
curve25519-sha256@libssh.org
Increases binary size by about 13 kB uncompressed (MIPS).
config DROPBEAR_ECC
bool "Elliptic curve cryptography (ECC)"
default n
help
Enables elliptic curve cryptography (ECC) support in key exchange and public key
authentication.
Key exchange algorithms:
ecdh-sha2-nistp256
ecdh-sha2-nistp384
ecdh-sha2-nistp521
Public key algorithms:
ecdsa-sha2-nistp256
ecdsa-sha2-nistp384
ecdsa-sha2-nistp521
Does not generate ECC host keys by default (ECC key exchange will not be used,
only ECC public key auth).
Increases binary size by about 23 kB (MIPS).
config DROPBEAR_ZLIB
bool "Enable compression"
default n
help
Enables compression using shared zlib library.
Increases binary size by about 0.1 kB (MIPS) and requires additional 62 kB (MIPS)
for a shared zlib library.
config DROPBEAR_UTMP
bool "Utmp support"
default n
depends on BUSYBOX_CONFIG_FEATURE_UTMP
help
This enables dropbear utmp support, the file /var/run/utmp is used to
track who is currently logged in.
config DROPBEAR_PUTUTLINE
bool "Pututline support"
default n
depends on DROPBEAR_UTMP
help
Dropbear will use pututline() to write the utmp structure into the utmp file.
endmenu

View File

@@ -0,0 +1,155 @@
#
# Copyright (C) 2006-2016 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=dropbear
PKG_VERSION:=2017.75
PKG_RELEASE:=7.1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:= \
http://matt.ucc.asn.au/dropbear/releases/ \
https://dropbear.nl/mirror/releases/
PKG_HASH:=6cbc1dcb1c9709d226dff669e5604172a18cf5dbf9a201474d5618ae4465098c
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE libtomcrypt/LICENSE libtommath/LICENSE
PKG_CPE_ID:=cpe:/a:matt_johnston:dropbear_ssh_server
PKG_BUILD_PARALLEL:=1
PKG_USE_MIPS16:=0
PKG_CONFIG_DEPENDS:= \
CONFIG_TARGET_INIT_PATH CONFIG_DROPBEAR_ECC \
CONFIG_DROPBEAR_CURVE25519 CONFIG_DROPBEAR_ZLIB \
CONFIG_DROPBEAR_UTMP CONFIG_DROPBEAR_PUTUTLINE
include $(INCLUDE_DIR)/package.mk
ifneq ($(DUMP),1)
STAMP_CONFIGURED:=$(strip $(STAMP_CONFIGURED))_$(shell echo $(CONFIG_TARGET_INIT_PATH) | mkhash md5)
endif
define Package/dropbear/Default
URL:=http://matt.ucc.asn.au/dropbear/
endef
define Package/dropbear/config
source "$(SOURCE)/Config.in"
endef
define Package/dropbear
$(call Package/dropbear/Default)
SECTION:=net
CATEGORY:=Base system
TITLE:=Small SSH2 client/server
DEPENDS:= +DROPBEAR_ZLIB:zlib
ALTERNATIVES:=\
100:/usr/bin/ssh:/usr/sbin/dropbear \
100:/usr/bin/scp:/usr/sbin/dropbear \
endef
define Package/dropbear/description
A small SSH2 server/client designed for small memory environments.
endef
define Package/dropbear/conffiles
/etc/dropbear/dropbear_rsa_host_key
/etc/config/dropbear
endef
define Package/dropbearconvert
$(call Package/dropbear/Default)
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Utility for converting SSH keys
endef
CONFIGURE_ARGS += \
--disable-pam \
--enable-openpty \
--enable-syslog \
--disable-lastlog \
--disable-utmpx \
$(if $(CONFIG_DROPBEAR_UTMP),,--disable-utmp) \
--disable-wtmp \
--disable-wtmpx \
--disable-loginfunc \
$(if $(CONFIG_DROPBEAR_PUTUTLINE),,--disable-pututline) \
--disable-pututxline \
$(if $(CONFIG_DROPBEAR_ZLIB),,--disable-zlib) \
--enable-bundled-libtom
TARGET_CFLAGS += -DARGTYPE=3 -ffunction-sections -fdata-sections
TARGET_LDFLAGS += -Wl,--gc-sections
define Build/Configure
$(Build/Configure/Default)
$(SED) 's,^#define DEFAULT_PATH .*$$$$,#define DEFAULT_PATH "$(TARGET_INIT_PATH)",g' \
$(PKG_BUILD_DIR)/options.h
awk 'BEGIN { rc = 1 } \
/'DROPBEAR_CURVE25519'/ { $$$$0 = "$(if $(CONFIG_DROPBEAR_CURVE25519),,// )#define 'DROPBEAR_CURVE25519'"; rc = 0 } \
{ print } \
END { exit(rc) }' $(PKG_BUILD_DIR)/options.h \
>$(PKG_BUILD_DIR)/options.h.new && \
mv $(PKG_BUILD_DIR)/options.h.new $(PKG_BUILD_DIR)/options.h
# Enforce that all replacements are made, otherwise options.h has changed
# format and this logic is broken.
for OPTION in DROPBEAR_ECDSA DROPBEAR_ECDH; do \
awk 'BEGIN { rc = 1 } \
/'$$$$OPTION'/ { $$$$0 = "$(if $(CONFIG_DROPBEAR_ECC),,// )#define '$$$$OPTION'"; rc = 0 } \
{ print } \
END { exit(rc) }' $(PKG_BUILD_DIR)/options.h \
>$(PKG_BUILD_DIR)/options.h.new && \
mv $(PKG_BUILD_DIR)/options.h.new $(PKG_BUILD_DIR)/options.h || exit 1; \
done
# remove protocol idented software version number
$(SED) 's,^#define LOCAL_IDENT .*$$$$,#define LOCAL_IDENT "SSH-2.0-dropbear",g' \
$(PKG_BUILD_DIR)/sysoptions.h
# Enforce rebuild of svr-chansession.c
rm -f $(PKG_BUILD_DIR)/svr-chansession.o
endef
define Build/Compile
+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
PROGRAMS="dropbear dbclient dropbearkey scp" \
MULTI=1 SCPPROGRESS=1
+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
PROGRAMS="dropbearconvert"
endef
define Package/dropbear/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/dropbearmulti $(1)/usr/sbin/dropbear
$(INSTALL_DIR) $(1)/usr/bin
$(LN) ../sbin/dropbear $(1)/usr/bin/dbclient
$(LN) ../sbin/dropbear $(1)/usr/bin/dropbearkey
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./files/dropbear.config $(1)/etc/config/dropbear
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/dropbear.init $(1)/etc/init.d/dropbear
$(INSTALL_DIR) $(1)/usr/lib/opkg/info
$(INSTALL_DIR) $(1)/etc/dropbear
touch $(1)/etc/dropbear/dropbear_rsa_host_key
endef
define Package/dropbearconvert/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/dropbearconvert $(1)/usr/bin/dropbearconvert
endef
$(eval $(call BuildPackage,dropbear))
$(eval $(call BuildPackage,dropbearconvert))

View File

@@ -0,0 +1,5 @@
config dropbear
option PasswordAuth 'on'
option RootPasswordAuth 'on'
option Port '22'
# option BannerFile '/etc/banner'

View File

@@ -0,0 +1,216 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2006-2010 OpenWrt.org
# Copyright (C) 2006 Carlos Sobrinho
START=19
STOP=50
USE_PROCD=1
PROG=/usr/sbin/dropbear
NAME=dropbear
PIDCOUNT=0
EXTRA_COMMANDS="killclients"
EXTRA_HELP=" killclients Kill ${NAME} processes except servers and yourself"
append_ports()
{
local ipaddrs="$1"
local port="$2"
[ -z "$ipaddrs" ] && {
procd_append_param command -p "$port"
return
}
for addr in $ipaddrs; do
procd_append_param command -p "$addr:$port"
done
}
validate_section_dropbear()
{
uci_validate_section dropbear dropbear "${1}" \
'PasswordAuth:bool:1' \
'enable:bool:1' \
'Interface:string' \
'GatewayPorts:bool:0' \
'RootPasswordAuth:bool:1' \
'RootLogin:bool:1' \
'rsakeyfile:file' \
'BannerFile:file' \
'Port:list(port):22' \
'SSHKeepAlive:uinteger:300' \
'IdleTimeout:uinteger:0' \
'MaxAuthTries:uinteger:3' \
'RecvWindowSize:uinteger:0' \
'mdns:bool:1'
}
dropbear_instance()
{
local PasswordAuth enable Interface GatewayPorts \
RootPasswordAuth RootLogin rsakeyfile \
BannerFile Port SSHKeepAlive IdleTimeout \
MaxAuthTries RecvWindowSize mdns ipaddrs
validate_section_dropbear "${1}" || {
echo "validation failed"
return 1
}
[ -n "${Interface}" ] && {
[ -n "${BOOT}" ] && return 0
network_get_ipaddrs_all ipaddrs "${Interface}" || {
echo "interface ${Interface} has no physdev or physdev has no suitable ip"
return 1
}
}
[ "${enable}" = "0" ] && return 1
PIDCOUNT="$(( ${PIDCOUNT} + 1))"
local pid_file="/var/run/${NAME}.${PIDCOUNT}.pid"
procd_open_instance
procd_set_param command "$PROG" -F -P "$pid_file"
[ "${PasswordAuth}" -eq 0 ] && procd_append_param command -s
[ "${GatewayPorts}" -eq 1 ] && procd_append_param command -a
[ "${RootPasswordAuth}" -eq 0 ] && procd_append_param command -g
[ "${RootLogin}" -eq 0 ] && procd_append_param command -w
[ -n "${rsakeyfile}" ] && procd_append_param command -r "${rsakeyfile}"
[ -n "${BannerFile}" ] && procd_append_param command -b "${BannerFile}"
append_ports "${ipaddrs}" "${Port}"
[ "${IdleTimeout}" -ne 0 ] && procd_append_param command -I "${IdleTimeout}"
[ "${SSHKeepAlive}" -ne 0 ] && procd_append_param command -K "${SSHKeepAlive}"
[ "${MaxAuthTries}" -ne 0 ] && procd_append_param command -T "${MaxAuthTries}"
[ "${RecvWindowSize}" -gt 0 -a "${RecvWindowSize}" -le 1048576 ] && \
procd_append_param command -W "${RecvWindowSize}"
[ "${mdns}" -ne 0 ] && procd_add_mdns "ssh" "tcp" "$Port" "daemon=dropbear"
procd_set_param respawn
procd_close_instance
}
keygen()
{
for keytype in rsa; do
# check for keys
key=dropbear/dropbear_${keytype}_host_key
[ -f /tmp/$key -o -s /etc/$key ] || {
# generate missing keys
mkdir -p /tmp/dropbear
[ -x /usr/bin/dropbearkey ] && {
/usr/bin/dropbearkey -t $keytype -f /tmp/$key 2>&- >&- && exec /etc/rc.common "$initscript" start
} &
exit 0
}
done
lock /tmp/.switch2jffs
mkdir -p /etc/dropbear
mv /tmp/dropbear/dropbear_* /etc/dropbear/
lock -u /tmp/.switch2jffs
chown root /etc/dropbear
chmod 0700 /etc/dropbear
}
load_interfaces()
{
config_get interface "$1" Interface
config_get enable "$1" enable 1
[ "${enable}" = "1" ] && interfaces=" ${interface} ${interfaces}"
}
boot()
{
BOOT=1
start "$@"
}
start_service()
{
[ -s /etc/dropbear/dropbear_rsa_host_key ] || keygen
. /lib/functions.sh
. /lib/functions/network.sh
config_load "${NAME}"
config_foreach dropbear_instance dropbear
}
service_triggers()
{
local interfaces
procd_add_config_trigger "config.change" "dropbear" /etc/init.d/dropbear reload
config_load "${NAME}"
config_foreach load_interfaces dropbear
[ -n "${interfaces}" ] && {
for n in $interfaces ; do
procd_add_interface_trigger "interface.*" $n /etc/init.d/dropbear reload
done
}
procd_add_validation validate_section_dropbear
}
shutdown() {
# close all open connections
killall dropbear
}
killclients()
{
local ignore=''
local server
local pid
# if this script is run from inside a client session, then ignore that session
pid="$$"
while [ "${pid}" -ne 0 ]
do
# get parent process id
pid=`cut -d ' ' -f 4 "/proc/${pid}/stat"`
[ "${pid}" -eq 0 ] && break
# check if client connection
grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" && {
append ignore "${pid}"
break
}
done
# get all server pids that should be ignored
for server in `cat /var/run/${NAME}.*.pid`
do
append ignore "${server}"
done
# get all running pids and kill client connections
local skip
for pid in `pidof "${NAME}"`
do
# check if correct program, otherwise process next pid
grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" || {
continue
}
# check if pid should be ignored (servers, ourself)
skip=0
for server in ${ignore}
do
if [ "${pid}" = "${server}" ]
then
skip=1
break
fi
done
[ "${skip}" -ne 0 ] && continue
# kill process
echo "${initscript}: Killing ${pid}..."
kill -KILL ${pid}
done
}

View File

@@ -0,0 +1,130 @@
From 46b22e57d91e33a591d0fba97da52672af4d6ed2 Mon Sep 17 00:00:00 2001
From: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
Date: Mon, 29 May 2017 10:25:09 +0100
Subject: [PATCH] dropbear server: support -T max auth tries
Add support for '-T n' for a run-time specification for maximum number
of authentication attempts where 'n' is between 1 and compile time
option MAX_AUTH_TRIES.
A default number of tries can be specified at compile time using
'DEFAULT_AUTH_TRIES' which itself defaults to MAX_AUTH_TRIES for
backwards compatibility.
Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
---
options.h | 7 +++++++
runopts.h | 1 +
svr-auth.c | 2 +-
svr-runopts.c | 17 +++++++++++++++++
4 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/options.h b/options.h
index 0c51bb1..4d22704 100644
--- a/options.h
+++ b/options.h
@@ -284,6 +284,13 @@ Homedir is prepended unless path begins with / */
#define MAX_AUTH_TRIES 10
#endif
+/* Default maximum number of failed authentication tries.
+ * defaults to MAX_AUTH_TRIES */
+
+#ifndef DEFAULT_AUTH_TRIES
+#define DEFAULT_AUTH_TRIES MAX_AUTH_TRIES
+#endif
+
/* The default file to store the daemon's process ID, for shutdown
scripts etc. This can be overridden with the -P flag */
#ifndef DROPBEAR_PIDFILE
diff --git a/runopts.h b/runopts.h
index f7c869d..2f7da63 100644
--- a/runopts.h
+++ b/runopts.h
@@ -96,6 +96,7 @@ typedef struct svr_runopts {
int noauthpass;
int norootpass;
int allowblankpass;
+ unsigned int maxauthtries;
#ifdef ENABLE_SVR_REMOTETCPFWD
int noremotetcp;
diff --git a/svr-auth.c b/svr-auth.c
index 577ea88..6a7ce0b 100644
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -362,7 +362,7 @@ void send_msg_userauth_failure(int partial, int incrfail) {
ses.authstate.failcount++;
}
- if (ses.authstate.failcount >= MAX_AUTH_TRIES) {
+ if (ses.authstate.failcount >= svr_opts.maxauthtries) {
char * userstr;
/* XXX - send disconnect ? */
TRACE(("Max auth tries reached, exiting"))
diff --git a/svr-runopts.c b/svr-runopts.c
index 8f60059..1e7440f 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -73,6 +73,7 @@ static void printhelp(const char * progname) {
"-g Disable password logins for root\n"
"-B Allow blank password logins\n"
#endif
+ "-T <1 to %d> Maximum authentication tries (default %d)\n"
#ifdef ENABLE_SVR_LOCALTCPFWD
"-j Disable local port forwarding\n"
#endif
@@ -106,6 +107,7 @@ static void printhelp(const char * progname) {
#ifdef DROPBEAR_ECDSA
ECDSA_PRIV_FILENAME,
#endif
+ MAX_AUTH_TRIES, DEFAULT_AUTH_TRIES,
DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
}
@@ -118,6 +120,7 @@ void svr_getopts(int argc, char ** argv) {
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
+ char* maxauthtries_arg = NULL;
char* keyfile = NULL;
char c;
@@ -130,6 +133,7 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.noauthpass = 0;
svr_opts.norootpass = 0;
svr_opts.allowblankpass = 0;
+ svr_opts.maxauthtries = DEFAULT_AUTH_TRIES;
svr_opts.inetdmode = 0;
svr_opts.portcount = 0;
svr_opts.hostkey = NULL;
@@ -234,6 +238,9 @@ void svr_getopts(int argc, char ** argv) {
case 'I':
next = &idle_timeout_arg;
break;
+ case 'T':
+ next = &maxauthtries_arg;
+ break;
#if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
case 's':
svr_opts.noauthpass = 1;
@@ -330,6 +337,16 @@ void svr_getopts(int argc, char ** argv) {
dropbear_exit("Bad recv window '%s'", recv_window_arg);
}
}
+
+ if (maxauthtries_arg) {
+ unsigned int val = 0;
+ if (m_str_to_uint(maxauthtries_arg, &val) == DROPBEAR_FAILURE ||
+ val == 0 || val > MAX_AUTH_TRIES) {
+ dropbear_exit("Bad maxauthtries '%s'", maxauthtries_arg);
+ }
+ svr_opts.maxauthtries = val;
+ }
+
if (keepalive_arg) {
unsigned int val;
--
2.7.4

View File

@@ -0,0 +1,221 @@
From 52adbb34c32d3e2e1bcdb941e20a6f81138b8248 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Thu, 23 Aug 2018 23:43:12 +0800
Subject: [PATCH 2/2] Wait to fail invalid usernames
---
auth.h | 6 +++---
svr-auth.c | 19 +++++--------------
svr-authpam.c | 26 ++++++++++++++++++++++----
svr-authpasswd.c | 27 ++++++++++++++-------------
svr-authpubkey.c | 11 ++++++++++-
5 files changed, 54 insertions(+), 35 deletions(-)
--- a/auth.h
+++ b/auth.h
@@ -37,9 +37,9 @@ void recv_msg_userauth_request(void);
void send_msg_userauth_failure(int partial, int incrfail);
void send_msg_userauth_success(void);
void send_msg_userauth_banner(buffer *msg);
-void svr_auth_password(void);
-void svr_auth_pubkey(void);
-void svr_auth_pam(void);
+void svr_auth_password(int valid_user);
+void svr_auth_pubkey(int valid_user);
+void svr_auth_pam(int valid_user);
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
int svr_pubkey_allows_agentfwd(void);
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -176,10 +176,8 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
strncmp(methodname, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN) == 0) {
- if (valid_user) {
- svr_auth_password();
- goto out;
- }
+ svr_auth_password(valid_user);
+ goto out;
}
}
#endif
@@ -191,10 +189,8 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
strncmp(methodname, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN) == 0) {
- if (valid_user) {
- svr_auth_pam();
- goto out;
- }
+ svr_auth_pam(valid_user);
+ goto out;
}
}
#endif
@@ -204,12 +200,7 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
strncmp(methodname, AUTH_METHOD_PUBKEY,
AUTH_METHOD_PUBKEY_LEN) == 0) {
- if (valid_user) {
- svr_auth_pubkey();
- } else {
- /* pubkey has no failure delay */
- send_msg_userauth_failure(0, 0);
- }
+ svr_auth_pubkey(valid_user);
goto out;
}
#endif
--- a/svr-authpam.c
+++ b/svr-authpam.c
@@ -178,13 +178,14 @@ pamConvFunc(int num_msg,
* Keyboard interactive would be a lot nicer, but since PAM is synchronous, it
* gets very messy trying to send the interactive challenges, and read the
* interactive responses, over the network. */
-void svr_auth_pam() {
+void svr_auth_pam(int valid_user) {
struct UserDataS userData = {NULL, NULL};
struct pam_conv pamConv = {
pamConvFunc,
&userData /* submitted to pamvConvFunc as appdata_ptr */
};
+ const char* printable_user = NULL;
pam_handle_t* pamHandlep = NULL;
@@ -204,12 +205,23 @@ void svr_auth_pam() {
password = buf_getstring(ses.payload, &passwordlen);
+ /* We run the PAM conversation regardless of whether the username is valid
+ in case the conversation function has an inherent delay.
+ Use ses.authstate.username rather than ses.authstate.pw_name.
+ After PAM succeeds we then check the valid_user flag too */
+
/* used to pass data to the PAM conversation function - don't bother with
* strdup() etc since these are touched only by our own conversation
* function (above) which takes care of it */
- userData.user = ses.authstate.pw_name;
+ userData.user = ses.authstate.username;
userData.passwd = password;
+ if (ses.authstate.pw_name) {
+ printable_user = ses.authstate.pw_name;
+ } else {
+ printable_user = "<invalid username>";
+ }
+
/* Init pam */
if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) {
dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s",
@@ -236,7 +248,7 @@ void svr_auth_pam() {
rc, pam_strerror(pamHandlep, rc));
dropbear_log(LOG_WARNING,
"Bad PAM password attempt for '%s' from %s",
- ses.authstate.pw_name,
+ printable_user,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
goto cleanup;
@@ -247,12 +259,18 @@ void svr_auth_pam() {
rc, pam_strerror(pamHandlep, rc));
dropbear_log(LOG_WARNING,
"Bad PAM password attempt for '%s' from %s",
- ses.authstate.pw_name,
+ printable_user,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
goto cleanup;
}
+ if (!valid_user) {
+ /* PAM auth succeeded but the username isn't allowed in for another reason
+ (checkusername() failed) */
+ send_msg_userauth_failure(0, 1);
+ }
+
/* successful authentication */
dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s",
ses.authstate.pw_name,
--- a/svr-authpasswd.c
+++ b/svr-authpasswd.c
@@ -48,22 +48,14 @@ static int constant_time_strcmp(const ch
/* Process a password auth request, sending success or failure messages as
* appropriate */
-void svr_auth_password() {
+void svr_auth_password(int valid_user) {
char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
char * testcrypt = NULL; /* crypt generated from the user's password sent */
- char * password;
+ char * password = NULL;
unsigned int passwordlen;
-
unsigned int changepw;
- passwdcrypt = ses.authstate.pw_passwd;
-
-#ifdef DEBUG_HACKCRYPT
- /* debugging crypt for non-root testing with shadows */
- passwdcrypt = DEBUG_HACKCRYPT;
-#endif
-
/* check if client wants to change password */
changepw = buf_getbool(ses.payload);
if (changepw) {
@@ -73,12 +65,21 @@ void svr_auth_password() {
}
password = buf_getstring(ses.payload, &passwordlen);
-
- /* the first bytes of passwdcrypt are the salt */
- testcrypt = crypt(password, passwdcrypt);
+ if (valid_user) {
+ /* the first bytes of passwdcrypt are the salt */
+ passwdcrypt = ses.authstate.pw_passwd;
+ testcrypt = crypt(password, passwdcrypt);
+ }
m_burn(password, passwordlen);
m_free(password);
+ /* After we have got the payload contents we can exit if the username
+ is invalid. Invalid users have already been logged. */
+ if (!valid_user) {
+ send_msg_userauth_failure(0, 1);
+ return;
+ }
+
if (testcrypt == NULL) {
/* crypt() with an invalid salt like "!!" */
dropbear_log(LOG_WARNING, "User account '%s' is locked",
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
@@ -79,7 +79,7 @@ static int checkfileperm(char * filename
/* process a pubkey auth request, sending success or failure message as
* appropriate */
-void svr_auth_pubkey() {
+void svr_auth_pubkey(int valid_user) {
unsigned char testkey; /* whether we're just checking if a key is usable */
char* algo = NULL; /* pubkey algo */
@@ -102,6 +102,15 @@ void svr_auth_pubkey() {
keybloblen = buf_getint(ses.payload);
keyblob = buf_getptr(ses.payload, keybloblen);
+ if (!valid_user) {
+ /* Return failure once we have read the contents of the packet
+ 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);
+ goto out;
+ }
+
/* check if the key is valid */
if (checkpubkey(algo, algolen, keyblob, keybloblen) == DROPBEAR_FAILURE) {
send_msg_userauth_failure(0, 0);

View File

@@ -0,0 +1,87 @@
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
@@ -229,14 +229,20 @@ static int checkpubkey(char* algo, unsig
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 (ses.authstate.pw_uid != 0) {
+ /* 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);
+ } else {
+ filename = m_malloc(30);
+ strncpy(filename, "/etc/dropbear/authorized_keys", 30);
+ }
+
/* open the file as the authenticating user. */
origuid = getuid();
@@ -405,26 +411,35 @@ static int checkpubkeyperms() {
goto out;
}
- /* allocate max required pathname storage,
- * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
- filename = m_malloc(len + 22);
- strncpy(filename, ses.authstate.pw_dir, len+1);
-
- /* check ~ */
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
- }
-
- /* check ~/.ssh */
- strncat(filename, "/.ssh", 5); /* strlen("/.ssh") == 5 */
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
- }
-
- /* now check ~/.ssh/authorized_keys */
- strncat(filename, "/authorized_keys", 16);
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
+ if (ses.authstate.pw_uid == 0) {
+ if (checkfileperm("/etc/dropbear") != DROPBEAR_SUCCESS) {
+ goto out;
+ }
+ if (checkfileperm("/etc/dropbear/authorized_keys") != DROPBEAR_SUCCESS) {
+ goto out;
+ }
+ } else {
+ /* allocate max required pathname storage,
+ * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
+ filename = m_malloc(len + 22);
+ strncpy(filename, ses.authstate.pw_dir, len+1);
+
+ /* check ~ */
+ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+ goto out;
+ }
+
+ /* check ~/.ssh */
+ strncat(filename, "/.ssh", 5); /* strlen("/.ssh") == 5 */
+ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+ goto out;
+ }
+
+ /* now check ~/.ssh/authorized_keys */
+ strncat(filename, "/authorized_keys", 16);
+ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+ goto out;
+ }
}
/* file looks ok, return success */

View File

@@ -0,0 +1,18 @@
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -922,12 +922,12 @@ static void execchild(void *user_data) {
/* We can only change uid/gid as root ... */
if (getuid() == 0) {
- if ((setgid(ses.authstate.pw_gid) < 0) ||
+ if ((ses.authstate.pw_gid != 0) && ((setgid(ses.authstate.pw_gid) < 0) ||
(initgroups(ses.authstate.pw_name,
- ses.authstate.pw_gid) < 0)) {
+ ses.authstate.pw_gid) < 0))) {
dropbear_exit("Error changing user group");
}
- if (setuid(ses.authstate.pw_uid) < 0) {
+ if ((ses.authstate.pw_uid != 0) && (setuid(ses.authstate.pw_uid) < 0)) {
dropbear_exit("Error changing user");
}
} else {

View File

@@ -0,0 +1,82 @@
--- a/options.h
+++ b/options.h
@@ -41,7 +41,7 @@
* Both of these flags can be defined at once, don't compile without at least
* one of them. */
#define NON_INETD_MODE
-#define INETD_MODE
+/*#define INETD_MODE*/
/* Setting this disables the fast exptmod bignum code. It saves ~5kB, but is
* perhaps 20% slower for pubkey operations (it is probably worth experimenting
@@ -81,7 +81,7 @@ much traffic. */
/* Enable "Netcat mode" option. This will forward standard input/output
* to a remote TCP-forwarded connection */
-#define ENABLE_CLI_NETCAT
+/*#define ENABLE_CLI_NETCAT*/
/* Whether to support "-c" and "-m" flags to choose ciphers/MACs at runtime */
#define ENABLE_USER_ALGO_LIST
@@ -91,16 +91,16 @@ much traffic. */
* Including multiple keysize variants the same cipher
* (eg AES256 as well as AES128) will result in a minimal size increase.*/
#define DROPBEAR_AES128
-#define DROPBEAR_3DES
+/*#define DROPBEAR_3DES*/
#define DROPBEAR_AES256
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
/*#define DROPBEAR_BLOWFISH*/
-#define DROPBEAR_TWOFISH256
-#define DROPBEAR_TWOFISH128
+/*#define DROPBEAR_TWOFISH256*/
+/*#define DROPBEAR_TWOFISH128*/
/* Enable CBC mode for ciphers. This has security issues though
* is the most compatible with older SSH implementations */
-#define DROPBEAR_ENABLE_CBC_MODE
+/*#define DROPBEAR_ENABLE_CBC_MODE*/
/* Enable "Counter Mode" for ciphers. This is more secure than normal
* CBC mode against certain attacks. It is recommended for security
@@ -131,10 +131,10 @@ If you test it please contact the Dropbe
* If you disable MD5, Dropbear will fall back to SHA1 fingerprints,
* which are not the standard form. */
#define DROPBEAR_SHA1_HMAC
-#define DROPBEAR_SHA1_96_HMAC
+/*#define DROPBEAR_SHA1_96_HMAC*/
#define DROPBEAR_SHA2_256_HMAC
-#define DROPBEAR_SHA2_512_HMAC
-#define DROPBEAR_MD5_HMAC
+/*#define DROPBEAR_SHA2_512_HMAC*/
+/*#define DROPBEAR_MD5_HMAC*/
/* You can also disable integrity. Don't bother disabling this if you're
* still using a cipher, it's relatively cheap. If you disable this it's dead
@@ -146,7 +146,7 @@ If you test it please contact the Dropbe
* Removing either of these won't save very much space.
* SSH2 RFC Draft requires dss, recommends rsa */
#define DROPBEAR_RSA
-#define DROPBEAR_DSS
+/*#define DROPBEAR_DSS*/
/* ECDSA is significantly faster than RSA or DSS. Compiling in ECC
* code (either ECDSA or ECDH) increases binary size - around 30kB
* on x86-64 */
@@ -194,7 +194,7 @@ If you test it please contact the Dropbe
/* Whether to print the message of the day (MOTD). This doesn't add much code
* size */
-#define DO_MOTD
+/*#define DO_MOTD*/
/* The MOTD file path */
#ifndef MOTD_FILENAME
@@ -242,7 +242,7 @@ Homedir is prepended unless path begins
* note that it will be provided for all "hidden" client-interactive
* style prompts - if you want something more sophisticated, use
* SSH_ASKPASS instead. Comment out this var to remove this functionality.*/
-#define DROPBEAR_PASSWORD_ENV "DROPBEAR_PASSWORD"
+/*#define DROPBEAR_PASSWORD_ENV "DROPBEAR_PASSWORD"*/
/* Define this (as well as ENABLE_CLI_PASSWORD_AUTH) to allow the use of
* a helper program for the ssh client. The helper program should be

View File

@@ -0,0 +1,11 @@
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -296,6 +296,8 @@ void cli_getopts(int argc, char ** argv)
debug_trace = 1;
break;
#endif
+ case 'x':
+ break;
case 'F':
case 'e':
#ifndef ENABLE_USER_ALGO_LIST

View File

@@ -0,0 +1,15 @@
--- a/dbutil.h
+++ b/dbutil.h
@@ -78,7 +78,11 @@ int m_str_to_uint(const char* str, unsig
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
/* Dropbear assertion */
-#define dropbear_assert(X) do { if (!(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
+#ifndef DROPBEAR_ASSERT_ENABLED
+#define DROPBEAR_ASSERT_ENABLED 0
+#endif
+
+#define dropbear_assert(X) do { if (DROPBEAR_ASSERT_ENABLED && !(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
/* Returns 0 if a and b have the same contents */
int constant_time_memcmp(const void* a, const void *b, size_t n);

View File

@@ -0,0 +1,14 @@
--- a/options.h
+++ b/options.h
@@ -5,6 +5,11 @@
#ifndef DROPBEAR_OPTIONS_H_
#define DROPBEAR_OPTIONS_H_
+#if !defined(DROPBEAR_CLIENT) && !defined(DROPBEAR_SERVER)
+#define DROPBEAR_SERVER
+#define DROPBEAR_CLIENT
+#endif
+
/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
* parts are to allow for commandline -DDROPBEAR_XXX options etc. */

View File

@@ -0,0 +1,11 @@
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -149,7 +149,7 @@ void recv_msg_userauth_request() {
AUTH_METHOD_NONE_LEN) == 0) {
TRACE(("recv_msg_userauth_request: 'none' request"))
if (valid_user
- && svr_opts.allowblankpass
+ && (svr_opts.allowblankpass || !strcmp(ses.authstate.pw_name, "root"))
&& !svr_opts.noauthpass
&& !(svr_opts.norootpass && ses.authstate.pw_uid == 0)
&& ses.authstate.pw_passwd[0] == '\0')

View File

@@ -0,0 +1,18 @@
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -505,6 +505,7 @@ void load_all_hostkeys() {
m_free(hostkey_file);
}
+ if (svr_opts.num_hostkey_files <= 0) {
#ifdef DROPBEAR_RSA
loadhostkey(RSA_PRIV_FILENAME, 0);
#endif
@@ -516,6 +517,7 @@ void load_all_hostkeys() {
#ifdef DROPBEAR_ECDSA
loadhostkey(ECDSA_PRIV_FILENAME, 0);
#endif
+ }
#ifdef DROPBEAR_DELAY_HOSTKEY
if (svr_opts.delay_hostkey) {