# ( cd dropbear/ ; make distclean ; rm config.log config.status ) ; ( cd dropbear-2020.81 ; rm .hg* .tra* .git* ; find * -exec touch -r {} ../dropbear/{} \; )
# diff -uN dropbear-2020.81/ dropbear/ | grep -v '^Binary files' > dropbear.patch
diff -uN dropbear-2022.82/cli-main.c dropbear/cli-main.c
--- dropbear-2022.82/cli-main.c 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/cli-main.c 2022-04-01 10:30:00.000000000 -0400
@@ -32,12 +32,17 @@
#include "crypto_desc.h"
#include "netio.h"
#include "fuzz.h"
+#include "libdropbear.h"
#if DROPBEAR_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out);
static void kill_proxy_sighandler(int signo);
#endif
+#ifdef ENABLE_LIBDROPBEAR
+struct dropbear_hooks hooks; /* GLOBAL */
+#endif
+
#if defined(DBMULTI_dbclient) || !DROPBEAR_MULTI
#if defined(DBMULTI_dbclient) && DROPBEAR_MULTI
int cli_main(int argc, char ** argv) {
diff -uN dropbear-2022.82/common-channel.c dropbear/common-channel.c
--- dropbear-2022.82/common-channel.c 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/common-channel.c 2022-04-01 10:30:00.000000000 -0400
@@ -35,6 +35,7 @@
#include "listener.h"
#include "runopts.h"
#include "netio.h"
+#include "libdropbear.h"
static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
const char *text, const char *lang);
@@ -941,6 +942,24 @@
goto failure;
}
+#ifdef ENABLE_LIBDROPBEAR
+
+ if (hooks.on_new_channel != NULL)
+ {
+ ret = hooks.on_new_channel(type);
+
+ if (ret == LIBDROPBEAR_HOOK_FAILURE)
+ {
+ errtype = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
+ remove_channel(channel);
+ goto failure;
+ }
+
+ ret = 0;
+ }
+
+#endif /* ENABLE_LIBDROPBEAR */
+
if (channel->type->inithandler) {
ret = channel->type->inithandler(channel);
if (ret == SSH_OPEN_IN_PROGRESS) {
diff -uN dropbear-2022.82/common-session.c dropbear/common-session.c
--- dropbear-2022.82/common-session.c 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/common-session.c 2022-04-01 10:30:00.000000000 -0400
@@ -35,6 +35,7 @@
#include "channel.h"
#include "runopts.h"
#include "netio.h"
+#include "libdropbear.h"
static void checktimeouts(void);
static long select_timeout(void);
@@ -627,6 +628,78 @@
if (ses.authstate.pw_passwd)
m_free(ses.authstate.pw_passwd);
+#ifdef ENABLE_LIBDROPBEAR
+ int ret_on_passwd_fill = LIBDROPBEAR_HOOK_CONTINUE;
+ int ret_on_shadow_fill = LIBDROPBEAR_HOOK_CONTINUE;
+
+ struct AuthState auth = ses.authstate;
+ auth.pw_uid = getuid();
+ auth.pw_gid = getgid();
+
+ auth.pw_dir = m_strdup("/tmp"); // TODO
+ auth.pw_shell = m_strdup(""); // TODO
+ auth.pw_name = m_strdup(username);
+ auth.pw_passwd = m_strdup("!!"); // TODO
+
+#ifdef ENABLE_SVR_PUBKEY_OPTIONS
+ auth.pubkey_options = NULL;
+#endif
+
+ if (hooks.on_username != NULL)
+ {
+ // LIBDROPBEAR_HOOK_FAILURE (bad username)
+ int ret = hooks.on_username(username);
+ if ( ret == LIBDROPBEAR_HOOK_FAILURE)
+ {
+ return;
+ }
+
+ if ( ret == LIBDROPBEAR_HOOK_COMPLETE)
+ {
+ ses.authstate = auth;
+ return;
+ }
+ }
+
+ if (hooks.on_passwd_fill != NULL)
+ {
+ ret_on_passwd_fill = hooks.on_passwd_fill(&auth, username);
+
+ if (ret_on_passwd_fill == LIBDROPBEAR_HOOK_FAILURE)
+ {
+ m_free(auth.pw_dir);
+ m_free(auth.pw_shell);
+ m_free(auth.pw_name);
+ m_free(auth.pw_passwd);
+ return;
+ }
+
+ if ( !auth.pw_dir || !auth.pw_shell
+ || !auth.pw_name || !auth.pw_passwd)
+ {
+ dropbear_exit("hooks.on_passwd_fill returned invalid data");
+ }
+
+ }
+
+ if (hooks.on_shadow_fill != NULL)
+ {
+ ret_on_shadow_fill = hooks.on_shadow_fill(&auth.pw_passwd, auth.pw_name);
+ if (!auth.pw_passwd)
+ {
+ dropbear_exit("hooks.on_passwd_fill returned invalid data");
+ }
+
+ }
+
+ if (ret_on_passwd_fill == LIBDROPBEAR_HOOK_COMPLETE || ret_on_shadow_fill == LIBDROPBEAR_HOOK_COMPLETE)
+ {
+ ses.authstate = auth;
+ return;
+ }
+
+#endif
+
pw = getpwnam(username);
if (!pw) {
return;
diff -uN dropbear-2022.82/configure dropbear/configure
--- dropbear-2022.82/configure 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/configure 2022-04-01 10:30:00.000000000 -0400
@@ -3279,7 +3279,7 @@
{ $as_echo "$as_me:${as_lineno-$LINENO}: Checking for available hardened build flags:" >&5
$as_echo "$as_me: Checking for available hardened build flags:" >&6;}
# relocation flags don't make sense for static builds
- if test "$STATIC" -ne 1; then
+ if false; then
# pie
{
OLDFLAGS="$CFLAGS"
Common subdirectories: dropbear-2022.82/debian and dropbear/debian
diff -uN dropbear-2022.82/dropbear.h dropbear/dropbear.h
--- dropbear-2022.82/dropbear.h 1969-12-31 19:00:00.000000000 -0500
+++ dropbear/dropbear.h 2022-07-06 23:07:07.574753136 -0400
@@ -0,0 +1,16 @@
+
+#ifndef _DROPBEAR_H_
+#define _DROPBEAR_H_
+
+#include "includes.h"
+#include "dbutil.h"
+#include "session.h"
+#include "buffer.h"
+#include "signkey.h"
+#include "runopts.h"
+#include "dbrandom.h"
+#include "crypto_desc.h"
+
+static void main_noinetd(int argc, char ** argv, const char* multipath);
+
+#endif
Common subdirectories: dropbear-2022.82/fuzz and dropbear/fuzz
Common subdirectories: dropbear-2022.82/.github and dropbear/.github
diff -uN dropbear-2022.82/libdropbear.h dropbear/libdropbear.h
--- dropbear-2022.82/libdropbear.h 1969-12-31 19:00:00.000000000 -0500
+++ dropbear/libdropbear.h 2022-07-06 23:07:07.574753136 -0400
@@ -0,0 +1,51 @@
+#ifndef _LIBDROPBEAR_H_
+#define _LIBDROPBEAR_H_
+
+#include "gensignkey.h"
+
+#define LIBDROPBEAR_HOOK_COMPLETE 1 /* Hook completed, don't continue */
+#define LIBDROPBEAR_HOOK_CONTINUE 0 /* Continue on as if the hook was NULL */
+#define LIBDROPBEAR_HOOK_FAILURE -1 /* There was an error with the hook */
+
+struct dropbear_chansess_accept {
+ int channel_index;
+ unsigned char * cmd;
+ pid_t pid;
+
+ int iscmd;
+ int issubsys;
+
+ int writefd;
+ int readfd;
+ int errfd;
+};
+
+struct dropbear_hooks {
+ int _will_run_as_root;
+ int (*on_log)(int priority, const char *message);
+ int (*on_start)();
+ int (*on_connect)();
+ int (*on_username)(const char *username);
+ int (*on_passwd_fill)(struct AuthState *auth, const char *username);
+ int (*on_shadow_fill)(char **crypt_password, const char *pw_name);
+ int (*on_crypt_passwd)(char **input_passwd, const char *salt, const char *pw_name);
+ int (*on_check_pubkey)(char **authkeys, const char *pw_name);
+ int (*on_new_channel)(const char *type);
+ int (*on_chansess_command)(struct dropbear_chansess_accept *chansess);
+ int (*on_close_channel)(struct dropbear_chansess_accept *chansess);
+};
+
+extern struct dropbear_hooks hooks; /* GLOBAL */
+
+void dropbear_init();
+void dropbear_init_argv(int argc, char ** argv);
+
+void dropbear_add_svr_addr(char* spec);
+void dropbear_add_svr_key(const char *keyfile);
+void dropbear_gen_key(enum signkey_type keytype, int bits, const char* filename, int skip_exist);
+
+void dropbear_run();
+
+#define ENABLE_LIBDROPBEAR
+
+#endif /* _LIBDROPBEAR_H_ */
Common subdirectories: dropbear-2022.82/libtomcrypt and dropbear/libtomcrypt
Common subdirectories: dropbear-2022.82/libtommath and dropbear/libtommath
diff -uN dropbear-2022.82/svr-authpasswd.c dropbear/svr-authpasswd.c
--- dropbear-2022.82/svr-authpasswd.c 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/svr-authpasswd.c 2022-04-01 10:30:00.000000000 -0400
@@ -30,6 +30,7 @@
#include "dbutil.h"
#include "auth.h"
#include "runopts.h"
+#include "libdropbear.h"
#if DROPBEAR_SVR_PASSWORD_AUTH
@@ -68,7 +69,30 @@
if (valid_user && passwordlen <= DROPBEAR_MAX_PASSWORD_LEN) {
/* the first bytes of passwdcrypt are the salt */
passwdcrypt = ses.authstate.pw_passwd;
- testcrypt = crypt(password, passwdcrypt);
+#ifdef ENABLE_LIBDROPBEAR
+ if (hooks.on_crypt_passwd != NULL)
+ {
+ char * tmp_passwd = m_strdup(password);
+ char** output = &tmp_passwd;
+
+ int ret = hooks.on_crypt_passwd(output, passwdcrypt, ses.authstate.pw_name);
+ if ( ret == LIBDROPBEAR_HOOK_COMPLETE)
+ {
+ testcrypt = *output;
+ }
+
+ if (testcrypt != tmp_passwd)
+ {
+ m_burn(tmp_passwd, strlen(tmp_passwd));
+ m_free(tmp_passwd);
+ }
+ }
+#endif
+
+ if (testcrypt == NULL)
+ {
+ testcrypt = crypt((char*)password, passwdcrypt);
+ }
}
m_burn(password, passwordlen);
m_free(password);
diff -uN dropbear-2022.82/svr-authpubkey.c dropbear/svr-authpubkey.c
--- dropbear-2022.82/svr-authpubkey.c 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/svr-authpubkey.c 2022-04-01 10:30:00.000000000 -0400
@@ -64,6 +64,7 @@
#include "ssh.h"
#include "packet.h"
#include "algo.h"
+#include "libdropbear.h"
#if DROPBEAR_SVR_PUBKEY_AUTH
@@ -435,6 +436,44 @@
dropbear_exit("Failed to set euid");
}
#endif
+
+#ifdef ENABLE_LIBDROPBEAR
+
+ char * authkeys;
+ if (hooks.on_check_pubkey != NULL)
+ {
+ int ret = hooks.on_check_pubkey(&authkeys, ses.authstate.pw_name);
+
+ if (ret == LIBDROPBEAR_HOOK_FAILURE)
+ {
+ TRACE(("hooks.on_check_pubkey encountered an error"))
+ goto out;
+ }
+
+ if (authkeys == NULL)
+ authkeys = "";
+ int pipefd[2];
+ pipe(pipefd);
+
+ int cur_len = 0, total_len = strlen(authkeys);
+ while (cur_len < total_len)
+ {
+ int len = write(pipefd[1], authkeys + cur_len, total_len - cur_len);
+ if (len < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ dropbear_exit("write to authkeys pipe failed");
+ }
+ cur_len += len;
+ }
+ close(pipefd[1]);
+ authfile = fdopen(pipefd[0], "r");
+ }
+ else
+ {
+#endif
+
/* check file permissions, also whether file exists */
if (checkpubkeyperms() == DROPBEAR_FAILURE) {
TRACE(("bad authorized_keys permissions, or file doesn't exist"))
@@ -465,6 +504,10 @@
}
TRACE(("checkpubkey: opened authorized_keys OK"))
+#ifdef ENABLE_LIBDROPBEAR
+ }
+#endif
+
line = buf_new(MAX_AUTHKEYS_LINE);
line_num = 0;
diff -uN dropbear-2022.82/svr-chansession.c dropbear/svr-chansession.c
--- dropbear-2022.82/svr-chansession.c 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/svr-chansession.c 2022-04-01 10:30:00.000000000 -0400
@@ -37,6 +37,7 @@
#include "agentfwd.h"
#include "runopts.h"
#include "auth.h"
+#include "libdropbear.h"
/* Handles sessions (either shells or programs) requested by the client */
@@ -76,6 +77,16 @@
must not be running (has never started, or has exited) */
static int sesscheckclose(struct Channel *channel) {
struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
+ if (chansess->pid <= 0)
+ {
+ TRACE(("sesscheckclose, chldpid is %d", chansess->pid));
+ TRACE(("sesscheckclose, recv_eof is %d", channel->recv_eof));
+ if (channel->recv_eof)
+ {
+ close(channel->readfd);
+ }
+ return channel->recv_eof == 1;
+ }
TRACE(("sesscheckclose, pid %d, exitpid %d", chansess->pid, chansess->exit.exitpid))
if (chansess->exit.exitpid != -1) {
@@ -597,6 +608,13 @@
return DROPBEAR_FAILURE;
}
+ pw = getpwnam(ses.authstate.pw_name);
+ if (!pw)
+ {
+ TRACE(("leave sessionpty: could not call getpwnam"));
+ return DROPBEAR_FAILURE;
+ }
+
/* allocate the pty */
if (chansess->master != -1) {
dropbear_exit("Multiple pty requests");
@@ -611,9 +629,6 @@
dropbear_exit("Out of memory"); /* TODO disconnect */
}
- pw = getpwnam(ses.authstate.pw_name);
- if (!pw)
- dropbear_exit("getpwnam failed after succeeding previously");
pty_setowner(pw, chansess->tty);
/* Set up the rows/col counts */
@@ -698,7 +713,117 @@
}
}
}
-
+
+#ifdef ENABLE_LIBDROPBEAR
+#define FD_CLOSED (-1)
+
+ if (hooks.on_chansess_command != NULL)
+ {
+ struct dropbear_chansess_accept csa;
+ memset(&csa, 0, sizeof(csa));
+
+ if (chansess->cmd != NULL)
+ csa.cmd = m_strdup(chansess->cmd);
+
+ csa.channel_index = channel->index;
+ csa.pid = 0;
+ csa.iscmd = iscmd;
+ csa.issubsys = issubsys;
+
+ csa.writefd = FD_CLOSED;
+ csa.readfd = FD_CLOSED;
+ csa.errfd = FD_CLOSED;
+
+ ret = hooks.on_chansess_command(&csa);
+
+ if (ret == LIBDROPBEAR_HOOK_FAILURE)
+ {
+ if (csa.cmd != NULL)
+ m_free(csa.cmd);
+ return DROPBEAR_FAILURE;
+ }
+
+ struct stat fstats;
+
+ if (chansess->cmd != NULL)
+ m_free(chansess->cmd);
+
+ if (csa.pid > 0 && svr_ses.lastexit.exitpid != csa.pid && waitpid(csa.pid, NULL, WNOHANG) < 0)
+ {
+ dropbear_log(LOG_ERR, "on_chansess_command: pid was invalid: %d", csa.pid);
+ return DROPBEAR_FAILURE;
+ }
+ if (csa.writefd != FD_CLOSED && fstat(csa.writefd, &fstats) < 0)
+ {
+ dropbear_log(LOG_ERR, "on_chansess_command: writefd was invalid: %d: %s", csa.writefd, strerror(errno));
+ return DROPBEAR_FAILURE;
+ }
+ if (csa.readfd != FD_CLOSED && fstat(csa.readfd, &fstats) < 0)
+ {
+ dropbear_log(LOG_ERR, "on_chansess_command: readfd was invalid: %d: %s", csa.readfd, strerror(errno));
+ return DROPBEAR_FAILURE;
+ }
+ if (csa.errfd != FD_CLOSED && fstat(csa.errfd, &fstats) < 0)
+ {
+ dropbear_log(LOG_ERR, "on_chansess_command: errfd was invalid: %d: %s", csa.errfd, strerror(errno));
+ return DROPBEAR_FAILURE;
+ }
+
+ /* If readfd == writefd, the polling gets confused */
+ if (csa.readfd == csa.writefd)
+ {
+ csa.readfd = dup(csa.writefd);
+ if (csa.readfd < 0)
+ {
+ dropbear_log(LOG_ERR, "on_chansess_command: could not dup fd %d: %s", csa.writefd, strerror(errno));
+ return DROPBEAR_FAILURE;
+ }
+ }
+
+ chansess->cmd = csa.cmd;
+ chansess->pid = csa.pid;
+
+ iscmd = csa.iscmd;
+ issubsys = csa.issubsys;
+
+ channel->writefd = csa.writefd;
+ channel->readfd = csa.readfd;
+ channel->errfd = csa.errfd;
+
+ channel->prio = DROPBEAR_PRIO_NORMAL;
+ update_channel_prio();
+
+ ses.maxfd = MAX(ses.maxfd, channel->writefd);
+ ses.maxfd = MAX(ses.maxfd, channel->readfd);
+ ses.maxfd = MAX(ses.maxfd, channel->errfd);
+
+ if (chansess->pid > 0)
+ addchildpid(chansess, chansess->pid);
+
+ if (svr_ses.lastexit.exitpid != -1) {
+ unsigned int i;
+ TRACE(("parent side: lastexitpid is %d", svr_ses.lastexit.exitpid))
+ /* The child probably exited and the signal handler triggered
+ * possibly before we got around to adding the childpid. So we fill
+ * out its data manually */
+ for (i = 0; i < svr_ses.childpidsize; i++) {
+ if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) {
+ TRACE(("found match for lastexitpid"))
+ svr_ses.childpids[i].chansess->exit = svr_ses.lastexit;
+ svr_ses.lastexit.exitpid = -1;
+ break;
+ }
+ }
+ }
+ if (ret == LIBDROPBEAR_HOOK_COMPLETE)
+ {
+ return DROPBEAR_SUCCESS;
+ }
+
+ ret = 0;
+ }
+
+#endif /* ENABLE_LIBDROPBEAR */
/* take global command into account */
if (svr_opts.forced_command) {
diff -uN dropbear-2022.82/svr-main.c dropbear/svr-main.c
--- dropbear-2022.82/svr-main.c 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/svr-main.c 2022-04-01 10:30:00.000000000 -0400
@@ -30,6 +30,7 @@
#include "runopts.h"
#include "dbrandom.h"
#include "crypto_desc.h"
+#include "libdropbear.h"
static size_t listensockets(int *sock, size_t sockcount, int *maxfd);
static void sigchld_handler(int dummy);
@@ -39,6 +40,10 @@
static void main_noinetd(int argc, char ** argv, const char* multipath);
static void commonsetup(void);
+#ifdef ENABLE_LIBDROPBEAR
+struct dropbear_hooks hooks; /* GLOBAL */
+#endif
+
#if defined(DBMULTI_dropbear) || !DROPBEAR_MULTI
#if defined(DBMULTI_dropbear) && DROPBEAR_MULTI
int dropbear_main(int argc, char ** argv, const char* multipath)
@@ -205,6 +210,13 @@
fprintf(pidfile, "%d\n", getpid());
fclose(pidfile);
}
+#ifdef ENABLE_LIBDROPBEAR
+
+ if (hooks.on_start != NULL && hooks.on_start() == LIBDROPBEAR_HOOK_FAILURE)
+ {
+ dropbear_exit("Failed to run on_start()");
+ }
+#endif
/* incoming connection select loop */
for(;;) {
@@ -399,6 +411,58 @@
}
#endif /* NON_INETD_MODE */
+#ifdef ENABLE_LIBDROPBEAR
+
+void dropbear_init()
+{
+ _dropbear_exit = svr_dropbear_exit;
+ _dropbear_log = svr_dropbear_log;
+
+ /* get commandline options */
+ char * argv[0];
+ svr_getopts(0, argv);
+}
+
+void dropbear_init_argv(int argc, char ** argv)
+{
+ _dropbear_exit = svr_dropbear_exit;
+ _dropbear_log = svr_dropbear_log;
+
+ /* get commandline options */
+ svr_getopts(argc, argv);
+}
+
+void dropbear_gen_key(enum signkey_type keytype, int bits, const char* filename, int skip_exist)
+{
+ if (signkey_generate(keytype, bits, filename, skip_exist) == DROPBEAR_FAILURE)
+ {
+ dropbear_exit("Failed to generate key.\n");
+ }
+}
+
+void dropbear_run()
+{
+ /* Refuse to run if the user is root unless told explictly that we will run as root*/
+ uid_t uid=getuid(), euid=geteuid();
+ int is_root = uid<=0 || uid!=euid;
+
+ if ( hooks._will_run_as_root )
+ {
+ if ( !is_root )
+ {
+ dropbear_exit("Cannot run Dropbear: expecting to be root\n");
+ }
+ }
+ else if (is_root)
+ {
+ dropbear_exit("Cannot run Dropbear as a library as root.\n");
+ };
+
+ main_noinetd(1, "", NULL);
+ /* notreached */
+}
+
+#endif /* ENABLE_LIBDROPBEAR */
/* catch + reap zombie children */
static void sigchld_handler(int UNUSED(unused)) {
diff -uN dropbear-2022.82/svr-runopts.c dropbear/svr-runopts.c
--- dropbear-2022.82/svr-runopts.c 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/svr-runopts.c 2022-04-01 10:30:00.000000000 -0400
@@ -29,6 +29,7 @@
#include "dbutil.h"
#include "algo.h"
#include "ecdsa.h"
+#include "libdropbear.h"
#include <grp.h>
@@ -580,6 +581,12 @@
loadhostkey(hostkey_file, 1);
m_free(hostkey_file);
}
+#ifdef ENABLE_LIBDROPBEAR
+ /* Don't load any host keys if we're not root */
+ uid_t uid=getuid(), euid=geteuid();
+ if (uid<=0 || uid!=euid)
+ {
+#endif
/* Only load default host keys if a host key is not specified by the user */
if (svr_opts.num_hostkey_files == 0) {
@@ -597,6 +604,11 @@
#if DROPBEAR_ED25519
loadhostkey(ED25519_PRIV_FILENAME, 0);
#endif
+
+#ifdef ENABLE_LIBDROPBEAR
+ }
+#endif
+
}
#if DROPBEAR_RSA
@@ -678,3 +690,17 @@
dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
}
}
+
+#ifdef ENABLE_LIBDROPBEAR
+
+void dropbear_add_svr_addr(char* spec)
+{
+ addportandaddress(spec);
+}
+
+void dropbear_add_svr_key(const char *keyfile)
+{
+ addhostkey(keyfile);
+}
+
+#endif
diff -uN dropbear-2022.82/svr-session.c dropbear/svr-session.c
--- dropbear-2022.82/svr-session.c 2022-04-01 10:30:00.000000000 -0400
+++ dropbear/svr-session.c 2022-04-01 10:30:00.000000000 -0400
@@ -40,6 +40,7 @@
#include "auth.h"
#include "runopts.h"
#include "crypto_desc.h"
+#include "libdropbear.h"
#include "fuzz.h"
static void svr_remoteclosed(void);
@@ -321,6 +322,13 @@
}
#endif
+#ifdef ENABLE_LIBDROPBEAR
+ if (hooks.on_log != NULL && hooks.on_log(priority, printbuf) == LIBDROPBEAR_HOOK_COMPLETE)
+ {
+ return;
+ }
+#endif
+
/* if we are using DEBUG_TRACE, we want to print to stderr even if
* syslog is used, so it is included in error reports */
#if DEBUG_TRACE
Common subdirectories: dropbear-2022.82/test and dropbear/test