diff options
-rw-r--r-- | CHANGES | 21 | ||||
-rw-r--r-- | Makefile.in | 2 | ||||
-rw-r--r-- | TODO | 8 | ||||
-rw-r--r-- | algo.h | 4 | ||||
-rw-r--r-- | auth.h | 8 | ||||
-rw-r--r-- | bignum.c | 4 | ||||
-rw-r--r-- | bignum.h | 2 | ||||
-rw-r--r-- | buffer.c | 10 | ||||
-rw-r--r-- | buffer.h | 1 | ||||
-rw-r--r-- | channel.h | 2 | ||||
-rw-r--r-- | cli-auth.c | 2 | ||||
-rw-r--r-- | cli-authpubkey.c | 26 | ||||
-rw-r--r-- | cli-channel.c | 5 | ||||
-rw-r--r-- | cli-chansession.c | 2 | ||||
-rw-r--r-- | cli-runopts.c | 12 | ||||
-rw-r--r-- | cli-session.c | 16 | ||||
-rw-r--r-- | cli-tcpfwd.c | 2 | ||||
-rw-r--r-- | common-algo.c | 4 | ||||
-rw-r--r-- | common-channel.c | 46 | ||||
-rw-r--r-- | common-kex.c | 27 | ||||
-rw-r--r-- | dbclient.1 | 69 | ||||
-rw-r--r-- | dbutil.c | 3 | ||||
-rw-r--r-- | dbutil.h | 2 | ||||
-rw-r--r-- | debian/README.Debian.diet | 15 | ||||
-rw-r--r-- | debug.h | 2 | ||||
-rw-r--r-- | dropbear.8 | 2 | ||||
-rw-r--r-- | dropbearkey.8 | 2 | ||||
-rw-r--r-- | dss.c | 34 | ||||
-rw-r--r-- | gendss.c | 28 | ||||
-rw-r--r-- | genrsa.c | 5 | ||||
-rw-r--r-- | includes.h | 2 | ||||
-rw-r--r-- | kex.h | 6 | ||||
-rw-r--r-- | options.h | 16 | ||||
-rw-r--r-- | packet.c | 3 | ||||
-rw-r--r-- | random.c | 61 | ||||
-rw-r--r-- | random.h | 3 | ||||
-rw-r--r-- | rsa.c | 92 | ||||
-rw-r--r-- | runopts.h | 2 | ||||
-rw-r--r-- | scp.c | 3 | ||||
-rw-r--r-- | session.h | 7 | ||||
-rw-r--r-- | signkey.c | 22 | ||||
-rw-r--r-- | svr-authpam.c | 2 | ||||
-rw-r--r-- | svr-authpasswd.c | 2 | ||||
-rw-r--r-- | svr-authpubkey.c | 2 | ||||
-rw-r--r-- | svr-chansession.c | 10 | ||||
-rw-r--r-- | svr-tcpfwd.c | 2 | ||||
-rw-r--r-- | svr-x11fwd.c | 2 |
47 files changed, 373 insertions, 230 deletions
@@ -1,3 +1,24 @@ +0.46 + +- Fix long-standing bug which caused connections to be closed if an ssh-agent + socket was no longer available + +- print a warning if we seem to be blocking on /dev/random + (suggested by Paul Fox) + +- fixed a memory leak in DSS code (thanks to Boris Berezovsky for the patch) + +- dbclient -L no longer segfaults, allocate correct buffer size (thanks + to David Cook for reporting it) + +- added RSA blinding (recommended by Dan Kaminsky) + +- rearranged bignum reading/random generation code + +- Reset the non-blocking status on stderr and stdout as well as stdin, + fixes a problem where the shell running dbclient will exit (thanks to + Brent Roman for reporting it) + 0.45 - Mon March 7 2005 - Makefile no longer appends 'static' to statically linked binaries diff --git a/Makefile.in b/Makefile.in index 1fa0f99..fc820dd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -69,7 +69,7 @@ AR=@AR@ RANLIB=@RANLIB@ STRIP=@STRIP@ INSTALL=@INSTALL@ -CFLAGS=-I. -I$(srcdir)/libtomcrypt @CFLAGS@ +CFLAGS=-I. -I$(srcdir)/libtomcrypt/src/headers/ @CFLAGS@ LIBS=$(LTC) $(LTM) @LIBS@ LDFLAGS=@LDFLAGS@ @@ -2,12 +2,12 @@ Current: Things which might need doing: +- default private dbclient keys + - Make options.h generated from configure perhaps? - Improved queueing of unauthed connections -- fix agent fwd problems - - handle /etc/environment in AIX - check that there aren't timing issues with valid/invalid user authentication @@ -15,9 +15,9 @@ Things which might need doing: - Binding to different interfaces -- possible RSA blinding? need to check whether this is vuln to timing attacks - check PRNG -- CTR mode, SSH_MSG_IGNORE sending to improve CBC security +- CTR mode +- SSH_MSG_IGNORE sending to improve CBC security - DH Group Exchange possibly, or just add group14 (whatever it's called today) - fix scp.c for IRIX @@ -51,13 +51,13 @@ extern const struct dropbear_cipher dropbear_nocipher; extern const struct dropbear_hash dropbear_nohash; struct dropbear_cipher { - const struct _cipher_descriptor *cipherdesc; + const struct ltc_cipher_descriptor *cipherdesc; unsigned long keysize; unsigned char blocksize; }; struct dropbear_hash { - const struct _hash_descriptor *hashdesc; + const struct ltc_hash_descriptor *hashdesc; unsigned long keysize; unsigned char hashsize; }; @@ -84,13 +84,13 @@ struct AuthState { }; -struct PubkeyList; -/* A singly linked list of pubkeys */ -struct PubkeyList { +struct SignKeyList; +/* A singly linked list of signing keys */ +struct SignKeyList { sign_key *key; int type; /* The type of key */ - struct PubkeyList *next; + struct SignKeyList *next; /* filename? or the buffer? for encrypted keys, so we can later get * the private key portion */ @@ -52,9 +52,9 @@ void m_mp_init_multi(mp_int *mp, ...) va_end(args); } -void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len) { +void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) { - if (mp_read_unsigned_bin(mp, bytes, len) != MP_OKAY) { + if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) { dropbear_exit("mem alloc error"); } } @@ -29,7 +29,7 @@ void m_mp_init(mp_int *mp); void m_mp_init_multi(mp_int *mp, ...); -void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len); +void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len); void sha1_process_mp(hash_state *hs, mp_int *mp); #endif /* _BIGNUM_H_ */ @@ -160,6 +160,16 @@ unsigned char buf_getbyte(buffer* buf) { return buf->data[buf->pos++]; } +/* Get a bool from the buffer and increment the pos */ +unsigned char buf_getbool(buffer* buf) { + + unsigned char b; + b = buf_getbyte(buf); + if (b != 0) + b = 1; + return b; +} + /* put a byte, incrementing the length if required */ void buf_putbyte(buffer* buf, unsigned char val) { @@ -50,6 +50,7 @@ void buf_setpos(buffer* buf, unsigned int pos); void buf_incrpos(buffer* buf, int incr); /* -ve is ok, to go backwards */ void buf_incrwritepos(buffer* buf, unsigned int incr); unsigned char buf_getbyte(buffer* buf); +unsigned char buf_getbool(buffer* buf); void buf_putbyte(buffer* buf, unsigned char val); unsigned char* buf_getptr(buffer* buf, unsigned int len); unsigned char* buf_getwriteptr(buffer* buf, unsigned int len); @@ -100,7 +100,7 @@ void chaninitialise(); void chancleanup(); void setchannelfds(fd_set *readfd, fd_set *writefd); void channelio(fd_set *readfd, fd_set *writefd); -struct Channel* getchannel(unsigned int chan); +struct Channel* getchannel(); struct Channel* newchannel(unsigned int remotechan, const struct ChanType *type, unsigned int transwindow, unsigned int transmaxpacket); @@ -127,7 +127,7 @@ void recv_msg_userauth_failure() { methods = buf_getstring(ses.payload, &methlen); - partial = buf_getbyte(ses.payload); + partial = buf_getbool(ses.payload); if (partial) { dropbear_log(LOG_INFO, "Authentication partially succeeded, more attempts required"); diff --git a/cli-authpubkey.c b/cli-authpubkey.c index 61b17d9..9d36bc3 100644 --- a/cli-authpubkey.c +++ b/cli-authpubkey.c @@ -38,29 +38,29 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign); * We use it to remove the key we tried from the list */ void cli_pubkeyfail() { - struct PubkeyList *keyitem; - struct PubkeyList **previtem; + struct SignKeyList *keyitem; + struct SignKeyList **previtem; TRACE(("enter cli_pubkeyfail")) - previtem = &cli_opts.pubkeys; + previtem = &cli_opts.privkeys; /* Find the key we failed with, and remove it */ - for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) { - if (keyitem == cli_ses.lastpubkey) { + for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) { + if (keyitem == cli_ses.lastprivkey) { *previtem = keyitem->next; } previtem = &keyitem; } - sign_key_free(cli_ses.lastpubkey->key); /* It won't be used again */ - m_free(cli_ses.lastpubkey); + sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */ + m_free(cli_ses.lastprivkey); TRACE(("leave cli_pubkeyfail")) } void recv_msg_userauth_pk_ok() { - struct PubkeyList *keyitem; + struct SignKeyList *keyitem; buffer* keybuf; char* algotype = NULL; unsigned int algolen; @@ -80,7 +80,7 @@ void recv_msg_userauth_pk_ok() { /* Iterate through our keys, find which one it was that matched, and * send a real request with that key */ - for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) { + for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) { if (keyitem->type != keytype) { /* Types differed */ @@ -172,11 +172,11 @@ int cli_auth_pubkey() { TRACE(("enter cli_auth_pubkey")) - if (cli_opts.pubkeys != NULL) { + if (cli_opts.privkeys != NULL) { /* Send a trial request */ - send_msg_userauth_pubkey(cli_opts.pubkeys->key, - cli_opts.pubkeys->type, 0); - cli_ses.lastpubkey = cli_opts.pubkeys; + send_msg_userauth_pubkey(cli_opts.privkeys->key, + cli_opts.privkeys->type, 0); + cli_ses.lastprivkey = cli_opts.privkeys; TRACE(("leave cli_auth_pubkey-success")) return 1; } else { diff --git a/cli-channel.c b/cli-channel.c index 42e165b..1bd49ab 100644 --- a/cli-channel.c +++ b/cli-channel.c @@ -33,15 +33,12 @@ /* We receive channel data - only used by the client chansession code*/ void recv_msg_channel_extended_data() { - unsigned int chan; struct Channel *channel; unsigned int datatype; TRACE(("enter recv_msg_channel_extended_data")) - chan = buf_getint(ses.payload); - channel = getchannel(chan); - + channel = getchannel(); if (channel == NULL) { dropbear_exit("Unknown channel"); } diff --git a/cli-chansession.c b/cli-chansession.c index 76e9dfa..a8363ac 100644 --- a/cli-chansession.c +++ b/cli-chansession.c @@ -62,7 +62,7 @@ static void cli_chansessreq(struct Channel *channel) { TRACE(("enter cli_chansessreq")) type = buf_getstring(ses.payload, NULL); - wantreply = buf_getbyte(ses.payload); + wantreply = buf_getbool(ses.payload); if (strcmp(type, "exit-status") != 0) { TRACE(("unknown request '%s'", type)) diff --git a/cli-runopts.c b/cli-runopts.c index 3ac5c2b..285c51d 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -53,7 +53,7 @@ static void printhelp() { "-i <identityfile> (multiple allowed)\n" #endif #ifdef ENABLE_CLI_LOCALTCPFWD - "-L <listenport:remotehsot:reportport> Local port forwarding\n" + "-L <listenport:remotehost:remoteport> Local port forwarding\n" #endif #ifdef ENABLE_CLI_REMOTETCPFWD "-R <listenport:remotehost:remoteport> Remote port forwarding\n" @@ -89,7 +89,7 @@ void cli_getopts(int argc, char ** argv) { cli_opts.cmd = NULL; cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */ #ifdef ENABLE_CLI_PUBKEY_AUTH - cli_opts.pubkeys = NULL; + cli_opts.privkeys = NULL; #endif #ifdef ENABLE_CLI_LOCALTCPFWD cli_opts.localfwds = NULL; @@ -271,7 +271,7 @@ void cli_getopts(int argc, char ** argv) { #ifdef ENABLE_CLI_PUBKEY_AUTH static void loadidentityfile(const char* filename) { - struct PubkeyList * nextkey; + struct SignKeyList * nextkey; sign_key *key; int keytype; @@ -284,11 +284,11 @@ static void loadidentityfile(const char* filename) { } else { - nextkey = (struct PubkeyList*)m_malloc(sizeof(struct PubkeyList)); + nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList)); nextkey->key = key; - nextkey->next = cli_opts.pubkeys; + nextkey->next = cli_opts.privkeys; nextkey->type = keytype; - cli_opts.pubkeys = nextkey; + cli_opts.privkeys = nextkey; } } #endif diff --git a/cli-session.c b/cli-session.c index 4d6a645..8b58526 100644 --- a/cli-session.c +++ b/cli-session.c @@ -113,16 +113,20 @@ static void cli_session_init() { cli_ses.tty_raw_mode = 0; cli_ses.winchange = 0; - /* We store stdin's flags, so we can set them back on exit (otherwise - * busybox's ash isn't happy */ + /* We store std{in,out,err}'s flags, so we can set them back on exit + * (otherwise busybox's ash isn't happy */ cli_ses.stdincopy = dup(STDIN_FILENO); cli_ses.stdinflags = fcntl(STDIN_FILENO, F_GETFL, 0); + cli_ses.stdoutcopy = dup(STDOUT_FILENO); + cli_ses.stdoutflags = fcntl(STDOUT_FILENO, F_GETFL, 0); + cli_ses.stderrcopy = dup(STDERR_FILENO); + cli_ses.stderrflags = fcntl(STDERR_FILENO, F_GETFL, 0); cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a specific exit status */ /* Auth */ - cli_ses.lastpubkey = NULL; + cli_ses.lastprivkey = NULL; cli_ses.lastauthtype = 0; /* For printing "remote host closed" for the user */ @@ -250,9 +254,11 @@ void cli_session_cleanup() { return; } - /* Set stdin back to non-blocking - busybox ash dies nastily - * if we don't revert the flags */ + /* Set std{in,out,err} back to non-blocking - busybox ash dies nastily if + * we don't revert the flags */ fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags); + fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags); + fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags); cli_tty_cleanup(); diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c index aa5b720..300a2fa 100644 --- a/cli-tcpfwd.c +++ b/cli-tcpfwd.c @@ -94,7 +94,7 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr, TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr, remoteport)); - tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*)); + tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); tcpinfo->sendaddr = m_strdup(remoteaddr); tcpinfo->sendport = remoteport; tcpinfo->listenport = listenport; diff --git a/common-algo.c b/common-algo.c index 1975864..ea9c311 100644 --- a/common-algo.c +++ b/common-algo.c @@ -125,7 +125,7 @@ algo_type sshkex[] = { * This should be run before using any of the ciphers/hashes */ void crypto_init() { - const struct _cipher_descriptor *regciphers[] = { + const struct ltc_cipher_descriptor *regciphers[] = { #ifdef DROPBEAR_AES128_CBC &aes_desc, #endif @@ -141,7 +141,7 @@ void crypto_init() { NULL }; - const struct _hash_descriptor *reghashes[] = { + const struct ltc_hash_descriptor *reghashes[] = { /* we need sha1 for hostkey stuff regardless */ &sha1_desc, #ifdef DROPBEAR_MD5_HMAC diff --git a/common-channel.c b/common-channel.c index 6f73fab..f03039a 100644 --- a/common-channel.c +++ b/common-channel.c @@ -162,8 +162,13 @@ struct Channel* newchannel(unsigned int remotechan, return newchan; } -/* Get the channel structure corresponding to a channel number */ -struct Channel* getchannel(unsigned int chan) { +/* Returns the channel structure corresponding to the channel in the current + * data packet (ses.payload must be positioned appropriately) */ +struct Channel* getchannel() { + + unsigned int chan; + + chan = buf_getint(ses.payload); if (chan >= ses.chansize || ses.channels[chan] == NULL) { return NULL; } @@ -474,14 +479,11 @@ void setchannelfds(fd_set *readfd, fd_set *writefd) { * etc) FD is also EOF */ void recv_msg_channel_eof() { - unsigned int chan; struct Channel * channel; TRACE(("enter recv_msg_channel_eof")) - chan = buf_getint(ses.payload); - channel = getchannel(chan); - + channel = getchannel(); if (channel == NULL) { dropbear_exit("EOF for unknown channel"); } @@ -500,15 +502,11 @@ void recv_msg_channel_eof() { /* Handle channel closure(), respond in kind and close the channels */ void recv_msg_channel_close() { - unsigned int chan; struct Channel * channel; TRACE(("enter recv_msg_channel_close")) - chan = buf_getint(ses.payload); - TRACE(("close channel = %d", chan)) - channel = getchannel(chan); - + channel = getchannel(); if (channel == NULL) { /* disconnect ? */ dropbear_exit("Close for unknown channel"); @@ -567,14 +565,11 @@ static void deletechannel(struct Channel *channel) { * such as chansession or x11fwd */ void recv_msg_channel_request() { - unsigned int chan; struct Channel *channel; TRACE(("enter recv_msg_channel_request")) - chan = buf_getint(ses.payload); - channel = getchannel(chan); - + channel = getchannel(); if (channel == NULL) { /* disconnect ? */ dropbear_exit("Unknown channel"); @@ -666,12 +661,9 @@ static void send_msg_channel_data(struct Channel *channel, int isextended, /* We receive channel data */ void recv_msg_channel_data() { - unsigned int chan; struct Channel *channel; - chan = buf_getint(ses.payload); - channel = getchannel(chan); - + channel = getchannel(); if (channel == NULL) { dropbear_exit("Unknown channel"); } @@ -738,13 +730,10 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd, * as data is sent, and incremented upon receiving window-adjust messages */ void recv_msg_channel_window_adjust() { - unsigned int chan; struct Channel * channel; unsigned int incr; - chan = buf_getint(ses.payload); - channel = getchannel(chan); - + channel = getchannel(); if (channel == NULL) { dropbear_exit("Unknown channel"); } @@ -961,14 +950,12 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) { * successful*/ void recv_msg_channel_open_confirmation() { - unsigned int chan; struct Channel * channel; int ret; TRACE(("enter recv_msg_channel_open_confirmation")) - chan = buf_getint(ses.payload); - channel = getchannel(chan); + channel = getchannel(); if (channel == NULL) { dropbear_exit("Unknown channel"); } @@ -977,7 +964,8 @@ void recv_msg_channel_open_confirmation() { channel->transwindow = buf_getint(ses.payload); channel->transmaxpacket = buf_getint(ses.payload); - TRACE(("new chan remote %d localho %d", channel->remotechan, chan)) + TRACE(("new chan remote %d local %d", + channel->remotechan, channel->index)) /* Run the inithandler callback */ if (channel->type->inithandler) { @@ -995,11 +983,9 @@ void recv_msg_channel_open_confirmation() { /* Notification that our channel open request failed */ void recv_msg_channel_open_failure() { - unsigned int chan; struct Channel * channel; - chan = buf_getbyte(ses.payload); - channel = getchannel(chan); + channel = getchannel(); if (channel == NULL) { dropbear_exit("Unknown channel"); } diff --git a/common-kex.c b/common-kex.c index 97e341d..8a8aa93 100644 --- a/common-kex.c +++ b/common-kex.c @@ -457,7 +457,6 @@ void recv_msg_kexinit() { /* the rest of ses.kexhashbuf will be done after DH exchange */ ses.kexstate.recvkexinit = 1; -// ses.expecting = 0; // client matt TRACE(("leave recv_msg_kexinit")) } @@ -470,18 +469,13 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) { DEF_MP_INT(dh_p); DEF_MP_INT(dh_q); DEF_MP_INT(dh_g); - unsigned char randbuf[DH_P_LEN]; - int dh_q_len; TRACE(("enter send_msg_kexdh_reply")) m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL); /* read the prime and generator*/ - if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN) - != MP_OKAY) { - dropbear_exit("Diffie-Hellman error"); - } + bytes_to_mp(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN); if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) { dropbear_exit("Diffie-Hellman error"); @@ -496,16 +490,8 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) { dropbear_exit("Diffie-Hellman error"); } - dh_q_len = mp_unsigned_bin_size(&dh_q); - - /* calculate our random value dh_y */ - do { - assert((unsigned int)dh_q_len <= sizeof(randbuf)); - genrandom(randbuf, dh_q_len); - if (mp_read_unsigned_bin(dh_priv, randbuf, dh_q_len) != MP_OKAY) { - dropbear_exit("Diffie-Hellman error"); - } - } while (mp_cmp(dh_priv, &dh_q) == MP_GT || mp_cmp_d(dh_priv, 0) != MP_GT); + /* Generate a private portion 0 < dh_priv < dh_q */ + gen_random_mpint(&dh_q, dh_priv); /* f = g^y mod p */ if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) { @@ -527,10 +513,7 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them, /* read the prime and generator*/ mp_init(&dh_p); - if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN) - != MP_OKAY) { - dropbear_exit("Diffie-Hellman error"); - } + bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN); /* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */ if (mp_cmp(dh_pub_them, &dh_p) != MP_LT @@ -683,7 +666,7 @@ static void read_kex_algos() { buf_eatstring(ses.payload); /* first_kex_packet_follows */ - if (buf_getbyte(ses.payload)) { + if (buf_getbool(ses.payload)) { ses.kexstate.firstfollows = 1; /* if the guess wasn't good, we ignore the packet sent */ if (!allgood) { diff --git a/dbclient.1 b/dbclient.1 new file mode 100644 index 0000000..fc6f0d0 --- /dev/null +++ b/dbclient.1 @@ -0,0 +1,69 @@ +.TH dbclient 1 +.SH NAME +dbclient \- lightweight SSH2 client +.SH SYNOPSIS +.B dbclient +[\-Tt] [\-p +.I port\fR] [\-i +.I id\fR] [\-L +.I l\fR:\fIh\fR:\fIr\fR] [\-R +.I l\fR:\fIh\fR:\fIr\fR] [\-l +.IR user ] +.I host +.SH DESCRIPTION +.B dbclient +is a SSH 2 client designed to be small enough to be used in small memory +environments, while still being functional and secure enough for general use. +.SH OPTIONS +.TP +.B \-p \fIport +Remote port. +Connect to port +.I port +on the remote host. +Default is 22. +.TP +.B \-i \fIidfile +Identity file. +Read the identity from file +.I idfile +(multiple allowed). +.TP +.B \-L \fIlocalport\fR:\fIremotehost\fR:\fIremoteport\fR +Local port forwarding. +Forward the port +.I localport +on the local host to port +.I remoteport +on the remote host +.IR remotehost . +.TP +.B \-R \fIlocalport\fR:\fIremotehost\fR:\fIremoteport\fR +Remote port forwarding. +Forward the port +.I remoteport +on the remote host +.I remotehost +to port +.I localport +on the local host. +.TP +.B \-l \fIuser +Username. +Login as +.I user +on the remote host. +.TP +.B \-t +Allocate a pty. +.TP +.B \-T +Don't allocate a pty. +.SH AUTHOR +Matt Johnston (matt@ucc.asn.au). +.br +Gerrit Pape (pape@smarden.org) wrote this manual page. +.SH SEE ALSO +dropbear(8), dropbearkey(8) +.P +http://matt.ucc.asn.au/dropbear/dropbear.html @@ -430,10 +430,11 @@ char* getaddrhostname(struct sockaddr_storage * addr) { } #ifdef DEBUG_TRACE -void printhex(unsigned char* buf, int len) { +void printhex(const char * label, const unsigned char * buf, int len) { int i; + fprintf(stderr, "%s\n", label); for (i = 0; i < len; i++) { fprintf(stderr, "%02x", buf[i]); if (i % 16 == 15) { @@ -41,7 +41,7 @@ void dropbear_close(const char* format, ...); void dropbear_log(int priority, const char* format, ...); #ifdef DEBUG_TRACE void dropbear_trace(const char* format, ...); -void printhex(unsigned char* buf, int len); +void printhex(const char * label, const unsigned char * buf, int len); extern int debug_trace; #endif char * stripcontrol(const char * text); diff --git a/debian/README.Debian.diet b/debian/README.Debian.diet new file mode 100644 index 0000000..bd0cb5c --- /dev/null +++ b/debian/README.Debian.diet @@ -0,0 +1,15 @@ +Building with the diet libc +--------------------------- + +This package optionally can be built with the diet libc instead of the +glibc to provide small statically linked programs. The resulting package +has no dependency on any other package. + +To use the diet libc, make sure the latest versions of the dietlibc-dev +package is installed, and set DEB_BUILD_OPTIONS=diet in the environment +when building the package, e.g.: + + # apt-get install dietlibc-dev + $ DEB_BUILD_OPTIONS=diet fakeroot apt-get source -b dropbear + + -- Gerrit Pape <pape@smarden.org>, Sat, 17 Jul 2004 19:09:34 +0000 @@ -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 @@ -76,6 +76,6 @@ Matt Johnston (matt@ucc.asn.au). .br Gerrit Pape (pape@smarden.org) wrote this manual page. .SH SEE ALSO -dropbearkey(8) +dropbearkey(8), dbclient(1) .P http://matt.ucc.asn.au/dropbear/dropbear.html diff --git a/dropbearkey.8 b/dropbearkey.8 index 3128007..a093d85 100644 --- a/dropbearkey.8 +++ b/dropbearkey.8 @@ -42,6 +42,6 @@ Matt Johnston (matt@ucc.asn.au). .br Gerrit Pape (pape@smarden.org) wrote this manual page. .SH SEE ALSO -dropbear(8) +dropbear(8), dbclient(1) .P http://matt.ucc.asn.au/dropbear/dropbear.html @@ -190,10 +190,8 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data, /* create the signature - s' and r' are the received signatures in buf */ /* w = (s')-1 mod q */ /* let val1 = s' */ - if (mp_read_unsigned_bin(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE) - != MP_OKAY) { - goto out; - } + bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE); + if (mp_cmp(&val1, key->q) != MP_LT) { TRACE(("verify failed, s' >= q")) goto out; @@ -205,9 +203,8 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data, /* u1 = ((SHA(M')w) mod q */ /* let val1 = SHA(M') = msghash */ - if (mp_read_unsigned_bin(&val1, msghash, SHA1_HASH_SIZE) != MP_OKAY) { - goto out; - } + bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE); + /* let val3 = u1 = ((SHA(M')w) mod q */ if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) { goto out; @@ -215,10 +212,7 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data, /* u2 = ((r')w) mod q */ /* let val1 = r' */ - if (mp_read_unsigned_bin(&val1, &string[0], SHA1_HASH_SIZE) - != MP_OKAY) { - goto out; - } + bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE); if (mp_cmp(&val1, key->q) != MP_LT) { TRACE(("verify failed, r' >= q")) goto out; @@ -261,6 +255,7 @@ out: } #endif /* DROPBEAR_SIGNKEY_VERIFY */ +#ifdef DSS_PROTOK /* convert an unsigned mp into an array of bytes, malloced. * This array must be freed after use, len contains the length of the array, * if len != NULL */ @@ -279,6 +274,7 @@ static unsigned char* mptobytes(mp_int *mp, int *len) { } return ret; } +#endif /* Sign the data presented with key, writing the signature contents * to the buffer @@ -304,8 +300,6 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data, unsigned char *privkeytmp; unsigned char proto_k[SHA512_HASH_SIZE]; DEF_MP_INT(dss_protok); -#else - unsigned char kbuf[SHA1_HASH_SIZE]; #endif DEF_MP_INT(dss_k); DEF_MP_INT(dss_m); @@ -343,22 +337,16 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data, /* generate k */ m_mp_init(&dss_protok); - bytestomp(&dss_protok, proto_k, SHA512_HASH_SIZE); + bytes_to_mp(&dss_protok, proto_k, SHA512_HASH_SIZE); mp_mod(&dss_protok, key->q, &dss_k); mp_clear(&dss_protok); m_burn(proto_k, SHA512_HASH_SIZE); #else /* DSS_PROTOK not defined*/ - do { - genrandom(kbuf, SHA1_HASH_SIZE); - if (mp_read_unsigned_bin(&dss_k, kbuf, SHA1_HASH_SIZE) != MP_OKAY) { - dropbear_exit("dss error"); - } - } while (mp_cmp(&dss_k, key->q) == MP_GT || mp_cmp_d(&dss_k, 0) != MP_GT); - m_burn(kbuf, SHA1_HASH_SIZE); + gen_random_mpint(key->q, &dss_k); #endif /* now generate the actual signature */ - bytestomp(&dss_m, msghash, SHA1_HASH_SIZE); + bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE); /* g^k mod p */ if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) { @@ -417,7 +405,7 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data, mp_clear(&dss_s); buf_incrwritepos(buf, writelen); - mp_clear_multi(&dss_k, &dss_temp1, &dss_temp1, &dss_r, &dss_s, + mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s, &dss_m, NULL); /* create the signature to return */ @@ -77,10 +77,7 @@ static void getq(dss_key *key) { buf[0] |= 0x80; /* top bit high */ buf[QSIZE-1] |= 0x01; /* bottom bit high */ - if (mp_read_unsigned_bin(key->q, buf, QSIZE) != MP_OKAY) { - fprintf(stderr, "dss key generation failed\n"); - exit(1); - } + bytes_to_mp(key->q, buf, QSIZE); /* 18 rounds are required according to HAC */ if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) { @@ -116,10 +113,7 @@ static void getp(dss_key *key, unsigned int size) { buf[0] |= 0x80; /* set the top bit high */ /* X is a random mp_int */ - if (mp_read_unsigned_bin(&tempX, buf, size) != MP_OKAY) { - fprintf(stderr, "dss key generation failed\n"); - exit(1); - } + bytes_to_mp(&tempX, buf, size); /* C = X mod 2q */ if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) { @@ -147,6 +141,7 @@ static void getp(dss_key *key, unsigned int size) { } while (!result); mp_clear_multi(&tempX, &tempC, &tempP, &temp2q, NULL); + m_burn(buf, size); m_free(buf); } @@ -189,22 +184,7 @@ static void getg(dss_key * key) { static void getx(dss_key *key) { - DEF_MP_INT(val); - char buf[QSIZE]; - - m_mp_init(&val); - - do { - genrandom(buf, QSIZE); - - if (mp_read_unsigned_bin(&val, buf, QSIZE) != MP_OKAY) { - fprintf(stderr, "dss key generation failed\n"); - } - } while ((mp_cmp_d(&val, 1) == MP_GT) && (mp_cmp(&val, key->q) == MP_LT)); - - mp_copy(&val, key->x); - mp_clear(&val); - + gen_random_mpint(key->q, key->x); } static void gety(dss_key *key) { @@ -108,10 +108,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus, genrandom(buf, size+1); buf[0] |= 0x80; /* MSB set */ - if (mp_read_unsigned_bin(prime, buf, size+1) != MP_OKAY) { - fprintf(stderr, "rsa generation failed\n"); - exit(1); - } + bytes_to_mp(prime, buf, size+1); /* find the next integer which is prime, 8 round of miller-rabin */ if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) { @@ -111,7 +111,7 @@ #include <libgen.h> #endif -#include "libtomcrypt/mycrypt.h" +#include "libtomcrypt/src/headers/tomcrypt.h" #include "libtommath/tommath.h" #include "compat.h" @@ -37,10 +37,10 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv); void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them, sign_key *hostkey); -void recv_msg_kexdh_init(); // server +void recv_msg_kexdh_init(); /* server */ -void send_msg_kexdh_init(); // client -void recv_msg_kexdh_reply(); // client +void send_msg_kexdh_init(); /* client */ +void recv_msg_kexdh_reply(); /* client */ extern const unsigned char dh_p_val[]; #define DH_P_LEN 128 /* The length of the dh_p_val array */ @@ -90,6 +90,11 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #define DROPBEAR_RSA #define DROPBEAR_DSS +/* RSA can be vulnerable to timing attacks which use the time required for + * signing to guess the private key. Blinding avoids this attack, though makes + * signing operations slightly slower. */ +#define RSA_BLINDING + /* Define DSS_PROTOK to use PuTTY's method of generating the value k for dss, * rather than just from the random byte source. Undefining this will save you * ~4k in binary size with static uclibc, but your DSS hostkey could be exposed @@ -313,14 +318,6 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #define DISABLE_AGENTFWD #endif -#ifndef ENABLE_LOCALTCPFWD -#define DISABLE_TCPDIRECT -#endif - -#ifndef ENABLE_REMOTETCPFWD -#define DISABLE_REMOTETCPFWD -#endif - #if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) #define ENABLE_CLI_ANYTCPFWD #endif @@ -329,7 +326,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #define DROPBEAR_TCP_ACCEPT #endif -#if defined(ENABLE_REMOTETCPFWD) || defined(ENABLE_LOCALTCPFWD) || \ +#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) || \ + defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_SVR_LOCALTCPFWD) || \ defined(ENABLE_AGENTFWD) || defined(ENABLE_X11FWD) #define USING_LISTENERS #endif @@ -201,6 +201,7 @@ static void read_packet_init() { /* decrypt it */ if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize), buf_getwriteptr(ses.decryptreadbuf,blocksize), + blocksize, &ses.keys->recv_symmetric_struct) != CRYPT_OK) { dropbear_exit("error decrypting"); } @@ -254,6 +255,7 @@ void decrypt_packet() { while (ses.readbuf->pos < ses.readbuf->len - macsize) { if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize), buf_getwriteptr(ses.decryptreadbuf, blocksize), + blocksize, &ses.keys->recv_symmetric_struct) != CRYPT_OK) { dropbear_exit("error decrypting"); } @@ -491,6 +493,7 @@ void encrypt_packet() { while (clearwritebuf->pos < clearwritebuf->len) { if (cbc_encrypt(buf_getptr(clearwritebuf, blocksize), buf_getwriteptr(writebuf, blocksize), + blocksize, &ses.keys->trans_symmetric_struct) != CRYPT_OK) { dropbear_exit("error encrypting"); } @@ -25,14 +25,15 @@ #include "includes.h" #include "buffer.h" #include "dbutil.h" +#include "bignum.h" -int donerandinit = 0; +static int donerandinit = 0; /* this is used to generate unique output from the same hashpool */ -unsigned int counter = 0; +static unsigned int counter = 0; #define MAX_COUNTER 1000000/* the max value for the counter, so it won't loop */ -unsigned char hashpool[SHA1_HASH_SIZE]; +static unsigned char hashpool[SHA1_HASH_SIZE]; #define INIT_SEED_SIZE 32 /* 256 bits */ @@ -50,6 +51,7 @@ static void readrand(unsigned char* buf, unsigned int buflen); static void readrand(unsigned char* buf, unsigned int buflen) { + static int already_blocked = 0; int readfd; unsigned int readpos; int readlen; @@ -92,6 +94,24 @@ static void readrand(unsigned char* buf, unsigned int buflen) { /* read the actual random data */ readpos = 0; do { + if (!already_blocked) + { + int ret; + struct timeval timeout; + fd_set read_fds; + + timeout.tv_sec = 2; /* two seconds should be enough */ + timeout.tv_usec = 0; + + FD_ZERO(&read_fds); + FD_SET(readfd, &read_fds); + ret = select(readfd + 1, &read_fds, NULL, NULL, &timeout); + if (ret == 0) + { + dropbear_log(LOG_INFO, "Warning: Reading the random source seems to have blocked.\nIf you experience problems, you probably need to find a better entropy source."); + already_blocked = 1; + } + } readlen = read(readfd, &buf[readpos], buflen - readpos); if (readlen <= 0) { if (readlen < 0 && errno == EINTR) { @@ -159,3 +179,38 @@ void genrandom(unsigned char* buf, unsigned int len) { } m_burn(hash, sizeof(hash)); } + +/* Generates a random mp_int. + * max is a *mp_int specifying an upper bound. + * rand must be an initialised *mp_int for the result. + * the result rand satisfies: 0 < rand < max + * */ +void gen_random_mpint(mp_int *max, mp_int *rand) { + + unsigned char *randbuf = NULL; + unsigned int len = 0; + const char masks[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f}; + + const int size_bits = mp_count_bits(max); + + len = size_bits / 8; + if ((size_bits % 8) != 0) { + len += 1; + } + + randbuf = (unsigned char*)m_malloc(len); + do { + genrandom(randbuf, len); + /* Mask out the unrequired bits - mp_read_unsigned_bin expects + * MSB first.*/ + randbuf[0] &= masks[size_bits % 8]; + + bytes_to_mp(rand, randbuf, len); + + /* keep regenerating until we get one satisfying + * 0 < rand < max */ + } while ( ( (max != NULL) && (mp_cmp(rand, max) != MP_LT) ) + || (mp_cmp_d(rand, 0) != MP_GT) ); + m_burn(randbuf, len); + m_free(randbuf); +} @@ -25,8 +25,11 @@ #ifndef _RANDOM_H_ #define _RANDOM_H_ +struct mp_int; + void seedrandom(); void genrandom(unsigned char* buf, int len); void addrandom(unsigned char* buf, int len); +void gen_random_mpint(mp_int *max, mp_int *rand); #endif /* _RANDOM_H_ */ @@ -38,8 +38,9 @@ #ifdef DROPBEAR_RSA -static mp_int * rsa_pad_em(rsa_key * key, - const unsigned char * data, unsigned int len); +static void rsa_pad_em(rsa_key * key, + const unsigned char * data, unsigned int len, + mp_int * rsa_em); /* Load a public rsa key from a buffer, initialising the values. * The key will have the same format as buf_put_rsa_key. @@ -203,14 +204,14 @@ int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data, unsigned int slen; DEF_MP_INT(rsa_s); DEF_MP_INT(rsa_mdash); - mp_int *rsa_em = NULL; + DEF_MP_INT(rsa_em); int ret = DROPBEAR_FAILURE; TRACE(("enter buf_rsa_verify")) assert(key != NULL); - m_mp_init_multi(&rsa_mdash, &rsa_s, NULL); + m_mp_init_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL); slen = buf_getint(buf); if (slen != (unsigned int)mp_unsigned_bin_size(key->n)) { @@ -231,29 +232,25 @@ int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data, } /* create the magic PKCS padded value */ - rsa_em = rsa_pad_em(key, data, len); + rsa_pad_em(key, data, len, &rsa_em); if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) { TRACE(("failed exptmod rsa_s")) goto out; } - if (mp_cmp(rsa_em, &rsa_mdash) == MP_EQ) { + if (mp_cmp(&rsa_em, &rsa_mdash) == MP_EQ) { /* signature is valid */ TRACE(("success!")) ret = DROPBEAR_SUCCESS; } out: - if (rsa_em) { - mp_clear(rsa_em); - m_free(rsa_em); - } - mp_clear_multi(&rsa_mdash, &rsa_s, NULL); + mp_clear_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL); TRACE(("leave buf_rsa_verify: ret %d", ret)) return ret; - } + #endif /* DROPBEAR_SIGNKEY_VERIFY */ /* Sign the data presented with key, writing the signature contents @@ -264,22 +261,55 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data, unsigned int nsize, ssize; unsigned int i; DEF_MP_INT(rsa_s); - mp_int *rsa_em = NULL; + DEF_MP_INT(rsa_tmp1); + DEF_MP_INT(rsa_tmp2); + DEF_MP_INT(rsa_tmp3); + unsigned char *tmpbuf; TRACE(("enter buf_put_rsa_sign")) assert(key != NULL); - rsa_em = rsa_pad_em(key, data, len); + m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL); - m_mp_init(&rsa_s); + rsa_pad_em(key, data, len, &rsa_tmp1); /* the actual signing of the padded data */ + +#ifdef RSA_BLINDING + + /* With blinding, s = (r^(-1))((em)*r^e)^d mod n */ + + /* generate the r blinding value */ + /* rsa_tmp2 is r */ + gen_random_mpint(key->n, &rsa_tmp2); + + /* rsa_tmp1 is em */ + /* em' = em * r^e mod n */ + + mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s); /* rsa_s used as a temp var*/ + mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3); + mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2); + + /* rsa_tmp2 is em' */ + /* s' = (em')^d mod n */ + mp_exptmod(&rsa_tmp2, key->d, key->n, &rsa_tmp1); + + /* rsa_tmp1 is s' */ + /* rsa_tmp3 is r^(-1) mod n */ + /* s = (s')r^(-1) mod n */ + mp_mulmod(&rsa_tmp1, &rsa_tmp3, key->n, &rsa_s); + +#else + /* s = em^d mod n */ - if (mp_exptmod(rsa_em, key->d, key->n, &rsa_s) != MP_OKAY) { + /* rsa_tmp1 is em */ + if (mp_exptmod(&rsa_tmp1, key->d, key->n, &rsa_s) != MP_OKAY) { dropbear_exit("rsa error"); } - mp_clear(rsa_em); - m_free(rsa_em); + +#endif /* RSA_BLINDING */ + + mp_clear_multi(&rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL); /* create the signature to return */ buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN); @@ -302,7 +332,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data, mp_clear(&rsa_s); #if defined(DEBUG_RSA) && defined(DEBUG_TRACE) - printhex(buf->data, buf->len); + printhex("RSA sig", buf->data, buf->len); #endif @@ -318,19 +348,22 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data, * * prefix is the ASN1 designator prefix, * hex 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 + * + * rsa_em must be a pointer to an initialised mp_int. */ -static mp_int * rsa_pad_em(rsa_key * key, - const unsigned char * data, unsigned int len) { +static void rsa_pad_em(rsa_key * key, + const unsigned char * data, unsigned int len, + mp_int * rsa_em) { /* ASN1 designator (including the 0x00 preceding) */ - const char rsa_asn1_magic[] = + const unsigned char rsa_asn1_magic[] = {0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}; -#define RSA_ASN1_MAGIC_LEN 16 + const unsigned int RSA_ASN1_MAGIC_LEN = 16; + buffer * rsa_EM = NULL; hash_state hs; unsigned int nsize; - mp_int * rsa_em = NULL; assert(key != NULL); assert(data != NULL); @@ -358,16 +391,9 @@ static mp_int * rsa_pad_em(rsa_key * key, /* Create the mp_int from the encoded bytes */ buf_setpos(rsa_EM, 0); - rsa_em = (mp_int*)m_malloc(sizeof(mp_int)); - m_mp_init(rsa_em); - if (mp_read_unsigned_bin(rsa_em, buf_getptr(rsa_EM, rsa_EM->size), - rsa_EM->size) != MP_OKAY) { - dropbear_exit("rsa error"); - } + bytes_to_mp(rsa_em, buf_getptr(rsa_EM, rsa_EM->size), + rsa_EM->size); buf_free(rsa_EM); - - return rsa_em; - } #endif /* DROPBEAR_RSA */ @@ -95,7 +95,7 @@ typedef struct cli_runopts { char *cmd; int wantpty; #ifdef ENABLE_CLI_PUBKEY_AUTH - struct PubkeyList *pubkeys; /* Keys to use for public-key auth */ + struct SignKeyList *privkeys; /* Keys to use for public-key auth */ #endif #ifdef ENABLE_CLI_REMOTETCPFWD struct TCPFwdList * remotefwds; @@ -244,9 +244,6 @@ main(int argc, char **argv) extern char *optarg; extern int optind; - /* hack, seems to work */ -// __progname = argv[0]; - args.list = NULL; addargs(&args, "ssh"); /* overwritten with ssh_program */ addargs(&args, "-x"); @@ -211,19 +211,22 @@ struct clientsession { mp_int *dh_e, *dh_x; /* Used during KEX */ cli_kex_state kex_state; /* Used for progressing KEX */ cli_state state; /* Used to progress auth/channelsession etc */ - int something; /* XXX */ unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */ int tty_raw_mode; /* Whether we're in raw mode (and have to clean up) */ struct termios saved_tio; int stdincopy; int stdinflags; + int stdoutcopy; + int stdoutflags; + int stderrcopy; + int stderrflags; int winchange; /* Set to 1 when a windowchange signal happens */ int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD, for the last type of auth we tried */ - struct PubkeyList *lastpubkey; + struct SignKeyList *lastprivkey; int retval; /* What the command exit status was - we emulate it */ #if 0 @@ -279,7 +279,7 @@ static char * sign_key_md5_fingerprint(unsigned char* keyblob, char * ret; hash_state hs; unsigned char hash[MD5_HASH_SIZE]; - unsigned int h, i; + unsigned int i; unsigned int buflen; md5_init(&hs); @@ -296,10 +296,11 @@ static char * sign_key_md5_fingerprint(unsigned char* keyblob, memset(ret, 'Z', buflen); strcpy(ret, "md5 "); - for (i = 4, h = 0; i < buflen; i+=3, h++) { - ret[i] = hexdig(hash[h] >> 4); - ret[i+1] = hexdig(hash[h] & 0x0f); - ret[i+2] = ':'; + for (i = 0; i < MD5_HASH_SIZE; i++) { + unsigned int pos = 4 + i*3; + ret[pos] = hexdig(hash[i] >> 4); + ret[pos+1] = hexdig(hash[i] & 0x0f); + ret[pos+2] = ':'; } ret[buflen-1] = 0x0; @@ -313,7 +314,7 @@ static char * sign_key_sha1_fingerprint(unsigned char* keyblob, char * ret; hash_state hs; unsigned char hash[SHA1_HASH_SIZE]; - unsigned int h, i; + unsigned int i; unsigned int buflen; sha1_init(&hs); @@ -329,10 +330,11 @@ static char * sign_key_sha1_fingerprint(unsigned char* keyblob, strcpy(ret, "sha1 "); - for (i = 5, h = 0; i < buflen; i+=3, h++) { - ret[i] = hexdig(hash[h] >> 4); - ret[i+1] = hexdig(hash[h] & 0x0f); - ret[i+2] = ':'; + for (i = 0; i < SHA1_HASH_SIZE; i++) { + unsigned int pos = 5 + 3*i; + ret[pos] = hexdig(hash[i] >> 4); + ret[pos+1] = hexdig(hash[i] & 0x0f); + ret[pos+2] = ':'; } ret[buflen-1] = 0x0; diff --git a/svr-authpam.c b/svr-authpam.c index e045b74..fe1f123 100644 --- a/svr-authpam.c +++ b/svr-authpam.c @@ -155,7 +155,7 @@ void svr_auth_pam() { unsigned char changepw; /* check if client wants to change password */ - changepw = buf_getbyte(ses.payload); + changepw = buf_getbool(ses.payload); if (changepw) { /* not implemented by this server */ send_msg_userauth_failure(0, 1); diff --git a/svr-authpasswd.c b/svr-authpasswd.c index 4348817..5be1e2a 100644 --- a/svr-authpasswd.c +++ b/svr-authpasswd.c @@ -71,7 +71,7 @@ void svr_auth_password() { } /* check if client wants to change password */ - changepw = buf_getbyte(ses.payload); + changepw = buf_getbool(ses.payload); if (changepw) { /* not implemented by this server */ send_msg_userauth_failure(0, 1); diff --git a/svr-authpubkey.c b/svr-authpubkey.c index 5daba0f..dcd59f0 100644 --- a/svr-authpubkey.c +++ b/svr-authpubkey.c @@ -64,7 +64,7 @@ void svr_auth_pubkey() { /* 0 indicates user just wants to check if key can be used, 1 is an * actual attempt*/ - testkey = (buf_getbyte(ses.payload) == 0); + testkey = (buf_getbool(ses.payload) == 0); algo = buf_getstring(ses.payload, &algolen); keybloblen = buf_getint(ses.payload); diff --git a/svr-chansession.c b/svr-chansession.c index c04d592..1704c6e 100644 --- a/svr-chansession.c +++ b/svr-chansession.c @@ -305,7 +305,7 @@ static void chansessionrequest(struct Channel *channel) { TRACE(("enter chansessionrequest")) type = buf_getstring(ses.payload, &typelen); - wantreply = buf_getbyte(ses.payload); + wantreply = buf_getbool(ses.payload); if (typelen > MAX_NAME_LEN) { TRACE(("leave chansessionrequest: type too long")) /* XXX send error?*/ @@ -837,7 +837,7 @@ static void execchild(struct ChanSess *chansess) { /* close file descriptors except stdin/stdout/stderr * Need to be sure FDs are closed here to avoid reading files as root */ - for (i = 3; i < (unsigned int)ses.maxfd; i++) { + for (i = 3; i <= (unsigned int)ses.maxfd; i++) { if (m_close(i) == DROPBEAR_FAILURE) { dropbear_exit("Error closing file desc"); } @@ -862,8 +862,10 @@ static void execchild(struct ChanSess *chansess) { if ((setgid(ses.authstate.pw->pw_gid) < 0) || (initgroups(ses.authstate.pw->pw_name, - ses.authstate.pw->pw_gid) < 0) || - (setuid(ses.authstate.pw->pw_uid) < 0)) { + ses.authstate.pw->pw_gid) < 0)) { + dropbear_exit("error changing user group"); + } + if (setuid(ses.authstate.pw->pw_uid) < 0) { dropbear_exit("error changing user"); } } else { diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c index 7fbc609..3acc4ff 100644 --- a/svr-tcpfwd.c +++ b/svr-tcpfwd.c @@ -78,7 +78,7 @@ void recv_msg_global_request_remotetcp() { } reqname = buf_getstring(ses.payload, &namelen); - wantreply = buf_getbyte(ses.payload); + wantreply = buf_getbool(ses.payload); if (namelen > MAXNAMLEN) { TRACE(("name len is wrong: %d", namelen)) diff --git a/svr-x11fwd.c b/svr-x11fwd.c index e15fb82..cbc8a79 100644 --- a/svr-x11fwd.c +++ b/svr-x11fwd.c @@ -52,7 +52,7 @@ int x11req(struct ChanSess * chansess) { return DROPBEAR_FAILURE; } - chansess->x11singleconn = buf_getbyte(ses.payload); + chansess->x11singleconn = buf_getbool(ses.payload); chansess->x11authprot = buf_getstring(ses.payload, NULL); chansess->x11authcookie = buf_getstring(ses.payload, NULL); chansess->x11screennum = buf_getint(ses.payload); |