summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--algo.h5
-rw-r--r--cli-algo.c9
-rw-r--r--cli-kex.c91
-rw-r--r--cli-main.c33
-rw-r--r--cli-session.c101
-rw-r--r--common-kex.c258
-rw-r--r--common-session.c150
-rw-r--r--dbutil.c90
-rw-r--r--dbutil.h5
-rw-r--r--debug.h2
-rw-r--r--kex.h16
-rw-r--r--main.c4
-rw-r--r--options.h5
-rw-r--r--process-packet.c2
-rw-r--r--session.h23
-rw-r--r--signkey.c3
-rw-r--r--svr-algo.c4
-rw-r--r--svr-kex.c182
-rw-r--r--svr-session.c82
-rw-r--r--tcpfwd-direct.c6
20 files changed, 750 insertions, 321 deletions
diff --git a/algo.h b/algo.h
index 369f73c..3e8ebb5 100644
--- a/algo.h
+++ b/algo.h
@@ -66,10 +66,9 @@ void crypto_init();
int have_algo(char* algo, size_t algolen, algo_type algos[]);
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
-algo_type * common_buf_match_algo(buffer* buf, algo_type localalgos[],
- int *goodguess);
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess);
-algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[]);
+algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
+ int *goodguess);
#endif /* _ALGO_H_ */
diff --git a/cli-algo.c b/cli-algo.c
index ba1ed85..5edd6a1 100644
--- a/cli-algo.c
+++ b/cli-algo.c
@@ -33,7 +33,8 @@
* direction MUST be the first algorithm on the client's list
* that is also on the server's list.
*/
-algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[]) {
+algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
+ int *goodguess) {
unsigned char * algolist = NULL;
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
@@ -41,6 +42,8 @@ algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[]) {
unsigned int count, i, j;
algo_type * ret = NULL;
+ *goodguess = 0;
+
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
TRACE(("cli_buf_match_algo: %s", algolist));
@@ -78,6 +81,10 @@ algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[]) {
if (len == strlen(remotealgos[i])
&& strncmp(localalgos[j].name,
remotealgos[i], len) == 0) {
+ if (i == 0 && j == 0) {
+ /* was a good guess */
+ *goodguess = 1;
+ }
ret = &localalgos[j];
goto out;
}
diff --git a/cli-kex.c b/cli-kex.c
new file mode 100644
index 0000000..4d26332
--- /dev/null
+++ b/cli-kex.c
@@ -0,0 +1,91 @@
+/*
+ * Dropbear - a SSH2 server
+ *
+ * Copyright (c) 2002,2003 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 "session.h"
+#include "dbutil.h"
+#include "algo.h"
+#include "buffer.h"
+#include "session.h"
+#include "kex.h"
+#include "ssh.h"
+#include "packet.h"
+#include "bignum.h"
+#include "random.h"
+#include "runopts.h"
+
+
+
+void send_msg_kexdh_init() {
+
+ cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
+ cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
+
+ m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x);
+ gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
+
+ CHECKCLEARTOWRITE();
+ buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
+ buf_putmpint(ses.writepayload, cli_ses.dh_e);
+ encrypt_packet();
+ ses.requirenext = SSH_MSG_KEXDH_REPLY;
+}
+
+/* Handle a diffie-hellman key exchange reply. */
+void recv_msg_kexdh_reply() {
+
+ mp_int dh_f;
+ sign_key *hostkey = NULL;
+ int type;
+
+ type = ses.newkeys->algo_hostkey;
+
+ hostkey = new_sign_key();
+ if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
+ dropbear_exit("Bad KEX packet");
+ }
+
+ m_mp_init(&dh_f);
+ if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
+ dropbear_exit("Bad KEX packet");
+ }
+
+ kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey);
+ mp_clear(&dh_f);
+
+ if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
+ != DROPBEAR_SUCCESS) {
+ dropbear_exit("Bad hostkey signature");
+ }
+
+ /* XXX TODO */
+ dropbear_log(LOG_WARNING,"Not checking hostkey fingerprint for the moment");
+
+ sign_key_free(hostkey);
+ hostkey = NULL;
+
+ send_msg_newkeys();
+ ses.requirenext = SSH_MSG_NEWKEYS;
+ TRACE(("leave recv_msg_kexdh_init"));
+}
diff --git a/cli-main.c b/cli-main.c
new file mode 100644
index 0000000..2460060
--- /dev/null
+++ b/cli-main.c
@@ -0,0 +1,33 @@
+#include <includes.h>
+
+int main(int argc, char ** argv) {
+
+ int sock;
+ char* error = NULL;
+ char* hostandport;
+ int len;
+
+ _dropbear_exit = cli_dropbear_exit;
+ _dropbear_log = cli_dropbear_log;
+
+ cli_getopts(argc, argv);
+
+ sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
+ 0, &error);
+
+ if (sock < 0) {
+ dropbear_exit("%s", error);
+ }
+
+ /* Set up the host:port log */
+ len = strlen(cli_opts.remotehost);
+ len += 10; /* 16 bit port and leeway*/
+ hostandport = (char*)m_malloc(len);
+ snprintf(hostandport, len, "%s%d",
+ cli_opts.remotehost, cli_opts.remoteport);
+
+ cli_session(sock, hostandport);
+
+ /* not reached */
+ return -1;
+}
diff --git a/cli-session.c b/cli-session.c
new file mode 100644
index 0000000..d5afaf9
--- /dev/null
+++ b/cli-session.c
@@ -0,0 +1,101 @@
+#include "includes.h"
+#include "session.h"
+#include "dbutil.h"
+#include "kex.h"
+#include "ssh.h"
+#include "packet.h"
+#include "tcpfwd-direct.h"
+#include "tcpfwd-remote.h"
+#include "channel.h"
+#include "random.h"
+
+static void cli_remoteclosed();
+static void cli_sessionloop();
+
+struct clientsession cli_ses; /* GLOBAL */
+
+static const packettype cli_packettypes[] = {
+ /* TYPE, AUTHREQUIRED, FUNCTION */
+ {SSH_MSG_KEXINIT, recv_msg_kexinit},
+ {SSH_MSG_KEXDH_REPLY, recv_msg_kexdh_reply}, // client
+ {SSH_MSG_NEWKEYS, recv_msg_newkeys},
+ {SSH_MSG_CHANNEL_DATA, recv_msg_channel_data},
+ {SSH_MSG_CHANNEL_WINDOW_ADJUST, recv_msg_channel_window_adjust},
+ {SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_remotetcp},
+ {SSH_MSG_CHANNEL_REQUEST, recv_msg_channel_request},
+ {SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open},
+ {SSH_MSG_CHANNEL_EOF, recv_msg_channel_eof},
+ {SSH_MSG_CHANNEL_CLOSE, recv_msg_channel_close},
+ {SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation},
+ {SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
+ {0, 0} /* End */
+};
+
+static const struct ChanType *cli_chantypes[] = {
+// &clichansess,
+ /* &chan_tcpdirect etc, though need to only allow if we've requested
+ * that forwarding */
+ NULL /* Null termination */
+};
+void cli_session(int sock, char* remotehost) {
+
+ crypto_init();
+ common_session_init(sock, remotehost);
+
+ chaninitialise(cli_chantypes);
+
+ /* For printing "remote host closed" for the user */
+ session_remoteclosed = cli_remoteclosed;
+
+ /* packet handlers */
+ ses.packettypes = cli_packettypes;
+
+ /* Ready to go */
+ sessinitdone = 1;
+
+ /* Exchange identification */
+ session_identification();
+
+ seedrandom();
+
+ send_msg_kexinit();
+
+ /* XXX here we do stuff differently */
+
+ session_loop(cli_sessionloop);
+
+ /* Not reached */
+
+
+}
+
+static void cli_sessionloop() {
+
+ switch (cli_ses.state) {
+
+ KEXINIT_RCVD:
+ /* We initiate the KEX. If DH wasn't the correct type, the KEXINIT
+ * negotiation would have failed. */
+ send_msg_kexdh_init();
+ cli_ses.state = KEXDH_INIT_SENT;
+ break;
+
+ default:
+ break;
+ }
+
+ if (cli_ses.donefirstkex && !cli_ses.authdone) {
+
+
+
+}
+
+/* called when the remote side closes the connection */
+static void cli_remoteclosed() {
+
+ /* XXX TODO perhaps print a friendlier message if we get this but have
+ * already sent/received disconnect message(s) ??? */
+ close(ses.sock);
+ ses.sock = -1;
+ dropbear_exit("%s closed the connection", ses.remotehost);
+}
diff --git a/common-kex.c b/common-kex.c
index e1ae91a..21accb6 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -193,7 +193,6 @@ void kexinitialise() {
ses.kexstate.sentnewkeys = 0;
/* first_packet_follows */
- /* TODO - currently not handled */
ses.kexstate.firstfollows = 0;
ses.kexstate.datatrans = 0;
@@ -402,47 +401,54 @@ void recv_msg_kexinit() {
if (IS_DROPBEAR_CLIENT) {
+#ifdef DROPBEAR_CLIENT
- /* read the peer's choice of algos */
- cli_read_kex();
+ /* read the peer's choice of algos */
+ read_kex_algos(cli_buf_match_algo);
- /* V_C, the client's version string (CR and NL excluded) */
+ /* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
(unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT));
- /* V_S, the server's version string (CR and NL excluded) */
+ /* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
ses.remoteident, strlen((char*)ses.remoteident));
- /* I_C, the payload of the client's SSH_MSG_KEXINIT */
+ /* 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);
- /* I_S, the payload of the server's SSH_MSG_KEXINIT */
+ /* 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);
+ cli_ses.state = KEXINIT_RCVD;
+#endif
} else {
+ /* SERVER */
+#ifdef DROPBEAR_SERVER
- /* read the peer's choice of algos */
- svr_read_kex();
- /* V_C, the client's version string (CR and NL excluded) */
+ /* read the peer's choice of algos */
+ read_kex_algos(svr_buf_match_algo);
+ /* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
ses.remoteident, strlen((char*)ses.remoteident));
- /* V_S, the server's version string (CR and NL excluded) */
+ /* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
(unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT));
- /* I_C, the payload of the client's SSH_MSG_KEXINIT */
+ /* 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);
- /* I_S, the payload of the server's SSH_MSG_KEXINIT */
+ /* 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.requirenext = SSH_MSG_KEXDH_INIT;
+#endif
}
buf_free(ses.transkexinit);
@@ -450,9 +456,233 @@ void recv_msg_kexinit() {
/* the rest of ses.kexhashbuf will be done after DH exchange */
ses.kexstate.recvkexinit = 1;
- ses.requirenext = SSH_MSG_KEXDH_INIT;
// ses.expecting = 0; // client matt
TRACE(("leave recv_msg_kexinit"));
}
+/* Initialises and generate one side of the diffie-hellman key exchange values.
+ * See the ietf-secsh-transport draft, section 6, for details */
+void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
+
+ mp_int dh_p, dh_q, dh_g;
+ unsigned char randbuf[DH_P_LEN];
+ int dh_q_len;
+
+ TRACE(("enter send_msg_kexdh_reply"));
+
+ m_mp_init_multi(&dh_g, &dh_p, &dh_q, dh_priv, dh_pub, NULL);
+
+ /* read the prime and generator*/
+ if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
+ != MP_OKAY) {
+ dropbear_exit("Diffie-Hellman error");
+ }
+
+ if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
+ dropbear_exit("Diffie-Hellman error");
+ }
+
+ /* calculate q = (p-1)/2 */
+ /* dh_priv is just a temp var here */
+ if (mp_sub_d(&dh_p, 1, dh_priv) != MP_OKAY) {
+ dropbear_exit("Diffie-Hellman error");
+ }
+ if (mp_div_2(dh_priv, &dh_q) != MP_OKAY) {
+ dropbear_exit("Diffie-Hellman error");
+ }
+
+ dh_q_len = mp_unsigned_bin_size(&dh_q);
+
+ /* calculate our random value dh_y */
+ do {
+ assert((unsigned int)dh_q_len <= sizeof(randbuf));
+ genrandom(randbuf, dh_q_len);
+ if (mp_read_unsigned_bin(dh_priv, randbuf, dh_q_len) != MP_OKAY) {
+ dropbear_exit("Diffie-Hellman error");
+ }
+ } while (mp_cmp(dh_priv, &dh_q) == MP_GT || mp_cmp_d(dh_priv, 0) != MP_GT);
+
+ /* f = g^y mod p */
+ if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
+ dropbear_exit("Diffie-Hellman error");
+ }
+ mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL);
+}
+
+/* This function is fairly common between client/server, with some substitution
+ * of dh_e/dh_f etc. Hence these arguments:
+ * dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is
+ * vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */
+void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
+ sign_key *hostkey) {
+
+ mp_int dh_p;
+ mp_int *dh_e = NULL, *dh_f = NULL;
+ hash_state hs;
+
+ /* read the prime and generator*/
+ mp_init(&dh_p);
+ if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
+ != MP_OKAY) {
+ dropbear_exit("Diffie-Hellman error");
+ }
+
+ /* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
+ if (mp_cmp(dh_pub_them, &dh_p) != MP_LT
+ || mp_cmp_d(dh_pub_them, 0) != MP_GT) {
+ dropbear_exit("Diffie-Hellman error");
+ }
+
+ /* K = e^y mod p = f^x mod p */
+ ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int));
+ m_mp_init(ses.dh_K);
+ if (mp_exptmod(dh_pub_them, dh_priv, &dh_p, ses.dh_K) != MP_OKAY) {
+ dropbear_exit("Diffie-Hellman error");
+ }
+
+ /* clear no longer needed vars */
+ mp_clear_multi(&dh_p, NULL);
+
+ /* From here on, the code needs to work with the _same_ vars on each side,
+ * not vice-versaing for client/server */
+ if (IS_DROPBEAR_CLIENT) {
+ dh_e = dh_pub_us;
+ dh_f = dh_pub_them;
+ } else {
+ dh_e = dh_pub_them;
+ dh_f = dh_pub_us;
+ }
+
+ /* Create the remainder of the hash buffer, to generate the exchange hash */
+ /* K_S, the host key */
+ buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
+ /* e, exchange value sent by the client */
+ buf_putmpint(ses.kexhashbuf, dh_e);
+ /* f, exchange value sent by the server */
+ buf_putmpint(ses.kexhashbuf, dh_f);
+ /* K, the shared secret */
+ buf_putmpint(ses.kexhashbuf, ses.dh_K);
+
+ /* calculate the hash H to sign */
+ sha1_init(&hs);
+ buf_setpos(ses.kexhashbuf, 0);
+ sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
+ ses.kexhashbuf->len);
+ sha1_done(&hs, ses.hash);
+ buf_free(ses.kexhashbuf);
+ ses.kexhashbuf = NULL;
+
+ /* first time around, we set the session_id to H */
+ if (ses.session_id == NULL) {
+ /* create the session_id, this never needs freeing */
+ ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
+ memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
+ }
+}
+
+/* read the other side's algo list. buf_match_algo is a callback to match
+ * algos for the client or server. */
+void read_kex_algos(
+ algo_type*(buf_match_algo)(buffer*buf, algo_type localalgos[],
+ int *goodguess)) {
+
+ algo_type * algo;
+ char * erralgo = NULL;
+
+ int goodguess = 0;
+ int allgood = 1; /* we AND this with each goodguess and see if its still
+ true after */
+
+ buf_incrpos(ses.payload, 16); /* start after the cookie */
+
+ ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
+
+ /* kex_algorithms */
+ algo = buf_match_algo(ses.payload, sshkex, &goodguess);
+ allgood &= goodguess;
+ if (algo == NULL) {
+ erralgo = "kex";
+ goto error;
+ }
+ ses.newkeys->algo_kex = algo->val;
+
+ /* server_host_key_algorithms */
+ algo = buf_match_algo(ses.payload, sshhostkey, &goodguess);
+ allgood &= goodguess;
+ if (algo == NULL) {
+ erralgo = "hostkey";
+ goto error;
+ }
+ ses.newkeys->algo_hostkey = algo->val;
+
+ /* encryption_algorithms_client_to_server */
+ algo = buf_match_algo(ses.payload, sshciphers, &goodguess);
+ if (algo == NULL) {
+ erralgo = "enc c->s";
+ goto error;
+ }
+ ses.newkeys->recv_algo_crypt = (struct dropbear_cipher*)algo->data;
+
+ /* encryption_algorithms_server_to_client */
+ algo = buf_match_algo(ses.payload, sshciphers, &goodguess);
+ if (algo == NULL) {
+ erralgo = "enc s->c";
+ goto error;
+ }
+ ses.newkeys->trans_algo_crypt = (struct dropbear_cipher*)algo->data;
+
+ /* mac_algorithms_client_to_server */
+ algo = buf_match_algo(ses.payload, sshhashes, &goodguess);
+ if (algo == NULL) {
+ erralgo = "mac c->s";
+ goto error;
+ }
+ ses.newkeys->recv_algo_mac = (struct dropbear_hash*)algo->data;
+
+ /* mac_algorithms_server_to_client */
+ algo = buf_match_algo(ses.payload, sshhashes, &goodguess);
+ if (algo == NULL) {
+ erralgo = "mac s->c";
+ goto error;
+ }
+ ses.newkeys->trans_algo_mac = (struct dropbear_hash*)algo->data;
+
+ /* compression_algorithms_client_to_server */
+ algo = buf_match_algo(ses.payload, sshcompress, &goodguess);
+ if (algo == NULL) {
+ erralgo = "comp c->s";
+ goto error;
+ }
+ ses.newkeys->recv_algo_comp = algo->val;
+
+ /* compression_algorithms_server_to_client */
+ algo = buf_match_algo(ses.payload, sshcompress, &goodguess);
+ if (algo == NULL) {
+ erralgo = "comp s->c";
+ goto error;
+ }
+ ses.newkeys->trans_algo_comp = algo->val;
+
+ /* languages_client_to_server */
+ buf_eatstring(ses.payload);
+
+ /* languages_server_to_client */
+ buf_eatstring(ses.payload);
+
+ /* first_kex_packet_follows */
+ if (buf_getbyte(ses.payload)) {
+ ses.kexstate.firstfollows = 1;
+ /* if the guess wasn't good, we ignore the packet sent */
+ if (!allgood) {
+ ses.ignorenext = 1;
+ }
+ }
+
+ /* reserved for future extensions */
+ buf_getint(ses.payload);
+ return;
+
+error:
+ dropbear_exit("no matching algo %s", erralgo);
+}
diff --git a/common-session.c b/common-session.c
index 6e37e29..70ddbfe 100644
--- a/common-session.c
+++ b/common-session.c
@@ -35,6 +35,7 @@
#include "channel.h"
#include "atomicio.h"
+
struct sshsession ses; /* GLOBAL */
/* need to know if the session struct has been initialised, this way isn't the
@@ -44,19 +45,18 @@ int sessinitdone = 0; /* GLOBAL */
/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
int exitflag = 0; /* GLOBAL */
-static int ident_readln(int fd, char* buf, int count);
-
-
void(*session_remoteclosed)() = NULL;
+static void checktimeouts();
+static int ident_readln(int fd, char* buf, int count);
+
/* called only at the start of a session, set up initial state */
-void common_session_init(int sock) {
+void common_session_init(int sock, char* remotehost) {
TRACE(("enter session_init"));
- ses.remoteaddr = NULL;
- ses.remotehost = NULL;
+ ses.remotehost = remotehost;
ses.sock = sock;
ses.maxfd = sock;
@@ -114,6 +114,86 @@ void common_session_init(int sock) {
TRACE(("leave session_init"));
}
+void session_loop(void(*loophandler)()) {
+
+ fd_set readfd, writefd;
+ struct timeval timeout;
+ int val;
+
+ /* main loop, select()s for all sockets in use */
+ for(;;) {
+
+ timeout.tv_sec = SELECT_TIMEOUT;
+ timeout.tv_usec = 0;
+ FD_ZERO(&writefd);
+ FD_ZERO(&readfd);
+ assert(ses.payload == NULL);
+ if (ses.sock != -1) {
+ FD_SET(ses.sock, &readfd);
+ if (!isempty(&ses.writequeue)) {
+ FD_SET(ses.sock, &writefd);
+ }
+ }
+
+ /* set up for channels which require reading/writing */
+ if (ses.dataallowed) {
+ setchannelfds(&readfd, &writefd);
+ }
+ val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
+
+ if (exitflag) {
+ dropbear_exit("Terminated by signal");
+ }
+
+ if (val < 0) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ dropbear_exit("Error in select");
+ }
+ }
+
+ /* check for auth timeout, rekeying required etc */
+ checktimeouts();
+
+ if (val == 0) {
+ /* timeout */
+ TRACE(("select timeout"));
+ continue;
+ }
+
+ /* process session socket's incoming/outgoing data */
+ if (ses.sock != -1) {
+ if (FD_ISSET(ses.sock, &writefd) && !isempty(&ses.writequeue)) {
+ write_packet();
+ }
+
+ if (FD_ISSET(ses.sock, &readfd)) {
+ read_packet();
+ }
+
+ /* Process the decrypted packet. After this, the read buffer
+ * will be ready for a new packet */
+ if (ses.payload != NULL) {
+ process_packet();
+ }
+ }
+
+ /* process pipes etc for the channels, ses.dataallowed == 0
+ * during rekeying ) */
+ if (ses.dataallowed) {
+ channelio(&readfd, &writefd);
+ }
+
+ if (loophandler) {
+ loophandler();
+ }
+
+ } /* for(;;) */
+
+ /* Not reached */
+}
+
/* clean up a session on exit */
void common_session_cleanup() {
@@ -134,35 +214,7 @@ void common_session_cleanup() {
TRACE(("leave session_cleanup"));
}
-/* Check all timeouts which are required. Currently these are the time for
- * user authentication, and the automatic rekeying. */
-void checktimeouts() {
-
- struct timeval tv;
- long secs;
-
- if (gettimeofday(&tv, 0) < 0) {
- dropbear_exit("Error getting time");
- }
-
- secs = tv.tv_sec;
-
- if (ses.connecttimeout != 0 && secs > ses.connecttimeout) {
- dropbear_close("Timeout before auth");
- }
-
- /* we can't rekey if we haven't done remote ident exchange yet */
- if (ses.remoteident == NULL) {
- return;
- }
- if (!ses.kexstate.sentkexinit
- && (secs - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
- || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)){
- TRACE(("rekeying after timeout or max data reached"));
- send_msg_kexinit();
- }
-}
void session_identification() {
/* max length of 255 chars */
@@ -268,3 +320,33 @@ static int ident_readln(int fd, char* buf, int count) {
return pos+1;
}
+/* Check all timeouts which are required. Currently these are the time for
+ * user authentication, and the automatic rekeying. */
+static void checktimeouts() {
+
+ struct timeval tv;
+ long secs;
+
+ if (gettimeofday(&tv, 0) < 0) {
+ dropbear_exit("Error getting time");
+ }
+
+ secs = tv.tv_sec;
+
+ if (ses.connecttimeout != 0 && secs > ses.connecttimeout) {
+ dropbear_close("Timeout before auth");
+ }
+
+ /* we can't rekey if we haven't done remote ident exchange yet */
+ if (ses.remoteident == NULL) {
+ return;
+ }
+
+ if (!ses.kexstate.sentkexinit
+ && (secs - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
+ || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)){
+ TRACE(("rekeying after timeout or max data reached"));
+ send_msg_kexinit();
+ }
+}
+
diff --git a/dbutil.c b/dbutil.c
index 2494f38..1c0648c 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -113,6 +113,95 @@ void dropbear_trace(const char* format, ...) {
}
#endif /* DEBUG_TRACE */
+/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
+ * return immediately if nonblocking is set */
+int connect_remote(const char* remotehost, const char* remoteport,
+ int nonblocking, char ** errstring) {
+
+ struct addrinfo *res0 = NULL, *res = NULL, hints;
+ int sock;
+ int err;
+
+ TRACE(("enter connect_remote"));
+
+ if (errstring != NULL) {
+ *errstring = NULL;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = PF_UNSPEC;
+
+ err = getaddrinfo(remotehost, remoteport, &hints, &res0);
+ if (err) {
+ if (errstring != NULL && *errstring == NULL) {
+ int len;
+ len = 20 + strlen(gai_strerror(err));
+ *errstring = (char*)m_malloc(len);
+ snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
+ }
+ TRACE(("Error resolving: %s", gai_strerror(err)));
+ return -1;
+ }
+
+ sock = -1;
+ err = EADDRNOTAVAIL;
+ for (res = res0; res; res = res->ai_next) {
+
+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (sock < 0) {
+ err = errno;
+ continue;
+ }
+
+ if (nonblocking) {
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+ close(sock);
+ sock = -1;
+ if (errstring != NULL && *errstring == NULL) {
+ *errstring = m_strdup("Failed non-blocking");
+ }
+ TRACE(("Failed non-blocking: %s", strerror(errno)));
+ continue;
+ }
+ }
+
+ if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
+ if (errno == EINPROGRESS) {
+ TRACE(("Connect in progress"));
+ break;
+ } else {
+ err = errno;
+ close(sock);
+ sock = -1;
+ continue;
+ }
+ }
+
+ break; /* Success */
+ }
+
+ if (sock < 0) {
+ /* Failed */
+ if (errstring != NULL && *errstring == NULL) {
+ int len;
+ len = 20 + strlen(strerror(err));
+ *errstring = (char*)m_malloc(len);
+ snprintf(*errstring, len, "Error connecting: %s", strerror(err));
+ }
+ 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));
+ }
+
+ freeaddrinfo(res0);
+
+ TRACE(("leave connect_remote: sock %d", sock));
+ return sock;
+}
+
/* Return a string representation of the socket address passed. The return
* value is allocated with malloc() */
unsigned char * getaddrstring(struct sockaddr * addr) {
@@ -304,3 +393,4 @@ void m_burn(void *data, unsigned int len) {
*p++ = 0x66;
}
}
+
diff --git a/dbutil.h b/dbutil.h
index 3da6b2f..49b7466 100644
--- a/dbutil.h
+++ b/dbutil.h
@@ -45,6 +45,8 @@ void printhex(unsigned char* buf, int len);
#endif
char * stripcontrol(const char * text);
unsigned char * getaddrstring(struct sockaddr * addr);
+int connect_remote(const char* remotehost, const char* remoteport,
+ int nonblocking, char ** errstring);
char* getaddrhostname(struct sockaddr * addr);
int buf_readfile(buffer* buf, const char* filename);
@@ -56,4 +58,7 @@ void * m_realloc(void* ptr, size_t size);
void __m_free(void* ptr);
void m_burn(void* data, unsigned int len);
+/* Used to force mp_ints to be initialised */
+#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
+
#endif /* _DBUTIL_H_ */
diff --git a/debug.h b/debug.h
index d619a58..736690a 100644
--- a/debug.h
+++ b/debug.h
@@ -36,7 +36,7 @@
/* Define this to print trace statements - very verbose */
/* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing does not sanitise strings etc */
-#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/kex.h b/kex.h
index 61b022e..e6c8ac1 100644
--- a/kex.h
+++ b/kex.h
@@ -26,17 +26,25 @@
#define _KEX_H_
#include "includes.h"
+#include "algo.h"
void send_msg_kexinit();
void recv_msg_kexinit();
-void send_dh_kex();
-void recv_msg_kexdh_init();
void send_msg_newkeys();
void recv_msg_newkeys();
void kexinitialise();
+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);
-void svr_read_kex();
-void cli_read_kex();
+void read_kex_algos(
+ algo_type*(buf_match_algo)(buffer*buf, algo_type localalgos[],
+ int *goodguess));
+
+void recv_msg_kexdh_init(); // server
+
+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 */
diff --git a/main.c b/main.c
index b9ff7aa..0ef1e62 100644
--- a/main.c
+++ b/main.c
@@ -240,8 +240,10 @@ int main(int argc, char ** argv)
if (m_close(childpipe[0]) == DROPBEAR_FAILURE) {
dropbear_exit("Couldn't close socket");
}
+
/* start the session */
- svr_session(childsock, childpipe[1], &remoteaddr);
+ svr_session(childsock, childpipe[1],
+ getaddrhostname(&remoteaddr));
/* don't return */
assert(0);
}
diff --git a/options.h b/options.h
index c6b552a..3aeac0f 100644
--- a/options.h
+++ b/options.h
@@ -30,7 +30,7 @@
* parts are to allow for commandline -DDROPBEAR_XXX options etc.
******************************************************************/
#define DROPBEAR_SERVER
-/* #define DROPBEAR_CLIENT */
+//#define DROPBEAR_CLIENT
#ifndef DROPBEAR_PORT
#define DROPBEAR_PORT 22
@@ -48,6 +48,7 @@
* perhaps 20% slower for pubkey operations (it is probably worth experimenting
* if you want to use this) */
/*#define NO_FAST_EXPTMOD*/
+#define DROPBEAR_SMALL_CODE
/* Enable X11 Forwarding */
#define ENABLE_X11FWD
@@ -181,7 +182,7 @@
*******************************************************************/
#ifndef DROPBEAR_VERSION
-#define DROPBEAR_VERSION "0.41"
+#define DROPBEAR_VERSION "0.41-and-client"
#endif
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
diff --git a/process-packet.c b/process-packet.c
index 7b73cb7..afa45ef 100644
--- a/process-packet.c
+++ b/process-packet.c
@@ -104,9 +104,11 @@ void process_packet() {
*/
/* check that we aren't expecting a particular packet */
+#if 0
if (cli_ses.expecting && cli_ses.expecting == type) {
cli_ses.expecting = 0;
}
+#endif
}
#endif
diff --git a/session.h b/session.h
index cc8340d..d929c1c 100644
--- a/session.h
+++ b/session.h
@@ -26,6 +26,7 @@
#define _SESSION_H_
#include "includes.h"
+#include "options.h"
#include "buffer.h"
#include "signkey.h"
#include "kex.h"
@@ -38,7 +39,8 @@
extern int sessinitdone; /* Is set to 0 somewhere */
extern int exitflag;
-void common_session_init(int sock);
+void common_session_init(int sock, char* remotehost);
+void session_loop(void(*loophandler)());
void common_session_cleanup();
void checktimeouts();
void session_identification();
@@ -46,10 +48,14 @@ void session_identification();
extern void(*session_remoteclosed)();
/* Server */
-void svr_session(int sock, int childpipe, struct sockaddr *remoteaddr);
+void svr_session(int sock, int childpipe, char *remotehost);
void svr_dropbear_exit(int exitcode, const char* format, va_list param);
void svr_dropbear_log(int priority, const char* format, va_list param);
+/* Client */
+void cli_session(int sock, char *remotehost);
+void cli_dropbear_exit(int exitcode, const char* format, va_list param);
+void cli_dropbear_log(int priority, const char* format, va_list param);
struct key_context {
@@ -85,8 +91,8 @@ struct sshsession {
int sock;
- struct sockaddr *remoteaddr;
unsigned char *remotehost; /* the peer hostname */
+
unsigned char *remoteident;
int maxfd; /* the maximum file descriptor to check with select() */
@@ -166,11 +172,20 @@ struct serversession {
};
+typedef enum {
+ NOTHING,
+ KEXINIT_RCVD,
+ KEXDH_INIT_SENT,
+ KEXDH_REPLY_RCVD,
+} cli_state;
struct clientsession {
+ mp_int *dh_e, *dh_x; /* Used during KEX */
+ cli_state state; /* Used to progress the KEX/auth/channelsession etc */
int something; /* XXX */
+ unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
};
@@ -182,7 +197,7 @@ extern struct serversession svr_ses;
#endif /* DROPBEAR_SERVER */
#ifdef DROPBEAR_CLIENT
-extern struct serversession cli_ses;
+extern struct clientsession cli_ses;
#endif /* DROPBEAR_CLIENT */
#endif /* _SESSION_H_ */
diff --git a/signkey.c b/signkey.c
index c529c8c..5fcdbbf 100644
--- a/signkey.c
+++ b/signkey.c
@@ -45,7 +45,8 @@ sign_key * new_sign_key() {
}
/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
- * type is set to hold the type returned */
+ * type should be set by the caller to specify the type to read, and
+ * on return is set to the type read (useful when type = _ANY) */
int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
unsigned char* ident;
diff --git a/svr-algo.c b/svr-algo.c
index 33b9471..dc6565a 100644
--- a/svr-algo.c
+++ b/svr-algo.c
@@ -16,6 +16,8 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
unsigned int count, i, j;
algo_type * ret = NULL;
+ *goodguess = 0;
+
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
/* Debug this */
@@ -57,8 +59,6 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
/* set if it was a good guess */
if (i == 0 && j == 0) {
*goodguess = 1;
- } else {
- *goodguess = 0;
}
/* set the algo to return */
ret = &localalgos[j];
diff --git a/svr-kex.c b/svr-kex.c
index 4dfa6a7..35b50a6 100644
--- a/svr-kex.c
+++ b/svr-kex.c
@@ -70,87 +70,15 @@ void recv_msg_kexdh_init() {
* See the ietf-secsh-transport draft, section 6, for details */
static void send_msg_kexdh_reply(mp_int *dh_e) {
- mp_int dh_p, dh_q, dh_g, dh_y, dh_f;
- unsigned char randbuf[DH_P_LEN];
- int dh_q_len;
- hash_state hs;
+ mp_int dh_y, dh_f;
TRACE(("enter send_msg_kexdh_reply"));
- m_mp_init_multi(&dh_g, &dh_p, &dh_q, &dh_y, &dh_f, NULL);
+ gen_kexdh_vals(&dh_f, &dh_y);
- /* read the prime and generator*/
- if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
- != MP_OKAY) {
- dropbear_exit("Diffie-Hellman error");
- }
-
- if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
- dropbear_exit("Diffie-Hellman error");
- }
-
- /* calculate q = (p-1)/2 */
- if (mp_sub_d(&dh_p, 1, &dh_y) != MP_OKAY) { /*dh_y is just a temp var here*/
- dropbear_exit("Diffie-Hellman error");
- }
- if (mp_div_2(&dh_y, &dh_q) != MP_OKAY) {
- dropbear_exit("Diffie-Hellman error");
- }
-
- dh_q_len = mp_unsigned_bin_size(&dh_q);
-
- /* calculate our random value dh_y */
- do {
- assert((unsigned int)dh_q_len <= sizeof(randbuf));
- genrandom(randbuf, dh_q_len);
- if (mp_read_unsigned_bin(&dh_y, randbuf, dh_q_len) != MP_OKAY) {
- dropbear_exit("Diffie-Hellman error");
- }
- } while (mp_cmp(&dh_y, &dh_q) == MP_GT || mp_cmp_d(&dh_y, 0) != MP_GT);
-
- /* f = g^y mod p */
- if (mp_exptmod(&dh_g, &dh_y, &dh_p, &dh_f) != MP_OKAY) {
- dropbear_exit("Diffie-Hellman error");
- }
- mp_clear(&dh_g);
-
- /* K = e^y mod p */
- ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int));
- m_mp_init(ses.dh_K);
- if (mp_exptmod(dh_e, &dh_y, &dh_p, ses.dh_K) != MP_OKAY) {
- dropbear_exit("Diffie-Hellman error");
- }
+ kexdh_comb_key(&dh_f, &dh_y, dh_e, svr_opts.hostkey);
+ mp_clear(&dh_y);
- /* clear no longer needed vars */
- mp_clear_multi(&dh_y, &dh_p, &dh_q, NULL);
-
- /* Create the remainder of the hash buffer, to generate the exchange hash */
- /* K_S, the host key */
- buf_put_pub_key(ses.kexhashbuf, svr_opts.hostkey,
- ses.newkeys->algo_hostkey);
- /* e, exchange value sent by the client */
- buf_putmpint(ses.kexhashbuf, dh_e);
- /* f, exchange value sent by the server */
- buf_putmpint(ses.kexhashbuf, &dh_f);
- /* K, the shared secret */
- buf_putmpint(ses.kexhashbuf, ses.dh_K);
-
- /* calculate the hash H to sign */
- sha1_init(&hs);
- buf_setpos(ses.kexhashbuf, 0);
- sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
- ses.kexhashbuf->len);
- sha1_done(&hs, ses.hash);
- buf_free(ses.kexhashbuf);
- ses.kexhashbuf = NULL;
-
- /* first time around, we set the session_id to H */
- if (ses.session_id == NULL) {
- /* create the session_id, this never needs freeing */
- ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
- memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
- }
-
/* we can start creating the kexdh_reply packet */
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_REPLY);
@@ -171,105 +99,3 @@ static void send_msg_kexdh_reply(mp_int *dh_e) {
TRACE(("leave send_msg_kexdh_reply"));
}
-/* read the client's choice of algorithms */
-void svr_read_kex() {
-
- algo_type * algo;
- char * erralgo = NULL;
-
- int goodguess = 0;
- int allgood = 1; /* we AND this with each goodguess and see if its still
- true after */
-
- buf_incrpos(ses.payload, 16); /* start after the cookie */
-
- ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
-
- /* kex_algorithms */
- algo = svr_buf_match_algo(ses.payload, sshkex, &goodguess);
- allgood &= goodguess;
- if (algo == NULL) {
- erralgo = "kex";
- goto error;
- }
- ses.newkeys->algo_kex = algo->val;
-
- /* server_host_key_algorithms */
- algo = svr_buf_match_algo(ses.payload, sshhostkey, &goodguess);
- allgood &= goodguess;
- if (algo == NULL) {
- erralgo = "hostkey";
- goto error;
- }
- ses.newkeys->algo_hostkey = algo->val;
-
- /* encryption_algorithms_client_to_server */
- algo = svr_buf_match_algo(ses.payload, sshciphers, &goodguess);
- if (algo == NULL) {
- erralgo = "enc c->s";
- goto error;
- }
- ses.newkeys->recv_algo_crypt = (struct dropbear_cipher*)algo->data;
-
- /* encryption_algorithms_server_to_client */
- algo = svr_buf_match_algo(ses.payload, sshciphers, &goodguess);
- if (algo == NULL) {
- erralgo = "enc s->c";
- goto error;
- }
- ses.newkeys->trans_algo_crypt = (struct dropbear_cipher*)algo->data;
-
- /* mac_algorithms_client_to_server */
- algo = svr_buf_match_algo(ses.payload, sshhashes, &goodguess);
- if (algo == NULL) {
- erralgo = "mac c->s";
- goto error;
- }
- ses.newkeys->recv_algo_mac = (struct dropbear_hash*)algo->data;
-
- /* mac_algorithms_server_to_client */
- algo = svr_buf_match_algo(ses.payload, sshhashes, &goodguess);
- if (algo == NULL) {
- erralgo = "mac s->c";
- goto error;
- }
- ses.newkeys->trans_algo_mac = (struct dropbear_hash*)algo->data;
-
- /* compression_algorithms_client_to_server */
- algo = svr_buf_match_algo(ses.payload, sshcompress, &goodguess);
- if (algo == NULL) {
- erralgo = "comp c->s";
- goto error;
- }
- ses.newkeys->recv_algo_comp = algo->val;
-
- /* compression_algorithms_server_to_client */
- algo = svr_buf_match_algo(ses.payload, sshcompress, &goodguess);
- if (algo == NULL) {
- erralgo = "comp s->c";
- goto error;
- }
- ses.newkeys->trans_algo_comp = algo->val;
-
- /* languages_client_to_server */
- buf_eatstring(ses.payload);
-
- /* languages_server_to_client */
- buf_eatstring(ses.payload);
-
- /* first_kex_packet_follows */
- if (buf_getbyte(ses.payload)) {
- ses.kexstate.firstfollows = 1;
- /* if the guess wasn't good, we ignore the packet sent */
- if (!allgood) {
- ses.ignorenext = 1;
- }
- }
-
- /* reserved for future extensions */
- buf_getint(ses.payload);
- return;
-
-error:
- dropbear_exit("no matching algo %s", erralgo);
-}
diff --git a/svr-session.c b/svr-session.c
index 927a1c1..cb309fe 100644
--- a/svr-session.c
+++ b/svr-session.c
@@ -50,7 +50,7 @@ static const packettype svr_packettypes[] = {
{SSH_MSG_SERVICE_REQUEST, recv_msg_service_request}, // server
{SSH_MSG_USERAUTH_REQUEST, recv_msg_userauth_request}, //server
{SSH_MSG_KEXINIT, recv_msg_kexinit},
- {SSH_MSG_KEXDH_INIT, recv_msg_kexdh_init},
+ {SSH_MSG_KEXDH_INIT, recv_msg_kexdh_init}, // server
{SSH_MSG_NEWKEYS, recv_msg_newkeys},
{SSH_MSG_CHANNEL_DATA, recv_msg_channel_data},
{SSH_MSG_CHANNEL_WINDOW_ADJUST, recv_msg_channel_window_adjust},
@@ -70,17 +70,12 @@ static const struct ChanType *svr_chantypes[] = {
NULL /* Null termination is mandatory. */
};
-void svr_session(int sock, int childpipe, struct sockaddr* remoteaddr) {
+void svr_session(int sock, int childpipe, char* remotehost) {
- fd_set readfd, writefd;
struct timeval timeout;
- int val;
crypto_init();
- common_session_init(sock);
-
- ses.remoteaddr = remoteaddr;
- ses.remotehost = getaddrhostname(remoteaddr);
+ common_session_init(sock, remotehost);
/* Initialise server specific parts of the session */
svr_ses.childpipe = childpipe;
@@ -111,75 +106,12 @@ void svr_session(int sock, int childpipe, struct sockaddr* remoteaddr) {
/* start off with key exchange */
send_msg_kexinit();
- FD_ZERO(&readfd);
- FD_ZERO(&writefd);
-
- /* main loop, select()s for all sockets in use */
- for(;;) {
-
- timeout.tv_sec = SELECT_TIMEOUT;
- timeout.tv_usec = 0;
- FD_ZERO(&writefd);
- FD_ZERO(&readfd);
- assert(ses.payload == NULL);
- if (ses.sock != -1) {
- FD_SET(ses.sock, &readfd);
- if (!isempty(&ses.writequeue)) {
- FD_SET(ses.sock, &writefd);
- }
- }
-
- /* set up for channels which require reading/writing */
- if (ses.dataallowed) {
- setchannelfds(&readfd, &writefd);
- }
- val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
-
- if (exitflag) {
- dropbear_exit("Terminated by signal");
- }
-
- if (val < 0) {
- if (errno == EINTR) {
- continue;
- } else {
- dropbear_exit("Error in select");
- }
- }
-
- /* check for auth timeout, rekeying required etc */
- checktimeouts();
-
- if (val == 0) {
- /* timeout */
- TRACE(("select timeout"));
- continue;
- }
-
- /* process session socket's incoming/outgoing data */
- if (ses.sock != -1) {
- if (FD_ISSET(ses.sock, &writefd) && !isempty(&ses.writequeue)) {
- write_packet();
- }
-
- if (FD_ISSET(ses.sock, &readfd)) {
- read_packet();
- }
-
- /* Process the decrypted packet. After this, the read buffer
- * will be ready for a new packet */
- if (ses.payload != NULL) {
- process_packet();
- }
- }
+ /* Run the main for loop. NULL is for the dispatcher - only the client
+ * code makes use of it */
+ session_loop(NULL);
- /* process pipes etc for the channels, ses.dataallowed == 0
- * during rekeying ) */
- if (ses.dataallowed) {
- channelio(&readfd, &writefd);
- }
+ /* Not reached */
- } /* for(;;) */
}
/* failure exit - format must be <= 100 chars */
diff --git a/tcpfwd-direct.c b/tcpfwd-direct.c
index b6a2178..b611283 100644
--- a/tcpfwd-direct.c
+++ b/tcpfwd-direct.c
@@ -27,6 +27,7 @@ static int newtcpdirect(struct Channel * channel) {
unsigned int destport;
unsigned char* orighost = NULL;
unsigned int origport;
+ char portstring[6];
int sock;
int len;
int ret = DROPBEAR_FAILURE;
@@ -58,7 +59,8 @@ static int newtcpdirect(struct Channel * channel) {
goto out;
}
- sock = newtcp(desthost, destport);
+ snprintf(portstring, sizeof(portstring), "%d", destport);
+ sock = connect_remote(desthost, portstring, 1, NULL);
if (sock < 0) {
TRACE(("leave newtcpdirect: sock failed"));
goto out;
@@ -86,6 +88,7 @@ out:
* returned will need to be checked for success when it is first written.
* Similarities with OpenSSH's connect_to() are not coincidental.
* Returns -1 on failure */
+#if 0
static int newtcp(const char * host, int port) {
int sock = -1;
@@ -152,4 +155,5 @@ static int newtcp(const char * host, int port) {
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
return sock;
}
+#endif
#endif /* DISABLE_TCPFWD_DIRECT */