netutils/dropbear: add Dropbear SSH server port for NuttX

Integrated SSH daemon authenticating against FSUTILS_PASSWD, with an
ECDSA P-256 host key and an NSH session over a PTY per connection. Built
from the upstream Dropbear tarball (pinned commit) and patched for
NuttX, using Dropbear's bundled libtomcrypt for all crypto. setsid()
(apache/nuttx#19184) and link() now come from NuttX, not local stubs.

Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
This commit is contained in:
Felipe Moura 2026-06-23 19:40:49 -03:00 committed by Alan C. Assis
parent e44c4f370f
commit fee2ddbf54
24 changed files with 2449 additions and 1 deletions

View file

@ -69,7 +69,7 @@ int passwd_append(FAR const char *username, FAR const char *password)
{
int errcode = errno;
DEBUGASSERT(errcode > 0);
return errcode;
return -errcode;
}
/* The format of the password file is:

6
netutils/dropbear/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
/dropbear
/*.zip
*.o
.built
.depend
Make.dep

View file

@ -0,0 +1,185 @@
# ##############################################################################
# apps/netutils/dropbear/CMakeLists.txt
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. The ASF licenses this
# file to you under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# ##############################################################################
if(CONFIG_NETUTILS_DROPBEAR)
set(DROPBEAR_COMMIT "${CONFIG_NETUTILS_DROPBEAR_COMMIT}")
string(REPLACE "\"" "" DROPBEAR_COMMIT "${DROPBEAR_COMMIT}")
set(DROPBEAR_ZIP "${DROPBEAR_COMMIT}.zip")
set(DROPBEAR_URL "https://github.com/mkj/dropbear/archive")
set(DROPBEAR_UNPACKNAME "dropbear")
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${DROPBEAR_UNPACKNAME}")
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${DROPBEAR_ZIP}")
message(STATUS "Downloading Dropbear: ${DROPBEAR_URL}/${DROPBEAR_ZIP}")
file(DOWNLOAD "${DROPBEAR_URL}/${DROPBEAR_ZIP}"
"${CMAKE_CURRENT_SOURCE_DIR}/${DROPBEAR_ZIP}")
endif()
message(STATUS "Unpacking Dropbear: ${DROPBEAR_ZIP}")
execute_process(
COMMAND unzip -q -o "${DROPBEAR_ZIP}"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE result)
if(result EQUAL 0)
file(RENAME "${CMAKE_CURRENT_SOURCE_DIR}/dropbear-${DROPBEAR_COMMIT}"
"${CMAKE_CURRENT_SOURCE_DIR}/${DROPBEAR_UNPACKNAME}")
execute_process(
COMMAND
patch -s -N -l -p1 -d "${DROPBEAR_UNPACKNAME}" -i
"${CMAKE_CURRENT_SOURCE_DIR}/patch/0001-guard-platform-declarations.patch"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
execute_process(
COMMAND
patch -s -N -l -p1 -d "${DROPBEAR_UNPACKNAME}" -i
"${CMAKE_CURRENT_SOURCE_DIR}/patch/0002-use-nuttx-passwd-auth.patch"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
execute_process(
COMMAND
patch -s -N -l -p1 -d "${DROPBEAR_UNPACKNAME}" -i
"${CMAKE_CURRENT_SOURCE_DIR}/patch/0003-allow-localoptions-to-override-tracking-malloc.patch"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
execute_process(
COMMAND
patch -s -N -l -p1 -d "${DROPBEAR_UNPACKNAME}" -i
"${CMAKE_CURRENT_SOURCE_DIR}/patch/0004-use-nuttx-unused-macro.patch"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
message(STATUS "Generating default_options_guard.h")
execute_process(
COMMAND
sh
"${CMAKE_CURRENT_SOURCE_DIR}/${DROPBEAR_UNPACKNAME}/src/ifndef_wrapper.sh"
INPUT_FILE
"${CMAKE_CURRENT_SOURCE_DIR}/${DROPBEAR_UNPACKNAME}/src/default_options.h"
OUTPUT_FILE
"${CMAKE_CURRENT_SOURCE_DIR}/${DROPBEAR_UNPACKNAME}/src/default_options_guard.h"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
endif()
set(PROGNAME "${CONFIG_NETUTILS_DROPBEAR_PROGNAME}")
string(REPLACE "\"" "" PROGNAME "${PROGNAME}")
set(DROPBEAR_SRCS
dropbear_nshsession.c
port/nuttx_auth.c
port/dropbear_utils.c
dropbear/src/dbutil.c
dropbear/src/buffer.c
dropbear/src/dbhelpers.c
dropbear/src/bignum.c
dropbear/src/signkey.c
dropbear/src/dbrandom.c
dropbear/src/queue.c
dropbear/src/atomicio.c
dropbear/src/compat.c
dropbear/src/fake-rfc2553.c
dropbear/src/curve25519.c
dropbear/src/chachapoly.c
dropbear/src/ltc_prng.c
dropbear/src/ecc.c
dropbear/src/ecdsa.c
dropbear/src/crypto_desc.c
dropbear/src/dbmalloc.c
dropbear/src/gensignkey.c
dropbear/src/common-session.c
dropbear/src/packet.c
dropbear/src/common-algo.c
dropbear/src/common-kex.c
dropbear/src/common-channel.c
dropbear/src/common-chansession.c
dropbear/src/termcodes.c
dropbear/src/tcp-accept.c
dropbear/src/listener.c
dropbear/src/process-packet.c
dropbear/src/common-runopts.c
dropbear/src/circbuffer.c
dropbear/src/list.c
dropbear/src/netio.c
dropbear/src/gcm.c
dropbear/src/kex-x25519.c
dropbear/src/svr-kex.c
dropbear/src/svr-auth.c
dropbear/src/svr-authpasswd.c
dropbear/src/svr-session.c
dropbear/src/svr-service.c
dropbear/src/svr-runopts.c
dropbear/src/svr-tcpfwd.c
dropbear/src/svr-forward.c
dropbear/src/svr-streamfwd.c
dropbear/src/svr-authpam.c)
file(GLOB LIBTOMMATH_SRCS CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/dropbear/libtommath/*.c")
list(APPEND DROPBEAR_SRCS ${LIBTOMMATH_SRCS})
file(GLOB_RECURSE LIBTOMCRYPT_SRCS CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/dropbear/libtomcrypt/src/*.c")
list(FILTER LIBTOMCRYPT_SRCS EXCLUDE REGEX ".*/prngs/sober128tab\\.c$")
list(APPEND DROPBEAR_SRCS ${LIBTOMCRYPT_SRCS})
nuttx_add_application(
NAME
${PROGNAME}
SRCS
${DROPBEAR_SRCS}
dropbear_main.c
STACKSIZE
${CONFIG_NETUTILS_DROPBEAR_STACKSIZE}
PRIORITY
${CONFIG_NETUTILS_DROPBEAR_PRIORITY}
DEPENDS
${DROPBEAR_UNPACKNAME})
target_include_directories(
${PROGNAME}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/port
${CMAKE_CURRENT_SOURCE_DIR}/dropbear
${CMAKE_CURRENT_SOURCE_DIR}/dropbear/src
${CMAKE_CURRENT_SOURCE_DIR}/dropbear/libtomcrypt/src/headers
${CMAKE_CURRENT_SOURCE_DIR}/dropbear/libtommath
${CMAKE_CURRENT_SOURCE_DIR}/../../nshlib)
if(CONFIG_NETUTILS_DROPBEAR_COMPRESSION)
target_include_directories(
${PROGNAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../system/zlib/zlib)
endif()
target_compile_definitions(
${PROGNAME} PRIVATE LOCALOPTIONS_H_EXISTS=1 DROPBEAR_NUTTX=1
DROPBEAR_NUTTX_PASSWD=1)
set_source_files_properties(
dropbear_nshsession.c
PROPERTIES COMPILE_DEFINITIONS
"Channel=dropbear_channel;ChanType=dropbear_chantype")
# LTC_SOURCE must be set only for libtomcrypt sources.
set_source_files_properties(${LIBTOMCRYPT_SRCS} PROPERTIES COMPILE_DEFINITIONS
LTC_SOURCE=1)
target_compile_options(${PROGNAME} PRIVATE -Wno-pointer-sign -Wno-format)
target_sources(apps PRIVATE ${DROPBEAR_SRCS})
endif()

120
netutils/dropbear/Kconfig Normal file
View file

@ -0,0 +1,120 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
menuconfig NETUTILS_DROPBEAR
tristate "Dropbear SSH server"
default n
depends on NET && NET_TCP
depends on !DISABLE_PSEUDOFS_OPERATIONS
depends on !DISABLE_PTHREAD
depends on SCHED_WAITPID
depends on NSH_LIBRARY
depends on FSUTILS_PASSWD
depends on PSEUDOTERM
depends on SERIAL
depends on ARCH_HAVE_RNG
depends on DEV_RANDOM
depends on DEV_URANDOM
depends on LIBC_NETDB
depends on LIBC_GAISTRERROR
select CRYPTO
select CRYPTO_RANDOM_POOL
---help---
Enable a minimal Dropbear SSH server port for NuttX. This initial
port is based on the ESP-IDF MCU test port and provides a single
foreground SSH server process with SSH sessions backed by NSH.
if NETUTILS_DROPBEAR
config NETUTILS_DROPBEAR_STACKSIZE
int "Dropbear main stack size"
default 65536
---help---
Stack size for the Dropbear server built-in.
This is architecture-specific, so adjust it according to your setup.
config NETUTILS_DROPBEAR_PRIORITY
int "Dropbear main priority"
default 100
config NETUTILS_DROPBEAR_SHELL_PRIORITY
int "Dropbear NSH session priority"
default 100
config NETUTILS_DROPBEAR_PROGNAME
string "Dropbear program name"
default "dropbear"
---help---
This is the name of the program that will be used when the NSH ELF
program is installed.
config NETUTILS_DROPBEAR_LISTEN_RETRIES
int "Dropbear listen retries"
default 0
---help---
Number of times to retry listen setup when no listen socket could
be opened. Zero means to retry forever.
config NETUTILS_DROPBEAR_LISTEN_RETRY_MAX
int "Dropbear maximum listen retry interval"
default 120
range 1 3600
---help---
Maximum number of seconds to wait between listen setup retries.
The retry delay starts at one second and doubles until it reaches
this value.
config NETUTILS_DROPBEAR_SHELL_STACKSIZE
int "Dropbear NSH session task stack size"
default 8192
config NETUTILS_DROPBEAR_PORT
int "Dropbear listen port"
default 2222
config NETUTILS_DROPBEAR_HOSTKEY_PATH
string "Dropbear ECDSA P-256 host key path"
default "/etc/dropbear/dropbear_ecdsa_host_key"
---help---
Path to the persistent ECDSA P-256 host key used by the Dropbear
server. The file is stored in Dropbear's native host key format.
config NETUTILS_DROPBEAR_GENERATE_HOSTKEY
bool "Generate host key if missing"
default y
---help---
Pass -R so Dropbear generates an ECDSA P-256 host key on demand and
persists it at NETUTILS_DROPBEAR_HOSTKEY_PATH when it does not exist.
Product builds can disable this and provision the host key
externally (loaded with -r).
config NETUTILS_DROPBEAR_COMPRESSION
bool "Enable SSH compression (zlib)"
default n
depends on LIB_ZLIB
---help---
Enable zlib compression for SSH sessions. Requires the zlib
library (LIB_ZLIB). When disabled, Dropbear is built with
DISABLE_ZLIB and negotiates no compression.
WARNING: each session allocates a zlib deflate state of about
256 KiB (DROPBEAR_ZLIB_WINDOW_BITS=15, DROPBEAR_ZLIB_MEM_LEVEL=8),
and the state is allocated even for the delayed zlib@openssh.com
method, right after key exchange.
config NETUTILS_DROPBEAR_SYSLOG
bool "Log via syslog"
default n
---help---
Route Dropbear log messages through syslog(). When disabled,
Dropbear is built with DISABLE_SYSLOG.
config NETUTILS_DROPBEAR_COMMIT
string "Dropbear upstream commit"
default "54ef47adf8c99b422be6a8f694f2866e62f88b9e"
---help---
Upstream Dropbear (mkj/dropbear) commit to download and build.
endif

View file

@ -0,0 +1,25 @@
############################################################################
# apps/netutils/dropbear/Make.defs
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
ifneq ($(CONFIG_NETUTILS_DROPBEAR),)
CONFIGURED_APPS += $(APPDIR)/netutils/dropbear
endif

157
netutils/dropbear/Makefile Normal file
View file

@ -0,0 +1,157 @@
############################################################################
# apps/netutils/dropbear/Makefile
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
include $(APPDIR)/Make.defs
ifneq ($(CONFIG_NETUTILS_DROPBEAR),)
DROPBEAR_COMMIT = $(patsubst "%",%,$(strip $(CONFIG_NETUTILS_DROPBEAR_COMMIT)))
DROPBEAR_ZIP = $(DROPBEAR_COMMIT).zip
DROPBEAR_UNPACKNAME = dropbear
DROPBEAR_URL = https://github.com/mkj/dropbear/archive
UNPACK ?= unzip -q -o
ifeq ($(CONFIG_HOST_MACOS),y)
PATCH ?= gpatch
else
PATCH ?= patch
endif
MODULE = $(CONFIG_NETUTILS_DROPBEAR)
PROGNAME = $(CONFIG_NETUTILS_DROPBEAR_PROGNAME)
PRIORITY = $(CONFIG_NETUTILS_DROPBEAR_PRIORITY)
STACKSIZE = $(CONFIG_NETUTILS_DROPBEAR_STACKSIZE)
CFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)netutils$(DELIM)dropbear"
CFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)port"
CFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)dropbear"
CFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)dropbear$(DELIM)src"
CFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)dropbear$(DELIM)libtomcrypt$(DELIM)src$(DELIM)headers"
CFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)dropbear$(DELIM)libtommath"
CFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)nshlib"
ifneq ($(CONFIG_NETUTILS_DROPBEAR_COMPRESSION),)
CFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)system$(DELIM)zlib$(DELIM)zlib"
endif
CFLAGS += ${DEFINE_PREFIX}LOCALOPTIONS_H_EXISTS=1
CFLAGS += ${DEFINE_PREFIX}DROPBEAR_NUTTX=1
CFLAGS += ${DEFINE_PREFIX}DROPBEAR_NUTTX_PASSWD=1
CFLAGS += -Wno-pointer-sign -Wno-format
dropbear_nshsession.c_CFLAGS += ${DEFINE_PREFIX}Channel=dropbear_channel
dropbear_nshsession.c_CFLAGS += ${DEFINE_PREFIX}ChanType=dropbear_chantype
CSRCS = dropbear_nshsession.c
CSRCS += port/nuttx_auth.c
CSRCS += port/dropbear_utils.c
CSRCS += \
dropbear/src/dbutil.c \
dropbear/src/buffer.c \
dropbear/src/dbhelpers.c \
dropbear/src/bignum.c \
dropbear/src/signkey.c \
dropbear/src/dbrandom.c \
dropbear/src/queue.c \
dropbear/src/atomicio.c \
dropbear/src/compat.c \
dropbear/src/fake-rfc2553.c \
dropbear/src/curve25519.c \
dropbear/src/chachapoly.c \
dropbear/src/ltc_prng.c \
dropbear/src/ecc.c \
dropbear/src/ecdsa.c \
dropbear/src/crypto_desc.c \
dropbear/src/dbmalloc.c \
dropbear/src/gensignkey.c \
dropbear/src/common-session.c \
dropbear/src/packet.c \
dropbear/src/common-algo.c \
dropbear/src/common-kex.c \
dropbear/src/common-channel.c \
dropbear/src/common-chansession.c \
dropbear/src/termcodes.c \
dropbear/src/tcp-accept.c \
dropbear/src/listener.c \
dropbear/src/process-packet.c \
dropbear/src/common-runopts.c \
dropbear/src/circbuffer.c \
dropbear/src/list.c \
dropbear/src/netio.c \
dropbear/src/gcm.c \
dropbear/src/kex-x25519.c \
dropbear/src/svr-kex.c \
dropbear/src/svr-auth.c \
dropbear/src/svr-authpasswd.c \
dropbear/src/svr-session.c \
dropbear/src/svr-service.c \
dropbear/src/svr-runopts.c \
dropbear/src/svr-tcpfwd.c \
dropbear/src/svr-forward.c \
dropbear/src/svr-streamfwd.c \
dropbear/src/svr-authpam.c
TOMMATH_SRCS = $(shell if [ -d "$(DROPBEAR_UNPACKNAME)/libtommath" ]; then find "$(DROPBEAR_UNPACKNAME)/libtommath" -name "*.c"; fi)
TOMCRYPT_SRCS = $(shell if [ -d "$(DROPBEAR_UNPACKNAME)/libtomcrypt/src" ]; then find "$(DROPBEAR_UNPACKNAME)/libtomcrypt/src" -name "*.c" ! -name "sober128tab.c"; fi)
CSRCS += $(TOMMATH_SRCS)
CSRCS += $(TOMCRYPT_SRCS)
# Match the ESP-IDF port behavior: LTC_SOURCE is only for libtomcrypt sources.
$(foreach src,$(TOMCRYPT_SRCS),$(eval $(src)_CFLAGS += ${DEFINE_PREFIX}LTC_SOURCE=1))
MAINSRC = dropbear_main.c
$(DROPBEAR_ZIP):
@echo "Downloading: $(DROPBEAR_ZIP)"
$(Q) curl -L -o $(DROPBEAR_ZIP) $(DROPBEAR_URL)/$(DROPBEAR_ZIP)
$(DROPBEAR_UNPACKNAME): $(DROPBEAR_ZIP)
@echo "Unpacking: $(DROPBEAR_ZIP) -> $(DROPBEAR_UNPACKNAME)"
$(Q) $(UNPACK) $(DROPBEAR_ZIP)
$(Q) rm -rf $(DROPBEAR_UNPACKNAME)
$(Q) mv dropbear-$(DROPBEAR_COMMIT) $(DROPBEAR_UNPACKNAME)
@echo "Patching $(DROPBEAR_UNPACKNAME)"
$(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0001-guard-platform-declarations.patch; true
$(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0002-use-nuttx-passwd-auth.patch; true
$(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0003-allow-localoptions-to-override-tracking-malloc.patch; true
$(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0004-use-nuttx-unused-macro.patch; true
@echo "Generating default_options_guard.h"
$(Q) sh $(DROPBEAR_UNPACKNAME)$(DELIM)src$(DELIM)ifndef_wrapper.sh \
< $(DROPBEAR_UNPACKNAME)$(DELIM)src$(DELIM)default_options.h \
> $(DROPBEAR_UNPACKNAME)$(DELIM)src$(DELIM)default_options_guard.h
$(Q) touch $(DROPBEAR_UNPACKNAME)
ifeq ($(wildcard $(DROPBEAR_UNPACKNAME)/.git),)
context:: $(DROPBEAR_UNPACKNAME)
clean::
$(call DELFILE, port$(DELIM)*.o)
distclean::
$(call DELDIR, $(DROPBEAR_UNPACKNAME))
$(call DELFILE, $(DROPBEAR_ZIP))
endif
endif
include $(APPDIR)/Application.mk

View file

@ -0,0 +1,329 @@
/****************************************************************************
* apps/netutils/dropbear/dropbear_main.c
*
* SPDX-License-Identifier: Apache-2.0
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/socket.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "includes.h"
#include "algo.h"
#include "crypto_desc.h"
#define dropbear_main dropbear_multi_entry
#include "dbutil.h"
#undef dropbear_main
#include "dbrandom.h"
#include "netio.h"
#include "runopts.h"
#include "session.h"
#include "signkey.h"
#include "gensignkey.h"
#include "ssh.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define DROPBEAR_PORT_STRING_HELPER(n) #n
#define DROPBEAR_PORT_STRING(n) DROPBEAR_PORT_STRING_HELPER(n)
/****************************************************************************
* Private Types
****************************************************************************/
typedef void (*dropbear_exit_handler_t)(int exitcode, FAR const char *format,
va_list param) ATTRIB_NORETURN;
/****************************************************************************
* Private Data
****************************************************************************/
static jmp_buf g_session_exit_jmp;
static int g_session_exitcode;
/****************************************************************************
* Private Functions
****************************************************************************/
static void dropbear_session_exit(int exitcode, FAR const char *format,
va_list param) noreturn_function;
static void dropbear_session_exit(int exitcode, FAR const char *format,
va_list param)
{
char exitmsg[150];
char fullmsg[300];
char fromaddr[60];
int signal_pipe[2];
vsnprintf(exitmsg, sizeof(exitmsg), format, param);
fromaddr[0] = '\0';
if (svr_ses.addrstring != NULL)
{
snprintf(fromaddr, sizeof(fromaddr), " from <%s>", svr_ses.addrstring);
}
if (!ses.init_done)
{
snprintf(fullmsg, sizeof(fullmsg), "Early exit%s: %s", fromaddr,
exitmsg);
}
else if (ses.authstate.authdone)
{
snprintf(fullmsg, sizeof(fullmsg), "Exit (%s)%s: %s",
ses.authstate.pw_name, fromaddr, exitmsg);
}
else if (ses.authstate.pw_name != NULL)
{
snprintf(fullmsg, sizeof(fullmsg),
"Exit before auth%s: (user '%s', %u fails): %s",
fromaddr, ses.authstate.pw_name, ses.authstate.failcount,
exitmsg);
}
else
{
snprintf(fullmsg, sizeof(fullmsg), "Exit before auth%s: %s", fromaddr,
exitmsg);
}
dropbear_log(LOG_INFO, "%s", fullmsg);
signal_pipe[0] = ses.signal_pipe[0];
signal_pipe[1] = ses.signal_pipe[1];
session_cleanup();
if (signal_pipe[0] > STDERR_FILENO)
{
m_close(signal_pipe[0]);
}
if (signal_pipe[1] > STDERR_FILENO && signal_pipe[1] != signal_pipe[0])
{
m_close(signal_pipe[1]);
}
memset(&ses, 0, sizeof(ses));
memset(&svr_ses, 0, sizeof(svr_ses));
g_session_exitcode = exitcode;
longjmp(g_session_exit_jmp, 1);
while (1)
{
}
}
static void dropbear_setup(FAR const char *port)
{
/* Load the host key with -r so it lives in the persistent (epoch 0)
* allocation rather than being created lazily inside a per-session malloc
* epoch (-R), which would free it when the first session ends and leave a
* dangling svr_opts.hostkey for the next connection.
*/
FAR char *argv[] =
{
"dropbear",
"-F",
"-p",
(FAR char *)port,
"-r",
CONFIG_NETUTILS_DROPBEAR_HOSTKEY_PATH,
NULL
};
_dropbear_exit = svr_dropbear_exit;
_dropbear_log = svr_dropbear_log;
disallow_core();
svr_getopts(6, argv);
seedrandom();
crypto_init();
#ifdef CONFIG_NETUTILS_DROPBEAR_GENERATE_HOSTKEY
/* Generate the ECDSA host key now if it is missing. signkey_generate()
* with skip_exist=1 silently succeeds when the file already exists.
*/
if (signkey_generate(DROPBEAR_SIGNKEY_ECDSA_NISTP256, 0,
CONFIG_NETUTILS_DROPBEAR_HOSTKEY_PATH, 1)
== DROPBEAR_FAILURE)
{
dropbear_exit("failed to generate host key");
}
#endif
load_all_hostkeys();
if (dropbear_auth_initialize() < 0)
{
dropbear_exit("failed to initialize password auth");
}
}
static void dropbear_run_session(int childsock)
{
dropbear_exit_handler_t saved_exit;
saved_exit = _dropbear_exit;
_dropbear_exit = dropbear_session_exit;
m_malloc_set_epoch(1);
if (setjmp(g_session_exit_jmp) == 0)
{
svr_session(childsock, -1);
}
m_malloc_free_epoch(1, 1);
m_malloc_set_epoch(0);
_dropbear_exit = saved_exit;
if (g_session_exitcode != EXIT_SUCCESS)
{
dropbear_log(LOG_WARNING, "session exited with status %d",
g_session_exitcode);
}
}
static size_t dropbear_listen_sockets(FAR int *socks, size_t sockcount,
FAR int *maxfd)
{
FAR char *errstring = NULL;
size_t sockpos = 0;
unsigned int i;
for (i = 0; i < svr_opts.portcount; i++)
{
int nsock;
unsigned int n;
nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i],
&socks[sockpos], sockcount - sockpos,
&errstring, maxfd, svr_opts.interface);
if (nsock < 0)
{
dropbear_log(LOG_WARNING, "failed listening on '%s': %s",
svr_opts.ports[i],
errstring != NULL ? errstring : "unknown error");
m_free(errstring);
errstring = NULL;
continue;
}
for (n = 0; n < (unsigned int)nsock; n++)
{
set_sock_priority(socks[sockpos + n], DROPBEAR_PRIO_LOWDELAY);
}
sockpos += (size_t)nsock;
}
return sockpos;
}
static size_t dropbear_wait_listen_sockets(FAR int *socks, size_t sockcount,
FAR int *maxfd)
{
int retries = 0;
int retry_delay = 1;
while (1)
{
size_t count;
*maxfd = -1;
count = dropbear_listen_sockets(socks, sockcount, maxfd);
if (count > 0)
{
return count;
}
#if CONFIG_NETUTILS_DROPBEAR_LISTEN_RETRIES > 0
if (retries++ >= CONFIG_NETUTILS_DROPBEAR_LISTEN_RETRIES)
{
dropbear_exit("no listening ports available");
}
#else
retries++;
#endif
dropbear_log(LOG_WARNING, "Retry %d in %d seconds...", retries,
retry_delay);
sleep(retry_delay);
retry_delay *= 2;
if (retry_delay > CONFIG_NETUTILS_DROPBEAR_LISTEN_RETRY_MAX)
{
retry_delay = CONFIG_NETUTILS_DROPBEAR_LISTEN_RETRY_MAX;
}
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
int main(int argc, FAR char *argv[])
{
FAR const char *port = DROPBEAR_PORT_STRING(CONFIG_NETUTILS_DROPBEAR_PORT);
int listensocks[MAX_LISTEN_ADDR];
int maxfd = -1;
if (argc > 1)
{
port = argv[1];
}
dropbear_setup(port);
dropbear_wait_listen_sockets(listensocks, MAX_LISTEN_ADDR, &maxfd);
printf("dropbear: listening on port %s\n", port);
while (1)
{
struct sockaddr_storage remoteaddr;
socklen_t remoteaddrlen = sizeof(remoteaddr);
FAR char *remote_host = NULL;
FAR char *remote_port = NULL;
int childsock;
childsock = accept(listensocks[0], (FAR struct sockaddr *)&remoteaddr,
&remoteaddrlen);
if (childsock < 0)
{
continue;
}
getaddrstring(&remoteaddr, &remote_host, &remote_port, 0);
dropbear_log(LOG_INFO, "connection from %s:%s",
remote_host != NULL ? remote_host : "?",
remote_port != NULL ? remote_port : "?");
m_free(remote_host);
m_free(remote_port);
seedrandom();
dropbear_run_session(childsock);
close(childsock);
}
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,633 @@
/****************************************************************************
* apps/netutils/dropbear/dropbear_nshsession.c
*
* SPDX-License-Identifier: Apache-2.0
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "includes.h"
#include "channel.h"
#include "chansession.h"
#include "dbutil.h"
#include "session.h"
#include "nsh.h"
#include "nsh_console.h"
#include <errno.h>
#include <fcntl.h>
#include <pty.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <spawn.h>
#include <stdbool.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
struct dropbear_nshsession_s
{
int pty_readfd;
int pty_writefd;
pid_t nsh_pid;
volatile bool done;
pthread_t waiter;
bool waiter_started;
bool have_winsize;
struct winsize win;
};
struct dropbear_signal_name_s
{
FAR const char *name;
int signo;
};
/****************************************************************************
* Private Data
****************************************************************************/
static const struct dropbear_signal_name_s g_dropbear_signals[] =
{
{ "ABRT", SIGABRT },
{ "ALRM", SIGALRM },
{ "FPE", SIGFPE },
{ "HUP", SIGHUP },
{ "ILL", SIGILL },
{ "INT", SIGINT },
{ "KILL", SIGKILL },
{ "PIPE", SIGPIPE },
{ "QUIT", SIGQUIT },
{ "SEGV", SIGSEGV },
{ "TERM", SIGTERM },
{ "USR1", SIGUSR1 },
{ "USR2", SIGUSR2 },
};
/****************************************************************************
* Private Functions
****************************************************************************/
static int dropbear_nsh_main(int argc, FAR char *argv[])
{
FAR struct console_stdio_s *pstate;
FAR char *nsh_argv[] =
{
"nsh",
NULL
};
int ret;
(void)argc;
(void)argv;
pstate = nsh_newconsole(true);
if (pstate == NULL)
{
dropbear_log(LOG_WARNING, "failed to create NSH console");
return -ENOMEM;
}
ret = nsh_session(pstate, NSH_LOGIN_NONE, 1, nsh_argv);
dropbear_log(LOG_INFO, "NSH session exited: %d", ret);
nsh_exit(&pstate->cn_vtbl, ret);
return ret;
}
static FAR void *dropbear_nsh_waiter(FAR void *arg)
{
FAR struct dropbear_nshsession_s *sess = arg;
unsigned char ch = 0;
int status;
int ret;
ret = waitpid(sess->nsh_pid, &status, 0);
if (ret < 0)
{
dropbear_log(LOG_WARNING, "NSH session wait failed: %s",
strerror(errno));
}
sess->nsh_pid = -1;
sess->done = true;
/* Match Dropbear's SIGCHLD wakeup path. The session loop checks channel
* close conditions when this pipe becomes readable.
*/
if (ses.signal_pipe[1] >= 0)
{
write(ses.signal_pipe[1], &ch, sizeof(ch));
}
return NULL;
}
static int dropbear_newchansess(FAR struct dropbear_channel *channel)
{
FAR struct dropbear_nshsession_s *sess;
sess = m_malloc(sizeof(*sess));
memset(sess, 0, sizeof(*sess));
sess->pty_readfd = -1;
sess->pty_writefd = -1;
sess->nsh_pid = -1;
channel->typedata = sess;
channel->prio = DROPBEAR_PRIO_LOWDELAY;
return 0;
}
static int dropbear_sesscheckclose(FAR struct dropbear_channel *channel)
{
FAR struct dropbear_nshsession_s *sess = channel->typedata;
return sess != NULL && sess->done;
}
static int dropbear_setup_spawn_attrs(FAR posix_spawnattr_t *attr,
FAR const char **errmsg)
{
struct sched_param param;
int rc;
param.sched_priority = CONFIG_NETUTILS_DROPBEAR_SHELL_PRIORITY;
*errmsg = "spawn priority setup";
rc = posix_spawnattr_setschedparam(attr, &param);
if (rc != 0)
{
return rc;
}
*errmsg = "spawn stack setup";
rc = posix_spawnattr_setstacksize(
attr, CONFIG_NETUTILS_DROPBEAR_SHELL_STACKSIZE);
if (rc != 0)
{
return rc;
}
*errmsg = "spawn flags setup";
return posix_spawnattr_setflags(attr, POSIX_SPAWN_SETSCHEDPARAM);
}
static int
dropbear_setup_spawn_stdio(FAR posix_spawn_file_actions_t *actions,
int slavefd)
{
static const int stdio_fds[] =
{
STDIN_FILENO,
STDOUT_FILENO,
STDERR_FILENO
};
int i;
int rc;
for (i = 0; i < nitems(stdio_fds); i++)
{
rc = posix_spawn_file_actions_adddup2(actions, slavefd, stdio_fds[i]);
if (rc != 0)
{
return rc;
}
}
return 0;
}
static int
dropbear_setup_spawn_close(FAR posix_spawn_file_actions_t *actions,
int fd)
{
if (fd <= STDERR_FILENO)
{
return 0;
}
return posix_spawn_file_actions_addclose(actions, fd);
}
static int dropbear_start_nsh(FAR struct dropbear_channel *channel,
FAR struct dropbear_nshsession_s *sess)
{
posix_spawn_file_actions_t actions;
posix_spawnattr_t attr;
FAR const char *errmsg;
FAR char * const argv[] =
{
"nsh",
NULL
};
int masterfd;
int slavefd;
int writefd;
int rc;
if (sess->nsh_pid >= 0)
{
dropbear_log(LOG_WARNING, "NSH session already running");
return DROPBEAR_FAILURE;
}
rc = openpty(&masterfd, &slavefd, NULL, NULL,
sess->have_winsize ? &sess->win : NULL);
if (rc < 0)
{
dropbear_log(LOG_WARNING, "openpty failed: %s", strerror(errno));
return DROPBEAR_FAILURE;
}
writefd = dup(masterfd);
if (writefd < 0)
{
dropbear_log(LOG_WARNING, "pty dup failed: %s", strerror(errno));
close(masterfd);
close(slavefd);
return DROPBEAR_FAILURE;
}
rc = posix_spawn_file_actions_init(&actions);
if (rc != 0)
{
dropbear_log(LOG_WARNING, "spawn actions init failed: %s",
strerror(rc));
close(masterfd);
close(writefd);
close(slavefd);
return DROPBEAR_FAILURE;
}
rc = posix_spawnattr_init(&attr);
if (rc != 0)
{
dropbear_log(LOG_WARNING, "spawn attr init failed: %s", strerror(rc));
goto err_with_actions;
}
rc = dropbear_setup_spawn_attrs(&attr, &errmsg);
if (rc != 0)
{
dropbear_log(LOG_WARNING, "%s failed: %s", errmsg, strerror(rc));
goto err_with_attr;
}
rc = dropbear_setup_spawn_stdio(&actions, slavefd);
if (rc != 0)
{
dropbear_log(LOG_WARNING, "spawn stdio setup failed: %s",
strerror(rc));
goto err_with_attr;
}
rc = dropbear_setup_spawn_close(&actions, masterfd);
if (rc != 0)
{
dropbear_log(LOG_WARNING, "spawn master close setup failed: %s",
strerror(rc));
goto err_with_attr;
}
rc = dropbear_setup_spawn_close(&actions, writefd);
if (rc != 0)
{
dropbear_log(LOG_WARNING, "spawn write close setup failed: %s",
strerror(rc));
goto err_with_attr;
}
rc = dropbear_setup_spawn_close(&actions, slavefd);
if (rc != 0)
{
dropbear_log(LOG_WARNING, "spawn slave close setup failed: %s",
strerror(rc));
goto err_with_attr;
}
sess->nsh_pid = task_spawn("dropbear nsh", dropbear_nsh_main, &actions,
&attr, argv, NULL);
if (sess->nsh_pid < 0)
{
dropbear_log(LOG_WARNING, "failed to create NSH task: %s",
strerror(-sess->nsh_pid));
goto err_with_attr;
}
close(slavefd);
slavefd = -1;
rc = pthread_create(&sess->waiter, NULL, dropbear_nsh_waiter, sess);
if (rc != 0)
{
dropbear_log(LOG_WARNING, "failed to create NSH waiter: %s",
strerror(rc));
close(masterfd);
close(writefd);
masterfd = -1;
writefd = -1;
kill(sess->nsh_pid, SIGTERM);
waitpid(sess->nsh_pid, NULL, 0);
sess->nsh_pid = -1;
goto err_with_attr;
}
sess->waiter_started = true;
sess->pty_readfd = masterfd;
sess->pty_writefd = writefd;
channel->readfd = masterfd;
channel->writefd = writefd;
channel->bidir_fd = 0;
setnonblocking(channel->readfd);
setnonblocking(channel->writefd);
ses.maxfd = MAX(ses.maxfd, channel->readfd);
ses.maxfd = MAX(ses.maxfd, channel->writefd);
posix_spawnattr_destroy(&attr);
posix_spawn_file_actions_destroy(&actions);
dropbear_log(LOG_INFO, "NSH PTY session started");
return DROPBEAR_SUCCESS;
err_with_attr:
posix_spawnattr_destroy(&attr);
err_with_actions:
posix_spawn_file_actions_destroy(&actions);
if (masterfd >= 0)
{
close(masterfd);
}
if (writefd >= 0)
{
close(writefd);
}
if (slavefd >= 0)
{
close(slavefd);
}
sess->nsh_pid = -1;
return DROPBEAR_FAILURE;
}
static void dropbear_parse_winsize(FAR struct dropbear_nshsession_s *sess)
{
unsigned int cols = buf_getint(ses.payload);
unsigned int rows = buf_getint(ses.payload);
unsigned int width = buf_getint(ses.payload);
unsigned int height = buf_getint(ses.payload);
sess->win.ws_col = cols;
sess->win.ws_row = rows;
sess->win.ws_xpixel = width;
sess->win.ws_ypixel = height;
sess->have_winsize = true;
if (sess->pty_readfd >= 0)
{
ioctl(sess->pty_readfd, TIOCSWINSZ, (unsigned long)&sess->win);
}
}
static int dropbear_handle_pty_req(FAR struct dropbear_nshsession_s *sess)
{
unsigned int len;
FAR char *term;
FAR char *modes;
term = buf_getstring(ses.payload, &len);
dropbear_parse_winsize(sess);
modes = buf_getstring(ses.payload, &len);
m_free(term);
m_free(modes);
return DROPBEAR_SUCCESS;
}
static int dropbear_signal_from_name(FAR const char *name)
{
int i;
for (i = 0; i < nitems(g_dropbear_signals); i++)
{
if (strcmp(name, g_dropbear_signals[i].name) == 0)
{
return g_dropbear_signals[i].signo;
}
}
return -EINVAL;
}
static int dropbear_write_terminal_signal(
FAR struct dropbear_nshsession_s *sess,
int signo)
{
#ifdef CONFIG_TTY_SIGINT
unsigned char ch;
ssize_t nwritten;
if (signo == SIGINT && sess->pty_writefd >= 0)
{
ch = CONFIG_TTY_SIGINT_CHAR;
nwritten = write(sess->pty_writefd, &ch, sizeof(ch));
if (nwritten == sizeof(ch))
{
return DROPBEAR_SUCCESS;
}
dropbear_log(LOG_WARNING, "SSH terminal INT failed: %s",
strerror(errno));
return DROPBEAR_FAILURE;
}
#endif
return DROPBEAR_FAILURE;
}
static int dropbear_handle_signal(FAR struct dropbear_nshsession_s *sess)
{
unsigned int len;
FAR char *name;
int signo;
int ret;
name = buf_getstring(ses.payload, &len);
signo = dropbear_signal_from_name(name);
if (signo < 0)
{
dropbear_log(LOG_WARNING, "unsupported SSH signal '%s'", name);
m_free(name);
return DROPBEAR_FAILURE;
}
ret = dropbear_write_terminal_signal(sess, signo);
if (ret == DROPBEAR_SUCCESS)
{
dropbear_log(LOG_INFO, "SSH signal '%s' sent to PTY", name);
m_free(name);
return DROPBEAR_SUCCESS;
}
if (sess->nsh_pid <= 0)
{
dropbear_log(LOG_WARNING, "SSH signal '%s' has no NSH session", name);
m_free(name);
return DROPBEAR_FAILURE;
}
ret = kill(sess->nsh_pid, signo);
if (ret < 0)
{
dropbear_log(LOG_WARNING, "SSH signal '%s' failed: %s",
name, strerror(errno));
m_free(name);
return DROPBEAR_FAILURE;
}
dropbear_log(LOG_INFO, "SSH signal '%s' sent to NSH session", name);
m_free(name);
return DROPBEAR_SUCCESS;
}
static void dropbear_chansessionrequest(FAR struct dropbear_channel *channel)
{
unsigned int typelen;
FAR char *type = buf_getstring(ses.payload, &typelen);
unsigned char wantreply = buf_getbool(ses.payload);
FAR struct dropbear_nshsession_s *sess = channel->typedata;
int ret = DROPBEAR_FAILURE;
TRACE(("dropbear_chansessionrequest: type='%s'", type))
if (strcmp(type, "pty-req") == 0)
{
ret = dropbear_handle_pty_req(sess);
}
else if (strcmp(type, "shell") == 0)
{
ret = dropbear_start_nsh(channel, sess);
}
else if (strcmp(type, "exec") == 0)
{
dropbear_log(LOG_WARNING, "SSH exec requests are not supported");
}
else if (strcmp(type, "window-change") == 0)
{
dropbear_parse_winsize(sess);
ret = DROPBEAR_SUCCESS;
}
else if (strcmp(type, "signal") == 0)
{
ret = dropbear_handle_signal(sess);
}
else if (strcmp(type, "break") == 0)
{
ret = DROPBEAR_SUCCESS;
}
else
{
TRACE(("dropbear_chansessionrequest: unhandled type '%s'", type))
}
if (wantreply)
{
if (ret == DROPBEAR_SUCCESS)
{
send_msg_channel_success(channel);
}
else
{
send_msg_channel_failure(channel);
}
}
m_free(type);
}
static void
dropbear_closechansess(FAR const struct dropbear_channel *channel)
{
FAR struct dropbear_nshsession_s *sess = channel->typedata;
if (sess != NULL)
{
sess->done = true;
}
}
static void
dropbear_cleanupchansess(FAR const struct dropbear_channel *channel)
{
FAR struct dropbear_nshsession_s *sess = channel->typedata;
if (sess == NULL)
{
return;
}
sess->done = true;
if (sess->nsh_pid > 0)
{
kill(sess->nsh_pid, SIGTERM);
}
if (sess->waiter_started)
{
pthread_join(sess->waiter, NULL);
sess->waiter_started = false;
}
m_free(sess);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/* Chansession lifecycle hooks invoked from svr-session.c. Upstream
* svr-chansession.c uses these to set up and reap the global childpids[] /
* SIGCHLD machinery; the NSH bridge tracks each session's child through its
* own waiter thread (dropbear_nsh_waiter), so both are no-ops here.
*/
void svr_chansessinitialise(void)
{
}
void svr_chansess_checksignal(void)
{
}
/****************************************************************************
* Public Data
****************************************************************************/
const struct dropbear_chantype svrchansess =
{
"session",
dropbear_newchansess,
dropbear_sesscheckclose,
dropbear_chansessionrequest,
dropbear_closechansess,
dropbear_cleanupchansess,
};

View file

@ -0,0 +1,26 @@
--- a/src/dbutil.c
+++ b/src/dbutil.c
@@ -66,6 +66,10 @@
#include "session.h"
#include "atomicio.h"
+#ifdef DROPBEAR_NUTTX
+int execv(const char *path, char * const argv[]);
+#endif
+
#define MAX_FMT 100
static void generic_dropbear_exit(int exitcode, const char* format,
--- a/src/signkey.h
+++ b/src/signkey.h
@@ -150,9 +150,9 @@
void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, const buffer *data_buf);
#if DROPBEAR_SIGNKEY_VERIFY
int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf);
int sk_buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf, char* app, unsigned int applen);
-char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen);
#endif
+char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen);
int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
const unsigned char* algoname, unsigned int algolen,
const buffer * line, char ** fingerprint);

View file

@ -0,0 +1,87 @@
--- a/src/svr-authpasswd.c
+++ b/src/svr-authpasswd.c
@@ -33,6 +33,77 @@
#if DROPBEAR_SVR_PASSWORD_AUTH
+#if DROPBEAR_NUTTX_PASSWD
+
+/* Process a password auth request, sending success or failure messages as
+ * appropriate */
+void svr_auth_password(int valid_user) {
+
+ char * password = NULL;
+ unsigned int passwordlen;
+ unsigned int changepw;
+ int auth_ok = 0;
+
+ /* check if client wants to change password */
+ changepw = buf_getbool(ses.payload);
+ if (changepw) {
+ /* not implemented by this server */
+ send_msg_userauth_failure(0, 1);
+ return;
+ }
+
+ password = buf_getstring(ses.payload, &passwordlen);
+ if (valid_user && passwordlen <= DROPBEAR_MAX_PASSWORD_LEN &&
+ strlen(password) == passwordlen) {
+ auth_ok = dropbear_verify_password(ses.authstate.pw_name, password);
+ }
+ 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 (passwordlen > DROPBEAR_MAX_PASSWORD_LEN) {
+ dropbear_log(LOG_WARNING,
+ "Too-long password attempt for '%s' from %s",
+ ses.authstate.pw_name,
+ svr_ses.addrstring);
+ send_msg_userauth_failure(0, 1);
+ return;
+ }
+
+ if (auth_ok == DROPBEAR_SUCCESS) {
+ if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PASSWORD)) {
+ /* successful password authentication, but extra auth required */
+ dropbear_log(LOG_NOTICE,
+ "Password auth succeeded for '%s' from %s, extra auth required",
+ ses.authstate.pw_name,
+ svr_ses.addrstring);
+ ses.authstate.authtypes &= ~AUTH_TYPE_PASSWORD; /* password auth ok, delete the method flag */
+ send_msg_userauth_failure(1, 0); /* Send partial success */
+ } else {
+ /* successful authentication */
+ dropbear_log(LOG_NOTICE,
+ "Password auth succeeded for '%s' from %s",
+ ses.authstate.pw_name,
+ svr_ses.addrstring);
+ send_msg_userauth_success();
+ }
+ } else {
+ dropbear_log(LOG_WARNING,
+ "Bad password attempt for '%s' from %s",
+ ses.authstate.pw_name,
+ svr_ses.addrstring);
+ send_msg_userauth_failure(0, 1);
+ }
+}
+
+#else
+
/* not constant time when strings are differing lengths.
string content isn't leaked, and crypt hashes are predictable length. */
static int constant_time_strcmp(const char* a, const char* b) {
@@ -131,4 +202,6 @@
}
}
+#endif /* DROPBEAR_NUTTX_PASSWD */
+
#endif

View file

@ -0,0 +1,24 @@
--- a/src/sysoptions.h
+++ b/src/sysoptions.h
@@ -183,7 +183,9 @@ defined(__has_feature)
#define LTC_ECC521
#endif
-#define DROPBEAR_LTC_PRNG (DROPBEAR_ECC)
+#ifndef DROPBEAR_LTC_PRNG
+#define DROPBEAR_LTC_PRNG (DROPBEAR_ECC)
+#endif
/* RSA can be vulnerable to timing attacks which use the time required for
* signing to guess the private key. Blinding avoids this attack, though makes
@@ -436,7 +438,9 @@ defined(__has_feature)
#define DROPBEAR_CLIENT_TCP_FAST_OPEN 0
#endif
-#define DROPBEAR_TRACKING_MALLOC (DROPBEAR_FUZZ)
+#ifndef DROPBEAR_TRACKING_MALLOC
+#define DROPBEAR_TRACKING_MALLOC (DROPBEAR_FUZZ)
+#endif
/* Used to work around Memory Sanitizer false positives */
#if defined(__has_feature)

View file

@ -0,0 +1,202 @@
--- a/src/compat.c
+++ b/src/compat.c
@@ -89,6 +89,6 @@
#ifndef HAVE_GETUSERSHELL
static char **curshell, **shells, *strings;
-static char **initshells();
+static char **initshells(void);
#endif
#ifndef HAVE_STRLCPY
@@ -234,7 +234,7 @@
curshell = initshells();
}
-static char **initshells() {
+static char **initshells(void) {
static const char *okshells[] = { COMPAT_USER_SHELLS, NULL };
register char **sp, *cp;
register FILE *fp;
--- a/src/common-algo.c
+++ b/src/common-algo.c
@@ -39,16 +39,25 @@
/* This file (algo.c) organises the ciphers which can be used, and is used to
* decide which ciphers/hashes/compression/signing to use during key exchange*/
-static int void_cipher(const unsigned char* in, unsigned char* out,
- unsigned long len, void* UNUSED(cipher_state)) {
+static int void_cipher(const unsigned char* in, unsigned char* out,
+ unsigned long len, void* cipher_state) {
+ UNUSED(cipher_state);
+
if (in != out) {
memmove(out, in, len);
}
return CRYPT_OK;
}
-static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
- const unsigned char* UNUSED(key),
- int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
+static int void_start(int cipher, const unsigned char* IV,
+ const unsigned char* key,
+ int keylen, int num_rounds, void* cipher_state) {
+ UNUSED(cipher);
+ UNUSED(IV);
+ UNUSED(key);
+ UNUSED(keylen);
+ UNUSED(num_rounds);
+ UNUSED(cipher_state);
+
return CRYPT_OK;
}
--- a/src/common-channel.c
+++ b/src/common-channel.c
@@ -410,7 +410,9 @@
#ifndef HAVE_WRITEV
static int writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
- const unsigned char *UNUSED(moredata), unsigned int *morelen) {
+ const unsigned char *moredata, unsigned int *morelen) {
+ UNUSED(moredata);
+
unsigned char *circ_p1, *circ_p2;
unsigned int circ_len1, circ_len2;
--- a/src/dbutil.c
+++ b/src/dbutil.c
@@ -138,7 +138,9 @@
}
-static void generic_dropbear_log(int UNUSED(priority), const char* format,
+static void generic_dropbear_log(int priority, const char* format,
va_list param) {
+ UNUSED(priority);
+
char printbuf[1024];
--- a/src/netio.c
+++ b/src/netio.c
@@ -47,7 +47,10 @@
}
}
-static void cancel_callback(int result, int sock, void* UNUSED(data), const char* UNUSED(errstring)) {
+static void cancel_callback(int result, int sock, void* data, const char* errstring) {
+ UNUSED(data);
+ UNUSED(errstring);
+
if (result == DROPBEAR_SUCCESS)
{
m_close(sock);
--- a/src/ltc_prng.c
+++ b/src/ltc_prng.c
@@ -32,8 +32,10 @@
@param prng [out] The PRNG state to initialize
@return CRYPT_OK if successful
*/
-int dropbear_prng_start(prng_state* UNUSED(prng))
+int dropbear_prng_start(prng_state* prng)
{
+ UNUSED(prng);
+
return CRYPT_OK;
}
@@ -44,8 +46,12 @@
@param prng PRNG state to update
@return CRYPT_OK if successful
*/
-int dropbear_prng_add_entropy(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
+int dropbear_prng_add_entropy(const unsigned char* in, unsigned long inlen, prng_state* prng)
{
+ UNUSED(in);
+ UNUSED(inlen);
+ UNUSED(prng);
+
return CRYPT_OK;
}
@@ -54,8 +60,10 @@
@param prng The PRNG to make active
@return CRYPT_OK if successful
*/
-int dropbear_prng_ready(prng_state* UNUSED(prng))
+int dropbear_prng_ready(prng_state* prng)
{
+ UNUSED(prng);
+
return CRYPT_OK;
}
@@ -66,8 +74,10 @@
@param prng The active PRNG to read from
@return Number of octets read
*/
-unsigned long dropbear_prng_read(unsigned char* out, unsigned long outlen, prng_state* UNUSED(prng))
+unsigned long dropbear_prng_read(unsigned char* out, unsigned long outlen, prng_state* prng)
{
+ UNUSED(prng);
+
LTC_ARGCHK(out != NULL);
genrandom(out, outlen);
return outlen;
@@ -78,8 +88,10 @@
@param prng The PRNG to terminate
@return CRYPT_OK if successful
*/
-int dropbear_prng_done(prng_state* UNUSED(prng))
+int dropbear_prng_done(prng_state* prng)
{
+ UNUSED(prng);
+
return CRYPT_OK;
}
@@ -90,8 +102,11 @@
@param prng The PRNG to export
@return CRYPT_OK if successful
*/
-int dropbear_prng_export(unsigned char* UNUSED(out), unsigned long* outlen, prng_state* UNUSED(prng))
+int dropbear_prng_export(unsigned char* out, unsigned long* outlen, prng_state* prng)
{
+ UNUSED(out);
+ UNUSED(prng);
+
LTC_ARGCHK(outlen != NULL);
*outlen = 0;
@@ -105,8 +120,12 @@
@param prng The PRNG to import
@return CRYPT_OK if successful
*/
-int dropbear_prng_import(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
+int dropbear_prng_import(const unsigned char* in, unsigned long inlen, prng_state* prng)
{
+ UNUSED(in);
+ UNUSED(inlen);
+ UNUSED(prng);
+
return CRYPT_OK;
}
--- a/src/chachapoly.c
+++ b/src/chachapoly.c
@@ -43,9 +43,13 @@
const struct dropbear_cipher dropbear_chachapoly =
{&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE};
-static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
+static int dropbear_chachapoly_start(int cipher, const unsigned char* IV,
const unsigned char *key, int keylen,
- int UNUSED(num_rounds), dropbear_chachapoly_state *state) {
+ int num_rounds, dropbear_chachapoly_state *state) {
+ UNUSED(cipher);
+ UNUSED(IV);
+ UNUSED(num_rounds);
+
int err;
TRACE2(("enter dropbear_chachapoly_start"))

View file

@ -0,0 +1,20 @@
/****************************************************************************
* apps/netutils/dropbear/port/config.h
*
* SPDX-License-Identifier: Apache-2.0
****************************************************************************/
#ifndef __APPS_NETUTILS_DROPBEAR_PORT_CONFIG_H
#define __APPS_NETUTILS_DROPBEAR_PORT_CONFIG_H
/* Dropbear looks for a file named config.h. Keep this wrapper name stable;
* NuttX-specific autoconf replacements live in nuttx_config.h.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include "nuttx_config.h"
#endif /* __APPS_NETUTILS_DROPBEAR_PORT_CONFIG_H */

View file

@ -0,0 +1,149 @@
/****************************************************************************
* apps/netutils/dropbear/port/dropbear_utils.c
*
* SPDX-License-Identifier: Apache-2.0
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "dropbear_utils.h"
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
/****************************************************************************
* Private Functions
****************************************************************************/
static int dropbear_hex_value(char ch)
{
if (ch >= '0' && ch <= '9')
{
return ch - '0';
}
if (ch >= 'a' && ch <= 'f')
{
return ch - 'a' + 10;
}
if (ch >= 'A' && ch <= 'F')
{
return ch - 'A' + 10;
}
return -1;
}
static int dropbear_try_mkdir(FAR const char *path)
{
if (mkdir(path, 0700) < 0 && errno != EEXIST)
{
return -errno;
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
void dropbear_hex_encode(FAR char *dst, FAR const uint8_t *src,
size_t srclen)
{
static const char hex[] = "0123456789abcdef";
size_t i;
for (i = 0; i < srclen; i++)
{
dst[i * 2] = hex[src[i] >> 4];
dst[i * 2 + 1] = hex[src[i] & 0x0f];
}
dst[srclen * 2] = '\0';
}
int dropbear_hex_decode(FAR const char *src, size_t srclen,
FAR uint8_t *dst, size_t dstlen)
{
size_t i;
if (srclen != dstlen * 2)
{
return -EINVAL;
}
for (i = 0; i < dstlen; i++)
{
int hi = dropbear_hex_value(src[i * 2]);
int lo = dropbear_hex_value(src[i * 2 + 1]);
if (hi < 0 || lo < 0)
{
return -EINVAL;
}
dst[i] = (uint8_t)((hi << 4) | lo);
}
return OK;
}
int dropbear_try_prepare_parent(FAR const char *path)
{
char dir[PATH_MAX];
struct stat st;
FAR char *slash;
FAR char *p;
int ret;
if (strlcpy(dir, path, sizeof(dir)) >= sizeof(dir))
{
return -ENAMETOOLONG;
}
slash = strrchr(dir, '/');
if (slash == NULL || slash == dir)
{
return OK;
}
*slash = '\0';
if (stat(dir, &st) == 0)
{
return OK;
}
for (p = dir + 1; *p != '\0'; p++)
{
if (*p == '/')
{
*p = '\0';
ret = dropbear_try_mkdir(dir);
if (ret < 0)
{
return ret;
}
*p = '/';
}
}
return dropbear_try_mkdir(dir);
}
#ifndef CONFIG_SCHED_USER_IDENTITY
int dropbear_getgroups(int size, gid_t list[])
{
(void)size;
(void)list;
set_errno(ENOSYS);
return ERROR;
}
#endif

View file

@ -0,0 +1,31 @@
/****************************************************************************
* apps/netutils/dropbear/port/dropbear_utils.h
*
* SPDX-License-Identifier: Apache-2.0
****************************************************************************/
#ifndef __APPS_NETUTILS_DROPBEAR_PORT_DROPBEAR_UTILS_H
#define __APPS_NETUTILS_DROPBEAR_PORT_DROPBEAR_UTILS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "config.h"
#include <stddef.h>
#include <stdint.h>
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
void dropbear_hex_encode(FAR char *dst, FAR const uint8_t *src,
size_t srclen);
int dropbear_hex_decode(FAR const char *src, size_t srclen,
FAR uint8_t *dst, size_t dstlen);
int dropbear_try_prepare_parent(FAR const char *path);
#endif /* __APPS_NETUTILS_DROPBEAR_PORT_DROPBEAR_UTILS_H */

View file

@ -0,0 +1,81 @@
/****************************************************************************
* apps/netutils/dropbear/port/localoptions.h
*
* SPDX-License-Identifier: Apache-2.0
****************************************************************************/
#ifndef __APPS_NETUTILS_DROPBEAR_PORT_LOCALOPTIONS_H
#define __APPS_NETUTILS_DROPBEAR_PORT_LOCALOPTIONS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define DROPBEAR_TRACKING_MALLOC 1
/* Persist the native Dropbear ECDSA host key at the configured path. */
#define ECDSA_PRIV_FILENAME CONFIG_NETUTILS_DROPBEAR_HOSTKEY_PATH
#define DROPBEAR_SVR_DROP_PRIVS 0
#ifdef CONFIG_SCHED_USER_IDENTITY
# define DROPBEAR_SVR_MULTIUSER 1
#else
# define DROPBEAR_SVR_MULTIUSER 0
#endif
#define DROPBEAR_SVR_PASSWORD_AUTH 1
#define DROPBEAR_SVR_PUBKEY_AUTH 0
#define DROPBEAR_SVR_PUBKEY_OPTIONS 0
#define DROPBEAR_REEXEC 0
#define DROPBEAR_SMALL_CODE 1
#define DROPBEAR_USER_ALGO_LIST 0
#define DROPBEAR_X11FWD 0
#define DROPBEAR_SVR_AGENTFWD 0
#define DROPBEAR_SVR_LOCALTCPFWD 0
#define DROPBEAR_SVR_REMOTETCPFWD 0
#define DROPBEAR_SVR_LOCALSTREAMFWD 0
#define DROPBEAR_SVR_REMOTESTREAMFWD 0
#define DROPBEAR_DSS 0
#define DROPBEAR_RSA 0
#define DROPBEAR_ECDSA 1
#define DROPBEAR_ED25519 0
#define DROPBEAR_SK_KEYS 0
#define DROPBEAR_ECC_256 1
#define DROPBEAR_ECC_384 0
#define DROPBEAR_ECC_521 0
#define DROPBEAR_AES128 1
#define DROPBEAR_AES256 0
#define DROPBEAR_CHACHA20POLY1305 1
#define DROPBEAR_ENABLE_CBC_MODE 0
#define DROPBEAR_ENABLE_GCM_MODE 0
#define DROPBEAR_SHA1_HMAC 0
#define DROPBEAR_SHA2_256_HMAC 1
#define DROPBEAR_SHA2_512_HMAC 0
#define DROPBEAR_SHA1_96_HMAC 0
#define DROPBEAR_CURVE25519 1
#define DROPBEAR_DH_GROUP14_SHA1 0
#define DROPBEAR_DH_GROUP14_SHA256 0
#define DROPBEAR_DH_GROUP16 0
#define DROPBEAR_DH_GROUP1 0
#define DROPBEAR_ECDH 0
#define DROPBEAR_SNTRUP761 0
#define DROPBEAR_MLKEM768 0
#define DROPBEAR_DEFAULT_CLI_AUTHKEY "/etc/dropbear/authorized_keys"
#define DROPBEAR_SFTPSERVER 0
#endif /* __APPS_NETUTILS_DROPBEAR_PORT_LOCALOPTIONS_H */

View file

@ -0,0 +1,109 @@
/****************************************************************************
* apps/netutils/dropbear/port/nuttx_auth.c
*
* SPDX-License-Identifier: Apache-2.0
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "config.h"
#include <sys/types.h>
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "fsutils/passwd.h"
#include "dbutil.h"
/****************************************************************************
* Private Data
****************************************************************************/
static struct passwd g_dropbear_pw;
static char g_dropbear_name[64];
static char g_dropbear_dir[] = "/";
static char g_dropbear_shell[] = "/bin/sh";
static char g_dropbear_password_marker[] = "x";
/****************************************************************************
* Private Functions
****************************************************************************/
static FAR struct passwd *dropbear_fill_pw(FAR const char *name, uid_t uid)
{
memset(&g_dropbear_pw, 0, sizeof(g_dropbear_pw));
snprintf(g_dropbear_name, sizeof(g_dropbear_name), "%s", name);
g_dropbear_pw.pw_uid = uid;
g_dropbear_pw.pw_gid = 0;
g_dropbear_pw.pw_name = g_dropbear_name;
g_dropbear_pw.pw_passwd = g_dropbear_password_marker;
g_dropbear_pw.pw_gecos = g_dropbear_name;
g_dropbear_pw.pw_dir = g_dropbear_dir;
g_dropbear_pw.pw_shell = g_dropbear_shell;
return &g_dropbear_pw;
}
FAR struct passwd *dropbear_getpwuid(uid_t uid)
{
return dropbear_fill_pw("root", uid);
}
FAR struct passwd *dropbear_getpwnam(FAR const char *name)
{
if (name == NULL || name[0] == '\0')
{
return NULL;
}
return dropbear_fill_pw(name, 0);
}
/****************************************************************************
* Public Functions
****************************************************************************/
uid_t dropbear_getuid(void)
{
return 0;
}
uid_t dropbear_geteuid(void)
{
return 0;
}
int dropbear_auth_initialize(void)
{
dropbear_log(LOG_INFO, "using NuttX passwd auth at %s",
CONFIG_FSUTILS_PASSWD_PATH);
return OK;
}
int dropbear_verify_password(FAR const char *username,
FAR const char *password)
{
int ret;
ret = passwd_verify(username, password);
if (PASSWORD_VERIFY_MATCH(ret))
{
return DROPBEAR_SUCCESS;
}
if (PASSWORD_VERIFY_ERROR(ret) && ret != -ENOENT)
{
dropbear_log(LOG_WARNING, "passwd_verify failed for '%s': %d",
username, ret);
}
return DROPBEAR_FAILURE;
}

View file

@ -0,0 +1,142 @@
/****************************************************************************
* apps/netutils/dropbear/port/nuttx_config.h
*
* SPDX-License-Identifier: Apache-2.0
****************************************************************************/
#ifndef __APPS_NETUTILS_DROPBEAR_PORT_NUTTX_CONFIG_H
#define __APPS_NETUTILS_DROPBEAR_PORT_NUTTX_CONFIG_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define DROPBEAR_SERVER 1
#define BUNDLED_LIBTOM 1
#define DISABLE_LASTLOG 1
#define DISABLE_PAM 1
#define DISABLE_PUTUTLINE 1
#define DISABLE_PUTUTXLINE 1
#define DISABLE_UTMP 1
#define DISABLE_UTMPX 1
#define DISABLE_WTMP 1
#define DISABLE_WTMPX 1
#ifndef CONFIG_NETUTILS_DROPBEAR_SYSLOG
# define DISABLE_SYSLOG 1
#endif
#ifndef CONFIG_NETUTILS_DROPBEAR_COMPRESSION
# define DISABLE_ZLIB 1
#endif
#define DROPBEAR_FUZZ 0
#define DROPBEAR_PLUGIN 0
#define HAVE_BASENAME 1
#define HAVE_CLOCK_GETTIME 1
#define HAVE_CONST_GAI_STRERROR_PROTO 1
#define HAVE_CRYPT 1
#define HAVE_DECL_HTOLE64 1
#define HAVE_ENDIAN_H 1
#define HAVE_EXPLICIT_BZERO 1
#define HAVE_FREEADDRINFO 1
#define HAVE_GAI_STRERROR 1
#define HAVE_GETADDRINFO 1
#define HAVE_GETNAMEINFO 1
#define HAVE_GETRANDOM 1
#define HAVE_INTTYPES_H 1
#define HAVE_LIBGEN_H 1
#define HAVE_NETDB_H 1
#define HAVE_NETINET_IN_H 1
#define HAVE_NETINET_TCP_H 1
#define HAVE_PATHS_H 1
#define HAVE_PUTENV 1
#define HAVE_STATIC_ASSERT 1
#define HAVE_STDINT_H 1
#define HAVE_STDIO_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRINGS_H 1
#define HAVE_STRING_H 1
#define HAVE_STRLCAT 1
#define HAVE_STRLCPY 1
#define HAVE_STRUCT_ADDRINFO 1
#define HAVE_STRUCT_IN6_ADDR 1
#define HAVE_STRUCT_SOCKADDR_IN6 1
#define HAVE_STRUCT_SOCKADDR_STORAGE 1
#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
#define HAVE_SYS_RANDOM_H 1
#define HAVE_SYS_SELECT_H 1
#define HAVE_SYS_SOCKET_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_SYS_UIO_H 1
#define HAVE_SYS_WAIT_H 1
#define HAVE_UINT16_T 1
#define HAVE_UINT32_T 1
#define HAVE_UINT8_T 1
#define HAVE_U_INT16_T 1
#define HAVE_U_INT32_T 1
#define HAVE_U_INT8_T 1
#define HAVE_UNDERSCORE_STATIC_ASSERT 1
#define HAVE_UNISTD_H 1
/* NuttX exposes writev(), but keep this port on Dropbear's simpler write()
* path until the SSH-to-NSH channel bridge is validated with vectored
* writes.
*/
#undef HAVE_WRITEV
#define STDC_HEADERS 1
#define PACKAGE_BUGREPORT ""
#define PACKAGE_NAME ""
#define PACKAGE_STRING ""
#define PACKAGE_TARNAME ""
#define PACKAGE_URL ""
#define PACKAGE_VERSION ""
#define SELECT_TYPE_ARG1 int
#define SELECT_TYPE_ARG234 (fd_set *)
#define SELECT_TYPE_ARG5 (struct timeval *)
#ifndef PF_UNIX
# define PF_UNIX AF_UNIX
#endif
#ifndef GRND_NONBLOCK
# define GRND_NONBLOCK O_NONBLOCK
#endif
#define IPPORT_RESERVED 1024
#define getuid dropbear_getuid
#define geteuid dropbear_geteuid
#define getpwuid dropbear_getpwuid
#define getpwnam dropbear_getpwnam
uid_t getuid(void);
uid_t geteuid(void);
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
int dropbear_auth_initialize(void);
int dropbear_verify_password(const char *username, const char *password);
#ifndef CONFIG_SCHED_USER_IDENTITY
/* NuttX has no supplementary-group support, so getgroups() does not exist. */
int dropbear_getgroups(int size, gid_t list[]);
# define getgroups dropbear_getgroups
#endif
#endif /* __APPS_NETUTILS_DROPBEAR_PORT_NUTTX_CONFIG_H */

View file

@ -101,6 +101,10 @@ if(CONFIG_NSH_LIBRARY)
endif()
endif()
if(CONFIG_NSH_DROPBEAR)
list(APPEND CSRCS nsh_dropbear.c)
endif()
if(NOT CONFIG_NSH_DISABLESCRIPT)
list(APPEND CSRCS nsh_test.c)
endif()

View file

@ -1201,6 +1201,28 @@ config NSH_DISABLE_TELNETSTART
endmenu # Telnet Configuration
menu "Dropbear Configuration"
config NSH_DROPBEAR
bool "Start Dropbear SSH server"
default n
depends on NETUTILS_DROPBEAR
depends on NSH_BUILTIN_APPS
depends on !NSH_DISABLEBG
select NSH_LOGIN
---help---
If NSH_DROPBEAR is set to 'y', then NSH starts the Dropbear SSH
server automatically.
config NSH_DISABLE_DROPBEARSTART
bool "Disable to start Dropbear"
default n
depends on NSH_DROPBEAR
---help---
Determines if NSH starts Dropbear automatically.
endmenu # Dropbear Configuration
config NSH_LOGIN
bool
default n

View file

@ -86,6 +86,10 @@ CSRCS += nsh_telnetlogin.c
endif
endif
ifeq ($(CONFIG_NSH_DROPBEAR),y)
CSRCS += nsh_dropbear.c
endif
ifneq ($(CONFIG_NSH_DISABLESCRIPT),y)
CSRCS += nsh_test.c
endif

View file

@ -844,6 +844,10 @@ int nsh_login(FAR struct console_stdio_s *pstate);
int nsh_telnetlogin(FAR struct console_stdio_s *pstate);
#endif
#if defined(CONFIG_NSH_DROPBEAR) && !defined(CONFIG_NSH_DISABLE_DROPBEARSTART)
int nsh_dropbearstart(void);
#endif
/* Application interface */
int nsh_command(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char *argv[]);

76
nshlib/nsh_dropbear.c Normal file
View file

@ -0,0 +1,76 @@
/****************************************************************************
* apps/nshlib/nsh_dropbear.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include "nsh.h"
#include "nsh_console.h"
#ifdef CONFIG_NSH_DROPBEAR
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nsh_dropbearstart
*
* Description:
* nsh_dropbearstart() starts the Dropbear SSH server. This function
* returns immediately after the daemon has been started.
*
* Returned Values:
* Zero is returned if Dropbear was started. A negated errno value will be
* returned on failure.
*
****************************************************************************/
#ifndef CONFIG_NSH_DISABLE_DROPBEARSTART
int nsh_dropbearstart(void)
{
FAR struct console_stdio_s *pstate = nsh_newconsole(false);
char cmdline[] = CONFIG_NETUTILS_DROPBEAR_PROGNAME " &";
int ret;
DEBUGASSERT(pstate != NULL);
ninfo("Starting the Dropbear SSH server\n");
ret = nsh_parse(&pstate->cn_vtbl, cmdline);
if (ret < 0)
{
nerr("ERROR: Failed to start Dropbear: %d\n", ret);
}
nsh_release(&pstate->cn_vtbl);
return ret;
}
#endif
#endif /* CONFIG_NSH_DROPBEAR */

View file

@ -175,4 +175,16 @@ void nsh_initialize(void)
nsh_telnetstart(AF_UNSPEC);
#endif
#if defined(CONFIG_NSH_DROPBEAR) && \
!defined(CONFIG_NSH_DISABLE_DROPBEARSTART) && \
!defined(CONFIG_NETINIT_NETLOCAL)
/* If Dropbear is selected as an SSH front-end, then start the daemon
* UNLESS network initialization is deferred via CONFIG_NETINIT_NETLOCAL.
* In that case, Dropbear must be started manually with the dropbear
* command after the network has been initialized.
*/
nsh_dropbearstart();
#endif
}