summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGES53
-rw-r--r--LICENSE2
-rw-r--r--Makefile.in2
-rw-r--r--algo.h22
-rw-r--r--auth.h3
-rw-r--r--cli-auth.c4
-rw-r--r--cli-authpubkey.c1
-rw-r--r--cli-kex.c1
-rw-r--r--cli-main.c5
-rw-r--r--cli-runopts.c104
-rw-r--r--cli-session.c4
-rw-r--r--cli-tcpfwd.c38
-rw-r--r--common-algo.c124
-rw-r--r--common-channel.c10
-rw-r--r--common-kex.c126
-rw-r--r--common-session.c44
-rw-r--r--configure.in3
-rw-r--r--dbclient.147
-rw-r--r--debian/changelog6
-rw-r--r--debian/dropbear.postinst2
-rw-r--r--debug.h2
-rw-r--r--dropbear.862
-rw-r--r--dropbearkey.811
-rw-r--r--kex.h5
-rw-r--r--libtomcrypt/src/headers/tomcrypt_custom.h12
-rw-r--r--loginrec.c2
-rw-r--r--options.h53
-rw-r--r--packet.c327
-rw-r--r--packet.h2
-rw-r--r--process-packet.c1
-rw-r--r--runopts.h1
-rw-r--r--scp.c15
-rw-r--r--session.h53
-rw-r--r--svr-auth.c2
-rw-r--r--svr-authpubkeyoptions.c2
-rw-r--r--svr-chansession.c3
-rw-r--r--svr-main.c2
-rw-r--r--svr-runopts.c20
-rw-r--r--sysoptions.h16
-rw-r--r--tcpfwd.h4
40 files changed, 789 insertions, 407 deletions
diff --git a/CHANGES b/CHANGES
index eb6855c..7e7d73f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,56 @@
+0.52 - Wed 12 November 2008
+
+- Add "netcat-alike" option (-B) to dbclient, allowing Dropbear to tunnel
+ standard input/output to a TCP port-forwarded remote host.
+
+- Add "proxy command" support to dbclient, to allow using a spawned process for
+ IO rather than a direct TCP connection. eg
+ dbclient remotehost
+ is equivalent to
+ dbclient -J 'nc remotehost 22' remotehost
+ (the hostname is still provided purely for looking up saved host keys)
+
+- Combine netcat-alike and proxy support to allow "multihop" connections, with
+ comma-separated host syntax. Allows running
+
+ dbclient user1@host1,user2@host2,user3@host3
+
+ to end up at host3 via the other two, using SSH TCP forwarding. It's a bit
+ like onion-routing. All connections are established from the local machine.
+ The comma-separated syntax can also be used for scp/rsync, eg
+
+ rsync -a -e dbclient m@gateway,m2@host,martello:/home/matt/ ~/backup/
+
+ to bounce through a few hosts.
+
+- Add -I "idle timeout" option (contributed by Farrell Aultman)
+
+- Allow restrictions on authorized_keys logins such as restricting commands
+ to be run etc. This is a subset of those allowed by OpenSSH, doesn't
+ yet allow restricting source host.
+
+- Use vfork() for scp on uClinux
+
+- Default to PATH=/usr/bin:/bin for shells.
+
+- Report errors if -R forwarding fails
+
+- Add counter mode cipher support, which avoids some security problems with the
+ standard CBC mode.
+
+- Support zlib@openssh.com delayed compression for client/server. It can be
+ required for the Dropbear server with the '-Z' option. This is useful for
+ security as it avoids exposing the server to attacks on zlib by
+ unauthenticated remote users, though requires client side support.
+
+- options.h has been split into options.h (user-changable) and sysoptions.h
+ (less commonly changed)
+
+- Support "dbclient -s sftp" to specify a subsystem
+
+- Fix a bug in replies to channel requests that could be triggered by recent
+ versions of PuTTY
+
0.51 - Thu 27 March 2008
- Make a copy of password fields rather erroneously relying on getwpnam()
diff --git a/LICENSE b/LICENSE
index ec93fa1..ba11d4f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
same license:
-Copyright (c) 2002-2006 Matt Johnston
+Copyright (c) 2002-2008 Matt Johnston
Portions copyright (c) 2004 Mihnea Stoenescu
All rights reserved.
diff --git a/Makefile.in b/Makefile.in
index 3e6c855..4c8441f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -25,7 +25,7 @@ COMMONOBJS=dbutil.o buffer.o \
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
- svr-tcpfwd.o svr-authpam.o
+ svr-tcpfwd.o svr-authpam.o @CRYPTLIB@
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
diff --git a/algo.h b/algo.h
index 5ed01cc..c83cfff 100644
--- a/algo.h
+++ b/algo.h
@@ -29,13 +29,18 @@
#include "includes.h"
#include "buffer.h"
+#define DROPBEAR_MODE_UNUSED 0
+#define DROPBEAR_MODE_CBC 1
+#define DROPBEAR_MODE_CTR 2
+
struct Algo_Type {
unsigned char *name; /* identifying name */
char val; /* a value for this cipher, or -1 for invalid */
- void *data; /* algorithm specific data */
- unsigned usable : 1; /* whether we can use this algorithm */
-
+ const void *data; /* algorithm specific data */
+ char usable; /* whether we can use this algorithm */
+ const void *mode; /* the mode, currently only used for ciphers,
+ points to a 'struct dropbear_cipher_mode' */
};
typedef struct Algo_Type algo_type;
@@ -48,6 +53,7 @@ extern algo_type sshhashes[];
extern algo_type sshcompress[];
extern const struct dropbear_cipher dropbear_nocipher;
+extern const struct dropbear_cipher_mode dropbear_mode_none;
extern const struct dropbear_hash dropbear_nohash;
struct dropbear_cipher {
@@ -56,6 +62,16 @@ struct dropbear_cipher {
unsigned char blocksize;
};
+struct dropbear_cipher_mode {
+ int (*start)(int cipher, const unsigned char *IV,
+ const unsigned char *key,
+ int keylen, int num_rounds, void *cipher_state);
+ int (*encrypt)(const unsigned char *pt, unsigned char *ct,
+ unsigned long len, void *cipher_state);
+ int (*decrypt)(const unsigned char *ct, unsigned char *pt,
+ unsigned long len, void *cipher_state);
+};
+
struct dropbear_hash {
const struct ltc_hash_descriptor *hashdesc;
unsigned long keysize;
diff --git a/auth.h b/auth.h
index d6fe120..55efeef 100644
--- a/auth.h
+++ b/auth.h
@@ -135,7 +135,8 @@ struct SignKeyList {
int type; /* The type of key */
struct SignKeyList *next;
int source;
- /* filename? or the buffer? for encrypted keys, so we can later get
+ char *filename;
+ /* the buffer? for encrypted keys, so we can later get
* the private key portion */
};
diff --git a/cli-auth.c b/cli-auth.c
index 1024538..8b6a440 100644
--- a/cli-auth.c
+++ b/cli-auth.c
@@ -91,7 +91,7 @@ void recv_msg_userauth_banner() {
}
}
- printf("%s\n", banner);
+ fprintf(stderr, "%s\n", banner);
out:
m_free(banner);
@@ -229,6 +229,8 @@ void recv_msg_userauth_failure() {
void recv_msg_userauth_success() {
TRACE(("received msg_userauth_success"))
+ /* Note: in delayed-zlib mode, setting authdone here
+ * will enable compression in the transport layer */
ses.authstate.authdone = 1;
cli_ses.state = USERAUTH_SUCCESS_RCVD;
cli_ses.lastauthtype = AUTH_TYPE_NONE;
diff --git a/cli-authpubkey.c b/cli-authpubkey.c
index 3b89eae..20277a1 100644
--- a/cli-authpubkey.c
+++ b/cli-authpubkey.c
@@ -53,6 +53,7 @@ void cli_pubkeyfail() {
}
sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */
+ m_free(cli_ses.lastprivkey->filename);
m_free(cli_ses.lastprivkey);
TRACE(("leave cli_pubkeyfail"))
diff --git a/cli-kex.c b/cli-kex.c
index 37de6e3..c4048ec 100644
--- a/cli-kex.c
+++ b/cli-kex.c
@@ -327,4 +327,5 @@ out:
if (line != NULL) {
buf_free(line);
}
+ m_free(fingerprint);
}
diff --git a/cli-main.c b/cli-main.c
index 4ba43c0..e7ddaa8 100644
--- a/cli-main.c
+++ b/cli-main.c
@@ -32,7 +32,9 @@
static void cli_dropbear_exit(int exitcode, const char* format, va_list param);
static void cli_dropbear_log(int priority, const char* format, va_list param);
+#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out);
+#endif
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
@@ -63,6 +65,7 @@ int main(int argc, char ** argv) {
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
cli_proxy_cmd(&sock_in, &sock_out);
+ m_free(cli_opts.proxycmd);
} else
#endif
{
@@ -132,6 +135,7 @@ static void exec_proxy_cmd(void *user_data_cmd) {
dropbear_exit("Failed to run '%s'\n", cmd);
}
+#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out) {
int ret;
@@ -144,3 +148,4 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out) {
*sock_in = *sock_out = -1;
}
}
+#endif // ENABLE_CLI_PROXYCMD
diff --git a/cli-runopts.c b/cli-runopts.c
index d49caa2..a7c0f82 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -49,7 +49,11 @@ static void add_netcat(const char *str);
static void printhelp() {
fprintf(stderr, "Dropbear client v%s\n"
+#ifdef ENABLE_CLI_MULTIHOP
+ "Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n"
+#else
"Usage: %s [options] [user@]host[/port] [command]\n"
+#endif
"Options are:\n"
"-p <remoteport>\n"
"-l <username>\n"
@@ -74,22 +78,22 @@ static void printhelp() {
#endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
+ "-I <idle_timeout> (0 is never, default %d)\n"
#ifdef ENABLE_CLI_NETCAT
- "-B <endhost:endport> Netcat-alike bouncing\n"
+ "-B <endhost:endport> Netcat-alike forwarding\n"
#endif
#ifdef ENABLE_CLI_PROXYCMD
- "-J <proxy_program> Use program rather than tcp connection\n"
+ "-J <proxy_program> Use program pipe rather than TCP connection\n"
#endif
#ifdef DEBUG_TRACE
- "-v verbose\n"
+ "-v verbose (compiled with DEBUG_TRACE)\n"
#endif
,DROPBEAR_VERSION, cli_opts.progname,
- DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE);
+ DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
}
void cli_getopts(int argc, char ** argv) {
-
unsigned int i, j;
char ** next = 0;
unsigned int cmdlen;
@@ -109,6 +113,8 @@ void cli_getopts(int argc, char ** argv) {
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
+ char* idle_timeout_arg = NULL;
+ char *host_arg = NULL;
/* see printhelp() for options */
cli_opts.progname = argv[0];
@@ -264,6 +270,9 @@ void cli_getopts(int argc, char ** argv) {
case 'K':
next = &keepalive_arg;
break;
+ case 'I':
+ next = &idle_timeout_arg;
+ break;
#ifdef ENABLE_CLI_AGENTFWD
case 'A':
cli_opts.agent_fwd = 1;
@@ -307,12 +316,8 @@ void cli_getopts(int argc, char ** argv) {
/* Either the hostname or commands */
- if (cli_opts.remotehost == NULL) {
-#ifdef ENABLE_CLI_MULTIHOP
- parse_multihop_hostname(argv[i], argv[0]);
-#else
- parse_hostname(argv[i]);
-#endif
+ if (host_arg == NULL) {
+ host_arg = argv[i];
} else {
/* this is part of the commands to send - after this we
@@ -341,7 +346,7 @@ void cli_getopts(int argc, char ** argv) {
/* And now a few sanity checks and setup */
- if (cli_opts.remotehost == NULL) {
+ if (host_arg == NULL) {
printhelp();
exit(EXIT_FAILURE);
}
@@ -377,12 +382,26 @@ void cli_getopts(int argc, char ** argv) {
}
}
+ if (idle_timeout_arg) {
+ if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
+ dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
+ }
+ }
+
#ifdef ENABLE_CLI_NETCAT
if (cli_opts.cmd && cli_opts.netcat_host) {
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
}
#endif
-
+
+ /* The hostname gets set up last, since
+ * in multi-hop mode it will require knowledge
+ * of other flags such as -i */
+#ifdef ENABLE_CLI_MULTIHOP
+ parse_multihop_hostname(host_arg, argv[0]);
+#else
+ parse_hostname(host_arg);
+#endif
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
@@ -395,14 +414,12 @@ static void loadidentityfile(const char* filename) {
key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY;
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
-
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
sign_key_free(key);
-
} else {
-
nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
nextkey->key = key;
+ nextkey->filename = m_strdup(filename);
nextkey->next = cli_opts.privkeys;
nextkey->type = keytype;
nextkey->source = SIGNKEY_SOURCE_RAW_FILE;
@@ -413,6 +430,39 @@ static void loadidentityfile(const char* filename) {
#ifdef ENABLE_CLI_MULTIHOP
+static char*
+multihop_passthrough_args() {
+ char *ret;
+ int total;
+ unsigned int len = 0;
+ struct SignKeyList *nextkey;
+ /* Fill out -i and -W options that make sense for all
+ * the intermediate processes */
+ for (nextkey = cli_opts.privkeys; nextkey; nextkey = nextkey->next)
+ {
+ len += 3 + strlen(nextkey->filename);
+ }
+ len += 20; // space for -W <size>, terminator.
+ ret = m_malloc(len);
+ total = 0;
+
+ if (opts.recv_window != DEFAULT_RECV_WINDOW)
+ {
+ int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window);
+ total += written;
+ }
+
+ for (nextkey = cli_opts.privkeys; nextkey; nextkey = nextkey->next)
+ {
+ const size_t size = len - total;
+ int written = snprintf(ret+total, size, "-i %s", nextkey->filename);
+ dropbear_assert(written < size);
+ total += written;
+ }
+
+ return ret;
+}
+
/* Sets up 'onion-forwarding' connections. This will spawn
* a separate dbclient process for each hop.
* As an example, if the cmdline is
@@ -427,6 +477,7 @@ static void loadidentityfile(const char* filename) {
*/
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
char *userhostarg = NULL;
+ char *hostbuf = NULL;
char *last_hop = NULL;;
char *remainder = NULL;
@@ -439,11 +490,12 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
&& strchr(cli_opts.username, ',')
&& strchr(cli_opts.username, '@')) {
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
- userhostarg = m_malloc(len);
- snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg);
+ hostbuf = m_malloc(len);
+ snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
} else {
- userhostarg = m_strdup(orighostarg);
+ hostbuf = m_strdup(orighostarg);
}
+ userhostarg = hostbuf;
last_hop = strrchr(userhostarg, ',');
if (last_hop) {
@@ -461,19 +513,24 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
if (last_hop) {
/* Set up the proxycmd */
unsigned int cmd_len = 0;
+ char *passthrough_args = multihop_passthrough_args();
if (cli_opts.proxycmd) {
dropbear_exit("-J can't be used with multihop mode");
}
if (cli_opts.remoteport == NULL) {
cli_opts.remoteport = "22";
}
- cmd_len = strlen(remainder)
+ cmd_len = strlen(argv0) + strlen(remainder)
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
- + strlen(argv0) + 30;
+ + strlen(passthrough_args)
+ + 30;
cli_opts.proxycmd = m_malloc(cmd_len);
- snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s",
- argv0, cli_opts.remotehost, cli_opts.remoteport, remainder);
+ snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
+ argv0, cli_opts.remotehost, cli_opts.remoteport,
+ passthrough_args, remainder);
+ m_free(passthrough_args);
}
+ m_free(hostbuf);
}
#endif /* !ENABLE_CLI_MULTIHOP */
@@ -622,6 +679,7 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
goto badport;
}
+ newfwd->have_reply = 0;
newfwd->next = *fwdlist;
*fwdlist = newfwd;
diff --git a/cli-session.c b/cli-session.c
index 8c087d4..4aa2366 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -64,6 +64,10 @@ static const packettype cli_packettypes[] = {
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
{SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */
+#ifdef ENABLE_CLI_REMOTETCPFWD
+ {SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
+ {SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
+#endif
{0, 0} /* End */
};
diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c
index c3bfd4d..0e60090 100644
--- a/cli-tcpfwd.c
+++ b/cli-tcpfwd.c
@@ -128,7 +128,7 @@ static void send_msg_global_request_remotetcp(int port) {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
buf_putstring(ses.writepayload, "tcpip-forward", 13);
- buf_putbyte(ses.writepayload, 0);
+ buf_putbyte(ses.writepayload, 1); /* want_reply */
if (opts.listen_fwd_all) {
listenspec = "";
} else {
@@ -143,6 +143,42 @@ static void send_msg_global_request_remotetcp(int port) {
TRACE(("leave send_msg_global_request_remotetcp"))
}
+/* The only global success/failure messages are for remotetcp.
+ * Since there isn't any identifier in these messages, we have to rely on them
+ * being in the same order as we sent the requests. This is the ordering
+ * of the cli_opts.remotefwds list */
+void cli_recv_msg_request_success() {
+
+ /* Nothing in the packet. We just mark off that we have received the reply,
+ * so that we can report failure for later ones. */
+ struct TCPFwdList * iter = NULL;
+
+ iter = cli_opts.remotefwds;
+ while (iter != NULL) {
+ if (!iter->have_reply)
+ {
+ iter->have_reply = 1;
+ return;
+ }
+ iter = iter->next;
+ }
+}
+
+void cli_recv_msg_request_failure() {
+ struct TCPFwdList * iter = NULL;
+
+ iter = cli_opts.remotefwds;
+ while (iter != NULL) {
+ if (!iter->have_reply)
+ {
+ iter->have_reply = 1;
+ dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", iter->listenport, iter->connectaddr, iter->connectport);
+ return;
+ }
+ iter = iter->next;
+ }
+}
+
void setup_remotetcp() {
struct TCPFwdList * iter = NULL;
diff --git a/common-algo.c b/common-algo.c
index 21ac96a..892399f 100644
--- a/common-algo.c
+++ b/common-algo.c
@@ -29,32 +29,46 @@
/* 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 *cipher_state) {
+ if (in != out) {
+ memmove(out, in, len);
+ }
+ return CRYPT_OK;
+}
+
+static int void_start(int cipher, const unsigned char *IV,
+ const unsigned char *key,
+ int keylen, int num_rounds, void *cipher_state) {
+ return CRYPT_OK;
+}
+
/* Mappings for ciphers, parameters are
{&cipher_desc, keysize, blocksize} */
/* NOTE: if keysize > 2*SHA1_HASH_SIZE, code such as hashkeys()
needs revisiting */
-#ifdef DROPBEAR_AES256_CBC
+#ifdef DROPBEAR_AES256
static const struct dropbear_cipher dropbear_aes256 =
{&aes_desc, 32, 16};
#endif
-#ifdef DROPBEAR_AES128_CBC
+#ifdef DROPBEAR_AES128
static const struct dropbear_cipher dropbear_aes128 =
{&aes_desc, 16, 16};
#endif
-#ifdef DROPBEAR_BLOWFISH_CBC
+#ifdef DROPBEAR_BLOWFISH
static const struct dropbear_cipher dropbear_blowfish =
{&blowfish_desc, 16, 8};
#endif
-#ifdef DROPBEAR_TWOFISH256_CBC
+#ifdef DROPBEAR_TWOFISH256
static const struct dropbear_cipher dropbear_twofish256 =
{&twofish_desc, 32, 16};
#endif
-#ifdef DROPBEAR_TWOFISH128_CBC
+#ifdef DROPBEAR_TWOFISH128
static const struct dropbear_cipher dropbear_twofish128 =
{&twofish_desc, 16, 16};
#endif
-#ifdef DROPBEAR_3DES_CBC
+#ifdef DROPBEAR_3DES
static const struct dropbear_cipher dropbear_3des =
{&des3_desc, 24, 8};
#endif
@@ -63,6 +77,24 @@ static const struct dropbear_cipher dropbear_3des =
const struct dropbear_cipher dropbear_nocipher =
{NULL, 16, 8};
+/* A few void* s are required to silence warnings
+ * about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
+const struct dropbear_cipher_mode dropbear_mode_cbc =
+ {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
+const struct dropbear_cipher_mode dropbear_mode_none =
+ {void_start, void_cipher, void_cipher};
+#ifdef DROPBEAR_ENABLE_CTR_MODE
+/* a wrapper to make ctr_start and cbc_start look the same */
+static int dropbear_big_endian_ctr_start(int cipher,
+ const unsigned char *IV,
+ const unsigned char *key, int keylen,
+ int num_rounds, symmetric_CTR *ctr) {
+ return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
+}
+const struct dropbear_cipher_mode dropbear_mode_ctr =
+ {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
+#endif
+
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
{&hash_desc, keysize, hashsize} */
@@ -83,65 +115,81 @@ const struct dropbear_hash dropbear_nohash =
{NULL, 16, 0}; /* used initially */
-/* The following map ssh names to internal values */
+/* The following map ssh names to internal values.
+ * The ordering here is important for the client - the first mode
+ * that is also supported by the server will get used. */
algo_type sshciphers[] = {
-#ifdef DROPBEAR_AES128_CBC
- {"aes128-cbc", 0, (void*)&dropbear_aes128, 1},
+#ifdef DROPBEAR_ENABLE_CTR_MODE
+#ifdef DROPBEAR_AES128
+ {"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
+#endif
+#ifdef DROPBEAR_3DES
+ {"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
+#endif
+#ifdef DROPBEAR_AES256
+ {"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
+#endif
+#endif /* DROPBEAR_ENABLE_CTR_MODE */
+
+/* CBC modes are always enabled */
+#ifdef DROPBEAR_AES128
+ {"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
#endif
-#ifdef DROPBEAR_3DES_CBC
- {"3des-cbc", 0, (void*)&dropbear_3des, 1},
+#ifdef DROPBEAR_3DES
+ {"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
#endif
-#ifdef DROPBEAR_AES256_CBC
- {"aes256-cbc", 0, (void*)&dropbear_aes256, 1},
+#ifdef DROPBEAR_AES256
+ {"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
#endif
-#ifdef DROPBEAR_TWOFISH256_CBC
- {"twofish256-cbc", 0, (void*)&dropbear_twofish256, 1},
- {"twofish-cbc", 0, (void*)&dropbear_twofish256, 1},
+#ifdef DROPBEAR_TWOFISH256
+ {"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
+ {"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
#endif
-#ifdef DROPBEAR_TWOFISH128_CBC
- {"twofish128-cbc", 0, (void*)&dropbear_twofish128, 1},
+#ifdef DROPBEAR_TWOFISH128
+ {"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
#endif
-#ifdef DROPBEAR_BLOWFISH_CBC
- {"blowfish-cbc", 0, (void*)&dropbear_blowfish, 1},
+#ifdef DROPBEAR_BLOWFISH
+ {"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
#endif
- {NULL, 0, NULL, 0}
+ {NULL, 0, NULL, 0, NULL}
};
algo_type sshhashes[] = {
#ifdef DROPBEAR_SHA1_96_HMAC
- {"hmac-sha1-96", 0, (void*)&dropbear_sha1_96, 1},
+ {"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
#endif
#ifdef DROPBEAR_SHA1_HMAC
- {"hmac-sha1", 0, (void*)&dropbear_sha1, 1},
+ {"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
#endif
#ifdef DROPBEAR_MD5_HMAC
- {"hmac-md5", 0, (void*)&dropbear_md5, 1},
+ {"hmac-md5", 0, &dropbear_md5, 1, NULL},
#endif
- {NULL, 0, NULL, 0}
+ {NULL, 0, NULL, 0, NULL}
};
algo_type sshcompress[] = {
#ifndef DISABLE_ZLIB
- {"zlib", DROPBEAR_COMP_ZLIB, NULL, 1},
+ {"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
+ {"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
#endif
- {"none", DROPBEAR_COMP_NONE, NULL, 1},
- {NULL, 0, NULL, 0}
+ {"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
+ {NULL, 0, NULL, 0, NULL}
};
algo_type sshhostkey[] = {
#ifdef DROPBEAR_RSA
- {"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1},
+ {"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
#endif
#ifdef DROPBEAR_DSS
- {"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1},
+ {"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL},
#endif
- {NULL, 0, NULL, 0}
+ {NULL, 0, NULL, 0, NULL}
};
algo_type sshkex[] = {
- {"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1},
- {NULL, 0, NULL, 0}
+ {"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
+ {NULL, 0, NULL, 0, NULL}
};
@@ -150,16 +198,16 @@ algo_type sshkex[] = {
void crypto_init() {
const struct ltc_cipher_descriptor *regciphers[] = {
-#ifdef DROPBEAR_AES_CBC
+#ifdef DROPBEAR_AES
&aes_desc,
#endif
-#ifdef DROPBEAR_BLOWFISH_CBC
+#ifdef DROPBEAR_BLOWFISH
&blowfish_desc,
#endif
-#ifdef DROPBEAR_TWOFISH_CBC
+#ifdef DROPBEAR_TWOFISH
&twofish_desc,
#endif
-#ifdef DROPBEAR_3DES_CBC
+#ifdef DROPBEAR_3DES
&des3_desc,
#endif
NULL
@@ -215,7 +263,7 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
unsigned int donefirst = 0;
buffer *algolist = NULL;
- algolist = buf_new(100);
+ algolist = buf_new(160);
for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) {
if (donefirst)
diff --git a/common-channel.c b/common-channel.c
index 2105184..95fce78 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -276,10 +276,10 @@ static void check_close(struct Channel *channel) {
channel->flushing = 1;
}
- // if a type-specific check_close is defined we will only exit
- // once that has been triggered. this is only used for a server "session"
- // channel, to ensure that the shell has exited (and the exit status
- // retrieved) before we close things up.
+ /* if a type-specific check_close is defined we will only exit
+ once that has been triggered. this is only used for a server "session"
+ channel, to ensure that the shell has exited (and the exit status
+ retrieved) before we close things up. */
if (!channel->type->check_close
|| channel->type->check_close(channel)) {
close_allowed = 1;
@@ -691,7 +691,7 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
dropbear_exit("received data after eof");
}
- if (fd < 0) {
+ if (fd < 0) {
/* If we have encountered failed write, the far side might still
* be sending data without having yet received our close notification.
* We just drop the data. */
diff --git a/common-kex.c b/common-kex.c
index e9c655d..052324b 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -272,8 +272,8 @@ void gen_new_keys() {
recv_IV = S2C_IV;
trans_key = C2S_key;
recv_key = S2C_key;
- C2S_keysize = ses.newkeys->trans_algo_crypt->keysize;
- S2C_keysize = ses.newkeys->recv_algo_crypt->keysize;
+ C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
+ S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
mactransletter = 'E';
macrecvletter = 'F';
} else {
@@ -281,8 +281,8 @@ void gen_new_keys() {
recv_IV = C2S_IV;
trans_key = S2C_key;
recv_key = C2S_key;
- C2S_keysize = ses.newkeys->recv_algo_crypt->keysize;
- S2C_keysize = ses.newkeys->trans_algo_crypt->keysize;
+ C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
+ S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
mactransletter = 'F';
macrecvletter = 'E';
}
@@ -292,30 +292,33 @@ void gen_new_keys() {
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
- recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name);
+ recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
if (recv_cipher < 0)
dropbear_exit("crypto error");
-
- if (cbc_start(recv_cipher, recv_IV, recv_key,
- ses.newkeys->recv_algo_crypt->keysize, 0,
- &ses.newkeys->recv_symmetric_struct) != CRYPT_OK) {
+ if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
+ recv_IV, recv_key,
+ ses.newkeys->recv.algo_crypt->keysize, 0,
+ &ses.newkeys->recv.cipher_state) != CRYPT_OK) {
dropbear_exit("crypto error");
}
- trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name);
+
+ trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
if (trans_cipher < 0)
dropbear_exit("crypto error");
-
- if (cbc_start(trans_cipher, trans_IV, trans_key,
- ses.newkeys->trans_algo_crypt->keysize, 0,
- &ses.newkeys->trans_symmetric_struct) != CRYPT_OK) {
+ if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
+ trans_IV, trans_key,
+ ses.newkeys->trans.algo_crypt->keysize, 0,
+ &ses.newkeys->trans.cipher_state) != CRYPT_OK) {
dropbear_exit("crypto error");
}
/* MAC keys */
- hashkeys(ses.newkeys->transmackey,
- ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter);
- hashkeys(ses.newkeys->recvmackey,
- ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter);
+ hashkeys(ses.newkeys->trans.mackey,
+ ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
+ hashkeys(ses.newkeys->recv.mackey,
+ ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
+ ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name),
+ ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name),
#ifndef DISABLE_ZLIB
gen_new_zstreams();
@@ -331,53 +334,68 @@ void gen_new_keys() {
}
#ifndef DISABLE_ZLIB
+
+int is_compress_trans() {
+ return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB
+ || (ses.authstate.authdone
+ && ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
+}
+
+int is_compress_recv() {
+ return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB
+ || (ses.authstate.authdone
+ && ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
+}
+
/* Set up new zlib compression streams, close the old ones. Only
* called from gen_new_keys() */
static void gen_new_zstreams() {
/* create new zstreams */
- if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB) {
- ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream));
- ses.newkeys->recv_zstream->zalloc = Z_NULL;
- ses.newkeys->recv_zstream->zfree = Z_NULL;
+ if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
+ || ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
+ ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
+ ses.newkeys->recv.zstream->zalloc = Z_NULL;
+ ses.newkeys->recv.zstream->zfree = Z_NULL;
- if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) {
+ if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
dropbear_exit("zlib error");
}
} else {
- ses.newkeys->recv_zstream = NULL;
+ ses.newkeys->recv.zstream = NULL;
}
- if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB) {
- ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream));
- ses.newkeys->trans_zstream->zalloc = Z_NULL;
- ses.newkeys->trans_zstream->zfree = Z_NULL;
+ if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
+ || ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
+ ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
+ ses.newkeys->trans.zstream->zalloc = Z_NULL;
+ ses.newkeys->trans.zstream->zfree = Z_NULL;
- if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION)
+ if (deflateInit(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION)
!= Z_OK) {
dropbear_exit("zlib error");
}
} else {
- ses.newkeys->trans_zstream = NULL;
+ ses.newkeys->trans.zstream = NULL;
}
-
+
/* clean up old keys */
- if (ses.keys->recv_zstream != NULL) {
- if (inflateEnd(ses.keys->recv_zstream) == Z_STREAM_ERROR) {
+ if (ses.keys->recv.zstream != NULL) {
+ if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("crypto error");
}
- m_free(ses.keys->recv_zstream);
+ m_free(ses.keys->recv.zstream);
}
- if (ses.keys->trans_zstream != NULL) {
- if (deflateEnd(ses.keys->trans_zstream) == Z_STREAM_ERROR) {
+ if (ses.keys->trans.zstream != NULL) {
+ if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("crypto error");
}
- m_free(ses.keys->trans_zstream);
+ m_free(ses.keys->trans.zstream);
}
}
-#endif
+#endif /* DISABLE_ZLIB */
/* Executed upon receiving a kexinit message from the client to initiate
@@ -682,28 +700,36 @@ static void read_kex_algos() {
/* Handle the asymmetry */
if (IS_DROPBEAR_CLIENT) {
- ses.newkeys->recv_algo_crypt =
+ ses.newkeys->recv.algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data;
- ses.newkeys->trans_algo_crypt =
+ ses.newkeys->trans.algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data;
- ses.newkeys->recv_algo_mac =
+ ses.newkeys->recv.crypt_mode =
+ (struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
+ ses.newkeys->trans.crypt_mode =
+ (struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
+ ses.newkeys->recv.algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data;
- ses.newkeys->trans_algo_mac =
+ ses.newkeys->trans.algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data;
- ses.newkeys->recv_algo_comp = s2c_comp_algo->val;
- ses.newkeys->trans_algo_comp = c2s_comp_algo->val;
+ ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
+ ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
} else {
/* SERVER */
- ses.newkeys->recv_algo_crypt =
+ ses.newkeys->recv.algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data;
- ses.newkeys->trans_algo_crypt =
+ ses.newkeys->trans.algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data;
- ses.newkeys->recv_algo_mac =
+ ses.newkeys->recv.crypt_mode =
+ (struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
+ ses.newkeys->trans.crypt_mode =
+ (struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
+ ses.newkeys->recv.algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data;
- ses.newkeys->trans_algo_mac =
+ ses.newkeys->trans.algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data;
- ses.newkeys->recv_algo_comp = c2s_comp_algo->val;
- ses.newkeys->trans_algo_comp = s2c_comp_algo->val;
+ ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
+ ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
}
/* reserved for future extensions */
diff --git a/common-session.c b/common-session.c
index 3d759b5..1348da2 100644
--- a/common-session.c
+++ b/common-session.c
@@ -63,6 +63,7 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
ses.maxfd = MAX(sock_in, sock_out);
ses.connect_time = 0;
+ ses.last_trx_packet_time = 0;
ses.last_packet_time = 0;
if (pipe(ses.signal_pipe) < 0) {
@@ -70,6 +71,9 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
}
setnonblocking(ses.signal_pipe[0]);
setnonblocking(ses.signal_pipe[1]);
+
+ ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
+ ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
kexfirstinitialise(); /* initialise the kex state */
@@ -77,7 +81,6 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
ses.transseq = 0;
ses.readbuf = NULL;
- ses.decryptreadbuf = NULL;
ses.payload = NULL;
ses.recvseq = 0;
@@ -94,20 +97,22 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
/* set all the algos to none */
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
ses.newkeys = NULL;
- ses.keys->recv_algo_crypt = &dropbear_nocipher;
- ses.keys->trans_algo_crypt = &dropbear_nocipher;
+ ses.keys->recv.algo_crypt = &dropbear_nocipher;
+ ses.keys->trans.algo_crypt = &dropbear_nocipher;
+ ses.keys->recv.crypt_mode = &dropbear_mode_none;
+ ses.keys->trans.crypt_mode = &dropbear_mode_none;
- ses.keys->recv_algo_mac = &dropbear_nohash;
- ses.keys->trans_algo_mac = &dropbear_nohash;
+ ses.keys->recv.algo_mac = &dropbear_nohash;
+ ses.keys->trans.algo_mac = &dropbear_nohash;
ses.keys->algo_kex = -1;
ses.keys->algo_hostkey = -1;
- ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE;
- ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE;
+ ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
+ ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
#ifndef DISABLE_ZLIB
- ses.keys->recv_zstream = NULL;
- ses.keys->trans_zstream = NULL;
+ ses.keys->recv.zstream = NULL;
+ ses.keys->trans.zstream = NULL;
#endif
/* key exchange buffers */
@@ -256,7 +261,7 @@ void session_identification() {
ses.remoteclosed();
}
- /* If they send more than 50 lines, something is wrong */
+ /* If they send more than 50 lines, something is wrong */
for (i = 0; i < 50; i++) {
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
@@ -281,11 +286,11 @@ void session_identification() {
memcpy(ses.remoteident, linebuf, len);
}
- /* Shall assume that 2.x will be backwards compatible. */
- if (strncmp(ses.remoteident, "SSH-2.", 6) != 0
- && strncmp(ses.remoteident, "SSH-1.99-", 9) != 0) {
- dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
- }
+ /* Shall assume that 2.x will be backwards compatible. */
+ if (strncmp(ses.remoteident, "SSH-2.", 6) != 0
+ && strncmp(ses.remoteident, "SSH-1.99-", 9) != 0) {
+ dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
+ }
TRACE(("remoteident: %s", ses.remoteident))
@@ -397,9 +402,14 @@ static void checktimeouts() {
}
if (opts.keepalive_secs > 0
- && now - ses.last_packet_time >= opts.keepalive_secs) {
+ && now - ses.last_trx_packet_time >= opts.keepalive_secs) {
send_msg_ignore();
}
+
+ if (opts.idle_timeout_secs > 0 && ses.last_packet_time > 0
+ && now - ses.last_packet_time >= opts.idle_timeout_secs) {
+ dropbear_close("Idle timeout");
+ }
}
static long select_timeout() {
@@ -412,6 +422,8 @@ static long select_timeout() {
ret = MIN(AUTH_TIMEOUT, ret);
if (opts.keepalive_secs > 0)
ret = MIN(opts.keepalive_secs, ret);
+ if (opts.idle_timeout_secs > 0)
+ ret = MIN(opts.idle_timeout_secs, ret);
return ret;
}
diff --git a/configure.in b/configure.in
index 52a75e0..c7149e8 100644
--- a/configure.in
+++ b/configure.in
@@ -82,7 +82,8 @@ AC_CHECK_DECL(__UCLIBC__,
],,,)
# Checks for libraries.
-AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt")
+AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt")
+AC_SUBST(CRYPTLIB)
# Check if zlib is needed
AC_ARG_WITH(zlib,
diff --git a/dbclient.1 b/dbclient.1
index 033672d..96e6c5c 100644
--- a/dbclient.1
+++ b/dbclient.1
@@ -10,6 +10,13 @@ dbclient \- lightweight SSH2 client
.I l\fR:\fIh\fR:\fIr\fR] [\-l
.IR user ]
.I host
+.RI [ command ]
+
+.B dbclient
+[
+.I args ]
+.I [user1]@host1[/port1],[user2]@host2[/port2],...
+
.SH DESCRIPTION
.B dbclient
is a SSH 2 client designed to be small enough to be used in small memory
@@ -86,22 +93,52 @@ useful for working around firewalls or routers that drop connections after
a certain period of inactivity. The trade-off is that a session may be
closed if there is a temporary lapse of network connectivity. A setting
if 0 disables keepalives.
+.TP
+.B \-I \fIidle_timeout
+Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
+.TP
+.B \-J \fIproxy_command
+Use the standard input/output of the program \fIproxy_command\fR rather than using
+a normal TCP connection. A hostname should be still be provided, as this is used for
+comparing saved hostkeys.
+.TP
+.B \-B \fIendhost:endport
+"Netcat-alike" mode, where Dropbear will connect to the given host, then create a
+forwarded connection to \fIendhost\fR. This will then be presented as dbclient's
+standard input/output.
+
+Dropbear will also allow multiple "hops" to be specified, separated by commas. In
+this case a connection will be made to the first host, then a TCP forwarded
+connection will be made through that to the second host, and so on. Hosts other than
+the final destination will not see anything other than the encrypted SSH stream.
+A port for a host can be specified with a slash (eg matt@martello/44 ).
+This syntax can also be used with scp or rsync (specifying dbclient as the
+ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg
+
+scp -S dbclient matt@martello,root@wrt,canyons:/tmp/dump .
+
+Note that hostnames are resolved by the prior hop (so "canyons" would be resolved by the host "wrt")
+in the example above, the same way as other -L TCP forwarded hosts are. Host keys are
+checked locally based on the given hostname.
+
.SH ENVIRONMENT
.TP
+.B DROPBEAR_PASSWORD
+A password to use for remote authentication can be specified in the environment
+variable DROPBEAR_PASSWORD. Care should be taken that the password is not
+exposed to other users on a multi-user system, or stored in accessible files.
+.TP
.B SSH_ASKPASS
dbclient can use an external program to request a password from a user.
SSH_ASKPASS should be set to the path of a program that will return a password
on standard output. This program will only be used if either DISPLAY is set and
standard input is not a TTY, or the environment variable SSH_ASKPASS_ALWAYS is
set.
-.TP
-.B DROPBEAR_PASSWORD
-A password to use for remote authentication can be specified in the environment
-variable DROPBEAR_PASSWORD. Care should be taken that the password is not
-exposed to other users on a multi-user system, or stored in accessible files.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
+Mihnea Stoenescu wrote initial Dropbear client support
+.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8), dropbearkey(8)
diff --git a/debian/changelog b/debian/changelog
index f51769b..83639c9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+dropbear (0.52-0.1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Matt Johnston <matt@ucc.asn.au> Wed, 12 Nov 2008 22:54:00 +0900
+
dropbear (0.51-0.1) unstable; urgency=low
* New upstream release.
diff --git a/debian/dropbear.postinst b/debian/dropbear.postinst
index 7c95cfa..2491e45 100644
--- a/debian/dropbear.postinst
+++ b/debian/dropbear.postinst
@@ -71,7 +71,7 @@ if test -x /etc/init.d/dropbear; then
fi
if test -n "$2" && dpkg --compare-versions "$2" lt '0.50-4' &&
-update-service --check dropbear; then
+update-service --check dropbear 2>/dev/null; then
update-service --remove /etc/dropbear 2>/dev/null || :
sleep 6
rm -rf /var/run/dropbear /var/run/dropbear.log
diff --git a/debug.h b/debug.h
index a9cc0bd..b8c2a57 100644
--- a/debug.h
+++ b/debug.h
@@ -39,7 +39,7 @@
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing may not sanitise strings etc. This will add a reasonable
* amount to your executable size. */
-#define DEBUG_TRACE
+/*#define DEBUG_TRACE*/
/* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
diff --git a/dropbear.8 b/dropbear.8
index c9c2e79..ecbad31 100644
--- a/dropbear.8
+++ b/dropbear.8
@@ -24,7 +24,10 @@ before user login (default: none).
dsskeyfile.
Use the contents of the file
.I dsskey
-for the dss host key (default: /etc/dropbear/dropbear_dss_host_key).
+for the DSS host key (default: /etc/dropbear/dropbear_dss_host_key).
+Note that
+some SSH implementations
+use the term "DSA" rather than "DSS", they mean the same thing.
This file is generated with
.BR dropbearkey (8).
.TP
@@ -94,6 +97,63 @@ useful for working around firewalls or routers that drop connections after
a certain period of inactivity. The trade-off is that a session may be
closed if there is a temporary lapse of network connectivity. A setting
if 0 disables keepalives.
+.TP
+.B \-I \fIidle_timeout
+Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
+.SH FILES
+
+.TP
+Authorized Keys
+
+~/.ssh/authorized_keys can be set up to allow remote login with a RSA or DSS
+key. Each line is of the form
+.TP
+[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
+
+and can be extracted from a Dropbear private host key with "dropbearkey -y". This is the same format as used by OpenSSH, though the restrictions are a subset (keys with unknown restrictions are ignored).
+Restrictions are comma separated, with double quotes around spaces in arguments.
+Available restrictions are:
+
+.TP
+.B no-port-forwarding
+Don't allow port forwarding for this connection
+
+.TP
+.B no-agent-forwarding
+Don't allow agent forwarding for this connection
+
+.TP
+.B no-X11-forwarding
+Don't allow X11 forwarding for this connection
+
+.TP
+.B no-pty
+Disable PTY allocation. Note that a user can still obtain most of the
+same functionality with other means even if no-pty is set.
+
+.TP
+.B command="\fIforced_command\fR"
+Disregard the command provided by the user and always run \fIforced_command\fR.
+
+The authorized_keys file and its containing ~/.ssh directory must only be
+writable by the user, otherwise Dropbear will not allow a login using public
+key authentication.
+
+.TP
+Host Key Files
+
+Host key files are read at startup from a standard location, by default
+/etc/dropbear/dropbear_dss_host_key and /etc/dropbear/dropbear_rsa_host_key
+or specified on the commandline with -d or -r. These are of the form generated
+by dropbearkey.
+
+.TP
+Message Of The Day
+
+By default the file /etc/motd will be printed for any login shell (unless
+disabled at compile-time). This can also be disabled per-user
+by creating a file ~/.hushlogin .
+
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
diff --git a/dropbearkey.8 b/dropbearkey.8
index a093d85..b5745dd 100644
--- a/dropbearkey.8
+++ b/dropbearkey.8
@@ -11,13 +11,16 @@ dropbearkey \- create private keys for the use with dropbear(8)
.IR bits ]
.SH DESCRIPTION
.B dropbearkey
-generates a type
-.I rsa
+generates a
+.I RSA
or
-.I dss
-SSH private key, and saves it to a file for the use with the
+.I DSS
+format SSH private key, and saves it to a file for the use with the
.BR dropbear (8)
SSH 2 server.
+Note that
+some SSH implementations
+use the term "DSA" rather than "DSS", they mean the same thing.
.SH OPTIONS
.TP
.B \-t \fItype
diff --git a/kex.h b/kex.h
index d3dd187..a3bdc7a 100644
--- a/kex.h
+++ b/kex.h
@@ -37,6 +37,11 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv);
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
sign_key *hostkey);
+#ifndef DISABLE_ZLIB
+int is_compress_trans();
+int is_compress_recv();
+#endif
+
void recv_msg_kexdh_init(); /* server */
void send_msg_kexdh_init(); /* client */
diff --git a/libtomcrypt/src/headers/tomcrypt_custom.h b/libtomcrypt/src/headers/tomcrypt_custom.h
index 440168b..928f54e 100644
--- a/libtomcrypt/src/headers/tomcrypt_custom.h
+++ b/libtomcrypt/src/headers/tomcrypt_custom.h
@@ -90,15 +90,15 @@
/* #define LTC_NO_BSWAP */
-#ifdef DROPBEAR_BLOWFISH_CBC
+#ifdef DROPBEAR_BLOWFISH
#define BLOWFISH
#endif
-#ifdef DROPBEAR_AES_CBC
+#ifdef DROPBEAR_AES
#define RIJNDAEL
#endif
-#ifdef DROPBEAR_TWOFISH_CBC
+#ifdef DROPBEAR_TWOFISH
#define TWOFISH
/* enabling just TWOFISH_SMALL will make the binary ~1kB smaller, turning on
@@ -108,12 +108,16 @@
/*#define TWOFISH_TABLES*/
#endif
-#ifdef DROPBEAR_3DES_CBC
+#ifdef DROPBEAR_3DES
#define DES
#endif
#define LTC_CBC_MODE
+#ifdef DROPBEAR_ENABLE_CTR_MODE
+#define LTC_CTR_MODE
+#endif
+
#if defined(DROPBEAR_DSS) && defined(DSS_PROTOK)
#define SHA512
#endif
diff --git a/loginrec.c b/loginrec.c
index f084566..14b8090 100644
--- a/loginrec.c
+++ b/loginrec.c
@@ -1334,7 +1334,7 @@ lastlog_openseek(struct logininfo *li, int *fd, int filemode)
return 0;
}
- *fd = open(lastlog_file, filemode);
+ *fd = open(lastlog_file, filemode, 0600);
if ( *fd < 0) {
dropbear_log(LOG_INFO, "lastlog_openseek: Couldn't open %s: %s",
lastlog_file, strerror(errno));
diff --git a/options.h b/options.h
index 5515628..021457c 100644
--- a/options.h
+++ b/options.h
@@ -46,9 +46,10 @@
/*#define NO_FAST_EXPTMOD*/
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
-several kB in binary size, however will make the symmetrical ciphers (AES, DES
-etc) slower (perhaps by 50%). Recommended for most small systems. */
-#define DROPBEAR_SMALL_CODE
+several kB in binary size however will make the symmetrical ciphers and hashes
+slower, perhaps by 50%. Recommended for small systems that aren't doing
+much traffic. */
+/*#define DROPBEAR_SMALL_CODE*/
/* Enable X11 Forwarding - server only */
#define ENABLE_X11FWD
@@ -60,10 +61,6 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define ENABLE_CLI_LOCALTCPFWD
#define ENABLE_CLI_REMOTETCPFWD
-/* Allow using -J <proxycommand> to run the connection through a
- pipe to a program, rather the normal TCP connection */
-#define ENABLE_CLI_PROXYCMD
-
#define ENABLE_SVR_LOCALTCPFWD
#define ENABLE_SVR_REMOTETCPFWD
@@ -71,23 +68,36 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define ENABLE_SVR_AGENTFWD
#define ENABLE_CLI_AGENTFWD
-/* Enable "Netcat mode". TODO describe here. */
-#define ENABLE_CLI_NETCAT
+/* Note: Both ENABLE_CLI_PROXYCMD and ENABLE_CLI_NETCAT must be set to
+ * allow multihop dbclient connections */
+
+/* Allow using -J <proxycommand> to run the connection through a
+ pipe to a program, rather the normal TCP connection */
+#define ENABLE_CLI_PROXYCMD
+
+/* Enable "Netcat mode" option. This will forward standard input/output
+ * to a remote TCP-forwarded connection */
+#define ENABLE_CLI_NETCAT
/* Encryption - at least one required.
- * RFC Draft requires 3DES and recommends AES128 for interoperability.
+ * Protocol RFC requires 3DES and recommends AES128 for interoperability.
* Including multiple keysize variants the same cipher
* (eg AES256 as well as AES128) will result in a minimal size increase.*/
-#define DROPBEAR_AES128_CBC
-#define DROPBEAR_3DES_CBC
-#define DROPBEAR_AES256_CBC
-#define DROPBEAR_BLOWFISH_CBC
-#define DROPBEAR_TWOFISH256_CBC
-#define DROPBEAR_TWOFISH128_CBC
+#define DROPBEAR_AES128
+#define DROPBEAR_3DES
+#define DROPBEAR_AES256
+#define DROPBEAR_BLOWFISH
+#define DROPBEAR_TWOFISH256
+#define DROPBEAR_TWOFISH128
+
+/* Enable "Counter Mode" for ciphers. This is more secure than normal
+ * CBC mode against certain attacks. This adds around 1kB to binary
+ * size and is recommended for most cases */
+#define DROPBEAR_ENABLE_CTR_MODE
/* Message Integrity - at least one required.
- * RFC Draft requires sha1 and recommends sha1-96.
+ * Protocol RFC requires sha1 and recommends sha1-96.
* sha1-96 may be of use for slow links, as it has a smaller overhead.
*
* Note: there's no point disabling sha1 to save space, since it's used
@@ -143,7 +153,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define ENABLE_SVR_PASSWORD_AUTH
/* PAM requires ./configure --enable-pam */
-/* #define ENABLE_SVR_PAM_AUTH */
+/*#define ENABLE_SVR_PAM_AUTH*/
#define ENABLE_SVR_PUBKEY_AUTH
/* Wether to ake public key options in authorized_keys file into account */
@@ -250,6 +260,13 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
be overridden at runtime with -K. 0 disables keepalives */
#define DEFAULT_KEEPALIVE 0
+/* Ensure that data is received within IDLE_TIMEOUT seconds. This can
+be overridden at runtime with -I. 0 disables idle timeouts */
+#define DEFAULT_IDLE_TIMEOUT 0
+
+/* The default path. This will often get replaced by the shell */
+#define DEFAULT_PATH "/usr/bin:/bin"
+
/* Some other defines (that mostly should be left alone) are defined
* in sysoptions.h */
#include "sysoptions.h"
diff --git a/packet.c b/packet.c
index 30f4758..37ffdd2 100644
--- a/packet.c
+++ b/packet.c
@@ -35,9 +35,11 @@
#include "auth.h"
#include "channel.h"
-static void read_packet_init();
-static void writemac(buffer * outputbuffer, buffer * clearwritebuf);
-static int checkmac(buffer* hashbuf, buffer* readbuf);
+static int read_packet_init();
+static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
+ buffer * clear_buf, unsigned int clear_len,
+ unsigned char *output_mac);
+static int checkmac();
#define ZLIB_COMPRESS_INCR 20 /* this is 12 bytes + 0.1% of 8000 bytes */
#define ZLIB_DECOMPRESS_INCR 100
@@ -72,6 +74,7 @@ void write_packet() {
}
}
+ ses.last_trx_packet_time = time(NULL);
ses.last_packet_time = time(NULL);
if (written == 0) {
@@ -101,18 +104,18 @@ void read_packet() {
unsigned char blocksize;
TRACE(("enter read_packet"))
- blocksize = ses.keys->recv_algo_crypt->blocksize;
+ blocksize = ses.keys->recv.algo_crypt->blocksize;
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
+ int ret;
/* In the first blocksize of a packet */
/* Read the first blocksize of the packet, so we can decrypt it and
* find the length of the whole packet */
- read_packet_init();
+ ret = read_packet_init();
- /* If we don't have the length of decryptreadbuf, we didn't read
- * a whole blocksize and should exit */
- if (ses.decryptreadbuf->len == 0) {
+ if (ret == DROPBEAR_FAILURE) {
+ /* didn't read enough to determine the length */
TRACE(("leave read_packet: packetinit done"))
return;
}
@@ -120,7 +123,6 @@ void read_packet() {
/* Attempt to read the remainder of the packet, note that there
* mightn't be any available (EAGAIN) */
- dropbear_assert(ses.readbuf != NULL);
maxlen = ses.readbuf->len - ses.readbuf->pos;
len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
@@ -150,7 +152,9 @@ void read_packet() {
/* Function used to read the initial portion of a packet, and determine the
* length. Only called during the first BLOCKSIZE of a packet. */
-static void read_packet_init() {
+/* Returns DROPBEAR_SUCCESS if the length is determined,
+ * DROPBEAR_FAILURE otherwise */
+static int read_packet_init() {
unsigned int maxlen;
int len;
@@ -158,14 +162,12 @@ static void read_packet_init() {
unsigned char macsize;
- blocksize = ses.keys->recv_algo_crypt->blocksize;
- macsize = ses.keys->recv_algo_mac->hashsize;
+ blocksize = ses.keys->recv.algo_crypt->blocksize;
+ macsize = ses.keys->recv.algo_mac->hashsize;
if (ses.readbuf == NULL) {
/* start of a new packet */
ses.readbuf = buf_new(INIT_READBUF);
- dropbear_assert(ses.decryptreadbuf == NULL);
- ses.decryptreadbuf = buf_new(blocksize);
}
maxlen = blocksize - ses.readbuf->pos;
@@ -179,7 +181,7 @@ static void read_packet_init() {
if (len < 0) {
if (errno == EINTR) {
TRACE(("leave read_packet_init: EINTR"))
- return;
+ return DROPBEAR_FAILURE;
}
dropbear_exit("error reading: %s", strerror(errno));
}
@@ -188,30 +190,22 @@ static void read_packet_init() {
if ((unsigned int)len != maxlen) {
/* don't have enough bytes to determine length, get next time */
- return;
+ return DROPBEAR_FAILURE;
}
/* now we have the first block, need to get packet length, so we decrypt
* the first block (only need first 4 bytes) */
buf_setpos(ses.readbuf, 0);
- if (ses.keys->recv_algo_crypt->cipherdesc == NULL) {
- /* copy it */
- memcpy(buf_getwriteptr(ses.decryptreadbuf, blocksize),
- buf_getptr(ses.readbuf, blocksize),
- blocksize);
- } else {
- /* decrypt it */
- if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize),
- buf_getwriteptr(ses.decryptreadbuf,blocksize),
- blocksize,
- &ses.keys->recv_symmetric_struct) != CRYPT_OK) {
- dropbear_exit("error decrypting");
- }
+ if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
+ buf_getwriteptr(ses.readbuf, blocksize),
+ blocksize,
+ &ses.keys->recv.cipher_state) != CRYPT_OK) {
+ dropbear_exit("error decrypting");
}
- buf_setlen(ses.decryptreadbuf, blocksize);
- len = buf_getint(ses.decryptreadbuf) + 4 + macsize;
+ len = buf_getint(ses.readbuf) + 4 + macsize;
+
+ TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize))
- buf_setpos(ses.readbuf, blocksize);
/* check packet length */
if ((len > RECV_MAX_PACKET_LEN) ||
@@ -220,9 +214,12 @@ static void read_packet_init() {
dropbear_exit("bad packet size %d", len);
}
- buf_resize(ses.readbuf, len);
+ if (len > ses.readbuf->size) {
+ buf_resize(ses.readbuf, len);
+ }
buf_setlen(ses.readbuf, len);
-
+ buf_setpos(ses.readbuf, blocksize);
+ return DROPBEAR_SUCCESS;
}
/* handle the received packet */
@@ -234,77 +231,58 @@ void decrypt_packet() {
unsigned int len;
TRACE(("enter decrypt_packet"))
- blocksize = ses.keys->recv_algo_crypt->blocksize;
- macsize = ses.keys->recv_algo_mac->hashsize;
+ blocksize = ses.keys->recv.algo_crypt->blocksize;
+ macsize = ses.keys->recv.algo_mac->hashsize;
ses.kexstate.datarecv += ses.readbuf->len;
/* we've already decrypted the first blocksize in read_packet_init */
buf_setpos(ses.readbuf, blocksize);
- buf_resize(ses.decryptreadbuf, ses.readbuf->len - macsize);
- buf_setlen(ses.decryptreadbuf, ses.decryptreadbuf->size);
- buf_setpos(ses.decryptreadbuf, blocksize);
-
- /* decrypt if encryption is set, memcpy otherwise */
- if (ses.keys->recv_algo_crypt->cipherdesc == NULL) {
- /* copy it */
- len = ses.readbuf->len - macsize - blocksize;
- memcpy(buf_getwriteptr(ses.decryptreadbuf, len),
- buf_getptr(ses.readbuf, len), len);
- } else {
- /* decrypt */
- while (ses.readbuf->pos < ses.readbuf->len - macsize) {
- if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize),
- buf_getwriteptr(ses.decryptreadbuf, blocksize),
- blocksize,
- &ses.keys->recv_symmetric_struct) != CRYPT_OK) {
- dropbear_exit("error decrypting");
- }
- buf_incrpos(ses.readbuf, blocksize);
- buf_incrwritepos(ses.decryptreadbuf, blocksize);
- }
+ /* decrypt it in-place */
+ len = ses.readbuf->len - macsize - ses.readbuf->pos;
+ if (ses.keys->recv.crypt_mode->decrypt(
+ buf_getptr(ses.readbuf, len),
+ buf_getwriteptr(ses.readbuf, len),
+ len,
+ &ses.keys->recv.cipher_state) != CRYPT_OK) {
+ dropbear_exit("error decrypting");
}
+ buf_incrpos(ses.readbuf, len);
/* check the hmac */
- buf_setpos(ses.readbuf, ses.readbuf->len - macsize);
- if (checkmac(ses.readbuf, ses.decryptreadbuf) != DROPBEAR_SUCCESS) {
+ if (checkmac() != DROPBEAR_SUCCESS) {
dropbear_exit("Integrity error");
}
- /* readbuf no longer required */
- buf_free(ses.readbuf);
- ses.readbuf = NULL;
-
/* get padding length */
- buf_setpos(ses.decryptreadbuf, PACKET_PADDING_OFF);
- padlen = buf_getbyte(ses.decryptreadbuf);
+ buf_setpos(ses.readbuf, PACKET_PADDING_OFF);
+ padlen = buf_getbyte(ses.readbuf);
/* payload length */
/* - 4 - 1 is for LEN and PADLEN values */
- len = ses.decryptreadbuf->len - padlen - 4 - 1;
+ len = ses.readbuf->len - padlen - 4 - 1;
if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) {
dropbear_exit("bad packet size");
}
- buf_setpos(ses.decryptreadbuf, PACKET_PAYLOAD_OFF);
+ buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
#ifndef DISABLE_ZLIB
- if (ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB) {
+ if (is_compress_recv()) {
/* decompress */
- ses.payload = buf_decompress(ses.decryptreadbuf, len);
-
+ ses.payload = buf_decompress(ses.readbuf, len);
} else
#endif
{
/* copy payload */
ses.payload = buf_new(len);
- memcpy(ses.payload->data, buf_getptr(ses.decryptreadbuf, len), len);
+ memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
buf_incrlen(ses.payload, len);
}
- buf_free(ses.decryptreadbuf);
- ses.decryptreadbuf = NULL;
+ buf_free(ses.readbuf);
+ ses.readbuf = NULL;
buf_setpos(ses.payload, 0);
ses.recvseq++;
@@ -312,49 +290,22 @@ void decrypt_packet() {
TRACE(("leave decrypt_packet"))
}
-/* Checks the mac in hashbuf, for the data in readbuf.
+/* Checks the mac at the end of a decrypted readbuf.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
-static int checkmac(buffer* macbuf, buffer* sourcebuf) {
-
- unsigned int macsize;
- hmac_state hmac;
- unsigned char tempbuf[MAX_MAC_LEN];
- unsigned long bufsize;
- unsigned int len;
-
- macsize = ses.keys->recv_algo_mac->hashsize;
- if (macsize == 0) {
- return DROPBEAR_SUCCESS;
- }
+static int checkmac() {
- /* calculate the mac */
- if (hmac_init(&hmac,
- find_hash(ses.keys->recv_algo_mac->hashdesc->name),
- ses.keys->recvmackey,
- ses.keys->recv_algo_mac->keysize)
- != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
+ unsigned char mac_bytes[MAX_MAC_LEN];
+ unsigned int mac_size, contents_len;
- /* sequence number */
- STORE32H(ses.recvseq, tempbuf);
- if (hmac_process(&hmac, tempbuf, 4) != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
+ mac_size = ses.keys->trans.algo_mac->hashsize;
+ contents_len = ses.readbuf->len - mac_size;
- buf_setpos(sourcebuf, 0);
- len = sourcebuf->len;
- if (hmac_process(&hmac, buf_getptr(sourcebuf, len), len) != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
-
- bufsize = sizeof(tempbuf);
- if (hmac_done(&hmac, tempbuf, &bufsize) != CRYPT_OK) {
- dropbear_exit("HMAC error");
- }
+ buf_setpos(ses.readbuf, 0);
+ make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
/* compare the hash */
- if (memcmp(tempbuf, buf_getptr(macbuf, macsize), macsize) != 0) {
+ buf_setpos(ses.readbuf, contents_len);
+ if (memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
return DROPBEAR_FAILURE;
} else {
return DROPBEAR_SUCCESS;
@@ -369,7 +320,7 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
buffer * ret;
z_streamp zstream;
- zstream = ses.keys->recv_zstream;
+ zstream = ses.keys->recv.zstream;
ret = buf_new(len);
zstream->avail_in = len;
@@ -465,10 +416,12 @@ void maybe_flush_reply_queue() {
void encrypt_packet() {
unsigned char padlen;
- unsigned char blocksize, macsize;
- buffer * writebuf; /* the packet which will go on the wire */
- buffer * clearwritebuf; /* unencrypted, possibly compressed */
+ unsigned char blocksize, mac_size;
+ buffer * writebuf; /* the packet which will go on the wire. This is
+ encrypted in-place. */
unsigned char type;
+ unsigned int len, encrypt_buf_size;
+ unsigned char mac_bytes[MAX_MAC_LEN];
type = ses.writepayload->data[0];
TRACE(("enter encrypt_packet()"))
@@ -482,33 +435,36 @@ void encrypt_packet() {
return;
}
- blocksize = ses.keys->trans_algo_crypt->blocksize;
- macsize = ses.keys->trans_algo_mac->hashsize;
+ blocksize = ses.keys->trans.algo_crypt->blocksize;
+ mac_size = ses.keys->trans.algo_mac->hashsize;
/* Encrypted packet len is payload+5, then worst case is if we are 3 away
* from a blocksize multiple. In which case we need to pad to the
* multiple, then add another blocksize (or MIN_PACKET_LEN) */
- clearwritebuf = buf_new((ses.writepayload->len+4+1) + MIN_PACKET_LEN + 3
+ encrypt_buf_size = (ses.writepayload->len+4+1) + MIN_PACKET_LEN + 3;
+ /* add space for the MAC at the end */
+ encrypt_buf_size += mac_size;
+
#ifndef DISABLE_ZLIB
- + ZLIB_COMPRESS_INCR /* bit of a kludge, but we can't know len*/
+ encrypt_buf_size += ZLIB_COMPRESS_INCR; /* bit of a kludge, but we can't know len*/
#endif
- );
- buf_setlen(clearwritebuf, PACKET_PAYLOAD_OFF);
- buf_setpos(clearwritebuf, PACKET_PAYLOAD_OFF);
+ writebuf = buf_new(encrypt_buf_size);
+ buf_setlen(writebuf, PACKET_PAYLOAD_OFF);
+ buf_setpos(writebuf, PACKET_PAYLOAD_OFF);
buf_setpos(ses.writepayload, 0);
#ifndef DISABLE_ZLIB
/* compression */
- if (ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB) {
- buf_compress(clearwritebuf, ses.writepayload, ses.writepayload->len);
+ if (is_compress_trans()) {
+ buf_compress(writebuf, ses.writepayload, ses.writepayload->len);
} else
#endif
{
- memcpy(buf_getwriteptr(clearwritebuf, ses.writepayload->len),
+ memcpy(buf_getwriteptr(writebuf, ses.writepayload->len),
buf_getptr(ses.writepayload, ses.writepayload->len),
ses.writepayload->len);
- buf_incrwritepos(clearwritebuf, ses.writepayload->len);
+ buf_incrwritepos(writebuf, ses.writepayload->len);
}
/* finished with payload */
@@ -517,60 +473,45 @@ void encrypt_packet() {
/* length of padding - packet length must be a multiple of blocksize,
* with a minimum of 4 bytes of padding */
- padlen = blocksize - (clearwritebuf->len) % blocksize;
+ padlen = blocksize - (writebuf->len) % blocksize;
if (padlen < 4) {
padlen += blocksize;
}
/* check for min packet length */
- if (clearwritebuf->len + padlen < MIN_PACKET_LEN) {
+ if (writebuf->len + padlen < MIN_PACKET_LEN) {
padlen += blocksize;
}
- buf_setpos(clearwritebuf, 0);
+ buf_setpos(writebuf, 0);
/* packet length excluding the packetlength uint32 */
- buf_putint(clearwritebuf, clearwritebuf->len + padlen - 4);
+ buf_putint(writebuf, writebuf->len + padlen - 4);
/* padding len */
- buf_putbyte(clearwritebuf, padlen);
+ buf_putbyte(writebuf, padlen);
/* actual padding */
- buf_setpos(clearwritebuf, clearwritebuf->len);
- buf_incrlen(clearwritebuf, padlen);
- genrandom(buf_getptr(clearwritebuf, padlen), padlen);
-
- /* do the actual encryption */
- buf_setpos(clearwritebuf, 0);
- /* create a new writebuffer, this is freed when it has been put on the
- * wire by writepacket() */
- writebuf = buf_new(clearwritebuf->len + macsize);
-
- if (ses.keys->trans_algo_crypt->cipherdesc == NULL) {
- /* copy it */
- memcpy(buf_getwriteptr(writebuf, clearwritebuf->len),
- buf_getptr(clearwritebuf, clearwritebuf->len),
- clearwritebuf->len);
- buf_incrwritepos(writebuf, clearwritebuf->len);
- } else {
- /* encrypt it */
- while (clearwritebuf->pos < clearwritebuf->len) {
- if (cbc_encrypt(buf_getptr(clearwritebuf, blocksize),
- buf_getwriteptr(writebuf, blocksize),
- blocksize,
- &ses.keys->trans_symmetric_struct) != CRYPT_OK) {
- dropbear_exit("error encrypting");
- }
- buf_incrpos(clearwritebuf, blocksize);
- buf_incrwritepos(writebuf, blocksize);
- }
- }
+ buf_setpos(writebuf, writebuf->len);
+ buf_incrlen(writebuf, padlen);
+ genrandom(buf_getptr(writebuf, padlen), padlen);
- /* now add a hmac and we're done */
- writemac(writebuf, clearwritebuf);
+ make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
- /* clearwritebuf is finished with */
- buf_free(clearwritebuf);
- clearwritebuf = NULL;
+ /* do the actual encryption, in-place */
+ buf_setpos(writebuf, 0);
+ /* encrypt it in-place*/
+ len = writebuf->len;
+ if (ses.keys->trans.crypt_mode->encrypt(
+ buf_getptr(writebuf, len),
+ buf_getwriteptr(writebuf, len),
+ len,
+ &ses.keys->trans.cipher_state) != CRYPT_OK) {
+ dropbear_exit("error encrypting");
+ }
+ buf_incrpos(writebuf, len);
- /* enqueue the packet for sending */
+ /* stick the MAC on it */
+ buf_putbytes(writebuf, mac_bytes, mac_size);
+
+ /* enqueue the packet for sending. It will get freed after transmission. */
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, (void*)writebuf);
@@ -583,47 +524,43 @@ void encrypt_packet() {
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
-static void writemac(buffer * outputbuffer, buffer * clearwritebuf) {
-
- unsigned int macsize;
+/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
+static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
+ buffer * clear_buf, unsigned int clear_len,
+ unsigned char *output_mac) {
unsigned char seqbuf[4];
- unsigned char tempbuf[MAX_MAC_LEN];
unsigned long bufsize;
hmac_state hmac;
TRACE(("enter writemac"))
- macsize = ses.keys->trans_algo_mac->hashsize;
- if (macsize > 0) {
+ if (key_state->algo_mac->hashsize > 0) {
/* calculate the mac */
if (hmac_init(&hmac,
- find_hash(ses.keys->trans_algo_mac->hashdesc->name),
- ses.keys->transmackey,
- ses.keys->trans_algo_mac->keysize) != CRYPT_OK) {
+ key_state->hash_index,
+ key_state->mackey,
+ key_state->algo_mac->keysize) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
/* sequence number */
- STORE32H(ses.transseq, seqbuf);
+ STORE32H(seqno, seqbuf);
if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
/* the actual contents */
- buf_setpos(clearwritebuf, 0);
+ buf_setpos(clear_buf, 0);
if (hmac_process(&hmac,
- buf_getptr(clearwritebuf,
- clearwritebuf->len),
- clearwritebuf->len) != CRYPT_OK) {
+ buf_getptr(clear_buf, clear_len),
+ clear_len) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
- bufsize = sizeof(tempbuf);
- if (hmac_done(&hmac, tempbuf, &bufsize)
- != CRYPT_OK) {
+ bufsize = MAX_MAC_LEN;
+ if (hmac_done(&hmac, output_mac, &bufsize) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
- buf_putbytes(outputbuffer, tempbuf, macsize);
}
TRACE(("leave writemac"))
}
@@ -640,29 +577,29 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
while (1) {
- ses.keys->trans_zstream->avail_in = endpos - src->pos;
- ses.keys->trans_zstream->next_in =
- buf_getptr(src, ses.keys->trans_zstream->avail_in);
+ ses.keys->trans.zstream->avail_in = endpos - src->pos;
+ ses.keys->trans.zstream->next_in =
+ buf_getptr(src, ses.keys->trans.zstream->avail_in);
- ses.keys->trans_zstream->avail_out = dest->size - dest->pos;
- ses.keys->trans_zstream->next_out =
- buf_getwriteptr(dest, ses.keys->trans_zstream->avail_out);
+ ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
+ ses.keys->trans.zstream->next_out =
+ buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
- result = deflate(ses.keys->trans_zstream, Z_SYNC_FLUSH);
+ result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
- buf_setpos(src, endpos - ses.keys->trans_zstream->avail_in);
- buf_setlen(dest, dest->size - ses.keys->trans_zstream->avail_out);
+ buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
+ buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
buf_setpos(dest, dest->len);
if (result != Z_OK) {
dropbear_exit("zlib error");
}
- if (ses.keys->trans_zstream->avail_in == 0) {
+ if (ses.keys->trans.zstream->avail_in == 0) {
break;
}
- dropbear_assert(ses.keys->trans_zstream->avail_out == 0);
+ dropbear_assert(ses.keys->trans.zstream->avail_out == 0);
/* the buffer has been filled, we must extend. This only happens in
* unusual circumstances where the data grows in size after deflate(),
diff --git a/packet.h b/packet.h
index 8fadeb3..4645b14 100644
--- a/packet.h
+++ b/packet.h
@@ -44,6 +44,6 @@ typedef struct PacketType {
#define PACKET_PADDING_OFF 4
#define PACKET_PAYLOAD_OFF 5
-#define INIT_READBUF 200
+#define INIT_READBUF 128
#endif /* _PACKET_H_ */
diff --git a/process-packet.c b/process-packet.c
index d96c1cb..fe4a543 100644
--- a/process-packet.c
+++ b/process-packet.c
@@ -70,6 +70,7 @@ void process_packet() {
dropbear_close("Disconnect received");
}
+ ses.last_packet_time = time(NULL);
/* This applies for KEX, where the spec says the next packet MUST be
* NEWKEYS */
diff --git a/runopts.h b/runopts.h
index 6cbdd26..bc35435 100644
--- a/runopts.h
+++ b/runopts.h
@@ -38,6 +38,7 @@ typedef struct runopts {
#endif
unsigned int recv_window;
unsigned int keepalive_secs;
+ unsigned int idle_timeout_secs;
} runopts;
diff --git a/scp.c b/scp.c
index 1d788c9..da64dd1 100644
--- a/scp.c
+++ b/scp.c
@@ -130,13 +130,22 @@ do_local_cmd(arglist *a)
fprintf(stderr, " %s", a->list[i]);
fprintf(stderr, "\n");
}
- if ((pid = fork()) == -1)
+#ifdef __uClinux__
+ pid = vfork();
+#else
+ pid = fork();
+#endif /* __uClinux__ */
+ if (pid == -1)
fatal("do_local_cmd: fork: %s", strerror(errno));
if (pid == 0) {
execvp(a->list[0], a->list);
perror(a->list[0]);
+#ifdef __uClinux__
+ _exit(1);
+#else
exit(1);
+#endif /* __uClinux__ */
}
do_cmd_pid = pid;
@@ -225,7 +234,11 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
execvp(ssh_program, args.list);
perror(ssh_program);
+#ifndef __uClinux__
exit(1);
+#else
+ _exit(1);
+#endif /* __uClinux__ */
} else if (do_cmd_pid == -1) {
fatal("fork: %s", strerror(errno));
}
diff --git a/session.h b/session.h
index b63a258..5a4569e 100644
--- a/session.h
+++ b/session.h
@@ -60,28 +60,36 @@ void cli_session(int sock_in, int sock_out, char *remotehost);
void cli_session_cleanup();
void cleantext(unsigned char* dirtytext);
+/* crypto parameters that are stored individually for transmit and receive */
+struct key_context_directional {
+ const struct dropbear_cipher *algo_crypt; /* NULL for none */
+ const struct dropbear_cipher_mode *crypt_mode;
+ const struct dropbear_hash *algo_mac; /* NULL for none */
+ int hash_index; /* lookup for libtomcrypt */
+ char algo_comp; /* compression */
+#ifndef DISABLE_ZLIB
+ z_streamp zstream;
+#endif
+ /* actual keys */
+ union {
+ symmetric_CBC cbc;
+#ifdef DROPBEAR_ENABLE_CTR_MODE
+ symmetric_CTR ctr;
+#endif
+ } cipher_state;
+ unsigned char mackey[MAX_MAC_KEY];
+};
+
struct key_context {
- const struct dropbear_cipher *recv_algo_crypt; /* NULL for none */
- const struct dropbear_cipher *trans_algo_crypt; /* NULL for none */
- const struct dropbear_hash *recv_algo_mac; /* NULL for none */
- const struct dropbear_hash *trans_algo_mac; /* NULL for none */
+ struct key_context_directional recv;
+ struct key_context_directional trans;
+
char algo_kex;
char algo_hostkey;
- char recv_algo_comp; /* compression */
- char trans_algo_comp;
-#ifndef DISABLE_ZLIB
- z_streamp recv_zstream;
- z_streamp trans_zstream;
-#endif
-
- /* actual keys */
- symmetric_CBC recv_symmetric_struct;
- symmetric_CBC trans_symmetric_struct;
- unsigned char recvmackey[MAX_MAC_KEY];
- unsigned char transmackey[MAX_MAC_KEY];
-
+ int allow_compress; /* whether compression has started (useful in
+ zlib@openssh.com delayed compression case) */
};
struct packetlist;
@@ -114,8 +122,7 @@ struct sshsession {
throughout the code, as handlers fill out this
buffer with the packet to send. */
struct Queue writequeue; /* A queue of encrypted packets to send */
- buffer *readbuf; /* Encrypted */
- buffer *decryptreadbuf; /* Post-decryption */
+ buffer *readbuf; /* From the wire, decrypted in-place */
buffer *payload; /* Post-decompression, the actual SSH packet */
unsigned int transseq, recvseq; /* Sequence IDs */
@@ -134,12 +141,16 @@ struct sshsession {
unsigned char lastpacket; /* What the last received packet type was */
- int signal_pipe[2]; /* stores endpoints of a self-pipe used for
+ int signal_pipe[2]; /* stores endpoints of a self-pipe used for
race-free signal handling */
- time_t last_packet_time; /* time of the last packet transmission, for
+ time_t last_trx_packet_time; /* time of the last packet transmission, for
keepalive purposes */
+ time_t last_packet_time; /* time of the last packet transmission or receive, for
+ idle timeout purposes */
+
+
/* KEX/encryption related */
struct KEXState kexstate;
struct key_context *keys;
diff --git a/svr-auth.c b/svr-auth.c
index 4adf809..5da0aa7 100644
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -368,6 +368,8 @@ void send_msg_userauth_success() {
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_SUCCESS);
encrypt_packet();
+ /* authdone must be set after encrypt_packet() for
+ * delayed-zlib mode */
ses.authstate.authdone = 1;
ses.connect_time = 0;
diff --git a/svr-authpubkeyoptions.c b/svr-authpubkeyoptions.c
index 8a92d62..13a179d 100644
--- a/svr-authpubkeyoptions.c
+++ b/svr-authpubkeyoptions.c
@@ -105,7 +105,7 @@ void svr_pubkey_options_cleanup() {
/* helper for svr_add_pubkey_options. returns DROPBEAR_SUCCESS if the option is matched,
and increments the options_buf */
static int match_option(buffer *options_buf, const char *opt_name) {
- const int len = strlen(opt_name);
+ const unsigned int len = strlen(opt_name);
if (options_buf->len - options_buf->pos < len) {
return DROPBEAR_FAILURE;
}
diff --git a/svr-chansession.c b/svr-chansession.c
index 9b2a412..23dad8c 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -663,11 +663,11 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
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 */
- int i;
for (i = 0; i < svr_ses.childpidsize; i++) {
if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) {
TRACE(("found match for lastexitpid"))
@@ -878,6 +878,7 @@ static void execchild(void *user_data) {
addnewvar("LOGNAME", ses.authstate.pw_name);
addnewvar("HOME", ses.authstate.pw_dir);
addnewvar("SHELL", get_user_shell());
+ addnewvar("PATH", DEFAULT_PATH);
if (chansess->term != NULL) {
addnewvar("TERM", chansess->term);
}
diff --git a/svr-main.c b/svr-main.c
index 8d57084..45ea4be 100644
--- a/svr-main.c
+++ b/svr-main.c
@@ -133,7 +133,7 @@ void main_noinetd() {
for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
childpipes[i] = -1;
}
- bzero(preauth_addrs, sizeof(preauth_addrs));
+ memset(preauth_addrs, 0x0, sizeof(preauth_addrs));
/* Set up the listening sockets */
listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock);
diff --git a/svr-runopts.c b/svr-runopts.c
index c8b6585..4f1355a 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -82,8 +82,9 @@ static void printhelp(const char * progname) {
#endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
+ "-I <idle_timeout> (0 is never, default %d)\n"
#ifdef DEBUG_TRACE
- "-v verbose\n"
+ "-v verbose (compiled with DEBUG_TRACE)\n"
#endif
,DROPBEAR_VERSION, progname,
#ifdef DROPBEAR_DSS
@@ -93,7 +94,7 @@ static void printhelp(const char * progname) {
RSA_PRIV_FILENAME,
#endif
DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
- DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE);
+ DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
}
void svr_getopts(int argc, char ** argv) {
@@ -103,6 +104,7 @@ void svr_getopts(int argc, char ** argv) {
int nextisport = 0;
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
+ char* idle_timeout_arg = NULL;
/* see printhelp() for options */
svr_opts.rsakeyfile = NULL;
@@ -134,7 +136,8 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.usingsyslog = 1;
#endif
opts.recv_window = DEFAULT_RECV_WINDOW;
- opts.keepalive_secs = DEFAULT_KEEPALIVE;
+ opts.keepalive_secs = DEFAULT_KEEPALIVE;
+ opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
#ifdef ENABLE_SVR_REMOTETCPFWD
opts.listen_fwd_all = 0;
@@ -218,6 +221,9 @@ void svr_getopts(int argc, char ** argv) {
case 'K':
next = &keepalive_arg;
break;
+ case 'I':
+ next = &idle_timeout_arg;
+ break;
#if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
case 's':
svr_opts.noauthpass = 1;
@@ -253,7 +259,7 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS);
svr_opts.portcount = 1;
}
-
+
if (svr_opts.dsskeyfile == NULL) {
svr_opts.dsskeyfile = DSS_PRIV_FILENAME;
}
@@ -294,6 +300,12 @@ void svr_getopts(int argc, char ** argv) {
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
}
}
+
+ if (idle_timeout_arg) {
+ if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
+ dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
+ }
+ }
}
static void addportandaddress(char* spec) {
diff --git a/sysoptions.h b/sysoptions.h
index 6b17151..2de1184 100644
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -4,7 +4,7 @@
*******************************************************************/
#ifndef DROPBEAR_VERSION
-#define DROPBEAR_VERSION "0.51"
+#define DROPBEAR_VERSION "0.52"
#endif
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
@@ -68,6 +68,7 @@
#define DROPBEAR_COMP_NONE 0
#define DROPBEAR_COMP_ZLIB 1
+#define DROPBEAR_COMP_ZLIB_DELAY 2
/* Required for pubkey auth */
#if defined(ENABLE_SVR_PUBKEY_AUTH) || defined(DROPBEAR_CLIENT)
@@ -133,12 +134,12 @@
accept for keyb-interactive
auth */
-#if defined(DROPBEAR_AES256_CBC) || defined(DROPBEAR_AES128_CBC)
-#define DROPBEAR_AES_CBC
+#if defined(DROPBEAR_AES256) || defined(DROPBEAR_AES128)
+#define DROPBEAR_AES
#endif
-#if defined(DROPBEAR_TWOFISH256_CBC) || defined(DROPBEAR_TWOFISH128_CBC)
-#define DROPBEAR_TWOFISH_CBC
+#if defined(DROPBEAR_TWOFISH256) || defined(DROPBEAR_TWOFISH128)
+#define DROPBEAR_TWOFISH
#endif
#ifndef ENABLE_X11FWD
@@ -201,5 +202,8 @@
#define IS_DROPBEAR_CLIENT 1
#else
-#error You must compiled with either DROPBEAR_CLIENT or DROPBEAR_SERVER selected
+/* Just building key utils? */
+#define IS_DROPBEAR_SERVER 0
+#define IS_DROPBEAR_CLIENT 0
+
#endif
diff --git a/tcpfwd.h b/tcpfwd.h
index f50515c..251612e 100644
--- a/tcpfwd.h
+++ b/tcpfwd.h
@@ -49,6 +49,8 @@ struct TCPFwdList {
const unsigned char* connectaddr;
unsigned int connectport;
unsigned int listenport;
+ unsigned int have_reply; /* is set to 1 after a reply has been received
+ when setting up the forwarding */
struct TCPFwdList * next;
};
@@ -62,6 +64,8 @@ extern const struct ChanType svr_chan_tcpdirect;
void setup_localtcp();
void setup_remotetcp();
extern const struct ChanType cli_chan_tcpremote;
+void cli_recv_msg_request_success();
+void cli_recv_msg_request_failure();
/* Common */
int listen_tcpfwd(struct TCPListener* tcpinfo);