From 4f62da0f0d5da78b6c7a0cf507307aeacc8ac842 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 29 Mar 2013 20:44:13 +0800 Subject: [PATCH 01/48] first_kex_packet_follows working, needs tidying --HG-- branch : kexguess --- cli-kex.c | 5 +++-- cli-session.c | 21 ++++++++++++++------- common-kex.c | 34 ++++++++++++++++++++++++++-------- kex.h | 4 +++- session.h | 2 ++ 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/cli-kex.c b/cli-kex.c index 9dadb3c..828af9a 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -42,7 +42,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen); #define MAX_KNOWNHOSTS_LINE 4500 void send_msg_kexdh_init() { - + TRACE(("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, NULL); @@ -53,7 +53,8 @@ void send_msg_kexdh_init() { buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT); buf_putmpint(ses.writepayload, cli_ses.dh_e); encrypt_packet(); - ses.requirenext = SSH_MSG_KEXDH_REPLY; + // XXX fixme + //ses.requirenext = SSH_MSG_KEXDH_REPLY; } /* Handle a diffie-hellman key exchange reply. */ diff --git a/cli-session.c b/cli-session.c index e58fdbd..cc514bb 100644 --- a/cli-session.c +++ b/cli-session.c @@ -109,6 +109,12 @@ void cli_session(int sock_in, int sock_out) { } +static void cli_send_kex_first_guess() { + send_msg_kexdh_init(); + dropbear_log(LOG_INFO, "kexdh_init guess sent"); + //cli_ses.kex_state = KEXDH_INIT_SENT; +} + static void cli_session_init() { cli_ses.state = STATE_NOTHING; @@ -148,6 +154,9 @@ static void cli_session_init() { ses.packettypes = cli_packettypes; ses.isserver = 0; + + ses.send_kex_first_guess = cli_send_kex_first_guess; + } /* This function drives the progress of the session - it initiates KEX, @@ -157,15 +166,13 @@ static void cli_sessionloop() { TRACE(("enter cli_sessionloop")) if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) { - cli_ses.kex_state = KEXINIT_RCVD; - } - - if (cli_ses.kex_state == KEXINIT_RCVD) { - /* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT * negotiation would have failed. */ - send_msg_kexdh_init(); - cli_ses.kex_state = KEXDH_INIT_SENT; + if (!ses.kexstate.our_first_follows_matches) { + dropbear_log(LOG_INFO, "kexdh_init after remote's kexinit"); + send_msg_kexdh_init(); + } + cli_ses.kex_state = KEXDH_INIT_SENT; TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD")) return; } diff --git a/common-kex.c b/common-kex.c index 56b206d..e4b4c02 100644 --- a/common-kex.c +++ b/common-kex.c @@ -131,8 +131,8 @@ void send_msg_kexinit() { /* languages_server_to_client */ buf_putstring(ses.writepayload, "", 0); - /* first_kex_packet_follows - unimplemented for now */ - buf_putbyte(ses.writepayload, 0x00); + /* first_kex_packet_follows */ + buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL)); /* reserved unit32 */ buf_putint(ses.writepayload, 0); @@ -144,9 +144,19 @@ void send_msg_kexinit() { encrypt_packet(); ses.dataallowed = 0; /* don't send other packets during kex */ + ses.kexstate.sentkexinit = 1; + + ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); + + if (ses.send_kex_first_guess) { + ses.newkeys->algo_kex = sshkex[0].val; + ses.newkeys->algo_hostkey = sshhostkey[0].val; + ses.send_kex_first_guess(); + } + TRACE(("DATAALLOWED=0")) TRACE(("-> KEXINIT")) - ses.kexstate.sentkexinit = 1; + } /* *** NOTE regarding (send|recv)_msg_newkeys *** @@ -236,11 +246,13 @@ static void kexinitialise() { ses.kexstate.sentnewkeys = 0; /* first_packet_follows */ - ses.kexstate.firstfollows = 0; + ses.kexstate.them_firstfollows = 0; ses.kexstate.datatrans = 0; ses.kexstate.datarecv = 0; + ses.kexstate.our_first_follows_matches = 0; + ses.kexstate.lastkextime = time(NULL); } @@ -555,7 +567,7 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) { DEF_MP_INT(dh_q); DEF_MP_INT(dh_g); - TRACE(("enter send_msg_kexdh_reply")) + TRACE(("enter gen_kexdh_vals")) m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL); @@ -678,7 +690,7 @@ static void read_kex_algos() { buf_incrpos(ses.payload, 16); /* start after the cookie */ - ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); + memset(ses.newkeys, 0x0, sizeof(*ses.newkeys)); /* kex_algorithms */ algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess); @@ -754,9 +766,10 @@ static void read_kex_algos() { /* languages_server_to_client */ buf_eatstring(ses.payload); - /* first_kex_packet_follows */ + /* their first_kex_packet_follows */ if (buf_getbool(ses.payload)) { - ses.kexstate.firstfollows = 1; + TRACE(("them kex firstfollows. allgood %d", allgood)) + ses.kexstate.them_firstfollows = 1; /* if the guess wasn't good, we ignore the packet sent */ if (!allgood) { ses.ignorenext = 1; @@ -799,6 +812,11 @@ static void read_kex_algos() { /* reserved for future extensions */ buf_getint(ses.payload); + + if (ses.send_kex_first_guess && allgood) { + TRACE(("our_first_follows_matches 1")) + ses.kexstate.our_first_follows_matches = 1; + } return; error: diff --git a/kex.h b/kex.h index c89b0a3..dc5f46b 100644 --- a/kex.h +++ b/kex.h @@ -51,13 +51,15 @@ struct KEXState { unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */ unsigned recvkexinit : 1; - unsigned firstfollows : 1; /* true when first_kex_packet_follows is set */ + unsigned them_firstfollows : 1; /* true when first_kex_packet_follows is set */ unsigned sentnewkeys : 1; /* set once we've send MSG_NEWKEYS (will be cleared once we have also received */ unsigned recvnewkeys : 1; /* set once we've received MSG_NEWKEYS (cleared once we have also sent */ unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed, ie the transport layer has been set up */ + unsigned our_first_follows_matches : 1; + time_t lastkextime; /* time of the last kex */ unsigned int datatrans; /* data transmitted since last kex */ unsigned int datarecv; /* data received since last kex */ diff --git a/session.h b/session.h index 0719e34..6b106f5 100644 --- a/session.h +++ b/session.h @@ -178,6 +178,8 @@ struct sshsession { void(*remoteclosed)(); /* A callback to handle closure of the remote connection */ + void(*send_kex_first_guess)(); + struct AuthState authstate; /* Common amongst client and server, since most struct elements are common */ From 99d9cf500b30c77107bf8477dd55831626f9beaf Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 29 Mar 2013 23:29:48 +0800 Subject: [PATCH 02/48] Add kexguess2 behaviour --HG-- branch : kexguess --- algo.h | 14 ++++++++++++-- cli-algo.c | 32 +++++++++++++++++++++++++++----- common-algo.c | 1 + common-kex.c | 21 ++++++++++++--------- debug.h | 4 ++-- kex.h | 1 + options.h | 4 ++-- session.h | 1 + svr-algo.c | 32 ++++++++++++++++++++++++++++---- 9 files changed, 86 insertions(+), 24 deletions(-) diff --git a/algo.h b/algo.h index ad57037..755cfcd 100644 --- a/algo.h +++ b/algo.h @@ -83,10 +83,20 @@ void crypto_init(); int have_algo(char* algo, size_t algolen, algo_type algos[]); void buf_put_algolist(buffer * buf, algo_type localalgos[]); +enum kexguess2_used { + KEXGUESS2_LOOK, + KEXGUESS2_NO, + KEXGUESS2_YES, +}; + +#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au" +#define KEXGUESS2_ALGO_ID 99 + + algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[], - int *goodguess); + enum kexguess2_used *kexguess2, int *goodguess); algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[], - int *goodguess); + enum kexguess2_used *kexguess2, int *goodguess); #ifdef ENABLE_USER_ALGO_LIST int check_user_algos(const char* user_algo_list, algo_type * algos, diff --git a/cli-algo.c b/cli-algo.c index 09da41a..ec8c541 100644 --- a/cli-algo.c +++ b/cli-algo.c @@ -34,7 +34,7 @@ * that is also on the server's list. */ algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[], - int *goodguess) { + enum kexguess2_used *kexguess2, int *goodguess) { unsigned char * algolist = NULL; unsigned char * remotealgos[MAX_PROPOSED_ALGO]; @@ -42,7 +42,9 @@ algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[], unsigned int count, i, j; algo_type * ret = NULL; - *goodguess = 0; + if (goodguess) { + *goodguess = 0; + } /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */ algolist = buf_getstring(buf, &len); @@ -72,6 +74,19 @@ algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[], } } + if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) { + for (i = 0; i < count; i++) + { + if (strcmp(remotealgos[i], KEXGUESS2_ALGO_NAME) == 0) { + *kexguess2 = KEXGUESS2_YES; + break; + } + } + if (*kexguess2 == KEXGUESS2_LOOK) { + *kexguess2 = KEXGUESS2_NO; + } + } + /* iterate and find the first match */ for (j = 0; localalgos[j].name != NULL; j++) { @@ -81,9 +96,16 @@ 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; + if (goodguess && kexguess2) { + if (*kexguess2 == KEXGUESS2_YES) { + if (j == 0) { + *goodguess = 1; + } + } else { + if (i == 0 && j == 0) { + *goodguess = 1; + } + } } ret = &localalgos[j]; goto out; diff --git a/common-algo.c b/common-algo.c index 4a14651..46dbe74 100644 --- a/common-algo.c +++ b/common-algo.c @@ -215,6 +215,7 @@ algo_type sshhostkey[] = { algo_type sshkex[] = { {"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL}, {"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL}, + {KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL}, {NULL, 0, NULL, 0, NULL} }; diff --git a/common-kex.c b/common-kex.c index e4b4c02..0640b9f 100644 --- a/common-kex.c +++ b/common-kex.c @@ -692,18 +692,21 @@ static void read_kex_algos() { memset(ses.newkeys, 0x0, sizeof(*ses.newkeys)); + enum kexguess2_used kexguess2 = KEXGUESS2_LOOK; + /* kex_algorithms */ - algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess); allgood &= goodguess; - if (algo == NULL) { + if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) { erralgo = "kex"; goto error; } + TRACE(("kexguess2 %d", kexguess2)) TRACE(("kex algo %s", algo->name)) ses.newkeys->algo_kex = algo->val; /* server_host_key_algorithms */ - algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess); allgood &= goodguess; if (algo == NULL) { erralgo = "hostkey"; @@ -713,7 +716,7 @@ static void read_kex_algos() { ses.newkeys->algo_hostkey = algo->val; /* encryption_algorithms_client_to_server */ - c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess); + c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, NULL, NULL); if (c2s_cipher_algo == NULL) { erralgo = "enc c->s"; goto error; @@ -721,7 +724,7 @@ static void read_kex_algos() { 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); + s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, NULL, NULL); if (s2c_cipher_algo == NULL) { erralgo = "enc s->c"; goto error; @@ -729,7 +732,7 @@ static void read_kex_algos() { 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); + c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, NULL, NULL); if (c2s_hash_algo == NULL) { erralgo = "mac c->s"; goto error; @@ -737,7 +740,7 @@ static void read_kex_algos() { 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); + s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, NULL, NULL); if (s2c_hash_algo == NULL) { erralgo = "mac s->c"; goto error; @@ -745,7 +748,7 @@ static void read_kex_algos() { TRACE(("hash s2c is %s", s2c_hash_algo->name)) /* compression_algorithms_client_to_server */ - c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess); + c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); if (c2s_comp_algo == NULL) { erralgo = "comp c->s"; goto error; @@ -753,7 +756,7 @@ static void read_kex_algos() { TRACE(("hash c2s is %s", c2s_comp_algo->name)) /* compression_algorithms_server_to_client */ - s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess); + s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); if (s2c_comp_algo == NULL) { erralgo = "comp s->c"; goto error; diff --git a/debug.h b/debug.h index b20e685..02c100f 100644 --- a/debug.h +++ b/debug.h @@ -39,7 +39,7 @@ * Caution: Don't use this in an unfriendly environment (ie unfirewalled), * since the printing may not sanitise strings etc. This will add a reasonable * amount to your executable size. */ -/*#define DEBUG_TRACE */ +#define DEBUG_TRACE /* All functions writing to the cleartext payload buffer call * CHECKCLEARTOWRITE() before writing. This is only really useful if you're @@ -69,7 +69,7 @@ /* To debug with GDB it is easier to run with no forking of child processes. You will need to pass "-F" as well. */ -/* #define DEBUG_NOFORK */ +#define DEBUG_NOFORK /* For testing as non-root on shadowed systems, include the crypt of a password diff --git a/kex.h b/kex.h index dc5f46b..72430e9 100644 --- a/kex.h +++ b/kex.h @@ -66,6 +66,7 @@ struct KEXState { }; + #define MAX_KEXHASHBUF 2000 #endif /* _KEX_H_ */ diff --git a/options.h b/options.h index c52d6c2..71d39cc 100644 --- a/options.h +++ b/options.h @@ -174,9 +174,9 @@ much traffic. */ * PAM challenge/response. * You can't enable both PASSWORD and PAM. */ -#define ENABLE_SVR_PASSWORD_AUTH +//#define ENABLE_SVR_PASSWORD_AUTH /* PAM requires ./configure --enable-pam */ -/*#define ENABLE_SVR_PAM_AUTH*/ +#define ENABLE_SVR_PAM_AUTH #define ENABLE_SVR_PUBKEY_AUTH /* Whether to take public key options in diff --git a/session.h b/session.h index 6b106f5..3b9e957 100644 --- a/session.h +++ b/session.h @@ -170,6 +170,7 @@ struct sshsession { struct packetlist *reply_queue_head, *reply_queue_tail; algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[], + enum kexguess2_used *kexguess2, int *goodguess); /* The function to use to choose which algorithm to use from the ones presented by the remote side. Is specific to the client/server mode, diff --git a/svr-algo.c b/svr-algo.c index f8f9055..620cfeb 100644 --- a/svr-algo.c +++ b/svr-algo.c @@ -33,7 +33,7 @@ * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are * guessed correctly */ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[], - int *goodguess) + enum kexguess2_used *kexguess2, int *goodguess) { unsigned char * algolist = NULL; @@ -42,7 +42,9 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[], unsigned int count, i, j; algo_type * ret = NULL; - *goodguess = 0; + if (goodguess) { + *goodguess = 0; + } /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */ algolist = buf_getstring(buf, &len); @@ -73,6 +75,19 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[], } } + if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) { + for (i = 0; i < count; i++) + { + if (strcmp(remotealgos[i], KEXGUESS2_ALGO_NAME) == 0) { + *kexguess2 = KEXGUESS2_YES; + break; + } + } + if (*kexguess2 == KEXGUESS2_LOOK) { + *kexguess2 = KEXGUESS2_NO; + } + } + /* iterate and find the first match */ for (i = 0; i < count; i++) { @@ -83,8 +98,17 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[], if (len == strlen(localalgos[j].name) && strncmp(localalgos[j].name, remotealgos[i], len) == 0) { /* set if it was a good guess */ - if (i == 0 && j == 0) { - *goodguess = 1; + if (goodguess && kexguess2) { + if (*kexguess2 == KEXGUESS2_YES) { + if (i == 0) { + *goodguess = 1; + } + + } else { + if (i == 0 && j == 0) { + *goodguess = 1; + } + } } /* set the algo to return */ ret = &localalgos[j]; From 9c7485331a581d1ff32f9caf005e7b13fa1c051e Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sat, 30 Mar 2013 23:55:05 +0800 Subject: [PATCH 03/48] Get rid of client/server specific buf_match_algo, use single function with a couple of if statements instead --HG-- branch : kexguess --- Makefile.in | 4 +- algo.h | 4 +- cli-algo.c | 121 ------------------------------------------------ cli-session.c | 1 - common-algo.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++ common-kex.c | 16 +++---- session.h | 7 --- svr-algo.c | 124 -------------------------------------------------- svr-session.c | 1 - 9 files changed, 128 insertions(+), 267 deletions(-) delete mode 100644 cli-algo.c delete mode 100644 svr-algo.c diff --git a/Makefile.in b/Makefile.in index cec35f1..108566c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -28,12 +28,12 @@ COMMONOBJS=dbutil.o buffer.o \ queue.o \ atomicio.o compat.o fake-rfc2553.o -SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ +SVROBJS=svr-kex.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \ svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\ svr-tcpfwd.o svr-authpam.o -CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ +CLIOBJS=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-authinteract.o \ cli-agentfwd.o list.o diff --git a/algo.h b/algo.h index 755cfcd..ad40c0d 100644 --- a/algo.h +++ b/algo.h @@ -93,9 +93,7 @@ enum kexguess2_used { #define KEXGUESS2_ALGO_ID 99 -algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[], - enum kexguess2_used *kexguess2, int *goodguess); -algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[], +algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], enum kexguess2_used *kexguess2, int *goodguess); #ifdef ENABLE_USER_ALGO_LIST diff --git a/cli-algo.c b/cli-algo.c deleted file mode 100644 index ec8c541..0000000 --- a/cli-algo.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Dropbear - a SSH2 server - * SSH client implementation - * - * Copyright (c) 2002,2003 Matt Johnston - * Copyright (c) 2004 by Mihnea Stoenescu - * 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 "algo.h" -#include "dbutil.h" - - -/* - * The chosen [encryption | MAC | compression] algorithm to each - * 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[], - enum kexguess2_used *kexguess2, int *goodguess) { - - unsigned char * algolist = NULL; - unsigned char * remotealgos[MAX_PROPOSED_ALGO]; - unsigned int len; - unsigned int count, i, j; - algo_type * ret = NULL; - - if (goodguess) { - *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)) - if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) { - goto out; /* just a sanity check, no other use */ - } - - /* remotealgos will contain a list of the strings parsed out */ - /* We will have at least one string (even if it's just "") */ - remotealgos[0] = algolist; - count = 1; - /* Iterate through, replacing ','s with NULs, to split it into - * words. */ - for (i = 0; i < len; i++) { - if (algolist[i] == '\0') { - /* someone is trying something strange */ - goto out; - } - if (algolist[i] == ',') { - algolist[i] = '\0'; - remotealgos[count] = &algolist[i+1]; - count++; - } - if (count >= MAX_PROPOSED_ALGO) { - break; - } - } - - if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) { - for (i = 0; i < count; i++) - { - if (strcmp(remotealgos[i], KEXGUESS2_ALGO_NAME) == 0) { - *kexguess2 = KEXGUESS2_YES; - break; - } - } - if (*kexguess2 == KEXGUESS2_LOOK) { - *kexguess2 = KEXGUESS2_NO; - } - } - - /* iterate and find the first match */ - - for (j = 0; localalgos[j].name != NULL; j++) { - if (localalgos[j].usable) { - len = strlen(localalgos[j].name); - for (i = 0; i < count; i++) { - if (len == strlen(remotealgos[i]) - && strncmp(localalgos[j].name, - remotealgos[i], len) == 0) { - if (goodguess && kexguess2) { - if (*kexguess2 == KEXGUESS2_YES) { - if (j == 0) { - *goodguess = 1; - } - } else { - if (i == 0 && j == 0) { - *goodguess = 1; - } - } - } - ret = &localalgos[j]; - goto out; - } - } - } - } - -out: - m_free(algolist); - return ret; -} - diff --git a/cli-session.c b/cli-session.c index cc514bb..590bfcc 100644 --- a/cli-session.c +++ b/cli-session.c @@ -148,7 +148,6 @@ static void cli_session_init() { /* For printing "remote host closed" for the user */ ses.remoteclosed = cli_remoteclosed; - ses.buf_match_algo = cli_buf_match_algo; /* packet handlers */ ses.packettypes = cli_packettypes; diff --git a/common-algo.c b/common-algo.c index 46dbe74..8267852 100644 --- a/common-algo.c +++ b/common-algo.c @@ -24,6 +24,7 @@ * SOFTWARE. */ #include "algo.h" +#include "session.h" #include "dbutil.h" /* This file (algo.c) organises the ciphers which can be used, and is used to @@ -308,6 +309,122 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) { buf_free(algolist); } +/* match the first algorithm in the comma-separated list in buf which is + * also in localalgos[], or return NULL on failure. + * (*goodguess) is set to 1 if the preferred client/server algos match, + * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are + * guessed correctly */ +algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], + enum kexguess2_used *kexguess2, int *goodguess) +{ + + unsigned char * algolist = NULL; + const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO]; + unsigned int len; + unsigned int remotecount, localcount, clicount, servcount, i, j; + algo_type * ret = NULL; + const unsigned char **clinames, **servnames; + + if (goodguess) { + *goodguess = 0; + } + + /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */ + algolist = buf_getstring(buf, &len); + TRACE(("buf_match_algo: %s", algolist)) + if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) { + goto out; + } + + /* remotenames will contain a list of the strings parsed out */ + /* We will have at least one string (even if it's just "") */ + remotenames[0] = algolist; + remotecount = 1; + for (i = 0; i < len; i++) { + if (algolist[i] == '\0') { + /* someone is trying something strange */ + goto out; + } + if (algolist[i] == ',') { + algolist[i] = '\0'; + remotenames[remotecount] = &algolist[i+1]; + remotecount++; + } + if (remotecount >= MAX_PROPOSED_ALGO) { + break; + } + } + if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) { + for (i = 0; i < remotecount; i++) + { + if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) { + *kexguess2 = KEXGUESS2_YES; + break; + } + } + if (*kexguess2 == KEXGUESS2_LOOK) { + *kexguess2 = KEXGUESS2_NO; + } + } + + for (i = 0; localalgos[i].name != NULL; i++) { + if (localalgos[i].usable) { + localnames[i] = localalgos[i].name; + } else { + localnames[i] = NULL; + } + } + localcount = i; + + if (IS_DROPBEAR_SERVER) { + clinames = remotenames; + clicount = remotecount; + servnames = localnames; + servcount = localcount; + } else { + clinames = localnames; + clicount = localcount; + servnames = remotenames; + servcount = remotecount; + } + + /* iterate and find the first match */ + for (i = 0; i < clicount; i++) { + for (j = 0; j < servcount; j++) { + if (!(servnames[j] && clinames[i])) { + // unusable algos are NULL + continue; + } + if (strcmp(servnames[j], clinames[i]) == 0) { + /* set if it was a good guess */ + if (goodguess && kexguess2) { + if (*kexguess2 == KEXGUESS2_YES) { + if (i == 0) { + *goodguess = 1; + } + + } else { + if (i == 0 && j == 0) { + *goodguess = 1; + } + } + } + /* set the algo to return */ + if (IS_DROPBEAR_SERVER) { + ret = &localalgos[j]; + } else { + ret = &localalgos[i]; + } + goto out; + } + } + } + +out: + m_free(algolist); + return ret; +} + #ifdef DROPBEAR_NONE_CIPHER void diff --git a/common-kex.c b/common-kex.c index 0640b9f..eb1fd7b 100644 --- a/common-kex.c +++ b/common-kex.c @@ -695,7 +695,7 @@ static void read_kex_algos() { enum kexguess2_used kexguess2 = KEXGUESS2_LOOK; /* kex_algorithms */ - algo = ses.buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess); + algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess); allgood &= goodguess; if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) { erralgo = "kex"; @@ -706,7 +706,7 @@ static void read_kex_algos() { ses.newkeys->algo_kex = algo->val; /* server_host_key_algorithms */ - algo = ses.buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess); + algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess); allgood &= goodguess; if (algo == NULL) { erralgo = "hostkey"; @@ -716,7 +716,7 @@ static void read_kex_algos() { ses.newkeys->algo_hostkey = algo->val; /* encryption_algorithms_client_to_server */ - c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, NULL, NULL); + c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL); if (c2s_cipher_algo == NULL) { erralgo = "enc c->s"; goto error; @@ -724,7 +724,7 @@ static void read_kex_algos() { TRACE(("enc c2s is %s", c2s_cipher_algo->name)) /* encryption_algorithms_server_to_client */ - s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, NULL, NULL); + s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL); if (s2c_cipher_algo == NULL) { erralgo = "enc s->c"; goto error; @@ -732,7 +732,7 @@ static void read_kex_algos() { TRACE(("enc s2c is %s", s2c_cipher_algo->name)) /* mac_algorithms_client_to_server */ - c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, NULL, NULL); + c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL); if (c2s_hash_algo == NULL) { erralgo = "mac c->s"; goto error; @@ -740,7 +740,7 @@ static void read_kex_algos() { TRACE(("hash c2s is %s", c2s_hash_algo->name)) /* mac_algorithms_server_to_client */ - s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, NULL, NULL); + s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL); if (s2c_hash_algo == NULL) { erralgo = "mac s->c"; goto error; @@ -748,7 +748,7 @@ static void read_kex_algos() { TRACE(("hash s2c is %s", s2c_hash_algo->name)) /* compression_algorithms_client_to_server */ - c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); + c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); if (c2s_comp_algo == NULL) { erralgo = "comp c->s"; goto error; @@ -756,7 +756,7 @@ static void read_kex_algos() { TRACE(("hash c2s is %s", c2s_comp_algo->name)) /* compression_algorithms_server_to_client */ - s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); + s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); if (s2c_comp_algo == NULL) { erralgo = "comp s->c"; goto error; diff --git a/session.h b/session.h index 3b9e957..8e71bdc 100644 --- a/session.h +++ b/session.h @@ -169,13 +169,6 @@ struct sshsession { concluded (ie, while dataallowed was unset)*/ struct packetlist *reply_queue_head, *reply_queue_tail; - algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[], - enum kexguess2_used *kexguess2, - int *goodguess); /* The function to use to choose which algorithm - to use from the ones presented by the remote - side. Is specific to the client/server mode, - hence the function-pointer callback.*/ - void(*remoteclosed)(); /* A callback to handle closure of the remote connection */ diff --git a/svr-algo.c b/svr-algo.c deleted file mode 100644 index 620cfeb..0000000 --- a/svr-algo.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Dropbear - a SSH2 server - * SSH client implementation - * - * Copyright (c) 2002,2003 Matt Johnston - * Copyright (c) 2004 by Mihnea Stoenescu - * 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 "algo.h" -#include "dbutil.h" - -/* match the first algorithm in the comma-separated list in buf which is - * also in localalgos[], or return NULL on failure. - * (*goodguess) is set to 1 if the preferred client/server algos match, - * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are - * guessed correctly */ -algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[], - enum kexguess2_used *kexguess2, int *goodguess) -{ - - unsigned char * algolist = NULL; - unsigned char * remotealgos[MAX_PROPOSED_ALGO]; - unsigned int len; - unsigned int count, i, j; - algo_type * ret = NULL; - - if (goodguess) { - *goodguess = 0; - } - - /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */ - algolist = buf_getstring(buf, &len); - /* Debug this */ - TRACE(("buf_match_algo: %s", algolist)) - if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) { - goto out; /* just a sanity check, no other use */ - } - - /* remotealgos will contain a list of the strings parsed out */ - /* We will have at least one string (even if it's just "") */ - remotealgos[0] = algolist; - count = 1; - /* Iterate through, replacing ','s with NULs, to split it into - * words. */ - for (i = 0; i < len; i++) { - if (algolist[i] == '\0') { - /* someone is trying something strange */ - goto out; - } - if (algolist[i] == ',') { - algolist[i] = '\0'; - remotealgos[count] = &algolist[i+1]; - count++; - } - if (count >= MAX_PROPOSED_ALGO) { - break; - } - } - - if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) { - for (i = 0; i < count; i++) - { - if (strcmp(remotealgos[i], KEXGUESS2_ALGO_NAME) == 0) { - *kexguess2 = KEXGUESS2_YES; - break; - } - } - if (*kexguess2 == KEXGUESS2_LOOK) { - *kexguess2 = KEXGUESS2_NO; - } - } - - /* iterate and find the first match */ - for (i = 0; i < count; i++) { - - len = strlen(remotealgos[i]); - - for (j = 0; localalgos[j].name != NULL; j++) { - if (localalgos[j].usable) { - if (len == strlen(localalgos[j].name) && - strncmp(localalgos[j].name, remotealgos[i], len) == 0) { - /* set if it was a good guess */ - if (goodguess && kexguess2) { - if (*kexguess2 == KEXGUESS2_YES) { - if (i == 0) { - *goodguess = 1; - } - - } else { - if (i == 0 && j == 0) { - *goodguess = 1; - } - } - } - /* set the algo to return */ - ret = &localalgos[j]; - goto out; - } - } - } - } - -out: - m_free(algolist); - return ret; -} diff --git a/svr-session.c b/svr-session.c index cf82289..a564525 100644 --- a/svr-session.c +++ b/svr-session.c @@ -106,7 +106,6 @@ void svr_session(int sock, int childpipe) { /* packet handlers */ ses.packettypes = svr_packettypes; - ses.buf_match_algo = svr_buf_match_algo; ses.isserver = 1; From a0e931005b6f9de407ba2ac5b5df9e34d4a7fb7e Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 31 Mar 2013 00:40:00 +0800 Subject: [PATCH 04/48] send out our kexinit packet before blocking to read the SSH version string --- cli-session.c | 2 +- common-session.c | 29 +++++++++++++++++++---------- session.h | 7 +++++-- svr-session.c | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/cli-session.c b/cli-session.c index e58fdbd..f862bc8 100644 --- a/cli-session.c +++ b/cli-session.c @@ -99,7 +99,7 @@ void cli_session(int sock_in, int sock_out) { sessinitdone = 1; /* Exchange identification */ - session_identification(); + send_session_identification(); send_msg_kexinit(); diff --git a/common-session.c b/common-session.c index f4fa579..ec5c9ed 100644 --- a/common-session.c +++ b/common-session.c @@ -39,6 +39,7 @@ static void checktimeouts(); static long select_timeout(); static int ident_readln(int fd, char* buf, int count); +static void read_session_identification(); struct sshsession ses; /* GLOBAL */ @@ -141,7 +142,10 @@ void session_loop(void(*loophandler)()) { FD_ZERO(&writefd); FD_ZERO(&readfd); dropbear_assert(ses.payload == NULL); - if (ses.sock_in != -1) { + + /* during initial setup we flush out the KEXINIT packet before + * attempting to read the remote version string, which might block */ + if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) { FD_SET(ses.sock_in, &readfd); } if (ses.sock_out != -1 && !isempty(&ses.writequeue)) { @@ -195,7 +199,12 @@ void session_loop(void(*loophandler)()) { if (ses.sock_in != -1) { if (FD_ISSET(ses.sock_in, &readfd)) { - read_packet(); + if (!ses.remoteident) { + /* blocking read of the version string */ + read_session_identification(); + } else { + read_packet(); + } } /* Process the decrypted packet. After this, the read buffer @@ -245,20 +254,20 @@ void common_session_cleanup() { } -void session_identification() { - - /* max length of 255 chars */ - char linebuf[256]; - int len = 0; - char done = 0; - int i; - +void send_session_identification() { /* write our version string, this blocks */ if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) { ses.remoteclosed(); } +} +static void read_session_identification() { + /* max length of 255 chars */ + char linebuf[256]; + int len = 0; + char done = 0; + int i; /* If they send more than 50 lines, something is wrong */ for (i = 0; i < 50; i++) { len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf)); diff --git a/session.h b/session.h index 0719e34..d524226 100644 --- a/session.h +++ b/session.h @@ -45,7 +45,7 @@ extern int exitflag; void common_session_init(int sock_in, int sock_out); void session_loop(void(*loophandler)()); void common_session_cleanup(); -void session_identification(); +void send_session_identification(); void send_msg_ignore(); const char* get_user_shell(); @@ -111,7 +111,10 @@ struct sshsession { int sock_in; int sock_out; - unsigned char *remoteident; + /* remotehost will be initially NULL as we delay + * reading the remote version string. it will be set + * by the time any recv_() packet methods are called */ + unsigned char *remoteident; int maxfd; /* the maximum file descriptor to check with select() */ diff --git a/svr-session.c b/svr-session.c index cf82289..7234f4a 100644 --- a/svr-session.c +++ b/svr-session.c @@ -114,7 +114,7 @@ void svr_session(int sock, int childpipe) { sessinitdone = 1; /* exchange identification, version etc */ - session_identification(); + send_session_identification(); /* start off with key exchange */ send_msg_kexinit(); From 36526700a983e09e77f03e404f207d6fbc220306 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 31 Mar 2013 21:38:17 +0800 Subject: [PATCH 05/48] Don't bother waiting for a ssh-connection service reply - the server will disconnect if it wasn't accepted --- Makefile.in | 2 +- cli-service.c | 85 --------------------------------------------------- cli-session.c | 24 +++++++++++---- service.h | 2 -- session.h | 4 --- 5 files changed, 19 insertions(+), 98 deletions(-) delete mode 100644 cli-service.c diff --git a/Makefile.in b/Makefile.in index cec35f1..8e1ba52 100644 --- a/Makefile.in +++ b/Makefile.in @@ -34,7 +34,7 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-tcpfwd.o svr-authpam.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-session.o cli-runopts.o cli-chansession.o \ cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \ cli-agentfwd.o list.o diff --git a/cli-service.c b/cli-service.c deleted file mode 100644 index f763103..0000000 --- a/cli-service.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Dropbear SSH - * - * Copyright (c) 2002,2003 Matt Johnston - * Copyright (c) 2004 by Mihnea Stoenescu - * 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 "service.h" -#include "dbutil.h" -#include "packet.h" -#include "buffer.h" -#include "session.h" -#include "ssh.h" - -void send_msg_service_request(char* servicename) { - - TRACE(("enter send_msg_service_request: servicename='%s'", servicename)) - - CHECKCLEARTOWRITE(); - - buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST); - buf_putstring(ses.writepayload, servicename, strlen(servicename)); - - encrypt_packet(); - TRACE(("leave send_msg_service_request")) -} - -/* This just sets up the state variables right for the main client session loop - * to deal with */ -void recv_msg_service_accept() { - - unsigned char* servicename; - unsigned int len; - - TRACE(("enter recv_msg_service_accept")) - - servicename = buf_getstring(ses.payload, &len); - - /* ssh-userauth */ - if (cli_ses.state == SERVICE_AUTH_REQ_SENT - && len == SSH_SERVICE_USERAUTH_LEN - && strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) { - - cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD; - m_free(servicename); - TRACE(("leave recv_msg_service_accept: done ssh-userauth")) - return; - } - - /* ssh-connection */ - if (cli_ses.state == SERVICE_CONN_REQ_SENT - && len == SSH_SERVICE_CONNECTION_LEN - && strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) { - - if (ses.authstate.authdone != 1) { - dropbear_exit("Request for connection before auth"); - } - - cli_ses.state = SERVICE_CONN_ACCEPT_RCVD; - m_free(servicename); - TRACE(("leave recv_msg_service_accept: done ssh-connection")) - return; - } - - dropbear_exit("Unrecognised service accept"); -} diff --git a/cli-session.c b/cli-session.c index f862bc8..81aa8c9 100644 --- a/cli-session.c +++ b/cli-session.c @@ -41,6 +41,7 @@ static void cli_remoteclosed(); static void cli_sessionloop(); static void cli_session_init(); static void cli_finished(); +static void recv_msg_service_accept(void); struct clientsession cli_ses; /* GLOBAL */ @@ -150,6 +151,23 @@ static void cli_session_init() { ses.isserver = 0; } +static void send_msg_service_request(char* servicename) { + + TRACE(("enter send_msg_service_request: servicename='%s'", servicename)) + + CHECKCLEARTOWRITE(); + + buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST); + buf_putstring(ses.writepayload, servicename, strlen(servicename)); + + encrypt_packet(); + TRACE(("leave send_msg_service_request")) +} + +static void recv_msg_service_accept(void) { + // do nothing, if it failed then the server MUST have disconnected +} + /* This function drives the progress of the session - it initiates KEX, * service, userauth and channel requests */ static void cli_sessionloop() { @@ -195,12 +213,6 @@ static void cli_sessionloop() { /* We've got the transport layer sorted, we now need to request * userauth */ send_msg_service_request(SSH_SERVICE_USERAUTH); - cli_ses.state = SERVICE_AUTH_REQ_SENT; - TRACE(("leave cli_sessionloop: sent userauth service req")) - return; - - /* userauth code */ - case SERVICE_AUTH_ACCEPT_RCVD: cli_auth_getmethods(); cli_ses.state = USERAUTH_REQ_SENT; TRACE(("leave cli_sessionloop: sent userauth methods req")) diff --git a/service.h b/service.h index 197d8d1..9c60c09 100644 --- a/service.h +++ b/service.h @@ -26,7 +26,5 @@ #define _SERVICE_H_ void recv_msg_service_request(); /* Server */ -void send_msg_service_request(); /* Client */ -void recv_msg_service_accept(); /* Client */ #endif /* _SERVICE_H_ */ diff --git a/session.h b/session.h index d524226..39104a3 100644 --- a/session.h +++ b/session.h @@ -236,10 +236,6 @@ typedef enum { typedef enum { STATE_NOTHING, - SERVICE_AUTH_REQ_SENT, - SERVICE_AUTH_ACCEPT_RCVD, - SERVICE_CONN_REQ_SENT, - SERVICE_CONN_ACCEPT_RCVD, USERAUTH_REQ_SENT, USERAUTH_FAIL_RCVD, USERAUTH_SUCCESS_RCVD, From f6b304250bda59f7dcc56ffa7c4c5f482e66d32f Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 31 Mar 2013 23:15:35 +0800 Subject: [PATCH 06/48] Try using writev() for writing packets out to tcp --- configure.ac | 4 ++-- includes.h | 4 ++++ packet.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++------ queue.h | 2 +- 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 3b82bb7..05461f3 100644 --- a/configure.ac +++ b/configure.ac @@ -211,7 +211,7 @@ AC_ARG_ENABLE(shadow, # 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 netinet/in_systm.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, sys/uio.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -616,7 +616,7 @@ AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL -AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork]) +AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev]) AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME)) diff --git a/includes.h b/includes.h index 571a3be..203ccfd 100644 --- a/includes.h +++ b/includes.h @@ -120,6 +120,10 @@ #include #endif +#ifdef HAVE_SYS_UIO_H +#include +#endif + #ifdef BUNDLED_LIBTOM #include "libtomcrypt/src/headers/tomcrypt.h" #include "libtommath/tommath.h" diff --git a/packet.c b/packet.c index f979cae..5cd60c2 100644 --- a/packet.c +++ b/packet.c @@ -55,10 +55,60 @@ void write_packet() { buffer * writebuf = NULL; time_t now; unsigned packet_type; + int all_ignore = 1; +#ifdef HAVE_WRITEV + struct iovec *iov = NULL; + int i; + struct Link *l; +#endif TRACE(("enter write_packet")) dropbear_assert(!isempty(&ses.writequeue)); +#ifdef HAVE_WRITEV + iov = m_malloc(sizeof(*iov) * ses.writequeue.count); + for (l = ses.writequeue.head, i = 0; l; l = l->link, i++) + { + writebuf = (buffer*)l->item; + packet_type = writebuf->data[writebuf->len-1]; + len = writebuf->len - 1 - writebuf->pos; + dropbear_assert(len > 0); + all_ignore &= (packet_type == SSH_MSG_IGNORE); + iov[i].iov_base = buf_getptr(writebuf, len); + iov[i].iov_len = len; + } + written = writev(ses.sock_out, iov, ses.writequeue.count); + if (written < 0) { + if (errno == EINTR) { + m_free(iov); + TRACE(("leave writepacket: EINTR")) + return; + } else { + dropbear_exit("Error writing"); + } + } + + if (written == 0) { + ses.remoteclosed(); + } + + while (written > 0) { + writebuf = (buffer*)examine(&ses.writequeue); + len = writebuf->len - 1 - writebuf->pos; + if (len > written) { + // partial buffer write + buf_incrpos(writebuf, written); + written = 0; + } else { + written -= len; + dequeue(&ses.writequeue); + buf_free(writebuf); + } + } + + m_free(iov); + +#else /* Get the next buffer in the queue of encrypted packets to write*/ writebuf = (buffer*)examine(&ses.writequeue); @@ -78,13 +128,7 @@ void write_packet() { dropbear_exit("Error writing"); } } - - now = time(NULL); - ses.last_trx_packet_time = now; - - if (packet_type != SSH_MSG_IGNORE) { - ses.last_packet_time = now; - } + all_ignore = (packet_type == SSH_MSG_IGNORE); if (written == 0) { ses.remoteclosed(); @@ -100,6 +144,14 @@ void write_packet() { buf_incrpos(writebuf, written); } +#endif + now = time(NULL); + ses.last_trx_packet_time = now; + + if (!all_ignore) { + ses.last_packet_time = now; + } + TRACE(("leave write_packet")) } diff --git a/queue.h b/queue.h index 80fbb9d..8cffab7 100644 --- a/queue.h +++ b/queue.h @@ -36,7 +36,7 @@ struct Queue { struct Link* head; struct Link* tail; - unsigned int count; /* safety value */ + unsigned int count; }; From 5abe22d1a514d1f98f88927a23701b51bd7c134e Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 31 Mar 2013 23:29:03 +0800 Subject: [PATCH 07/48] Fix incorrect logic for USE_VFORK and calling arg_setup() --- scp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scp.c b/scp.c index 8715726..114d095 100644 --- a/scp.c +++ b/scp.c @@ -230,7 +230,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) close(pin[0]); close(pout[1]); -#ifdef USE_VFORK +#ifndef USE_VFORK arg_setup(host, remuser, cmd); #endif From 484516da516037d37747319e9b7cff91bffb6a4a Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 31 Mar 2013 23:48:25 +0800 Subject: [PATCH 08/48] Send an auth packet straight away, save another roundtrip This needs a bit of testing to make sure it doesn't have side-effects. --- cli-auth.c | 9 +++++---- sysoptions.h | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cli-auth.c b/cli-auth.c index 321cbf3..7dc101f 100644 --- a/cli-auth.c +++ b/cli-auth.c @@ -40,11 +40,12 @@ void cli_authinitialise() { /* Send a "none" auth request to get available methods */ void cli_auth_getmethods() { - TRACE(("enter cli_auth_getmethods")) - +#ifdef CLI_IMMEDIATE_AUTH + ses.authstate.authtypes = AUTH_TYPE_PUBKEY | AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT; + cli_auth_try(); +#else CHECKCLEARTOWRITE(); - buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); buf_putstring(ses.writepayload, cli_opts.username, strlen(cli_opts.username)); @@ -53,8 +54,8 @@ void cli_auth_getmethods() { buf_putstring(ses.writepayload, "none", 4); /* 'none' method */ encrypt_packet(); +#endif TRACE(("leave cli_auth_getmethods")) - } void recv_msg_userauth_banner() { diff --git a/sysoptions.h b/sysoptions.h index 8c591ea..6e60294 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -188,6 +188,9 @@ #define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */ #endif +/* Send an auth request straight away rather than trying "none" type to get a list */ +#define CLI_IMMEDIATE_AUTH + /* Changing this is inadvisable, it appears to have problems * with flushing compressed data */ #define DROPBEAR_ZLIB_MEM_LEVEL 8 From 90cf7f012cdc6143752464bc9bb2b4a9f94f7132 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 1 Apr 2013 00:07:26 +0800 Subject: [PATCH 09/48] Move the more verbose TRACE() statements into TRACE2() --- buffer.c | 4 ++-- cli-kex.c | 2 +- cli-session.c | 4 ++-- common-channel.c | 4 ++-- dbutil.c | 20 +++++++++++++++++--- dbutil.h | 1 + debug.h | 4 +++- dss.c | 6 +++--- packet.c | 40 +++++++++++++++++++--------------------- process-packet.c | 4 ++-- queue.c | 2 -- rsa.c | 6 +++--- signkey.c | 18 +++++++++--------- 13 files changed, 64 insertions(+), 51 deletions(-) diff --git a/buffer.c b/buffer.c index 13fa1ce..facee24 100644 --- a/buffer.c +++ b/buffer.c @@ -282,7 +282,7 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) { void buf_putmpint(buffer* buf, mp_int * mp) { unsigned int len, pad = 0; - TRACE(("enter buf_putmpint")) + TRACE2(("enter buf_putmpint")) dropbear_assert(mp != NULL); @@ -318,7 +318,7 @@ void buf_putmpint(buffer* buf, mp_int * mp) { buf_incrwritepos(buf, len-pad); } - TRACE(("leave buf_putmpint")) + TRACE2(("leave buf_putmpint")) } /* Retrieve an mp_int from the buffer. diff --git a/cli-kex.c b/cli-kex.c index 9dadb3c..e039071 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -246,7 +246,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { /* Compare hostnames */ if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen), hostlen) != 0) { - TRACE(("hosts don't match")) + TRACE2(("hosts don't match")) continue; } diff --git a/cli-session.c b/cli-session.c index 81aa8c9..3adec73 100644 --- a/cli-session.c +++ b/cli-session.c @@ -172,7 +172,7 @@ static void recv_msg_service_accept(void) { * service, userauth and channel requests */ static void cli_sessionloop() { - TRACE(("enter cli_sessionloop")) + TRACE2(("enter cli_sessionloop")) if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) { cli_ses.kex_state = KEXINIT_RCVD; @@ -286,7 +286,7 @@ static void cli_sessionloop() { break; } - TRACE(("leave cli_sessionloop: fell out")) + TRACE2(("leave cli_sessionloop: fell out")) } diff --git a/common-channel.c b/common-channel.c index 05b9d11..331ea60 100644 --- a/common-channel.c +++ b/common-channel.c @@ -273,10 +273,10 @@ static unsigned int write_pending(struct Channel * channel) { static void check_close(struct Channel *channel) { int close_allowed = 0; - TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d", + TRACE2(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d", channel->writefd, channel->readfd, channel->errfd, channel->sent_close, channel->recv_close)) - TRACE(("writebuf size %d extrabuf size %d", + TRACE2(("writebuf size %d extrabuf size %d", channel->writebuf ? cbuf_getused(channel->writebuf) : 0, channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) diff --git a/dbutil.c b/dbutil.c index 044388a..8c48a24 100644 --- a/dbutil.c +++ b/dbutil.c @@ -151,6 +151,20 @@ void dropbear_trace(const char* format, ...) { fprintf(stderr, "\n"); va_end(param); } +void dropbear_trace2(const char* format, ...) { + + va_list param; + + if (!(debug_trace && getenv("DROPBEAR_TRACE2"))) { + return; + } + + va_start(param, format); + fprintf(stderr, "TRACE2 (%d): ", getpid()); + vfprintf(stderr, format, param); + fprintf(stderr, "\n"); + va_end(param); +} #endif /* DEBUG_TRACE */ static void set_sock_priority(int sock) { @@ -725,7 +739,7 @@ int buf_getline(buffer * line, FILE * authfile) { int c = EOF; - TRACE(("enter buf_getline")) + TRACE2(("enter buf_getline")) buf_setpos(line, 0); buf_setlen(line, 0); @@ -750,10 +764,10 @@ out: /* if we didn't read anything before EOF or error, exit */ if (c == EOF && line->pos == 0) { - TRACE(("leave buf_getline: failure")) + TRACE2(("leave buf_getline: failure")) return DROPBEAR_FAILURE; } else { - TRACE(("leave buf_getline: success")) + TRACE2(("leave buf_getline: success")) buf_setpos(line, 0); return DROPBEAR_SUCCESS; } diff --git a/dbutil.h b/dbutil.h index 0f16bf3..fc01251 100644 --- a/dbutil.h +++ b/dbutil.h @@ -57,6 +57,7 @@ void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN; #ifdef DEBUG_TRACE void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2); +void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2); void printhex(const char * label, const unsigned char * buf, int len); extern int debug_trace; #endif diff --git a/debug.h b/debug.h index b20e685..289c577 100644 --- a/debug.h +++ b/debug.h @@ -39,7 +39,7 @@ * Caution: Don't use this in an unfriendly environment (ie unfirewalled), * since the printing may not sanitise strings etc. This will add a reasonable * amount to your executable size. */ -/*#define DEBUG_TRACE */ +/* #define DEBUG_TRACE */ /* All functions writing to the cleartext payload buffer call * CHECKCLEARTOWRITE() before writing. This is only really useful if you're @@ -63,8 +63,10 @@ /* you don't need to touch this block */ #ifdef DEBUG_TRACE #define TRACE(X) dropbear_trace X; +#define TRACE2(X) dropbear_trace2 X; #else /*DEBUG_TRACE*/ #define TRACE(X) +#define TRACE2(X) #endif /*DEBUG_TRACE*/ /* To debug with GDB it is easier to run with no forking of child processes. diff --git a/dss.c b/dss.c index d984669..75dc0d0 100644 --- a/dss.c +++ b/dss.c @@ -101,9 +101,9 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) { /* Clear and free the memory used by a public or private key */ void dss_key_free(dropbear_dss_key *key) { - TRACE(("enter dsa_key_free")) + TRACE2(("enter dsa_key_free")) if (key == NULL) { - TRACE(("enter dsa_key_free: key == NULL")) + TRACE2(("enter dsa_key_free: key == NULL")) return; } if (key->p) { @@ -127,7 +127,7 @@ void dss_key_free(dropbear_dss_key *key) { m_free(key->x); } m_free(key); - TRACE(("leave dsa_key_free")) + TRACE2(("leave dsa_key_free")) } /* put the dss public key into the buffer in the required format: diff --git a/packet.c b/packet.c index 5cd60c2..4a3a53a 100644 --- a/packet.c +++ b/packet.c @@ -62,7 +62,7 @@ void write_packet() { struct Link *l; #endif - TRACE(("enter write_packet")) + TRACE2(("enter write_packet")) dropbear_assert(!isempty(&ses.writequeue)); #ifdef HAVE_WRITEV @@ -81,7 +81,7 @@ void write_packet() { if (written < 0) { if (errno == EINTR) { m_free(iov); - TRACE(("leave writepacket: EINTR")) + TRACE2(("leave writepacket: EINTR")) return; } else { dropbear_exit("Error writing"); @@ -122,7 +122,7 @@ void write_packet() { if (written < 0) { if (errno == EINTR) { - TRACE(("leave writepacket: EINTR")) + TRACE2(("leave writepacket: EINTR")) return; } else { dropbear_exit("Error writing"); @@ -152,7 +152,7 @@ void write_packet() { ses.last_packet_time = now; } - TRACE(("leave write_packet")) + TRACE2(("leave write_packet")) } /* Non-blocking function reading available portion of a packet into the @@ -164,7 +164,7 @@ void read_packet() { unsigned int maxlen; unsigned char blocksize; - TRACE(("enter read_packet")) + TRACE2(("enter read_packet")) blocksize = ses.keys->recv.algo_crypt->blocksize; if (ses.readbuf == NULL || ses.readbuf->len < blocksize) { @@ -177,7 +177,7 @@ void read_packet() { if (ret == DROPBEAR_FAILURE) { /* didn't read enough to determine the length */ - TRACE(("leave read_packet: packetinit done")) + TRACE2(("leave read_packet: packetinit done")) return; } } @@ -199,7 +199,7 @@ void read_packet() { if (len < 0) { if (errno == EINTR || errno == EAGAIN) { - TRACE(("leave read_packet: EINTR or EAGAIN")) + TRACE2(("leave read_packet: EINTR or EAGAIN")) return; } else { dropbear_exit("Error reading: %s", strerror(errno)); @@ -215,7 +215,7 @@ void read_packet() { /* The main select() loop process_packet() to * handle the packet contents... */ } - TRACE(("leave read_packet")) + TRACE2(("leave read_packet")) } /* Function used to read the initial portion of a packet, and determine the @@ -249,7 +249,7 @@ static int read_packet_init() { } if (slen < 0) { if (errno == EINTR) { - TRACE(("leave read_packet_init: EINTR")) + TRACE2(("leave read_packet_init: EINTR")) return DROPBEAR_FAILURE; } dropbear_exit("Error reading: %s", strerror(errno)); @@ -273,7 +273,7 @@ static int read_packet_init() { } len = buf_getint(ses.readbuf) + 4 + macsize; - TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize)) + TRACE2(("packet size is %d, block %d mac %d", len, blocksize, macsize)) /* check packet length */ @@ -299,7 +299,7 @@ void decrypt_packet() { unsigned int padlen; unsigned int len; - TRACE(("enter decrypt_packet")) + TRACE2(("enter decrypt_packet")) blocksize = ses.keys->recv.algo_crypt->blocksize; macsize = ses.keys->recv.algo_mac->hashsize; @@ -356,7 +356,7 @@ void decrypt_packet() { ses.recvseq++; - TRACE(("leave decrypt_packet")) + TRACE2(("leave decrypt_packet")) } /* Checks the mac at the end of a decrypted readbuf. @@ -455,7 +455,7 @@ static void enqueue_reply_packet() { ses.reply_queue_head = new_item; } ses.reply_queue_tail = new_item; - TRACE(("leave enqueue_reply_packet")) + TRACE2(("leave enqueue_reply_packet")) } void maybe_flush_reply_queue() { @@ -492,13 +492,13 @@ void encrypt_packet() { unsigned int len, encrypt_buf_size; unsigned char mac_bytes[MAX_MAC_LEN]; - TRACE(("enter encrypt_packet()")) + TRACE2(("enter encrypt_packet()")) buf_setpos(ses.writepayload, 0); packet_type = buf_getbyte(ses.writepayload); buf_setpos(ses.writepayload, 0); - TRACE(("encrypt_packet type is %d", packet_type)) + TRACE2(("encrypt_packet type is %d", packet_type)) if ((!ses.dataallowed && !packet_is_okay_kex(packet_type)) || ses.kexstate.sentnewkeys) { @@ -611,7 +611,7 @@ void encrypt_packet() { ses.kexstate.datatrans += writebuf->len; ses.transseq++; - TRACE(("leave encrypt_packet()")) + TRACE2(("leave encrypt_packet()")) } @@ -624,8 +624,6 @@ static void make_mac(unsigned int seqno, const struct key_context_directional * unsigned long bufsize; hmac_state hmac; - TRACE(("enter writemac")) - if (key_state->algo_mac->hashsize > 0) { /* calculate the mac */ if (hmac_init(&hmac, @@ -654,7 +652,7 @@ static void make_mac(unsigned int seqno, const struct key_context_directional * dropbear_exit("HMAC error"); } } - TRACE(("leave writemac")) + TRACE2(("leave writemac")) } #ifndef DISABLE_ZLIB @@ -665,7 +663,7 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) { unsigned int endpos = src->pos + len; int result; - TRACE(("enter buf_compress")) + TRACE2(("enter buf_compress")) while (1) { @@ -699,6 +697,6 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) { buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR); } - TRACE(("leave buf_compress")) + TRACE2(("leave buf_compress")) } #endif diff --git a/process-packet.c b/process-packet.c index 2ae410d..384e449 100644 --- a/process-packet.c +++ b/process-packet.c @@ -45,7 +45,7 @@ void process_packet() { unsigned char type; unsigned int i; - TRACE(("enter process_packet")) + TRACE2(("enter process_packet")) type = buf_getbyte(ses.payload); TRACE(("process_packet: packet type = %d", type)) @@ -123,7 +123,7 @@ out: buf_free(ses.payload); ses.payload = NULL; - TRACE(("leave process_packet")) + TRACE2(("leave process_packet")) } diff --git a/queue.c b/queue.c index 7a80124..9d00808 100644 --- a/queue.c +++ b/queue.c @@ -70,7 +70,6 @@ void enqueue(struct Queue* queue, void* item) { struct Link* newlink; - TRACE(("enter enqueue")) newlink = (struct Link*)m_malloc(sizeof(struct Link)); newlink->item = item; @@ -85,5 +84,4 @@ void enqueue(struct Queue* queue, void* item) { queue->head = newlink; } queue->count++; - TRACE(("leave enqueue")) } diff --git a/rsa.c b/rsa.c index 91bf59d..520ad84 100644 --- a/rsa.c +++ b/rsa.c @@ -139,10 +139,10 @@ out: /* Clear and free the memory used by a public or private key */ void rsa_key_free(dropbear_rsa_key *key) { - TRACE(("enter rsa_key_free")) + TRACE2(("enter rsa_key_free")) if (key == NULL) { - TRACE(("leave rsa_key_free: key == NULL")) + TRACE2(("leave rsa_key_free: key == NULL")) return; } if (key->d) { @@ -166,7 +166,7 @@ void rsa_key_free(dropbear_rsa_key *key) { m_free(key->q); } m_free(key); - TRACE(("leave rsa_key_free")) + TRACE2(("leave rsa_key_free")) } /* Put the public rsa key into the buffer in the required format: diff --git a/signkey.c b/signkey.c index 1d908f4..f647990 100644 --- a/signkey.c +++ b/signkey.c @@ -98,7 +98,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) { int keytype; int ret = DROPBEAR_FAILURE; - TRACE(("enter buf_get_pub_key")) + TRACE2(("enter buf_get_pub_key")) ident = buf_getstring(buf, &len); keytype = signkey_type_from_name(ident, len); @@ -109,7 +109,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) { return DROPBEAR_FAILURE; } - TRACE(("buf_get_pub_key keytype is %d", keytype)) + TRACE2(("buf_get_pub_key keytype is %d", keytype)) *type = keytype; @@ -137,7 +137,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) { } #endif - TRACE(("leave buf_get_pub_key")) + TRACE2(("leave buf_get_pub_key")) return ret; @@ -153,7 +153,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) { int keytype; int ret = DROPBEAR_FAILURE; - TRACE(("enter buf_get_priv_key")) + TRACE2(("enter buf_get_priv_key")) ident = buf_getstring(buf, &len); keytype = signkey_type_from_name(ident, len); @@ -190,7 +190,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) { } #endif - TRACE(("leave buf_get_priv_key")) + TRACE2(("leave buf_get_priv_key")) return ret; @@ -201,7 +201,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) { buffer *pubkeys; - TRACE(("enter buf_put_pub_key")) + TRACE2(("enter buf_put_pub_key")) pubkeys = buf_new(MAX_PUBKEY_SIZE); #ifdef DROPBEAR_DSS @@ -223,7 +223,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) { pubkeys->len); buf_free(pubkeys); - TRACE(("leave buf_put_pub_key")) + TRACE2(("leave buf_put_pub_key")) } /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */ @@ -251,7 +251,7 @@ void buf_put_priv_key(buffer* buf, sign_key *key, int type) { void sign_key_free(sign_key *key) { - TRACE(("enter sign_key_free")) + TRACE2(("enter sign_key_free")) #ifdef DROPBEAR_DSS dss_key_free(key->dsskey); @@ -265,7 +265,7 @@ void sign_key_free(sign_key *key) { m_free(key->filename); m_free(key); - TRACE(("leave sign_key_free")) + TRACE2(("leave sign_key_free")) } static char hexdig(unsigned char x) { From 5af0d33164261fb9603d1b44f715d63659799373 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 1 Apr 2013 22:26:24 +0800 Subject: [PATCH 10/48] Try password before interactive - bit of a hack --- cli-auth.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cli-auth.c b/cli-auth.c index 7dc101f..42c925b 100644 --- a/cli-auth.c +++ b/cli-auth.c @@ -257,6 +257,16 @@ void cli_auth_try() { } #endif +#ifdef ENABLE_CLI_PASSWORD_AUTH + if (ses.keys->trans.algo_crypt->cipherdesc == NULL) { + fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n"); + } else if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { + cli_auth_password(); + finished = 1; + cli_ses.lastauthtype = AUTH_TYPE_PASSWORD; + } +#endif + #ifdef ENABLE_CLI_INTERACT_AUTH if (ses.keys->trans.algo_crypt->cipherdesc == NULL) { fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n"); @@ -271,16 +281,6 @@ void cli_auth_try() { } #endif -#ifdef ENABLE_CLI_PASSWORD_AUTH - if (ses.keys->trans.algo_crypt->cipherdesc == NULL) { - fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n"); - } else if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { - cli_auth_password(); - finished = 1; - cli_ses.lastauthtype = AUTH_TYPE_PASSWORD; - } -#endif - TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype)) if (!finished) { From 90b5691183f12d348d2651e026e8438ad278c2be Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 1 Apr 2013 22:26:55 +0800 Subject: [PATCH 11/48] Run the cleanup handler also when we close due to TCP connection being closed --- cli-main.c | 3 +-- cli-session.c | 7 ++++--- common-session.c | 6 +++++- session.h | 4 ++-- svr-session.c | 13 +++++++++---- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/cli-main.c b/cli-main.c index 5f72969..1a8b02e 100644 --- a/cli-main.c +++ b/cli-main.c @@ -98,8 +98,7 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) { } /* Do the cleanup first, since then the terminal will be reset */ - cli_session_cleanup(); - common_session_cleanup(); + session_cleanup(); _dropbear_log(LOG_INFO, fmtbuf, param); diff --git a/cli-session.c b/cli-session.c index 3adec73..0c6635a 100644 --- a/cli-session.c +++ b/cli-session.c @@ -42,6 +42,7 @@ static void cli_sessionloop(); static void cli_session_init(); static void cli_finished(); static void recv_msg_service_accept(void); +static void cli_session_cleanup(void); struct clientsession cli_ses; /* GLOBAL */ @@ -143,6 +144,7 @@ static void cli_session_init() { /* For printing "remote host closed" for the user */ ses.remoteclosed = cli_remoteclosed; + ses.extra_session_cleanup = cli_session_cleanup; ses.buf_match_algo = cli_buf_match_algo; /* packet handlers */ @@ -290,7 +292,7 @@ static void cli_sessionloop() { } -void cli_session_cleanup() { +static void cli_session_cleanup(void) { if (!sessinitdone) { return; @@ -308,8 +310,7 @@ void cli_session_cleanup() { static void cli_finished() { - cli_session_cleanup(); - common_session_cleanup(); + session_cleanup(); fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username, cli_opts.remotehost, cli_opts.remoteport); exit(cli_ses.retval); diff --git a/common-session.c b/common-session.c index ec5c9ed..b514796 100644 --- a/common-session.c +++ b/common-session.c @@ -234,7 +234,7 @@ void session_loop(void(*loophandler)()) { } /* clean up a session on exit */ -void common_session_cleanup() { +void session_cleanup() { TRACE(("enter session_cleanup")) @@ -243,6 +243,10 @@ void common_session_cleanup() { TRACE(("leave session_cleanup: !sessinitdone")) return; } + + if (ses.extra_session_cleanup) { + ses.extra_session_cleanup(); + } m_free(ses.session_id); m_burn(ses.keys, sizeof(struct key_context)); diff --git a/session.h b/session.h index 39104a3..dd486f0 100644 --- a/session.h +++ b/session.h @@ -44,7 +44,7 @@ extern int exitflag; void common_session_init(int sock_in, int sock_out); void session_loop(void(*loophandler)()); -void common_session_cleanup(); +void session_cleanup(); void send_session_identification(); void send_msg_ignore(); @@ -58,7 +58,6 @@ void svr_dropbear_log(int priority, const char* format, va_list param); /* Client */ void cli_session(int sock_in, int sock_out); -void cli_session_cleanup(); void cleantext(unsigned char* dirtytext); /* crypto parameters that are stored individually for transmit and receive */ @@ -181,6 +180,7 @@ struct sshsession { void(*remoteclosed)(); /* A callback to handle closure of the remote connection */ + void(*extra_session_cleanup)(); /* client or server specific cleanup */ struct AuthState authstate; /* Common amongst client and server, since most struct elements are common */ diff --git a/svr-session.c b/svr-session.c index 7234f4a..c235c8a 100644 --- a/svr-session.c +++ b/svr-session.c @@ -72,6 +72,13 @@ static const struct ChanType *svr_chantypes[] = { NULL /* Null termination is mandatory. */ }; +static void +svr_session_cleanup(void) +{ + /* free potential public key options */ + svr_pubkey_options_cleanup(); +} + void svr_session(int sock, int childpipe) { char *host, *port; size_t len; @@ -103,6 +110,7 @@ void svr_session(int sock, int childpipe) { /* set up messages etc */ ses.remoteclosed = svr_remoteclosed; + ses.extra_session_cleanup = svr_session_cleanup; /* packet handlers */ ses.packettypes = svr_packettypes; @@ -160,11 +168,8 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) { if (svr_ses.server_pid == getpid()) #endif { - /* free potential public key options */ - svr_pubkey_options_cleanup(); - /* must be after we've done with username etc */ - common_session_cleanup(); + session_cleanup(); } exit(exitcode); From ff2aa20565df2ed528080288d0102cffb25e4204 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 2 Apr 2013 00:11:53 +0800 Subject: [PATCH 12/48] Be a bit more careful about when we want to use CLI_AUTH_IMMEDIATE Only use it if we have pubkeys to try, or we have $DROPBEAR_PASSWORD set --- auth.h | 2 +- cli-auth.c | 54 +++++++++++++++++++++++++++++---------------------- cli-session.c | 4 +++- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/auth.h b/auth.h index 0fd9c73..df6634e 100644 --- a/auth.h +++ b/auth.h @@ -67,7 +67,7 @@ void recv_msg_userauth_pk_ok(); void recv_msg_userauth_info_request(); void cli_get_user(); void cli_auth_getmethods(); -void cli_auth_try(); +int cli_auth_try(); void recv_msg_userauth_banner(); void cli_pubkeyfail(); void cli_auth_password(); diff --git a/cli-auth.c b/cli-auth.c index 42c925b..efa9e9b 100644 --- a/cli-auth.c +++ b/cli-auth.c @@ -42,9 +42,15 @@ void cli_authinitialise() { void cli_auth_getmethods() { TRACE(("enter cli_auth_getmethods")) #ifdef CLI_IMMEDIATE_AUTH - ses.authstate.authtypes = AUTH_TYPE_PUBKEY | AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT; - cli_auth_try(); -#else + ses.authstate.authtypes = AUTH_TYPE_PUBKEY; + if (getenv(DROPBEAR_PASSWORD_ENV)) { + ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT; + } + if (cli_auth_try() == DROPBEAR_SUCCESS) { + TRACE(("skipped initial none auth query")) + return; + } +#endif CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); buf_putstring(ses.writepayload, cli_opts.username, @@ -54,7 +60,6 @@ void cli_auth_getmethods() { buf_putstring(ses.writepayload, "none", 4); /* 'none' method */ encrypt_packet(); -#endif TRACE(("leave cli_auth_getmethods")) } @@ -241,7 +246,7 @@ void recv_msg_userauth_success() { #endif } -void cli_auth_try() { +int cli_auth_try() { int finished = 0; TRACE(("enter cli_auth_try")) @@ -258,36 +263,39 @@ void cli_auth_try() { #endif #ifdef ENABLE_CLI_PASSWORD_AUTH - if (ses.keys->trans.algo_crypt->cipherdesc == NULL) { - fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n"); - } else if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { - cli_auth_password(); - finished = 1; - cli_ses.lastauthtype = AUTH_TYPE_PASSWORD; + if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) { + if (ses.keys->trans.algo_crypt->cipherdesc == NULL) { + fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n"); + } else { + cli_auth_password(); + finished = 1; + cli_ses.lastauthtype = AUTH_TYPE_PASSWORD; + } } #endif #ifdef ENABLE_CLI_INTERACT_AUTH - if (ses.keys->trans.algo_crypt->cipherdesc == NULL) { - fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n"); - } else if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) { - if (cli_ses.auth_interact_failed) { - finished = 0; + if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) { + if (ses.keys->trans.algo_crypt->cipherdesc == NULL) { + fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n"); } else { - cli_auth_interactive(); - cli_ses.lastauthtype = AUTH_TYPE_INTERACT; - finished = 1; + if (!cli_ses.auth_interact_failed) { + cli_auth_interactive(); + cli_ses.lastauthtype = AUTH_TYPE_INTERACT; + finished = 1; + } } } #endif TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype)) - if (!finished) { - dropbear_exit("No auth methods could be used."); + if (finished) { + TRACE(("leave cli_auth_try success")) + return DROPBEAR_SUCCESS; } - - TRACE(("leave cli_auth_try")) + TRACE(("leave cli_auth_try failure")) + return DROPBEAR_FAILURE; } /* A helper for getpass() that exits if the user cancels. The returned diff --git a/cli-session.c b/cli-session.c index 0c6635a..b13948f 100644 --- a/cli-session.c +++ b/cli-session.c @@ -221,7 +221,9 @@ static void cli_sessionloop() { return; case USERAUTH_FAIL_RCVD: - cli_auth_try(); + if (cli_auth_try() == DROPBEAR_FAILURE) { + dropbear_exit("No auth methods could be used."); + } cli_ses.state = USERAUTH_REQ_SENT; TRACE(("leave cli_sessionloop: cli_auth_try")) return; From e55e4687543793216b501e0de8fd3fbeb4264e1b Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 2 Apr 2013 18:53:18 +0800 Subject: [PATCH 13/48] Fix segfault when /dev/urandom isn't writable --- random.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/random.c b/random.c index 0378e9a..f935e21 100644 --- a/random.c +++ b/random.c @@ -157,6 +157,9 @@ static void write_urandom() /* This is opportunistic, don't worry about failure */ unsigned char buf[INIT_SEED_SIZE]; FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w"); + if (!f) { + return; + } genrandom(buf, sizeof(buf)); fwrite(buf, sizeof(buf), 1, f); fclose(f); From dcd1527a1125eef0e9171f440276522476624fd8 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 2 Apr 2013 18:59:00 +0800 Subject: [PATCH 14/48] fix tabs --- random.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/random.c b/random.c index f935e21..1f687a2 100644 --- a/random.c +++ b/random.c @@ -157,9 +157,9 @@ static void write_urandom() /* This is opportunistic, don't worry about failure */ unsigned char buf[INIT_SEED_SIZE]; FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w"); - if (!f) { - return; - } + if (!f) { + return; + } genrandom(buf, sizeof(buf)); fwrite(buf, sizeof(buf), 1, f); fclose(f); From a6eb824950e6d938fa47c1f9fa1880b652d51833 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 2 Apr 2013 19:11:13 +0800 Subject: [PATCH 15/48] add IUTF8 --- termcodes.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/termcodes.c b/termcodes.c index d59505c..490e6ce 100644 --- a/termcodes.c +++ b/termcodes.c @@ -107,8 +107,14 @@ const struct TermCode termcodes[MAX_TERMCODE+1] = { #else {0, 0}, #endif - {0, 0}, /* 42 */ + /* IUTF8 isn't standardised in rfc4254 but is likely soon. + * Implemented by linux and darwin */ +#ifdef IUTF8 + {IUTF8, TERMCODE_INPUT}, +#else {0, 0}, +#endif + {0, 0}, /* 43 */ {0, 0}, {0, 0}, {0, 0}, From f267ca1f3a51a465ee98d0cfd230c40ddfeda332 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 3 Apr 2013 00:32:05 +0800 Subject: [PATCH 16/48] Add sentinel attribute --HG-- branch : kexguess --- bignum.h | 2 +- dbutil.h | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/bignum.h b/bignum.h index 042f811..cabb4a2 100644 --- a/bignum.h +++ b/bignum.h @@ -28,7 +28,7 @@ #include "includes.h" void m_mp_init(mp_int *mp); -void m_mp_init_multi(mp_int *mp, ...); +void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL; void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len); void sha1_process_mp(hash_state *hs, mp_int *mp); diff --git a/dbutil.h b/dbutil.h index fc01251..3af79f7 100644 --- a/dbutil.h +++ b/dbutil.h @@ -35,14 +35,12 @@ void startsyslog(); #ifdef __GNUC__ #define ATTRIB_PRINTF(fmt,args) __attribute__((format(printf, fmt, args))) +#define ATTRIB_NORETURN __attribute__((noreturn)) +#define ATTRIB_SENTINEL __attribute__((sentinel)) #else #define ATTRIB_PRINTF(fmt,args) -#endif - -#ifdef __GNUC__ -#define ATTRIB_NORETURN __attribute__((noreturn)) -#else #define ATTRIB_NORETURN +#define ATTRIB_SENTINEL #endif extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN; From 78fbed8c3eda1d7f3e0ffa41b54cd3c6ae31a0fe Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 3 Apr 2013 00:32:55 +0800 Subject: [PATCH 17/48] Don't usually need to recalculate dh_e for the repeated kexdh_init packet --HG-- branch : kexguess --- cli-kex.c | 17 +++++++++++++---- cli-session.c | 10 +++++++--- common-algo.c | 2 +- session.h | 1 + sysoptions.h | 5 +++-- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/cli-kex.c b/cli-kex.c index 833529a..1158aa6 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -43,11 +43,19 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen); void send_msg_kexdh_init() { TRACE(("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, NULL); + if ((cli_ses.dh_e && cli_ses.dh_x + && cli_ses.dh_val_algo == ses.newkeys->algo_kex)) { + TRACE(("reusing existing dh_e from first_kex_packet_follows")) + } else { + if (!cli_ses.dh_e || !cli_ses.dh_e) { + 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, NULL); + } - gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x); + gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x); + cli_ses.dh_val_algo = ses.newkeys->algo_kex; + } CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT); @@ -99,6 +107,7 @@ void recv_msg_kexdh_reply() { mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL); m_free(cli_ses.dh_e); m_free(cli_ses.dh_x); + cli_ses.dh_val_algo = DROPBEAR_KEX_NONE; if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) != DROPBEAR_SUCCESS) { diff --git a/cli-session.c b/cli-session.c index 600827f..9e64281 100644 --- a/cli-session.c +++ b/cli-session.c @@ -182,6 +182,11 @@ static void cli_sessionloop() { TRACE2(("enter cli_sessionloop")) + if (ses.lastpacket == 0) { + TRACE2(("exit cli_sessionloop: no real packets yet")) + return; + } + if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) { /* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT * negotiation would have failed. */ @@ -206,10 +211,9 @@ static void cli_sessionloop() { return; } - /* We should exit if we haven't donefirstkex: we shouldn't reach here - * in normal operation */ if (ses.kexstate.donefirstkex == 0) { - TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex")) + /* We might reach here if we have partial packet reads or have + * received SSG_MSG_IGNORE etc. Just skip it */ return; } diff --git a/common-algo.c b/common-algo.c index 8267852..b698611 100644 --- a/common-algo.c +++ b/common-algo.c @@ -214,8 +214,8 @@ algo_type sshhostkey[] = { }; algo_type sshkex[] = { - {"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL}, {"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL}, + {"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL}, {KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL}, {NULL, 0, NULL, 0, NULL} }; diff --git a/session.h b/session.h index 33c1539..9bbeac4 100644 --- a/session.h +++ b/session.h @@ -241,6 +241,7 @@ typedef enum { struct clientsession { mp_int *dh_e, *dh_x; /* Used during KEX */ + int dh_val_algo; /* KEX algorithm corresponding to current dh_e and dh_x */ cli_kex_state kex_state; /* Used for progressing KEX */ cli_state state; /* Used to progress auth/channelsession etc */ unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */ diff --git a/sysoptions.h b/sysoptions.h index 6e60294..4d648c1 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -61,8 +61,9 @@ #define DROPBEAR_FAILURE -1 /* various algorithm identifiers */ -#define DROPBEAR_KEX_DH_GROUP1 0 -#define DROPBEAR_KEX_DH_GROUP14 1 +#define DROPBEAR_KEX_NONE 0 +#define DROPBEAR_KEX_DH_GROUP1 1 +#define DROPBEAR_KEX_DH_GROUP14 2 #define DROPBEAR_SIGNKEY_ANY 0 #define DROPBEAR_SIGNKEY_RSA 1 From cbd3d5e3a535111b4cd6736d6aff432a252845d2 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 3 Apr 2013 00:43:31 +0800 Subject: [PATCH 18/48] Put some #ifdef options around first-follows options in case they need to be disabled --HG-- branch : kexguess --- cli-session.c | 5 ++++- common-algo.c | 2 ++ common-kex.c | 4 ++++ sysoptions.h | 9 +++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/cli-session.c b/cli-session.c index 9e64281..32b7ac7 100644 --- a/cli-session.c +++ b/cli-session.c @@ -110,11 +110,12 @@ void cli_session(int sock_in, int sock_out) { } +#ifdef USE_KEX_FIRST_FOLLOWS static void cli_send_kex_first_guess() { send_msg_kexdh_init(); dropbear_log(LOG_INFO, "kexdh_init guess sent"); - //cli_ses.kex_state = KEXDH_INIT_SENT; } +#endif static void cli_session_init() { @@ -155,7 +156,9 @@ static void cli_session_init() { ses.isserver = 0; +#ifdef USE_KEX_FIRST_FOLLOWS ses.send_kex_first_guess = cli_send_kex_first_guess; +#endif } diff --git a/common-algo.c b/common-algo.c index b698611..c74463c 100644 --- a/common-algo.c +++ b/common-algo.c @@ -216,7 +216,9 @@ algo_type sshhostkey[] = { algo_type sshkex[] = { {"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL}, {"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL}, +#ifdef USE_KEXGUESS2 {KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL}, +#endif {NULL, 0, NULL, 0, NULL} }; diff --git a/common-kex.c b/common-kex.c index eb1fd7b..6c22600 100644 --- a/common-kex.c +++ b/common-kex.c @@ -692,7 +692,11 @@ static void read_kex_algos() { memset(ses.newkeys, 0x0, sizeof(*ses.newkeys)); +#ifdef USE_KEXGUESS2 enum kexguess2_used kexguess2 = KEXGUESS2_LOOK; +#else + enum kexguess2_used kexguess2 = KEXGUESS2_NO; +#endif /* kex_algorithms */ algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess); diff --git a/sysoptions.h b/sysoptions.h index 4d648c1..22c2a4d 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -23,6 +23,15 @@ #define AUTH_TIMEOUT 300 /* we choose 5 minutes */ #endif +/* A client should try and send an initial key exchange packet guessing + * the algorithm that will match - saves a round trip connecting, has little + * overhead if the guess was "wrong". */ +#define USE_KEX_FIRST_FOLLOWS +/* Use protocol extension to allow "first follows" to succeed more frequently. + * This is currently Dropbear-specific but will gracefully fallback when connecting + * to other implementations. */ +#define USE_KEXGUESS2 + /* Minimum key sizes for DSS and RSA */ #ifndef MIN_DSS_KEYLEN #define MIN_DSS_KEYLEN 512 From 557d86aa79ec533c816bc062d1263a17b291eb84 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 3 Apr 2013 07:33:47 +0800 Subject: [PATCH 19/48] Fix a few options and headers --- bignum.h | 1 + options.h | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bignum.h b/bignum.h index cabb4a2..ba98db1 100644 --- a/bignum.h +++ b/bignum.h @@ -26,6 +26,7 @@ #define _BIGNUM_H_ #include "includes.h" +#include "dbutil.h" void m_mp_init(mp_int *mp); void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL; diff --git a/options.h b/options.h index 71d39cc..88b17ca 100644 --- a/options.h +++ b/options.h @@ -153,7 +153,7 @@ much traffic. */ #endif /* Whether to do reverse DNS lookups. */ -#define DO_HOST_LOOKUP +//#define DO_HOST_LOOKUP /* Whether to print the message of the day (MOTD). This doesn't add much code * size */ @@ -174,9 +174,9 @@ much traffic. */ * PAM challenge/response. * You can't enable both PASSWORD and PAM. */ -//#define ENABLE_SVR_PASSWORD_AUTH +#define ENABLE_SVR_PASSWORD_AUTH /* PAM requires ./configure --enable-pam */ -#define ENABLE_SVR_PAM_AUTH +//#define ENABLE_SVR_PAM_AUTH #define ENABLE_SVR_PUBKEY_AUTH /* Whether to take public key options in From 286fa93a8d898b27fdd451512fde312ca08dce5f Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 3 Apr 2013 07:34:18 +0800 Subject: [PATCH 20/48] fix leftover kexguess debugging --- cli-session.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli-session.c b/cli-session.c index 9d4bcde..7adea26 100644 --- a/cli-session.c +++ b/cli-session.c @@ -114,7 +114,6 @@ void cli_session(int sock_in, int sock_out) { #ifdef USE_KEX_FIRST_FOLLOWS static void cli_send_kex_first_guess() { send_msg_kexdh_init(); - dropbear_log(LOG_INFO, "kexdh_init guess sent"); } #endif @@ -197,7 +196,6 @@ static void cli_sessionloop() { /* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT * negotiation would have failed. */ if (!ses.kexstate.our_first_follows_matches) { - dropbear_log(LOG_INFO, "kexdh_init after remote's kexinit"); send_msg_kexdh_init(); } cli_ses.kex_state = KEXDH_INIT_SENT; From a2f70a3751a60d4843f7d6b8db2a0ce1389e2a99 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 3 Apr 2013 19:23:53 +0800 Subject: [PATCH 21/48] Just put the version string on the queue, don't use atomicio --- common-session.c | 14 +++++--------- process-packet.c | 2 +- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/common-session.c b/common-session.c index b514796..6b357bf 100644 --- a/common-session.c +++ b/common-session.c @@ -33,7 +33,6 @@ #include "random.h" #include "kex.h" #include "channel.h" -#include "atomicio.h" #include "runopts.h" static void checktimeouts(); @@ -50,8 +49,6 @@ int sessinitdone = 0; /* GLOBAL */ /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */ int exitflag = 0; /* GLOBAL */ - - /* called only at the start of a session, set up initial state */ void common_session_init(int sock_in, int sock_out) { @@ -257,13 +254,12 @@ void session_cleanup() { TRACE(("leave session_cleanup")) } - void send_session_identification() { - /* write our version string, this blocks */ - if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n", - strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) { - ses.remoteclosed(); - } + buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1); + buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n")); + buf_putbyte(writebuf, 0x0); // packet type + buf_setpos(writebuf, 0); + enqueue(&ses.writequeue, writebuf); } static void read_session_identification() { diff --git a/process-packet.c b/process-packet.c index 384e449..128eb72 100644 --- a/process-packet.c +++ b/process-packet.c @@ -48,7 +48,7 @@ void process_packet() { TRACE2(("enter process_packet")) type = buf_getbyte(ses.payload); - TRACE(("process_packet: packet type = %d", type)) + TRACE(("process_packet: packet type = %d, len %d", type, ses.payload->len)) ses.lastpacket = type; From e2c813df4d7572df8d905c1bf2aed756c72abaab Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 3 Apr 2013 23:54:58 +0800 Subject: [PATCH 22/48] Fix MAC bug which would prevent asymmetric hashes --- packet.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packet.c b/packet.c index 4a3a53a..366c3d1 100644 --- a/packet.c +++ b/packet.c @@ -74,6 +74,8 @@ void write_packet() { len = writebuf->len - 1 - writebuf->pos; dropbear_assert(len > 0); all_ignore &= (packet_type == SSH_MSG_IGNORE); + TRACE2(("write_packet writev #%d type %d len %d/%d", i, packet_type, + len, writebuf->len-1)) iov[i].iov_base = buf_getptr(writebuf, len); iov[i].iov_len = len; } @@ -366,7 +368,7 @@ static int checkmac() { unsigned char mac_bytes[MAX_MAC_LEN]; unsigned int mac_size, contents_len; - mac_size = ses.keys->trans.algo_mac->hashsize; + mac_size = ses.keys->recv.algo_mac->hashsize; contents_len = ses.readbuf->len - mac_size; buf_setpos(ses.readbuf, 0); @@ -455,7 +457,6 @@ static void enqueue_reply_packet() { ses.reply_queue_head = new_item; } ses.reply_queue_tail = new_item; - TRACE2(("leave enqueue_reply_packet")) } void maybe_flush_reply_queue() { @@ -500,16 +501,12 @@ void encrypt_packet() { TRACE2(("encrypt_packet type is %d", packet_type)) - if ((!ses.dataallowed && !packet_is_okay_kex(packet_type)) - || ses.kexstate.sentnewkeys) { + if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))) { /* During key exchange only particular packets are allowed. Since this packet_type isn't OK we just enqueue it to send after the KEX, see maybe_flush_reply_queue */ - - /* We also enqueue packets here when we have sent a MSG_NEWKEYS - * packet but are yet to received one. For simplicity we just switch - * over all the keys at once. This is the 'ses.kexstate.sentnewkeys' - * case. */ + TRACE2(("Delay sending reply packet. dataallowed %d, type %d, sentnewkeys %d", + ses.dataallowed, packet_type, ses.kexstate.sentnewkeys)) enqueue_reply_packet(); return; } From 7f42096d0fb56c54768f16e93666f8ee420a5424 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 4 Apr 2013 00:18:50 +0800 Subject: [PATCH 23/48] Take transmit and receive keys into use separately --- cli-kex.c | 1 - cli-session.c | 4 +-- common-kex.c | 86 +++++++++++++++++++++++++++------------------------ dbutil.c | 24 ++++++++------ packet.c | 2 -- session.h | 1 + 6 files changed, 64 insertions(+), 54 deletions(-) diff --git a/cli-kex.c b/cli-kex.c index 1158aa6..fd2e48e 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -256,7 +256,6 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { /* Compare hostnames */ if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen), hostlen) != 0) { - TRACE2(("hosts don't match")) continue; } diff --git a/cli-session.c b/cli-session.c index 7adea26..9639ffa 100644 --- a/cli-session.c +++ b/cli-session.c @@ -204,8 +204,7 @@ static void cli_sessionloop() { } /* A KEX has finished, so we should go back to our KEX_NOTHING state */ - if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0 - && ses.kexstate.sentkexinit == 0) { + if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.sentnewkeys) { cli_ses.kex_state = KEX_NOTHING; } @@ -218,6 +217,7 @@ static void cli_sessionloop() { if (ses.kexstate.donefirstkex == 0) { /* We might reach here if we have partial packet reads or have * received SSG_MSG_IGNORE etc. Just skip it */ + TRACE2(("donefirstkex false\n")) return; } diff --git a/common-kex.c b/common-kex.c index 6c22600..88dcb89 100644 --- a/common-kex.c +++ b/common-kex.c @@ -80,7 +80,7 @@ static const unsigned char dh_p_14[DH_P_14_LEN] = { static const int DH_G_VAL = 2; static void kexinitialise(); -void gen_new_keys(); +static void gen_new_keys(); #ifndef DISABLE_ZLIB static void gen_new_zstreams(); #endif @@ -159,11 +159,39 @@ void send_msg_kexinit() { } -/* *** NOTE regarding (send|recv)_msg_newkeys *** - * Changed by mihnea from the original kex.c to set dataallowed after a - * completed key exchange, no matter the order in which it was performed. - * This enables client mode without affecting server functionality. - */ +void switch_keys() { + TRACE2(("enter switch_keys")) + if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) { + dropbear_exit("Unexpected newkeys message"); + } + + if (!ses.keys) { + ses.keys = m_malloc(sizeof(*ses.newkeys)); + } + if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) { + TRACE(("switch_keys recv")) + ses.keys->recv = ses.newkeys->recv; + m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv)); + ses.newkeys->recv.valid = 0; + } + if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) { + TRACE(("switch_keys trans")) + ses.keys->trans = ses.newkeys->trans; + m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans)); + ses.newkeys->trans.valid = 0; + } + if (ses.kexstate.sentnewkeys && ses.kexstate.recvnewkeys) + { + TRACE(("switch_keys done")) + ses.keys->algo_kex = ses.newkeys->algo_kex; + ses.keys->algo_hostkey = ses.newkeys->algo_hostkey; + ses.keys->allow_compress = 0; + m_free(ses.newkeys); + ses.newkeys = NULL; + kexinitialise(); + } + TRACE2(("leave switch_keys")) +} /* Bring new keys into use after a key exchange, and let the client know*/ void send_msg_newkeys() { @@ -174,44 +202,25 @@ void send_msg_newkeys() { CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS); encrypt_packet(); + - /* set up our state */ - if (ses.kexstate.recvnewkeys) { - TRACE(("while RECVNEWKEYS=1")) - gen_new_keys(); - kexinitialise(); /* we've finished with this kex */ - TRACE((" -> DATAALLOWED=1")) - ses.dataallowed = 1; /* we can send other packets again now */ - ses.kexstate.donefirstkex = 1; - } else { - ses.kexstate.sentnewkeys = 1; - TRACE(("SENTNEWKEYS=1")) - } + ses.kexstate.sentnewkeys = 1; + ses.kexstate.donefirstkex = 1; + ses.dataallowed = 1; /* we can send other packets again now */ + gen_new_keys(); + switch_keys(); - TRACE(("-> MSG_NEWKEYS")) TRACE(("leave send_msg_newkeys")) } /* Bring the new keys into use after a key exchange */ void recv_msg_newkeys() { - TRACE(("<- MSG_NEWKEYS")) TRACE(("enter recv_msg_newkeys")) - /* simply check if we've sent SSH_MSG_NEWKEYS, and if so, - * switch to the new keys */ - if (ses.kexstate.sentnewkeys) { - TRACE(("while SENTNEWKEYS=1")) - gen_new_keys(); - kexinitialise(); /* we've finished with this kex */ - TRACE((" -> DATAALLOWED=1")) - ses.dataallowed = 1; /* we can send other packets again now */ - ses.kexstate.donefirstkex = 1; - } else { - TRACE(("RECVNEWKEYS=1")) - ses.kexstate.recvnewkeys = 1; - } + ses.kexstate.recvnewkeys = 1; + switch_keys(); TRACE(("leave recv_msg_newkeys")) } @@ -293,8 +302,7 @@ static void hashkeys(unsigned char *out, int outlen, * ses.newkeys is the new set of keys which are generated, these are only * taken into use after both sides have sent a newkeys message */ -/* Originally from kex.c, generalized for cli/svr mode --mihnea */ -void gen_new_keys() { +static void gen_new_keys() { unsigned char C2S_IV[MAX_IV_LEN]; unsigned char C2S_key[MAX_KEY_LEN]; @@ -382,11 +390,9 @@ void gen_new_keys() { gen_new_zstreams(); #endif - /* Switch over to the new keys */ - m_burn(ses.keys, sizeof(struct key_context)); - m_free(ses.keys); - ses.keys = ses.newkeys; - ses.newkeys = NULL; + /* Ready to switch over */ + ses.newkeys->trans.valid = 1; + ses.newkeys->recv.valid = 1; m_burn(C2S_IV, sizeof(C2S_IV)); m_burn(C2S_key, sizeof(C2S_key)); diff --git a/dbutil.c b/dbutil.c index 8c48a24..8ee6050 100644 --- a/dbutil.c +++ b/dbutil.c @@ -138,29 +138,39 @@ void dropbear_log(int priority, const char* format, ...) { #ifdef DEBUG_TRACE void dropbear_trace(const char* format, ...) { - va_list param; + struct timeval tv; if (!debug_trace) { return; } + gettimeofday(&tv, NULL); + va_start(param, format); - fprintf(stderr, "TRACE (%d): ", getpid()); + fprintf(stderr, "TRACE (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec); vfprintf(stderr, format, param); fprintf(stderr, "\n"); va_end(param); } + void dropbear_trace2(const char* format, ...) { - + static int trace_env = -1; va_list param; + struct timeval tv; - if (!(debug_trace && getenv("DROPBEAR_TRACE2"))) { + if (trace_env == -1) { + trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0; + } + + if (!(debug_trace && trace_env)) { return; } + gettimeofday(&tv, NULL); + va_start(param, format); - fprintf(stderr, "TRACE2 (%d): ", getpid()); + fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec); vfprintf(stderr, format, param); fprintf(stderr, "\n"); va_end(param); @@ -739,8 +749,6 @@ int buf_getline(buffer * line, FILE * authfile) { int c = EOF; - TRACE2(("enter buf_getline")) - buf_setpos(line, 0); buf_setlen(line, 0); @@ -764,10 +772,8 @@ out: /* if we didn't read anything before EOF or error, exit */ if (c == EOF && line->pos == 0) { - TRACE2(("leave buf_getline: failure")) return DROPBEAR_FAILURE; } else { - TRACE2(("leave buf_getline: success")) buf_setpos(line, 0); return DROPBEAR_SUCCESS; } diff --git a/packet.c b/packet.c index 366c3d1..09f0600 100644 --- a/packet.c +++ b/packet.c @@ -505,8 +505,6 @@ void encrypt_packet() { /* During key exchange only particular packets are allowed. Since this packet_type isn't OK we just enqueue it to send after the KEX, see maybe_flush_reply_queue */ - TRACE2(("Delay sending reply packet. dataallowed %d, type %d, sentnewkeys %d", - ses.dataallowed, packet_type, ses.kexstate.sentnewkeys)) enqueue_reply_packet(); return; } diff --git a/session.h b/session.h index a76fa99..4ba8ac8 100644 --- a/session.h +++ b/session.h @@ -78,6 +78,7 @@ struct key_context_directional { #endif } cipher_state; unsigned char mackey[MAX_MAC_LEN]; + int valid; }; struct key_context { From 2fdb5fd6ced264fec1594cf674ef125f5dc6a500 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 4 Apr 2013 07:51:13 +0800 Subject: [PATCH 24/48] setup tcp after requesting a channel - might hide some DNS latency --- cli-session.c | 15 ++++++++------- debug.h | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cli-session.c b/cli-session.c index 9639ffa..401c9e2 100644 --- a/cli-session.c +++ b/cli-session.c @@ -266,13 +266,6 @@ static void cli_sessionloop() { } } -#ifdef ENABLE_CLI_LOCALTCPFWD - setup_localtcp(); -#endif -#ifdef ENABLE_CLI_REMOTETCPFWD - setup_remotetcp(); -#endif - #ifdef ENABLE_CLI_NETCAT if (cli_opts.netcat_host) { cli_send_netcat_request(); @@ -281,6 +274,14 @@ static void cli_sessionloop() { if (!cli_opts.no_cmd) { cli_send_chansess_request(); } + +#ifdef ENABLE_CLI_LOCALTCPFWD + setup_localtcp(); +#endif +#ifdef ENABLE_CLI_REMOTETCPFWD + setup_remotetcp(); +#endif + TRACE(("leave cli_sessionloop: running")) cli_ses.state = SESSION_RUNNING; return; diff --git a/debug.h b/debug.h index 289c577..be09865 100644 --- a/debug.h +++ b/debug.h @@ -39,7 +39,7 @@ * Caution: Don't use this in an unfriendly environment (ie unfirewalled), * since the printing may not sanitise strings etc. This will add a reasonable * amount to your executable size. */ -/* #define DEBUG_TRACE */ +#define DEBUG_TRACE /* All functions writing to the cleartext payload buffer call * CHECKCLEARTOWRITE() before writing. This is only really useful if you're From 3ec467047856eb76945dc7804d1ba7743935fb2d Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 10 Apr 2013 21:32:44 +0800 Subject: [PATCH 25/48] reset terminal modes before printing a message --- cli-chansession.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli-chansession.c b/cli-chansession.c index 65d1f4f..17e0d53 100644 --- a/cli-chansession.c +++ b/cli-chansession.c @@ -82,14 +82,12 @@ out: /* If the main session goes, we close it up */ static void cli_closechansess(struct Channel *UNUSED(channel)) { + cli_tty_cleanup(); /* Restore tty modes etc */ /* This channel hasn't gone yet, so we have > 1 */ if (ses.chancount > 1) { dropbear_log(LOG_INFO, "Waiting for other channels to close..."); } - - cli_tty_cleanup(); /* Restore tty modes etc */ - } void cli_start_send_channel_request(struct Channel *channel, From c0d7c6693f579a814c50d7965f8e89fa470b2c03 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 10 Apr 2013 21:32:55 +0800 Subject: [PATCH 26/48] run closehandlers on cleanup --- common-channel.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common-channel.c b/common-channel.c index 331ea60..8b7369c 100644 --- a/common-channel.c +++ b/common-channel.c @@ -561,7 +561,11 @@ static void remove_channel(struct Channel * channel) { TRACE(("CLOSE errfd %d", channel->errfd)) close(channel->errfd); - channel->typedata = NULL; + if (!channel->close_handler_done + && channel->type->closehandler) { + channel->type->closehandler(channel); + channel->close_handler_done = 1; + } ses.channels[channel->index] = NULL; m_free(channel); @@ -625,7 +629,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) { * exttype if is extended */ maxlen = MIN(maxlen, ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0)); - TRACE(("maxlen %d", maxlen)) + TRACE(("maxlen %zd", maxlen)) if (maxlen == 0) { TRACE(("leave send_msg_channel_data: no window")) return; From adeb372a66643000aee8445f8b2f9854fdfb4402 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 11 Apr 2013 23:03:58 +0800 Subject: [PATCH 27/48] Fix zlib for split newkeys --- common-kex.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/common-kex.c b/common-kex.c index 88dcb89..530de0b 100644 --- a/common-kex.c +++ b/common-kex.c @@ -82,7 +82,8 @@ static const int DH_G_VAL = 2; static void kexinitialise(); static void gen_new_keys(); #ifndef DISABLE_ZLIB -static void gen_new_zstreams(); +static void gen_new_zstream_recv(); +static void gen_new_zstream_trans(); #endif static void read_kex_algos(); /* helper function for gen_new_keys */ @@ -159,7 +160,7 @@ void send_msg_kexinit() { } -void switch_keys() { +static void switch_keys() { TRACE2(("enter switch_keys")) if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) { dropbear_exit("Unexpected newkeys message"); @@ -170,12 +171,14 @@ void switch_keys() { } if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) { TRACE(("switch_keys recv")) + gen_new_zstream_recv(); ses.keys->recv = ses.newkeys->recv; m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv)); ses.newkeys->recv.valid = 0; } if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) { TRACE(("switch_keys trans")) + gen_new_zstream_trans(); ses.keys->trans = ses.newkeys->trans; m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans)); ses.newkeys->trans.valid = 0; @@ -386,10 +389,6 @@ static void gen_new_keys() { ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name); } -#ifndef DISABLE_ZLIB - gen_new_zstreams(); -#endif - /* Ready to switch over */ ses.newkeys->trans.valid = 1; ses.newkeys->recv.valid = 1; @@ -418,7 +417,7 @@ int is_compress_recv() { /* Set up new zlib compression streams, close the old ones. Only * called from gen_new_keys() */ -static void gen_new_zstreams() { +static void gen_new_zstream_recv() { /* create new zstreams */ if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB @@ -433,6 +432,17 @@ static void gen_new_zstreams() { } else { ses.newkeys->recv.zstream = NULL; } + /* clean up old keys */ + if (ses.keys->recv.zstream != NULL) { + if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) { + /* Z_DATA_ERROR is ok, just means that stream isn't ended */ + dropbear_exit("Crypto error"); + } + m_free(ses.keys->recv.zstream); + } +} + +static void gen_new_zstream_trans() { if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB || ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) { @@ -450,14 +460,6 @@ static void gen_new_zstreams() { ses.newkeys->trans.zstream = NULL; } - /* clean up old keys */ - if (ses.keys->recv.zstream != NULL) { - if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) { - /* Z_DATA_ERROR is ok, just means that stream isn't ended */ - dropbear_exit("Crypto error"); - } - m_free(ses.keys->recv.zstream); - } if (ses.keys->trans.zstream != NULL) { if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) { /* Z_DATA_ERROR is ok, just means that stream isn't ended */ From 4404126501ba18184a8e04f815c21e7a9184414a Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 14 Apr 2013 22:49:10 +0800 Subject: [PATCH 28/48] -y -y to disable hostkey checking fix missing trailing space when passing arguments for multihop mode From Hans Harder --- cli-kex.c | 5 +++++ cli-runopts.c | 31 +++++++++++++++++++++++++++---- dbclient.1 | 3 ++- runopts.h | 1 + 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/cli-kex.c b/cli-kex.c index 0d5a9d2..c47faae 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -217,6 +217,11 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { buffer * line = NULL; int ret; + if (cli_opts.no_hostkey_check) { + fprintf(stderr, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost); + return; + } + hostsfile = open_known_hosts_file(&readonly); if (!hostsfile) { ask_to_confirm(keyblob, keybloblen); diff --git a/cli-runopts.c b/cli-runopts.c index 5ddcc21..d95dad5 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -62,6 +62,7 @@ static void printhelp() { "-N Don't run a remote command\n" "-f Run in background after auth\n" "-y Always accept remote host key if unknown\n" + "-y -y Don't perform any remote host key checking (caution)\n" "-s Request a subsystem (use by external sftp)\n" #ifdef ENABLE_CLI_PUBKEY_AUTH "-i (multiple allowed)\n" @@ -130,6 +131,7 @@ void cli_getopts(int argc, char ** argv) { cli_opts.backgrounded = 0; cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */ cli_opts.always_accept_key = 0; + cli_opts.no_hostkey_check = 0; cli_opts.is_subsystem = 0; #ifdef ENABLE_CLI_PUBKEY_AUTH cli_opts.privkeys = list_new(); @@ -213,6 +215,10 @@ void cli_getopts(int argc, char ** argv) { switch (argv[i][1]) { case 'y': /* always accept the remote hostkey */ + if (cli_opts.always_accept_key) { + // twice means no checking at all + cli_opts.no_hostkey_check = 1; + } cli_opts.always_accept_key = 1; break; case 'p': /* remoteport */ @@ -461,20 +467,31 @@ multihop_passthrough_args() { int total; unsigned int len = 0; m_list_elem *iter; - /* Fill out -i and -W options that make sense for all + /* Fill out -i, -y, -W options that make sense for all * the intermediate processes */ for (iter = cli_opts.privkeys->first; iter; iter = iter->next) { sign_key * key = (sign_key*)iter->item; len += 3 + strlen(key->filename); } - len += 20; // space for -W , terminator. + len += 30; // space for -W , terminator. ret = m_malloc(len); total = 0; + if (cli_opts.no_hostkey_check) + { + int written = snprintf(ret+total, len-total, "-y -y "); + total += written; + } + else if (cli_opts.always_accept_key) + { + int written = snprintf(ret+total, len-total, "-y "); + total += written; + } + if (opts.recv_window != DEFAULT_RECV_WINDOW) { - int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window); + int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window); total += written; } @@ -482,11 +499,17 @@ multihop_passthrough_args() { { sign_key * key = (sign_key*)iter->item; const size_t size = len - total; - int written = snprintf(ret+total, size, "-i %s", key->filename); + int written = snprintf(ret+total, size, "-i %s ", key->filename); dropbear_assert((unsigned int)written < size); total += written; } + /* if args where passed, total will be not zero, and it will have a space at the end, so remove that */ + if (total > 0) + { + total--; + } + return ret; } diff --git a/dbclient.1 b/dbclient.1 index 69af18a..29d8cd8 100644 --- a/dbclient.1 +++ b/dbclient.1 @@ -80,7 +80,8 @@ by the ssh server. .TP .B \-y Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the -connection will abort as normal. +connection will abort as normal. If specified a second time no host key checking +is performed at all, this is usually undesirable. .TP .B \-A Forward agent connections to the remote host. dbclient will use any diff --git a/runopts.h b/runopts.h index 9cd84d0..0dc3088 100644 --- a/runopts.h +++ b/runopts.h @@ -121,6 +121,7 @@ typedef struct cli_runopts { char *cmd; int wantpty; int always_accept_key; + int no_hostkey_check; int no_cmd; int backgrounded; int is_subsystem; From ba15bbfe33f4d6174526a03fda1b3b543a0b1d12 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 14 Apr 2013 23:08:57 +0800 Subject: [PATCH 29/48] Document escape chars --- dbclient.1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dbclient.1 b/dbclient.1 index 29d8cd8..aac32ff 100644 --- a/dbclient.1 +++ b/dbclient.1 @@ -61,10 +61,10 @@ Login as on the remote host. .TP .B \-t -Allocate a pty. +Allocate a PTY. .TP .B \-T -Don't allocate a pty. +Don't allocate a PTY. .TP .B \-N Don't request a remote shell or run any commands. Any command arguments are ignored. @@ -137,6 +137,11 @@ Note that hostnames are resolved by the prior hop (so "canyons" would be resolve in the example above, the same way as other -L TCP forwarded hosts are. Host keys are checked locally based on the given hostname. +.SH ESCAPE CHARACTERS +Typing a newline followed by the key sequence \fI~.\fR (tilde, dot) will terminate a connection. +The sequence \fI~^Z\fR (tilde, ctrl-z) will background the connection. This behaviour only +applies when a PTY is used. + .SH ENVIRONMENT .TP .B DROPBEAR_PASSWORD From ef151888fbef7f33f2140da579945b7fcb83151c Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 14 Apr 2013 23:16:16 +0800 Subject: [PATCH 30/48] requirenext fixup for firstkexfollows --- CHANGES | 36 ++++++++++++++++++++++++++++++++++++ cli-kex.c | 7 ++++--- common-kex.c | 2 +- common-session.c | 2 +- debug.h | 2 +- process-packet.c | 9 +++++---- session.h | 5 +++-- svr-kex.c | 3 ++- 8 files changed, 53 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index d21dc99..22b5a37 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,39 @@ +2013.57 - + +- Improved initial connection time particularly with high latency connections. + The number of round trips has been reduced for both client and server. + CPU time hasn't been changed. + +- Client will attempt to send an initial key exchange packet to save a round + trip. Dropbear implements an extension kexguess2@matt.ucc.asn.au to allow + the first packet guess to succeed in wider circumstances than the standard + behaviour. When communicating with other implementations the standard + behaviour is used. + +- Client side: when public key or password authentication with + $DROPBEAR_PASSWORD is used, an initial authentication request will + be sent immediately rather than querying the list of available methods. + This behaviour is enabled by CLI_IMMEDIATE_AUTH option (on by default), + please let the Dropbear author know if it causes any interoperability + problems. + +- Implement client escape characters ~. (terminate session) and + ~^Z (background session) + +- Server will more reliably clean up utmp when connection is closed + +- Don't crash if /dev/urandom isn't writable (RHEL5), thanks to Scott Case + +- Add "-y -y" client option to skip host key checking, thanks to Hans Harder + +- scp didn't work properly on systems using vfork(), thanks to Frank Van Uffelen + +- Added IUTF8 terminal mode support. Not yet standardised though seems that it + will soon be + +- Some verbose DROPBEAR_TRACE output is now hidden unless $DROPBEAR_TRACE2 + enviroment variable is set + 2013.56 - Thursday 21 March 2013 - Allow specifying cipher (-c) and MAC (-m) lists for dbclient diff --git a/cli-kex.c b/cli-kex.c index 3859109..e4d41cb 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -61,8 +61,8 @@ void send_msg_kexdh_init() { buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT); buf_putmpint(ses.writepayload, cli_ses.dh_e); encrypt_packet(); - // XXX fixme - //ses.requirenext = SSH_MSG_KEXDH_REPLY; + ses.requirenext[0] = SSH_MSG_KEXDH_REPLY; + ses.requirenext[1] = SSH_MSG_KEXINIT; } /* Handle a diffie-hellman key exchange reply. */ @@ -118,7 +118,8 @@ void recv_msg_kexdh_reply() { hostkey = NULL; send_msg_newkeys(); - ses.requirenext = SSH_MSG_NEWKEYS; + ses.requirenext[0] = SSH_MSG_NEWKEYS; + ses.requirenext[1] = 0; TRACE(("leave recv_msg_kexdh_init")) } diff --git a/common-kex.c b/common-kex.c index 530de0b..ba06e4f 100644 --- a/common-kex.c +++ b/common-kex.c @@ -542,7 +542,7 @@ void recv_msg_kexinit() { buf_putstring(ses.kexhashbuf, ses.transkexinit->data, ses.transkexinit->len); - ses.requirenext = SSH_MSG_KEXDH_INIT; + ses.requirenext[0] = SSH_MSG_KEXDH_INIT; } buf_free(ses.transkexinit); diff --git a/common-session.c b/common-session.c index 6b357bf..9df0f3d 100644 --- a/common-session.c +++ b/common-session.c @@ -82,7 +82,7 @@ void common_session_init(int sock_in, int sock_out) { initqueue(&ses.writequeue); - ses.requirenext = SSH_MSG_KEXINIT; + ses.requirenext[0] = SSH_MSG_KEXINIT; ses.dataallowed = 1; /* we can send data until we actually send the SSH_MSG_KEXINIT */ ses.ignorenext = 0; diff --git a/debug.h b/debug.h index be09865..289c577 100644 --- a/debug.h +++ b/debug.h @@ -39,7 +39,7 @@ * Caution: Don't use this in an unfriendly environment (ie unfirewalled), * since the printing may not sanitise strings etc. This will add a reasonable * amount to your executable size. */ -#define DEBUG_TRACE +/* #define DEBUG_TRACE */ /* All functions writing to the cleartext payload buffer call * CHECKCLEARTOWRITE() before writing. This is only really useful if you're diff --git a/process-packet.c b/process-packet.c index 128eb72..3ac0c1b 100644 --- a/process-packet.c +++ b/process-packet.c @@ -74,14 +74,15 @@ void process_packet() { /* This applies for KEX, where the spec says the next packet MUST be * NEWKEYS */ - if (ses.requirenext != 0) { - if (ses.requirenext != type) { - /* TODO send disconnect? */ + if (ses.requirenext[0] != 0) { + if (ses.requirenext[0] != type + && (ses.requirenext[1] == 0 || ses.requirenext[1] != type)) { dropbear_exit("Unexpected packet type %d, expected %d", type, ses.requirenext); } else { /* Got what we expected */ - ses.requirenext = 0; + ses.requirenext[0] = 0; + ses.requirenext[1] = 0; } } diff --git a/session.h b/session.h index 4ba8ac8..28cb5a9 100644 --- a/session.h +++ b/session.h @@ -135,8 +135,9 @@ struct sshsession { unsigned dataallowed : 1; /* whether we can send data packets or we are in the middle of a KEX or something */ - unsigned char requirenext; /* byte indicating what packet we require next, - or 0x00 for any */ + unsigned char requirenext[2]; /* bytes indicating what packets we require next, + or 0x00 for any. Second option can only be + used if the first byte is also set */ unsigned char ignorenext; /* whether to ignore the next packet, used for kex_follows stuff */ diff --git a/svr-kex.c b/svr-kex.c index abd7986..e56f082 100644 --- a/svr-kex.c +++ b/svr-kex.c @@ -61,7 +61,8 @@ void recv_msg_kexdh_init() { mp_clear(&dh_e); send_msg_newkeys(); - ses.requirenext = SSH_MSG_NEWKEYS; + ses.requirenext[0] = SSH_MSG_NEWKEYS; + ses.requirenext[1] = 0; TRACE(("leave recv_msg_kexdh_init")) } From d3cef72f26c757c80b24d737b87013f92940549f Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 15 Apr 2013 21:51:27 +0800 Subject: [PATCH 31/48] changelog updates for 2013.57 --- CHANGES | 30 +++++++++++++++++------------- cli-runopts.c | 2 +- debian/changelog | 6 ++++++ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index 22b5a37..afe972e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,17 +1,16 @@ -2013.57 - +2013.57 - Monday 15 April 2013 -- Improved initial connection time particularly with high latency connections. - The number of round trips has been reduced for both client and server. +- Decreased connection setup time particularly with high latency connections, + the number of round trips has been reduced for both client and server. CPU time hasn't been changed. -- Client will attempt to send an initial key exchange packet to save a round - trip. Dropbear implements an extension kexguess2@matt.ucc.asn.au to allow - the first packet guess to succeed in wider circumstances than the standard - behaviour. When communicating with other implementations the standard - behaviour is used. +- Client will send an initial key exchange guess to save a round trip. + Dropbear implements an extension kexguess2@matt.ucc.asn.au to allow the first + packet guess to succeed in wider circumstances than the standard behaviour. + When communicating with other implementations the standard behaviour is used. - Client side: when public key or password authentication with - $DROPBEAR_PASSWORD is used, an initial authentication request will + $DROPBEAR_PASSWORD is used an initial authentication request will be sent immediately rather than querying the list of available methods. This behaviour is enabled by CLI_IMMEDIATE_AUTH option (on by default), please let the Dropbear author know if it causes any interoperability @@ -20,7 +19,8 @@ - Implement client escape characters ~. (terminate session) and ~^Z (background session) -- Server will more reliably clean up utmp when connection is closed +- Server will more reliably clean up utmp when connection is closed, reported by + Mattias Walström - Don't crash if /dev/urandom isn't writable (RHEL5), thanks to Scott Case @@ -28,11 +28,15 @@ - scp didn't work properly on systems using vfork(), thanks to Frank Van Uffelen -- Added IUTF8 terminal mode support. Not yet standardised though seems that it - will soon be +- Added IUTF8 terminal mode support (Linux and Mac OS). Not standardised yet +though probably will be soon - Some verbose DROPBEAR_TRACE output is now hidden unless $DROPBEAR_TRACE2 - enviroment variable is set + enviroment variable is set + +- Fix using asymmetric MAC algorithms (broke in ) + +- Renamed configure.in to configure.ac to quieten autoconf, from Mike Frysinger 2013.56 - Thursday 21 March 2013 diff --git a/cli-runopts.c b/cli-runopts.c index d95dad5..a6e2b06 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -504,7 +504,7 @@ multihop_passthrough_args() { total += written; } - /* if args where passed, total will be not zero, and it will have a space at the end, so remove that */ + /* if args were passed, total will be not zero, and it will have a space at the end, so remove that */ if (total > 0) { total--; diff --git a/debian/changelog b/debian/changelog index 7b17620..11e924e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +dropbear (2013.57-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Mon, 15 Apr 2013 22:54:00 +0800 + dropbear (2013.56-0.1) unstable; urgency=low * New upstream release. From b4cdfcb506dd872b871ae1fad97e474c0658c286 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 15 Apr 2013 21:56:04 +0800 Subject: [PATCH 32/48] bump version to 2013.57 --- sysoptions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysoptions.h b/sysoptions.h index 22c2a4d..3072d3d 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -4,7 +4,7 @@ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "2013.56" +#define DROPBEAR_VERSION "2013.57" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION From 38f42a0fa204e81f2f23357f72c91d6f09654546 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 15 Apr 2013 22:01:41 +0800 Subject: [PATCH 33/48] Fix error message for requirenext change --- process-packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/process-packet.c b/process-packet.c index 3ac0c1b..ecc4863 100644 --- a/process-packet.c +++ b/process-packet.c @@ -77,8 +77,8 @@ void process_packet() { if (ses.requirenext[0] != 0) { if (ses.requirenext[0] != type && (ses.requirenext[1] == 0 || ses.requirenext[1] != type)) { - dropbear_exit("Unexpected packet type %d, expected %d", type, - ses.requirenext); + dropbear_exit("Unexpected packet type %d, expected [%d,%d]", type, + ses.requirenext[0], ses.requirenext[1]); } else { /* Got what we expected */ ses.requirenext[0] = 0; From 79a307bca2126cba846b890d0fee66dea13c15bd Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 15 Apr 2013 22:10:49 +0800 Subject: [PATCH 34/48] Added tag DROPBEAR_2013.57 for changeset 96b8bcb88017 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 71a20fe..7bf1a7a 100644 --- a/.hgtags +++ b/.hgtags @@ -36,3 +36,4 @@ d354464b2aa6f6ba0bf44d43bcae5aa798435393 DROPBEAR_2012.55 d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1 0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1 1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56 +96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57 From bd7a46f514c708ddf0a575e1f2bb5cbf0336b09e Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 15 Apr 2013 22:11:11 +0800 Subject: [PATCH 35/48] Added signature for changeset 095b46180bbc --- .hgsigs | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgsigs b/.hgsigs index 5dcb50e..7d3e8fb 100644 --- a/.hgsigs +++ b/.hgsigs @@ -2,3 +2,4 @@ aa2f51a6b81d33de5e9898a7f27c792a173d9b26 0 iD8DBQBOuADmjPn4sExkf7wRAv/fAJ9FJFvjD 3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 0 iD8DBQBOuSlQjPn4sExkf7wRAvkbAKCgE1e8xEMQ16CGeoywhIQ0QR4eNgCfZdYYlzjb/+521Uvh5/7FRYEmrho= 85f835f2fe0ac2c503c50a414de127222fb0a57c 0 iD8DBQBPRkMUjPn4sExkf7wRAvM4AJ9mw2OAkyjhSbamM1MizlEJUX18HACgoFKQkYf6BnYxN34Nv2HhM0cmzUc= 9b80981212fe6c01b7c16b3ca7c4e66af56f12f1 0 iEYEABECAAYFAlFLKKcACgkQjPn4sExkf7xK7wCfcioCmJPsysSbQO6+4qZMVe0mmLwAn2/o+wRf4MrUXlohrr7aXEF9vdSB +095b46180bbc412b029420587736a6185afc17e1 0 iEYEABECAAYFAlFsCnkACgkQjPn4sExkf7xLrwCfeMWjUaSmfU/fvseT5TdrYRqBEVQAoLz5SFLEA40C5f8zE8Ma/vgVJVIC From 154a65fc31922d612a44c0a839c2a7c27f722390 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 16 Apr 2013 22:16:32 +0800 Subject: [PATCH 36/48] Fix build when zlib is disabled, from http://freetz.org/browser/trunk/make/dropbear/patches/350-no_zlib_fix.patch --- common-kex.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common-kex.c b/common-kex.c index ba06e4f..a488877 100644 --- a/common-kex.c +++ b/common-kex.c @@ -171,14 +171,18 @@ static void switch_keys() { } if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) { TRACE(("switch_keys recv")) +#ifndef DISABLE_ZLIB gen_new_zstream_recv(); +#endif ses.keys->recv = ses.newkeys->recv; m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv)); ses.newkeys->recv.valid = 0; } if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) { TRACE(("switch_keys trans")) +#ifndef DISABLE_ZLIB gen_new_zstream_trans(); +#endif ses.keys->trans = ses.newkeys->trans; m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans)); ses.newkeys->trans.valid = 0; From 54a76342f5e4df4e6510b38815bb95ad44d6ef36 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 17 Apr 2013 22:29:18 +0800 Subject: [PATCH 37/48] If running as non-root only allow that user to log in --- loginrec.c | 2 -- svr-auth.c | 13 +++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/loginrec.c b/loginrec.c index 14b8090..d6ec75f 100644 --- a/loginrec.c +++ b/loginrec.c @@ -329,8 +329,6 @@ login_write (struct logininfo *li) { #ifndef HAVE_CYGWIN if ((int)geteuid() != 0) { - dropbear_log(LOG_WARNING, - "Attempt to write login records by non-root user (aborting)"); return 1; } #endif diff --git a/svr-auth.c b/svr-auth.c index 404232e..1912660 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -226,6 +226,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) { char* listshell = NULL; char* usershell = NULL; + int uid; TRACE(("enter checkusername")) if (userlen > MAX_USERNAME_LEN) { return DROPBEAR_FAILURE; @@ -255,6 +256,18 @@ static int checkusername(unsigned char *username, unsigned int userlen) { return DROPBEAR_FAILURE; } + /* check if we are running as non-root, and login user is different from the server */ + uid = geteuid(); + if (uid != 0 && uid != ses.authstate.pw_uid) { + TRACE(("running as nonroot, only server uid is allowed")) + dropbear_log(LOG_WARNING, + "Login attempt with wrong user %s from %s", + ses.authstate.pw_name, + svr_ses.addrstring); + send_msg_userauth_failure(0, 1); + return DROPBEAR_FAILURE; + } + /* check for non-root if desired */ if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { TRACE(("leave checkusername: root login disabled")) From 3525cabf48eb97d2e58a1e715e70fab399d40568 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 17 Apr 2013 22:48:43 +0800 Subject: [PATCH 38/48] Use '#' for host#port separator, document it. This fixes scp in multihop --- cli-runopts.c | 6 +++++- dbclient.1 | 9 ++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cli-runopts.c b/cli-runopts.c index a6e2b06..62568b0 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -610,7 +610,11 @@ static void parse_hostname(const char* orighostarg) { cli_opts.username = m_strdup(cli_opts.own_user); } - port = strchr(cli_opts.remotehost, '/'); + port = strchr(cli_opts.remotehost, '#'); + if (!port) { + // legacy separator + port = strchr(cli_opts.remotehost, '/'); + } if (port) { *port = '\0'; cli_opts.remoteport = port+1; diff --git a/dbclient.1 b/dbclient.1 index aac32ff..2379e4a 100644 --- a/dbclient.1 +++ b/dbclient.1 @@ -15,7 +15,7 @@ dbclient \- lightweight SSH2 client .B dbclient [ .I args ] -.I [user1]@host1[/port1],[user2]@host2[/port2],... +.I [user1]@host1[#port1],[user2]@host2[#port2],... .SH DESCRIPTION .B dbclient @@ -24,10 +24,9 @@ environments, while still being functional and secure enough for general use. .SH OPTIONS .TP .B \-p \fIport -Remote port. -Connect to port +Connect to .I port -on the remote host. +on the remote host. Alternatively a port can be specified as hostname#port. Default is 22. .TP .B \-i \fIidfile @@ -127,7 +126,7 @@ Dropbear will also allow multiple "hops" to be specified, separated by commas. I this case a connection will be made to the first host, then a TCP forwarded connection will be made through that to the second host, and so on. Hosts other than the final destination will not see anything other than the encrypted SSH stream. -A port for a host can be specified with a slash (eg matt@martello/44 ). +A port for a host can be specified with a hash (eg matt@martello#44 ). This syntax can also be used with scp or rsync (specifying dbclient as the ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg From f98eb5808bd5fbdf7463f2d7233bb3cc52b12f89 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 17 Apr 2013 23:17:27 +0800 Subject: [PATCH 39/48] Use % rather than # for port delimiter --- cli-runopts.c | 2 +- dbclient.1 | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli-runopts.c b/cli-runopts.c index 62568b0..91a2f42 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -610,7 +610,7 @@ static void parse_hostname(const char* orighostarg) { cli_opts.username = m_strdup(cli_opts.own_user); } - port = strchr(cli_opts.remotehost, '#'); + port = strchr(cli_opts.remotehost, '%'); if (!port) { // legacy separator port = strchr(cli_opts.remotehost, '/'); diff --git a/dbclient.1 b/dbclient.1 index 2379e4a..7ad550f 100644 --- a/dbclient.1 +++ b/dbclient.1 @@ -15,7 +15,7 @@ dbclient \- lightweight SSH2 client .B dbclient [ .I args ] -.I [user1]@host1[#port1],[user2]@host2[#port2],... +.I [user1]@host1[%port1],[user2]@host2[%port2],... .SH DESCRIPTION .B dbclient @@ -26,7 +26,7 @@ environments, while still being functional and secure enough for general use. .B \-p \fIport Connect to .I port -on the remote host. Alternatively a port can be specified as hostname#port. +on the remote host. Alternatively a port can be specified as hostname%port. Default is 22. .TP .B \-i \fIidfile @@ -126,7 +126,7 @@ Dropbear will also allow multiple "hops" to be specified, separated by commas. I this case a connection will be made to the first host, then a TCP forwarded connection will be made through that to the second host, and so on. Hosts other than the final destination will not see anything other than the encrypted SSH stream. -A port for a host can be specified with a hash (eg matt@martello#44 ). +A port for a host can be specified with a hash (eg matt@martello%44 ). This syntax can also be used with scp or rsync (specifying dbclient as the ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg From 43769b5bb370cb932012eccb3bca7487955760f0 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 18 Apr 2013 21:47:38 +0800 Subject: [PATCH 40/48] Don't enable CLI_IMMEDIATE_AUTH by default, it breaks blank password logins --- options.h | 7 +++++++ sysoptions.h | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/options.h b/options.h index 88b17ca..7d06322 100644 --- a/options.h +++ b/options.h @@ -204,6 +204,13 @@ much traffic. */ * return the password on standard output */ /*#define ENABLE_CLI_ASKPASS_HELPER*/ +/* Send a real auth request first rather than requesting a list of available methods. + * It saves a network round trip at login but prevents immediate login to + * accounts with no password, and might be rejected by some strict servers (none + * encountered yet) - hence it isn't enabled by default. */ +/* #define CLI_IMMEDIATE_AUTH */ + + /* Source for randomness. This must be able to provide hundreds of bytes per SSH * connection without blocking. In addition /dev/random is used for seeding * rsa/dss key generation */ diff --git a/sysoptions.h b/sysoptions.h index 3072d3d..be736ef 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -198,9 +198,6 @@ #define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */ #endif -/* Send an auth request straight away rather than trying "none" type to get a list */ -#define CLI_IMMEDIATE_AUTH - /* Changing this is inadvisable, it appears to have problems * with flushing compressed data */ #define DROPBEAR_ZLIB_MEM_LEVEL 8 From 6da90b34febf3d1796ef0810281908fe415a2964 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 18 Apr 2013 22:57:47 +0800 Subject: [PATCH 41/48] 2013.58 --- CHANGES | 11 +++++++++++ debian/changelog | 6 ++++++ sysoptions.h | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index afe972e..abd9b46 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,14 @@ +2013.58 - Thursday 18 April 2013 + +- Fix building with Zlib disabled, thanks to Hans Harder and cuma@freetz + +- Use % as a separator for ports, fixes scp in multihop mode, from Hans Harder + +- Reject logins for other users when running as non-root, from Hans Harder + +- Disable client immediate authentication request by default, it prevents + passwordless logins from working + 2013.57 - Monday 15 April 2013 - Decreased connection setup time particularly with high latency connections, diff --git a/debian/changelog b/debian/changelog index 11e924e..d6aeeb8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +dropbear (2013.58-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Thu, 18 Apr 2013 22:54:00 +0800 + dropbear (2013.57-0.1) unstable; urgency=low * New upstream release. diff --git a/sysoptions.h b/sysoptions.h index be736ef..c12f5d1 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -4,7 +4,7 @@ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "2013.57" +#define DROPBEAR_VERSION "2013.58" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION From 791a78ad1fdcbcadf229b23a8626bd1c22fa7ce3 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 18 Apr 2013 23:10:19 +0800 Subject: [PATCH 42/48] Added tag DROPBEAR_2013.58 for changeset e76614145aea --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 7bf1a7a..d3e2f04 100644 --- a/.hgtags +++ b/.hgtags @@ -37,3 +37,4 @@ d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1 0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1 1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56 96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57 +e76614145aea67f66e4a4257685c771efba21aa1 DROPBEAR_2013.58 From e4c672bdbb7b529cdbe56845312417eb12900829 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 18 Apr 2013 23:10:24 +0800 Subject: [PATCH 43/48] Added signature for changeset f168962bab85 --- .hgsigs | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgsigs b/.hgsigs index 7d3e8fb..5c5eb40 100644 --- a/.hgsigs +++ b/.hgsigs @@ -3,3 +3,4 @@ aa2f51a6b81d33de5e9898a7f27c792a173d9b26 0 iD8DBQBOuADmjPn4sExkf7wRAv/fAJ9FJFvjD 85f835f2fe0ac2c503c50a414de127222fb0a57c 0 iD8DBQBPRkMUjPn4sExkf7wRAvM4AJ9mw2OAkyjhSbamM1MizlEJUX18HACgoFKQkYf6BnYxN34Nv2HhM0cmzUc= 9b80981212fe6c01b7c16b3ca7c4e66af56f12f1 0 iEYEABECAAYFAlFLKKcACgkQjPn4sExkf7xK7wCfcioCmJPsysSbQO6+4qZMVe0mmLwAn2/o+wRf4MrUXlohrr7aXEF9vdSB 095b46180bbc412b029420587736a6185afc17e1 0 iEYEABECAAYFAlFsCnkACgkQjPn4sExkf7xLrwCfeMWjUaSmfU/fvseT5TdrYRqBEVQAoLz5SFLEA40C5f8zE8Ma/vgVJVIC +f168962bab857ca030829e4cd73d9b32c868c874 0 iEYEABECAAYFAlFwDNwACgkQjPn4sExkf7wJ6QCePVovn/avKXUyNwNBYCcov6JLYqkAnRCPQdkXgv20N3t10r6PRMBBo1/S From 3ea9068e1825f77d0ada7f146bb4ae3d1335ff61 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 18 Apr 2013 23:15:17 +0800 Subject: [PATCH 44/48] Save with utf8 encoding --- CHANGES | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index abd9b46..65d237b 100644 --- a/CHANGES +++ b/CHANGES @@ -31,7 +31,7 @@ ~^Z (background session) - Server will more reliably clean up utmp when connection is closed, reported by - Mattias Walström + Mattias Walström - Don't crash if /dev/urandom isn't writable (RHEL5), thanks to Scott Case @@ -71,10 +71,10 @@ though probably will be soon - Allow using IPv6 bracket notation for addresses in server "-p" option, from Ben Jencks -- A few improvements for Android from Reimar Döffinger +- A few improvements for Android from Reimar Döffinger - Fix memory leak for TCP forwarded connections to hosts that timed out, - reported by Norbert Benczúr. Appears to be a very long-standing bug. + reported by Norbert Benczúr. Appears to be a very long-standing bug. - Fix "make clean" for out of tree builds @@ -700,7 +700,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default Lobenstock and Mihnea Stoenescu - Use daemon() function if available (or our own copy) rather than separate - code (thanks to Frédéric Lavernhe for the report and debugging, and Bernard + code (thanks to Frédéric Lavernhe for the report and debugging, and Bernard Blackham for his suggestion on what to look at) - Fixed up support for first_kex_packet_follows, required to talk to ssh.com @@ -819,7 +819,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default - Various signedness fixes - Can listen on multiple ports - added option to disable openpty with configure script, - (from K.-P. Kirchdörfer ) + (from K.-P. Kirchdörfer ) - Various cleanups to bignum code (thanks to Tom St Denis ) - Fix compile error when disabling RSA From 57166b400c25c2e45b23639a413edc3620cf2812 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 29 Apr 2013 23:42:37 +0800 Subject: [PATCH 45/48] Avoid segfault for locked accounts (invalid salt to crypt()) --- svr-authpasswd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/svr-authpasswd.c b/svr-authpasswd.c index 38fccc2..17dd2a1 100644 --- a/svr-authpasswd.c +++ b/svr-authpasswd.c @@ -66,6 +66,14 @@ void svr_auth_password() { m_burn(password, passwordlen); m_free(password); + if (testcrypt == NULL) { + /* crypt() with an invalid salt like "!!" */ + dropbear_log(LOG_WARNING, "User account '%s' is locked", + ses.authstate.pw_name); + send_msg_userauth_failure(0, 1); + return; + } + /* check for empty password */ if (passwdcrypt[0] == '\0') { dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected", From 49263b5314e59de654d7b01f513b1cd95b1b9ec9 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 8 May 2013 23:23:14 +0800 Subject: [PATCH 46/48] Limit decompressed size --- packet.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packet.c b/packet.c index 09f0600..d458ccf 100644 --- a/packet.c +++ b/packet.c @@ -42,7 +42,7 @@ static void make_mac(unsigned int seqno, const struct key_context_directional * static int checkmac(); #define ZLIB_COMPRESS_INCR 100 -#define ZLIB_DECOMPRESS_INCR 100 +#define ZLIB_DECOMPRESS_INCR 1024 #ifndef DISABLE_ZLIB static buffer* buf_decompress(buffer* buf, unsigned int len); static void buf_compress(buffer * dest, buffer * src, unsigned int len); @@ -420,7 +420,12 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) { } if (zstream->avail_out == 0) { - buf_resize(ret, ret->size + ZLIB_DECOMPRESS_INCR); + int new_size = 0; + if (ret->size >= RECV_MAX_PAYLOAD_LEN) { + dropbear_exit("bad packet, oversized decompressed"); + } + new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR); + buf_resize(ret, new_size); } } } From 372e81a84202a1ca21bbb81f562ac6df66fce615 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 13 May 2013 21:06:35 +0800 Subject: [PATCH 47/48] Update config.guess and config.sub --- config.guess | 601 +++++++++++++++++++++++++++------------------------ config.sub | 368 ++++++++++++++++++++++--------- 2 files changed, 583 insertions(+), 386 deletions(-) diff --git a/config.guess b/config.guess index 6cc26cd..2055429 100644 --- a/config.guess +++ b/config.guess @@ -1,14 +1,12 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. +# Copyright 1992-2013 Free Software Foundation, Inc. -timestamp='2007-01-15' +timestamp='2013-04-24' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -17,26 +15,22 @@ timestamp='2007-01-15' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Originally written by Per Bothner . -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). # -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. +# Originally written by Per Bothner. # -# The plan is that this can be called by configure scripts if you -# don't specify an explicit build system type. +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches with a ChangeLog entry to config-patches@gnu.org. + me=`echo "$0" | sed -e 's,.*/,,'` @@ -56,8 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. +Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -144,7 +137,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward @@ -170,7 +163,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep __ELF__ >/dev/null + | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? @@ -180,7 +173,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in fi ;; *) - os=netbsd + os=netbsd ;; esac # The OS release @@ -201,6 +194,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} @@ -223,7 +220,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on @@ -269,7 +266,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit ;; + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead @@ -295,12 +295,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo s390-ibm-zvmoe exit ;; *:OS400:*:*) - echo powerpc-ibm-os400 + echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; - arm:riscos:*:*|arm:RISCOS:*:*) + arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) @@ -324,14 +324,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; - i86pc:SunOS:5.*:*) - echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize @@ -375,23 +394,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; @@ -461,8 +480,8 @@ EOF echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ @@ -475,7 +494,7 @@ EOF else echo i586-dg-dgux${UNAME_RELEASE} fi - exit ;; + exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; @@ -532,7 +551,7 @@ EOF echo rs6000-ibm-aix3.2 fi exit ;; - *:AIX:*:[45]) + *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 @@ -575,52 +594,52 @@ EOF 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac + esac ;; + esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + sed 's/^ //' << EOF >$dummy.c - #define _HPUX_SOURCE - #include - #include + #define _HPUX_SOURCE + #include + #include - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa @@ -640,7 +659,7 @@ EOF # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | - grep __LP64__ >/dev/null + grep -q __LP64__ then HP_ARCH="hppa2.0w" else @@ -711,22 +730,22 @@ EOF exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd - exit ;; + exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi - exit ;; + exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd - exit ;; + exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd - exit ;; + exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd - exit ;; + exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; @@ -750,14 +769,14 @@ EOF exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} @@ -769,37 +788,51 @@ EOF echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) - case ${UNAME_MACHINE} in - pc98) - echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; - x86:Interix*:[3456]*) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; - EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*) - echo x86_64-unknown-interix${UNAME_RELEASE} - exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we @@ -829,85 +862,13 @@ EOF i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; - arm*:Linux:*:*) + aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; - avr32*:Linux:*:*) + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; - cris:Linux:*:*) - echo cris-axis-linux-gnu - exit ;; - crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu - exit ;; - frv:Linux:*:*) - echo frv-unknown-linux-gnu - exit ;; - ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - mips:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips - #undef mipsel - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mipsel - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips64 - #undef mips64el - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mips64el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips64 - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - or32:Linux:*:*) - echo or32-unknown-linux-gnu - exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu - exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; @@ -917,11 +878,101 @@ EOF EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif + #else + #include + #ifdef __UCLIBC__ + LIBC=uclibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or1k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in @@ -930,14 +981,17 @@ EOF *) echo hppa-unknown-linux-gnu ;; esac exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-gnu + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu @@ -945,78 +999,20 @@ EOF sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu - exit ;; - xtensa:Linux:*:*) - echo xtensa-unknown-linux-gnu - exit ;; - i*86:Linux:*:*) - # The BFD linker knows what the default object file format is, so - # first see if it will tell us. cd to the root directory to prevent - # problems with other programs or directories called `ld' in the path. - # Set LC_ALL=C to ensure ld outputs messages in English. - ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ - | sed -ne '/supported targets:/!d - s/[ ][ ]*/ /g - s/.*supported targets: *// - s/ .*// - p'` - case "$ld_supported_targets" in - elf32-i386) - TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" - ;; - a.out-i386-linux) - echo "${UNAME_MACHINE}-pc-linux-gnuaout" - exit ;; - coff-i386) - echo "${UNAME_MACHINE}-pc-linux-gnucoff" - exit ;; - "") - # Either a pre-BFD a.out linker (linux-gnuoldld) or - # one that does not give us useful --help. - echo "${UNAME_MACHINE}-pc-linux-gnuoldld" - exit ;; - esac - # Determine whether the default compiler is a.out or elf - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - #ifdef __ELF__ - # ifdef __GLIBC__ - # if __GLIBC__ >= 2 LIBC=gnu - # else - LIBC=gnulibc1 - # endif - # else - LIBC=gnulibc1 - # endif - #else - #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) - LIBC=gnu - #else - LIBC=gnuaout - #endif - #endif - #ifdef __dietlibc__ - LIBC=dietlibc - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^LIBC/{ - s: ::g - p - }'`" - test x"${LIBC}" != x && { - echo "${UNAME_MACHINE}-pc-linux-${LIBC}" - exit - } - test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } - ;; + test -r /lib/libc.so && od -An -S13 /lib/libc.so | grep -q __uClibc_main && LIBC=uclibc + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both @@ -1024,11 +1020,11 @@ EOF echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. + # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) @@ -1045,7 +1041,7 @@ EOF i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) @@ -1060,7 +1056,7 @@ EOF fi exit ;; i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. + # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; @@ -1088,10 +1084,13 @@ EOF exit ;; pc:*:*:*) # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i386. - echo i386-pc-msdosdjgpp - exit ;; + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; @@ -1126,8 +1125,18 @@ EOF /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; @@ -1140,7 +1149,7 @@ EOF rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) @@ -1160,10 +1169,10 @@ EOF echo ns32k-sni-sysv fi exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm @@ -1189,11 +1198,11 @@ EOF exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv${UNAME_RELEASE} else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv${UNAME_RELEASE} fi - exit ;; + exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; @@ -1203,6 +1212,12 @@ EOF BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; @@ -1230,6 +1245,16 @@ EOF *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} @@ -1245,7 +1270,10 @@ EOF *:QNX:*:4*) echo i386-pc-qnx exit ;; - NSE-?:NONSTOP_KERNEL:*:*) + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) @@ -1290,13 +1318,13 @@ EOF echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` + UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; @@ -1311,11 +1339,14 @@ EOF i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; esac -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - eval $set_cc_for_build cat >$dummy.c < printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 - "4" + "4" #else - "" + "" #endif - ); exit (0); + ); exit (0); #endif #endif @@ -1471,9 +1502,9 @@ This script, last modified $timestamp, has failed to recognize the operating system you are using. It is advised that you download the most up to date version of the config scripts from - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD and - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD If the version you run ($0) is already up to date, please send the following data and any information you think might be diff --git a/config.sub b/config.sub index 5defff6..8b612ab 100644 --- a/config.sub +++ b/config.sub @@ -1,44 +1,40 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. +# Copyright 1992-2013 Free Software Foundation, Inc. -timestamp='2007-01-18' +timestamp='2013-04-24' -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. +# Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. @@ -72,8 +68,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. +Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -120,12 +115,18 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ - uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] @@ -148,10 +149,13 @@ case $os in -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray) + -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; + -bluegene*) + os=-cnk + ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 @@ -166,10 +170,10 @@ case $os in os=-chorusos basic_machine=$1 ;; - -chorusrdb) - os=-chorusrdb + -chorusrdb) + os=-chorusrdb basic_machine=$1 - ;; + ;; -hiux*) os=-hiuxwe2 ;; @@ -214,6 +218,12 @@ case $os in -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; -lynx*) os=-lynxos ;; @@ -238,24 +248,34 @@ case $basic_machine in # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ + | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ + | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | mcore | mep \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ - | mips64vr | mips64vrel \ + | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ @@ -266,31 +286,45 @@ case $basic_machine in | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ + | moxie \ | mt \ | msp430 \ - | nios | nios2 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ - | or32 \ + | open8 \ + | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ + | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu | strongarm \ - | tahoe | thumb | tic4x | tic80 | tron \ - | v850 | v850e \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ - | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ - | z8k) + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) basic_machine=$basic_machine-unknown ;; - m6811 | m68hc11 | m6812 | m68hc12) - # Motorola 68HC11/12. + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; @@ -300,6 +334,21 @@ case $basic_machine in basic_machine=mt-unknown ;; + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. @@ -314,29 +363,37 @@ case $basic_machine in # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ + | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | be32-* | be64-* \ | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ - | mips64vr-* | mips64vrel-* \ + | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ @@ -347,31 +404,41 @@ case $basic_machine in | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ - | nios-* | nios2-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ - | romp-* | rs6000-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ - | tahoe-* | thumb-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ | tron-* \ - | v850-* | v850e-* | vax-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ - | xstormy16-* | xtensa-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ | ymp-* \ - | z8k-*) + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. @@ -389,7 +456,7 @@ case $basic_machine in basic_machine=a29k-amd os=-udi ;; - abacus) + abacus) basic_machine=abacus-unknown ;; adobe68k) @@ -435,6 +502,10 @@ case $basic_machine in basic_machine=m68k-apollo os=-bsd ;; + aros) + basic_machine=i386-pc + os=-aros + ;; aux) basic_machine=m68k-apple os=-aux @@ -443,10 +514,35 @@ case $basic_machine in basic_machine=ns32k-sequent os=-dynix ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; c90) basic_machine=c90-cray os=-unicos ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; convex-c1) basic_machine=c1-convex os=-bsd @@ -475,8 +571,8 @@ case $basic_machine in basic_machine=craynv-cray os=-unicosmp ;; - cr16c) - basic_machine=cr16c-unknown + cr16 | cr16-*) + basic_machine=cr16-unknown os=-elf ;; crds | unos) @@ -514,6 +610,10 @@ case $basic_machine in basic_machine=m88k-motorola os=-sysv3 ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp @@ -629,7 +729,6 @@ case $basic_machine in i370-ibm* | ibm*) basic_machine=i370-ibm ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 @@ -668,6 +767,14 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; m88k-omron*) basic_machine=m88k-omron ;; @@ -679,10 +786,21 @@ case $basic_machine in basic_machine=ns32k-utek os=-sysv ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; miniframe) basic_machine=m68000-convergent ;; @@ -711,10 +829,18 @@ case $basic_machine in ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; + msys) + basic_machine=i386-pc + os=-msys + ;; mvs) basic_machine=i370-ibm os=-mvs ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; ncr3000) basic_machine=i486-ncr os=-sysv4 @@ -779,6 +905,12 @@ case $basic_machine in np1) basic_machine=np1-gould ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; nsr-tandem) basic_machine=nsr-tandem ;; @@ -809,6 +941,14 @@ case $basic_machine in basic_machine=i860-intel os=-osf ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; pbd) basic_machine=sparc-tti ;; @@ -853,9 +993,10 @@ case $basic_machine in ;; power) basic_machine=power-ibm ;; - ppc) basic_machine=powerpc-unknown + ppc | ppcbe) basic_machine=powerpc-unknown ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown @@ -880,7 +1021,11 @@ case $basic_machine in basic_machine=i586-unknown os=-pw32 ;; - rdos) + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) basic_machine=i386-pc os=-rdos ;; @@ -949,6 +1094,9 @@ case $basic_machine in basic_machine=i860-stratus os=-sysv4 ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; sun2) basic_machine=m68000-sun ;; @@ -1005,17 +1153,9 @@ case $basic_machine in basic_machine=t90-cray os=-unicos ;; - tic54x | c54x*) - basic_machine=tic54x-unknown - os=-coff - ;; - tic55x | c55x*) - basic_machine=tic55x-unknown - os=-coff - ;; - tic6x | c6x*) - basic_machine=tic6x-unknown - os=-coff + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown @@ -1084,6 +1224,9 @@ case $basic_machine in xps | xps100) basic_machine=xps100-honeywell ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; ymp) basic_machine=ymp-cray os=-unicos @@ -1092,6 +1235,10 @@ case $basic_machine in basic_machine=z8k-unknown os=-sim ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; none) basic_machine=none-none os=-none @@ -1130,7 +1277,7 @@ case $basic_machine in we32k) basic_machine=we32k-att ;; - sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) @@ -1177,9 +1324,12 @@ esac if [ x"$os" != x"" ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. + # First match some system type aliases + # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; @@ -1200,21 +1350,23 @@ case $os in # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* \ + | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ @@ -1222,7 +1374,7 @@ case $os in | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1261,7 +1413,7 @@ case $os in -opened*) os=-openedition ;; - -os400*) + -os400*) os=-os400 ;; -wince*) @@ -1310,7 +1462,7 @@ case $os in -sinix*) os=-sysv4 ;; - -tpf*) + -tpf*) os=-tpf ;; -triton*) @@ -1346,12 +1498,14 @@ case $os in -aros*) os=-aros ;; - -kaos*) - os=-kaos - ;; -zvmoe) os=-zvmoe ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; -none) ;; *) @@ -1374,10 +1528,10 @@ else # system, and we'll never get to this point. case $basic_machine in - score-*) + score-*) os=-elf ;; - spu-*) + spu-*) os=-elf ;; *-acorn) @@ -1389,8 +1543,20 @@ case $basic_machine in arm*-semi) os=-aout ;; - c4x-* | tic4x-*) - os=-coff + c4x-* | tic4x-*) + os=-coff + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff ;; # This must come before the *-dec entry. pdp10-*) @@ -1410,14 +1576,11 @@ case $basic_machine in ;; m68000-sun) os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 ;; m68*-cisco) os=-aout ;; - mep-*) + mep-*) os=-elf ;; mips*-cisco) @@ -1426,6 +1589,9 @@ case $basic_machine in mips*-*) os=-elf ;; + or1k-*) + os=-elf + ;; or32-*) os=-coff ;; @@ -1444,7 +1610,7 @@ case $basic_machine in *-ibm) os=-aix ;; - *-knuth) + *-knuth) os=-mmixware ;; *-wec) @@ -1549,7 +1715,7 @@ case $basic_machine in -sunos*) vendor=sun ;; - -aix*) + -cnk*|-aix*) vendor=ibm ;; -beos*) From a57947c513a53e77de0b2eaa67ca6404f444a29f Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 13 May 2013 21:35:13 +0800 Subject: [PATCH 48/48] Fix bad comma in header list --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 05461f3..a98b629 100644 --- a/configure.ac +++ b/configure.ac @@ -211,7 +211,7 @@ AC_ARG_ENABLE(shadow, # 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 netinet/in_systm.h, sys/uio.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 sys/uio.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST