mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
149 Commits
DROPBEAR_2
...
DROPBEAR_2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84e18f72ae | ||
|
|
633b98ef28 | ||
|
|
2a34a72bff | ||
|
|
24bae46e42 | ||
|
|
7585d4606e | ||
|
|
94bff1df66 | ||
|
|
2e60d20a76 | ||
|
|
ce59260ee9 | ||
|
|
387ebccf36 | ||
|
|
2f618af086 | ||
|
|
0ac33d22f7 | ||
|
|
c7bd5ac77d | ||
|
|
941c067765 | ||
|
|
839e023ed8 | ||
|
|
2e05a2b8c4 | ||
|
|
fc2c67e61c | ||
|
|
9c3e9fcdad | ||
|
|
1a4db21fe4 | ||
|
|
d96a52541f | ||
|
|
e7ac4c1ab3 | ||
|
|
ecd8505218 | ||
|
|
1fa1c3f9db | ||
|
|
91df741926 | ||
|
|
2a431cab03 | ||
|
|
9fdab3ced8 | ||
|
|
6e15e75391 | ||
|
|
1c2a1838fc | ||
|
|
bfd730aa4c | ||
|
|
e3c6a86b1e | ||
|
|
bbaeb917ff | ||
|
|
20f1e49b73 | ||
|
|
292656d899 | ||
|
|
05b36b484e | ||
|
|
be3016b8d5 | ||
|
|
5cf43d76bf | ||
|
|
6f05e810d9 | ||
|
|
947d2697cf | ||
|
|
449ddae628 | ||
|
|
6b90885d4f | ||
|
|
bd6c37adb6 | ||
|
|
59235276ac | ||
|
|
e5ce3fc51b | ||
|
|
9f97511356 | ||
|
|
ef0aac432c | ||
|
|
7928d83b02 | ||
|
|
3e91ec07e4 | ||
|
|
d680a9e3fb | ||
|
|
6086851fc1 | ||
|
|
61726df20c | ||
|
|
1601a657d4 | ||
|
|
50b14f696c | ||
|
|
c239baf801 | ||
|
|
18638859e6 | ||
|
|
224b16b247 | ||
|
|
d9d97969a3 | ||
|
|
897da4ee36 | ||
|
|
90f9f43335 | ||
|
|
0e1dee828a | ||
|
|
cbdc1f0753 | ||
|
|
7e306336d0 | ||
|
|
e7def4c211 | ||
|
|
19e1afbd1c | ||
|
|
fee32054e6 | ||
|
|
9754fdd995 | ||
|
|
ef20b9ff7a | ||
|
|
275611fbaa | ||
|
|
a070159cc5 | ||
|
|
20f9683ae0 | ||
|
|
dce384668b | ||
|
|
fdcd21e74b | ||
|
|
67b4fa313e | ||
|
|
5dff74109e | ||
|
|
20d970a0e2 | ||
|
|
94734ad377 | ||
|
|
14ad6a5972 | ||
|
|
9e66b5a9b1 | ||
|
|
f782cf375a | ||
|
|
3317916111 | ||
|
|
f367273549 | ||
|
|
91ef9b2fa9 | ||
|
|
579463933b | ||
|
|
989c5c1436 | ||
|
|
3113932151 | ||
|
|
125a970d71 | ||
|
|
89c0b2a6d8 | ||
|
|
31e379c300 | ||
|
|
843953379c | ||
|
|
2a90c1ca7e | ||
|
|
59bb1777be | ||
|
|
c5f3c550a6 | ||
|
|
1809f741cb | ||
|
|
9adfff5c1a | ||
|
|
8008b595d3 | ||
|
|
21bed0d21a | ||
|
|
4b1f5ec7c2 | ||
|
|
ab9439519a | ||
|
|
abeb9d64a3 | ||
|
|
fdb7ffa864 | ||
|
|
46845fd3e8 | ||
|
|
c53ca6ebc0 | ||
|
|
f04a3a2cfa | ||
|
|
364a53577e | ||
|
|
1b1997bf2d | ||
|
|
34f9adb1c9 | ||
|
|
2e7d468b90 | ||
|
|
86a717c80c | ||
|
|
76a3eb393c | ||
|
|
5f0cc969a0 | ||
|
|
755c1458f0 | ||
|
|
8795d733ec | ||
|
|
28f61c8b3a | ||
|
|
9abcc7b909 | ||
|
|
2c35f1c8fd | ||
|
|
136188259e | ||
|
|
02179b1218 | ||
|
|
1e350de136 | ||
|
|
9aeda4c5bd | ||
|
|
8eb30c353a | ||
|
|
c44a78a2e6 | ||
|
|
b6685bf806 | ||
|
|
269d690e71 | ||
|
|
4df268f10e | ||
|
|
19b3f01477 | ||
|
|
86811f4765 | ||
|
|
dd0352d93b | ||
|
|
30ec18d938 | ||
|
|
9d495ab2b5 | ||
|
|
9174de47a9 | ||
|
|
d857faf18e | ||
|
|
d5c8ba1690 | ||
|
|
9bb9b4829d | ||
|
|
e25c297c3c | ||
|
|
4de876f259 | ||
|
|
b9073961f7 | ||
|
|
a7a79d569a | ||
|
|
6165f53fcd | ||
|
|
4122cac66b | ||
|
|
a1dcebe4f4 | ||
|
|
6cbb23a819 | ||
|
|
5c57a31184 | ||
|
|
7b2c42aa75 | ||
|
|
1ed8d3938e | ||
|
|
b24984deb3 | ||
|
|
eabd9f5e60 | ||
|
|
d4609682af | ||
|
|
634415f79e | ||
|
|
4ba830fc31 | ||
|
|
3022a46039 | ||
|
|
d9a868ff60 |
2
.hgsigs
2
.hgsigs
@@ -12,3 +12,5 @@ a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVq
|
||||
277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn
|
||||
96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m
|
||||
caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq
|
||||
2d421bc0545d1be6d59a4ebfe61606d94b124b0c 0 iEYEABECAAYFAlRJDCQACgkQjPn4sExkf7xUYACcCwVJkYWXJn5x/D5A+qMupy778lEAn0rg1oNiq96YU/4jOPsS5IMItihu
|
||||
1d2d81b1b7c1b100e9c369e40b9fa5b2d491eea9 0 iEYEABECAAYFAlTKOKUACgkQjPn4sExkf7xWMACfYFozyHiRk5GaocTa5z6Ws1uyB4kAoLubxoxcnM3E7AA9mHAzc3OB5M0Y
|
||||
|
||||
2
.hgtags
2
.hgtags
@@ -45,3 +45,5 @@ e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test
|
||||
2351b2da8e0d08dcc6e64fcc328b53b9630bda68 DROPBEAR_2014.63
|
||||
0d2d39957c029adb7f4327d37fe6b4900f0736d9 DROPBEAR_2014.64
|
||||
e9579816f20ea85affc6135e87f8477992808948 DROPBEAR_2014.65
|
||||
735511a4c761141416ad0e6728989d2dafa55bc2 DROPBEAR_2014.66
|
||||
cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
|
||||
|
||||
@@ -3,7 +3,9 @@ compiler:
|
||||
- gcc
|
||||
|
||||
script:
|
||||
- autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst && make install
|
||||
- autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS" --prefix=$HOME/inst
|
||||
- test "$NOWRITEV" && sed -i s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h || true
|
||||
- make install
|
||||
- ~/inst/bin/dropbearkey -t rsa -f testrsa
|
||||
- ~/inst/bin/dropbearkey -t dss -f testdss
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
|
||||
@@ -15,6 +17,7 @@ before_install:
|
||||
- sudo apt-get install -qq libz-dev libtomcrypt-dev libtommath-dev
|
||||
|
||||
env:
|
||||
- BUNDLEDLIBTOM=--disable-bundled-libtom
|
||||
- BUNDLEDLIBTOM=--disable-bundled-libtom WEXTRAFLAGS=-Werror
|
||||
- BUNDLEDLIBTOM=--enable-bundled-libtom
|
||||
- MULTI=1
|
||||
- NOWRITEV=1
|
||||
|
||||
76
CHANGES
76
CHANGES
@@ -1,3 +1,79 @@
|
||||
2015.68 - Saturday 8 August 2015
|
||||
|
||||
- Reduce local data copying for improved efficiency. Measured 30%
|
||||
increase in throughput for connections to localhost
|
||||
|
||||
- Forwarded TCP ports connect asynchronously and try all available addresses
|
||||
(IPv4, IPv6, round robin DNS)
|
||||
|
||||
- Fix all compile warnings, many patches from Gaël Portay
|
||||
Note that configure with -Werror may not be successful on some platforms (OS X)
|
||||
and some configuration options may still result in unused variable
|
||||
warnings.
|
||||
|
||||
- Use TCP Fast Open on Linux if available. Saves a round trip at connection
|
||||
to hosts that have previously been connected.
|
||||
Needs a recent Linux kernel and possibly "sysctl -w net.ipv4.tcp_fastopen=3"
|
||||
Client side is disabled by default pending further compatibility testing
|
||||
with networks and systems.
|
||||
|
||||
- Increase maximum command length to 9000 bytes
|
||||
|
||||
- Free memory before exiting, patch from Thorsten Horstmann. Useful for
|
||||
Dropbear ports to embedded systems and for checking memory leaks
|
||||
with valgrind. Only partially implemented for dbclient.
|
||||
This is disabled by default, enable with DROPBEAR_CLEANUP in sysoptions.h
|
||||
|
||||
- DROPBEAR_DEFAULT_CLI_AUTHKEY setting now always prepends home directory unless
|
||||
there is a leading slash (~ isn't treated specially)
|
||||
|
||||
- Fix small ECC memory leaks
|
||||
|
||||
- Tighten validation of Diffie-Hellman parameters, from Florent Daigniere of
|
||||
Matta Consulting. Odds of bad values are around 2**-512 -- improbable.
|
||||
|
||||
- Twofish-ctr cipher is supported though disabled by default
|
||||
|
||||
- Fix pre-authentication timeout when waiting for client SSH-2.0 banner, thanks
|
||||
to CL Ouyang
|
||||
|
||||
- Fix null pointer crash with restrictions in authorized_keys without a command, patch from
|
||||
Guilhem Moulin
|
||||
|
||||
- Ensure authentication timeout is handled while reading the initial banner,
|
||||
thanks to CL Ouyang for finding it.
|
||||
|
||||
- Fix null pointer crash when handling bad ECC keys. Found by afl-fuzz
|
||||
|
||||
2015.67 - Wednesday 28 January 2015
|
||||
|
||||
- Call fsync() after generating private keys to ensure they aren't lost if a
|
||||
reboot occurs. Thanks to Peter Korsgaard
|
||||
|
||||
- Disable non-delayed zlib compression by default on the server. Can be
|
||||
enabled if required for old clients with DROPBEAR_SERVER_DELAY_ZLIB
|
||||
|
||||
- Default client key path ~/.ssh/id_dropbear
|
||||
|
||||
- Prefer stronger algorithms by default, from Fedor Brunner.
|
||||
AES256 over 3DES
|
||||
Diffie-hellman group14 over group1
|
||||
|
||||
- Add option to disable CBC ciphers.
|
||||
|
||||
- Disable twofish in default options.h
|
||||
|
||||
- Enable sha2 HMAC algorithms by default, the code was already required
|
||||
for ECC key exchange. sha1 is the first preference still for performance.
|
||||
|
||||
- Fix installing dropbear.8 in a separate build directory, from Like Ma
|
||||
|
||||
- Allow configure to succeed if libtomcrypt/libtommath are missing, from Elan Ruusamäe
|
||||
|
||||
- Don't crash if ssh-agent provides an unknown type of key. From Catalin Patulea
|
||||
|
||||
- Minor bug fixes, a few issues found by Coverity scan
|
||||
|
||||
2014.66 - Thursday 23 October 2014
|
||||
|
||||
- Use the same keepalive handling behaviour as OpenSSH. This will work better
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
|
||||
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
|
||||
same license:
|
||||
|
||||
Copyright (c) 2002-2014 Matt Johnston
|
||||
Copyright (c) 2002-2015 Matt Johnston
|
||||
Portions copyright (c) 2004 Mihnea Stoenescu
|
||||
All rights reserved.
|
||||
|
||||
|
||||
10
Makefile.in
10
Makefile.in
@@ -40,12 +40,12 @@ SVROBJS=svr-kex.o svr-auth.o sshpty.o \
|
||||
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.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
|
||||
cli-agentfwd.o
|
||||
|
||||
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
|
||||
common-channel.o common-chansession.o termcodes.o loginrec.o \
|
||||
tcp-accept.o listener.o process-packet.o \
|
||||
common-runopts.o circbuffer.o curve25519-donna.o
|
||||
common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
|
||||
|
||||
KEYOBJS=dropbearkey.o
|
||||
|
||||
@@ -131,7 +131,7 @@ insmultidropbear: dropbearmulti
|
||||
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
|
||||
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
|
||||
insmulti%: dropbearmulti
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
@@ -140,12 +140,12 @@ insmulti%: dropbearmulti
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
# dropbear should go in sbin, so it needs a seperate rule
|
||||
# dropbear should go in sbin, so it needs a separate rule
|
||||
inst_dropbear: dropbear
|
||||
$(INSTALL) -d $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
|
||||
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
|
||||
inst_%: %
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
* 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. */
|
||||
#ifndef _AGENTFWD_H_
|
||||
#define _AGENTFWD_H_
|
||||
#ifndef DROPBEAR_AGENTFWD_H_
|
||||
#define DROPBEAR_AGENTFWD_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "chansession.h"
|
||||
@@ -60,4 +60,4 @@ void svr_agentset(struct ChanSess *chansess);
|
||||
|
||||
#endif /* ENABLE_SVR_AGENTFWD */
|
||||
|
||||
#endif /* _AGENTFWD_H_ */
|
||||
#endif /* DROPBEAR_AGENTFWD_H_ */
|
||||
|
||||
9
algo.h
9
algo.h
@@ -22,9 +22,9 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _ALGO_H_
|
||||
#ifndef DROPBEAR_ALGO_H_
|
||||
|
||||
#define _ALGO_H_
|
||||
#define DROPBEAR_ALGO_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
struct Algo_Type {
|
||||
|
||||
const unsigned char *name; /* identifying name */
|
||||
const char *name; /* identifying name */
|
||||
char val; /* a value for this cipher, or -1 for invalid */
|
||||
const void *data; /* algorithm specific data */
|
||||
char usable; /* whether we can use this algorithm */
|
||||
@@ -51,6 +51,7 @@ extern algo_type sshhostkey[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type ssh_compress[];
|
||||
extern algo_type ssh_delaycompress[];
|
||||
extern algo_type ssh_nocompress[];
|
||||
|
||||
extern const struct dropbear_cipher dropbear_nocipher;
|
||||
@@ -133,4 +134,4 @@ enum {
|
||||
DROPBEAR_COMP_ZLIB_DELAY,
|
||||
};
|
||||
|
||||
#endif /* _ALGO_H_ */
|
||||
#endif /* DROPBEAR_ALGO_H_ */
|
||||
|
||||
8
auth.h
8
auth.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _AUTH_H_
|
||||
#define _AUTH_H_
|
||||
#ifndef DROPBEAR_AUTH_H_
|
||||
#define DROPBEAR_AUTH_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -133,8 +133,8 @@ struct PubKeyOptions {
|
||||
int no_x11_forwarding_flag;
|
||||
int no_pty_flag;
|
||||
/* "command=" option. */
|
||||
unsigned char * forced_command;
|
||||
char * forced_command;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _AUTH_H_ */
|
||||
#endif /* DROPBEAR_AUTH_H_ */
|
||||
|
||||
6
bignum.h
6
bignum.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _BIGNUM_H_
|
||||
#define _BIGNUM_H_
|
||||
#ifndef DROPBEAR_BIGNUM_H_
|
||||
#define DROPBEAR_BIGNUM_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
@@ -35,4 +35,4 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
|
||||
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp);
|
||||
|
||||
#endif /* _BIGNUM_H_ */
|
||||
#endif /* DROPBEAR_BIGNUM_H_ */
|
||||
|
||||
48
buffer.c
48
buffer.c
@@ -46,17 +46,15 @@ buffer* buf_new(unsigned int size) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
|
||||
buf = (buffer*)m_malloc(sizeof(buffer));
|
||||
buf = (buffer*)m_malloc(sizeof(buffer)+size);
|
||||
|
||||
if (size > 0) {
|
||||
buf->data = (unsigned char*)m_malloc(size);
|
||||
buf->data = (unsigned char*)buf + sizeof(buffer);
|
||||
} else {
|
||||
buf->data = NULL;
|
||||
}
|
||||
|
||||
buf->size = size;
|
||||
buf->pos = 0;
|
||||
buf->len = 0;
|
||||
|
||||
return buf;
|
||||
|
||||
@@ -65,7 +63,6 @@ buffer* buf_new(unsigned int size) {
|
||||
/* free the buffer's data and the buffer itself */
|
||||
void buf_free(buffer* buf) {
|
||||
|
||||
m_free(buf->data)
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
@@ -78,17 +75,18 @@ void buf_burn(buffer* buf) {
|
||||
|
||||
/* resize a buffer, pos and len will be repositioned if required when
|
||||
* downsizing */
|
||||
void buf_resize(buffer *buf, unsigned int newsize) {
|
||||
buffer* buf_resize(buffer *buf, unsigned int newsize) {
|
||||
|
||||
if (newsize > BUF_MAX_SIZE) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
|
||||
buf->data = m_realloc(buf->data, newsize);
|
||||
buf = m_realloc(buf, sizeof(buffer)+newsize);
|
||||
buf->data = (unsigned char*)buf + sizeof(buffer);
|
||||
buf->size = newsize;
|
||||
buf->len = MIN(newsize, buf->len);
|
||||
buf->pos = MIN(newsize, buf->pos);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Create a copy of buf, allocating required memory etc. */
|
||||
@@ -99,7 +97,9 @@ buffer* buf_newcopy(buffer* buf) {
|
||||
|
||||
ret = buf_new(buf->len);
|
||||
ret->len = buf->len;
|
||||
memcpy(ret->data, buf->data, buf->len);
|
||||
if (buf->len > 0) {
|
||||
memcpy(ret->data, buf->data, buf->len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ void buf_setpos(buffer* buf, unsigned int pos) {
|
||||
buf->pos = pos;
|
||||
}
|
||||
|
||||
/* increment the postion by incr, increasing the buffer length if required */
|
||||
/* increment the position by incr, increasing the buffer length if required */
|
||||
void buf_incrwritepos(buffer* buf, unsigned int incr) {
|
||||
if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
|
||||
dropbear_exit("Bad buf_incrwritepos");
|
||||
@@ -203,10 +203,10 @@ unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
|
||||
/* Return a null-terminated string, it is malloced, so must be free()ed
|
||||
* Note that the string isn't checked for null bytes, hence the retlen
|
||||
* may be longer than what is returned by strlen */
|
||||
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
|
||||
unsigned int len;
|
||||
unsigned char* ret;
|
||||
char* ret;
|
||||
len = buf_getint(buf);
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
@@ -225,15 +225,15 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
buffer *ret;
|
||||
unsigned char* str;
|
||||
unsigned int len;
|
||||
str = buf_getstring(buf, &len);
|
||||
ret = m_malloc(sizeof(*ret));
|
||||
ret->data = str;
|
||||
ret->len = len;
|
||||
ret->size = len;
|
||||
ret->pos = 0;
|
||||
buffer *ret = NULL;
|
||||
unsigned int len = buf_getint(buf);
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
}
|
||||
ret = buf_new(len);
|
||||
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
|
||||
buf_incrpos(buf, len);
|
||||
buf_incrlen(ret, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -262,16 +262,16 @@ void buf_putint(buffer* buf, int unsigned val) {
|
||||
}
|
||||
|
||||
/* put a SSH style string into the buffer, increasing buffer len if required */
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len) {
|
||||
|
||||
buf_putint(buf, len);
|
||||
buf_putbytes(buf, str, len);
|
||||
buf_putbytes(buf, (const unsigned char*)str, len);
|
||||
|
||||
}
|
||||
|
||||
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
|
||||
buf_putstring(buf, buf_str->data, buf_str->len);
|
||||
buf_putstring(buf, (const char*)buf_str->data, buf_str->len);
|
||||
}
|
||||
|
||||
/* put the set of len bytes into the buffer, incrementing the pos, increasing
|
||||
|
||||
16
buffer.h
16
buffer.h
@@ -22,14 +22,15 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _BUFFER_H_
|
||||
#ifndef DROPBEAR_BUFFER_H_
|
||||
|
||||
#define _BUFFER_H_
|
||||
#define DROPBEAR_BUFFER_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct buf {
|
||||
|
||||
/* don't manipulate data member outside of buffer.c - it
|
||||
is a pointer into the malloc holding buffer itself */
|
||||
unsigned char * data;
|
||||
unsigned int len; /* the used size */
|
||||
unsigned int pos;
|
||||
@@ -40,7 +41,8 @@ struct buf {
|
||||
typedef struct buf buffer;
|
||||
|
||||
buffer * buf_new(unsigned int size);
|
||||
void buf_resize(buffer *buf, unsigned int newsize);
|
||||
/* Possibly returns a new buffer*, like realloc() */
|
||||
buffer * buf_resize(buffer *buf, unsigned int newsize);
|
||||
void buf_free(buffer* buf);
|
||||
void buf_burn(buffer* buf);
|
||||
buffer* buf_newcopy(buffer* buf);
|
||||
@@ -54,15 +56,15 @@ 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);
|
||||
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
buffer * buf_getstringbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len);
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str);
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
|
||||
void buf_putmpint(buffer* buf, mp_int * mp);
|
||||
int buf_getmpint(buffer* buf, mp_int* mp);
|
||||
unsigned int buf_getint(buffer* buf);
|
||||
|
||||
#endif /* _BUFFER_H_ */
|
||||
#endif /* DROPBEAR_BUFFER_H_ */
|
||||
|
||||
16
channel.h
16
channel.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CHANNEL_H_
|
||||
#define _CHANNEL_H_
|
||||
#ifndef DROPBEAR_CHANNEL_H_
|
||||
#define DROPBEAR_CHANNEL_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
@@ -73,6 +73,7 @@ struct Channel {
|
||||
* to ensure we don't run it twice (nor type->checkclose()). */
|
||||
int close_handler_done;
|
||||
|
||||
struct dropbear_progress_connection *conn_pending;
|
||||
int initconn; /* used for TCP forwarding, whether the channel has been
|
||||
fully initialised */
|
||||
|
||||
@@ -92,7 +93,7 @@ struct Channel {
|
||||
|
||||
struct ChanType {
|
||||
|
||||
int sepfds; /* Whether this channel has seperate pipes for in/out or not */
|
||||
int sepfds; /* Whether this channel has separate pipes for in/out or not */
|
||||
char *name;
|
||||
int (*inithandler)(struct Channel*);
|
||||
int (*check_close)(struct Channel*);
|
||||
@@ -100,9 +101,12 @@ struct ChanType {
|
||||
void (*closehandler)(struct Channel*);
|
||||
};
|
||||
|
||||
/* Callback for connect_remote */
|
||||
void channel_connect_done(int result, int sock, void* user_data, const char* errstring);
|
||||
|
||||
void chaninitialise(const struct ChanType *chantypes[]);
|
||||
void chancleanup();
|
||||
void setchannelfds(fd_set *readfd, fd_set *writefd);
|
||||
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads);
|
||||
void channelio(fd_set *readfd, fd_set *writefd);
|
||||
struct Channel* getchannel();
|
||||
/* Returns an arbitrary channel that is in a ready state - not
|
||||
@@ -131,10 +135,10 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type);
|
||||
void recv_msg_channel_open_confirmation();
|
||||
void recv_msg_channel_open_failure();
|
||||
#endif
|
||||
void start_send_channel_request(struct Channel *channel, unsigned char *type);
|
||||
void start_send_channel_request(struct Channel *channel, char *type);
|
||||
|
||||
void send_msg_request_success();
|
||||
void send_msg_request_failure();
|
||||
|
||||
|
||||
#endif /* _CHANNEL_H_ */
|
||||
#endif /* DROPBEAR_CHANNEL_H_ */
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CHANSESSION_H_
|
||||
#define _CHANSESSION_H_
|
||||
#ifndef DROPBEAR_CHANSESSION_H_
|
||||
#define DROPBEAR_CHANSESSION_H_
|
||||
|
||||
#include "loginrec.h"
|
||||
#include "channel.h"
|
||||
@@ -39,14 +39,14 @@ struct exitinfo {
|
||||
|
||||
struct ChanSess {
|
||||
|
||||
unsigned char * cmd; /* command to exec */
|
||||
char * cmd; /* command to exec */
|
||||
pid_t pid; /* child process pid */
|
||||
|
||||
/* pty details */
|
||||
int master; /* the master terminal fd*/
|
||||
int slave;
|
||||
unsigned char * tty;
|
||||
unsigned char * term;
|
||||
char * tty;
|
||||
char * term;
|
||||
|
||||
/* exit details */
|
||||
struct exitinfo exit;
|
||||
@@ -103,4 +103,4 @@ struct SigMap {
|
||||
|
||||
extern const struct SigMap signames[];
|
||||
|
||||
#endif /* _CHANSESSION_H_ */
|
||||
#endif /* DROPBEAR_CHANSESSION_H_ */
|
||||
|
||||
38
circbuffer.c
38
circbuffer.c
@@ -67,23 +67,6 @@ unsigned int cbuf_getavail(circbuffer * cbuf) {
|
||||
|
||||
}
|
||||
|
||||
unsigned int cbuf_readlen(circbuffer *cbuf) {
|
||||
|
||||
dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
|
||||
dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
|
||||
|
||||
if (cbuf->used == 0) {
|
||||
TRACE(("cbuf_readlen: unused buffer"))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cbuf->readpos < cbuf->writepos) {
|
||||
return cbuf->writepos - cbuf->readpos;
|
||||
}
|
||||
|
||||
return cbuf->size - cbuf->readpos;
|
||||
}
|
||||
|
||||
unsigned int cbuf_writelen(circbuffer *cbuf) {
|
||||
|
||||
dropbear_assert(cbuf->used <= cbuf->size);
|
||||
@@ -102,12 +85,19 @@ unsigned int cbuf_writelen(circbuffer *cbuf) {
|
||||
return cbuf->size - cbuf->writepos;
|
||||
}
|
||||
|
||||
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
|
||||
if (len > cbuf_readlen(cbuf)) {
|
||||
dropbear_exit("Bad cbuf read");
|
||||
}
|
||||
void cbuf_readptrs(circbuffer *cbuf,
|
||||
unsigned char **p1, unsigned int *len1,
|
||||
unsigned char **p2, unsigned int *len2) {
|
||||
*p1 = &cbuf->data[cbuf->readpos];
|
||||
*len1 = MIN(cbuf->used, cbuf->size - cbuf->readpos);
|
||||
|
||||
return &cbuf->data[cbuf->readpos];
|
||||
if (*len1 < cbuf->used) {
|
||||
*p2 = cbuf->data;
|
||||
*len2 = cbuf->used - *len1;
|
||||
} else {
|
||||
*p2 = NULL;
|
||||
*len2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
|
||||
@@ -131,10 +121,6 @@ void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
|
||||
|
||||
|
||||
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
|
||||
if (len > cbuf_readlen(cbuf)) {
|
||||
dropbear_exit("Bad cbuf read");
|
||||
}
|
||||
|
||||
dropbear_assert(cbuf->used >= len);
|
||||
cbuf->used -= len;
|
||||
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;
|
||||
|
||||
10
circbuffer.h
10
circbuffer.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CIRCBUFFER_H_
|
||||
#define _CIRCBUFFER_H_
|
||||
#ifndef DROPBEAR_CIRCBUFFER_H_
|
||||
#define DROPBEAR_CIRCBUFFER_H_
|
||||
struct circbuf {
|
||||
|
||||
unsigned int size;
|
||||
@@ -40,10 +40,12 @@ void cbuf_free(circbuffer * cbuf);
|
||||
|
||||
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
|
||||
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
|
||||
unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */
|
||||
unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
|
||||
|
||||
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len);
|
||||
/* returns pointers to the two portions of the circular buffer that can be read */
|
||||
void cbuf_readptrs(circbuffer *cbuf,
|
||||
unsigned char **p1, unsigned int *len1,
|
||||
unsigned char **p2, unsigned int *len2);
|
||||
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
|
||||
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
|
||||
void cbuf_incrread(circbuffer *cbuf, unsigned int len);
|
||||
|
||||
@@ -155,7 +155,7 @@ static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf_resize(inbuf, readlen);
|
||||
inbuf = buf_resize(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
|
||||
if ((size_t)ret != readlen) {
|
||||
@@ -210,13 +210,14 @@ static void agent_get_key_list(m_list * ret_list)
|
||||
ret = buf_get_pub_key(key_buf, pubkey, &key_type);
|
||||
buf_free(key_buf);
|
||||
if (ret != DROPBEAR_SUCCESS) {
|
||||
/* This is slack, properly would cleanup vars etc */
|
||||
dropbear_exit("Bad pubkey received from agent");
|
||||
}
|
||||
pubkey->type = key_type;
|
||||
pubkey->source = SIGNKEY_SOURCE_AGENT;
|
||||
TRACE(("Skipping bad/unknown type pubkey from agent"));
|
||||
sign_key_free(pubkey);
|
||||
} else {
|
||||
pubkey->type = key_type;
|
||||
pubkey->source = SIGNKEY_SOURCE_AGENT;
|
||||
|
||||
list_append(ret_list, pubkey);
|
||||
list_append(ret_list, pubkey);
|
||||
}
|
||||
|
||||
/* We'll ignore the comment for now. might want it later.*/
|
||||
buf_eatstring(inbuf);
|
||||
|
||||
10
cli-auth.c
10
cli-auth.c
@@ -43,9 +43,9 @@ void cli_auth_getmethods() {
|
||||
TRACE(("enter cli_auth_getmethods"))
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
|
||||
|
||||
@@ -75,7 +75,7 @@ void cli_auth_getmethods() {
|
||||
|
||||
void recv_msg_userauth_banner() {
|
||||
|
||||
unsigned char* banner = NULL;
|
||||
char* banner = NULL;
|
||||
unsigned int bannerlen;
|
||||
unsigned int i, linecount;
|
||||
|
||||
@@ -151,8 +151,8 @@ void recv_msg_userauth_specific_60() {
|
||||
|
||||
void recv_msg_userauth_failure() {
|
||||
|
||||
unsigned char * methods = NULL;
|
||||
unsigned char * tok = NULL;
|
||||
char * methods = NULL;
|
||||
char * tok = NULL;
|
||||
unsigned int methlen = 0;
|
||||
unsigned int partial = 0;
|
||||
unsigned int i = 0;
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
|
||||
static unsigned char* get_response(unsigned char* prompt)
|
||||
static char* get_response(char* prompt)
|
||||
{
|
||||
FILE* tty = NULL;
|
||||
unsigned char* response = NULL;
|
||||
char* response = NULL;
|
||||
/* not a password, but a reasonable limit */
|
||||
char buf[DROPBEAR_MAX_CLI_PASS];
|
||||
char* ret = NULL;
|
||||
@@ -50,13 +50,13 @@ static unsigned char* get_response(unsigned char* prompt)
|
||||
}
|
||||
|
||||
if (ret == NULL) {
|
||||
response = (unsigned char*)m_strdup("");
|
||||
response = m_strdup("");
|
||||
} else {
|
||||
unsigned int buflen = strlen(buf);
|
||||
/* fgets includes newlines */
|
||||
if (buflen > 0 && buf[buflen-1] == '\n')
|
||||
buf[buflen-1] = '\0';
|
||||
response = (unsigned char*)m_strdup(buf);
|
||||
response = m_strdup(buf);
|
||||
}
|
||||
|
||||
m_burn(buf, sizeof(buf));
|
||||
@@ -66,14 +66,14 @@ static unsigned char* get_response(unsigned char* prompt)
|
||||
|
||||
void recv_msg_userauth_info_request() {
|
||||
|
||||
unsigned char *name = NULL;
|
||||
unsigned char *instruction = NULL;
|
||||
char *name = NULL;
|
||||
char *instruction = NULL;
|
||||
unsigned int num_prompts = 0;
|
||||
unsigned int i;
|
||||
|
||||
unsigned char *prompt = NULL;
|
||||
char *prompt = NULL;
|
||||
unsigned int echo = 0;
|
||||
unsigned char *response = NULL;
|
||||
char *response = NULL;
|
||||
|
||||
TRACE(("enter recv_msg_recv_userauth_info_request"))
|
||||
|
||||
@@ -121,7 +121,7 @@ void recv_msg_userauth_info_request() {
|
||||
echo = buf_getbool(ses.payload);
|
||||
|
||||
if (!echo) {
|
||||
unsigned char* p = getpass_or_cancel(prompt);
|
||||
char* p = getpass_or_cancel(prompt);
|
||||
response = m_strdup(p);
|
||||
m_burn(p, strlen(p));
|
||||
} else {
|
||||
@@ -153,7 +153,7 @@ void cli_auth_interactive() {
|
||||
strlen(cli_opts.username));
|
||||
|
||||
/* service name */
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
|
||||
/* method */
|
||||
|
||||
@@ -143,10 +143,10 @@ void cli_auth_password() {
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
|
||||
AUTH_METHOD_PASSWORD_LEN);
|
||||
|
||||
buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */
|
||||
|
||||
@@ -58,7 +58,7 @@ void recv_msg_userauth_pk_ok() {
|
||||
buffer* keybuf = NULL;
|
||||
char* algotype = NULL;
|
||||
unsigned int algolen;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
unsigned int remotelen;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_pk_ok"))
|
||||
@@ -141,7 +141,7 @@ void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
const char *algoname = NULL;
|
||||
int algolen;
|
||||
unsigned int algolen;
|
||||
buffer* sigbuf = NULL;
|
||||
|
||||
TRACE(("enter send_msg_userauth_pubkey"))
|
||||
@@ -152,10 +152,10 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN);
|
||||
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
|
||||
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
|
||||
AUTH_METHOD_PUBKEY_LEN);
|
||||
|
||||
buf_putbyte(ses.writepayload, realsign);
|
||||
|
||||
@@ -56,7 +56,7 @@ const struct ChanType clichansess = {
|
||||
|
||||
static void cli_chansessreq(struct Channel *channel) {
|
||||
|
||||
unsigned char* type = NULL;
|
||||
char* type = NULL;
|
||||
int wantreply;
|
||||
|
||||
TRACE(("enter cli_chansessreq"))
|
||||
@@ -272,7 +272,7 @@ void cli_chansess_winchange() {
|
||||
|
||||
static void send_chansess_pty_req(struct Channel *channel) {
|
||||
|
||||
unsigned char* term = NULL;
|
||||
char* term = NULL;
|
||||
|
||||
TRACE(("enter send_chansess_pty_req"))
|
||||
|
||||
@@ -305,7 +305,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
|
||||
|
||||
static void send_chansess_shell_req(struct Channel *channel) {
|
||||
|
||||
unsigned char* reqtype = NULL;
|
||||
char* reqtype = NULL;
|
||||
|
||||
TRACE(("enter send_chansess_shell_req"))
|
||||
|
||||
@@ -392,7 +392,7 @@ static const struct ChanType cli_chan_netcat = {
|
||||
|
||||
void cli_send_netcat_request() {
|
||||
|
||||
const unsigned char* source_host = "127.0.0.1";
|
||||
const char* source_host = "127.0.0.1";
|
||||
const int source_port = 22;
|
||||
|
||||
TRACE(("enter cli_send_netcat_request"))
|
||||
@@ -403,7 +403,7 @@ void cli_send_netcat_request() {
|
||||
dropbear_exit("Couldn't open initial channel");
|
||||
}
|
||||
|
||||
buf_putstring(ses.writepayload, cli_opts.netcat_host,
|
||||
buf_putstring(ses.writepayload, cli_opts.netcat_host,
|
||||
strlen(cli_opts.netcat_host));
|
||||
buf_putint(ses.writepayload, cli_opts.netcat_port);
|
||||
|
||||
|
||||
12
cli-kex.c
12
cli-kex.c
@@ -79,7 +79,7 @@ void send_msg_kexdh_init() {
|
||||
}
|
||||
cli_ses.curve25519_param = gen_kexcurve25519_param();
|
||||
}
|
||||
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -322,7 +322,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
}
|
||||
|
||||
/* Compare hostnames */
|
||||
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
|
||||
if (strncmp(cli_opts.remotehost, (const char *) buf_getptr(line, hostlen),
|
||||
hostlen) != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -334,7 +334,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) {
|
||||
if (strncmp((const char *) buf_getptr(line, algolen), algoname, algolen) != 0) {
|
||||
TRACE(("algo doesn't match"))
|
||||
continue;
|
||||
}
|
||||
@@ -346,7 +346,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
}
|
||||
|
||||
/* Now we're at the interesting hostkey */
|
||||
ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen,
|
||||
ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algoname, algolen,
|
||||
line, &fingerprint);
|
||||
|
||||
if (ret == DROPBEAR_SUCCESS) {
|
||||
@@ -382,9 +382,9 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
|
||||
buf_setpos(line, 0);
|
||||
buf_setlen(line, 0);
|
||||
buf_putbytes(line, cli_opts.remotehost, hostlen);
|
||||
buf_putbytes(line, (const unsigned char *) cli_opts.remotehost, hostlen);
|
||||
buf_putbyte(line, ' ');
|
||||
buf_putbytes(line, algoname, algolen);
|
||||
buf_putbytes(line, (const unsigned char *) algoname, algolen);
|
||||
buf_putbyte(line, ' ');
|
||||
len = line->size - line->pos;
|
||||
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
|
||||
|
||||
20
cli-main.c
20
cli-main.c
@@ -30,6 +30,7 @@
|
||||
#include "session.h"
|
||||
#include "dbrandom.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
static void cli_dropbear_log(int priority, const char* format, va_list param);
|
||||
@@ -46,7 +47,7 @@ int main(int argc, char ** argv) {
|
||||
#endif
|
||||
|
||||
int sock_in, sock_out;
|
||||
char* error = NULL;
|
||||
struct dropbear_progress_connection *progress = NULL;
|
||||
|
||||
_dropbear_exit = cli_dropbear_exit;
|
||||
_dropbear_log = cli_dropbear_log;
|
||||
@@ -72,16 +73,11 @@ int main(int argc, char ** argv) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
|
||||
0, &error);
|
||||
sock_in = sock_out = sock;
|
||||
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport, cli_connected, &ses);
|
||||
sock_in = sock_out = -1;
|
||||
}
|
||||
|
||||
if (sock_in < 0) {
|
||||
dropbear_exit("%s", error);
|
||||
}
|
||||
|
||||
cli_session(sock_in, sock_out);
|
||||
cli_session(sock_in, sock_out, progress);
|
||||
|
||||
/* not reached */
|
||||
return -1;
|
||||
@@ -91,6 +87,7 @@ int main(int argc, char ** argv) {
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
|
||||
char fmtbuf[300];
|
||||
char exitmsg[500];
|
||||
|
||||
if (!sessinitdone) {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
|
||||
@@ -102,12 +99,15 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
cli_opts.remoteport, format);
|
||||
}
|
||||
|
||||
/* Arguments to the exit printout may be unsafe to use after session_cleanup() */
|
||||
vsnprintf(exitmsg, sizeof(exitmsg), fmtbuf, param);
|
||||
|
||||
/* Do the cleanup first, since then the terminal will be reset */
|
||||
session_cleanup();
|
||||
/* Avoid printing onwards from terminal cruft */
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
dropbear_log(LOG_INFO, "%s", exitmsg);;
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ static void parse_hostname(const char* orighostarg);
|
||||
static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
|
||||
static void fill_own_user();
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename);
|
||||
static void loadidentityfile(const char* filename, int warnfail);
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
static void addforward(const char* str, m_list *fwdlist);
|
||||
@@ -65,7 +65,7 @@ static void printhelp() {
|
||||
"-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 <identityfile> (multiple allowed)\n"
|
||||
"-i <identityfile> (multiple allowed, default %s)\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
"-A Enable agent auth forwarding\n"
|
||||
@@ -95,6 +95,9 @@ static void printhelp() {
|
||||
"-v verbose (compiled with DEBUG_TRACE)\n"
|
||||
#endif
|
||||
,DROPBEAR_VERSION, cli_opts.progname,
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
DROPBEAR_DEFAULT_CLI_AUTHKEY,
|
||||
#endif
|
||||
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
|
||||
|
||||
}
|
||||
@@ -153,7 +156,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.proxycmd = NULL;
|
||||
#endif
|
||||
#ifndef DISABLE_ZLIB
|
||||
opts.enable_compress = 1;
|
||||
opts.compress_mode = DROPBEAR_COMPRESS_ON;
|
||||
#endif
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
opts.cipher_list = NULL;
|
||||
@@ -174,7 +177,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
if (nextiskey) {
|
||||
/* Load a hostkey since the previous argument was "-i" */
|
||||
loadidentityfile(argv[i]);
|
||||
loadidentityfile(argv[i], 1);
|
||||
nextiskey = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -231,7 +234,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
case 'i': /* an identityfile */
|
||||
/* Keep scp happy when it changes "-i file" to "-ifile" */
|
||||
if (strlen(argv[i]) > 2) {
|
||||
loadidentityfile(&argv[i][2]);
|
||||
loadidentityfile(&argv[i][2], 1);
|
||||
} else {
|
||||
nextiskey = 1;
|
||||
}
|
||||
@@ -444,6 +447,14 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DROPBEAR_DEFAULT_CLI_AUTHKEY) && defined(ENABLE_CLI_PUBKEY_AUTH)
|
||||
{
|
||||
char *expand_path = expand_homedir_path(DROPBEAR_DEFAULT_CLI_AUTHKEY);
|
||||
loadidentityfile(expand_path, 0);
|
||||
m_free(expand_path);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The hostname gets set up last, since
|
||||
* in multi-hop mode it will require knowledge
|
||||
* of other flags such as -i */
|
||||
@@ -455,14 +466,18 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename) {
|
||||
static void loadidentityfile(const char* filename, int warnfail) {
|
||||
sign_key *key;
|
||||
enum signkey_type keytype;
|
||||
|
||||
TRACE(("loadidentityfile %s", filename))
|
||||
|
||||
key = new_sign_key();
|
||||
keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
|
||||
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
|
||||
if (warnfail) {
|
||||
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
|
||||
}
|
||||
sign_key_free(key);
|
||||
} else {
|
||||
key->type = keytype;
|
||||
@@ -483,11 +498,14 @@ multihop_passthrough_args() {
|
||||
m_list_elem *iter;
|
||||
/* Fill out -i, -y, -W options that make sense for all
|
||||
* the intermediate processes */
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
len += 3 + strlen(key->filename);
|
||||
}
|
||||
#endif /* ENABLE_CLI_PUBKEY_AUTH */
|
||||
|
||||
len += 30; /* space for -W <size>, terminator. */
|
||||
ret = m_malloc(len);
|
||||
total = 0;
|
||||
@@ -509,6 +527,7 @@ multihop_passthrough_args() {
|
||||
total += written;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
@@ -517,6 +536,7 @@ multihop_passthrough_args() {
|
||||
dropbear_assert((unsigned int)written < size);
|
||||
total += written;
|
||||
}
|
||||
#endif /* ENABLE_CLI_PUBKEY_AUTH */
|
||||
|
||||
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
|
||||
if (total > 0)
|
||||
@@ -594,7 +614,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
|
||||
passthrough_args, remainder);
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* The stream will be incompressible since it's encrypted. */
|
||||
opts.enable_compress = 0;
|
||||
opts.compress_mode = DROPBEAR_COMPRESS_OFF;
|
||||
#endif
|
||||
m_free(passthrough_args);
|
||||
}
|
||||
|
||||
@@ -37,11 +37,12 @@
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void cli_remoteclosed();
|
||||
static void cli_remoteclosed() ATTRIB_NORETURN;
|
||||
static void cli_sessionloop();
|
||||
static void cli_session_init();
|
||||
static void cli_finished();
|
||||
static void cli_finished() ATTRIB_NORETURN;
|
||||
static void recv_msg_service_accept(void);
|
||||
static void cli_session_cleanup(void);
|
||||
static void recv_msg_global_request_cli(void);
|
||||
@@ -93,21 +94,38 @@ static const struct ChanType *cli_chantypes[] = {
|
||||
NULL /* Null termination */
|
||||
};
|
||||
|
||||
void cli_session(int sock_in, int sock_out) {
|
||||
void cli_connected(int result, int sock, void* userdata, const char *errstring)
|
||||
{
|
||||
struct sshsession *myses = userdata;
|
||||
if (result == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Connect failed: %s", errstring);
|
||||
}
|
||||
myses->sock_in = myses->sock_out = sock;
|
||||
update_channel_prio();
|
||||
}
|
||||
|
||||
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress) {
|
||||
|
||||
common_session_init(sock_in, sock_out);
|
||||
|
||||
if (progress) {
|
||||
connect_set_writequeue(progress, &ses.writequeue);
|
||||
}
|
||||
|
||||
chaninitialise(cli_chantypes);
|
||||
|
||||
/* Set up cli_ses vars */
|
||||
cli_session_init();
|
||||
|
||||
|
||||
/* Ready to go */
|
||||
sessinitdone = 1;
|
||||
|
||||
/* Exchange identification */
|
||||
send_session_identification();
|
||||
|
||||
kexfirstinitialise(); /* initialise the kex state */
|
||||
|
||||
send_msg_kexinit();
|
||||
|
||||
session_loop(cli_sessionloop);
|
||||
@@ -356,10 +374,10 @@ static void cli_remoteclosed() {
|
||||
/* Operates in-place turning dirty (untrusted potentially containing control
|
||||
* characters) text into clean text.
|
||||
* Note: this is safe only with ascii - other charsets could have problems. */
|
||||
void cleantext(unsigned char* dirtytext) {
|
||||
void cleantext(char* dirtytext) {
|
||||
|
||||
unsigned int i, j;
|
||||
unsigned char c;
|
||||
char c;
|
||||
|
||||
j = 0;
|
||||
for (i = 0; dirtytext[i] != '\0'; i++) {
|
||||
|
||||
16
cli-tcpfwd.c
16
cli-tcpfwd.c
@@ -30,6 +30,7 @@
|
||||
#include "runopts.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
#include "netio.h"
|
||||
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
static int newtcpforwarded(struct Channel * channel);
|
||||
@@ -215,7 +216,6 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
m_list_elem * iter = NULL;
|
||||
struct TCPFwdEntry *fwd;
|
||||
char portstring[NI_MAXSERV];
|
||||
int sock;
|
||||
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
|
||||
origaddr = buf_getstring(ses.payload, NULL);
|
||||
@@ -254,19 +254,7 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
}
|
||||
|
||||
snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
|
||||
sock = connect_remote(fwd->connectaddr, portstring, 1, NULL);
|
||||
if (sock < 0) {
|
||||
TRACE(("leave newtcpdirect: sock failed"))
|
||||
err = SSH_OPEN_CONNECT_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, sock);
|
||||
|
||||
/* We don't set readfd, that will get set after the connection's
|
||||
* progress succeeds */
|
||||
channel->writefd = sock;
|
||||
channel->initconn = 1;
|
||||
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel);
|
||||
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
|
||||
|
||||
|
||||
@@ -84,10 +84,14 @@ const struct dropbear_cipher dropbear_nocipher =
|
||||
|
||||
/* A few void* s are required to silence warnings
|
||||
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
|
||||
#ifdef DROPBEAR_ENABLE_CBC_MODE
|
||||
const struct dropbear_cipher_mode dropbear_mode_cbc =
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_none =
|
||||
{void_start, void_cipher, void_cipher};
|
||||
|
||||
#ifdef DROPBEAR_ENABLE_CTR_MODE
|
||||
/* a wrapper to make ctr_start and cbc_start look the same */
|
||||
static int dropbear_big_endian_ctr_start(int cipher,
|
||||
@@ -98,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
|
||||
}
|
||||
const struct dropbear_cipher_mode dropbear_mode_ctr =
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
|
||||
{&hash_desc, keysize, hashsize} */
|
||||
@@ -137,21 +141,24 @@ algo_type sshciphers[] = {
|
||||
#ifdef DROPBEAR_AES128
|
||||
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_AES256
|
||||
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH_CTR
|
||||
/* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
|
||||
#ifdef DROPBEAR_TWOFISH256
|
||||
{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128
|
||||
{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#endif /* DROPBEAR_TWOFISH_CTR */
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
/* CBC modes are always enabled */
|
||||
#ifdef DROPBEAR_ENABLE_CBC_MODE
|
||||
#ifdef DROPBEAR_AES128
|
||||
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_AES256
|
||||
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
@@ -162,9 +169,16 @@ algo_type sshciphers[] = {
|
||||
#ifdef DROPBEAR_TWOFISH128
|
||||
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
|
||||
#endif
|
||||
@@ -172,18 +186,18 @@ algo_type sshciphers[] = {
|
||||
};
|
||||
|
||||
algo_type sshhashes[] = {
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA1_96_HMAC
|
||||
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA1_HMAC
|
||||
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
|
||||
#endif
|
||||
@@ -195,7 +209,13 @@ algo_type sshhashes[] = {
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
algo_type ssh_compress[] = {
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type ssh_delaycompress[] = {
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
@@ -265,8 +285,8 @@ algo_type sshkex[] = {
|
||||
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
|
||||
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL},
|
||||
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
|
||||
#ifdef USE_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
|
||||
#endif
|
||||
@@ -305,10 +325,10 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
buf_putbyte(algolist, ',');
|
||||
donefirst = 1;
|
||||
len = strlen(localalgos[i].name);
|
||||
buf_putbytes(algolist, localalgos[i].name, len);
|
||||
buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
|
||||
}
|
||||
}
|
||||
buf_putstring(buf, algolist->data, algolist->len);
|
||||
buf_putstring(buf, (const char*)algolist->data, algolist->len);
|
||||
buf_free(algolist);
|
||||
}
|
||||
|
||||
@@ -321,12 +341,12 @@ 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];
|
||||
char * algolist = NULL;
|
||||
const 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;
|
||||
const char **clinames, **servnames;
|
||||
|
||||
if (goodguess) {
|
||||
*goodguess = 0;
|
||||
@@ -471,7 +491,7 @@ algolist_string(algo_type algos[])
|
||||
buf_setpos(b, b->len);
|
||||
buf_putbyte(b, '\0');
|
||||
buf_setpos(b, 4);
|
||||
ret_list = m_strdup(buf_getptr(b, b->len - b->pos));
|
||||
ret_list = m_strdup((const char *) buf_getptr(b, b->len - b->pos));
|
||||
buf_free(b);
|
||||
return ret_list;
|
||||
}
|
||||
|
||||
221
common-channel.c
221
common-channel.c
@@ -35,20 +35,21 @@
|
||||
#include "ssh.h"
|
||||
#include "listener.h"
|
||||
#include "runopts.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
|
||||
const unsigned char *text, const unsigned char *lang);
|
||||
const char *text, const char *lang);
|
||||
static void send_msg_channel_open_confirmation(struct Channel* channel,
|
||||
unsigned int recvwindow,
|
||||
unsigned int recvmaxpacket);
|
||||
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf);
|
||||
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
const unsigned char *moredata, unsigned int *morelen);
|
||||
static void send_msg_channel_window_adjust(struct Channel *channel,
|
||||
unsigned int incr);
|
||||
static void send_msg_channel_data(struct Channel *channel, int isextended);
|
||||
static void send_msg_channel_eof(struct Channel *channel);
|
||||
static void send_msg_channel_close(struct Channel *channel);
|
||||
static void remove_channel(struct Channel *channel);
|
||||
static void check_in_progress(struct Channel *channel);
|
||||
static unsigned int write_pending(struct Channel * channel);
|
||||
static void check_close(struct Channel *channel);
|
||||
static void close_chan_fd(struct Channel *channel, int fd, int how);
|
||||
@@ -163,7 +164,6 @@ static struct Channel* newchannel(unsigned int remotechan,
|
||||
newchan->writefd = FD_UNINIT;
|
||||
newchan->readfd = FD_UNINIT;
|
||||
newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
|
||||
newchan->initconn = 0;
|
||||
newchan->await_open = 0;
|
||||
newchan->flushing = 0;
|
||||
|
||||
@@ -242,20 +242,14 @@ void channelio(fd_set *readfds, fd_set *writefds) {
|
||||
|
||||
/* write to program/pipe stdin */
|
||||
if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
|
||||
if (channel->initconn) {
|
||||
/* XXX should this go somewhere cleaner? */
|
||||
check_in_progress(channel);
|
||||
continue; /* Important not to use the channel after
|
||||
check_in_progress(), as it may be NULL */
|
||||
}
|
||||
writechannel(channel, channel->writefd, channel->writebuf);
|
||||
writechannel(channel, channel->writefd, channel->writebuf, NULL, NULL);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
/* stderr for client mode */
|
||||
if (ERRFD_IS_WRITE(channel)
|
||||
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
|
||||
writechannel(channel, channel->errfd, channel->extrabuf);
|
||||
writechannel(channel, channel->errfd, channel->extrabuf, NULL, NULL);
|
||||
do_check_close = 1;
|
||||
}
|
||||
|
||||
@@ -374,27 +368,27 @@ static void check_close(struct Channel *channel) {
|
||||
* if so, set up the channel properly. Otherwise, the channel is cleaned up, so
|
||||
* it is important that the channel reference isn't used after a call to this
|
||||
* function */
|
||||
static void check_in_progress(struct Channel *channel) {
|
||||
void channel_connect_done(int result, int sock, void* user_data, const char* UNUSED(errstring)) {
|
||||
|
||||
int val;
|
||||
socklen_t vallen = sizeof(val);
|
||||
struct Channel *channel = user_data;
|
||||
|
||||
TRACE(("enter check_in_progress"))
|
||||
TRACE(("enter channel_connect_done"))
|
||||
|
||||
if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen)
|
||||
|| val != 0) {
|
||||
send_msg_channel_open_failure(channel->remotechan,
|
||||
SSH_OPEN_CONNECT_FAILED, "", "");
|
||||
close(channel->writefd);
|
||||
remove_channel(channel);
|
||||
TRACE(("leave check_in_progress: fail"))
|
||||
} else {
|
||||
if (result == DROPBEAR_SUCCESS)
|
||||
{
|
||||
channel->readfd = channel->writefd = sock;
|
||||
channel->conn_pending = NULL;
|
||||
chan_initwritebuf(channel);
|
||||
send_msg_channel_open_confirmation(channel, channel->recvwindow,
|
||||
channel->recvmaxpacket);
|
||||
channel->readfd = channel->writefd;
|
||||
channel->initconn = 0;
|
||||
TRACE(("leave check_in_progress: success"))
|
||||
TRACE(("leave channel_connect_done: success"))
|
||||
}
|
||||
else
|
||||
{
|
||||
send_msg_channel_open_failure(channel->remotechan,
|
||||
SSH_OPEN_CONNECT_FAILED, "", "");
|
||||
remove_channel(channel);
|
||||
TRACE(("leave check_in_progress: fail"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +396,7 @@ static void check_in_progress(struct Channel *channel) {
|
||||
/* Send the close message and set the channel as closed */
|
||||
static void send_msg_channel_close(struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_msg_channel_close %p", channel))
|
||||
TRACE(("enter send_msg_channel_close %p", (void*)channel))
|
||||
if (channel->type->closehandler
|
||||
&& !channel->close_handler_done) {
|
||||
channel->type->closehandler(channel);
|
||||
@@ -440,35 +434,115 @@ static void send_msg_channel_eof(struct Channel *channel) {
|
||||
TRACE(("leave send_msg_channel_eof"))
|
||||
}
|
||||
|
||||
/* Called to write data out to the local side of the channel.
|
||||
* Only called when we know we can write to a channel, writes as much as
|
||||
* possible */
|
||||
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
|
||||
#ifndef HAVE_WRITEV
|
||||
static void writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
const unsigned char *UNUSED(moredata), unsigned int *morelen) {
|
||||
|
||||
int len, maxlen;
|
||||
unsigned char *circ_p1, *circ_p2;
|
||||
unsigned int circ_len1, circ_len2;
|
||||
ssize_t written;
|
||||
|
||||
TRACE(("enter writechannel fd %d", fd))
|
||||
if (morelen) {
|
||||
/* fallback doesn't consume moredata */
|
||||
*morelen = 0;
|
||||
}
|
||||
|
||||
maxlen = cbuf_readlen(cbuf);
|
||||
|
||||
/* Write the data out */
|
||||
len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
|
||||
if (len <= 0) {
|
||||
TRACE(("errno %d len %d", errno, len))
|
||||
if (len < 0 && errno != EINTR) {
|
||||
/* Write the first portion of the circular buffer */
|
||||
cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
|
||||
written = write(fd, circ_p1, circ_len1);
|
||||
if (written < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
|
||||
close_chan_fd(channel, fd, SHUT_WR);
|
||||
}
|
||||
TRACE(("leave writechannel: len <= 0"))
|
||||
} else {
|
||||
cbuf_incrread(cbuf, written);
|
||||
channel->recvdonelen += written;
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_WRITEV */
|
||||
|
||||
#ifdef HAVE_WRITEV
|
||||
static void writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
const unsigned char *moredata, unsigned int *morelen) {
|
||||
|
||||
struct iovec iov[3];
|
||||
unsigned char *circ_p1, *circ_p2;
|
||||
unsigned int circ_len1, circ_len2;
|
||||
int io_count = 0;
|
||||
|
||||
ssize_t written;
|
||||
|
||||
cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
|
||||
|
||||
if (circ_len1 > 0) {
|
||||
TRACE(("circ1 %d", circ_len1))
|
||||
iov[io_count].iov_base = circ_p1;
|
||||
iov[io_count].iov_len = circ_len1;
|
||||
io_count++;
|
||||
}
|
||||
|
||||
if (circ_len2 > 0) {
|
||||
TRACE(("circ2 %d", circ_len2))
|
||||
iov[io_count].iov_base = circ_p2;
|
||||
iov[io_count].iov_len = circ_len2;
|
||||
io_count++;
|
||||
}
|
||||
|
||||
if (morelen) {
|
||||
assert(moredata);
|
||||
TRACE(("more %d", *morelen))
|
||||
iov[io_count].iov_base = (void*)moredata;
|
||||
iov[io_count].iov_len = *morelen;
|
||||
io_count++;
|
||||
}
|
||||
|
||||
if (io_count == 0) {
|
||||
/* writechannel may sometimes be called twice in a main loop iteration.
|
||||
From common_recv_msg_channel_data() then channelio().
|
||||
The second call may not have any data to write, so we just return. */
|
||||
TRACE(("leave writechannel, no data"))
|
||||
return;
|
||||
}
|
||||
TRACE(("writechannel wrote %d", len))
|
||||
|
||||
cbuf_incrread(cbuf, len);
|
||||
channel->recvdonelen += len;
|
||||
if (morelen) {
|
||||
/* Default return value, none consumed */
|
||||
*morelen = 0;
|
||||
}
|
||||
|
||||
written = writev(fd, iov, io_count);
|
||||
|
||||
if (written < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
|
||||
close_chan_fd(channel, fd, SHUT_WR);
|
||||
}
|
||||
} else {
|
||||
int cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written);
|
||||
cbuf_incrread(cbuf, cbuf_written);
|
||||
if (morelen) {
|
||||
*morelen = written - cbuf_written;
|
||||
}
|
||||
channel->recvdonelen += written;
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* HAVE_WRITEV */
|
||||
|
||||
/* Called to write data out to the local side of the channel.
|
||||
Writes the circular buffer contents and also the "moredata" buffer
|
||||
if not null. Will ignore EAGAIN */
|
||||
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
const unsigned char *moredata, unsigned int *morelen) {
|
||||
TRACE(("enter writechannel fd %d", fd))
|
||||
#ifdef HAVE_WRITEV
|
||||
writechannel_writev(channel, fd, cbuf, moredata, morelen);
|
||||
#else
|
||||
writechannel_fallback(channel, fd, cbuf, moredata, morelen);
|
||||
#endif
|
||||
|
||||
/* Window adjust handling */
|
||||
if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
|
||||
/* Set it back to max window */
|
||||
send_msg_channel_window_adjust(channel, channel->recvdonelen);
|
||||
channel->recvwindow += channel->recvdonelen;
|
||||
channel->recvdonelen = 0;
|
||||
@@ -482,9 +556,10 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
|
||||
TRACE(("leave writechannel"))
|
||||
}
|
||||
|
||||
|
||||
/* Set the file descriptors for the main select in session.c
|
||||
* This avoid channels which don't have any window available, are closed, etc*/
|
||||
void setchannelfds(fd_set *readfds, fd_set *writefds) {
|
||||
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads) {
|
||||
|
||||
unsigned int i;
|
||||
struct Channel * channel;
|
||||
@@ -502,7 +577,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
|
||||
FD if there's the possibility of "~."" to kill an
|
||||
interactive session (the read_mangler) */
|
||||
if (channel->transwindow > 0
|
||||
&& (ses.dataallowed || channel->read_mangler)) {
|
||||
&& ((ses.dataallowed && allow_reads) || channel->read_mangler)) {
|
||||
|
||||
if (channel->readfd >= 0) {
|
||||
FD_SET(channel->readfd, readfds);
|
||||
@@ -514,8 +589,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
|
||||
}
|
||||
|
||||
/* Stuff from the wire */
|
||||
if (channel->initconn
|
||||
||(channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0)) {
|
||||
if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
|
||||
FD_SET(channel->writefd, writefds);
|
||||
}
|
||||
|
||||
@@ -586,11 +660,11 @@ static void remove_channel(struct Channel * channel) {
|
||||
/* close the FDs in case they haven't been done
|
||||
* yet (they might have been shutdown etc) */
|
||||
TRACE(("CLOSE writefd %d", channel->writefd))
|
||||
close(channel->writefd);
|
||||
m_close(channel->writefd);
|
||||
TRACE(("CLOSE readfd %d", channel->readfd))
|
||||
close(channel->readfd);
|
||||
m_close(channel->readfd);
|
||||
TRACE(("CLOSE errfd %d", channel->errfd))
|
||||
close(channel->errfd);
|
||||
m_close(channel->errfd);
|
||||
}
|
||||
|
||||
if (!channel->close_handler_done
|
||||
@@ -599,6 +673,10 @@ static void remove_channel(struct Channel * channel) {
|
||||
channel->close_handler_done = 1;
|
||||
}
|
||||
|
||||
if (channel->conn_pending) {
|
||||
cancel_connect(channel->conn_pending);
|
||||
}
|
||||
|
||||
ses.channels[channel->index] = NULL;
|
||||
m_free(channel);
|
||||
ses.chancount--;
|
||||
@@ -616,7 +694,7 @@ void recv_msg_channel_request() {
|
||||
|
||||
channel = getchannel();
|
||||
|
||||
TRACE(("enter recv_msg_channel_request %p", channel))
|
||||
TRACE(("enter recv_msg_channel_request %p", (void*)channel))
|
||||
|
||||
if (channel->sent_close) {
|
||||
TRACE(("leave recv_msg_channel_request: already closed channel"))
|
||||
@@ -749,6 +827,7 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
||||
unsigned int maxdata;
|
||||
unsigned int buflen;
|
||||
unsigned int len;
|
||||
unsigned int consumed;
|
||||
|
||||
TRACE(("enter recv_msg_channel_data"))
|
||||
|
||||
@@ -775,6 +854,18 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
||||
dropbear_exit("Oversized packet");
|
||||
}
|
||||
|
||||
dropbear_assert(channel->recvwindow >= datalen);
|
||||
channel->recvwindow -= datalen;
|
||||
dropbear_assert(channel->recvwindow <= opts.recv_window);
|
||||
|
||||
/* Attempt to write the data immediately without having to put it in the circular buffer */
|
||||
consumed = datalen;
|
||||
writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed);
|
||||
|
||||
datalen -= consumed;
|
||||
buf_incrpos(ses.payload, consumed);
|
||||
|
||||
|
||||
/* We may have to run throught twice, if the buffer wraps around. Can't
|
||||
* just "leave it for next time" like with writechannel, since this
|
||||
* is payload data */
|
||||
@@ -790,10 +881,6 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
||||
len -= buflen;
|
||||
}
|
||||
|
||||
dropbear_assert(channel->recvwindow >= datalen);
|
||||
channel->recvwindow -= datalen;
|
||||
dropbear_assert(channel->recvwindow <= opts.recv_window);
|
||||
|
||||
TRACE(("leave recv_msg_channel_data"))
|
||||
}
|
||||
|
||||
@@ -834,7 +921,7 @@ static void send_msg_channel_window_adjust(struct Channel* channel,
|
||||
/* Handle a new channel request, performing any channel-type-specific setup */
|
||||
void recv_msg_channel_open() {
|
||||
|
||||
unsigned char *type;
|
||||
char *type;
|
||||
unsigned int typelen;
|
||||
unsigned int remotechan, transwindow, transmaxpacket;
|
||||
struct Channel *channel;
|
||||
@@ -952,7 +1039,7 @@ void send_msg_channel_success(struct Channel *channel) {
|
||||
/* Send a channel open failure message, with a corresponding reason
|
||||
* code (usually resource shortage or unknown chan type) */
|
||||
static void send_msg_channel_open_failure(unsigned int remotechan,
|
||||
int reason, const unsigned char *text, const unsigned char *lang) {
|
||||
int reason, const char *text, const char *lang) {
|
||||
|
||||
TRACE(("enter send_msg_channel_open_failure"))
|
||||
CHECKCLEARTOWRITE();
|
||||
@@ -960,8 +1047,8 @@ static void send_msg_channel_open_failure(unsigned int remotechan,
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
|
||||
buf_putint(ses.writepayload, remotechan);
|
||||
buf_putint(ses.writepayload, reason);
|
||||
buf_putstring(ses.writepayload, text, strlen((char*)text));
|
||||
buf_putstring(ses.writepayload, lang, strlen((char*)lang));
|
||||
buf_putstring(ses.writepayload, text, strlen(text));
|
||||
buf_putstring(ses.writepayload, lang, strlen(lang));
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_channel_open_failure"))
|
||||
@@ -1001,7 +1088,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
|
||||
}
|
||||
} else {
|
||||
TRACE(("CLOSE some fd %d", fd))
|
||||
close(fd);
|
||||
m_close(fd);
|
||||
closein = closeout = 1;
|
||||
}
|
||||
|
||||
@@ -1024,7 +1111,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
|
||||
if (channel->type->sepfds && channel->readfd == FD_CLOSED
|
||||
&& channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
|
||||
TRACE(("CLOSE (finally) of %d", fd))
|
||||
close(fd);
|
||||
m_close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1141,15 +1228,15 @@ void send_msg_request_failure() {
|
||||
}
|
||||
|
||||
struct Channel* get_any_ready_channel() {
|
||||
size_t i;
|
||||
if (ses.chancount == 0) {
|
||||
return NULL;
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < ses.chansize; i++) {
|
||||
struct Channel *chan = ses.channels[i];
|
||||
if (chan
|
||||
&& !(chan->sent_eof || chan->recv_eof)
|
||||
&& !(chan->await_open || chan->initconn)) {
|
||||
&& !(chan->await_open)) {
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
@@ -1157,7 +1244,7 @@ struct Channel* get_any_ready_channel() {
|
||||
}
|
||||
|
||||
void start_send_channel_request(struct Channel *channel,
|
||||
unsigned char *type) {
|
||||
char *type) {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
|
||||
|
||||
76
common-kex.c
76
common-kex.c
@@ -238,14 +238,24 @@ void recv_msg_newkeys() {
|
||||
void kexfirstinitialise() {
|
||||
ses.kexstate.donefirstkex = 0;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (opts.enable_compress) {
|
||||
ses.compress_algos = ssh_compress;
|
||||
} else
|
||||
#endif
|
||||
#ifdef DISABLE_ZLIB
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
#else
|
||||
switch (opts.compress_mode)
|
||||
{
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
case DROPBEAR_COMPRESS_DELAYED:
|
||||
ses.compress_algos = ssh_delaycompress;
|
||||
break;
|
||||
|
||||
case DROPBEAR_COMPRESS_ON:
|
||||
ses.compress_algos = ssh_compress;
|
||||
break;
|
||||
|
||||
case DROPBEAR_COMPRESS_OFF:
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
kexinitialise();
|
||||
}
|
||||
|
||||
@@ -303,7 +313,7 @@ static void hashkeys(unsigned char *out, unsigned int outlen,
|
||||
hash_desc->done(&hs2, tmpout);
|
||||
memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
|
||||
}
|
||||
|
||||
m_burn(&hs2, sizeof(hash_state));
|
||||
}
|
||||
|
||||
/* Generate the actual encryption/integrity keys, using the results of the
|
||||
@@ -403,6 +413,7 @@ static void gen_new_keys() {
|
||||
m_burn(C2S_key, sizeof(C2S_key));
|
||||
m_burn(S2C_IV, sizeof(S2C_IV));
|
||||
m_burn(S2C_key, sizeof(S2C_key));
|
||||
m_burn(&hs, sizeof(hash_state));
|
||||
|
||||
TRACE(("leave gen_new_keys"))
|
||||
}
|
||||
@@ -500,7 +511,7 @@ void recv_msg_kexinit() {
|
||||
|
||||
/* start the kex hash */
|
||||
local_ident_len = strlen(LOCAL_IDENT);
|
||||
remote_ident_len = strlen((char*)ses.remoteident);
|
||||
remote_ident_len = strlen(ses.remoteident);
|
||||
|
||||
kexhashbuf_len = local_ident_len + remote_ident_len
|
||||
+ ses.transkexinit->len + ses.payload->len
|
||||
@@ -514,17 +525,18 @@ void recv_msg_kexinit() {
|
||||
read_kex_algos();
|
||||
|
||||
/* V_C, the client's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(unsigned char*)LOCAL_IDENT, local_ident_len);
|
||||
buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
|
||||
/* V_S, the server's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
|
||||
|
||||
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
ses.transkexinit->data, ses.transkexinit->len);
|
||||
(const char*)ses.transkexinit->data, ses.transkexinit->len);
|
||||
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
|
||||
buf_setpos(ses.payload, 0);
|
||||
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
|
||||
buf_setpos(ses.payload, ses.payload_beginning);
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
|
||||
ses.payload->len-ses.payload->pos);
|
||||
ses.requirenext = SSH_MSG_KEXDH_REPLY;
|
||||
} else {
|
||||
/* SERVER */
|
||||
@@ -534,16 +546,17 @@ void recv_msg_kexinit() {
|
||||
/* V_C, the client's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
|
||||
/* V_S, the server's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(unsigned char*)LOCAL_IDENT, local_ident_len);
|
||||
buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
|
||||
|
||||
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
|
||||
buf_setpos(ses.payload, 0);
|
||||
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
|
||||
buf_setpos(ses.payload, ses.payload_beginning);
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
|
||||
ses.payload->len-ses.payload->pos);
|
||||
|
||||
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
ses.transkexinit->data, ses.transkexinit->len);
|
||||
(const char*)ses.transkexinit->data, ses.transkexinit->len);
|
||||
|
||||
ses.requirenext = SSH_MSG_KEXDH_INIT;
|
||||
}
|
||||
@@ -618,16 +631,20 @@ void free_kexdh_param(struct kex_dh_param *param)
|
||||
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
sign_key *hostkey) {
|
||||
|
||||
mp_int dh_p;
|
||||
DEF_MP_INT(dh_p);
|
||||
DEF_MP_INT(dh_p_min1);
|
||||
mp_int *dh_e = NULL, *dh_f = NULL;
|
||||
|
||||
/* read the prime and generator*/
|
||||
m_mp_init(&dh_p);
|
||||
m_mp_init_multi(&dh_p, &dh_p_min1, NULL);
|
||||
load_dh_p(&dh_p);
|
||||
|
||||
/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
|
||||
if (mp_cmp(dh_pub_them, &dh_p) != MP_LT
|
||||
|| mp_cmp_d(dh_pub_them, 0) != MP_GT) {
|
||||
if (mp_sub_d(&dh_p, 1, &dh_p_min1) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
/* Check that dh_pub_them (dh_e or dh_f) is in the range [2, p-2] */
|
||||
if (mp_cmp(dh_pub_them, &dh_p_min1) != MP_LT
|
||||
|| mp_cmp_d(dh_pub_them, 1) != MP_GT) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
@@ -638,7 +655,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
}
|
||||
|
||||
/* clear no longer needed vars */
|
||||
mp_clear_multi(&dh_p, NULL);
|
||||
mp_clear_multi(&dh_p, &dh_p_min1, NULL);
|
||||
|
||||
/* From here on, the code needs to work with the _same_ vars on each side,
|
||||
* not vice-versaing for client/server */
|
||||
@@ -686,6 +703,9 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
ecc_key *Q_C, *Q_S, *Q_them;
|
||||
|
||||
Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve);
|
||||
if (Q_them == NULL) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
|
||||
ses.dh_K = dropbear_ecc_shared_secret(Q_them, ¶m->key);
|
||||
|
||||
@@ -764,9 +784,9 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
|
||||
/* K_S, the host key */
|
||||
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
|
||||
/* Q_C, client's ephemeral public key octet string */
|
||||
buf_putstring(ses.kexhashbuf, Q_C, CURVE25519_LEN);
|
||||
buf_putstring(ses.kexhashbuf, (const char*)Q_C, CURVE25519_LEN);
|
||||
/* Q_S, server's ephemeral public key octet string */
|
||||
buf_putstring(ses.kexhashbuf, Q_S, CURVE25519_LEN);
|
||||
buf_putstring(ses.kexhashbuf, (const char*)Q_S, CURVE25519_LEN);
|
||||
/* K, the shared secret */
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
@@ -798,6 +818,7 @@ static void finish_kexhashbuf(void) {
|
||||
|
||||
buf_burn(ses.kexhashbuf);
|
||||
buf_free(ses.kexhashbuf);
|
||||
m_burn(&hs, sizeof(hash_state));
|
||||
ses.kexhashbuf = NULL;
|
||||
|
||||
/* first time around, we set the session_id to H */
|
||||
@@ -805,7 +826,6 @@ static void finish_kexhashbuf(void) {
|
||||
/* create the session_id, this never needs freeing */
|
||||
ses.session_id = buf_newcopy(ses.hash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* read the other side's algo list. buf_match_algo is a callback to match
|
||||
|
||||
160
common-session.c
160
common-session.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "kex.h"
|
||||
#include "channel.h"
|
||||
#include "runopts.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void checktimeouts();
|
||||
static long select_timeout();
|
||||
@@ -53,17 +54,29 @@ int exitflag = 0; /* GLOBAL */
|
||||
void common_session_init(int sock_in, int sock_out) {
|
||||
time_t now;
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
debug_start_net();
|
||||
#endif
|
||||
|
||||
TRACE(("enter session_init"))
|
||||
|
||||
ses.sock_in = sock_in;
|
||||
ses.sock_out = sock_out;
|
||||
ses.maxfd = MAX(sock_in, sock_out);
|
||||
|
||||
if (sock_in >= 0) {
|
||||
setnonblocking(sock_in);
|
||||
}
|
||||
if (sock_out >= 0) {
|
||||
setnonblocking(sock_out);
|
||||
}
|
||||
|
||||
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
|
||||
/* Sets it to lowdelay */
|
||||
update_channel_prio();
|
||||
|
||||
now = monotonic_now();
|
||||
ses.connect_time = now;
|
||||
ses.last_packet_time_keepalive_recv = now;
|
||||
ses.last_packet_time_idle = now;
|
||||
ses.last_packet_time_any_sent = 0;
|
||||
@@ -78,8 +91,6 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
|
||||
|
||||
kexfirstinitialise(); /* initialise the kex state */
|
||||
|
||||
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
|
||||
ses.transseq = 0;
|
||||
|
||||
@@ -140,6 +151,7 @@ void session_loop(void(*loophandler)()) {
|
||||
|
||||
/* main loop, select()s for all sockets in use */
|
||||
for(;;) {
|
||||
const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
|
||||
|
||||
timeout.tv_sec = select_timeout();
|
||||
timeout.tv_usec = 0;
|
||||
@@ -147,9 +159,15 @@ void session_loop(void(*loophandler)()) {
|
||||
FD_ZERO(&readfd);
|
||||
dropbear_assert(ses.payload == NULL);
|
||||
|
||||
/* 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))) {
|
||||
/* We delay reading from the input socket during initial setup until
|
||||
after we have written out our initial KEXINIT packet (empty writequeue).
|
||||
This means our initial packet can be in-flight while we're doing a blocking
|
||||
read for the remote ident.
|
||||
We also avoid reading from the socket if the writequeue is full, that avoids
|
||||
replies backing up */
|
||||
if (ses.sock_in != -1
|
||||
&& (ses.remoteident || isempty(&ses.writequeue))
|
||||
&& writequeue_has_space) {
|
||||
FD_SET(ses.sock_in, &readfd);
|
||||
}
|
||||
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
|
||||
@@ -161,7 +179,10 @@ void session_loop(void(*loophandler)()) {
|
||||
FD_SET(ses.signal_pipe[0], &readfd);
|
||||
|
||||
/* set up for channels which can be read/written */
|
||||
setchannelfds(&readfd, &writefd);
|
||||
setchannelfds(&readfd, &writefd, writequeue_has_space);
|
||||
|
||||
/* Pending connections to test */
|
||||
set_connect_fds(&writefd);
|
||||
|
||||
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
|
||||
|
||||
@@ -210,11 +231,13 @@ void session_loop(void(*loophandler)()) {
|
||||
process_packet();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* if required, flush out any queued reply packets that
|
||||
were being held up during a KEX */
|
||||
maybe_flush_reply_queue();
|
||||
|
||||
handle_connect_fds(&writefd);
|
||||
|
||||
/* process pipes etc for the channels, ses.dataallowed == 0
|
||||
* during rekeying ) */
|
||||
channelio(&readfd, &writefd);
|
||||
@@ -236,6 +259,15 @@ void session_loop(void(*loophandler)()) {
|
||||
/* Not reached */
|
||||
}
|
||||
|
||||
static void cleanup_buf(buffer **buf) {
|
||||
if (!*buf) {
|
||||
return;
|
||||
}
|
||||
buf_burn(*buf);
|
||||
buf_free(*buf);
|
||||
*buf = NULL;
|
||||
}
|
||||
|
||||
/* clean up a session on exit */
|
||||
void session_cleanup() {
|
||||
|
||||
@@ -247,24 +279,47 @@ void session_cleanup() {
|
||||
return;
|
||||
}
|
||||
|
||||
/* BEWARE of changing order of functions here. */
|
||||
|
||||
/* Must be before extra_session_cleanup() */
|
||||
chancleanup();
|
||||
|
||||
if (ses.extra_session_cleanup) {
|
||||
ses.extra_session_cleanup();
|
||||
}
|
||||
|
||||
chancleanup();
|
||||
|
||||
/* Cleaning up keys must happen after other cleanup
|
||||
functions which might queue packets */
|
||||
if (ses.session_id) {
|
||||
buf_burn(ses.session_id);
|
||||
buf_free(ses.session_id);
|
||||
ses.session_id = NULL;
|
||||
/* After these are freed most functions will fail */
|
||||
#ifdef DROPBEAR_CLEANUP
|
||||
/* listeners call cleanup functions, this should occur before
|
||||
other session state is freed. */
|
||||
remove_all_listeners();
|
||||
|
||||
remove_connect_pending();
|
||||
|
||||
while (!isempty(&ses.writequeue)) {
|
||||
buf_free(dequeue(&ses.writequeue));
|
||||
}
|
||||
if (ses.hash) {
|
||||
buf_burn(ses.hash);
|
||||
buf_free(ses.hash);
|
||||
ses.hash = NULL;
|
||||
|
||||
m_free(ses.remoteident);
|
||||
m_free(ses.authstate.pw_dir);
|
||||
m_free(ses.authstate.pw_name);
|
||||
m_free(ses.authstate.pw_shell);
|
||||
m_free(ses.authstate.pw_passwd);
|
||||
m_free(ses.authstate.username);
|
||||
#endif
|
||||
|
||||
cleanup_buf(&ses.session_id);
|
||||
cleanup_buf(&ses.hash);
|
||||
cleanup_buf(&ses.payload);
|
||||
cleanup_buf(&ses.readbuf);
|
||||
cleanup_buf(&ses.writepayload);
|
||||
cleanup_buf(&ses.kexhashbuf);
|
||||
cleanup_buf(&ses.transkexinit);
|
||||
if (ses.dh_K) {
|
||||
mp_clear(ses.dh_K);
|
||||
}
|
||||
m_free(ses.dh_K);
|
||||
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
m_free(ses.keys);
|
||||
|
||||
@@ -273,10 +328,8 @@ void session_cleanup() {
|
||||
|
||||
void send_session_identification() {
|
||||
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);
|
||||
buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
|
||||
writebuf_enqueue(writebuf, 0);
|
||||
}
|
||||
|
||||
static void read_session_identification() {
|
||||
@@ -395,16 +448,16 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
}
|
||||
|
||||
void ignore_recv_response() {
|
||||
// Do nothing
|
||||
/* Do nothing */
|
||||
TRACE(("Ignored msg_request_response"))
|
||||
}
|
||||
|
||||
static void send_msg_keepalive() {
|
||||
CHECKCLEARTOWRITE();
|
||||
time_t old_time_idle = ses.last_packet_time_idle;
|
||||
|
||||
struct Channel *chan = get_any_ready_channel();
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
if (chan) {
|
||||
/* Channel requests are preferable, more implementations
|
||||
handle them than SSH_MSG_GLOBAL_REQUEST */
|
||||
@@ -434,6 +487,11 @@ static void checktimeouts() {
|
||||
time_t now;
|
||||
now = monotonic_now();
|
||||
|
||||
if (IS_DROPBEAR_SERVER && ses.connect_time != 0
|
||||
&& now - ses.connect_time >= AUTH_TIMEOUT) {
|
||||
dropbear_close("Timeout before auth");
|
||||
}
|
||||
|
||||
/* we can't rekey if we haven't done remote ident exchange yet */
|
||||
if (ses.remoteident == NULL) {
|
||||
return;
|
||||
@@ -474,20 +532,39 @@ static void checktimeouts() {
|
||||
}
|
||||
}
|
||||
|
||||
static void update_timeout(long limit, long now, long last_event, long * timeout) {
|
||||
TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
|
||||
limit, now, last_event, *timeout))
|
||||
if (last_event > 0 && limit > 0) {
|
||||
*timeout = MIN(*timeout, last_event+limit-now);
|
||||
TRACE2(("new timeout %ld", *timeout))
|
||||
}
|
||||
}
|
||||
|
||||
static long select_timeout() {
|
||||
/* determine the minimum timeout that might be required, so
|
||||
as to avoid waking when unneccessary */
|
||||
long ret = LONG_MAX;
|
||||
if (KEX_REKEY_TIMEOUT > 0)
|
||||
ret = MIN(KEX_REKEY_TIMEOUT, ret);
|
||||
/* AUTH_TIMEOUT is only relevant before authdone */
|
||||
if (ses.authstate.authdone != 1 && AUTH_TIMEOUT > 0)
|
||||
ret = MIN(AUTH_TIMEOUT, ret);
|
||||
if (opts.keepalive_secs > 0)
|
||||
ret = MIN(opts.keepalive_secs, ret);
|
||||
if (opts.idle_timeout_secs > 0)
|
||||
ret = MIN(opts.idle_timeout_secs, ret);
|
||||
return ret;
|
||||
long timeout = LONG_MAX;
|
||||
long now = monotonic_now();
|
||||
|
||||
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
|
||||
|
||||
if (ses.authstate.authdone != 1 && IS_DROPBEAR_SERVER) {
|
||||
/* AUTH_TIMEOUT is only relevant before authdone */
|
||||
update_timeout(AUTH_TIMEOUT, now, ses.connect_time, &timeout);
|
||||
}
|
||||
|
||||
if (ses.authstate.authdone) {
|
||||
update_timeout(opts.keepalive_secs, now,
|
||||
MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
|
||||
&timeout);
|
||||
}
|
||||
|
||||
update_timeout(opts.idle_timeout_secs, now, ses.last_packet_time_idle,
|
||||
&timeout);
|
||||
|
||||
/* clamp negative timeouts to zero - event has already triggered */
|
||||
return MAX(timeout, 0);
|
||||
}
|
||||
|
||||
const char* get_user_shell() {
|
||||
@@ -543,6 +620,11 @@ void update_channel_prio() {
|
||||
|
||||
TRACE(("update_channel_prio"))
|
||||
|
||||
if (ses.sock_out < 0) {
|
||||
TRACE(("leave update_channel_prio: no socket"))
|
||||
return;
|
||||
}
|
||||
|
||||
new_prio = DROPBEAR_PRIO_BULK;
|
||||
for (i = 0; i < ses.chansize; i++) {
|
||||
struct Channel *channel = ses.channels[i];
|
||||
@@ -573,7 +655,7 @@ void update_channel_prio() {
|
||||
}
|
||||
|
||||
if (new_prio != ses.socket_prio) {
|
||||
TRACE(("Dropbear priority transitioning %4.4s -> %4.4s", (char*)&ses.socket_prio, (char*)&new_prio))
|
||||
TRACE(("Dropbear priority transitioning %d -> %d", ses.socket_prio, new_prio))
|
||||
set_sock_priority(ses.sock_out, new_prio);
|
||||
ses.socket_prio = new_prio;
|
||||
}
|
||||
|
||||
10
compat.h
10
compat.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _COMPAT_H_
|
||||
#define _COMPAT_H_
|
||||
#ifndef DROPBEAR_COMPAT_H_
|
||||
#define DROPBEAR_COMPAT_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
@@ -49,8 +49,8 @@ void setusershell();
|
||||
void endusershell();
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_DEVNULL
|
||||
#define _PATH_DEVNULL "/dev/null"
|
||||
#ifndef DROPBEAR_PATH_DEVNULL
|
||||
#define DROPBEAR_PATH_DEVNULL "/dev/null"
|
||||
#endif
|
||||
|
||||
#endif /* _COMPAT_H_ */
|
||||
#endif /* DROPBEAR_COMPAT_H_ */
|
||||
|
||||
13
configure.ac
13
configure.ac
@@ -265,7 +265,7 @@ AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
]],
|
||||
[[ struct sockaddr_storage s; ]])],
|
||||
[[ if (sizeof(struct sockaddr_storage)) return 0 ]])],
|
||||
[ ac_cv_have_struct_sockaddr_storage="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_storage="no" ]
|
||||
)
|
||||
@@ -279,7 +279,7 @@ AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
]],
|
||||
[[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
|
||||
[[ if (sizeof(struct sockaddr_in6)) return 0 ]])],
|
||||
[ ac_cv_have_struct_sockaddr_in6="yes" ],
|
||||
[ ac_cv_have_struct_sockaddr_in6="no" ]
|
||||
)
|
||||
@@ -293,7 +293,7 @@ AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
]],
|
||||
[[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
|
||||
[[ if (sizeof(struct in6_addr)) return 0 ]])],
|
||||
[ ac_cv_have_struct_in6_addr="yes" ],
|
||||
[ ac_cv_have_struct_in6_addr="no" ]
|
||||
)
|
||||
@@ -308,7 +308,7 @@ AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
]],
|
||||
[[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
|
||||
[[ if (sizeof(struct addrinfo)) return 0 ]])],
|
||||
[ ac_cv_have_struct_addrinfo="yes" ],
|
||||
[ ac_cv_have_struct_addrinfo="no" ]
|
||||
)
|
||||
@@ -660,6 +660,7 @@ fi
|
||||
AC_EXEEXT
|
||||
|
||||
# XXX there must be a nicer way to do this
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AS_MKDIR_P(libtomcrypt/src/ciphers/aes)
|
||||
AS_MKDIR_P(libtomcrypt/src/ciphers/safer)
|
||||
AS_MKDIR_P(libtomcrypt/src/ciphers/twofish)
|
||||
@@ -710,8 +711,10 @@ AS_MKDIR_P(libtomcrypt/src/pk/katja)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/rsa)
|
||||
AS_MKDIR_P(libtomcrypt/src/prngs)
|
||||
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
|
||||
fi
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_CONFIG_FILES(Makefile libtomcrypt/Makefile libtommath/Makefile)
|
||||
AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef _CRYPTO_DESC_H
|
||||
#define _CRYPTO_DESC_H
|
||||
#ifndef DROPBEAR_CRYPTO_DESC_H
|
||||
#define DROPBEAR_CRYPTO_DESC_H
|
||||
|
||||
void crypto_init();
|
||||
|
||||
extern int dropbear_ltc_prng;
|
||||
|
||||
#endif /* _CRYPTO_DESC_H */
|
||||
#endif /* DROPBEAR_CRYPTO_DESC_H */
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
||||
|
||||
memcpy(origx, x, 10 * sizeof(limb));
|
||||
fsum(x, z);
|
||||
fdifference(z, origx); // does x - z
|
||||
fdifference(z, origx); /* does x - z */
|
||||
|
||||
memcpy(origxprime, xprime, sizeof(limb) * 10);
|
||||
fsum(xprime, zprime);
|
||||
@@ -554,7 +554,7 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
||||
fproduct(x2, xx, zz);
|
||||
freduce_degree(x2);
|
||||
freduce_coefficients(x2);
|
||||
fdifference(zz, xx); // does zz = xx - zz
|
||||
fdifference(zz, xx); /* does zz = xx - zz */
|
||||
memset(zzz + 10, 0, sizeof(limb) * 9);
|
||||
fscalar_product(zzz, zz, 121665);
|
||||
/* No need to call freduce_degree here:
|
||||
@@ -641,9 +641,9 @@ cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
|
||||
memcpy(resultz, nqz, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Shamelessly copied from djb's code
|
||||
// -----------------------------------------------------------------------------
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Shamelessly copied from djb's code
|
||||
* ----------------------------------------------------------------------------- */
|
||||
static void
|
||||
crecip(limb *out, const limb *z) {
|
||||
limb z2[10];
|
||||
|
||||
@@ -33,7 +33,7 @@ Identity file.
|
||||
Read the identity key from file
|
||||
.I idfile
|
||||
(multiple allowed). This file is created with dropbearkey(1) or converted
|
||||
from OpenSSH with dropbearconvert(1).
|
||||
from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is used
|
||||
.TP
|
||||
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Local port forwarding.
|
||||
|
||||
@@ -141,7 +141,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void addrandom(char * buf, unsigned int len)
|
||||
void addrandom(unsigned char * buf, unsigned int len)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
@@ -306,7 +306,7 @@ void gen_random_mpint(mp_int *max, mp_int *rand) {
|
||||
|
||||
/* keep regenerating until we get one satisfying
|
||||
* 0 < rand < max */
|
||||
} while (mp_cmp(rand, max) != MP_LT);
|
||||
} while (!(mp_cmp(rand, max) == MP_LT && mp_cmp_d(rand, 0) == MP_GT));
|
||||
m_burn(randbuf, len);
|
||||
m_free(randbuf);
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _RANDOM_H_
|
||||
#define _RANDOM_H_
|
||||
#ifndef DROPBEAR_RANDOM_H_
|
||||
#define DROPBEAR_RANDOM_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
void seedrandom();
|
||||
void genrandom(unsigned char* buf, unsigned int len);
|
||||
void addrandom(char * buf, unsigned int len);
|
||||
void addrandom(unsigned char * buf, unsigned int len);
|
||||
void gen_random_mpint(mp_int *max, mp_int *rand);
|
||||
|
||||
#endif /* _RANDOM_H_ */
|
||||
#endif /* DROPBEAR_RANDOM_H_ */
|
||||
|
||||
406
dbutil.c
406
dbutil.c
@@ -150,18 +150,44 @@ void dropbear_log(int priority, const char* format, ...) {
|
||||
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
|
||||
static double debug_start_time = -1;
|
||||
|
||||
void debug_start_net()
|
||||
{
|
||||
if (getenv("DROPBEAR_DEBUG_NET_TIMESTAMP"))
|
||||
{
|
||||
/* Timestamps start from first network activity */
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
debug_start_time = tv.tv_sec + (tv.tv_usec / 1000000.0);
|
||||
TRACE(("Resetting Dropbear TRACE timestamps"))
|
||||
}
|
||||
}
|
||||
|
||||
static double time_since_start()
|
||||
{
|
||||
double nowf;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
nowf = tv.tv_sec + (tv.tv_usec / 1000000.0);
|
||||
if (debug_start_time < 0)
|
||||
{
|
||||
debug_start_time = nowf;
|
||||
return 0;
|
||||
}
|
||||
return nowf - debug_start_time;
|
||||
}
|
||||
|
||||
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) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
|
||||
fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start());
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
@@ -170,7 +196,6 @@ void dropbear_trace(const char* format, ...) {
|
||||
void dropbear_trace2(const char* format, ...) {
|
||||
static int trace_env = -1;
|
||||
va_list param;
|
||||
struct timeval tv;
|
||||
|
||||
if (trace_env == -1) {
|
||||
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
|
||||
@@ -180,193 +205,14 @@ void dropbear_trace2(const char* format, ...) {
|
||||
return;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
|
||||
fprintf(stderr, "TRACE2 (%d) %f: ", getpid(), time_since_start());
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
}
|
||||
#endif /* DEBUG_TRACE */
|
||||
|
||||
void set_sock_nodelay(int sock) {
|
||||
int val;
|
||||
|
||||
/* disable nagle */
|
||||
val = 1;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
|
||||
}
|
||||
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio) {
|
||||
|
||||
int iptos_val = 0, so_prio_val = 0, rc;
|
||||
|
||||
/* Don't log ENOTSOCK errors so that this can harmlessly be called
|
||||
* on a client '-J' proxy pipe */
|
||||
|
||||
/* set the TOS bit for either ipv4 or ipv6 */
|
||||
#ifdef IPTOS_LOWDELAY
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
iptos_val = IPTOS_LOWDELAY;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
iptos_val = IPTOS_THROUGHPUT;
|
||||
}
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
|
||||
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0 && errno != ENOTSOCK) {
|
||||
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0 && errno != ENOTSOCK) {
|
||||
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
so_prio_val = TC_PRIO_INTERACTIVE;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
so_prio_val = TC_PRIO_BULK;
|
||||
}
|
||||
/* linux specific, sets QoS class. see tc-prio(8) */
|
||||
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
|
||||
if (rc < 0 && errno != ENOTSOCK)
|
||||
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
|
||||
strerror(errno));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Listen on address:port.
|
||||
* Special cases are address of "" listening on everything,
|
||||
* and address of NULL listening on localhost only.
|
||||
* Returns the number of sockets bound on success, or -1 on failure. On
|
||||
* failure, if errstring wasn't NULL, it'll be a newly malloced error
|
||||
* string.*/
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
|
||||
|
||||
struct addrinfo hints, *res = NULL, *res0 = NULL;
|
||||
int err;
|
||||
unsigned int nsock;
|
||||
struct linger linger;
|
||||
int val;
|
||||
int sock;
|
||||
|
||||
TRACE(("enter dropbear_listen"))
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
/* for calling getaddrinfo:
|
||||
address == NULL and !AI_PASSIVE: local loopback
|
||||
address == NULL and AI_PASSIVE: all interfaces
|
||||
address != NULL: whatever the address says */
|
||||
if (!address) {
|
||||
TRACE(("dropbear_listen: local loopback"))
|
||||
} else {
|
||||
if (address[0] == '\0') {
|
||||
TRACE(("dropbear_listen: all interfaces"))
|
||||
address = NULL;
|
||||
}
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
}
|
||||
err = getaddrinfo(address, port, &hints, &res0);
|
||||
|
||||
if (err) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(gai_strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
|
||||
}
|
||||
if (res0) {
|
||||
freeaddrinfo(res0);
|
||||
res0 = NULL;
|
||||
}
|
||||
TRACE(("leave dropbear_listen: failed resolving"))
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
nsock = 0;
|
||||
for (res = res0; res != NULL && nsock < sockcount;
|
||||
res = res->ai_next) {
|
||||
|
||||
/* Get a socket */
|
||||
socks[nsock] = socket(res->ai_family, res->ai_socktype,
|
||||
res->ai_protocol);
|
||||
|
||||
sock = socks[nsock]; /* For clarity */
|
||||
|
||||
if (sock < 0) {
|
||||
err = errno;
|
||||
TRACE(("socket() failed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Various useful socket options */
|
||||
val = 1;
|
||||
/* set to reuse, quick timeout */
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 5;
|
||||
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
|
||||
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||
if (res->ai_family == AF_INET6) {
|
||||
int on = 1;
|
||||
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&on, sizeof(on)) == -1) {
|
||||
dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
set_sock_nodelay(sock);
|
||||
|
||||
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("bind(%s) failed", port))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("listen() failed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
*maxfd = MAX(*maxfd, sock);
|
||||
|
||||
nsock++;
|
||||
}
|
||||
|
||||
if (res0) {
|
||||
freeaddrinfo(res0);
|
||||
res0 = NULL;
|
||||
}
|
||||
|
||||
if (nsock == 0) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error listening: %s", strerror(err));
|
||||
}
|
||||
TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
|
||||
return nsock;
|
||||
}
|
||||
|
||||
/* Connect to a given unix socket. The socket is blocking */
|
||||
#ifdef ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* path) {
|
||||
@@ -390,93 +236,6 @@ int connect_unix(const char* path) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
|
||||
* return immediately if nonblocking is set. On failure, if errstring
|
||||
* wasn't null, it will be a newly malloced error message */
|
||||
|
||||
/* TODO: maxfd */
|
||||
int connect_remote(const char* remotehost, const char* remoteport,
|
||||
int nonblocking, char ** errstring) {
|
||||
|
||||
struct addrinfo *res0 = NULL, *res = NULL, hints;
|
||||
int sock;
|
||||
int err;
|
||||
|
||||
TRACE(("enter connect_remote"))
|
||||
|
||||
if (errstring != NULL) {
|
||||
*errstring = NULL;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
|
||||
err = getaddrinfo(remotehost, remoteport, &hints, &res0);
|
||||
if (err) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 100 + strlen(gai_strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error resolving '%s' port '%s'. %s",
|
||||
remotehost, remoteport, gai_strerror(err));
|
||||
}
|
||||
TRACE(("Error resolving: %s", gai_strerror(err)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
sock = -1;
|
||||
err = EADDRNOTAVAIL;
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
|
||||
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (sock < 0) {
|
||||
err = errno;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nonblocking) {
|
||||
setnonblocking(sock);
|
||||
}
|
||||
|
||||
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
if (errno == EINPROGRESS && nonblocking) {
|
||||
TRACE(("Connect in progress"))
|
||||
break;
|
||||
} else {
|
||||
err = errno;
|
||||
close(sock);
|
||||
sock = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break; /* Success */
|
||||
}
|
||||
|
||||
if (sock < 0 && !(errno == EINPROGRESS && nonblocking)) {
|
||||
/* Failed */
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error connecting: %s", strerror(err));
|
||||
}
|
||||
TRACE(("Error connecting: %s", strerror(err)))
|
||||
} else {
|
||||
/* Success */
|
||||
set_sock_nodelay(sock);
|
||||
}
|
||||
|
||||
freeaddrinfo(res0);
|
||||
if (sock > 0 && errstring != NULL && *errstring != NULL) {
|
||||
m_free(*errstring);
|
||||
}
|
||||
|
||||
TRACE(("leave connect_remote: sock %d\n", sock))
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* Sets up a pipe for a, returning three non-blocking file descriptors
|
||||
* and the pid. exec_fn is the function that will actually execute the child process,
|
||||
* it will be run after the child has fork()ed, and is passed exec_data.
|
||||
@@ -612,88 +371,6 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
|
||||
execv(usershell, argv);
|
||||
}
|
||||
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (local_host || local_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, local_host, local_port, host_lookup);
|
||||
}
|
||||
if (remote_host || remote_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, remote_host, remote_port, host_lookup);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a string representation of the socket address passed. The return
|
||||
* value is allocated with malloc() */
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port,
|
||||
int host_lookup) {
|
||||
|
||||
char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
|
||||
unsigned int len;
|
||||
int ret;
|
||||
|
||||
int flags = NI_NUMERICSERV | NI_NUMERICHOST;
|
||||
|
||||
#ifndef DO_HOST_LOOKUP
|
||||
host_lookup = 0;
|
||||
#endif
|
||||
|
||||
if (host_lookup) {
|
||||
flags = NI_NUMERICSERV;
|
||||
}
|
||||
|
||||
len = sizeof(struct sockaddr_storage);
|
||||
/* Some platforms such as Solaris 8 require that len is the length
|
||||
* of the specific structure. Some older linux systems (glibc 2.1.3
|
||||
* such as debian potato) have sockaddr_storage.__ss_family instead
|
||||
* but we'll ignore them */
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
|
||||
if (addr->ss_family == AF_INET) {
|
||||
len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
if (addr->ss_family == AF_INET6) {
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
|
||||
serv, sizeof(serv)-1, flags);
|
||||
|
||||
if (ret != 0) {
|
||||
if (host_lookup) {
|
||||
/* On some systems (Darwin does it) we get EINTR from getnameinfo
|
||||
* somehow. Eew. So we'll just return the IP, since that doesn't seem
|
||||
* to exhibit that behaviour. */
|
||||
getaddrstring(addr, ret_host, ret_port, 0);
|
||||
return;
|
||||
} else {
|
||||
/* if we can't do a numeric lookup, something's gone terribly wrong */
|
||||
dropbear_exit("Failed lookup: %s", gai_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_host) {
|
||||
*ret_host = m_strdup(host);
|
||||
}
|
||||
if (ret_port) {
|
||||
*ret_port = m_strdup(serv);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
void printhex(const char * label, const unsigned char * buf, int len) {
|
||||
|
||||
@@ -827,12 +504,12 @@ out:
|
||||
|
||||
/* make sure that the socket closes */
|
||||
void m_close(int fd) {
|
||||
int val;
|
||||
|
||||
if (fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int val;
|
||||
do {
|
||||
val = close(fd);
|
||||
} while (val < 0 && errno == EINTR);
|
||||
@@ -936,6 +613,24 @@ int m_str_to_uint(const char* str, unsigned int *val) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns malloced path. inpath beginning with '/' is returned as-is,
|
||||
otherwise home directory is prepended */
|
||||
char * expand_homedir_path(const char *inpath) {
|
||||
struct passwd *pw = NULL;
|
||||
if (inpath[0] != '/') {
|
||||
pw = getpwuid(getuid());
|
||||
if (pw && pw->pw_dir) {
|
||||
int len = strlen(inpath) + strlen(pw->pw_dir) + 2;
|
||||
char *buf = m_malloc(len);
|
||||
snprintf(buf, len, "%s/%s", pw->pw_dir, inpath);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback */
|
||||
return m_strdup(inpath);
|
||||
}
|
||||
|
||||
int constant_time_memcmp(const void* a, const void *b, size_t n)
|
||||
{
|
||||
const char *xa = a, *xb = b;
|
||||
@@ -1001,3 +696,4 @@ time_t monotonic_now() {
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
28
dbutil.h
28
dbutil.h
@@ -22,12 +22,13 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DBUTIL_H_
|
||||
#ifndef DROPBEAR_DBUTIL_H_
|
||||
|
||||
#define _DBUTIL_H_
|
||||
#define DROPBEAR_DBUTIL_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "queue.h"
|
||||
|
||||
#ifndef DISABLE_SYSLOG
|
||||
void startsyslog();
|
||||
@@ -58,32 +59,18 @@ 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);
|
||||
void printmpint(const char *label, mp_int *mp);
|
||||
void debug_start_net();
|
||||
extern int debug_trace;
|
||||
#endif
|
||||
|
||||
enum dropbear_prio {
|
||||
DROPBEAR_PRIO_DEFAULT = 10,
|
||||
DROPBEAR_PRIO_LOWDELAY = 11,
|
||||
DROPBEAR_PRIO_BULK = 12,
|
||||
};
|
||||
|
||||
char * stripcontrol(const char * text);
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup);
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port, int host_lookup);
|
||||
void set_sock_nodelay(int sock);
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio);
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
|
||||
|
||||
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
|
||||
int *writefd, int *readfd, int *errfd, pid_t *pid);
|
||||
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
|
||||
#ifdef ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* addr);
|
||||
#endif
|
||||
int connect_remote(const char* remotehost, const char* remoteport,
|
||||
int nonblocking, char ** errstring);
|
||||
int buf_readfile(buffer* buf, const char* filename);
|
||||
int buf_getline(buffer * line, FILE * authfile);
|
||||
|
||||
@@ -91,7 +78,7 @@ void m_close(int fd);
|
||||
void * m_malloc(size_t size);
|
||||
void * m_strdup(const char * str);
|
||||
void * m_realloc(void* ptr, size_t size);
|
||||
#define m_free(X) free(X); (X) = NULL;
|
||||
#define m_free(X) do {free(X); (X) = NULL;} while (0)
|
||||
void m_burn(void* data, unsigned int len);
|
||||
void setnonblocking(int fd);
|
||||
void disallow_core();
|
||||
@@ -110,5 +97,6 @@ int constant_time_memcmp(const void* a, const void *b, size_t n);
|
||||
a real-world clock */
|
||||
time_t monotonic_now();
|
||||
|
||||
char * expand_homedir_path(const char *inpath);
|
||||
|
||||
#endif /* _DBUTIL_H_ */
|
||||
#endif /* DROPBEAR_DBUTIL_H_ */
|
||||
|
||||
12
debian/changelog
vendored
12
debian/changelog
vendored
@@ -1,3 +1,15 @@
|
||||
dropbear (2015.68-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sat, 8 Aug 2015 22:52:58 +0800
|
||||
|
||||
dropbear (2015.67-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 28 Jan 2015 22:53:59 +0800
|
||||
|
||||
dropbear (2014.66-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
6
debug.h
6
debug.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
#ifndef DROPBEAR_DEBUG_H_
|
||||
#define DROPBEAR_DEBUG_H_
|
||||
|
||||
#include "includes.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
|
||||
|
||||
@@ -100,7 +100,8 @@ Print the version
|
||||
.TP
|
||||
Authorized Keys
|
||||
|
||||
~/.ssh/authorized_keys can be set up to allow remote login with a RSA or DSS
|
||||
~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
|
||||
ECDSA, or DSS
|
||||
key. Each line is of the form
|
||||
.TP
|
||||
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
|
||||
@@ -139,7 +140,7 @@ Host Key Files
|
||||
|
||||
Host key files are read at startup from a standard location, by default
|
||||
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
|
||||
/etc/dropbear/dropbear-ecdsa_host_key
|
||||
/etc/dropbear/dropbear_ecdsa_host_key
|
||||
or specified on the commandline with -r. These are of the form generated
|
||||
by dropbearkey. The -R option can be used to automatically generate keys
|
||||
in the default location - keys will be generated after startup when the first
|
||||
|
||||
@@ -39,9 +39,9 @@ or
|
||||
An existing Dropbear or OpenSSH private key file
|
||||
.TP
|
||||
.B output file
|
||||
The path to write the converted private key file
|
||||
The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
|
||||
.SH EXAMPLE
|
||||
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/dropbear_priv
|
||||
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.SH SEE ALSO
|
||||
|
||||
@@ -33,7 +33,7 @@ or
|
||||
.TP
|
||||
.B \-f \fIfile
|
||||
Write the secret key to the file
|
||||
.IR file .
|
||||
.IR file . For client authentication ~/.ssh/id_dropbear is loaded by default
|
||||
.TP
|
||||
.B \-s \fIbits
|
||||
Set the key size to
|
||||
|
||||
@@ -76,7 +76,8 @@ static void printhelp(char * progname) {
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
" ecdsa\n"
|
||||
#endif
|
||||
"-f filename Use filename for the secret key\n"
|
||||
"-f filename Use filename for the secret key.\n"
|
||||
" ~/.ssh/id_dropbear is recommended for client keys.\n"
|
||||
"-s bits Key size in bits, should be a multiple of 8 (optional)\n"
|
||||
#ifdef DROPBEAR_DSS
|
||||
" DSS has a fixed size of 1024 bits\n"
|
||||
|
||||
6
dss.c
6
dss.c
@@ -165,7 +165,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
DEF_MP_INT(val3);
|
||||
DEF_MP_INT(val4);
|
||||
char * string = NULL;
|
||||
int stringlen;
|
||||
unsigned int stringlen;
|
||||
|
||||
TRACE(("enter buf_dss_verify"))
|
||||
dropbear_assert(key != NULL);
|
||||
@@ -186,7 +186,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
/* create the signature - s' and r' are the received signatures in buf */
|
||||
/* w = (s')-1 mod q */
|
||||
/* let val1 = s' */
|
||||
bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
|
||||
bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
|
||||
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, s' >= q"))
|
||||
@@ -208,7 +208,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
|
||||
/* u2 = ((r')w) mod q */
|
||||
/* let val1 = r' */
|
||||
bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE);
|
||||
bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, r' >= q"))
|
||||
goto out;
|
||||
|
||||
6
dss.h
6
dss.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DSS_H_
|
||||
#define _DSS_H_
|
||||
#ifndef DROPBEAR_DSS_H_
|
||||
#define DROPBEAR_DSS_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
@@ -53,4 +53,4 @@ void dss_key_free(dropbear_dss_key *key);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
#endif /* _DSS_H_ */
|
||||
#endif /* DROPBEAR_DSS_H_ */
|
||||
|
||||
5
ecc.c
5
ecc.c
@@ -86,11 +86,6 @@ static int ecc_is_point(ecc_key *key)
|
||||
{
|
||||
mp_int *prime, *b, *t1, *t2;
|
||||
int err;
|
||||
|
||||
prime = m_malloc(sizeof(mp_int));
|
||||
b = m_malloc(sizeof(mp_int));
|
||||
t1 = m_malloc(sizeof(mp_int));
|
||||
t2 = m_malloc(sizeof(mp_int));
|
||||
|
||||
m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);
|
||||
|
||||
|
||||
8
ecc.h
8
ecc.h
@@ -1,5 +1,5 @@
|
||||
#ifndef _DROPBEAR_ECC_H
|
||||
#define _DROPBEAR_ECC_H
|
||||
#ifndef DROPBEAR_DROPBEAR_ECC_H
|
||||
#define DROPBEAR_DROPBEAR_ECC_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
@@ -12,7 +12,7 @@ struct dropbear_ecc_curve {
|
||||
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
|
||||
const ltc_ecc_set_type *dp; /* curve domain parameters */
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
const unsigned char *name;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp256;
|
||||
@@ -33,4 +33,4 @@ mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _DROPBEAR_ECC_H */
|
||||
#endif /* DROPBEAR_DROPBEAR_ECC_H */
|
||||
|
||||
15
ecdsa.c
15
ecdsa.c
@@ -83,9 +83,9 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
|
||||
ecc_key *new_key = NULL;
|
||||
|
||||
/* string "ecdsa-sha2-[identifier]" */
|
||||
key_ident = buf_getstring(buf, &key_ident_len);
|
||||
key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
|
||||
/* string "[identifier]" */
|
||||
identifier = buf_getstring(buf, &identifier_len);
|
||||
identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
|
||||
|
||||
if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
|
||||
TRACE(("Bad identifier lengths"))
|
||||
@@ -131,6 +131,7 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
|
||||
|
||||
if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
|
||||
ecc_free(new_key);
|
||||
m_free(new_key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -139,10 +140,10 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
|
||||
|
||||
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
|
||||
struct dropbear_ecc_curve *curve = NULL;
|
||||
unsigned char key_ident[30];
|
||||
char key_ident[30];
|
||||
|
||||
curve = curve_for_dp(key->dp);
|
||||
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
buf_putstring(buf, key_ident, strlen(key_ident));
|
||||
buf_putstring(buf, curve->name, strlen(curve->name));
|
||||
buf_put_ecc_raw_pubkey_string(buf, key);
|
||||
@@ -160,7 +161,7 @@ void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
hash_state hs;
|
||||
unsigned char hash[64];
|
||||
void *e = NULL, *p = NULL, *s = NULL, *r;
|
||||
unsigned char key_ident[30];
|
||||
char key_ident[30];
|
||||
buffer *sigbuf = NULL;
|
||||
|
||||
TRACE(("buf_put_ecdsa_sign"))
|
||||
@@ -221,7 +222,7 @@ void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
}
|
||||
}
|
||||
|
||||
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
buf_putstring(buf, key_ident, strlen(key_ident));
|
||||
/* enough for nistp521 */
|
||||
sigbuf = buf_new(200);
|
||||
@@ -408,7 +409,7 @@ int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
out:
|
||||
ltc_ecc_del_point(mG);
|
||||
ltc_ecc_del_point(mQ);
|
||||
mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
|
||||
ltc_deinit_multi(r, s, v, w, u1, u2, p, e, m, NULL);
|
||||
if (mp != NULL) {
|
||||
ltc_mp.montgomery_deinit(mp);
|
||||
}
|
||||
|
||||
6
ecdsa.h
6
ecdsa.h
@@ -1,5 +1,5 @@
|
||||
#ifndef _ECDSA_H_
|
||||
#define _ECDSA_H_
|
||||
#ifndef DROPBEAR_ECDSA_H_
|
||||
#define DROPBEAR_ECDSA_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
@@ -32,4 +32,4 @@ int signkey_is_ecdsa(enum signkey_type type);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ECDSA_H_ */
|
||||
#endif /* DROPBEAR_ECDSA_H_ */
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#ifndef _FAKE_RFC2553_H
|
||||
#define _FAKE_RFC2553_H
|
||||
#ifndef DROPBEAR_FAKE_RFC2553_H
|
||||
#define DROPBEAR_FAKE_RFC2553_H
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
2
gendss.c
2
gendss.c
@@ -67,7 +67,7 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
|
||||
static void getq(dropbear_dss_key *key) {
|
||||
|
||||
char buf[QSIZE];
|
||||
unsigned char buf[QSIZE];
|
||||
|
||||
/* 160 bit prime */
|
||||
genrandom(buf, QSIZE);
|
||||
|
||||
6
gendss.h
6
gendss.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _GENDSS_H_
|
||||
#define _GENDSS_H_
|
||||
#ifndef DROPBEAR_GENDSS_H_
|
||||
#define DROPBEAR_GENDSS_H_
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
@@ -33,4 +33,4 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
#endif /* _GENDSS_H_ */
|
||||
#endif /* DROPBEAR_GENDSS_H_ */
|
||||
|
||||
6
genrsa.h
6
genrsa.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _GENRSA_H_
|
||||
#define _GENRSA_H_
|
||||
#ifndef DROPBEAR_GENRSA_H_
|
||||
#define DROPBEAR_GENRSA_H_
|
||||
|
||||
#include "rsa.h"
|
||||
|
||||
@@ -33,4 +33,4 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
#endif /* _GENRSA_H_ */
|
||||
#endif /* DROPBEAR_GENRSA_H_ */
|
||||
|
||||
@@ -41,6 +41,9 @@ static int buf_writefile(buffer * buf, const char * filename) {
|
||||
|
||||
out:
|
||||
if (fd >= 0) {
|
||||
if (fsync(fd) != 0) {
|
||||
dropbear_log(LOG_ERR, "fsync of %s failed: %s", filename, strerror(errno));
|
||||
}
|
||||
m_close(fd);
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _GENSIGNKEY_H
|
||||
#define _GENSIGNKEY_H
|
||||
#ifndef DROPBEAR_GENSIGNKEY_H
|
||||
#define DROPBEAR_GENSIGNKEY_H
|
||||
|
||||
#include "signkey.h"
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _INCLUDES_H_
|
||||
#define _INCLUDES_H_
|
||||
#ifndef DROPBEAR_INCLUDES_H_
|
||||
#define DROPBEAR_INCLUDES_H_
|
||||
|
||||
|
||||
#include "config.h"
|
||||
@@ -177,4 +177,4 @@ typedef u_int32_t uint32_t;
|
||||
# define UNUSED(x) x
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDES_H_ */
|
||||
#endif /* DROPBEAR_INCLUDES_H_ */
|
||||
|
||||
6
kex.h
6
kex.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _KEX_H_
|
||||
#define _KEX_H_
|
||||
#ifndef DROPBEAR_KEX_H_
|
||||
#define DROPBEAR_KEX_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
@@ -113,4 +113,4 @@ int curve25519_donna(unsigned char *out, const unsigned char *secret, const unsi
|
||||
|
||||
#define MAX_KEXHASHBUF 2000
|
||||
|
||||
#endif /* _KEX_H_ */
|
||||
#endif /* DROPBEAR_KEX_H_ */
|
||||
|
||||
35
keyimport.c
35
keyimport.c
@@ -193,7 +193,7 @@ out:
|
||||
static void base64_encode_fp(FILE * fp, unsigned char *data,
|
||||
int datalen, int cpl)
|
||||
{
|
||||
char out[100];
|
||||
unsigned char out[100];
|
||||
int n;
|
||||
unsigned long outlen;
|
||||
int rawcpl;
|
||||
@@ -445,7 +445,7 @@ static struct openssh_key *load_openssh_key(const char *filename)
|
||||
ret->keyblob_size);
|
||||
}
|
||||
outlen = ret->keyblob_size - ret->keyblob_len;
|
||||
if (base64_decode(buffer, len,
|
||||
if (base64_decode((const unsigned char *)buffer, len,
|
||||
ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
|
||||
errmsg = "Error decoding base64";
|
||||
goto error;
|
||||
@@ -464,17 +464,16 @@ static struct openssh_key *load_openssh_key(const char *filename)
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
m_burn(buffer, sizeof(buffer));
|
||||
return ret;
|
||||
|
||||
error:
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
m_burn(buffer, sizeof(buffer));
|
||||
if (ret) {
|
||||
if (ret->keyblob) {
|
||||
memset(ret->keyblob, 0, ret->keyblob_size);
|
||||
m_burn(ret->keyblob, ret->keyblob_size);
|
||||
m_free(ret->keyblob);
|
||||
}
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
m_free(ret);
|
||||
}
|
||||
if (fp) {
|
||||
@@ -494,9 +493,8 @@ static int openssh_encrypted(const char *filename)
|
||||
if (!key)
|
||||
return 0;
|
||||
ret = key->encrypted;
|
||||
memset(key->keyblob, 0, key->keyblob_size);
|
||||
m_burn(key->keyblob, key->keyblob_size);
|
||||
m_free(key->keyblob);
|
||||
memset(&key, 0, sizeof(key));
|
||||
m_free(key);
|
||||
return ret;
|
||||
}
|
||||
@@ -509,7 +507,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
int i, num_integers = 0;
|
||||
sign_key *retval = NULL;
|
||||
char *errmsg;
|
||||
char *modptr = NULL;
|
||||
unsigned char *modptr = NULL;
|
||||
int modlen = -9999;
|
||||
enum signkey_type type;
|
||||
|
||||
@@ -627,7 +625,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
|
||||
if (i == 0) {
|
||||
/* First integer is a version indicator */
|
||||
int expected;
|
||||
int expected = -1;
|
||||
switch (key->type) {
|
||||
case OSSH_RSA:
|
||||
case OSSH_DSA:
|
||||
@@ -648,12 +646,12 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
*/
|
||||
if (i == 1) {
|
||||
/* Save the details for after we deal with number 2. */
|
||||
modptr = (char *)p;
|
||||
modptr = p;
|
||||
modlen = len;
|
||||
} else if (i >= 2 && i <= 5) {
|
||||
buf_putstring(blobbuf, p, len);
|
||||
buf_putstring(blobbuf, (const char*)p, len);
|
||||
if (i == 2) {
|
||||
buf_putstring(blobbuf, modptr, modlen);
|
||||
buf_putstring(blobbuf, (const char*)modptr, modlen);
|
||||
}
|
||||
}
|
||||
} else if (key->type == OSSH_DSA) {
|
||||
@@ -661,7 +659,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
* OpenSSH key order is p, q, g, y, x,
|
||||
* we want the same.
|
||||
*/
|
||||
buf_putstring(blobbuf, p, len);
|
||||
buf_putstring(blobbuf, (const char*)p, len);
|
||||
}
|
||||
|
||||
/* Skip past the number. */
|
||||
@@ -810,7 +808,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
}
|
||||
m_burn(key->keyblob, key->keyblob_size);
|
||||
m_free(key->keyblob);
|
||||
m_burn(key, sizeof(key));
|
||||
m_burn(key, sizeof(*key));
|
||||
m_free(key);
|
||||
if (errmsg) {
|
||||
fprintf(stderr, "Error: %s\n", errmsg);
|
||||
@@ -826,7 +824,7 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
unsigned char *outblob = NULL;
|
||||
int outlen = -9999;
|
||||
struct mpint_pos numbers[9];
|
||||
int nnumbers = -1, pos, len, seqlen, i;
|
||||
int nnumbers = -1, pos = 0, len = 0, seqlen, i;
|
||||
char *header = NULL, *footer = NULL;
|
||||
char zero[1];
|
||||
int ret = 0;
|
||||
@@ -1045,7 +1043,8 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
int curve_oid_len = 0;
|
||||
const void* curve_oid = NULL;
|
||||
unsigned long pubkey_size = 2*curve_size+1;
|
||||
unsigned int k_size;
|
||||
int k_size;
|
||||
int err = 0;
|
||||
|
||||
/* version. less than 10 bytes */
|
||||
buf_incrwritepos(seq_buf,
|
||||
@@ -1091,7 +1090,7 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
|
||||
buf_putbyte(seq_buf, 0);
|
||||
int err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
|
||||
err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
|
||||
if (err != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _KEYIMPORT_H_
|
||||
#define _KEYIMPORT_H_
|
||||
#ifndef DROPBEAR_KEYIMPORT_H_
|
||||
#define DROPBEAR_KEYIMPORT_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -39,4 +39,4 @@ int import_write(const char *filename, sign_key *key, char *passphrase,
|
||||
sign_key *import_read(const char *filename, char *passphrase, int filetype);
|
||||
int import_encrypted(const char* filename, int filetype);
|
||||
|
||||
#endif /* _KEYIMPORT_H_ */
|
||||
#endif /* DROPBEAR_KEYIMPORT_H_ */
|
||||
|
||||
@@ -122,9 +122,10 @@ static ulong32 setup_mix2(ulong32 temp)
|
||||
*/
|
||||
int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
|
||||
{
|
||||
int i, j;
|
||||
int i;
|
||||
ulong32 temp, *rk;
|
||||
#ifndef ENCRYPT_ONLY
|
||||
int j;
|
||||
ulong32 *rrk;
|
||||
#endif
|
||||
LTC_ARGCHK(key != NULL);
|
||||
@@ -148,7 +149,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
LOAD32H(rk[2], key + 8);
|
||||
LOAD32H(rk[3], key + 12);
|
||||
if (keylen == 16) {
|
||||
#ifndef ENCRYPT_ONLY
|
||||
j = 44;
|
||||
#endif
|
||||
for (;;) {
|
||||
temp = rk[3];
|
||||
rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i];
|
||||
@@ -161,7 +164,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
rk += 4;
|
||||
}
|
||||
} else if (keylen == 24) {
|
||||
#ifndef ENCRYPT_ONLY
|
||||
j = 52;
|
||||
#endif
|
||||
LOAD32H(rk[4], key + 16);
|
||||
LOAD32H(rk[5], key + 20);
|
||||
for (;;) {
|
||||
@@ -182,7 +187,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
|
||||
rk += 6;
|
||||
}
|
||||
} else if (keylen == 32) {
|
||||
#ifndef ENCRYPT_ONLY
|
||||
j = 60;
|
||||
#endif
|
||||
LOAD32H(rk[4], key + 16);
|
||||
LOAD32H(rk[5], key + 20);
|
||||
LOAD32H(rk[6], key + 24);
|
||||
@@ -728,6 +735,7 @@ int ECB_TEST(void)
|
||||
*/
|
||||
void ECB_DONE(symmetric_key *skey)
|
||||
{
|
||||
(void)skey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1871,6 +1871,7 @@ void des_done(symmetric_key *skey)
|
||||
*/
|
||||
void des3_done(symmetric_key *skey)
|
||||
{
|
||||
(void)skey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -684,6 +684,7 @@ int twofish_test(void)
|
||||
*/
|
||||
void twofish_done(symmetric_key *skey)
|
||||
{
|
||||
(void)skey;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
(void)hash; (void)fname; (void)out; (void)outlen;
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
FILE *in;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
(void)hash; (void)in; (void)out; (void)outlen;
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
hash_state md;
|
||||
|
||||
@@ -4,8 +4,16 @@
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
/* portability macros for compiler-specific code attributes */
|
||||
#ifdef __GNUC__
|
||||
#define ATTRIB_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
#define ATTRIB_NORETURN
|
||||
#endif
|
||||
|
||||
|
||||
/* this is the default LibTomCrypt macro */
|
||||
void crypt_argchk(char *v, char *s, int d);
|
||||
void crypt_argchk(char *v, char *s, int d) ATTRIB_NORETURN;
|
||||
#define LTC_ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); }
|
||||
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
*/
|
||||
int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
unsigned char *buf, *isha;
|
||||
unsigned char buf[MAXBLOCKSIZE], isha[MAXBLOCKSIZE];
|
||||
unsigned long hashsize, i;
|
||||
int hash, err;
|
||||
|
||||
@@ -44,19 +44,6 @@ int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
|
||||
/* get the hash message digest size */
|
||||
hashsize = hash_descriptor[hash].hashsize;
|
||||
|
||||
/* allocate buffers */
|
||||
buf = XMALLOC(HMAC_BLOCKSIZE);
|
||||
isha = XMALLOC(hashsize);
|
||||
if (buf == NULL || isha == NULL) {
|
||||
if (buf != NULL) {
|
||||
XFREE(buf);
|
||||
}
|
||||
if (isha != NULL) {
|
||||
XFREE(isha);
|
||||
}
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
|
||||
/* Get the hash of the first HMAC vector plus the data */
|
||||
if ((err = hash_descriptor[hash].done(&hmac->md, isha)) != CRYPT_OK) {
|
||||
goto LBL_ERR;
|
||||
@@ -96,9 +83,6 @@ LBL_ERR:
|
||||
zeromem(hmac, sizeof(*hmac));
|
||||
#endif
|
||||
|
||||
XFREE(isha);
|
||||
XFREE(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ int hmac_file(int hash, const char *fname,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
#ifdef LTC_NO_FILE
|
||||
(void)hash; (void)fname; (void)key; (void)keylen; (void)out; (void)outlen;
|
||||
return CRYPT_NOP;
|
||||
#else
|
||||
hmac_state hmac;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
*/
|
||||
int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen)
|
||||
{
|
||||
unsigned char *buf;
|
||||
unsigned char buf[MAXBLOCKSIZE];
|
||||
unsigned long hashsize;
|
||||
unsigned long i, z;
|
||||
int err;
|
||||
@@ -49,16 +49,9 @@ int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned lon
|
||||
return CRYPT_INVALID_KEYSIZE;
|
||||
}
|
||||
|
||||
/* allocate ram for buf */
|
||||
buf = XMALLOC(HMAC_BLOCKSIZE);
|
||||
if (buf == NULL) {
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
|
||||
/* allocate memory for key */
|
||||
hmac->key = XMALLOC(HMAC_BLOCKSIZE);
|
||||
if (hmac->key == NULL) {
|
||||
XFREE(buf);
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
|
||||
@@ -101,7 +94,6 @@ done:
|
||||
zeromem(buf, HMAC_BLOCKSIZE);
|
||||
#endif
|
||||
|
||||
XFREE(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ void crypt_argchk(char *v, char *s, int d)
|
||||
{
|
||||
fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
|
||||
v, d, s);
|
||||
(void)raise(SIGABRT);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
|
||||
int i, j, err;
|
||||
void *mu, *mp;
|
||||
unsigned long buf;
|
||||
int first, bitbuf, bitcpy, bitcnt, mode, digidx;
|
||||
int bitcnt, mode, digidx;
|
||||
|
||||
LTC_ARGCHK(k != NULL);
|
||||
LTC_ARGCHK(G != NULL);
|
||||
@@ -98,8 +98,6 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
|
||||
bitcnt = 1;
|
||||
buf = 0;
|
||||
digidx = mp_get_digit_count(k) - 1;
|
||||
bitcpy = bitbuf = 0;
|
||||
first = 1;
|
||||
|
||||
/* perform ops */
|
||||
for (;;) {
|
||||
|
||||
6
list.h
6
list.h
@@ -1,5 +1,5 @@
|
||||
#ifndef _DROPBEAR_LIST_H
|
||||
#define _DROPBEAR_LIST_H
|
||||
#ifndef DROPBEAR_DROPBEAR_LIST_H
|
||||
#define DROPBEAR_DROPBEAR_LIST_H
|
||||
|
||||
struct _m_list;
|
||||
|
||||
@@ -25,4 +25,4 @@ void list_append(m_list *list, void *item);
|
||||
void * list_remove(m_list_elem *elem);
|
||||
|
||||
|
||||
#endif /* _DROPBEAR_LIST_H */
|
||||
#endif /* DROPBEAR_DROPBEAR_LIST_H */
|
||||
|
||||
11
listener.c
11
listener.c
@@ -161,5 +161,14 @@ void remove_listener(struct Listener* listener) {
|
||||
}
|
||||
ses.listeners[listener->index] = NULL;
|
||||
m_free(listener);
|
||||
|
||||
}
|
||||
|
||||
void remove_all_listeners(void) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < ses.listensize; i++) {
|
||||
if (ses.listeners[i]) {
|
||||
remove_listener(ses.listeners[i]);
|
||||
}
|
||||
}
|
||||
m_free(ses.listeners);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _LISTENER_H
|
||||
#define _LISTENER_H
|
||||
#ifndef DROPBEAR_LISTENER_H
|
||||
#define DROPBEAR_LISTENER_H
|
||||
|
||||
#define MAX_LISTENERS 20
|
||||
#define LISTENER_EXTEND_SIZE 1
|
||||
@@ -60,4 +60,6 @@ struct Listener * get_listener(int type, void* typedata,
|
||||
|
||||
void remove_listener(struct Listener* listener);
|
||||
|
||||
#endif /* _LISTENER_H */
|
||||
void remove_all_listeners(void);
|
||||
|
||||
#endif /* DROPBEAR_LISTENER_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _HAVE_LOGINREC_H_
|
||||
#define _HAVE_LOGINREC_H_
|
||||
#ifndef DROPBEAR_HAVE_LOGINREC_H_
|
||||
#define DROPBEAR_HAVE_LOGINREC_H_
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Andre Lucas. All rights reserved.
|
||||
@@ -182,4 +182,4 @@ char *line_fullname(char *dst, const char *src, size_t dstsize);
|
||||
char *line_stripname(char *dst, const char *src, size_t dstsize);
|
||||
char *line_abbrevname(char *dst, const char *src, size_t dstsize);
|
||||
|
||||
#endif /* _HAVE_LOGINREC_H_ */
|
||||
#endif /* DROPBEAR_HAVE_LOGINREC_H_ */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _LTC_PRNG_H_DROPBEAR
|
||||
#define _LTC_PRNG_H_DROPBEAR
|
||||
#ifndef DROPBEAR_LTC_PRNG_H_DROPBEAR
|
||||
#define DROPBEAR_LTC_PRNG_H_DROPBEAR
|
||||
|
||||
#include "options.h"
|
||||
#include "includes.h"
|
||||
@@ -10,4 +10,4 @@ extern const struct ltc_prng_descriptor dropbear_prng_desc;
|
||||
|
||||
#endif /* DROPBEAR_LTC_PRNG */
|
||||
|
||||
#endif /* _LTC_PRNG_H_DROPBEAR */
|
||||
#endif /* DROPBEAR_LTC_PRNG_H_DROPBEAR */
|
||||
|
||||
562
netio.c
Normal file
562
netio.c
Normal file
@@ -0,0 +1,562 @@
|
||||
#include "netio.h"
|
||||
#include "list.h"
|
||||
#include "dbutil.h"
|
||||
#include "session.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct dropbear_progress_connection {
|
||||
struct addrinfo *res;
|
||||
struct addrinfo *res_iter;
|
||||
|
||||
char *remotehost, *remoteport; /* For error reporting */
|
||||
|
||||
connect_callback cb;
|
||||
void *cb_data;
|
||||
|
||||
struct Queue *writequeue; /* A queue of encrypted packets to send with TCP fastopen,
|
||||
or NULL. */
|
||||
|
||||
int sock;
|
||||
|
||||
char* errstring;
|
||||
};
|
||||
|
||||
/* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
|
||||
Does not close sockets */
|
||||
static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) {
|
||||
if (c->res) {
|
||||
freeaddrinfo(c->res);
|
||||
}
|
||||
m_free(c->remotehost);
|
||||
m_free(c->remoteport);
|
||||
m_free(c->errstring);
|
||||
m_free(c);
|
||||
|
||||
if (iter) {
|
||||
list_remove(iter);
|
||||
}
|
||||
}
|
||||
|
||||
static void cancel_callback(int result, int sock, void* UNUSED(data), const char* UNUSED(errstring)) {
|
||||
if (result == DROPBEAR_SUCCESS)
|
||||
{
|
||||
m_close(sock);
|
||||
}
|
||||
}
|
||||
|
||||
void cancel_connect(struct dropbear_progress_connection *c) {
|
||||
c->cb = cancel_callback;
|
||||
c->cb_data = NULL;
|
||||
}
|
||||
|
||||
static void connect_try_next(struct dropbear_progress_connection *c) {
|
||||
struct addrinfo *r;
|
||||
int res = 0;
|
||||
int fastopen = 0;
|
||||
#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
|
||||
struct msghdr message;
|
||||
#endif
|
||||
|
||||
for (r = c->res_iter; r; r = r->ai_next)
|
||||
{
|
||||
dropbear_assert(c->sock == -1);
|
||||
|
||||
c->sock = socket(c->res_iter->ai_family, c->res_iter->ai_socktype, c->res_iter->ai_protocol);
|
||||
if (c->sock < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, c->sock);
|
||||
set_sock_nodelay(c->sock);
|
||||
setnonblocking(c->sock);
|
||||
|
||||
#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
|
||||
fastopen = (c->writequeue != NULL);
|
||||
|
||||
if (fastopen) {
|
||||
memset(&message, 0x0, sizeof(message));
|
||||
message.msg_name = r->ai_addr;
|
||||
message.msg_namelen = r->ai_addrlen;
|
||||
/* 6 is arbitrary, enough to hold initial packets */
|
||||
unsigned int iovlen = 6; /* Linux msg_iovlen is a size_t */
|
||||
struct iovec iov[6];
|
||||
packet_queue_to_iovec(c->writequeue, iov, &iovlen);
|
||||
message.msg_iov = iov;
|
||||
message.msg_iovlen = iovlen;
|
||||
res = sendmsg(c->sock, &message, MSG_FASTOPEN);
|
||||
/* Returns EINPROGRESS if FASTOPEN wasn't available */
|
||||
if (res < 0) {
|
||||
if (errno != EINPROGRESS) {
|
||||
m_free(c->errstring);
|
||||
c->errstring = m_strdup(strerror(errno));
|
||||
/* Not entirely sure which kind of errors are normal - 2.6.32 seems to
|
||||
return EPIPE for any (nonblocking?) sendmsg(). just fall back */
|
||||
TRACE(("sendmsg tcp_fastopen failed, falling back. %s", strerror(errno)));
|
||||
/* No kernel MSG_FASTOPEN support. Fall back below */
|
||||
fastopen = 0;
|
||||
/* Set to NULL to avoid trying again */
|
||||
c->writequeue = NULL;
|
||||
}
|
||||
} else {
|
||||
packet_queue_consume(c->writequeue, res);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Normal connect(), used as fallback for TCP fastopen too */
|
||||
if (!fastopen) {
|
||||
res = connect(c->sock, r->ai_addr, r->ai_addrlen);
|
||||
}
|
||||
|
||||
if (res < 0 && errno != EINPROGRESS) {
|
||||
/* failure */
|
||||
m_free(c->errstring);
|
||||
c->errstring = m_strdup(strerror(errno));
|
||||
close(c->sock);
|
||||
c->sock = -1;
|
||||
continue;
|
||||
} else {
|
||||
/* new connection was successful, wait for it to complete */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (r) {
|
||||
c->res_iter = r->ai_next;
|
||||
} else {
|
||||
c->res_iter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Connect via TCP to a host. */
|
||||
struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport,
|
||||
connect_callback cb, void* cb_data)
|
||||
{
|
||||
struct dropbear_progress_connection *c = NULL;
|
||||
int err;
|
||||
struct addrinfo hints;
|
||||
|
||||
c = m_malloc(sizeof(*c));
|
||||
c->remotehost = m_strdup(remotehost);
|
||||
c->remoteport = m_strdup(remoteport);
|
||||
c->sock = -1;
|
||||
c->cb = cb;
|
||||
c->cb_data = cb_data;
|
||||
|
||||
list_append(&ses.conn_pending, c);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
err = getaddrinfo(remotehost, remoteport, &hints, &c->res);
|
||||
if (err) {
|
||||
int len;
|
||||
len = 100 + strlen(gai_strerror(err));
|
||||
c->errstring = (char*)m_malloc(len);
|
||||
snprintf(c->errstring, len, "Error resolving '%s' port '%s'. %s",
|
||||
remotehost, remoteport, gai_strerror(err));
|
||||
TRACE(("Error resolving: %s", gai_strerror(err)))
|
||||
} else {
|
||||
c->res_iter = c->res;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void remove_connect_pending() {
|
||||
while (ses.conn_pending.first) {
|
||||
struct dropbear_progress_connection *c = ses.conn_pending.first->item;
|
||||
remove_connect(c, ses.conn_pending.first);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void set_connect_fds(fd_set *writefd) {
|
||||
m_list_elem *iter;
|
||||
TRACE(("enter handle_connect_fds"))
|
||||
for (iter = ses.conn_pending.first; iter; iter = iter->next) {
|
||||
struct dropbear_progress_connection *c = iter->item;
|
||||
/* Set one going */
|
||||
while (c->res_iter && c->sock < 0)
|
||||
{
|
||||
connect_try_next(c);
|
||||
}
|
||||
if (c->sock >= 0) {
|
||||
FD_SET(c->sock, writefd);
|
||||
} else {
|
||||
m_list_elem *remove_iter;
|
||||
/* Final failure */
|
||||
if (!c->errstring) {
|
||||
c->errstring = m_strdup("unexpected failure");
|
||||
}
|
||||
c->cb(DROPBEAR_FAILURE, -1, c->cb_data, c->errstring);
|
||||
/* Safely remove without invalidating iter */
|
||||
remove_iter = iter;
|
||||
iter = iter->prev;
|
||||
remove_connect(c, remove_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_connect_fds(fd_set *writefd) {
|
||||
m_list_elem *iter;
|
||||
TRACE(("enter handle_connect_fds"))
|
||||
for (iter = ses.conn_pending.first; iter; iter = iter->next) {
|
||||
int val;
|
||||
socklen_t vallen = sizeof(val);
|
||||
struct dropbear_progress_connection *c = iter->item;
|
||||
|
||||
if (c->sock < 0 || !FD_ISSET(c->sock, writefd)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE(("handling %s port %s socket %d", c->remotehost, c->remoteport, c->sock));
|
||||
|
||||
if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &val, &vallen) != 0) {
|
||||
TRACE(("handle_connect_fds getsockopt(%d) SO_ERROR failed: %s", c->sock, strerror(errno)))
|
||||
/* This isn't expected to happen - Unix has surprises though, continue gracefully. */
|
||||
m_close(c->sock);
|
||||
c->sock = -1;
|
||||
} else if (val != 0) {
|
||||
/* Connect failed */
|
||||
TRACE(("connect to %s port %s failed.", c->remotehost, c->remoteport))
|
||||
m_close(c->sock);
|
||||
c->sock = -1;
|
||||
|
||||
m_free(c->errstring);
|
||||
c->errstring = m_strdup(strerror(val));
|
||||
} else {
|
||||
/* New connection has been established */
|
||||
c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, NULL);
|
||||
remove_connect(c, iter);
|
||||
TRACE(("leave handle_connect_fds - success"))
|
||||
/* Must return here - remove_connect() invalidates iter */
|
||||
return;
|
||||
}
|
||||
}
|
||||
TRACE(("leave handle_connect_fds - end iter"))
|
||||
}
|
||||
|
||||
void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) {
|
||||
c->writequeue = writequeue;
|
||||
}
|
||||
|
||||
void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count) {
|
||||
struct Link *l;
|
||||
unsigned int i;
|
||||
int len;
|
||||
buffer *writebuf;
|
||||
|
||||
#ifndef IOV_MAX
|
||||
#define IOV_MAX UIO_MAXIOV
|
||||
#endif
|
||||
|
||||
*iov_count = MIN(MIN(queue->count, IOV_MAX), *iov_count);
|
||||
|
||||
for (l = queue->head, i = 0; i < *iov_count; l = l->link, i++)
|
||||
{
|
||||
writebuf = (buffer*)l->item;
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
dropbear_assert(len > 0);
|
||||
TRACE2(("write_packet writev #%d type %d len %d/%d", i, writebuf->data[writebuf->len-1],
|
||||
len, writebuf->len-1))
|
||||
iov[i].iov_base = buf_getptr(writebuf, len);
|
||||
iov[i].iov_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
void packet_queue_consume(struct Queue *queue, ssize_t written) {
|
||||
buffer *writebuf;
|
||||
int len;
|
||||
while (written > 0) {
|
||||
writebuf = (buffer*)examine(queue);
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
if (len > written) {
|
||||
/* partial buffer write */
|
||||
buf_incrpos(writebuf, written);
|
||||
written = 0;
|
||||
} else {
|
||||
written -= len;
|
||||
dequeue(queue);
|
||||
buf_free(writebuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_sock_nodelay(int sock) {
|
||||
int val;
|
||||
|
||||
/* disable nagle */
|
||||
val = 1;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
|
||||
void set_listen_fast_open(int sock) {
|
||||
int qlen = MAX(MAX_UNAUTH_PER_IP, 5);
|
||||
if (setsockopt(sock, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) != 0) {
|
||||
TRACE(("set_listen_fast_open failed for socket %d: %s", sock, strerror(errno)))
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio) {
|
||||
|
||||
int rc;
|
||||
#ifdef IPTOS_LOWDELAY
|
||||
int iptos_val = 0;
|
||||
#endif
|
||||
#ifdef SO_PRIORITY
|
||||
int so_prio_val = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/* Don't log ENOTSOCK errors so that this can harmlessly be called
|
||||
* on a client '-J' proxy pipe */
|
||||
|
||||
/* set the TOS bit for either ipv4 or ipv6 */
|
||||
#ifdef IPTOS_LOWDELAY
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
iptos_val = IPTOS_LOWDELAY;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
iptos_val = IPTOS_THROUGHPUT;
|
||||
}
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
|
||||
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0 && errno != ENOTSOCK) {
|
||||
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
|
||||
if (rc < 0 && errno != ENOTSOCK) {
|
||||
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SO_PRIORITY
|
||||
if (prio == DROPBEAR_PRIO_LOWDELAY) {
|
||||
so_prio_val = TC_PRIO_INTERACTIVE;
|
||||
} else if (prio == DROPBEAR_PRIO_BULK) {
|
||||
so_prio_val = TC_PRIO_BULK;
|
||||
}
|
||||
/* linux specific, sets QoS class. see tc-prio(8) */
|
||||
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
|
||||
if (rc < 0 && errno != ENOTSOCK)
|
||||
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
|
||||
strerror(errno));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Listen on address:port.
|
||||
* Special cases are address of "" listening on everything,
|
||||
* and address of NULL listening on localhost only.
|
||||
* Returns the number of sockets bound on success, or -1 on failure. On
|
||||
* failure, if errstring wasn't NULL, it'll be a newly malloced error
|
||||
* string.*/
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
|
||||
|
||||
struct addrinfo hints, *res = NULL, *res0 = NULL;
|
||||
int err;
|
||||
unsigned int nsock;
|
||||
struct linger linger;
|
||||
int val;
|
||||
int sock;
|
||||
|
||||
TRACE(("enter dropbear_listen"))
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
/* for calling getaddrinfo:
|
||||
address == NULL and !AI_PASSIVE: local loopback
|
||||
address == NULL and AI_PASSIVE: all interfaces
|
||||
address != NULL: whatever the address says */
|
||||
if (!address) {
|
||||
TRACE(("dropbear_listen: local loopback"))
|
||||
} else {
|
||||
if (address[0] == '\0') {
|
||||
TRACE(("dropbear_listen: all interfaces"))
|
||||
address = NULL;
|
||||
}
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
}
|
||||
err = getaddrinfo(address, port, &hints, &res0);
|
||||
|
||||
if (err) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(gai_strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
|
||||
}
|
||||
if (res0) {
|
||||
freeaddrinfo(res0);
|
||||
res0 = NULL;
|
||||
}
|
||||
TRACE(("leave dropbear_listen: failed resolving"))
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
nsock = 0;
|
||||
for (res = res0; res != NULL && nsock < sockcount;
|
||||
res = res->ai_next) {
|
||||
|
||||
/* Get a socket */
|
||||
socks[nsock] = socket(res->ai_family, res->ai_socktype,
|
||||
res->ai_protocol);
|
||||
|
||||
sock = socks[nsock]; /* For clarity */
|
||||
|
||||
if (sock < 0) {
|
||||
err = errno;
|
||||
TRACE(("socket() failed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Various useful socket options */
|
||||
val = 1;
|
||||
/* set to reuse, quick timeout */
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 5;
|
||||
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
|
||||
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||
if (res->ai_family == AF_INET6) {
|
||||
int on = 1;
|
||||
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&on, sizeof(on)) == -1) {
|
||||
dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
set_sock_nodelay(sock);
|
||||
|
||||
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("bind(%s) failed", port))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
|
||||
err = errno;
|
||||
close(sock);
|
||||
TRACE(("listen() failed"))
|
||||
continue;
|
||||
}
|
||||
|
||||
*maxfd = MAX(*maxfd, sock);
|
||||
|
||||
nsock++;
|
||||
}
|
||||
|
||||
if (res0) {
|
||||
freeaddrinfo(res0);
|
||||
res0 = NULL;
|
||||
}
|
||||
|
||||
if (nsock == 0) {
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
int len;
|
||||
len = 20 + strlen(strerror(err));
|
||||
*errstring = (char*)m_malloc(len);
|
||||
snprintf(*errstring, len, "Error listening: %s", strerror(err));
|
||||
}
|
||||
TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
|
||||
return nsock;
|
||||
}
|
||||
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (local_host || local_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, local_host, local_port, host_lookup);
|
||||
}
|
||||
if (remote_host || remote_port) {
|
||||
addrlen = sizeof(addr);
|
||||
if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
|
||||
dropbear_exit("Failed socket address: %s", strerror(errno));
|
||||
}
|
||||
getaddrstring(&addr, remote_host, remote_port, host_lookup);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a string representation of the socket address passed. The return
|
||||
* value is allocated with malloc() */
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port,
|
||||
int host_lookup) {
|
||||
|
||||
char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
|
||||
unsigned int len;
|
||||
int ret;
|
||||
|
||||
int flags = NI_NUMERICSERV | NI_NUMERICHOST;
|
||||
|
||||
#ifndef DO_HOST_LOOKUP
|
||||
host_lookup = 0;
|
||||
#endif
|
||||
|
||||
if (host_lookup) {
|
||||
flags = NI_NUMERICSERV;
|
||||
}
|
||||
|
||||
len = sizeof(struct sockaddr_storage);
|
||||
/* Some platforms such as Solaris 8 require that len is the length
|
||||
* of the specific structure. Some older linux systems (glibc 2.1.3
|
||||
* such as debian potato) have sockaddr_storage.__ss_family instead
|
||||
* but we'll ignore them */
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
|
||||
if (addr->ss_family == AF_INET) {
|
||||
len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
if (addr->ss_family == AF_INET6) {
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
|
||||
serv, sizeof(serv)-1, flags);
|
||||
|
||||
if (ret != 0) {
|
||||
if (host_lookup) {
|
||||
/* On some systems (Darwin does it) we get EINTR from getnameinfo
|
||||
* somehow. Eew. So we'll just return the IP, since that doesn't seem
|
||||
* to exhibit that behaviour. */
|
||||
getaddrstring(addr, ret_host, ret_port, 0);
|
||||
return;
|
||||
} else {
|
||||
/* if we can't do a numeric lookup, something's gone terribly wrong */
|
||||
dropbear_exit("Failed lookup: %s", gai_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_host) {
|
||||
*ret_host = m_strdup(host);
|
||||
}
|
||||
if (ret_port) {
|
||||
*ret_port = m_strdup(serv);
|
||||
}
|
||||
}
|
||||
|
||||
64
netio.h
Normal file
64
netio.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef DROPBEAR_NETIO_H
|
||||
#define DROPBEAR_NETIO_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "queue.h"
|
||||
|
||||
enum dropbear_prio {
|
||||
DROPBEAR_PRIO_DEFAULT = 10,
|
||||
DROPBEAR_PRIO_LOWDELAY = 11,
|
||||
DROPBEAR_PRIO_BULK = 12,
|
||||
};
|
||||
|
||||
void set_sock_nodelay(int sock);
|
||||
void set_sock_priority(int sock, enum dropbear_prio prio);
|
||||
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup);
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port, int host_lookup);
|
||||
int dropbear_listen(const char* address, const char* port,
|
||||
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
|
||||
|
||||
struct dropbear_progress_connection;
|
||||
|
||||
/* result is DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
|
||||
errstring is only set on DROPBEAR_FAILURE, returns failure message for the last attempted socket */
|
||||
typedef void(*connect_callback)(int result, int sock, void* data, const char* errstring);
|
||||
|
||||
/* Always returns a progress connection, if it fails it will call the callback at a later point */
|
||||
struct dropbear_progress_connection * connect_remote (const char* remotehost, const char* remoteport,
|
||||
connect_callback cb, void *cb_data);
|
||||
|
||||
/* Sets up for select() */
|
||||
void set_connect_fds(fd_set *writefd);
|
||||
/* Handles ready sockets after select() */
|
||||
void handle_connect_fds(fd_set *writefd);
|
||||
/* Cleanup */
|
||||
void remove_connect_pending();
|
||||
|
||||
/* Doesn't actually stop the connect, but adds a dummy callback instead */
|
||||
void cancel_connect(struct dropbear_progress_connection *c);
|
||||
|
||||
void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue);
|
||||
|
||||
/* TODO: writev #ifdef guard */
|
||||
/* Fills out iov which contains iov_count slots, returning the number filled in iov_count */
|
||||
void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count);
|
||||
void packet_queue_consume(struct Queue *queue, ssize_t written);
|
||||
|
||||
#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
|
||||
/* Try for any Linux builds, will fall back if the kernel doesn't support it */
|
||||
void set_listen_fast_open(int sock);
|
||||
/* Define values which may be supported by the kernel even if the libc is too old */
|
||||
#ifndef TCP_FASTOPEN
|
||||
#define TCP_FASTOPEN 23
|
||||
#endif
|
||||
#ifndef MSG_FASTOPEN
|
||||
#define MSG_FASTOPEN 0x20000000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
34
options.h
34
options.h
@@ -2,8 +2,8 @@
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved. See LICENSE for the license. */
|
||||
|
||||
#ifndef _OPTIONS_H_
|
||||
#define _OPTIONS_H_
|
||||
#ifndef DROPBEAR_OPTIONS_H_
|
||||
#define DROPBEAR_OPTIONS_H_
|
||||
|
||||
/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
|
||||
* parts are to allow for commandline -DDROPBEAR_XXX options etc. */
|
||||
@@ -98,11 +98,20 @@ much traffic. */
|
||||
#define DROPBEAR_TWOFISH256
|
||||
#define DROPBEAR_TWOFISH128
|
||||
|
||||
/* Enable CBC mode for ciphers. This has security issues though
|
||||
* is the most compatible with older SSH implementations */
|
||||
#define DROPBEAR_ENABLE_CBC_MODE
|
||||
|
||||
/* Enable "Counter Mode" for ciphers. This is more secure than normal
|
||||
* CBC mode against certain attacks. This adds around 1kB to binary
|
||||
* size and is recommended for most cases */
|
||||
* CBC mode against certain attacks. It is recommended for security
|
||||
* and forwards compatibility */
|
||||
#define DROPBEAR_ENABLE_CTR_MODE
|
||||
|
||||
/* Twofish counter mode is disabled by default because it
|
||||
has not been tested for interoperability with other SSH implementations.
|
||||
If you test it please contact the Dropbear author */
|
||||
/* #define DROPBEAR_TWOFISH_CTR */
|
||||
|
||||
/* You can compile with no encryption if you want. In some circumstances
|
||||
* this could be safe security-wise, though make sure you know what
|
||||
* you're doing. Anyone can see everything that goes over the wire, so
|
||||
@@ -123,8 +132,8 @@ much traffic. */
|
||||
* which are not the standard form. */
|
||||
#define DROPBEAR_SHA1_HMAC
|
||||
#define DROPBEAR_SHA1_96_HMAC
|
||||
/*#define DROPBEAR_SHA2_256_HMAC*/
|
||||
/*#define DROPBEAR_SHA2_512_HMAC*/
|
||||
#define DROPBEAR_SHA2_256_HMAC
|
||||
#define DROPBEAR_SHA2_512_HMAC
|
||||
#define DROPBEAR_MD5_HMAC
|
||||
|
||||
/* You can also disable integrity. Don't bother disabling this if you're
|
||||
@@ -170,6 +179,11 @@ much traffic. */
|
||||
#define DROPBEAR_ZLIB_WINDOW_BITS 15
|
||||
#endif
|
||||
|
||||
/* Server won't allow zlib compression until after authentication. Prevents
|
||||
flaws in the zlib library being unauthenticated exploitable flaws.
|
||||
Some old ssh clients may not support the alternative zlib@openssh.com method */
|
||||
#define DROPBEAR_SERVER_DELAY_ZLIB 1
|
||||
|
||||
/* Whether to do reverse DNS lookups. */
|
||||
/*#define DO_HOST_LOOKUP */
|
||||
|
||||
@@ -207,6 +221,10 @@ much traffic. */
|
||||
#define ENABLE_CLI_PUBKEY_AUTH
|
||||
#define ENABLE_CLI_INTERACT_AUTH
|
||||
|
||||
/* A default argument for dbclient -i <privatekey>.
|
||||
Homedir is prepended unless path begins with / */
|
||||
#define DROPBEAR_DEFAULT_CLI_AUTHKEY ".ssh/id_dropbear"
|
||||
|
||||
/* This variable can be used to set a password for client
|
||||
* authentication on the commandline. Beware of platforms
|
||||
* that don't protect environment variables of processes etc. Also
|
||||
@@ -276,7 +294,7 @@ much traffic. */
|
||||
|
||||
/* This is used by the scp binary when used as a client binary. If you're
|
||||
* not using the Dropbear client, you'll need to change it */
|
||||
#define _PATH_SSH_PROGRAM "/usr/bin/dbclient"
|
||||
#define DROPBEAR_PATH_SSH_PROGRAM "/usr/bin/dbclient"
|
||||
|
||||
/* Whether to log commands executed by a client. This only logs the
|
||||
* (single) command sent to the server, not what a user did in a
|
||||
@@ -324,4 +342,4 @@ be overridden at runtime with -I. 0 disables idle timeouts */
|
||||
* in sysoptions.h */
|
||||
#include "sysoptions.h"
|
||||
|
||||
#endif /* _OPTIONS_H_ */
|
||||
#endif /* DROPBEAR_OPTIONS_H_ */
|
||||
|
||||
156
packet.c
156
packet.c
@@ -34,6 +34,7 @@
|
||||
#include "service.h"
|
||||
#include "auth.h"
|
||||
#include "channel.h"
|
||||
#include "netio.h"
|
||||
|
||||
static int read_packet_init();
|
||||
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
|
||||
@@ -55,14 +56,15 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len);
|
||||
/* non-blocking function writing out a current encrypted packet */
|
||||
void write_packet() {
|
||||
|
||||
int len, written;
|
||||
buffer * writebuf = NULL;
|
||||
unsigned packet_type;
|
||||
ssize_t written;
|
||||
#ifdef HAVE_WRITEV
|
||||
struct iovec *iov = NULL;
|
||||
int i;
|
||||
struct Link *l;
|
||||
int iov_max_count;
|
||||
/* 50 is somewhat arbitrary */
|
||||
unsigned int iov_count = 50;
|
||||
struct iovec iov[50];
|
||||
#else
|
||||
int len;
|
||||
buffer* writebuf;
|
||||
int packet_type;
|
||||
#endif
|
||||
|
||||
TRACE2(("enter write_packet"))
|
||||
@@ -70,36 +72,13 @@ void write_packet() {
|
||||
|
||||
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
|
||||
|
||||
#ifndef IOV_MAX
|
||||
#define IOV_MAX UIO_MAXIOV
|
||||
#endif
|
||||
|
||||
/* Make sure the size of the iov is below the maximum allowed by the OS. */
|
||||
iov_max_count = ses.writequeue.count;
|
||||
if (iov_max_count > IOV_MAX)
|
||||
{
|
||||
iov_max_count = IOV_MAX;
|
||||
}
|
||||
|
||||
iov = m_malloc(sizeof(*iov) * iov_max_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);
|
||||
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;
|
||||
}
|
||||
packet_queue_to_iovec(&ses.writequeue, iov, &iov_count);
|
||||
/* This may return EAGAIN. The main loop sometimes
|
||||
calls write_packet() without bothering to test with select() since
|
||||
it's likely to be necessary */
|
||||
written = writev(ses.sock_out, iov, iov_max_count);
|
||||
written = writev(ses.sock_out, iov, iov_count);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
m_free(iov);
|
||||
TRACE2(("leave write_packet: EINTR"))
|
||||
return;
|
||||
} else {
|
||||
@@ -107,25 +86,13 @@ void write_packet() {
|
||||
}
|
||||
}
|
||||
|
||||
packet_queue_consume(&ses.writequeue, written);
|
||||
ses.writequeue_len -= written;
|
||||
|
||||
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 /* No writev () */
|
||||
/* Get the next buffer in the queue of encrypted packets to write*/
|
||||
writebuf = (buffer*)examine(&ses.writequeue);
|
||||
@@ -134,6 +101,8 @@ void write_packet() {
|
||||
* a cleartext packet_type indicator */
|
||||
packet_type = writebuf->data[writebuf->len-1];
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
TRACE2(("write_packet type %d len %d/%d", packet_type,
|
||||
len, writebuf->len-1))
|
||||
dropbear_assert(len > 0);
|
||||
/* Try to write as much as possible */
|
||||
written = write(ses.sock_out, buf_getptr(writebuf, len), len);
|
||||
@@ -151,6 +120,8 @@ void write_packet() {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
|
||||
ses.writequeue_len -= written;
|
||||
|
||||
if (written == len) {
|
||||
/* We've finished with the packet, free it */
|
||||
dequeue(&ses.writequeue);
|
||||
@@ -283,18 +254,18 @@ static int read_packet_init() {
|
||||
}
|
||||
len = buf_getint(ses.readbuf) + 4 + macsize;
|
||||
|
||||
TRACE2(("packet size is %d, block %d mac %d", len, blocksize, macsize))
|
||||
TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
|
||||
|
||||
|
||||
/* check packet length */
|
||||
if ((len > RECV_MAX_PACKET_LEN) ||
|
||||
(len < MIN_PACKET_LEN + macsize) ||
|
||||
((len - macsize) % blocksize != 0)) {
|
||||
dropbear_exit("Integrity error (bad packet size %d)", len);
|
||||
dropbear_exit("Integrity error (bad packet size %u)", len);
|
||||
}
|
||||
|
||||
if (len > ses.readbuf->size) {
|
||||
buf_resize(ses.readbuf, len);
|
||||
ses.readbuf = buf_resize(ses.readbuf, len);
|
||||
}
|
||||
buf_setlen(ses.readbuf, len);
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
@@ -342,7 +313,7 @@ void decrypt_packet() {
|
||||
/* - 4 - 1 is for LEN and PADLEN values */
|
||||
len = ses.readbuf->len - padlen - 4 - 1 - macsize;
|
||||
if ((len > RECV_MAX_PAYLOAD_LEN+ZLIB_COMPRESS_EXPANSION) || (len < 1)) {
|
||||
dropbear_exit("Bad packet size %d", len);
|
||||
dropbear_exit("Bad packet size %u", len);
|
||||
}
|
||||
|
||||
buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
|
||||
@@ -351,18 +322,21 @@ void decrypt_packet() {
|
||||
if (is_compress_recv()) {
|
||||
/* decompress */
|
||||
ses.payload = buf_decompress(ses.readbuf, len);
|
||||
buf_setpos(ses.payload, 0);
|
||||
ses.payload_beginning = 0;
|
||||
buf_free(ses.readbuf);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ses.payload = ses.readbuf;
|
||||
ses.payload_beginning = ses.payload->pos;
|
||||
buf_setlen(ses.payload, ses.payload->pos + len);
|
||||
/* copy payload */
|
||||
ses.payload = buf_new(len);
|
||||
memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
|
||||
buf_incrlen(ses.payload, len);
|
||||
//ses.payload = buf_new(len);
|
||||
//memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
|
||||
//buf_incrlen(ses.payload, len);
|
||||
}
|
||||
|
||||
buf_free(ses.readbuf);
|
||||
ses.readbuf = NULL;
|
||||
buf_setpos(ses.payload, 0);
|
||||
|
||||
ses.recvseq++;
|
||||
|
||||
@@ -435,7 +409,7 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
|
||||
dropbear_exit("bad packet, oversized decompressed");
|
||||
}
|
||||
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
|
||||
buf_resize(ret, new_size);
|
||||
ret = buf_resize(ret, new_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -605,15 +579,12 @@ void encrypt_packet() {
|
||||
/* stick the MAC on it */
|
||||
buf_putbytes(writebuf, mac_bytes, mac_size);
|
||||
|
||||
/* The last byte of the buffer stores the cleartext packet_type. It is not
|
||||
* transmitted but is used for transmit timeout purposes */
|
||||
buf_putbyte(writebuf, packet_type);
|
||||
/* enqueue the packet for sending. It will get freed after transmission. */
|
||||
buf_setpos(writebuf, 0);
|
||||
enqueue(&ses.writequeue, (void*)writebuf);
|
||||
|
||||
/* Update counts */
|
||||
ses.kexstate.datatrans += writebuf->len;
|
||||
|
||||
writebuf_enqueue(writebuf, packet_type);
|
||||
|
||||
/* Update counts */
|
||||
ses.transseq++;
|
||||
|
||||
now = monotonic_now();
|
||||
@@ -631,6 +602,16 @@ void encrypt_packet() {
|
||||
TRACE2(("leave encrypt_packet()"))
|
||||
}
|
||||
|
||||
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type) {
|
||||
/* The last byte of the buffer stores the cleartext packet_type. It is not
|
||||
* transmitted but is used for transmit timeout purposes */
|
||||
buf_putbyte(writebuf, packet_type);
|
||||
/* enqueue the packet for sending. It will get freed after transmission. */
|
||||
buf_setpos(writebuf, 0);
|
||||
enqueue(&ses.writequeue, (void*)writebuf);
|
||||
ses.writequeue_len += writebuf->len-1;
|
||||
}
|
||||
|
||||
|
||||
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
|
||||
/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
|
||||
@@ -674,7 +655,8 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* compresses len bytes from src, outputting to dest (starting from the
|
||||
* respective current positions. */
|
||||
* respective current positions. dest must have sufficient space,
|
||||
* len+ZLIB_COMPRESS_EXPANSION */
|
||||
static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
|
||||
unsigned int endpos = src->pos + len;
|
||||
@@ -682,38 +664,28 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
|
||||
TRACE2(("enter buf_compress"))
|
||||
|
||||
while (1) {
|
||||
dropbear_assert(dest->size - dest->pos >= len+ZLIB_COMPRESS_EXPANSION);
|
||||
|
||||
ses.keys->trans.zstream->avail_in = endpos - src->pos;
|
||||
ses.keys->trans.zstream->next_in =
|
||||
buf_getptr(src, ses.keys->trans.zstream->avail_in);
|
||||
ses.keys->trans.zstream->avail_in = endpos - src->pos;
|
||||
ses.keys->trans.zstream->next_in =
|
||||
buf_getptr(src, ses.keys->trans.zstream->avail_in);
|
||||
|
||||
ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
|
||||
ses.keys->trans.zstream->next_out =
|
||||
buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
|
||||
ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
|
||||
ses.keys->trans.zstream->next_out =
|
||||
buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
|
||||
|
||||
result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
|
||||
result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
|
||||
|
||||
buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
|
||||
buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
|
||||
buf_setpos(dest, dest->len);
|
||||
|
||||
if (result != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
|
||||
if (ses.keys->trans.zstream->avail_in == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
dropbear_assert(ses.keys->trans.zstream->avail_out == 0);
|
||||
|
||||
/* the buffer has been filled, we must extend. This only happens in
|
||||
* unusual circumstances where the data grows in size after deflate(),
|
||||
* but it is possible */
|
||||
buf_resize(dest, dest->size + ZLIB_COMPRESS_EXPANSION);
|
||||
buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
|
||||
buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
|
||||
buf_setpos(dest, dest->len);
|
||||
|
||||
if (result != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
|
||||
/* fails if destination buffer wasn't large enough */
|
||||
dropbear_assert(ses.keys->trans.zstream->avail_in == 0);
|
||||
TRACE2(("leave buf_compress"))
|
||||
}
|
||||
#endif
|
||||
|
||||
10
packet.h
10
packet.h
@@ -22,17 +22,21 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _PACKET_H_
|
||||
#ifndef DROPBEAR_PACKET_H_
|
||||
|
||||
#define _PACKET_H_
|
||||
#define DROPBEAR_PACKET_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "queue.h"
|
||||
#include "buffer.h"
|
||||
|
||||
void write_packet();
|
||||
void read_packet();
|
||||
void decrypt_packet();
|
||||
void encrypt_packet();
|
||||
|
||||
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type);
|
||||
|
||||
void process_packet();
|
||||
|
||||
void maybe_flush_reply_queue();
|
||||
@@ -46,4 +50,4 @@ typedef struct PacketType {
|
||||
|
||||
#define INIT_READBUF 128
|
||||
|
||||
#endif /* _PACKET_H_ */
|
||||
#endif /* DROPBEAR_PACKET_H_ */
|
||||
|
||||
4
queue.h
4
queue.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _QUEUE_H_
|
||||
#define _QUEUE_H_
|
||||
#ifndef DROPBEAR_QUEUE_H_
|
||||
#define DROPBEAR_QUEUE_H_
|
||||
|
||||
struct Link {
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ if ! head -n1 CHANGES | grep -q $VERSION ; then
|
||||
fi
|
||||
|
||||
if ! head -n1 debian/changelog | grep -q $VERSION ; then
|
||||
echo "CHANGES needs updating"
|
||||
echo "debian/changelog needs updating"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -33,8 +33,10 @@ hg archive "$RELDIR" || exit 2
|
||||
|
||||
rm -r "$RELDIR/autom4te.cache" || exit 2
|
||||
|
||||
(cd $RELDIR/.. && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2
|
||||
rm "$RELDIR/.hgtags"
|
||||
|
||||
(cd "$RELDIR/.." && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2
|
||||
|
||||
ls -l $ARCHIVE
|
||||
openssl sha1 $ARCHIVE
|
||||
openssl sha -sha256 $ARCHIVE
|
||||
echo "Done to $ARCHIVE"
|
||||
|
||||
6
rsa.h
6
rsa.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _RSA_H_
|
||||
#define _RSA_H_
|
||||
#ifndef DROPBEAR_RSA_H_
|
||||
#define DROPBEAR_RSA_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
@@ -55,4 +55,4 @@ void rsa_key_free(dropbear_rsa_key *key);
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
#endif /* _RSA_H_ */
|
||||
#endif /* DROPBEAR_RSA_H_ */
|
||||
|
||||
12
runopts.h
12
runopts.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _RUNOPTS_H_
|
||||
#define _RUNOPTS_H_
|
||||
#ifndef DROPBEAR_RUNOPTS_H_
|
||||
#define DROPBEAR_RUNOPTS_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -44,7 +44,11 @@ typedef struct runopts {
|
||||
/* TODO: add a commandline flag. Currently this is on by default if compression
|
||||
* is compiled in, but disabled for a client's non-final multihop stages. (The
|
||||
* intermediate stages are compressed streams, so are uncompressible. */
|
||||
int enable_compress;
|
||||
enum {
|
||||
DROPBEAR_COMPRESS_DELAYED, /* Server only */
|
||||
DROPBEAR_COMPRESS_ON,
|
||||
DROPBEAR_COMPRESS_OFF,
|
||||
} compress_mode;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
@@ -166,4 +170,4 @@ void parse_ciphers_macs();
|
||||
|
||||
void print_version(void);
|
||||
|
||||
#endif /* _RUNOPTS_H_ */
|
||||
#endif /* DROPBEAR_RUNOPTS_H_ */
|
||||
|
||||
4
scp.c
4
scp.c
@@ -96,7 +96,7 @@ int verbose_mode = 0;
|
||||
int showprogress = 1;
|
||||
|
||||
/* This is the program to execute for the secured connection. ("ssh" or -S) */
|
||||
char *ssh_program = _PATH_SSH_PROGRAM;
|
||||
char *ssh_program = DROPBEAR_PATH_SSH_PROGRAM;
|
||||
|
||||
/* This is used to store the pid of ssh_program */
|
||||
pid_t do_cmd_pid = -1;
|
||||
@@ -437,7 +437,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
/*
|
||||
* Finally check the exit status of the ssh process, if one was forked
|
||||
* and no error has occured yet
|
||||
* and no error has occurred yet
|
||||
*/
|
||||
if (do_cmd_pid != -1 && errs == 0) {
|
||||
if (remin != -1)
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _SERVICE_H_
|
||||
#define _SERVICE_H_
|
||||
#ifndef DROPBEAR_SERVICE_H_
|
||||
#define DROPBEAR_SERVICE_H_
|
||||
|
||||
void recv_msg_service_request(); /* Server */
|
||||
|
||||
#endif /* _SERVICE_H_ */
|
||||
#endif /* DROPBEAR_SERVICE_H_ */
|
||||
|
||||
37
session.h
37
session.h
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _SESSION_H_
|
||||
#define _SESSION_H_
|
||||
#ifndef DROPBEAR_SESSION_H_
|
||||
#define DROPBEAR_SESSION_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
@@ -38,12 +38,13 @@
|
||||
#include "tcpfwd.h"
|
||||
#include "chansession.h"
|
||||
#include "dbutil.h"
|
||||
#include "netio.h"
|
||||
|
||||
extern int sessinitdone; /* Is set to 0 somewhere */
|
||||
extern int exitflag;
|
||||
|
||||
void common_session_init(int sock_in, int sock_out);
|
||||
void session_loop(void(*loophandler)());
|
||||
void session_loop(void(*loophandler)()) ATTRIB_NORETURN;
|
||||
void session_cleanup();
|
||||
void send_session_identification();
|
||||
void send_msg_ignore();
|
||||
@@ -55,13 +56,14 @@ const char* get_user_shell();
|
||||
void fill_passwd(const char* username);
|
||||
|
||||
/* Server */
|
||||
void svr_session(int sock, int childpipe);
|
||||
void svr_session(int sock, int childpipe) ATTRIB_NORETURN;
|
||||
void svr_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
void svr_dropbear_log(int priority, const char* format, va_list param);
|
||||
|
||||
/* Client */
|
||||
void cli_session(int sock_in, int sock_out);
|
||||
void cleantext(unsigned char* dirtytext);
|
||||
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress) ATTRIB_NORETURN;
|
||||
void cli_connected(int result, int sock, void* userdata, const char *errstring);
|
||||
void cleantext(char* dirtytext);
|
||||
|
||||
/* crypto parameters that are stored individually for transmit and receive */
|
||||
struct key_context_directional {
|
||||
@@ -107,13 +109,18 @@ struct sshsession {
|
||||
/* Is it a client or server? */
|
||||
unsigned char isserver;
|
||||
|
||||
time_t connect_time; /* time the connection was established
|
||||
(cleared after auth once we're not
|
||||
respecting AUTH_TIMEOUT any more).
|
||||
A monotonic time, not realworld */
|
||||
|
||||
int sock_in;
|
||||
int sock_out;
|
||||
|
||||
/* 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;
|
||||
char *remoteident;
|
||||
|
||||
int maxfd; /* the maximum file descriptor to check with select() */
|
||||
|
||||
@@ -123,8 +130,13 @@ struct sshsession {
|
||||
throughout the code, as handlers fill out this
|
||||
buffer with the packet to send. */
|
||||
struct Queue writequeue; /* A queue of encrypted packets to send */
|
||||
unsigned int writequeue_len; /* Number of bytes pending to send in writequeue */
|
||||
buffer *readbuf; /* From the wire, decrypted in-place */
|
||||
buffer *payload; /* Post-decompression, the actual SSH packet */
|
||||
buffer *payload; /* Post-decompression, the actual SSH packet.
|
||||
May have extra data at the beginning, will be
|
||||
passed to packet processing functions positioned past
|
||||
that, see payload_beginning */
|
||||
unsigned int payload_beginning;
|
||||
unsigned int transseq, recvseq; /* Sequence IDs */
|
||||
|
||||
/* Packet-handling flags */
|
||||
@@ -144,6 +156,8 @@ struct sshsession {
|
||||
|
||||
int signal_pipe[2]; /* stores endpoints of a self-pipe used for
|
||||
race-free signal handling */
|
||||
|
||||
m_list conn_pending;
|
||||
|
||||
/* time of the last packet send/receive, for keepalive. Not real-world clock */
|
||||
time_t last_packet_time_keepalive_sent;
|
||||
@@ -222,11 +236,6 @@ struct serversession {
|
||||
/* The resolved remote address, used for lastlog etc */
|
||||
char *remotehost;
|
||||
|
||||
time_t connect_time; /* time the connection was established
|
||||
(cleared after auth once we're not
|
||||
respecting AUTH_TIMEOUT any more).
|
||||
A monotonic time, not realworld */
|
||||
|
||||
#ifdef USE_VFORK
|
||||
pid_t server_pid;
|
||||
#endif
|
||||
@@ -309,4 +318,4 @@ extern struct serversession svr_ses;
|
||||
extern struct clientsession cli_ses;
|
||||
#endif /* DROPBEAR_CLIENT */
|
||||
|
||||
#endif /* _SESSION_H_ */
|
||||
#endif /* DROPBEAR_SESSION_H_ */
|
||||
|
||||
15
signkey.c
15
signkey.c
@@ -138,9 +138,9 @@ signkey_key_ptr(sign_key *key, enum signkey_type type) {
|
||||
* on return is set to the type read (useful when type = _ANY) */
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
|
||||
unsigned char* ident;
|
||||
char *ident;
|
||||
unsigned int len;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE2(("enter buf_get_pub_key"))
|
||||
@@ -187,6 +187,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
ecc_free(*eck);
|
||||
m_free(*eck);
|
||||
*eck = NULL;
|
||||
}
|
||||
*eck = buf_get_ecdsa_pub_key(buf);
|
||||
@@ -208,9 +209,9 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
* on return is set to the type read (useful when type = _ANY) */
|
||||
int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
|
||||
unsigned char* ident;
|
||||
char *ident;
|
||||
unsigned int len;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE2(("enter buf_get_priv_key"))
|
||||
@@ -255,6 +256,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
ecc_free(*eck);
|
||||
m_free(*eck);
|
||||
*eck = NULL;
|
||||
}
|
||||
*eck = buf_get_ecdsa_priv_key(buf);
|
||||
@@ -355,18 +357,21 @@ void sign_key_free(sign_key *key) {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (key->ecckey256) {
|
||||
ecc_free(key->ecckey256);
|
||||
m_free(key->ecckey256);
|
||||
key->ecckey256 = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (key->ecckey384) {
|
||||
ecc_free(key->ecckey384);
|
||||
m_free(key->ecckey384);
|
||||
key->ecckey384 = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (key->ecckey521) {
|
||||
ecc_free(key->ecckey521);
|
||||
m_free(key->ecckey521);
|
||||
key->ecckey521 = NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -510,7 +515,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
|
||||
* signature blob */
|
||||
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
|
||||
|
||||
unsigned char * type_name = NULL;
|
||||
char *type_name = NULL;
|
||||
unsigned int type_name_len = 0;
|
||||
enum signkey_type type;
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _SIGNKEY_H_
|
||||
#define _SIGNKEY_H_
|
||||
#ifndef DROPBEAR_SIGNKEY_H_
|
||||
#define DROPBEAR_SIGNKEY_H_
|
||||
|
||||
#include "buffer.h"
|
||||
#include "dss.h"
|
||||
@@ -101,4 +101,4 @@ int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
|
||||
|
||||
void** signkey_key_ptr(sign_key *key, enum signkey_type type);
|
||||
|
||||
#endif /* _SIGNKEY_H_ */
|
||||
#endif /* DROPBEAR_SIGNKEY_H_ */
|
||||
|
||||
@@ -117,7 +117,7 @@ static void agentaccept(struct Listener *UNUSED(listener), int sock) {
|
||||
}
|
||||
|
||||
/* set up the environment variable pointing to the socket. This is called
|
||||
* just before command/shell execution, after dropping priveleges */
|
||||
* just before command/shell execution, after dropping privileges */
|
||||
void svr_agentset(struct ChanSess * chansess) {
|
||||
|
||||
char *path = NULL;
|
||||
|
||||
13
svr-auth.c
13
svr-auth.c
@@ -36,7 +36,7 @@
|
||||
#include "dbrandom.h"
|
||||
|
||||
static void authclear();
|
||||
static int checkusername(unsigned char *username, unsigned int userlen);
|
||||
static int checkusername(char *username, unsigned int userlen);
|
||||
|
||||
/* initialise the first time for a session, resetting all parameters */
|
||||
void svr_authinitialise() {
|
||||
@@ -100,7 +100,7 @@ void send_msg_userauth_banner(buffer *banner) {
|
||||
* checking, and handle success or failure */
|
||||
void recv_msg_userauth_request() {
|
||||
|
||||
unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
|
||||
char *username = NULL, *servicename = NULL, *methodname = NULL;
|
||||
unsigned int userlen, servicelen, methodlen;
|
||||
int valid_user = 0;
|
||||
|
||||
@@ -227,7 +227,7 @@ out:
|
||||
|
||||
/* Check that the username exists and isn't disallowed (root), and has a valid shell.
|
||||
* returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
|
||||
static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
static int checkusername(char *username, unsigned int userlen) {
|
||||
|
||||
char* listshell = NULL;
|
||||
char* usershell = NULL;
|
||||
@@ -333,14 +333,14 @@ void send_msg_userauth_failure(int partial, int incrfail) {
|
||||
typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */
|
||||
|
||||
if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
|
||||
buf_putbytes(typebuf, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
|
||||
buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
|
||||
if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
|
||||
buf_putbyte(typebuf, ',');
|
||||
}
|
||||
}
|
||||
|
||||
if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
|
||||
buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
|
||||
buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
|
||||
}
|
||||
|
||||
buf_putbufstring(ses.writepayload, typebuf);
|
||||
@@ -392,7 +392,8 @@ void send_msg_userauth_success() {
|
||||
/* authdone must be set after encrypt_packet() for
|
||||
* delayed-zlib mode */
|
||||
ses.authstate.authdone = 1;
|
||||
svr_ses.connect_time = 0;
|
||||
ses.connect_time = 0;
|
||||
|
||||
|
||||
if (ses.authstate.pw_uid == 0) {
|
||||
ses.allowprivport = 1;
|
||||
|
||||
@@ -188,7 +188,7 @@ void svr_auth_pam() {
|
||||
|
||||
pam_handle_t* pamHandlep = NULL;
|
||||
|
||||
unsigned char * password = NULL;
|
||||
char * password = NULL;
|
||||
unsigned int passwordlen;
|
||||
|
||||
int rc = PAM_SUCCESS;
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#ifdef ENABLE_SVR_PASSWORD_AUTH
|
||||
|
||||
/* not constant time when strings are differing lengths.
|
||||
string content isn't leaked, and crypt hashes are predictable length. */
|
||||
static int constant_time_strcmp(const char* a, const char* b) {
|
||||
size_t la = strlen(a);
|
||||
size_t lb = strlen(b);
|
||||
@@ -50,7 +52,7 @@ void svr_auth_password() {
|
||||
|
||||
char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
|
||||
char * testcrypt = NULL; /* crypt generated from the user's password sent */
|
||||
unsigned char * password;
|
||||
char * password;
|
||||
unsigned int passwordlen;
|
||||
|
||||
unsigned int changepw;
|
||||
@@ -73,7 +75,7 @@ void svr_auth_password() {
|
||||
password = buf_getstring(ses.payload, &passwordlen);
|
||||
|
||||
/* the first bytes of passwdcrypt are the salt */
|
||||
testcrypt = crypt((char*)password, passwdcrypt);
|
||||
testcrypt = crypt(password, passwdcrypt);
|
||||
m_burn(password, passwordlen);
|
||||
m_free(password);
|
||||
|
||||
|
||||
@@ -70,10 +70,10 @@
|
||||
#define MIN_AUTHKEYS_LINE 10 /* "ssh-rsa AB" - short but doesn't matter */
|
||||
#define MAX_AUTHKEYS_LINE 4200 /* max length of a line in authkeys */
|
||||
|
||||
static int checkpubkey(unsigned char* algo, unsigned int algolen,
|
||||
static int checkpubkey(char* algo, unsigned int algolen,
|
||||
unsigned char* keyblob, unsigned int keybloblen);
|
||||
static int checkpubkeyperms();
|
||||
static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
|
||||
static void send_msg_userauth_pk_ok(char* algo, unsigned int algolen,
|
||||
unsigned char* keyblob, unsigned int keybloblen);
|
||||
static int checkfileperm(char * filename);
|
||||
|
||||
@@ -82,10 +82,11 @@ static int checkfileperm(char * filename);
|
||||
void svr_auth_pubkey() {
|
||||
|
||||
unsigned char testkey; /* whether we're just checking if a key is usable */
|
||||
unsigned char* algo = NULL; /* pubkey algo */
|
||||
char* algo = NULL; /* pubkey algo */
|
||||
unsigned int algolen;
|
||||
unsigned char* keyblob = NULL;
|
||||
unsigned int keybloblen;
|
||||
unsigned int sign_payload_length;
|
||||
buffer * signbuf = NULL;
|
||||
sign_key * key = NULL;
|
||||
char* fp = NULL;
|
||||
@@ -125,9 +126,18 @@ void svr_auth_pubkey() {
|
||||
|
||||
/* create the data which has been signed - this a string containing
|
||||
* session_id, concatenated with the payload packet up to the signature */
|
||||
assert(ses.payload_beginning <= ses.payload->pos);
|
||||
sign_payload_length = ses.payload->pos - ses.payload_beginning;
|
||||
signbuf = buf_new(ses.payload->pos + 4 + ses.session_id->len);
|
||||
buf_putbufstring(signbuf, ses.session_id);
|
||||
buf_putbytes(signbuf, ses.payload->data, ses.payload->pos);
|
||||
|
||||
/* The entire contents of the payload prior. */
|
||||
buf_setpos(ses.payload, ses.payload_beginning);
|
||||
buf_putbytes(signbuf,
|
||||
buf_getptr(ses.payload, sign_payload_length),
|
||||
sign_payload_length);
|
||||
buf_incrpos(ses.payload, sign_payload_length);
|
||||
|
||||
buf_setpos(signbuf, 0);
|
||||
|
||||
/* ... and finally verify the signature */
|
||||
@@ -163,7 +173,7 @@ out:
|
||||
/* Reply that the key is valid for auth, this is sent when the user sends
|
||||
* a straight copy of their pubkey to test, to avoid having to perform
|
||||
* expensive signing operations with a worthless key */
|
||||
static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
|
||||
static void send_msg_userauth_pk_ok(char* algo, unsigned int algolen,
|
||||
unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
TRACE(("enter send_msg_userauth_pk_ok"))
|
||||
@@ -171,7 +181,7 @@ static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_PK_OK);
|
||||
buf_putstring(ses.writepayload, algo, algolen);
|
||||
buf_putstring(ses.writepayload, keyblob, keybloblen);
|
||||
buf_putstring(ses.writepayload, (const char*)keyblob, keybloblen);
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_userauth_pk_ok"))
|
||||
@@ -181,7 +191,7 @@ static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
|
||||
/* Checks whether a specified publickey (and associated algorithm) is an
|
||||
* acceptable key for authentication */
|
||||
/* Returns DROPBEAR_SUCCESS if key is ok for auth, DROPBEAR_FAILURE otherwise */
|
||||
static int checkpubkey(unsigned char* algo, unsigned int algolen,
|
||||
static int checkpubkey(char* algo, unsigned int algolen,
|
||||
unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
FILE * authfile = NULL;
|
||||
@@ -250,9 +260,9 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
|
||||
/* check the key type - will fail if there are options */
|
||||
TRACE(("a line!"))
|
||||
|
||||
if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) {
|
||||
if (strncmp((const char *) buf_getptr(line, algolen), algo, algolen) != 0) {
|
||||
int is_comment = 0;
|
||||
char *options_start = NULL;
|
||||
unsigned char *options_start = NULL;
|
||||
int options_len = 0;
|
||||
int escape, quoted;
|
||||
|
||||
@@ -298,7 +308,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
|
||||
if (line->pos + algolen+3 > line->len) {
|
||||
continue;
|
||||
}
|
||||
if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) {
|
||||
if (strncmp((const char *) buf_getptr(line, algolen), algo, algolen) != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -320,7 +330,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
|
||||
|
||||
TRACE(("checkpubkey: line pos = %d len = %d", line->pos, line->len))
|
||||
|
||||
ret = cmp_base64_key(keyblob, keybloblen, algo, algolen, line, NULL);
|
||||
ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algo, algolen, line, NULL);
|
||||
|
||||
if (ret == DROPBEAR_SUCCESS && options_buf) {
|
||||
ret = svr_add_pubkey_options(options_buf, line_num, filename);
|
||||
|
||||
@@ -91,7 +91,7 @@ int svr_pubkey_allows_pty() {
|
||||
/* Set chansession command to the one forced
|
||||
* by any 'command' public key option. */
|
||||
void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
|
||||
if (ses.authstate.pubkey_options) {
|
||||
if (ses.authstate.pubkey_options && ses.authstate.pubkey_options->forced_command) {
|
||||
if (chansess->cmd) {
|
||||
/* original_command takes ownership */
|
||||
chansess->original_command = chansess->cmd;
|
||||
@@ -120,7 +120,7 @@ static int match_option(buffer *options_buf, const char *opt_name) {
|
||||
if (options_buf->len - options_buf->pos < len) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
if (strncasecmp(buf_getptr(options_buf, len), opt_name, len) == 0) {
|
||||
if (strncasecmp((const char *) buf_getptr(options_buf, len), opt_name, len) == 0) {
|
||||
buf_incrpos(options_buf, len);
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ static int newchansess(struct Channel *channel) {
|
||||
|
||||
struct ChanSess *chansess;
|
||||
|
||||
TRACE(("new chansess %p", channel))
|
||||
TRACE(("new chansess %p", (void*)channel))
|
||||
|
||||
dropbear_assert(channel->typedata == NULL);
|
||||
|
||||
@@ -343,7 +343,7 @@ static void closechansess(struct Channel *channel) {
|
||||
* or x11/authagent forwarding. These are passed to appropriate handlers */
|
||||
static void chansessionrequest(struct Channel *channel) {
|
||||
|
||||
unsigned char * type = NULL;
|
||||
char * type = NULL;
|
||||
unsigned int typelen;
|
||||
unsigned char wantreply;
|
||||
int ret = 1;
|
||||
@@ -406,7 +406,7 @@ out:
|
||||
static int sessionsignal(struct ChanSess *chansess) {
|
||||
|
||||
int sig = 0;
|
||||
unsigned char* signame = NULL;
|
||||
char* signame = NULL;
|
||||
int i;
|
||||
|
||||
if (chansess->pid == 0) {
|
||||
@@ -557,7 +557,7 @@ static void get_termmodes(struct ChanSess *chansess) {
|
||||
static int sessionpty(struct ChanSess * chansess) {
|
||||
|
||||
unsigned int termlen;
|
||||
unsigned char namebuf[65];
|
||||
char namebuf[65];
|
||||
struct passwd * pw = NULL;
|
||||
|
||||
TRACE(("enter sessionpty"))
|
||||
@@ -583,7 +583,7 @@ static int sessionpty(struct ChanSess * chansess) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
chansess->tty = (char*)m_strdup(namebuf);
|
||||
chansess->tty = m_strdup(namebuf);
|
||||
if (!chansess->tty) {
|
||||
dropbear_exit("Out of memory"); /* TODO disconnect */
|
||||
}
|
||||
@@ -603,6 +603,7 @@ static int sessionpty(struct ChanSess * chansess) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef USE_VFORK
|
||||
static void make_connection_string(struct ChanSess *chansess) {
|
||||
char *local_ip, *local_port, *remote_ip, *remote_port;
|
||||
size_t len;
|
||||
@@ -624,6 +625,7 @@ static void make_connection_string(struct ChanSess *chansess) {
|
||||
m_free(remote_ip);
|
||||
m_free(remote_port);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handle a command request from the client. This is used for both shell
|
||||
* and command-execution requests, and passes the command to
|
||||
|
||||
27
svr-kex.c
27
svr-kex.c
@@ -84,7 +84,28 @@ void recv_msg_kexdh_init() {
|
||||
TRACE(("leave recv_msg_kexdh_init"))
|
||||
}
|
||||
|
||||
|
||||
#ifdef DROPBEAR_DELAY_HOSTKEY
|
||||
|
||||
static void fsync_parent_dir(const char* fn) {
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
char *fn_dir = m_strdup(fn);
|
||||
char *dir = dirname(fn_dir);
|
||||
int dirfd = open(dir, O_RDONLY);
|
||||
|
||||
if (dirfd != -1) {
|
||||
if (fsync(dirfd) != 0) {
|
||||
TRACE(("fsync of directory %s failed: %s", dir, strerror(errno)))
|
||||
}
|
||||
m_close(dirfd);
|
||||
} else {
|
||||
TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
|
||||
}
|
||||
|
||||
free(fn_dir);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void svr_ensure_hostkey() {
|
||||
|
||||
const char* fn = NULL;
|
||||
@@ -142,6 +163,10 @@ static void svr_ensure_hostkey() {
|
||||
}
|
||||
}
|
||||
|
||||
/* ensure directory update is flushed to disk, otherwise we can end up
|
||||
with zero-byte hostkey files if the power goes off */
|
||||
fsync_parent_dir(fn);
|
||||
|
||||
ret = readhostkey(fn, svr_opts.hostkey, &type);
|
||||
|
||||
if (ret == DROPBEAR_SUCCESS) {
|
||||
@@ -222,7 +247,7 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
|
||||
{
|
||||
struct kex_curve25519_param *param = gen_kexcurve25519_param();
|
||||
kexcurve25519_comb_key(param, ecdh_qs, svr_opts.hostkey);
|
||||
buf_putstring(ses.writepayload, param->pub, CURVE25519_LEN);
|
||||
buf_putstring(ses.writepayload, (const char*)param->pub, CURVE25519_LEN);
|
||||
free_kexcurve25519_param(param);
|
||||
}
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user