The unified diff between revisions [f452aa06..] and [a4cab2b4..] is displayed below. It can also be downloaded as a raw diff.
#
#
# add_file "cli-authinteract.c"
# content [001567a2e62e0f5f87d73463ab4f6e1f85415f35]
#
# patch "INSTALL"
# from [9efe85a4525184ca98a93c02802a1d42a24f2bcc]
# to [52b3298eab1a71cead9d4b3364a2ec9090262bf2]
#
# patch "Makefile.in"
# from [4be8bcfc6c1a68ca515d55ad95fa09cb6cdae56f]
# to [18432081a78218026941c91a605bf3101dda141a]
#
# patch "auth.h"
# from [aac1a55d01be93e35ab5b0281b9760f8c8ec79d1]
# to [84e61bd4fb2b09bcc8e5bef98e4d5c71fde907a2]
#
# patch "buffer.c"
# from [2fe54eba701ee5c354f265c40914f2733519af16]
# to [8818b6d266850c114615e8780d216c588f89d3c1]
#
# patch "channel.h"
# from [f0285633bae6fc082951524deaa3ada0061ebff4]
# to [b72f20eddf4824bdd1280ee7dbe855301813610c]
#
# patch "circbuffer.c"
# from [b56cdc09c658edcbf0fdc60a86c561026e97dd69]
# to [93e513140e4cc4cbde3d3ece44364ea0715e2a4d]
#
# patch "cli-auth.c"
# from [e4689b84510bdf41e8aa2279bfdb8fb31879c0a7]
# to [eb6d2144c4d4b27aaa50b7b1a1f2b879a9c0a06f]
#
# patch "cli-authpasswd.c"
# from [cf039b904bb3b86945491680557f2d3847d5740c]
# to [ac2864b6001ecb7272b258aeee75ed1287d745e2]
#
# patch "cli-chansession.c"
# from [e830bb4828a09f4f5c2094ae43bbc77b3d8a8970]
# to [8250f8508ce081c3facf84f9a8b5cd5caab220e5]
#
# patch "cli-runopts.c"
# from [79955079fc49e1b252055d125874535d52b5914b]
# to [5e702c8f3984796ffec8a22f7032ab2ad64140cd]
#
# patch "cli-session.c"
# from [e088b599dbdbd93930ff21e6bebe7dcbfbf66ed3]
# to [49416025c7fc3883ad9b8975474ad68307b24717]
#
# patch "cli-tcpfwd.c"
# from [d8d52da1d269d157d91e9731508a3b8beba444c2]
# to [3c2b139864eb87c901783d9d9398f3f584674533]
#
# patch "common-algo.c"
# from [37d9d05401ab9d81872628b05045b6437296e78b]
# to [a54999708e3805153b7f6857ce09f86ea3ad41e8]
#
# patch "common-channel.c"
# from [522b3539ac8ac8feb32efd8c3e7a0490e51b29c3]
# to [97ae918fb65d16853d0994b99fa1961d1c47fd32]
#
# patch "common-kex.c"
# from [960bfda8deaa204b5866f14647f3cd86d262d93f]
# to [b06f424fe466a6d3ecfb7072d59457ebb39c8780]
#
# patch "common-session.c"
# from [c141f714affb71abd896785b986c44fdfe98a357]
# to [1264a49e05001b96e621efa4abf6f9e77402ed71]
#
# patch "configure.in"
# from [2b2625caa07530f2fa625a0eee5d6e654f167dba]
# to [efc775ba6fb049596194158e06479c2a29a0e165]
#
# patch "dbclient.1"
# from [aed09b6b3d241203fd11a777e5fae635066d2dfc]
# to [2ae47b2e32dbafef9abf583844711c265e418619]
#
# patch "dbutil.c"
# from [9440c0ae5ca45076f63b0f295585bfaeb82dd57c]
# to [bcd256f4bdc8183dfd6b813375c39af6513b183d]
#
# patch "dbutil.h"
# from [3806a1758a9a15ee7a1e3b75e3a49c0d27a7343a]
# to [76eb992fc016821fd1584982e59abe7ac66c5671]
#
# patch "dropbear.8"
# from [8d1707f168fb2870937ffc24cb85e328328225ce]
# to [01a2e001c0e1dcbaa0105b5914c737744ae5c802]
#
# patch "dss.c"
# from [e72e0ab248024c0d858b55fdd382a414aeb31317]
# to [d58b7df483ca328e4102dbc59fab1cf85494263e]
#
# patch "includes.h"
# from [cb0e389740b51fc33f98b8c29c9f2ffe7cd11bc2]
# to [9baa00e2da012281cecc528405cf06e48b53fda8]
#
# patch "kex.h"
# from [4aedb4c80abfbc1df32da43a4903b34e8cddc56a]
# to [596a833742cc5ab88d3930e46214f19e129347f2]
#
# patch "keyimport.c"
# from [38a61bdea3196db5ff2a57fd389236948142b4ef]
# to [4d6aa56819151b18d6828b1a9b1db0b9864e40b3]
#
# patch "options.h"
# from [22166eca17d24203e474f1d8b26ce95ea45e0166]
# to [562d600e35b6a1ef1ab8d8df1dd61654056bd697]
#
# patch "packet.c"
# from [93ffb969c3097b6fe2c9f50cf80716ca0f209295]
# to [01803cc5860fe470ae70a883d807579b3bd0fc68]
#
# patch "queue.c"
# from [ccb24cf04c2fae9ff0008f7181239fff1e93f82b]
# to [0b2bee6c831b234a3fba77c4ae6d598126a3c07c]
#
# patch "rsa.c"
# from [a5bd0348ccf9497600f633057ec6028e8cf3c329]
# to [af6a357404e3480445b0b2835065a3e4666ee812]
#
# patch "runopts.h"
# from [866a99e2213c6a2602a649a2915471ef4b39770a]
# to [36768f6323c18233529bb202e8876a3dfbc5d5a5]
#
# patch "session.h"
# from [0e62967a248214d43a774911bfa4a0c503f0da17]
# to [029633beee5cd56701332bc0fa563ae201223469]
#
# patch "signkey.c"
# from [0b42ca44158bc9c2057064ddf12aa3ab11fb76b4]
# to [c0ce28d518a22769fdee4e64e6fcd77a9100e61f]
#
# patch "ssh.h"
# from [b63c0c60a29e5dec39b53218d20fe30cfd00a60e]
# to [190af1a6af0c6977129303befae06af9c58e6e07]
#
# patch "svr-authpam.c"
# from [d2e49b9902777338e827e1935b24457b86fce347]
# to [aa255168b81cef1ec80b008a7e98975cfa9600a3]
#
# patch "svr-authpubkey.c"
# from [a659d961ca849841adc5ac41a68f360a135763d5]
# to [6a8b306f446ff4aede63a6d5a72de0b8a15129e4]
#
# patch "svr-chansession.c"
# from [14640c883f2d3f5a07cb5614102eeb7762aa9b79]
# to [8b52f1a622321b7cf4ed3ac6f69e7241d14d324d]
#
# patch "svr-main.c"
# from [956679879949d5e02205ac66872e03986c76fc61]
# to [5c0e59de51df9c03a47947b7dcd100053623bfd3]
#
# patch "svr-runopts.c"
# from [6d28fe6609d584d48c70f1707e7d4f8460513aea]
# to [f68d09f9fe84a764badcdd18a0f69b14e44cb0e8]
#
# patch "svr-tcpfwd.c"
# from [9c0362f8d1c15ce9d702873cc1a2064754d7919b]
# to [bfd47e1ced10186c0d9ce06dca0f0d3694e9c3df]
#
# patch "tcp-accept.c"
# from [85218bbb73f0a9394f0f100aa416a917978318b7]
# to [413de2351e02bf67ef6e78238c449c6a480a2f75]
#
# patch "tcpfwd.h"
# from [e093ea296308000bdf7c4c54f49caf7bf353a47e]
# to [16c1fbd5251921ecc87e704bc2afe2076dd55a4e]
#
============================================================
--- cli-authinteract.c 001567a2e62e0f5f87d73463ab4f6e1f85415f35
+++ cli-authinteract.c 001567a2e62e0f5f87d73463ab4f6e1f85415f35
@@ -0,0 +1,168 @@
+/*
+ * Dropbear SSH
+ *
+ * Copyright (c) 2005 Matt Johnston
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. */
+
+#include "includes.h"
+#include "buffer.h"
+#include "dbutil.h"
+#include "session.h"
+#include "ssh.h"
+#include "runopts.h"
+
+#ifdef ENABLE_CLI_INTERACT_AUTH
+
+static unsigned char* get_response(unsigned char* prompt)
+{
+ FILE* tty = NULL;
+ unsigned char* response = NULL;
+ /* not a password, but a reasonable limit */
+ char buf[DROPBEAR_MAX_CLI_PASS];
+ char* ret = NULL;
+
+ fprintf(stderr, "%s", prompt);
+
+ tty = fopen(_PATH_TTY, "r");
+ if (tty) {
+ ret = fgets(buf, sizeof(buf), tty);
+ fclose(tty);
+ } else {
+ ret = fgets(buf, sizeof(buf), stdin);
+ }
+
+ if (ret == NULL) {
+ response = (unsigned char*)m_strdup("");
+ } else {
+ unsigned int buflen = strlen(buf);
+ /* fgets includes newlines */
+ if (buflen > 0 && buf[buflen-1] == '\n')
+ buf[buflen-1] = '\0';
+ response = (unsigned char*)m_strdup(buf);
+ }
+
+ m_burn(buf, sizeof(buf));
+
+ return response;
+}
+
+void recv_msg_userauth_info_request() {
+
+ unsigned char *name = NULL;
+ unsigned char *instruction = NULL;
+ unsigned int num_prompts = 0;
+ unsigned int i;
+
+ unsigned char *prompt = NULL;
+ unsigned int echo = 0;
+ unsigned char *response = NULL;
+
+ TRACE(("enter recv_msg_recv_userauth_info_request"))
+
+ cli_ses.interact_request_received = 1;
+
+ name = buf_getstring(ses.payload, NULL);
+ instruction = buf_getstring(ses.payload, NULL);
+
+ /* language tag */
+ buf_eatstring(ses.payload);
+
+ num_prompts = buf_getint(ses.payload);
+
+ if (num_prompts >= DROPBEAR_MAX_CLI_INTERACT_PROMPTS) {
+ dropbear_exit("Too many prompts received for keyboard-interactive");
+ }
+
+ /* we'll build the response as we go */
+ CHECKCLEARTOWRITE();
+ buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_INFO_RESPONSE);
+ buf_putint(ses.writepayload, num_prompts);
+
+ if (strlen(name) > 0) {
+ cleantext(name);
+ fprintf(stderr, "%s", name);
+ m_free(name);
+ }
+ if (strlen(instruction) > 0) {
+ cleantext(instruction);
+ fprintf(stderr, "%s", instruction);
+ m_free(instruction);
+ }
+
+ for (i = 0; i < num_prompts; i++) {
+ unsigned int response_len = 0;
+ prompt = buf_getstring(ses.payload, NULL);
+ cleantext(prompt);
+
+ echo = buf_getbool(ses.payload);
+
+ if (!echo) {
+ unsigned char* p = getpass(prompt);
+ response = m_strdup(p);
+ m_burn(p, strlen(p));
+ } else {
+ response = get_response(prompt);
+ }
+
+ response_len = strlen(response);
+ buf_putstring(ses.writepayload, response, response_len);
+ m_burn(response, response_len);
+ m_free(response);
+ }
+
+ encrypt_packet();
+
+
+ TRACE(("leave recv_msg_recv_userauth_info_request"))
+}
+
+void cli_auth_interactive() {
+
+ TRACE(("enter cli_auth_interactive"))
+ CHECKCLEARTOWRITE();
+
+ buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
+
+ /* username */
+ buf_putstring(ses.writepayload, cli_opts.username,
+ strlen(cli_opts.username));
+
+ /* service name */
+ buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
+ SSH_SERVICE_CONNECTION_LEN);
+
+ /* method */
+ buf_putstring(ses.writepayload, AUTH_METHOD_INTERACT,
+ AUTH_METHOD_INTERACT_LEN);
+
+ /* empty language tag */
+ buf_putstring(ses.writepayload, "", 0);
+
+ /* empty submethods */
+ buf_putstring(ses.writepayload, "", 0);
+
+ encrypt_packet();
+ cli_ses.interact_request_received = 0;
+
+ TRACE(("leave cli_auth_interactive"))
+
+}
+#endif /* ENABLE_CLI_INTERACT_AUTH */
============================================================
--- INSTALL 9efe85a4525184ca98a93c02802a1d42a24f2bcc
+++ INSTALL 52b3298eab1a71cead9d4b3364a2ec9090262bf2
@@ -28,6 +28,11 @@ Binaries can be strippd with "make strip
============================================================================
+If you're compiling for a 386-class CPU, you will probably need to add
+CFLAGS=-DLTC_NO_BSWAP so that libtomcrypt doesn't use 486+ instructions.
+
+============================================================================
+
Compiling with uClibc:
Firstly, make sure you have at least uclibc 0.9.17, as getusershell() in prior
============================================================
--- Makefile.in 4be8bcfc6c1a68ca515d55ad95fa09cb6cdae56f
+++ Makefile.in 18432081a78218026941c91a605bf3101dda141a
@@ -29,7 +29,7 @@ CLIOBJS=cli-algo.o cli-main.o cli-auth.o
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 \
- cli-authpubkey.o cli-tcpfwd.o cli-channel.o
+ cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
============================================================
--- auth.h aac1a55d01be93e35ab5b0281b9760f8c8ec79d1
+++ auth.h 84e61bd4fb2b09bcc8e5bef98e4d5c71fde907a2
@@ -41,29 +41,37 @@ void recv_msg_userauth_success();
/* Client functions */
void recv_msg_userauth_failure();
void recv_msg_userauth_success();
+void recv_msg_userauth_specific_60();
void recv_msg_userauth_pk_ok();
+void recv_msg_userauth_info_request();
void cli_get_user();
void cli_auth_getmethods();
void cli_auth_try();
void recv_msg_userauth_banner();
void cli_pubkeyfail();
-int cli_auth_password();
+void cli_auth_password();
int cli_auth_pubkey();
+void cli_auth_interactive();
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
-#define AUTH_TYPE_PUBKEY 1 << 0
-#define AUTH_TYPE_PASSWORD 1 << 1
+#define AUTH_TYPE_NONE 1
+#define AUTH_TYPE_PUBKEY 1 << 1
+#define AUTH_TYPE_PASSWORD 1 << 2
+#define AUTH_TYPE_INTERACT 1 << 3
-/* auth types, "none" means we should return list of acceptable types */
-#define AUTH_METHOD_NONE "none"
+#define AUTH_METHOD_NONE "none"
#define AUTH_METHOD_NONE_LEN 4
#define AUTH_METHOD_PUBKEY "publickey"
#define AUTH_METHOD_PUBKEY_LEN 9
#define AUTH_METHOD_PASSWORD "password"
#define AUTH_METHOD_PASSWORD_LEN 8
+#define AUTH_METHOD_INTERACT "keyboard-interactive"
+#define AUTH_METHOD_INTERACT_LEN 20
+
+
/* This structure is shared between server and client - it contains
* relatively little extraneous bits when used for the client rather than the
* server */
@@ -77,6 +85,9 @@ struct AuthState {
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for
client and server (though has differing [obvious]
meanings). */
+ unsigned perm_warn : 1; /* Server only, set if bad permissions on
+ ~/.ssh/authorized_keys have already been
+ logged. */
/* These are only used for the server */
char *printableuser; /* stripped of control chars, used for logs etc */
============================================================
--- buffer.c 2fe54eba701ee5c354f265c40914f2733519af16
+++ buffer.c 8818b6d266850c114615e8780d216c588f89d3c1
@@ -153,7 +153,7 @@ unsigned char buf_getbyte(buffer* buf) {
unsigned char buf_getbyte(buffer* buf) {
/* This check is really just ==, but the >= allows us to check for the
- * assert()able case of pos > len, which should _never_ happen. */
+ * bad case of pos > len, which should _never_ happen. */
if (buf->pos >= buf->len) {
dropbear_exit("bad buf_getbyte");
}
@@ -270,7 +270,7 @@ void buf_putmpint(buffer* buf, mp_int *
unsigned int len, pad = 0;
TRACE(("enter buf_putmpint"))
- assert(mp != NULL);
+ dropbear_assert(mp != NULL);
if (SIGN(mp) == MP_NEG) {
dropbear_exit("negative bignum");
============================================================
--- channel.h f0285633bae6fc082951524deaa3ada0061ebff4
+++ channel.h b72f20eddf4824bdd1280ee7dbe855301813610c
@@ -65,9 +65,9 @@ struct Channel {
unsigned int recvdonelen;
unsigned int recvmaxpacket, transmaxpacket;
void* typedata; /* a pointer to type specific data */
- int infd; /* data to send over the wire */
- int outfd; /* data for consumption, what was in writebuf */
- int errfd; /* used like infd or errfd, depending if it's client or server.
+ int writefd; /* read from wire, written to insecure side */
+ int readfd; /* read from insecure size, written to wire */
+ int errfd; /* used like writefd or readfd, depending if it's client or server.
Doesn't exactly belong here, but is cleaner here */
circbuffer *writebuf; /* data from the wire, for local consumption */
circbuffer *extrabuf; /* extended-data for the program - used like writebuf
@@ -81,6 +81,10 @@ struct Channel {
int initconn; /* used for TCP forwarding, whether the channel has been
fully initialised */
+ int await_open; /* flag indicating whether we've sent an open request
+ for this channel (and are awaiting a confirmation
+ or failure). */
+
const struct ChanType* type;
};
@@ -96,7 +100,7 @@ struct ChanType {
};
-void chaninitialise();
+void chaninitialise(const struct ChanType *chantypes[]);
void chancleanup();
void setchannelfds(fd_set *readfd, fd_set *writefd);
void channelio(fd_set *readfd, fd_set *writefd);
============================================================
--- circbuffer.c b56cdc09c658edcbf0fdc60a86c561026e97dd69
+++ circbuffer.c 93e513140e4cc4cbde3d3ece44364ea0715e2a4d
@@ -66,8 +66,8 @@ unsigned int cbuf_readlen(circbuffer *cb
unsigned int cbuf_readlen(circbuffer *cbuf) {
- assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
- assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
+ dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
+ dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == 0) {
TRACE(("cbuf_readlen: unused buffer"))
@@ -83,9 +83,9 @@ unsigned int cbuf_writelen(circbuffer *c
unsigned int cbuf_writelen(circbuffer *cbuf) {
- assert(cbuf->used <= cbuf->size);
- assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
- assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
+ dropbear_assert(cbuf->used <= cbuf->size);
+ dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
+ dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == cbuf->size) {
TRACE(("cbuf_writelen: full buffer"))
@@ -122,7 +122,7 @@ void cbuf_incrwrite(circbuffer *cbuf, un
}
cbuf->used += len;
- assert(cbuf->used <= cbuf->size);
+ dropbear_assert(cbuf->used <= cbuf->size);
cbuf->writepos = (cbuf->writepos + len) % cbuf->size;
}
@@ -132,7 +132,7 @@ void cbuf_incrread(circbuffer *cbuf, uns
dropbear_exit("bad cbuf read");
}
- assert(cbuf->used >= len);
+ dropbear_assert(cbuf->used >= len);
cbuf->used -= len;
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;
}
============================================================
--- cli-auth.c e4689b84510bdf41e8aa2279bfdb8fb31879c0a7
+++ cli-auth.c eb6d2144c4d4b27aaa50b7b1a1f2b879a9c0a06f
@@ -32,7 +32,6 @@
#include "packet.h"
#include "runopts.h"
-
void cli_authinitialise() {
memset(&ses.authstate, 0, sizeof(ses.authstate));
@@ -99,7 +98,41 @@ out:
TRACE(("leave recv_msg_userauth_banner"))
}
+/* This handles the message-specific types which
+ * all have a value of 60. These are
+ * SSH_MSG_USERAUTH_PASSWD_CHANGEREQ,
+ * SSH_MSG_USERAUTH_PK_OK, &
+ * SSH_MSG_USERAUTH_INFO_REQUEST. */
+void recv_msg_userauth_specific_60() {
+#ifdef ENABLE_CLI_PUBKEY_AUTH
+ if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
+ recv_msg_userauth_pk_ok();
+ return;
+ }
+#endif
+
+#ifdef ENABLE_CLI_INTERACT_AUTH
+ if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT) {
+ recv_msg_userauth_info_request();
+ return;
+ }
+#endif
+
+#ifdef ENABLE_CLI_PASSWORD_AUTH
+ if (cli_ses.lastauthtype == AUTH_TYPE_PASSWORD) {
+ /* Eventually there could be proper password-changing
+ * support. However currently few servers seem to
+ * implement it, and password auth is last-resort
+ * regardless - keyboard-interactive is more likely
+ * to be used anyway. */
+ dropbear_close("Your password has expired.");
+ }
+#endif
+
+ dropbear_exit("Unexpected userauth packet");
+}
+
void recv_msg_userauth_failure() {
unsigned char * methods = NULL;
@@ -113,8 +146,7 @@ void recv_msg_userauth_failure() {
if (cli_ses.state != USERAUTH_REQ_SENT) {
/* Perhaps we should be more fatal? */
- TRACE(("But we didn't send a userauth request!!!!!!"))
- return;
+ dropbear_exit("Unexpected userauth failure");
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
@@ -125,6 +157,19 @@ void recv_msg_userauth_failure() {
}
#endif
+#ifdef ENABLE_CLI_INTERACT_AUTH
+ /* If we get a failure message for keyboard interactive without
+ * receiving any request info packet, then we don't bother trying
+ * keyboard interactive again */
+ if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
+ && !cli_ses.interact_request_received) {
+ TRACE(("setting auth_interact_failed = 1"))
+ cli_ses.auth_interact_failed = 1;
+ }
+#endif
+
+ cli_ses.lastauthtype = AUTH_TYPE_NONE;
+
methods = buf_getstring(ses.payload, &methlen);
partial = buf_getbool(ses.payload);
@@ -157,6 +202,12 @@ void recv_msg_userauth_failure() {
ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
}
#endif
+#ifdef ENABLE_CLI_INTERACT_AUTH
+ if (strncmp(AUTH_METHOD_INTERACT, tok,
+ AUTH_METHOD_INTERACT_LEN) == 0) {
+ ses.authstate.authtypes |= AUTH_TYPE_INTERACT;
+ }
+#endif
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (strncmp(AUTH_METHOD_PASSWORD, tok,
AUTH_METHOD_PASSWORD_LEN) == 0) {
@@ -180,6 +231,7 @@ void recv_msg_userauth_success() {
TRACE(("received msg_userauth_success"))
ses.authstate.authdone = 1;
cli_ses.state = USERAUTH_SUCCESS_RCVD;
+ cli_ses.lastauthtype = AUTH_TYPE_NONE;
}
void cli_auth_try() {
@@ -189,7 +241,8 @@ void cli_auth_try() {
CHECKCLEARTOWRITE();
- /* XXX We hardcode that we try a pubkey first */
+ /* Order to try is pubkey, interactive, password.
+ * As soon as "finished" is set for one, we don't do any more. */
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
finished = cli_auth_pubkey();
@@ -197,13 +250,28 @@ void cli_auth_try() {
}
#endif
+#ifdef ENABLE_CLI_INTERACT_AUTH
+ if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) {
+ if (cli_ses.auth_interact_failed) {
+ finished = 0;
+ } else {
+ cli_auth_interactive();
+ cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
+ finished = 1;
+ }
+ }
+#endif
+
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
- finished = cli_auth_password();
+ cli_auth_password();
+ finished = 1;
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
}
#endif
+ TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
+
if (!finished) {
dropbear_exit("No auth methods could be used.");
}
============================================================
--- cli-authpasswd.c cf039b904bb3b86945491680557f2d3847d5740c
+++ cli-authpasswd.c ac2864b6001ecb7272b258aeee75ed1287d745e2
@@ -113,7 +113,7 @@ static char *gui_getpass(const char *pro
}
#endif /* ENABLE_CLI_ASKPASS_HELPER */
-int cli_auth_password() {
+void cli_auth_password() {
char* password = NULL;
@@ -149,7 +149,5 @@ int cli_auth_password() {
m_burn(password, strlen(password));
TRACE(("leave cli_auth_password"))
- return 1; /* Password auth can always be tried */
-
}
#endif /* ENABLE_CLI_PASSWORD_AUTH */
============================================================
--- cli-chansession.c e830bb4828a09f4f5c2094ae43bbc77b3d8a8970
+++ cli-chansession.c 8250f8508ce081c3facf84f9a8b5cd5caab220e5
@@ -340,10 +340,10 @@ static int cli_initchansess(struct Chann
static int cli_initchansess(struct Channel *channel) {
- channel->infd = STDOUT_FILENO;
+ channel->writefd = STDOUT_FILENO;
setnonblocking(STDOUT_FILENO);
- channel->outfd = STDIN_FILENO;
+ channel->readfd = STDIN_FILENO;
setnonblocking(STDIN_FILENO);
channel->errfd = STDERR_FILENO;
============================================================
--- cli-runopts.c 79955079fc49e1b252055d125874535d52b5914b
+++ cli-runopts.c 5e702c8f3984796ffec8a22f7032ab2ad64140cd
@@ -47,6 +47,7 @@ static void printhelp() {
"Usage: %s [options] [user@]host\n"
"Options are:\n"
"-p <remoteport>\n"
+ "-l <username>\n"
"-t Allocate a pty\n"
"-T Don't allocate a pty\n"
#ifdef ENABLE_CLI_PUBKEY_AUTH
@@ -54,11 +55,11 @@ static void printhelp() {
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
"-L <listenport:remotehost:remoteport> Local port forwarding\n"
+ "-g Allow remote hosts to connect to forwarded ports\n"
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
"-R <listenport:remotehost:remoteport> Remote port forwarding\n"
#endif
- "-l <username>\n"
#ifdef DEBUG_TRACE
"-v verbose\n"
#endif
@@ -93,12 +94,11 @@ void cli_getopts(int argc, char ** argv)
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
cli_opts.localfwds = NULL;
+ opts.listen_fwd_all = 0;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
cli_opts.remotefwds = NULL;
#endif
- opts.nolocaltcp = 0;
- opts.noremotetcp = 0;
/* not yet
opts.ipv4 = 1;
opts.ipv6 = 1;
@@ -167,6 +167,9 @@ void cli_getopts(int argc, char ** argv)
case 'L':
nextislocal = 1;
break;
+ case 'g':
+ opts.listen_fwd_all = 1;
+ break;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
case 'R':
============================================================
--- cli-session.c e088b599dbdbd93930ff21e6bebe7dcbfbf66ed3
+++ cli-session.c 49416025c7fc3883ad9b8975474ad68307b24717
@@ -63,9 +63,7 @@ static const packettype cli_packettypes[
{SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation},
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
-#ifdef ENABLE_CLI_PUBKEY_AUTH
- {SSH_MSG_USERAUTH_PK_OK, recv_msg_userauth_pk_ok}, /* client */
-#endif
+ {SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */
{0, 0} /* End */
};
@@ -285,7 +283,8 @@ static void cli_remoteclosed() {
}
/* Operates in-place turning dirty (untrusted potentially containing control
- * characters) text into clean text. */
+ * characters) text into clean text.
+ * Note: this is safe only with ascii - other charsets could have problems. */
void cleantext(unsigned char* dirtytext) {
unsigned int i, j;
============================================================
--- cli-tcpfwd.c d8d52da1d269d157d91e9731508a3b8beba444c2
+++ cli-tcpfwd.c 3c2b139864eb87c901783d9d9398f3f584674533
@@ -95,10 +95,19 @@ static int cli_localtcp(unsigned int lis
remoteport));
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
+
tcpinfo->sendaddr = m_strdup(remoteaddr);
tcpinfo->sendport = remoteport;
+
+ if (opts.listen_fwd_all) {
+ tcpinfo->listenaddr = m_strdup("");
+ } else {
+ tcpinfo->listenaddr = m_strdup("localhost");
+ }
tcpinfo->listenport = listenport;
+
tcpinfo->chantype = &cli_chan_tcplocal;
+ tcpinfo->tcp_type = direct;
ret = listen_tcpfwd(tcpinfo);
@@ -113,13 +122,20 @@ static void send_msg_global_request_remo
#ifdef ENABLE_CLI_REMOTETCPFWD
static void send_msg_global_request_remotetcp(int port) {
+ char* listenspec = NULL;
TRACE(("enter send_msg_global_request_remotetcp"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
buf_putstring(ses.writepayload, "tcpip-forward", 13);
buf_putbyte(ses.writepayload, 0);
- buf_putstring(ses.writepayload, "0.0.0.0", 7); /* TODO: IPv6? */
+ if (opts.listen_fwd_all) {
+ listenspec = "";
+ } else {
+ listenspec = "localhost";
+ }
+ /* TODO: IPv6? */;
+ buf_putstring(ses.writepayload, listenspec, strlen(listenspec));
buf_putint(ses.writepayload, port);
encrypt_packet();
@@ -186,11 +202,9 @@ static int newtcpforwarded(struct Channe
ses.maxfd = MAX(ses.maxfd, sock);
- /* Note that infd is actually the "outgoing" direction on the
- * tcp connection, vice versa for outfd.
- * We don't set outfd, that will get set after the connection's
+ /* We don't set readfd, that will get set after the connection's
* progress succeeds */
- channel->infd = sock;
+ channel->writefd = sock;
channel->initconn = 1;
err = SSH_OPEN_IN_PROGRESS;
============================================================
--- common-algo.c 37d9d05401ab9d81872628b05045b6437296e78b
+++ common-algo.c a54999708e3805153b7f6857ce09f86ea3ad41e8
@@ -32,20 +32,28 @@
/* Mappings for ciphers, parameters are
{&cipher_desc, keysize, blocksize} */
+#ifdef DROPBEAR_AES256_CBC
+static const struct dropbear_cipher dropbear_aes256 =
+ {&aes_desc, 32, 16};
+#endif
#ifdef DROPBEAR_AES128_CBC
-const struct dropbear_cipher dropbear_aes128 =
+static const struct dropbear_cipher dropbear_aes128 =
{&aes_desc, 16, 16};
#endif
#ifdef DROPBEAR_BLOWFISH_CBC
-const struct dropbear_cipher dropbear_blowfish =
+static const struct dropbear_cipher dropbear_blowfish =
{&blowfish_desc, 16, 8};
#endif
+#ifdef DROPBEAR_TWOFISH256_CBC
+static const struct dropbear_cipher dropbear_twofish256 =
+ {&twofish_desc, 32, 16};
+#endif
#ifdef DROPBEAR_TWOFISH128_CBC
-const struct dropbear_cipher dropbear_twofish128 =
+static const struct dropbear_cipher dropbear_twofish128 =
{&twofish_desc, 16, 16};
#endif
#ifdef DROPBEAR_3DES_CBC
-const struct dropbear_cipher dropbear_3des =
+static const struct dropbear_cipher dropbear_3des =
{&des3_desc, 24, 8};
#endif
@@ -57,11 +65,15 @@ const struct dropbear_cipher dropbear_no
{&hash_desc, keysize, hashsize} */
#ifdef DROPBEAR_SHA1_HMAC
-const struct dropbear_hash dropbear_sha1 =
+static const struct dropbear_hash dropbear_sha1 =
{&sha1_desc, 20, 20};
#endif
+#ifdef DROPBEAR_SHA1_96_HMAC
+static const struct dropbear_hash dropbear_sha1_96 =
+ {&sha1_desc, 20, 12};
+#endif
#ifdef DROPBEAR_MD5_HMAC
-const struct dropbear_hash dropbear_md5 =
+static const struct dropbear_hash dropbear_md5 =
{&md5_desc, 16, 16};
#endif
@@ -75,19 +87,29 @@ algo_type sshciphers[] = {
#ifdef DROPBEAR_AES128_CBC
{"aes128-cbc", 0, (void*)&dropbear_aes128, 1},
#endif
-#ifdef DROPBEAR_BLOWFISH_CBC
- {"blowfish-cbc", 0, (void*)&dropbear_blowfish, 1},
+#ifdef DROPBEAR_3DES_CBC
+ {"3des-cbc", 0, (void*)&dropbear_3des, 1},
#endif
+#ifdef DROPBEAR_AES256_CBC
+ {"aes256-cbc", 0, (void*)&dropbear_aes256, 1},
+#endif
+#ifdef DROPBEAR_TWOFISH256_CBC
+ {"twofish256-cbc", 0, (void*)&dropbear_twofish256, 1},
+ {"twofish-cbc", 0, (void*)&dropbear_twofish256, 1},
+#endif
#ifdef DROPBEAR_TWOFISH128_CBC
- {"twofish-cbc", 0, (void*)&dropbear_twofish128, 1},
+ {"twofish128-cbc", 0, (void*)&dropbear_twofish128, 1},
#endif
-#ifdef DROPBEAR_3DES_CBC
- {"3des-cbc", 0, (void*)&dropbear_3des, 1},
+#ifdef DROPBEAR_BLOWFISH_CBC
+ {"blowfish-cbc", 0, (void*)&dropbear_blowfish, 1},
#endif
{NULL, 0, NULL, 0}
};
algo_type sshhashes[] = {
+#ifdef DROPBEAR_SHA1_96_HMAC
+ {"hmac-sha1-96", 0, (void*)&dropbear_sha1_96, 1},
+#endif
#ifdef DROPBEAR_SHA1_HMAC
{"hmac-sha1", 0, (void*)&dropbear_sha1, 1},
#endif
@@ -98,10 +120,10 @@ algo_type sshcompress[] = {
};
algo_type sshcompress[] = {
- {"none", DROPBEAR_COMP_NONE, NULL, 1},
#ifndef DISABLE_ZLIB
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1},
#endif
+ {"none", DROPBEAR_COMP_NONE, NULL, 1},
{NULL, 0, NULL, 0}
};
@@ -126,13 +148,13 @@ void crypto_init() {
void crypto_init() {
const struct ltc_cipher_descriptor *regciphers[] = {
-#ifdef DROPBEAR_AES128_CBC
+#ifdef DROPBEAR_AES_CBC
&aes_desc,
#endif
#ifdef DROPBEAR_BLOWFISH_CBC
&blowfish_desc,
#endif
-#ifdef DROPBEAR_TWOFISH128_CBC
+#ifdef DROPBEAR_TWOFISH_CBC
&twofish_desc,
#endif
#ifdef DROPBEAR_3DES_CBC
@@ -187,21 +209,20 @@ void buf_put_algolist(buffer * buf, algo
/* Output a comma separated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
- unsigned int pos = 0, i, len;
- char str[50]; /* enough for local algo storage */
+ unsigned int i, len;
+ unsigned int donefirst = 0;
+ buffer *algolist = NULL;
+ algolist = buf_new(100);
for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) {
- /* Avoid generating a trailing comma */
- if (pos)
- str[pos++] = ',';
+ if (donefirst)
+ buf_putbyte(algolist, ',');
+ donefirst = 1;
len = strlen(localalgos[i].name);
- memcpy(&str[pos], localalgos[i].name, len);
- pos += len;
+ buf_putbytes(algolist, localalgos[i].name, len);
}
}
- str[pos]=0;
- /* Debug this */
- TRACE(("buf_put_algolist: %s", str))
- buf_putstring(buf, str, pos);
+ buf_putstring(buf, algolist->data, algolist->len);
+ buf_free(algolist);
}
============================================================
--- common-channel.c 522b3539ac8ac8feb32efd8c3e7a0490e51b29c3
+++ common-channel.c 97ae918fb65d16853d0994b99fa1961d1c47fd32
@@ -52,8 +52,8 @@ static void checkclose(struct Channel *c
static void checkinitdone(struct Channel *channel);
static void checkclose(struct Channel *channel);
-static void closeinfd(struct Channel * channel);
-static void closeoutfd(struct Channel * channel, int fd);
+static void closewritefd(struct Channel * channel);
+static void closereadfd(struct Channel * channel, int fd);
static void closechanfd(struct Channel *channel, int fd, int how);
#define FD_UNINIT (-2)
@@ -143,10 +143,11 @@ struct Channel* newchannel(unsigned int
newchan->transmaxpacket = transmaxpacket;
newchan->typedata = NULL;
- newchan->infd = FD_UNINIT;
- newchan->outfd = FD_UNINIT;
+ newchan->writefd = FD_UNINIT;
+ newchan->readfd = FD_UNINIT;
newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
newchan->initconn = 0;
+ newchan->await_open = 0;
newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
newchan->extrabuf = NULL; /* The user code can set it up */
@@ -176,7 +177,7 @@ struct Channel* getchannel() {
}
/* Iterate through the channels, performing IO if available */
-void channelio(fd_set *readfd, fd_set *writefd) {
+void channelio(fd_set *readfds, fd_set *writefds) {
struct Channel *channel;
unsigned int i;
@@ -191,21 +192,21 @@ void channelio(fd_set *readfd, fd_set *w
continue;
}
- /* read from program/pipe stdout */
- if (channel->outfd >= 0 && FD_ISSET(channel->outfd, readfd)) {
+ /* read data and send it over the wire */
+ if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
send_msg_channel_data(channel, 0, 0);
}
- /* read from program/pipe stderr */
+ /* read stderr data and send it over the wire */
if (channel->extrabuf == NULL &&
- channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) {
+ channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) {
send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR);
}
- /* if we can read from the infd, it might be closed, so we try to
+ /* if we can read from the writefd, it might be closed, so we try to
* see if it has errors */
- if (channel->infd >= 0 && channel->infd != channel->outfd
- && FD_ISSET(channel->infd, readfd)) {
+ if (channel->writefd >= 0 && channel->writefd != channel->readfd
+ && FD_ISSET(channel->writefd, readfds)) {
if (channel->initconn) {
/* Handling for "in progress" connection - this is needed
* to avoid spinning 100% CPU when we connect to a server
@@ -214,25 +215,25 @@ void channelio(fd_set *readfd, fd_set *w
continue; /* Important not to use the channel after
checkinitdone(), as it may be NULL */
}
- ret = write(channel->infd, NULL, 0); /* Fake write */
+ ret = write(channel->writefd, NULL, 0); /* Fake write */
if (ret < 0 && errno != EINTR && errno != EAGAIN) {
- closeinfd(channel);
+ closewritefd(channel);
}
}
/* write to program/pipe stdin */
- if (channel->infd >= 0 && FD_ISSET(channel->infd, writefd)) {
+ if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
if (channel->initconn) {
checkinitdone(channel);
continue; /* Important not to use the channel after
checkinitdone(), as it may be NULL */
}
- writechannel(channel, channel->infd, channel->writebuf);
+ writechannel(channel, channel->writefd, channel->writebuf);
}
/* stderr for client mode */
if (channel->extrabuf != NULL
- && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) {
+ && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
writechannel(channel, channel->errfd, channel->extrabuf);
}
@@ -243,7 +244,7 @@ void channelio(fd_set *readfd, fd_set *w
/* Listeners such as TCP, X11, agent-auth */
#ifdef USING_LISTENERS
- handle_listeners(readfd);
+ handle_listeners(readfds);
#endif
}
@@ -251,8 +252,8 @@ static void checkclose(struct Channel *c
/* do all the EOF/close type stuff checking for a channel */
static void checkclose(struct Channel *channel) {
- TRACE(("checkclose: infd %d, outfd %d, errfd %d, sentclosed %d, recvclosed %d",
- channel->infd, channel->outfd,
+ TRACE(("checkclose: writefd %d, readfd %d, errfd %d, sentclosed %d, recvclosed %d",
+ channel->writefd, channel->readfd,
channel->errfd, channel->sentclosed, channel->recvclosed))
TRACE(("writebuf %d extrabuf %s extrabuf %d",
cbuf_getused(channel->writebuf),
@@ -265,18 +266,18 @@ static void checkclose(struct Channel *c
* if the shell has exited etc */
if (channel->type->checkclose) {
if (channel->type->checkclose(channel)) {
- closeinfd(channel);
+ closewritefd(channel);
}
}
if (!channel->senteof
- && channel->outfd == FD_CLOSED
+ && channel->readfd == FD_CLOSED
&& (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
send_msg_channel_eof(channel);
}
- if (channel->infd == FD_CLOSED
- && channel->outfd == FD_CLOSED
+ if (channel->writefd == FD_CLOSED
+ && channel->readfd == FD_CLOSED
&& (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
send_msg_channel_close(channel);
}
@@ -313,17 +314,17 @@ static void checkinitdone(struct Channel
TRACE(("enter checkinitdone"))
- if (getsockopt(channel->infd, SOL_SOCKET, SO_ERROR, &val, &vallen)
+ if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen)
|| val != 0) {
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, "", "");
- close(channel->infd);
+ close(channel->writefd);
deletechannel(channel);
TRACE(("leave checkinitdone: fail"))
} else {
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
- channel->outfd = channel->infd;
+ channel->readfd = channel->writefd;
channel->initconn = 0;
TRACE(("leave checkinitdone: success"))
}
@@ -385,7 +386,7 @@ static void writechannel(struct Channel*
if (len < 0 && errno != EINTR) {
/* no more to write - we close it even if the fd was stderr, since
* that's a nasty failure too */
- closeinfd(channel);
+ closewritefd(channel);
}
TRACE(("leave writechannel: len <= 0"))
return;
@@ -394,9 +395,9 @@ static void writechannel(struct Channel*
cbuf_incrread(cbuf, len);
channel->recvdonelen += len;
- if (fd == channel->infd && len == maxlen && channel->recveof) {
+ if (fd == channel->writefd && len == maxlen && channel->recveof) {
/* Check if we're closing up */
- closeinfd(channel);
+ closewritefd(channel);
TRACE(("leave writechannel: recveof set"))
return;
}
@@ -409,9 +410,9 @@ static void writechannel(struct Channel*
channel->recvdonelen = 0;
}
- assert(channel->recvwindow <= RECV_MAXWINDOW);
- assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
- assert(channel->extrabuf == NULL ||
+ dropbear_assert(channel->recvwindow <= RECV_MAXWINDOW);
+ dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
+ dropbear_assert(channel->extrabuf == NULL ||
channel->recvwindow <= cbuf_getavail(channel->extrabuf));
@@ -420,7 +421,7 @@ static void writechannel(struct Channel*
/* Set the file descriptors for the main select in session.c
* This avoid channels which don't have any window available, are closed, etc*/
-void setchannelfds(fd_set *readfd, fd_set *writefd) {
+void setchannelfds(fd_set *readfds, fd_set *writefds) {
unsigned int i;
struct Channel * channel;
@@ -435,41 +436,41 @@ void setchannelfds(fd_set *readfd, fd_se
/* Stuff to put over the wire */
if (channel->transwindow > 0) {
- if (channel->outfd >= 0) {
- FD_SET(channel->outfd, readfd);
+ if (channel->readfd >= 0) {
+ FD_SET(channel->readfd, readfds);
}
if (channel->extrabuf == NULL && channel->errfd >= 0) {
- FD_SET(channel->errfd, readfd);
+ FD_SET(channel->errfd, readfds);
}
}
/* For checking FD status (ie closure etc) - we don't actually
- * read data from infd */
- TRACE(("infd = %d, outfd %d, errfd %d, bufused %d",
- channel->infd, channel->outfd,
+ * read data from writefd */
+ TRACE(("writefd = %d, readfd %d, errfd %d, bufused %d",
+ channel->writefd, channel->readfd,
channel->errfd,
cbuf_getused(channel->writebuf) ))
- if (channel->infd >= 0 && channel->infd != channel->outfd) {
- FD_SET(channel->infd, readfd);
+ if (channel->writefd >= 0 && channel->writefd != channel->readfd) {
+ FD_SET(channel->writefd, readfds);
}
/* Stuff from the wire, to local program/shell/user etc */
- if ((channel->infd >= 0 && cbuf_getused(channel->writebuf) > 0 )
+ if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
|| channel->initconn) {
- FD_SET(channel->infd, writefd);
+ FD_SET(channel->writefd, writefds);
}
if (channel->extrabuf != NULL && channel->errfd >= 0
&& cbuf_getused(channel->extrabuf) > 0 ) {
- FD_SET(channel->errfd, writefd);
+ FD_SET(channel->errfd, writefds);
}
} /* foreach channel */
#ifdef USING_LISTENERS
- set_listener_fds(readfd);
+ set_listener_fds(readfds);
#endif
}
@@ -492,7 +493,7 @@ void recv_msg_channel_eof() {
if (cbuf_getused(channel->writebuf) == 0
&& (channel->extrabuf == NULL
|| cbuf_getused(channel->extrabuf) == 0)) {
- closeinfd(channel);
+ closewritefd(channel);
}
TRACE(("leave recv_msg_channel_eof"))
@@ -540,8 +541,8 @@ static void removechannel(struct Channel
/* close the FDs in case they haven't been done
* yet (ie they were shutdown etc */
- close(channel->infd);
- close(channel->outfd);
+ close(channel->writefd);
+ close(channel->readfd);
close(channel->errfd);
channel->typedata = NULL;
@@ -603,14 +604,14 @@ static void send_msg_channel_data(struct
CHECKCLEARTOWRITE();
- assert(!channel->sentclosed);
+ dropbear_assert(!channel->sentclosed);
if (isextended) {
fd = channel->errfd;
} else {
- fd = channel->outfd;
+ fd = channel->readfd;
}
- assert(fd >= 0);
+ dropbear_assert(fd >= 0);
maxlen = MIN(channel->transwindow, channel->transmaxpacket);
/* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and
@@ -630,7 +631,7 @@ static void send_msg_channel_data(struct
if (len <= 0) {
/* on error/eof, send eof */
if (len == 0 || errno != EINTR) {
- closeoutfd(channel, fd);
+ closereadfd(channel, fd);
}
buf_free(buf);
buf = NULL;
@@ -668,7 +669,7 @@ void recv_msg_channel_data() {
dropbear_exit("Unknown channel");
}
- common_recv_msg_channel_data(channel, channel->infd, channel->writebuf);
+ common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf);
}
/* Shared for data and stderr data - when we receive data, put it in a buffer
@@ -688,7 +689,7 @@ void common_recv_msg_channel_data(struct
}
if (fd < 0) {
- dropbear_exit("received data with bad infd");
+ dropbear_exit("received data with bad writefd");
}
datalen = buf_getint(ses.payload);
@@ -718,9 +719,9 @@ void common_recv_msg_channel_data(struct
len -= buflen;
}
- assert(channel->recvwindow >= datalen);
+ dropbear_assert(channel->recvwindow >= datalen);
channel->recvwindow -= datalen;
- assert(channel->recvwindow <= RECV_MAXWINDOW);
+ dropbear_assert(channel->recvwindow <= RECV_MAXWINDOW);
TRACE(("leave recv_msg_channel_data"))
}
@@ -930,9 +931,11 @@ int send_msg_channel_open_init(int fd, c
/* set fd non-blocking */
setnonblocking(fd);
- chan->infd = chan->outfd = fd;
+ chan->writefd = chan->readfd = fd;
ses.maxfd = MAX(ses.maxfd, fd);
+ chan->await_open = 1;
+
/* now open the channel connection */
CHECKCLEARTOWRITE();
@@ -960,6 +963,11 @@ void recv_msg_channel_open_confirmation(
dropbear_exit("Unknown channel");
}
+ if (!channel->await_open) {
+ dropbear_exit("unexpected channel reply");
+ }
+ channel->await_open = 0;
+
channel->remotechan = buf_getint(ses.payload);
channel->transwindow = buf_getint(ses.payload);
channel->transmaxpacket = buf_getint(ses.payload);
@@ -990,26 +998,31 @@ void recv_msg_channel_open_failure() {
dropbear_exit("Unknown channel");
}
+ if (!channel->await_open) {
+ dropbear_exit("unexpected channel reply");
+ }
+ channel->await_open = 0;
+
removechannel(channel);
}
#endif /* USING_LISTENERS */
/* close a stdout/stderr fd */
-static void closeoutfd(struct Channel * channel, int fd) {
+static void closereadfd(struct Channel * channel, int fd) {
- /* don't close it if it is the same as infd,
- * unless infd is already set -1 */
- TRACE(("enter closeoutfd"))
+ /* don't close it if it is the same as writefd,
+ * unless writefd is already set -1 */
+ TRACE(("enter closereadfd"))
closechanfd(channel, fd, 0);
- TRACE(("leave closeoutfd"))
+ TRACE(("leave closereadfd"))
}
/* close a stdin fd */
-static void closeinfd(struct Channel * channel) {
+static void closewritefd(struct Channel * channel) {
- TRACE(("enter closeinfd"))
- closechanfd(channel, channel->infd, 1);
- TRACE(("leave closeinfd"))
+ TRACE(("enter closewritefd"))
+ closechanfd(channel, channel->writefd, 1);
+ TRACE(("leave closewritefd"))
}
/* close a fd, how is 0 for stdout/stderr, 1 for stdin */
@@ -1031,15 +1044,15 @@ static void closechanfd(struct Channel *
closein = closeout = 1;
}
- if (closeout && fd == channel->outfd) {
- channel->outfd = FD_CLOSED;
+ if (closeout && fd == channel->readfd) {
+ channel->readfd = FD_CLOSED;
}
if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
channel->errfd = FD_CLOSED;
}
- if (closein && fd == channel->infd) {
- channel->infd = FD_CLOSED;
+ if (closein && fd == channel->writefd) {
+ channel->writefd = FD_CLOSED;
}
if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
channel->errfd = FD_CLOSED;
@@ -1047,8 +1060,8 @@ static void closechanfd(struct Channel *
/* if we called shutdown on it and all references are gone, then we
* need to close() it to stop it lingering */
- if (channel->type->sepfds && channel->outfd == FD_CLOSED
- && channel->infd == FD_CLOSED && channel->errfd == FD_CLOSED) {
+ if (channel->type->sepfds && channel->readfd == FD_CLOSED
+ && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
close(fd);
}
}
============================================================
--- common-kex.c 960bfda8deaa204b5866f14647f3cd86d262d93f
+++ common-kex.c b06f424fe466a6d3ecfb7072d59457ebb39c8780
@@ -35,7 +35,7 @@
#include "random.h"
/* diffie-hellman-group1-sha1 value for p */
-const unsigned char dh_p_val[] = {
+static const unsigned char dh_p_val[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
@@ -47,8 +47,9 @@ const unsigned char dh_p_val[] = {
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+#define DH_P_LEN sizeof(dh_p_val)
-const int DH_G_VAL = 2;
+static const int DH_G_VAL = 2;
static void kexinitialise();
void gen_new_keys();
@@ -393,19 +394,29 @@ void recv_msg_kexinit() {
/* Belongs in common_kex.c where it should be moved after review */
void recv_msg_kexinit() {
+ unsigned int kexhashbuf_len = 0;
+ unsigned int remote_ident_len = 0;
+ unsigned int local_ident_len = 0;
+
TRACE(("<- KEXINIT"))
TRACE(("enter recv_msg_kexinit"))
- /* start the kex hash */
- ses.kexhashbuf = buf_new(MAX_KEXHASHBUF);
-
if (!ses.kexstate.sentkexinit) {
/* we need to send a kex packet */
send_msg_kexinit();
TRACE(("continue recv_msg_kexinit: sent kexinit"))
}
+ /* start the kex hash */
+ local_ident_len = strlen(LOCAL_IDENT);
+ remote_ident_len = strlen((char*)ses.remoteident);
+ kexhashbuf_len = local_ident_len + remote_ident_len
+ + ses.transkexinit->len + ses.payload->len
+ + KEXHASHBUF_MAX_INTS;
+
+ ses.kexhashbuf = buf_new(kexhashbuf_len);
+
if (IS_DROPBEAR_CLIENT) {
/* read the peer's choice of algos */
@@ -413,20 +424,16 @@ void recv_msg_kexinit() {
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
- (unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT));
+ (unsigned char*)LOCAL_IDENT, local_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
- buf_putstring(ses.kexhashbuf,
- ses.remoteident, strlen((char*)ses.remoteident));
+ buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf,
- buf_getptr(ses.transkexinit, ses.transkexinit->len),
- ses.transkexinit->len);
+ ses.transkexinit->data, ses.transkexinit->len);
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0);
- buf_putstring(ses.kexhashbuf,
- buf_getptr(ses.payload, ses.payload->len),
- ses.payload->len);
+ buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
} else {
/* SERVER */
@@ -434,21 +441,19 @@ void recv_msg_kexinit() {
/* read the peer's choice of algos */
read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */
- buf_putstring(ses.kexhashbuf,
- ses.remoteident, strlen((char*)ses.remoteident));
+ buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
- buf_putstring(ses.kexhashbuf,
- (unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT));
+ buf_putstring(ses.kexhashbuf,
+ (unsigned char*)LOCAL_IDENT, local_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0);
- buf_putstring(ses.kexhashbuf,
- buf_getptr(ses.payload, ses.payload->len),
- ses.payload->len);
+ buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
+
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf,
- buf_getptr(ses.transkexinit, ses.transkexinit->len),
- ses.transkexinit->len);
+ ses.transkexinit->data, ses.transkexinit->len);
+
ses.requirenext = SSH_MSG_KEXDH_INIT;
}
@@ -621,7 +626,7 @@ static void read_kex_algos() {
erralgo = "enc c->s";
goto error;
}
- TRACE(("c2s is %s", c2s_cipher_algo->name))
+ TRACE(("enc c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
@@ -629,7 +634,7 @@ static void read_kex_algos() {
erralgo = "enc s->c";
goto error;
}
- TRACE(("s2c is %s", s2c_cipher_algo->name))
+ TRACE(("enc s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
@@ -637,6 +642,7 @@ static void read_kex_algos() {
erralgo = "mac c->s";
goto error;
}
+ TRACE(("hash c2s is %s", c2s_hash_algo->name))
/* mac_algorithms_server_to_client */
s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
@@ -644,6 +650,7 @@ static void read_kex_algos() {
erralgo = "mac s->c";
goto error;
}
+ TRACE(("hash s2c is %s", s2c_hash_algo->name))
/* compression_algorithms_client_to_server */
c2s_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
@@ -651,6 +658,7 @@ static void read_kex_algos() {
erralgo = "comp c->s";
goto error;
}
+ TRACE(("hash c2s is %s", c2s_comp_algo->name))
/* compression_algorithms_server_to_client */
s2c_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
@@ -658,6 +666,7 @@ static void read_kex_algos() {
erralgo = "comp s->c";
goto error;
}
+ TRACE(("hash s2c is %s", s2c_comp_algo->name))
/* languages_client_to_server */
buf_eatstring(ses.payload);
@@ -700,13 +709,6 @@ static void read_kex_algos() {
ses.newkeys->trans_algo_comp = s2c_comp_algo->val;
}
- TRACE(("enc algo recv %s", algo->name))
- TRACE(("enc algo trans %s", algo->name))
- TRACE(("mac algo recv %s", algo->name))
- TRACE(("mac algo trans %s", algo->name))
- TRACE(("comp algo recv %s", algo->name))
- TRACE(("comp algo trans %s", algo->name))
-
/* reserved for future extensions */
buf_getint(ses.payload);
return;
============================================================
--- common-session.c c141f714affb71abd896785b986c44fdfe98a357
+++ common-session.c 1264a49e05001b96e621efa4abf6f9e77402ed71
@@ -63,7 +63,6 @@ void common_session_init(int sock, char*
ses.connecttimeout = 0;
kexfirstinitialise(); /* initialise the kex state */
- chaninitialise(); /* initialise the channel state */
ses.writepayload = buf_new(MAX_TRANS_PAYLOAD_LEN);
ses.transseq = 0;
@@ -131,7 +130,7 @@ void session_loop(void(*loophandler)())
timeout.tv_usec = 0;
FD_ZERO(&writefd);
FD_ZERO(&readfd);
- assert(ses.payload == NULL);
+ dropbear_assert(ses.payload == NULL);
if (ses.sock != -1) {
FD_SET(ses.sock, &readfd);
if (!isempty(&ses.writequeue)) {
============================================================
--- configure.in 2b2625caa07530f2fa625a0eee5d6e654f167dba
+++ configure.in efc775ba6fb049596194158e06479c2a29a0e165
@@ -206,7 +206,7 @@ AC_HEADER_SYS_WAIT
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h])
+AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h netinet/in_systm.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
============================================================
--- dbclient.1 aed09b6b3d241203fd11a777e5fae635066d2dfc
+++ dbclient.1 2ae47b2e32dbafef9abf583844711c265e418619
@@ -59,6 +59,11 @@ Don't allocate a pty.
.TP
.B \-T
Don't allocate a pty.
+.TP
+.B \-g
+Allow non-local hosts to connect to forwarded ports. Applies to -L and -R
+forwarded ports, though remote connections to -R forwarded ports may be limited
+by the ssh server.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
============================================================
--- dbutil.c 9440c0ae5ca45076f63b0f295585bfaeb82dd57c
+++ dbutil.c bcd256f4bdc8183dfd6b813375c39af6513b183d
@@ -110,6 +110,10 @@ static void generic_dropbear_exit(int ex
exit(exitcode);
}
+void fail_assert(const char* expr, const char* file, int line) {
+ dropbear_exit("failed assertion (%s:%d): `%s'", file, line, expr);
+}
+
static void generic_dropbear_log(int UNUSED(priority), const char* format,
va_list param) {
@@ -149,8 +153,33 @@ void dropbear_trace(const char* format,
}
#endif /* DEBUG_TRACE */
-/* Listen on address:port. Unless address is NULL, in which case listen on
- * everything. If called with address == "", we'll listen on localhost/loopback.
+static void set_sock_priority(int sock) {
+
+ int val;
+
+ /* disable nagle */
+ val = 1;
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
+
+ /* set the TOS bit. note that this will fail for ipv6, I can't find any
+ * equivalent. */
+#ifdef IPTOS_LOWDELAY
+ val = IPTOS_LOWDELAY;
+ setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
+#endif
+
+#ifdef SO_PRIORITY
+ /* linux specific, sets QoS class.
+ * 6 looks to be optimal for interactive traffic (see tc-prio(8) ). */
+ val = 6;
+ setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &val, sizeof(val));
+#endif
+
+}
+
+/* Listen on address:port.
+ * Special cases are address of "" listening on everything,
+ * and address of NULL listening on localhost only.
* Returns the number of sockets bound on success, or -1 on failure. On
* failure, if errstring wasn't NULL, it'll be a newly malloced error
* string.*/
@@ -170,11 +199,17 @@ int dropbear_listen(const char* address,
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
hints.ai_socktype = SOCK_STREAM;
- if (address && address[0] == '\0') {
+ // for calling getaddrinfo:
+ // address == NULL and !AI_PASSIVE: local loopback
+ // address == NULL and AI_PASSIVE: all interfaces
+ // address != NULL: whatever the address says
+ if (!address) {
TRACE(("dropbear_listen: local loopback"))
- address = NULL;
} else {
- TRACE(("dropbear_listen: not local loopback"))
+ if (address[0] == '\0') {
+ TRACE(("dropbear_listen: all interfaces"))
+ address = NULL;
+ }
hints.ai_flags = AI_PASSIVE;
}
err = getaddrinfo(address, port, &hints, &res0);
@@ -186,6 +221,10 @@ int dropbear_listen(const char* address,
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
}
+ if (res0) {
+ freeaddrinfo(res0);
+ res0 = NULL;
+ }
TRACE(("leave dropbear_listen: failed resolving"))
return -1;
}
@@ -215,8 +254,7 @@ int dropbear_listen(const char* address,
linger.l_linger = 5;
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
- /* disable nagle */
- setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
+ set_sock_priority(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
err = errno;
@@ -237,6 +275,11 @@ int dropbear_listen(const char* address,
nsock++;
}
+ if (res0) {
+ freeaddrinfo(res0);
+ res0 = NULL;
+ }
+
if (nsock == 0) {
if (errstring != NULL && *errstring == NULL) {
int len;
@@ -334,8 +377,7 @@ int connect_remote(const char* remotehos
TRACE(("Error connecting: %s", strerror(err)))
} else {
/* Success */
- /* (err is used as a dummy var here) */
- setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&err, sizeof(err));
+ set_sock_priority(sock);
}
freeaddrinfo(res0);
============================================================
--- dbutil.h 3806a1758a9a15ee7a1e3b75e3a49c0d27a7343a
+++ dbutil.h 76eb992fc016821fd1584982e59abe7ac66c5671
@@ -39,6 +39,7 @@ void dropbear_log(int priority, const ch
void dropbear_exit(const char* format, ...);
void dropbear_close(const char* format, ...);
void dropbear_log(int priority, const char* format, ...);
+void fail_assert(const char* expr, const char* file, int line);
#ifdef DEBUG_TRACE
void dropbear_trace(const char* format, ...);
void printhex(const char * label, const unsigned char * buf, int len);
@@ -66,4 +67,7 @@ void setnonblocking(int fd);
/* Used to force mp_ints to be initialised */
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
+/* Dropbear assertion */
+#define dropbear_assert(X) do { if (!(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
+
#endif /* _DBUTIL_H_ */
============================================================
--- dropbear.8 8d1707f168fb2870937ffc24cb85e328328225ce
+++ dropbear.8 01a2e001c0e1dcbaa0105b5914c737744ae5c802
@@ -71,6 +71,9 @@ In program mode the \-F option is implie
.B dropbear
under TCP/IP servers like inetd, tcpsvd, or tcpserver.
In program mode the \-F option is implied, and \-p options are ignored.
+.TP
+.B \-a
+Allow remote hosts to connect to forwarded ports.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
============================================================
--- dss.c e72e0ab248024c0d858b55fdd382a414aeb31317
+++ dss.c d58b7df483ca328e4102dbc59fab1cf85494263e
@@ -46,7 +46,7 @@ int buf_get_dss_pub_key(buffer* buf, dss
int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
TRACE(("enter buf_get_dss_pub_key"))
- assert(key != NULL);
+ dropbear_assert(key != NULL);
key->p = m_malloc(sizeof(mp_int));
key->q = m_malloc(sizeof(mp_int));
key->g = m_malloc(sizeof(mp_int));
@@ -80,7 +80,7 @@ int buf_get_dss_priv_key(buffer* buf, ds
int ret = DROPBEAR_FAILURE;
- assert(key != NULL);
+ dropbear_assert(key != NULL);
ret = buf_get_dss_pub_key(buf, key);
if (ret == DROPBEAR_FAILURE) {
@@ -137,7 +137,7 @@ void buf_put_dss_pub_key(buffer* buf, ds
*/
void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
- assert(key != NULL);
+ dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
buf_putmpint(buf, key->p);
buf_putmpint(buf, key->q);
@@ -149,7 +149,7 @@ void buf_put_dss_priv_key(buffer* buf, d
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */
void buf_put_dss_priv_key(buffer* buf, dss_key *key) {
- assert(key != NULL);
+ dropbear_assert(key != NULL);
buf_put_dss_pub_key(buf, key);
buf_putmpint(buf, key->x);
@@ -172,7 +172,7 @@ int buf_dss_verify(buffer* buf, dss_key
int stringlen;
TRACE(("enter buf_dss_verify"))
- assert(key != NULL);
+ dropbear_assert(key != NULL);
m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
@@ -310,7 +310,7 @@ void buf_put_dss_sign(buffer* buf, dss_k
hash_state hs;
TRACE(("enter buf_put_dss_sign"))
- assert(key != NULL);
+ dropbear_assert(key != NULL);
/* hash the data */
sha1_init(&hs);
@@ -380,7 +380,7 @@ void buf_put_dss_sign(buffer* buf, dss_k
buf_putint(buf, 2*SHA1_HASH_SIZE);
writelen = mp_unsigned_bin_size(&dss_r);
- assert(writelen <= SHA1_HASH_SIZE);
+ dropbear_assert(writelen <= SHA1_HASH_SIZE);
/* need to pad to 160 bits with leading zeros */
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
buf_putbyte(buf, 0);
@@ -393,7 +393,7 @@ void buf_put_dss_sign(buffer* buf, dss_k
buf_incrwritepos(buf, writelen);
writelen = mp_unsigned_bin_size(&dss_s);
- assert(writelen <= SHA1_HASH_SIZE);
+ dropbear_assert(writelen <= SHA1_HASH_SIZE);
/* need to pad to 160 bits with leading zeros */
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
buf_putbyte(buf, 0);
============================================================
--- includes.h cb0e389740b51fc33f98b8c29c9f2ffe7cd11bc2
+++ includes.h 9baa00e2da012281cecc528405cf06e48b53fda8
@@ -44,7 +44,6 @@
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
-#include <netinet/in.h>
#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
@@ -57,8 +56,6 @@
#include <stdarg.h>
#include <dirent.h>
-#include <arpa/inet.h>
-
#ifdef HAVE_UTMP_H
#include <utmp.h>
#endif
@@ -75,10 +72,20 @@
#include <lastlog.h>
#endif
+#include <arpa/inet.h>
+
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
+/* netbsd 1.6 needs this to be included before netinet/ip.h for some
+ * undocumented reason */
+#ifdef HAVE_NETINET_IN_SYSTM_H
+#include <netinet/in_systm.h>
+#endif
+
+#include <netinet/ip.h>
+
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
============================================================
--- kex.h 4aedb4c80abfbc1df32da43a4903b34e8cddc56a
+++ kex.h 596a833742cc5ab88d3930e46214f19e129347f2
@@ -42,11 +42,6 @@ void recv_msg_kexdh_reply(); /* client *
void send_msg_kexdh_init(); /* client */
void recv_msg_kexdh_reply(); /* client */
-extern const unsigned char dh_p_val[];
-#define DH_P_LEN 128 /* The length of the dh_p_val array */
-
-extern const int DH_G_VAL; /* == 2 */
-
struct KEXState {
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
============================================================
--- keyimport.c 38a61bdea3196db5ff2a57fd389236948142b4ef
+++ keyimport.c 4d6aa56819151b18d6828b1a9b1db0b9864e40b3
@@ -173,6 +173,8 @@ static int dropbear_write(const char*fil
buf_incrpos(buf, len);
} while (len > 0 && buf->len != buf->pos);
+ fclose(fp);
+
if (buf->pos != buf->len) {
ret = 0;
} else {
@@ -203,7 +205,7 @@ static void base64_encode_fp(FILE * fp,
unsigned long outlen;
int rawcpl;
rawcpl = cpl * 3 / 4;
- assert((unsigned int)cpl < sizeof(out));
+ dropbear_assert((unsigned int)cpl < sizeof(out));
while (datalen > 0) {
n = (datalen < rawcpl ? datalen : rawcpl);
@@ -714,7 +716,7 @@ static int openssh_write(const char *fil
}
#endif
- assert(keytype != -1);
+ dropbear_assert(keytype != -1);
/*
* Fetch the key blobs.
@@ -913,7 +915,7 @@ static int openssh_write(const char *fil
* with the same value. Those are all removed and the rest is
* returned.
*/
- assert(pos == len);
+ dropbear_assert(pos == len);
while (pos < outlen) {
outblob[pos++] = outlen - len;
}
@@ -1491,7 +1493,7 @@ sign_key *sshcom_read(const char *filena
privlen = pos - publen;
}
- assert(privlen > 0); /* should have bombed by now if not */
+ dropbear_assert(privlen > 0); /* should have bombed by now if not */
retkey = snew(struct ssh2_userkey);
retkey->alg = alg;
@@ -1557,7 +1559,7 @@ int sshcom_write(const char *filename, s
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
- assert(e.start && iqmp.start); /* can't go wrong */
+ dropbear_assert(e.start && iqmp.start); /* can't go wrong */
numbers[0] = e;
numbers[1] = d;
@@ -1581,7 +1583,7 @@ int sshcom_write(const char *filename, s
pos = 0;
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
- assert(y.start && x.start); /* can't go wrong */
+ dropbear_assert(y.start && x.start); /* can't go wrong */
numbers[0] = p;
numbers[1] = g;
@@ -1593,7 +1595,7 @@ int sshcom_write(const char *filename, s
initial_zero = 1;
type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
} else {
- assert(0); /* zoinks! */
+ dropbear_assert(0); /* zoinks! */
}
/*
@@ -1637,13 +1639,13 @@ int sshcom_write(const char *filename, s
}
ciphertext = (char *)outblob+lenpos+4;
cipherlen = pos - (lenpos+4);
- assert(!passphrase || cipherlen % 8 == 0);
+ dropbear_assert(!passphrase || cipherlen % 8 == 0);
/* Wrap up the encrypted blob string. */
PUT_32BIT(outblob+lenpos, cipherlen);
/* And finally fill in the total length field. */
PUT_32BIT(outblob+4, pos);
- assert(pos < outlen);
+ dropbear_assert(pos < outlen);
/*
* Encrypt the key.
============================================================
--- options.h 22166eca17d24203e474f1d8b26ce95ea45e0166
+++ options.h 562d600e35b6a1ef1ab8d8df1dd61654056bd697
@@ -62,25 +62,30 @@ etc) slower (perhaps by 50%). Recommende
#define ENABLE_AGENTFWD
/* Encryption - at least one required.
- * RFC Draft requires 3DES, and recommends Blowfish, AES128 & Twofish128 */
+ * RFC Draft 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_3DES_CBC
-/* Integrity - at least one required.
- * RFC Draft requires sha1-hmac, and recommends md5-hmac.
+/* Message Integrity - at least one required.
+ * RFC Draft 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 in the
+ * Note: there's no point disabling sha1 to save space, since it's used
* for the random number generator and public-key cryptography anyway.
* Disabling it here will just stop it from being used as the integrity portion
* of the ssh protocol.
*
- * These are also used for key fingerprints in logs (when pubkey auth is used),
- * MD5 fingerprints are printed if available, however SHA1 fingerprints will be
- * generated otherwise. This isn't exactly optimal, although SHA1 fingerprints
- * are not too hard to create from pubkeys if required. */
+ * These hashes are also used for public key fingerprints in logs.
+ * If you disable MD5, Dropbear will fall back to SHA1 fingerprints,
+ * which are not the standard form. */
#define DROPBEAR_SHA1_HMAC
+#define DROPBEAR_SHA1_96_HMAC
#define DROPBEAR_MD5_HMAC
/* Hostkey/public key algorithms - at least one required, these are used
@@ -128,6 +133,7 @@ etc) slower (perhaps by 50%). Recommende
#define ENABLE_CLI_PASSWORD_AUTH
#define ENABLE_CLI_PUBKEY_AUTH
+#define ENABLE_CLI_INTERACT_AUTH
/* Define this (as well as ENABLE_CLI_PASSWORD_AUTH) to allow the use of
* a helper program for the ssh client. The helper program should be
@@ -273,7 +279,7 @@ etc) slower (perhaps by 50%). Recommende
#define MAX_MAC_LEN SHA1_HASH_SIZE
-#define MAX_KEY_LEN 24 /* 3DES requires a 24 byte key */
+#define MAX_KEY_LEN 32 /* 256 bits for aes256 etc */
#define MAX_IV_LEN 20 /* must be same as max blocksize,
and >= SHA1_HASH_SIZE */
#define MAX_MAC_KEY 20
@@ -300,16 +306,32 @@ etc) slower (perhaps by 50%). Recommende
#define MAX_STRING_LEN 1400 /* ~= MAX_PROPOSED_ALGO * MAX_NAME_LEN, also
is the max length for a password etc */
-/* For a 4096 bit DSS key, empirically determined to be 1590 bytes */
-#define MAX_PUBKEY_SIZE 1600
-/* For a 4096 bit DSS key, empirically determined to be 1590 bytes */
-#define MAX_PRIVKEY_SIZE 1600
+/* For a 4096 bit DSS key, empirically determined */
+#define MAX_PUBKEY_SIZE 1700
+/* For a 4096 bit DSS key, empirically determined */
+#define MAX_PRIVKEY_SIZE 1700
+/* The maximum size of the bignum portion of the kexhash buffer */
+/* Sect. 8 of the transport draft, K_S + e + f + K */
+#define KEXHASHBUF_MAX_INTS (1700 + 130 + 130 + 130)
+
#define DROPBEAR_MAX_SOCKS 2 /* IPv4, IPv6 are all we'll get for now. Revisit
in a few years time.... */
#define DROPBEAR_MAX_CLI_PASS 1024
+#define DROPBEAR_MAX_CLI_INTERACT_PROMPTS 80 /* The number of prompts we'll
+ accept for keyb-interactive
+ auth */
+
+#if defined(DROPBEAR_AES256_CBC) || defined(DROPBEAR_AES128_CBC)
+#define DROPBEAR_AES_CBC
+#endif
+
+#if defined(DROPBEAR_TWOFISH256_CBC) || defined(DROPBEAR_TWOFISH128_CBC)
+#define DROPBEAR_TWOFISH_CBC
+#endif
+
#ifndef ENABLE_X11FWD
#define DISABLE_X11FWD
#endif
============================================================
--- packet.c 93ffb969c3097b6fe2c9f50cf80716ca0f209295
+++ packet.c 01803cc5860fe470ae70a883d807579b3bd0fc68
@@ -54,13 +54,13 @@ void write_packet() {
buffer * writebuf = NULL;
TRACE(("enter write_packet"))
- assert(!isempty(&ses.writequeue));
+ dropbear_assert(!isempty(&ses.writequeue));
/* Get the next buffer in the queue of encrypted packets to write*/
writebuf = (buffer*)examine(&ses.writequeue);
len = writebuf->len - writebuf->pos;
- assert(len > 0);
+ dropbear_assert(len > 0);
/* Try to write as much as possible */
written = write(ses.sock, buf_getptr(writebuf, len), len);
@@ -119,7 +119,7 @@ void read_packet() {
/* Attempt to read the remainder of the packet, note that there
* mightn't be any available (EAGAIN) */
- assert(ses.readbuf != NULL);
+ dropbear_assert(ses.readbuf != NULL);
maxlen = ses.readbuf->len - ses.readbuf->pos;
len = read(ses.sock, buf_getptr(ses.readbuf, maxlen), maxlen);
@@ -167,7 +167,7 @@ static void read_packet_init() {
if (ses.readbuf == NULL) {
/* start of a new packet */
ses.readbuf = buf_new(INIT_READBUF);
- assert(ses.decryptreadbuf == NULL);
+ dropbear_assert(ses.decryptreadbuf == NULL);
ses.decryptreadbuf = buf_new(blocksize);
}
@@ -220,7 +220,7 @@ static void read_packet_init() {
if ((len > MAX_PACKET_LEN) ||
(len < MIN_PACKET_LEN + macsize) ||
((len - macsize) % blocksize != 0)) {
- dropbear_exit("bad packet size");
+ dropbear_exit("bad packet size %d", len);
}
buf_resize(ses.readbuf, len);
@@ -319,14 +319,13 @@ static int checkmac(buffer* macbuf, buff
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int checkmac(buffer* macbuf, buffer* sourcebuf) {
- unsigned char macsize;
+ unsigned int macsize;
hmac_state hmac;
unsigned char tempbuf[MAX_MAC_LEN];
- unsigned long hashsize;
- int len;
+ unsigned long bufsize;
+ unsigned int len;
macsize = ses.keys->recv_algo_mac->hashsize;
-
if (macsize == 0) {
return DROPBEAR_SUCCESS;
}
@@ -352,8 +351,8 @@ static int checkmac(buffer* macbuf, buff
dropbear_exit("HMAC error");
}
- hashsize = sizeof(tempbuf);
- if (hmac_done(&hmac, tempbuf, &hashsize) != CRYPT_OK) {
+ bufsize = sizeof(tempbuf);
+ if (hmac_done(&hmac, tempbuf, &bufsize) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
@@ -529,15 +528,15 @@ static void writemac(buffer * outputbuff
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
static void writemac(buffer * outputbuffer, buffer * clearwritebuf) {
- int macsize;
+ unsigned int macsize;
unsigned char seqbuf[4];
- unsigned long hashsize;
+ 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) {
/* calculate the mac */
if (hmac_init(&hmac,
@@ -562,12 +561,12 @@ static void writemac(buffer * outputbuff
dropbear_exit("HMAC error");
}
- hashsize = macsize;
- if (hmac_done(&hmac, buf_getwriteptr(outputbuffer, macsize), &hashsize)
+ bufsize = sizeof(tempbuf);
+ if (hmac_done(&hmac, tempbuf, &bufsize)
!= CRYPT_OK) {
dropbear_exit("HMAC error");
}
- buf_incrwritepos(outputbuffer, macsize);
+ buf_putbytes(outputbuffer, tempbuf, macsize);
}
TRACE(("leave writemac"))
}
@@ -606,7 +605,7 @@ static void buf_compress(buffer * dest,
break;
}
- 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(),
============================================================
--- queue.c ccb24cf04c2fae9ff0008f7181239fff1e93f82b
+++ queue.c 0b2bee6c831b234a3fba77c4ae6d598126a3c07c
@@ -42,7 +42,7 @@ void* dequeue(struct Queue* queue) {
void* ret;
struct Link* oldhead;
- assert(!isempty(queue));
+ dropbear_assert(!isempty(queue));
ret = queue->head->item;
oldhead = queue->head;
@@ -62,7 +62,7 @@ void *examine(struct Queue* queue) {
void *examine(struct Queue* queue) {
- assert(!isempty(queue));
+ dropbear_assert(!isempty(queue));
return queue->head->item;
}
============================================================
--- rsa.c a5bd0348ccf9497600f633057ec6028e8cf3c329
+++ rsa.c af6a357404e3480445b0b2835065a3e4666ee812
@@ -49,7 +49,7 @@ int buf_get_rsa_pub_key(buffer* buf, rsa
int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
TRACE(("enter buf_get_rsa_pub_key"))
- assert(key != NULL);
+ dropbear_assert(key != NULL);
key->e = m_malloc(sizeof(mp_int));
key->n = m_malloc(sizeof(mp_int));
m_mp_init_multi(key->e, key->n, NULL);
@@ -80,7 +80,7 @@ int buf_get_rsa_priv_key(buffer* buf, rs
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_rsa_priv_key(buffer* buf, rsa_key *key) {
- assert(key != NULL);
+ dropbear_assert(key != NULL);
TRACE(("enter buf_get_rsa_priv_key"))
@@ -163,7 +163,7 @@ void buf_put_rsa_pub_key(buffer* buf, rs
void buf_put_rsa_pub_key(buffer* buf, rsa_key *key) {
TRACE(("enter buf_put_rsa_pub_key"))
- assert(key != NULL);
+ dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
buf_putmpint(buf, key->e);
@@ -178,7 +178,7 @@ void buf_put_rsa_priv_key(buffer* buf, r
TRACE(("enter buf_put_rsa_priv_key"))
- assert(key != NULL);
+ dropbear_assert(key != NULL);
buf_put_rsa_pub_key(buf, key);
buf_putmpint(buf, key->d);
@@ -209,7 +209,7 @@ int buf_rsa_verify(buffer * buf, rsa_key
TRACE(("enter buf_rsa_verify"))
- assert(key != NULL);
+ dropbear_assert(key != NULL);
m_mp_init_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL);
@@ -267,7 +267,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_k
unsigned char *tmpbuf;
TRACE(("enter buf_put_rsa_sign"))
- assert(key != NULL);
+ dropbear_assert(key != NULL);
m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);
@@ -320,7 +320,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_k
buf_putint(buf, nsize);
/* pad out s to same length as n */
ssize = mp_unsigned_bin_size(&rsa_s);
- assert(ssize <= nsize);
+ dropbear_assert(ssize <= nsize);
for (i = 0; i < nsize-ssize; i++) {
buf_putbyte(buf, 0x00);
}
@@ -365,8 +365,8 @@ static void rsa_pad_em(rsa_key * key,
hash_state hs;
unsigned int nsize;
- assert(key != NULL);
- assert(data != NULL);
+ dropbear_assert(key != NULL);
+ dropbear_assert(data != NULL);
nsize = mp_unsigned_bin_size(key->n);
rsa_EM = buf_new(nsize-1);
@@ -387,7 +387,7 @@ static void rsa_pad_em(rsa_key * key,
sha1_done(&hs, buf_getwriteptr(rsa_EM, SHA1_HASH_SIZE));
buf_incrwritepos(rsa_EM, SHA1_HASH_SIZE);
- assert(rsa_EM->pos == rsa_EM->size);
+ dropbear_assert(rsa_EM->pos == rsa_EM->size);
/* Create the mp_int from the encoded bytes */
buf_setpos(rsa_EM, 0);
============================================================
--- runopts.h 866a99e2213c6a2602a649a2915471ef4b39770a
+++ runopts.h 36768f6323c18233529bb202e8876a3dfbc5d5a5
@@ -33,8 +33,9 @@ typedef struct runopts {
typedef struct runopts {
- int nolocaltcp;
- int noremotetcp;
+#if defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
+ int listen_fwd_all;
+#endif
} runopts;
@@ -73,6 +74,13 @@ typedef struct svr_runopts {
int noauthpass;
int norootpass;
+#ifdef ENABLE_SVR_REMOTETCPFWD
+ int noremotetcp;
+#endif
+#ifdef ENABLE_SVR_LOCALTCPFWD
+ int nolocaltcp;
+#endif
+
sign_key *hostkey;
buffer * banner;
@@ -83,7 +91,6 @@ void loadhostkeys();
void svr_getopts(int argc, char ** argv);
void loadhostkeys();
-/* Uncompleted XXX matt */
typedef struct cli_runopts {
char *progname;
@@ -103,7 +110,6 @@ typedef struct cli_runopts {
#ifdef ENABLE_CLI_LOCALTCPFWD
struct TCPFwdList * localfwds;
#endif
- /* XXX TODO */
} cli_runopts;
============================================================
--- session.h 0e62967a248214d43a774911bfa4a0c503f0da17
+++ session.h 029633beee5cd56701332bc0fa563ae201223469
@@ -226,6 +226,13 @@ struct clientsession {
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
for the last type of auth we tried */
+#ifdef ENABLE_CLI_INTERACT_AUTH
+ int auth_interact_failed; /* flag whether interactive auth can still
+ be used */
+ int interact_request_received; /* flag whether we've received an
+ info request from the server for
+ interactive auth.*/
+#endif
struct SignKeyList *lastprivkey;
int retval; /* What the command exit status was - we emulate it */
============================================================
--- signkey.c 0b42ca44158bc9c2057064ddf12aa3ab11fb76b4
+++ signkey.c c0ce28d518a22769fdee4e64e6fcd77a9100e61f
@@ -404,6 +404,9 @@ int buf_verify(buffer * buf, sign_key *k
if (bloblen == DSS_SIGNATURE_SIZE &&
memcmp(ident, SSH_SIGNKEY_DSS, identlen) == 0) {
m_free(ident);
+ if (key->dsskey == NULL) {
+ dropbear_exit("no dss key to verify signature");
+ }
return buf_dss_verify(buf, key->dsskey, data, len);
}
#endif
@@ -411,6 +414,9 @@ int buf_verify(buffer * buf, sign_key *k
#ifdef DROPBEAR_RSA
if (memcmp(ident, SSH_SIGNKEY_RSA, identlen) == 0) {
m_free(ident);
+ if (key->rsakey == NULL) {
+ dropbear_exit("no rsa key to verify signature");
+ }
return buf_rsa_verify(buf, key->rsakey, data, len);
}
#endif
============================================================
--- ssh.h b63c0c60a29e5dec39b53218d20fe30cfd00a60e
+++ ssh.h 190af1a6af0c6977129303befae06af9c58e6e07
@@ -42,8 +42,19 @@
#define SSH_MSG_USERAUTH_FAILURE 51
#define SSH_MSG_USERAUTH_SUCCESS 52
#define SSH_MSG_USERAUTH_BANNER 53
+
+/* packets 60-79 are method-specific, aren't one-one mapping */
+#define SSH_MSG_USERAUTH_SPECIFIC_60 60
+
+#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60
+
#define SSH_MSG_USERAUTH_PK_OK 60
+/* keyboard interactive auth */
+#define SSH_MSG_USERAUTH_INFO_REQUEST 60
+#define SSH_MSG_USERAUTH_INFO_RESPONSE 61
+
+
/* If adding numbers here, check MAX_UNAUTH_PACKET_TYPE in process-packet.c
* is still valid */
============================================================
--- svr-authpam.c d2e49b9902777338e827e1935b24457b86fce347
+++ svr-authpam.c aa255168b81cef1ec80b008a7e98975cfa9600a3
@@ -59,7 +59,7 @@ pamConvFunc(int num_msg,
const char* message = (*msg)->msg;
- // make a copy we can strip
+ /* make a copy we can strip */
char * compare_message = m_strdup(message);
TRACE(("enter pamConvFunc"))
@@ -80,14 +80,14 @@ pamConvFunc(int num_msg,
}
- // Make the string lowercase.
+ /* Make the string lowercase. */
msg_len = strlen(compare_message);
for (i = 0; i < msg_len; i++) {
compare_message[i] = tolower(compare_message[i]);
}
- // If the string ends with ": ", remove the space.
- // ie "login: " vs "login:"
+ /* If the string ends with ": ", remove the space.
+ ie "login: " vs "login:" */
if (msg_len > 2
&& compare_message[msg_len-2] == ':'
&& compare_message[msg_len-1] == ' ') {
@@ -99,9 +99,9 @@ pamConvFunc(int num_msg,
case PAM_PROMPT_ECHO_OFF:
if (!(strcmp(compare_message, "password:") == 0)) {
- // We don't recognise the prompt as asking for a password,
- // so can't handle it. Add more above as required for
- // different pam modules/implementations
+ /* We don't recognise the prompt as asking for a password,
+ so can't handle it. Add more above as required for
+ different pam modules/implementations */
dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (no echo)",
compare_message);
rc = PAM_CONV_ERR;
@@ -125,9 +125,9 @@ pamConvFunc(int num_msg,
if (!((strcmp(compare_message, "login:" ) == 0)
|| (strcmp(compare_message, "please enter username:") == 0))) {
- // We don't recognise the prompt as asking for a username,
- // so can't handle it. Add more above as required for
- // different pam modules/implementations
+ /* We don't recognise the prompt as asking for a username,
+ so can't handle it. Add more above as required for
+ different pam modules/implementations */
dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (with echo)",
compare_message);
rc = PAM_CONV_ERR;
============================================================
--- svr-authpubkey.c a659d961ca849841adc5ac41a68f360a135763d5
+++ svr-authpubkey.c 6a8b306f446ff4aede63a6d5a72de0b8a15129e4
@@ -266,7 +266,6 @@ static int checkpubkeyperms() {
TRACE(("enter checkpubkeyperms"))
- assert(ses.authstate.pw);
if (ses.authstate.pw->pw_dir == NULL) {
goto out;
}
@@ -312,6 +311,7 @@ static int checkfileperm(char * filename
/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int checkfileperm(char * filename) {
struct stat filestat;
+ int badperm = 0;
TRACE(("enter checkfileperm(%s)", filename))
@@ -322,14 +322,23 @@ static int checkfileperm(char * filename
/* check ownership - user or root only*/
if (filestat.st_uid != ses.authstate.pw->pw_uid
&& filestat.st_uid != 0) {
- TRACE(("leave checkfileperm: wrong ownership"))
- return DROPBEAR_FAILURE;
+ badperm = 1;
+ TRACE(("wrong ownership"))
}
/* check permissions - don't want group or others +w */
if (filestat.st_mode & (S_IWGRP | S_IWOTH)) {
- TRACE(("leave checkfileperm: wrong perms"))
+ badperm = 1;
+ TRACE(("wrong perms"))
+ }
+ if (badperm) {
+ if (!ses.authstate.perm_warn) {
+ ses.authstate.perm_warn = 1;
+ dropbear_log(LOG_INFO, "%s must be owned by user or root, and not writable by others", filename);
+ }
+ TRACE(("leave checkfileperm: failure perms/owner"))
return DROPBEAR_FAILURE;
}
+
TRACE(("leave checkfileperm: success"))
return DROPBEAR_SUCCESS;
}
============================================================
--- svr-chansession.c 14640c883f2d3f5a07cb5614102eeb7762aa9b79
+++ svr-chansession.c 8b52f1a622321b7cf4ed3ac6f69e7241d14d324d
@@ -148,8 +148,8 @@ static void send_msg_chansess_exitstatus
static void send_msg_chansess_exitstatus(struct Channel * channel,
struct ChanSess * chansess) {
- assert(chansess->exit.exitpid != -1);
- assert(chansess->exit.exitsignal == -1);
+ dropbear_assert(chansess->exit.exitpid != -1);
+ dropbear_assert(chansess->exit.exitsignal == -1);
CHECKCLEARTOWRITE();
@@ -170,8 +170,8 @@ static void send_msg_chansess_exitsignal
int i;
char* signame = NULL;
- assert(chansess->exit.exitpid != -1);
- assert(chansess->exit.exitsignal > 0);
+ dropbear_assert(chansess->exit.exitpid != -1);
+ dropbear_assert(chansess->exit.exitsignal > 0);
CHECKCLEARTOWRITE();
@@ -205,7 +205,7 @@ static int newchansess(struct Channel *c
struct ChanSess *chansess;
- assert(channel->typedata == NULL);
+ dropbear_assert(channel->typedata == NULL);
chansess = (struct ChanSess*)m_malloc(sizeof(struct ChanSess));
chansess->cmd = NULL;
@@ -279,7 +279,7 @@ static void closechansess(struct Channel
/* clear child pid entries */
for (i = 0; i < svr_ses.childpidsize; i++) {
if (svr_ses.childpids[i].chansess == chansess) {
- assert(svr_ses.childpids[i].pid > 0);
+ dropbear_assert(svr_ses.childpids[i].pid > 0);
TRACE(("closing pid %d", svr_ses.childpids[i].pid))
TRACE(("exitpid = %d", chansess->exit.exitpid))
svr_ses.childpids[i].pid = -1;
@@ -313,7 +313,7 @@ static void chansessionrequest(struct Ch
}
chansess = (struct ChanSess*)channel->typedata;
- assert(chansess != NULL);
+ dropbear_assert(chansess != NULL);
TRACE(("type is %s", type))
if (strcmp(type, "window-change") == 0) {
@@ -673,15 +673,15 @@ static int noptycommand(struct Channel *
close(infds[FDIN]);
close(outfds[FDOUT]);
close(errfds[FDOUT]);
- channel->infd = infds[FDOUT];
- channel->outfd = outfds[FDIN];
+ channel->writefd = infds[FDOUT];
+ channel->readfd = outfds[FDIN];
channel->errfd = errfds[FDIN];
- ses.maxfd = MAX(ses.maxfd, channel->infd);
- ses.maxfd = MAX(ses.maxfd, channel->outfd);
+ ses.maxfd = MAX(ses.maxfd, channel->writefd);
+ ses.maxfd = MAX(ses.maxfd, channel->readfd);
ses.maxfd = MAX(ses.maxfd, channel->errfd);
- setnonblocking(channel->outfd);
- setnonblocking(channel->infd);
+ setnonblocking(channel->readfd);
+ setnonblocking(channel->writefd);
setnonblocking(channel->errfd);
}
@@ -784,8 +784,8 @@ static int ptycommand(struct Channel *ch
addchildpid(chansess, pid);
close(chansess->slave);
- channel->infd = chansess->master;
- channel->outfd = chansess->master;
+ channel->writefd = chansess->master;
+ channel->readfd = chansess->master;
/* don't need to set stderr here */
ses.maxfd = MAX(ses.maxfd, chansess->master);
============================================================
--- svr-main.c 956679879949d5e02205ac66872e03986c76fc61
+++ svr-main.c 5c0e59de51df9c03a47947b7dcd100053623bfd3
@@ -284,7 +284,7 @@ void main_noinetd() {
getaddrhostname(&remoteaddr),
addrstring);
/* don't return */
- assert(0);
+ dropbear_assert(0);
}
/* parent */
@@ -375,7 +375,7 @@ static int listensockets(int *sock, int
TRACE(("listening on '%s'", svr_opts.ports[i]))
- nsock = dropbear_listen(NULL, svr_opts.ports[i], &sock[sockpos],
+ nsock = dropbear_listen("", svr_opts.ports[i], &sock[sockpos],
sockcount - sockpos,
&errstring, maxfd);
============================================================
--- svr-runopts.c 6d28fe6609d584d48c70f1707e7d4f8460513aea
+++ svr-runopts.c f68d09f9fe84a764badcdd18a0f69b14e44cb0e8
@@ -63,13 +63,14 @@ static void printhelp(const char * progn
"-s Disable password logins\n"
"-g Disable password logins for root\n"
#endif
-#ifndef DISABLE_LOCALTCPFWD
+#ifdef ENABLE_SVR_LOCALTCPFWD
"-j Disable local port forwarding\n"
#endif
-#ifndef DISABLE_REMOTETCPFWD
+#ifdef ENABLE_SVR_REMOTETCPFWD
"-k Disable remote port forwarding\n"
+ "-a Allow connections to forwarded ports from any host\n"
#endif
- "-p port Listen on specified tcp port, up to %d can be specified\n"
+ "-p port Listen on specified tcp port, up to %d can be specified\n"
" (default %s if none specified)\n"
#ifdef INETD_MODE
"-i Start for inetd\n"
@@ -104,8 +105,8 @@ void svr_getopts(int argc, char ** argv)
svr_opts.inetdmode = 0;
svr_opts.portcount = 0;
svr_opts.hostkey = NULL;
- opts.nolocaltcp = 0;
- opts.noremotetcp = 0;
+ svr_opts.nolocaltcp = 0;
+ svr_opts.noremotetcp = 0;
/* not yet
opts.ipv4 = 1;
opts.ipv6 = 1;
@@ -116,6 +117,9 @@ void svr_getopts(int argc, char ** argv)
#ifndef DISABLE_SYSLOG
svr_opts.usingsyslog = 1;
#endif
+#ifdef ENABLE_SVR_REMOTETCPFWD
+ opts.listen_fwd_all = 0;
+#endif
for (i = 1; i < (unsigned int)argc; i++) {
if (next) {
@@ -152,13 +156,16 @@ void svr_getopts(int argc, char ** argv)
#endif
#ifndef DISABLE_LOCALTCPFWD
case 'j':
- opts.nolocaltcp = 1;
+ svr_opts.nolocaltcp = 1;
break;
#endif
#ifndef DISABLE_REMOTETCPFWD
case 'k':
- opts.noremotetcp = 1;
+ svr_opts.noremotetcp = 1;
break;
+ case 'a':
+ opts.listen_fwd_all = 1;
+ break;
#endif
#ifdef INETD_MODE
case 'i':
============================================================
--- svr-tcpfwd.c 9c0362f8d1c15ce9d702873cc1a2064754d7919b
+++ svr-tcpfwd.c bfd47e1ced10186c0d9ce06dca0f0d3694e9c3df
@@ -72,7 +72,7 @@ void recv_msg_global_request_remotetcp()
TRACE(("enter recv_msg_global_request_remotetcp"))
- if (opts.noremotetcp) {
+ if (svr_opts.noremotetcp) {
TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"))
goto out;
}
@@ -129,9 +129,9 @@ static int matchtcp(void* typedata1, voi
const struct TCPListener *info1 = (struct TCPListener*)typedata1;
const struct TCPListener *info2 = (struct TCPListener*)typedata2;
- return (info1->sendport == info2->sendport)
+ return (info1->listenport == info2->listenport)
&& (info1->chantype == info2->chantype)
- && (strcmp(info1->sendaddr, info2->sendaddr) == 0);
+ && (strcmp(info1->listenaddr, info2->listenaddr) == 0);
}
static int svr_cancelremotetcp() {
@@ -153,8 +153,10 @@ static int svr_cancelremotetcp() {
port = buf_getint(ses.payload);
- tcpinfo.sendaddr = bindaddr;
- tcpinfo.sendport = port;
+ tcpinfo.sendaddr = NULL;
+ tcpinfo.sendport = 0;
+ tcpinfo.listenaddr = bindaddr;
+ tcpinfo.listenport = port;
listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp);
if (listener) {
remove_listener( listener );
@@ -177,7 +179,6 @@ static int svr_remotetcpreq() {
TRACE(("enter remotetcpreq"))
- /* NOTE: at this stage, we ignore bindaddr. see below and listen_tcpfwd */
bindaddr = buf_getstring(ses.payload, &addrlen);
if (addrlen > MAX_IP_LEN) {
TRACE(("addr len too long: %d", addrlen))
@@ -202,20 +203,20 @@ static int svr_remotetcpreq() {
}
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
- tcpinfo->sendaddr = bindaddr;
- tcpinfo->sendport = port;
+ tcpinfo->sendaddr = NULL;
+ tcpinfo->sendport = 0;
+ tcpinfo->listenaddr = bindaddr;
tcpinfo->listenport = port;
tcpinfo->chantype = &svr_chan_tcpremote;
+ tcpinfo->tcp_type = forwarded;
- /* Note: bindaddr is actually ignored by listen_tcpfwd, since
- * we only want to bind to localhost */
ret = listen_tcpfwd(tcpinfo);
out:
if (ret == DROPBEAR_FAILURE) {
/* we only free it if a listener wasn't created, since the listener
* has to remember it if it's to be cancelled */
- m_free(tcpinfo->sendaddr);
+ m_free(tcpinfo->listenaddr);
m_free(tcpinfo);
}
TRACE(("leave remotetcpreq"))
@@ -235,7 +236,7 @@ static int newtcpdirect(struct Channel *
int len;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
- if (opts.nolocaltcp) {
+ if (svr_opts.nolocaltcp) {
TRACE(("leave newtcpdirect: local tcp forwarding disabled"))
goto out;
}
@@ -272,11 +273,9 @@ static int newtcpdirect(struct Channel *
ses.maxfd = MAX(ses.maxfd, sock);
- /* Note that infd is actually the "outgoing" direction on the
- * tcp connection, vice versa for outfd.
- * We don't set outfd, that will get set after the connection's
+ /* We don't set readfd, that will get set after the connection's
* progress succeeds */
- channel->infd = sock;
+ channel->writefd = sock;
channel->initconn = 1;
err = SSH_OPEN_IN_PROGRESS;
============================================================
--- tcp-accept.c 85218bbb73f0a9394f0f100aa416a917978318b7
+++ tcp-accept.c 413de2351e02bf67ef6e78238c449c6a480a2f75
@@ -39,6 +39,7 @@ static void cleanup_tcp(struct Listener
struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata);
m_free(tcpinfo->sendaddr);
+ m_free(tcpinfo->listenaddr);
m_free(tcpinfo);
}
@@ -64,11 +65,28 @@ static void tcp_acceptor(struct Listener
}
if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) {
+ unsigned char* addr = NULL;
+ unsigned int port = 0;
- buf_putstring(ses.writepayload, tcpinfo->sendaddr,
- strlen(tcpinfo->sendaddr));
- buf_putint(ses.writepayload, tcpinfo->sendport);
+ if (tcpinfo->tcp_type == direct) {
+ /* "direct-tcpip" */
+ /* host to connect, port to connect */
+ addr = tcpinfo->sendaddr;
+ port = tcpinfo->sendport;
+ } else {
+ dropbear_assert(tcpinfo->tcp_type == forwarded);
+ /* "forwarded-tcpip" */
+ /* address that was connected, port that was connected */
+ addr = tcpinfo->listenaddr;
+ port = tcpinfo->listenport;
+ }
+
+ buf_putstring(ses.writepayload, addr, strlen(addr));
+ buf_putint(ses.writepayload, port);
+
+ /* originator ip */
buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
+ /* originator port */
buf_putint(ses.writepayload, atol(portstring));
encrypt_packet();
@@ -86,16 +104,21 @@ int listen_tcpfwd(struct TCPListener* tc
struct Listener *listener = NULL;
int nsocks;
char* errstring = NULL;
+ // listen_spec = NULL indicates localhost
+ const char* listen_spec = NULL;
TRACE(("enter listen_tcpfwd"))
/* first we try to bind, so don't need to do so much cleanup on failure */
snprintf(portstring, sizeof(portstring), "%d", tcpinfo->listenport);
- /* XXX Note: we're just listening on localhost, no matter what they tell
- * us. If someone wants to make it listen otherways, then change
- * the "" argument. but that requires UI changes too */
- nsocks = dropbear_listen("", portstring, socks,
+ /* a listenaddr of "" will indicate all interfaces */
+ if (opts.listen_fwd_all
+ && (strcmp(tcpinfo->listenaddr, "localhost") != 0) ) {
+ listen_spec = tcpinfo->listenaddr;
+ }
+
+ nsocks = dropbear_listen(listen_spec, portstring, socks,
DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd);
if (nsocks < 0) {
dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
============================================================
--- tcpfwd.h e093ea296308000bdf7c4c54f49caf7bf353a47e
+++ tcpfwd.h 16c1fbd5251921ecc87e704bc2afe2076dd55a4e
@@ -28,20 +28,19 @@ struct TCPListener {
struct TCPListener {
- /* sendaddr/sendport are what we send in the channel init request. For a
- * forwarded-tcpip request, it's the addr/port we were binding to.
- * For a direct-tcpip request, it's the addr/port we want the other
+ /* For a direct-tcpip request, it's the addr/port we want the other
* end to connect to */
-
unsigned char *sendaddr;
unsigned int sendport;
- /* This is for direct-tcpip (ie the client listening), and specifies the
- * port to listen on. Is unspecified for the server */
+ /* This is the address/port that we listen on. The address has special
+ * meanings as per the rfc, "" for all interfaces, "localhost" for
+ * localhost, or a normal interface name. */
+ unsigned char *listenaddr;
unsigned int listenport;
const struct ChanType *chantype;
-
+ enum {direct, forwarded} tcp_type;
};
/* A link in a list of forwards */