mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
87 Commits
maemo-0.52
...
DROPBEAR_0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a545a0d04 | ||
|
|
0993e44b4f | ||
|
|
d634b502cf | ||
|
|
53fc7eaf03 | ||
|
|
3c42c5407c | ||
|
|
9d9a8ff735 | ||
|
|
abed230cdb | ||
|
|
e9879cd07b | ||
|
|
84c51f933c | ||
|
|
977c43fffb | ||
|
|
f99a19b6ca | ||
|
|
5a7a88b843 | ||
|
|
0ffdf2bba9 | ||
|
|
38ed870ffe | ||
|
|
1e4ed404c5 | ||
|
|
642920585f | ||
|
|
af07eb115a | ||
|
|
66371f9920 | ||
|
|
aabe0677c0 | ||
|
|
0fa65ebd4d | ||
|
|
27fddd2c35 | ||
|
|
fced1113d3 | ||
|
|
4d050c34cb | ||
|
|
a8c28714cd | ||
|
|
eabfd803c9 | ||
|
|
07b764ead6 | ||
|
|
8bad5d61fd | ||
|
|
9f42a75ef6 | ||
|
|
ddbfdb0799 | ||
|
|
3b07844548 | ||
|
|
85288d7b61 | ||
|
|
8174a2f27b | ||
|
|
e3ca0513a0 | ||
|
|
95a01f9002 | ||
|
|
52551cb771 | ||
|
|
4dfb834f7c | ||
|
|
c35e38c5e9 | ||
|
|
48734bb3b5 | ||
|
|
4e9f22c602 | ||
|
|
f88bed7a30 | ||
|
|
ccd02552dd | ||
|
|
4b1f9e50f2 | ||
|
|
0b50010436 | ||
|
|
d773103730 | ||
|
|
c7e3eb9b3f | ||
|
|
f15feb2ac6 | ||
|
|
2f1ed9a34b | ||
|
|
bb8234c2f1 | ||
|
|
bacd2a8c79 | ||
|
|
103a829eac | ||
|
|
0dcecfa526 | ||
|
|
bcd541d65f | ||
|
|
3608775306 | ||
|
|
8181d41bb5 | ||
|
|
a996e61a2e | ||
|
|
8a19a049b2 | ||
|
|
c742137dc8 | ||
|
|
9dc9aff016 | ||
|
|
c6582dbe37 | ||
|
|
709a3e75cf | ||
|
|
cb82c6e3e0 | ||
|
|
d6441f4397 | ||
|
|
08893f03a5 | ||
|
|
4be3826dd5 | ||
|
|
a21cf67a6c | ||
|
|
fe03c39241 | ||
|
|
6e78eca7c8 | ||
|
|
5d3dae1492 | ||
|
|
061565865c | ||
|
|
b639e18d39 | ||
|
|
2b54d3397c | ||
|
|
ff763e4005 | ||
|
|
8e72bbaa9d | ||
|
|
4b37932ba1 | ||
|
|
d1bfb6bfb7 | ||
|
|
35f3d2ff90 | ||
|
|
a60cb7dbaa | ||
|
|
cca4e1a080 | ||
|
|
c04cc62ebf | ||
|
|
8158e952b9 | ||
|
|
b717efb577 | ||
|
|
e674c73ee6 | ||
|
|
bb84e33d99 | ||
|
|
e41452afeb | ||
|
|
1e26b86f15 | ||
|
|
f7caf6f5c6 | ||
|
|
e444f0cfe6 |
57
CHANGES
57
CHANGES
@@ -1,3 +1,60 @@
|
||||
0.53.1 - Wednesday 2 March 2011
|
||||
|
||||
- -lcrypt needs to be before object files for static linking
|
||||
|
||||
- Compile fix when both client and agent forwarding are disabled
|
||||
|
||||
- Fix DROPBEAR_PRNGD_SOCKET mode
|
||||
|
||||
- Don't allow setting zlib memLevel since it seems buggy
|
||||
|
||||
0.53 - Thurs 24 February 2011
|
||||
|
||||
- Various performance/memory use improvements
|
||||
|
||||
- Client agent forwarding now works, using OpenSSH's ssh-agent
|
||||
|
||||
- Improve robustness of client multihop mode
|
||||
|
||||
- Fix a prime generation bug in bundled libtommath. This is unlikely to have
|
||||
generated any bad keys in the wild.
|
||||
See
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=615088
|
||||
http://bugs.gentoo.org/show_bug.cgi?id=328383
|
||||
http://bugs.gentoo.org/show_bug.cgi?id=328409
|
||||
|
||||
- Attempt to build against system libtomcrypt/libtommath if available. This
|
||||
can be disabled with ./configure --enable-bundled-libtom
|
||||
|
||||
- Make -K (keepalive) and -I (idle timeout) work together sensibly in the client.
|
||||
The idle timeout is no longer reset by SSH_MSG_IGNORE packets.
|
||||
|
||||
- Add diffie-hellman-group14-sha1 key exchange method
|
||||
|
||||
- Compile fix if ENABLE_CLI_PROXYCMD is disabled
|
||||
|
||||
- /usr/bin/X11/xauth is now the default path
|
||||
|
||||
- Client remote forward (-L/-R) arguments now accept a listen address
|
||||
|
||||
- In uClinux avoid trashing the parent process when a session exits
|
||||
|
||||
- Blowfish is now disabled by default since it has large memory usage
|
||||
|
||||
- Add option to change zlib windowbits/memlevel. Use less memory by default
|
||||
|
||||
- DROPBEAR_SMALL_CODE is now disabled by default
|
||||
|
||||
- SSH_ORIGINAL_COMMAND environment variable is set by the server when an
|
||||
authorized_keys command is specified.
|
||||
|
||||
- Set SSH_TTY and SSH_CONNECTION environment variables in the server
|
||||
|
||||
- Client banner is now printed to standard error rather than standard output
|
||||
|
||||
- Capitalisation in many log messages has been made consistent. This may affect
|
||||
scripts that parse logfiles.
|
||||
|
||||
0.52 - Wed 12 November 2008
|
||||
|
||||
- Add "netcat-alike" option (-B) to dbclient, allowing Dropbear to tunnel
|
||||
|
||||
28
Makefile.in
28
Makefile.in
@@ -16,20 +16,27 @@ endif
|
||||
LTC=libtomcrypt/libtomcrypt.a
|
||||
LTM=libtommath/libtommath.a
|
||||
|
||||
ifeq (@BUNDLED_LIBTOM@, 1)
|
||||
LIBTOM_DEPS=$(LTC) $(LTM)
|
||||
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
|
||||
LIBS+=$(LTC) $(LTM)
|
||||
endif
|
||||
|
||||
COMMONOBJS=dbutil.o buffer.o \
|
||||
dss.o bignum.o \
|
||||
signkey.o rsa.o random.o \
|
||||
queue.o \
|
||||
atomicio.o compat.o fake-rfc2553.o
|
||||
atomicio.o compat.o fake-rfc2553.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
|
||||
SVROBJS=@CRYPTLIB@ svr-kex.o svr-algo.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
|
||||
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
|
||||
svr-tcpfwd.o svr-authpam.o
|
||||
|
||||
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
|
||||
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o
|
||||
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
|
||||
cli-agentfwd.o list.o
|
||||
|
||||
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
|
||||
common-channel.o common-chansession.o termcodes.o loginrec.o \
|
||||
@@ -40,7 +47,7 @@ KEYOBJS=dropbearkey.o gendss.o genrsa.o
|
||||
|
||||
CONVERTOBJS=dropbearconvert.o keyimport.o
|
||||
|
||||
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o
|
||||
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
|
||||
|
||||
HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
|
||||
dss.h bignum.h signkey.h rsa.h random.h service.h auth.h \
|
||||
@@ -69,8 +76,8 @@ RANLIB=@RANLIB@
|
||||
STRIP=@STRIP@
|
||||
INSTALL=@INSTALL@
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
CFLAGS=-I. -I$(srcdir) -I$(srcdir)/libtomcrypt/src/headers/ $(CPPFLAGS) @CFLAGS@
|
||||
LIBS=$(LTC) $(LTM) @LIBS@
|
||||
CFLAGS+=-I. -I$(srcdir) $(CPPFLAGS) @CFLAGS@
|
||||
LIBS+=@LIBS@
|
||||
LDFLAGS=@LDFLAGS@
|
||||
|
||||
EXEEXT=@EXEEXT@
|
||||
@@ -106,10 +113,6 @@ ifeq ($(SCPPROGRESS), 1)
|
||||
CFLAGS+=-DPROGRESS_METER
|
||||
endif
|
||||
|
||||
#%: $(HEADERS)
|
||||
#%: $(HEADERS) Makefile
|
||||
# TODO
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
strip: $(TARGETS)
|
||||
@@ -153,8 +156,7 @@ dbclient: $(dbclientobjs)
|
||||
dropbearkey: $(dropbearkeyobjs)
|
||||
dropbearconvert: $(dropbearconvertobjs)
|
||||
|
||||
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \
|
||||
Makefile
|
||||
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS)
|
||||
|
||||
# scp doesn't use the libs so is special.
|
||||
@@ -171,7 +173,7 @@ endif
|
||||
|
||||
dropbearmulti: multilink
|
||||
|
||||
multibinary: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile
|
||||
multibinary: $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS)
|
||||
|
||||
multilink: multibinary $(addprefix link, $(PROGRAMS))
|
||||
|
||||
25
agentfwd.h
25
agentfwd.h
@@ -23,21 +23,34 @@
|
||||
* SOFTWARE. */
|
||||
#ifndef _AGENTFWD_H_
|
||||
#define _AGENTFWD_H_
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
|
||||
#include "includes.h"
|
||||
#include "chansession.h"
|
||||
#include "channel.h"
|
||||
#include "auth.h"
|
||||
#include "list.h"
|
||||
|
||||
/* An agent reply can be reasonably large, as it can
|
||||
* contain a list of all public keys held by the agent.
|
||||
* 10000 is arbitrary */
|
||||
#define MAX_AGENT_REPLY 10000
|
||||
|
||||
int svr_agentreq(struct ChanSess * chansess);
|
||||
void svr_agentcleanup(struct ChanSess * chansess);
|
||||
void svr_agentset(struct ChanSess *chansess);
|
||||
|
||||
/* client functions */
|
||||
void cli_load_agent_keys(m_list * ret_list);
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len);
|
||||
void cli_setup_agent(struct Channel *channel);
|
||||
|
||||
int agentreq(struct ChanSess * chansess);
|
||||
void agentsetauth(struct ChanSess *chansess);
|
||||
void agentcleanup(struct ChanSess * chansess);
|
||||
void agentset(struct ChanSess *chansess);
|
||||
|
||||
#ifdef __hpux
|
||||
#define seteuid(a) setresuid(-1, (a), -1)
|
||||
#define setegid(a) setresgid(-1, (a), -1)
|
||||
#endif
|
||||
|
||||
#endif /* DROPBEAR_AGENTFWD */
|
||||
extern const struct ChanType cli_chan_agent;
|
||||
|
||||
#endif /* _AGENTFWD_H_ */
|
||||
|
||||
3
algo.h
3
algo.h
@@ -50,7 +50,8 @@ extern algo_type sshkex[];
|
||||
extern algo_type sshhostkey[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type sshcompress[];
|
||||
extern algo_type ssh_compress[];
|
||||
extern algo_type ssh_nocompress[];
|
||||
|
||||
extern const struct dropbear_cipher dropbear_nocipher;
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_none;
|
||||
|
||||
18
auth.h
18
auth.h
@@ -26,6 +26,7 @@
|
||||
#define _AUTH_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
#include "chansession.h"
|
||||
|
||||
void svr_authinitialise();
|
||||
@@ -73,6 +74,7 @@ void cli_auth_password();
|
||||
int cli_auth_pubkey();
|
||||
void cli_auth_interactive();
|
||||
char* getpass_or_cancel(char* prompt);
|
||||
void cli_auth_pubkey_cleanup();
|
||||
|
||||
|
||||
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
|
||||
@@ -97,7 +99,6 @@ char* getpass_or_cancel(char* prompt);
|
||||
* relatively little extraneous bits when used for the client rather than the
|
||||
* server */
|
||||
struct AuthState {
|
||||
|
||||
char *username; /* This is the username the client presents to check. It
|
||||
is updated each run through, used for auth checking */
|
||||
unsigned char authtypes; /* Flags indicating which auth types are still
|
||||
@@ -120,19 +121,6 @@ struct AuthState {
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
struct PubKeyOptions* pubkey_options;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
struct SignKeyList;
|
||||
/* A singly linked list of signing keys */
|
||||
struct SignKeyList {
|
||||
|
||||
sign_key *key;
|
||||
int type; /* The type of key */
|
||||
struct SignKeyList *next;
|
||||
/* filename? or the buffer? for encrypted keys, so we can later get
|
||||
* the private key portion */
|
||||
|
||||
};
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
@@ -145,7 +133,7 @@ struct PubKeyOptions {
|
||||
int no_pty_flag;
|
||||
/* "command=" option. */
|
||||
unsigned char * forced_command;
|
||||
|
||||
unsigned char * original_command;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
6
bignum.c
6
bignum.c
@@ -31,7 +31,7 @@
|
||||
void m_mp_init(mp_int *mp) {
|
||||
|
||||
if (mp_init(mp) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ void m_mp_init_multi(mp_int *mp, ...)
|
||||
va_start(args, mp); /* init args to next argument from caller */
|
||||
while (cur_arg != NULL) {
|
||||
if (mp_init(cur_arg) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
cur_arg = va_arg(args, mp_int*);
|
||||
}
|
||||
@@ -55,7 +55,7 @@ void m_mp_init_multi(mp_int *mp, ...)
|
||||
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
|
||||
|
||||
if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
32
buffer.c
32
buffer.c
@@ -106,7 +106,7 @@ buffer* buf_newcopy(buffer* buf) {
|
||||
/* Set the length of the buffer */
|
||||
void buf_setlen(buffer* buf, unsigned int len) {
|
||||
if (len > buf->size) {
|
||||
dropbear_exit("bad buf_setlen");
|
||||
dropbear_exit("Bad buf_setlen");
|
||||
}
|
||||
buf->len = len;
|
||||
}
|
||||
@@ -114,7 +114,7 @@ void buf_setlen(buffer* buf, unsigned int len) {
|
||||
/* Increment the length of the buffer */
|
||||
void buf_incrlen(buffer* buf, unsigned int incr) {
|
||||
if (incr > BUF_MAX_INCR || buf->len + incr > buf->size) {
|
||||
dropbear_exit("bad buf_incrlen");
|
||||
dropbear_exit("Bad buf_incrlen");
|
||||
}
|
||||
buf->len += incr;
|
||||
}
|
||||
@@ -122,7 +122,7 @@ void buf_incrlen(buffer* buf, unsigned int incr) {
|
||||
void buf_setpos(buffer* buf, unsigned int pos) {
|
||||
|
||||
if (pos > buf->len) {
|
||||
dropbear_exit("bad buf_setpos");
|
||||
dropbear_exit("Bad buf_setpos");
|
||||
}
|
||||
buf->pos = pos;
|
||||
}
|
||||
@@ -130,7 +130,7 @@ void buf_setpos(buffer* buf, unsigned int pos) {
|
||||
/* increment the postion 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");
|
||||
dropbear_exit("Bad buf_incrwritepos");
|
||||
}
|
||||
buf->pos += incr;
|
||||
if (buf->pos > buf->len) {
|
||||
@@ -144,7 +144,7 @@ void buf_incrpos(buffer* buf, int incr) {
|
||||
if (incr > BUF_MAX_INCR ||
|
||||
(unsigned int)((int)buf->pos + incr) > buf->len
|
||||
|| ((int)buf->pos + incr) < 0) {
|
||||
dropbear_exit("bad buf_incrpos");
|
||||
dropbear_exit("Bad buf_incrpos");
|
||||
}
|
||||
buf->pos += incr;
|
||||
}
|
||||
@@ -155,7 +155,7 @@ unsigned char buf_getbyte(buffer* buf) {
|
||||
/* This check is really just ==, but the >= allows us to check for the
|
||||
* bad case of pos > len, which should _never_ happen. */
|
||||
if (buf->pos >= buf->len) {
|
||||
dropbear_exit("bad buf_getbyte");
|
||||
dropbear_exit("Bad buf_getbyte");
|
||||
}
|
||||
return buf->data[buf->pos++];
|
||||
}
|
||||
@@ -185,7 +185,7 @@ void buf_putbyte(buffer* buf, unsigned char val) {
|
||||
unsigned char* buf_getptr(buffer* buf, unsigned int len) {
|
||||
|
||||
if (buf->pos + len > buf->len) {
|
||||
dropbear_exit("bad buf_getptr");
|
||||
dropbear_exit("Bad buf_getptr");
|
||||
}
|
||||
return &buf->data[buf->pos];
|
||||
}
|
||||
@@ -195,7 +195,7 @@ unsigned char* buf_getptr(buffer* buf, unsigned int len) {
|
||||
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
|
||||
|
||||
if (buf->pos + len > buf->size) {
|
||||
dropbear_exit("bad buf_getwriteptr");
|
||||
dropbear_exit("Bad buf_getwriteptr");
|
||||
}
|
||||
return &buf->data[buf->pos];
|
||||
}
|
||||
@@ -209,7 +209,7 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
unsigned char* ret;
|
||||
len = buf_getint(buf);
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("string too long");
|
||||
dropbear_exit("String too long");
|
||||
}
|
||||
|
||||
if (retlen != NULL) {
|
||||
@@ -223,6 +223,20 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Just increment the buffer position the same as if we'd used buf_getstring,
|
||||
* but don't bother copying/malloc()ing for it */
|
||||
void buf_eatstring(buffer *buf) {
|
||||
|
||||
1
buffer.h
1
buffer.h
@@ -55,6 +55,7 @@ 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);
|
||||
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);
|
||||
|
||||
@@ -58,7 +58,7 @@ struct Channel {
|
||||
unsigned int recvmaxpacket, transmaxpacket;
|
||||
void* typedata; /* a pointer to type specific data */
|
||||
int writefd; /* read from wire, written to insecure side */
|
||||
int readfd; /* read from insecure size, written to wire */
|
||||
int readfd; /* read from insecure side, written to wire */
|
||||
int errfd; /* used like writefd or readfd, depending if it's client or server.
|
||||
Doesn't exactly belong here, but is cleaner here */
|
||||
circbuffer *writebuf; /* data from the wire, for local consumption */
|
||||
|
||||
@@ -50,6 +50,10 @@ struct ChanSess {
|
||||
|
||||
/* exit details */
|
||||
struct exitinfo exit;
|
||||
|
||||
/* Used to set $SSH_CONNECTION in the child session.
|
||||
Is only set temporarily before forking */
|
||||
char *connection_string;
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
struct Listener * x11listener;
|
||||
@@ -60,7 +64,7 @@ struct ChanSess {
|
||||
unsigned char x11singleconn;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
struct Listener * agentlistener;
|
||||
char * agentfile;
|
||||
char * agentdir;
|
||||
@@ -81,6 +85,7 @@ void cli_chansess_winchange();
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
void cli_send_netcat_request();
|
||||
#endif
|
||||
void cli_start_send_channel_request(struct Channel *channel, unsigned char *type);
|
||||
|
||||
void svr_chansessinitialise();
|
||||
extern const struct ChanType svrchansess;
|
||||
|
||||
10
circbuffer.c
10
circbuffer.c
@@ -33,7 +33,7 @@ circbuffer * cbuf_new(unsigned int size) {
|
||||
circbuffer *cbuf = NULL;
|
||||
|
||||
if (size > MAX_CBUF_SIZE) {
|
||||
dropbear_exit("bad cbuf size");
|
||||
dropbear_exit("Bad cbuf size");
|
||||
}
|
||||
|
||||
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
|
||||
@@ -101,7 +101,7 @@ unsigned int cbuf_writelen(circbuffer *cbuf) {
|
||||
|
||||
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
|
||||
if (len > cbuf_readlen(cbuf)) {
|
||||
dropbear_exit("bad cbuf read");
|
||||
dropbear_exit("Bad cbuf read");
|
||||
}
|
||||
|
||||
return &cbuf->data[cbuf->readpos];
|
||||
@@ -110,7 +110,7 @@ unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
|
||||
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
|
||||
|
||||
if (len > cbuf_writelen(cbuf)) {
|
||||
dropbear_exit("bad cbuf write");
|
||||
dropbear_exit("Bad cbuf write");
|
||||
}
|
||||
|
||||
return &cbuf->data[cbuf->writepos];
|
||||
@@ -118,7 +118,7 @@ unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
|
||||
|
||||
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
|
||||
if (len > cbuf_writelen(cbuf)) {
|
||||
dropbear_exit("bad cbuf write");
|
||||
dropbear_exit("Bad cbuf write");
|
||||
}
|
||||
|
||||
cbuf->used += len;
|
||||
@@ -129,7 +129,7 @@ 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_exit("Bad cbuf read");
|
||||
}
|
||||
|
||||
dropbear_assert(cbuf->used >= len);
|
||||
|
||||
311
cli-agentfwd.c
Normal file
311
cli-agentfwd.c
Normal file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2005 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
|
||||
#include "agentfwd.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
#include "dbutil.h"
|
||||
#include "chansession.h"
|
||||
#include "channel.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "random.h"
|
||||
#include "listener.h"
|
||||
#include "runopts.h"
|
||||
#include "atomicio.h"
|
||||
#include "signkey.h"
|
||||
#include "auth.h"
|
||||
|
||||
/* The protocol implemented to talk to OpenSSH's SSH2 agent is documented in
|
||||
PROTOCOL.agent in recent OpenSSH source distributions (5.1p1 has it). */
|
||||
|
||||
static int new_agent_chan(struct Channel * channel);
|
||||
|
||||
const struct ChanType cli_chan_agent = {
|
||||
0, /* sepfds */
|
||||
"auth-agent@openssh.com",
|
||||
new_agent_chan,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int connect_agent() {
|
||||
|
||||
int fd = -1;
|
||||
char* agent_sock = NULL;
|
||||
|
||||
agent_sock = getenv("SSH_AUTH_SOCK");
|
||||
if (agent_sock == NULL)
|
||||
return -1;
|
||||
|
||||
fd = connect_unix(agent_sock);
|
||||
|
||||
if (fd < 0) {
|
||||
dropbear_log(LOG_INFO, "Failed to connect to agent");
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
// handle a request for a connection to the locally running ssh-agent
|
||||
// or forward.
|
||||
static int new_agent_chan(struct Channel * channel) {
|
||||
|
||||
int fd = -1;
|
||||
|
||||
if (!cli_opts.agent_fwd)
|
||||
return SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
|
||||
fd = connect_agent();
|
||||
if (cli_opts.agent_fd < 0) {
|
||||
return SSH_OPEN_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
setnonblocking(fd);
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, fd);
|
||||
|
||||
channel->readfd = fd;
|
||||
channel->writefd = fd;
|
||||
|
||||
// success
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sends a request to the agent, returning a newly allocated buffer
|
||||
* with the response */
|
||||
/* This function will block waiting for a response - it will
|
||||
* only be used by client authentication (not for forwarded requests)
|
||||
* won't cause problems for interactivity. */
|
||||
/* Packet format (from draft-ylonen)
|
||||
4 bytes Length, msb first. Does not include length itself.
|
||||
1 byte Packet type. The value 255 is reserved for future extensions.
|
||||
data Any data, depending on packet type. Encoding as in the ssh packet
|
||||
protocol.
|
||||
*/
|
||||
static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
|
||||
buffer * payload = NULL;
|
||||
buffer * inbuf = NULL;
|
||||
size_t readlen = 0;
|
||||
ssize_t ret;
|
||||
const int fd = cli_opts.agent_fd;
|
||||
unsigned int data_len = 0;
|
||||
if (data)
|
||||
{
|
||||
data_len = data->len;
|
||||
}
|
||||
|
||||
payload = buf_new(4 + 1 + data_len);
|
||||
|
||||
buf_putint(payload, 1 + data_len);
|
||||
buf_putbyte(payload, type);
|
||||
if (data) {
|
||||
buf_putbytes(payload, data->data, data->len);
|
||||
}
|
||||
buf_setpos(payload, 0);
|
||||
|
||||
ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len);
|
||||
if ((size_t)ret != payload->len) {
|
||||
TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno)))
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf_free(payload);
|
||||
payload = NULL;
|
||||
TRACE(("Wrote out bytes for agent_request"))
|
||||
/* Now we read the response */
|
||||
inbuf = buf_new(4);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, 4), 4);
|
||||
if (ret != 4) {
|
||||
TRACE(("read of length failed for agent_request"))
|
||||
goto out;
|
||||
}
|
||||
buf_setpos(inbuf, 0);
|
||||
buf_setlen(inbuf, ret);
|
||||
|
||||
readlen = buf_getint(inbuf);
|
||||
if (readlen > MAX_AGENT_REPLY) {
|
||||
TRACE(("agent reply is too big"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE(("agent_request readlen is %d", readlen))
|
||||
|
||||
buf_resize(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
|
||||
if ((size_t)ret != readlen) {
|
||||
TRACE(("read of data failed for agent_request"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrwritepos(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
TRACE(("agent_request success, length %d", readlen))
|
||||
|
||||
out:
|
||||
if (payload)
|
||||
buf_free(payload);
|
||||
|
||||
return inbuf;
|
||||
}
|
||||
|
||||
static void agent_get_key_list(m_list * ret_list)
|
||||
{
|
||||
buffer * inbuf = NULL;
|
||||
unsigned int num = 0;
|
||||
unsigned char packet_type;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
inbuf = agent_request(SSH2_AGENTC_REQUEST_IDENTITIES, NULL);
|
||||
if (!inbuf) {
|
||||
TRACE(("agent_request failed returning identities"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The reply has a format of:
|
||||
byte SSH2_AGENT_IDENTITIES_ANSWER
|
||||
uint32 num_keys
|
||||
Followed by zero or more consecutive keys, encoded as:
|
||||
string key_blob
|
||||
string key_comment
|
||||
*/
|
||||
packet_type = buf_getbyte(inbuf);
|
||||
if (packet_type != SSH2_AGENT_IDENTITIES_ANSWER) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
num = buf_getint(inbuf);
|
||||
for (i = 0; i < num; i++) {
|
||||
sign_key * pubkey = NULL;
|
||||
int key_type = DROPBEAR_SIGNKEY_ANY;
|
||||
buffer * key_buf;
|
||||
|
||||
/* each public key is encoded as a string */
|
||||
key_buf = buf_getstringbuf(inbuf);
|
||||
pubkey = new_sign_key();
|
||||
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;
|
||||
|
||||
list_append(ret_list, pubkey);
|
||||
|
||||
/* We'll ignore the comment for now. might want it later.*/
|
||||
buf_eatstring(inbuf);
|
||||
}
|
||||
|
||||
out:
|
||||
if (inbuf) {
|
||||
buf_free(inbuf);
|
||||
inbuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_setup_agent(struct Channel *channel) {
|
||||
if (!getenv("SSH_AUTH_SOCK")) {
|
||||
return;
|
||||
}
|
||||
|
||||
cli_start_send_channel_request(channel, "auth-agent-req@openssh.com");
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
/* Returned keys are prepended to ret_list, which will
|
||||
be updated. */
|
||||
void cli_load_agent_keys(m_list *ret_list) {
|
||||
/* agent_fd will be closed after successful auth */
|
||||
cli_opts.agent_fd = connect_agent();
|
||||
if (cli_opts.agent_fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
agent_get_key_list(ret_list);
|
||||
}
|
||||
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
buffer *request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
|
||||
buffer *response;
|
||||
unsigned int keylen, siglen;
|
||||
int packet_type;
|
||||
|
||||
/* Request format
|
||||
byte SSH2_AGENTC_SIGN_REQUEST
|
||||
string key_blob
|
||||
string data
|
||||
uint32 flags
|
||||
*/
|
||||
/* We write the key, then figure how long it was and write that */
|
||||
//buf_putint(request_data, 0);
|
||||
buf_put_pub_key(request_data, key, key->type);
|
||||
keylen = request_data->len - 4;
|
||||
//buf_setpos(request_data, 0);
|
||||
//buf_putint(request_data, keylen);
|
||||
|
||||
//buf_setpos(request_data, request_data->len);
|
||||
buf_putstring(request_data, data, len);
|
||||
buf_putint(request_data, 0);
|
||||
|
||||
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
|
||||
buf_free(request_data);
|
||||
|
||||
if (!response) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
packet_type = buf_getbyte(response);
|
||||
if (packet_type != SSH2_AGENT_SIGN_RESPONSE) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Response format
|
||||
byte SSH2_AGENT_SIGN_RESPONSE
|
||||
string signature_blob
|
||||
*/
|
||||
siglen = buf_getint(response);
|
||||
buf_putbytes(sigblob, buf_getptr(response, siglen), siglen);
|
||||
buf_free(response);
|
||||
|
||||
return;
|
||||
fail:
|
||||
/* XXX don't fail badly here. instead propagate a failure code back up to
|
||||
the cli auth pubkey code, and just remove this key from the list of
|
||||
ones to try. */
|
||||
dropbear_exit("Agent failed signing key");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -91,7 +91,7 @@ void recv_msg_userauth_banner() {
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s\n", banner);
|
||||
fprintf(stderr, "%s\n", banner);
|
||||
|
||||
out:
|
||||
m_free(banner);
|
||||
@@ -234,6 +234,10 @@ void recv_msg_userauth_success() {
|
||||
ses.authstate.authdone = 1;
|
||||
cli_ses.state = USERAUTH_SUCCESS_RCVD;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_NONE;
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
cli_auth_pubkey_cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void cli_auth_try() {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "ssh.h"
|
||||
#include "runopts.h"
|
||||
#include "auth.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
|
||||
@@ -37,30 +38,23 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
|
||||
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
|
||||
* We use it to remove the key we tried from the list */
|
||||
void cli_pubkeyfail() {
|
||||
|
||||
struct SignKeyList *keyitem;
|
||||
struct SignKeyList **previtem;
|
||||
|
||||
TRACE(("enter cli_pubkeyfail"))
|
||||
previtem = &cli_opts.privkeys;
|
||||
|
||||
/* Find the key we failed with, and remove it */
|
||||
for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
|
||||
if (keyitem == cli_ses.lastprivkey) {
|
||||
*previtem = keyitem->next;
|
||||
m_list_elem *iter;
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
|
||||
sign_key *iter_key = (sign_key*)iter->item;
|
||||
|
||||
if (iter_key == cli_ses.lastprivkey)
|
||||
{
|
||||
/* found the failing key */
|
||||
list_remove(iter);
|
||||
sign_key_free(iter_key);
|
||||
cli_ses.lastprivkey = NULL;
|
||||
return;
|
||||
}
|
||||
previtem = &keyitem;
|
||||
}
|
||||
|
||||
sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */
|
||||
m_free(cli_ses.lastprivkey);
|
||||
|
||||
TRACE(("leave cli_pubkeyfail"))
|
||||
}
|
||||
|
||||
void recv_msg_userauth_pk_ok() {
|
||||
|
||||
struct SignKeyList *keyitem = NULL;
|
||||
m_list_elem *iter;
|
||||
buffer* keybuf = NULL;
|
||||
char* algotype = NULL;
|
||||
unsigned int algolen;
|
||||
@@ -80,9 +74,9 @@ void recv_msg_userauth_pk_ok() {
|
||||
|
||||
/* Iterate through our keys, find which one it was that matched, and
|
||||
* send a real request with that key */
|
||||
for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
|
||||
|
||||
if (keyitem->type != keytype) {
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
|
||||
sign_key *key = (sign_key*)iter->item;
|
||||
if (key->type != keytype) {
|
||||
/* Types differed */
|
||||
TRACE(("types differed"))
|
||||
continue;
|
||||
@@ -90,7 +84,7 @@ void recv_msg_userauth_pk_ok() {
|
||||
|
||||
/* Now we compare the contents of the key */
|
||||
keybuf->pos = keybuf->len = 0;
|
||||
buf_put_pub_key(keybuf, keyitem->key, keytype);
|
||||
buf_put_pub_key(keybuf, key, keytype);
|
||||
buf_setpos(keybuf, 0);
|
||||
buf_incrpos(keybuf, 4); /* first int is the length of the remainder (ie
|
||||
remotelen) which has already been taken from
|
||||
@@ -114,11 +108,11 @@ void recv_msg_userauth_pk_ok() {
|
||||
}
|
||||
buf_free(keybuf);
|
||||
|
||||
if (keyitem != NULL) {
|
||||
if (iter != NULL) {
|
||||
TRACE(("matching key"))
|
||||
/* XXX TODO: if it's an encrypted key, here we ask for their
|
||||
* password */
|
||||
send_msg_userauth_pubkey(keyitem->key, keytype, 1);
|
||||
send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1);
|
||||
} else {
|
||||
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
|
||||
}
|
||||
@@ -126,6 +120,25 @@ void recv_msg_userauth_pk_ok() {
|
||||
TRACE(("leave recv_msg_userauth_pk_ok"))
|
||||
}
|
||||
|
||||
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len)
|
||||
{
|
||||
if (key->source == SIGNKEY_SOURCE_AGENT) {
|
||||
/* Format the agent signature ourselves, as buf_put_sign would. */
|
||||
buffer *sigblob;
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
agent_buf_sign(sigblob, key, data, len);
|
||||
buf_setpos(sigblob, 0);
|
||||
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
|
||||
sigblob->len);
|
||||
|
||||
buf_free(sigblob);
|
||||
} else {
|
||||
buf_put_sign(buf, key, type, data, len);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* TODO: make it take an agent reference to use as well */
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
@@ -161,7 +174,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
|
||||
buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
|
||||
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
|
||||
buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
|
||||
cli_buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
|
||||
buf_free(sigbuf); /* Nothing confidential in the buffer */
|
||||
}
|
||||
|
||||
@@ -169,20 +182,41 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
TRACE(("leave send_msg_userauth_pubkey"))
|
||||
}
|
||||
|
||||
/* Returns 1 if a key was tried */
|
||||
int cli_auth_pubkey() {
|
||||
|
||||
TRACE(("enter cli_auth_pubkey"))
|
||||
|
||||
if (cli_opts.privkeys != NULL) {
|
||||
if (!cli_opts.agent_keys_loaded) {
|
||||
/* get the list of available keys from the agent */
|
||||
cli_load_agent_keys(cli_opts.privkeys);
|
||||
cli_opts.agent_keys_loaded = 1;
|
||||
}
|
||||
|
||||
if (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
/* Send a trial request */
|
||||
send_msg_userauth_pubkey(cli_opts.privkeys->key,
|
||||
cli_opts.privkeys->type, 0);
|
||||
cli_ses.lastprivkey = cli_opts.privkeys;
|
||||
send_msg_userauth_pubkey(key, key->type, 0);
|
||||
cli_ses.lastprivkey = key;
|
||||
TRACE(("leave cli_auth_pubkey-success"))
|
||||
return 1;
|
||||
} else {
|
||||
/* no more keys left */
|
||||
TRACE(("leave cli_auth_pubkey-failure"))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_auth_pubkey_cleanup() {
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
m_close(cli_opts.agent_fd);
|
||||
cli_opts.agent_fd = -1;
|
||||
#endif
|
||||
|
||||
while (cli_opts.privkeys->first) {
|
||||
sign_key * key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
}
|
||||
}
|
||||
#endif /* Pubkey auth */
|
||||
|
||||
@@ -33,13 +33,12 @@
|
||||
#include "runopts.h"
|
||||
#include "termcodes.h"
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
static void cli_closechansess(struct Channel *channel);
|
||||
static int cli_initchansess(struct Channel *channel);
|
||||
static void cli_chansessreq(struct Channel *channel);
|
||||
|
||||
static void start_channel_request(struct Channel *channel, unsigned char *type);
|
||||
|
||||
static void send_chansess_pty_req(struct Channel *channel);
|
||||
static void send_chansess_shell_req(struct Channel *channel);
|
||||
|
||||
@@ -92,7 +91,7 @@ static void cli_closechansess(struct Channel *UNUSED(channel)) {
|
||||
|
||||
}
|
||||
|
||||
static void start_channel_request(struct Channel *channel,
|
||||
void cli_start_send_channel_request(struct Channel *channel,
|
||||
unsigned char *type) {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
@@ -287,7 +286,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_chansess_pty_req"))
|
||||
|
||||
start_channel_request(channel, "pty-req");
|
||||
cli_start_send_channel_request(channel, "pty-req");
|
||||
|
||||
/* Don't want replies */
|
||||
buf_putbyte(ses.writepayload, 0);
|
||||
@@ -309,7 +308,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
|
||||
|
||||
/* Set up a window-change handler */
|
||||
if (signal(SIGWINCH, sigwinch_handler) == SIG_ERR) {
|
||||
dropbear_exit("signal error");
|
||||
dropbear_exit("Signal error");
|
||||
}
|
||||
TRACE(("leave send_chansess_pty_req"))
|
||||
}
|
||||
@@ -330,7 +329,7 @@ static void send_chansess_shell_req(struct Channel *channel) {
|
||||
reqtype = "shell";
|
||||
}
|
||||
|
||||
start_channel_request(channel, reqtype);
|
||||
cli_start_send_channel_request(channel, reqtype);
|
||||
|
||||
/* XXX TODO */
|
||||
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
|
||||
@@ -361,6 +360,12 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
cli_init_stdpipe_sess(channel);
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
if (cli_opts.agent_fwd) {
|
||||
cli_setup_agent(channel);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.wantpty) {
|
||||
send_chansess_pty_req(channel);
|
||||
}
|
||||
@@ -376,20 +381,20 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
|
||||
static const struct ChanType cli_chan_netcat = {
|
||||
0, /* sepfds */
|
||||
"direct-tcpip",
|
||||
cli_init_stdpipe_sess, /* inithandler */
|
||||
NULL,
|
||||
NULL,
|
||||
cli_closechansess
|
||||
};
|
||||
|
||||
void cli_send_netcat_request() {
|
||||
|
||||
const unsigned char* source_host = "127.0.0.1";
|
||||
const int source_port = 22;
|
||||
|
||||
const struct ChanType cli_chan_netcat = {
|
||||
0, /* sepfds */
|
||||
"direct-tcpip",
|
||||
cli_init_stdpipe_sess, /* inithandler */
|
||||
NULL,
|
||||
NULL,
|
||||
cli_closechansess
|
||||
};
|
||||
|
||||
cli_opts.wantpty = 0;
|
||||
|
||||
if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat)
|
||||
@@ -424,16 +429,3 @@ void cli_send_chansess_request() {
|
||||
TRACE(("leave cli_send_chansess_request"))
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
while (cli_opts.localfwds != NULL) {
|
||||
ret = cli_localtcp(cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
|
||||
cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
#endif
|
||||
|
||||
@@ -304,7 +304,7 @@ 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, ses.remotehost, hostlen);
|
||||
buf_putbytes(line, cli_opts.remotehost, hostlen);
|
||||
buf_putbyte(line, ' ');
|
||||
buf_putbytes(line, algoname, algolen);
|
||||
buf_putbyte(line, ' ');
|
||||
@@ -327,4 +327,5 @@ out:
|
||||
if (line != NULL) {
|
||||
buf_free(line);
|
||||
}
|
||||
m_free(fingerprint);
|
||||
}
|
||||
|
||||
20
cli-main.c
20
cli-main.c
@@ -32,7 +32,9 @@
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param);
|
||||
static void cli_dropbear_log(int priority, const char* format, va_list param);
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
static void cli_proxy_cmd(int *sock_in, int *sock_out);
|
||||
#endif
|
||||
|
||||
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
|
||||
@@ -43,8 +45,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
int sock_in, sock_out;
|
||||
char* error = NULL;
|
||||
char* hostandport;
|
||||
int len;
|
||||
|
||||
_dropbear_exit = cli_dropbear_exit;
|
||||
_dropbear_log = cli_dropbear_log;
|
||||
@@ -63,6 +63,7 @@ int main(int argc, char ** argv) {
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
if (cli_opts.proxycmd) {
|
||||
cli_proxy_cmd(&sock_in, &sock_out);
|
||||
m_free(cli_opts.proxycmd);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -75,14 +76,7 @@ int main(int argc, char ** argv) {
|
||||
dropbear_exit("%s", error);
|
||||
}
|
||||
|
||||
/* Set up the host:port log */
|
||||
len = strlen(cli_opts.remotehost);
|
||||
len += 10; /* 16 bit port and leeway*/
|
||||
hostandport = (char*)m_malloc(len);
|
||||
snprintf(hostandport, len, "%s:%s",
|
||||
cli_opts.remotehost, cli_opts.remoteport);
|
||||
|
||||
cli_session(sock_in, sock_out, hostandport);
|
||||
cli_session(sock_in, sock_out);
|
||||
|
||||
/* not reached */
|
||||
return -1;
|
||||
@@ -94,11 +88,11 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
char fmtbuf[300];
|
||||
|
||||
if (!sessinitdone) {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "exited: %s",
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
|
||||
format);
|
||||
} else {
|
||||
snprintf(fmtbuf, sizeof(fmtbuf),
|
||||
"connection to %s@%s:%s exited: %s",
|
||||
"Connection to %s@%s:%s exited: %s",
|
||||
cli_opts.username, cli_opts.remotehost,
|
||||
cli_opts.remoteport, format);
|
||||
}
|
||||
@@ -132,6 +126,7 @@ static void exec_proxy_cmd(void *user_data_cmd) {
|
||||
dropbear_exit("Failed to run '%s'\n", cmd);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
static void cli_proxy_cmd(int *sock_in, int *sock_out) {
|
||||
int ret;
|
||||
|
||||
@@ -144,3 +139,4 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out) {
|
||||
*sock_in = *sock_out = -1;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_CLI_PROXYCMD
|
||||
|
||||
196
cli-runopts.c
196
cli-runopts.c
@@ -29,6 +29,7 @@
|
||||
#include "dbutil.h"
|
||||
#include "algo.h"
|
||||
#include "tcpfwd.h"
|
||||
#include "list.h"
|
||||
|
||||
cli_runopts cli_opts; /* GLOBAL */
|
||||
|
||||
@@ -40,7 +41,7 @@ static void fill_own_user();
|
||||
static void loadidentityfile(const char* filename);
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
static void addforward(const char* str, struct TCPFwdList** fwdlist);
|
||||
static void addforward(const char* str, m_list *fwdlist);
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
static void add_netcat(const char *str);
|
||||
@@ -66,12 +67,15 @@ static void printhelp() {
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
"-i <identityfile> (multiple allowed)\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
"-A Enable agent auth forwarding\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
"-L <listenport:remotehost:remoteport> Local port forwarding\n"
|
||||
"-L <[listenaddress:]listenport:remotehost:remoteport> Local port forwarding\n"
|
||||
"-g Allow remote hosts to connect to forwarded ports\n"
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
"-R <listenport:remotehost:remoteport> Remote port forwarding\n"
|
||||
"-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n"
|
||||
#endif
|
||||
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
|
||||
"-K <keepalive> (0 is never, default %d)\n"
|
||||
@@ -91,7 +95,6 @@ static void printhelp() {
|
||||
}
|
||||
|
||||
void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
unsigned int i, j;
|
||||
char ** next = 0;
|
||||
unsigned int cmdlen;
|
||||
@@ -112,6 +115,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
char* recv_window_arg = NULL;
|
||||
char* keepalive_arg = NULL;
|
||||
char* idle_timeout_arg = NULL;
|
||||
char *host_arg = NULL;
|
||||
|
||||
/* see printhelp() for options */
|
||||
cli_opts.progname = argv[0];
|
||||
@@ -125,17 +129,24 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.always_accept_key = 0;
|
||||
cli_opts.is_subsystem = 0;
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
cli_opts.privkeys = NULL;
|
||||
cli_opts.privkeys = list_new();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
cli_opts.localfwds = NULL;
|
||||
cli_opts.localfwds = list_new();
|
||||
opts.listen_fwd_all = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
cli_opts.remotefwds = NULL;
|
||||
cli_opts.remotefwds = list_new();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
cli_opts.agent_fwd = 0;
|
||||
cli_opts.agent_keys_loaded = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
cli_opts.proxycmd = NULL;
|
||||
#endif
|
||||
#ifndef DISABLE_ZLIB
|
||||
opts.enable_compress = 1;
|
||||
#endif
|
||||
/* not yet
|
||||
opts.ipv4 = 1;
|
||||
@@ -158,7 +169,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
if (nextisremote) {
|
||||
TRACE(("nextisremote true"))
|
||||
addforward(argv[i], &cli_opts.remotefwds);
|
||||
addforward(argv[i], cli_opts.remotefwds);
|
||||
nextisremote = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -166,7 +177,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
if (nextislocal) {
|
||||
TRACE(("nextislocal true"))
|
||||
addforward(argv[i], &cli_opts.localfwds);
|
||||
addforward(argv[i], cli_opts.localfwds);
|
||||
nextislocal = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -266,6 +277,11 @@ void cli_getopts(int argc, char ** argv) {
|
||||
case 'I':
|
||||
next = &idle_timeout_arg;
|
||||
break;
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
case 'A':
|
||||
cli_opts.agent_fwd = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DEBUG_TRACE
|
||||
case 'v':
|
||||
debug_trace = 1;
|
||||
@@ -304,12 +320,8 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
/* Either the hostname or commands */
|
||||
|
||||
if (cli_opts.remotehost == NULL) {
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
parse_multihop_hostname(argv[i], argv[0]);
|
||||
#else
|
||||
parse_hostname(argv[i]);
|
||||
#endif
|
||||
if (host_arg == NULL) {
|
||||
host_arg = argv[i];
|
||||
} else {
|
||||
|
||||
/* this is part of the commands to send - after this we
|
||||
@@ -338,7 +350,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
/* And now a few sanity checks and setup */
|
||||
|
||||
if (cli_opts.remotehost == NULL) {
|
||||
if (host_arg == NULL) {
|
||||
printhelp();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -359,7 +371,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
if (cli_opts.backgrounded && cli_opts.cmd == NULL
|
||||
&& cli_opts.no_cmd == 0) {
|
||||
dropbear_exit("command required for -f");
|
||||
dropbear_exit("Command required for -f");
|
||||
}
|
||||
|
||||
if (recv_window_arg) {
|
||||
@@ -369,15 +381,19 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
if (keepalive_arg) {
|
||||
if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
|
||||
unsigned int val;
|
||||
if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
|
||||
}
|
||||
opts.keepalive_secs = val;
|
||||
}
|
||||
|
||||
if (idle_timeout_arg) {
|
||||
if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
|
||||
unsigned int val;
|
||||
if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
|
||||
}
|
||||
opts.idle_timeout_secs = val;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
@@ -385,36 +401,73 @@ void cli_getopts(int argc, char ** argv) {
|
||||
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* The hostname gets set up last, since
|
||||
* in multi-hop mode it will require knowledge
|
||||
* of other flags such as -i */
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
parse_multihop_hostname(host_arg, argv[0]);
|
||||
#else
|
||||
parse_hostname(host_arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename) {
|
||||
|
||||
struct SignKeyList * nextkey;
|
||||
sign_key *key;
|
||||
int keytype;
|
||||
|
||||
key = new_sign_key();
|
||||
keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
|
||||
|
||||
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
|
||||
sign_key_free(key);
|
||||
|
||||
} else {
|
||||
|
||||
nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
|
||||
nextkey->key = key;
|
||||
nextkey->next = cli_opts.privkeys;
|
||||
nextkey->type = keytype;
|
||||
cli_opts.privkeys = nextkey;
|
||||
key->type = keytype;
|
||||
key->source = SIGNKEY_SOURCE_RAW_FILE;
|
||||
key->filename = m_strdup(filename);
|
||||
list_append(cli_opts.privkeys, key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
|
||||
static char*
|
||||
multihop_passthrough_args() {
|
||||
char *ret;
|
||||
int total;
|
||||
unsigned int len = 0;
|
||||
m_list_elem *iter;
|
||||
/* Fill out -i and -W options that make sense for all
|
||||
* the intermediate processes */
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
len += 3 + strlen(key->filename);
|
||||
}
|
||||
len += 20; // space for -W <size>, terminator.
|
||||
ret = m_malloc(len);
|
||||
total = 0;
|
||||
|
||||
if (opts.recv_window != DEFAULT_RECV_WINDOW)
|
||||
{
|
||||
int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window);
|
||||
total += written;
|
||||
}
|
||||
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
const size_t size = len - total;
|
||||
int written = snprintf(ret+total, size, "-i %s", key->filename);
|
||||
dropbear_assert((unsigned int)written < size);
|
||||
total += written;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Sets up 'onion-forwarding' connections. This will spawn
|
||||
* a separate dbclient process for each hop.
|
||||
* As an example, if the cmdline is
|
||||
@@ -429,7 +482,8 @@ static void loadidentityfile(const char* filename) {
|
||||
*/
|
||||
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
|
||||
char *userhostarg = NULL;
|
||||
char *last_hop = NULL;;
|
||||
char *hostbuf = NULL;
|
||||
char *last_hop = NULL;
|
||||
char *remainder = NULL;
|
||||
|
||||
/* both scp and rsync parse a user@host argument
|
||||
@@ -441,11 +495,12 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
|
||||
&& strchr(cli_opts.username, ',')
|
||||
&& strchr(cli_opts.username, '@')) {
|
||||
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
|
||||
userhostarg = m_malloc(len);
|
||||
snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg);
|
||||
hostbuf = m_malloc(len);
|
||||
snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
|
||||
} else {
|
||||
userhostarg = m_strdup(orighostarg);
|
||||
hostbuf = m_strdup(orighostarg);
|
||||
}
|
||||
userhostarg = hostbuf;
|
||||
|
||||
last_hop = strrchr(userhostarg, ',');
|
||||
if (last_hop) {
|
||||
@@ -463,19 +518,28 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
|
||||
if (last_hop) {
|
||||
/* Set up the proxycmd */
|
||||
unsigned int cmd_len = 0;
|
||||
char *passthrough_args = multihop_passthrough_args();
|
||||
if (cli_opts.proxycmd) {
|
||||
dropbear_exit("-J can't be used with multihop mode");
|
||||
}
|
||||
if (cli_opts.remoteport == NULL) {
|
||||
cli_opts.remoteport = "22";
|
||||
}
|
||||
cmd_len = strlen(remainder)
|
||||
cmd_len = strlen(argv0) + strlen(remainder)
|
||||
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
|
||||
+ strlen(argv0) + 30;
|
||||
+ strlen(passthrough_args)
|
||||
+ 30;
|
||||
cli_opts.proxycmd = m_malloc(cmd_len);
|
||||
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s",
|
||||
argv0, cli_opts.remotehost, cli_opts.remoteport, remainder);
|
||||
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
|
||||
argv0, cli_opts.remotehost, cli_opts.remoteport,
|
||||
passthrough_args, remainder);
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* The stream will be incompressible since it's encrypted. */
|
||||
opts.enable_compress = 0;
|
||||
#endif
|
||||
m_free(passthrough_args);
|
||||
}
|
||||
m_free(hostbuf);
|
||||
}
|
||||
#endif /* !ENABLE_CLI_MULTIHOP */
|
||||
|
||||
@@ -564,14 +628,16 @@ static void fill_own_user() {
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_ANYTCPFWD
|
||||
/* Turn a "listenport:remoteaddr:remoteport" string into into a forwarding
|
||||
/* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
|
||||
* set, and add it to the forwarding list */
|
||||
static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
|
||||
static void addforward(const char* origstr, m_list *fwdlist) {
|
||||
|
||||
char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL;
|
||||
char * listenaddr = NULL;
|
||||
char * listenport = NULL;
|
||||
char * connectport = NULL;
|
||||
char * connectaddr = NULL;
|
||||
struct TCPFwdList* newfwd = NULL;
|
||||
char * connectport = NULL;
|
||||
struct TCPFwdEntry* newfwd = NULL;
|
||||
char * str = NULL;
|
||||
|
||||
TRACE(("enter addforward"))
|
||||
@@ -580,25 +646,43 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
|
||||
is never free()d. */
|
||||
str = m_strdup(origstr);
|
||||
|
||||
listenport = str;
|
||||
part1 = str;
|
||||
|
||||
connectaddr = strchr(str, ':');
|
||||
if (connectaddr == NULL) {
|
||||
TRACE(("connectaddr == NULL"))
|
||||
part2 = strchr(str, ':');
|
||||
if (part2 == NULL) {
|
||||
TRACE(("part2 == NULL"))
|
||||
goto fail;
|
||||
}
|
||||
*connectaddr = '\0';
|
||||
connectaddr++;
|
||||
*part2 = '\0';
|
||||
part2++;
|
||||
|
||||
connectport = strchr(connectaddr, ':');
|
||||
if (connectport == NULL) {
|
||||
TRACE(("connectport == NULL"))
|
||||
part3 = strchr(part2, ':');
|
||||
if (part3 == NULL) {
|
||||
TRACE(("part3 == NULL"))
|
||||
goto fail;
|
||||
}
|
||||
*connectport = '\0';
|
||||
connectport++;
|
||||
*part3 = '\0';
|
||||
part3++;
|
||||
|
||||
newfwd = (struct TCPFwdList*)m_malloc(sizeof(struct TCPFwdList));
|
||||
part4 = strchr(part3, ':');
|
||||
if (part4) {
|
||||
*part4 = '\0';
|
||||
part4++;
|
||||
}
|
||||
|
||||
if (part4) {
|
||||
listenaddr = part1;
|
||||
listenport = part2;
|
||||
connectaddr = part3;
|
||||
connectport = part4;
|
||||
} else {
|
||||
listenaddr = NULL;
|
||||
listenport = part1;
|
||||
connectaddr = part2;
|
||||
connectport = part3;
|
||||
}
|
||||
|
||||
newfwd = m_malloc(sizeof(struct TCPFwdEntry));
|
||||
|
||||
/* Now we check the ports - note that the port ints are unsigned,
|
||||
* the check later only checks for >= MAX_PORT */
|
||||
@@ -612,6 +696,7 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
newfwd->listenaddr = listenaddr;
|
||||
newfwd->connectaddr = connectaddr;
|
||||
|
||||
if (newfwd->listenport > 65535) {
|
||||
@@ -625,8 +710,7 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
|
||||
}
|
||||
|
||||
newfwd->have_reply = 0;
|
||||
newfwd->next = *fwdlist;
|
||||
*fwdlist = newfwd;
|
||||
list_append(fwdlist, newfwd);
|
||||
|
||||
TRACE(("leave addforward: done"))
|
||||
return;
|
||||
|
||||
@@ -72,7 +72,7 @@ void recv_msg_service_accept() {
|
||||
&& strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) {
|
||||
|
||||
if (ses.authstate.authdone != 1) {
|
||||
dropbear_exit("request for connection before auth");
|
||||
dropbear_exit("Request for connection before auth");
|
||||
}
|
||||
|
||||
cli_ses.state = SERVICE_CONN_ACCEPT_RCVD;
|
||||
@@ -81,5 +81,5 @@ void recv_msg_service_accept() {
|
||||
return;
|
||||
}
|
||||
|
||||
dropbear_exit("unrecognised service accept");
|
||||
dropbear_exit("Unrecognised service accept");
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "service.h"
|
||||
#include "runopts.h"
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
static void cli_remoteclosed();
|
||||
static void cli_sessionloop();
|
||||
@@ -74,17 +75,20 @@ static const packettype cli_packettypes[] = {
|
||||
static const struct ChanType *cli_chantypes[] = {
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
&cli_chan_tcpremote,
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
&cli_chan_agent,
|
||||
#endif
|
||||
NULL /* Null termination */
|
||||
};
|
||||
|
||||
void cli_session(int sock_in, int sock_out, char* remotehost) {
|
||||
void cli_session(int sock_in, int sock_out) {
|
||||
|
||||
seedrandom();
|
||||
|
||||
crypto_init();
|
||||
|
||||
common_session_init(sock_in, sock_out, remotehost);
|
||||
common_session_init(sock_in, sock_out);
|
||||
|
||||
chaninitialise(cli_chantypes);
|
||||
|
||||
@@ -209,7 +213,7 @@ static void cli_sessionloop() {
|
||||
is confusing, though stdout/stderr could be useful. */
|
||||
devnull = open(_PATH_DEVNULL, O_RDONLY);
|
||||
if (devnull < 0) {
|
||||
dropbear_exit("opening /dev/null: %d %s",
|
||||
dropbear_exit("Opening /dev/null: %d %s",
|
||||
errno, strerror(errno));
|
||||
}
|
||||
dup2(devnull, STDIN_FILENO);
|
||||
@@ -231,7 +235,7 @@ static void cli_sessionloop() {
|
||||
cli_send_netcat_request();
|
||||
} else
|
||||
#endif
|
||||
if (!cli_opts.no_cmd) {
|
||||
if (!cli_opts.no_cmd) {
|
||||
cli_send_chansess_request();
|
||||
}
|
||||
TRACE(("leave cli_sessionloop: running"))
|
||||
@@ -294,7 +298,7 @@ static void cli_remoteclosed() {
|
||||
m_close(ses.sock_out);
|
||||
ses.sock_in = -1;
|
||||
ses.sock_out = -1;
|
||||
dropbear_exit("remote closed the connection");
|
||||
dropbear_exit("Remote closed the connection");
|
||||
}
|
||||
|
||||
/* Operates in-place turning dirty (untrusted potentially containing control
|
||||
|
||||
145
cli-tcpfwd.c
145
cli-tcpfwd.c
@@ -45,7 +45,9 @@ const struct ChanType cli_chan_tcpremote = {
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
|
||||
static int cli_localtcp(const char* listenaddr,
|
||||
unsigned int listenport,
|
||||
const char* remoteaddr,
|
||||
unsigned int remoteport);
|
||||
static const struct ChanType cli_chan_tcplocal = {
|
||||
1, /* sepfds */
|
||||
@@ -59,33 +61,33 @@ static const struct ChanType cli_chan_tcplocal = {
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
void setup_localtcp() {
|
||||
|
||||
m_list_elem *iter;
|
||||
int ret;
|
||||
|
||||
TRACE(("enter setup_localtcp"))
|
||||
|
||||
if (cli_opts.localfwds == NULL) {
|
||||
TRACE(("cli_opts.localfwds == NULL"))
|
||||
}
|
||||
|
||||
while (cli_opts.localfwds != NULL) {
|
||||
ret = cli_localtcp(cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
for (iter = cli_opts.localfwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry * fwd = (struct TCPFwdEntry*)iter->item;
|
||||
ret = cli_localtcp(
|
||||
fwd->listenaddr,
|
||||
fwd->listenport,
|
||||
fwd->connectaddr,
|
||||
fwd->connectport);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
|
||||
cli_opts.localfwds->listenport,
|
||||
cli_opts.localfwds->connectaddr,
|
||||
cli_opts.localfwds->connectport);
|
||||
}
|
||||
|
||||
cli_opts.localfwds = cli_opts.localfwds->next;
|
||||
dropbear_log(LOG_WARNING, "Failed local port forward %s:%d:%s:%d",
|
||||
fwd->listenaddr,
|
||||
fwd->listenport,
|
||||
fwd->connectaddr,
|
||||
fwd->connectport);
|
||||
}
|
||||
}
|
||||
TRACE(("leave setup_localtcp"))
|
||||
|
||||
}
|
||||
|
||||
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
|
||||
static int cli_localtcp(const char* listenaddr,
|
||||
unsigned int listenport,
|
||||
const char* remoteaddr,
|
||||
unsigned int remoteport) {
|
||||
|
||||
struct TCPListener* tcpinfo = NULL;
|
||||
@@ -99,10 +101,17 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
|
||||
tcpinfo->sendaddr = m_strdup(remoteaddr);
|
||||
tcpinfo->sendport = remoteport;
|
||||
|
||||
if (opts.listen_fwd_all) {
|
||||
tcpinfo->listenaddr = m_strdup("");
|
||||
} else {
|
||||
tcpinfo->listenaddr = m_strdup("localhost");
|
||||
if (listenaddr)
|
||||
{
|
||||
tcpinfo->listenaddr = m_strdup(listenaddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts.listen_fwd_all) {
|
||||
tcpinfo->listenaddr = m_strdup("");
|
||||
} else {
|
||||
tcpinfo->listenaddr = m_strdup("localhost");
|
||||
}
|
||||
}
|
||||
tcpinfo->listenport = listenport;
|
||||
|
||||
@@ -120,22 +129,15 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
|
||||
#endif /* ENABLE_CLI_LOCALTCPFWD */
|
||||
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
static void send_msg_global_request_remotetcp(int port) {
|
||||
static void send_msg_global_request_remotetcp(const char *addr, int port) {
|
||||
|
||||
char* listenspec = NULL;
|
||||
TRACE(("enter send_msg_global_request_remotetcp"))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
|
||||
buf_putstring(ses.writepayload, "tcpip-forward", 13);
|
||||
buf_putbyte(ses.writepayload, 1); /* want_reply */
|
||||
if (opts.listen_fwd_all) {
|
||||
listenspec = "";
|
||||
} else {
|
||||
listenspec = "localhost";
|
||||
}
|
||||
/* TODO: IPv6? */;
|
||||
buf_putstring(ses.writepayload, listenspec, strlen(listenspec));
|
||||
buf_putstring(ses.writepayload, addr, strlen(addr));
|
||||
buf_putint(ses.writepayload, port);
|
||||
|
||||
encrypt_packet();
|
||||
@@ -148,88 +150,84 @@ static void send_msg_global_request_remotetcp(int port) {
|
||||
* being in the same order as we sent the requests. This is the ordering
|
||||
* of the cli_opts.remotefwds list */
|
||||
void cli_recv_msg_request_success() {
|
||||
|
||||
/* Nothing in the packet. We just mark off that we have received the reply,
|
||||
* so that we can report failure for later ones. */
|
||||
struct TCPFwdList * iter = NULL;
|
||||
|
||||
iter = cli_opts.remotefwds;
|
||||
while (iter != NULL) {
|
||||
if (!iter->have_reply)
|
||||
{
|
||||
iter->have_reply = 1;
|
||||
m_list_elem * iter = NULL;
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->have_reply) {
|
||||
fwd->have_reply = 1;
|
||||
return;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_recv_msg_request_failure() {
|
||||
struct TCPFwdList * iter = NULL;
|
||||
|
||||
iter = cli_opts.remotefwds;
|
||||
while (iter != NULL) {
|
||||
if (!iter->have_reply)
|
||||
{
|
||||
iter->have_reply = 1;
|
||||
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", iter->listenport, iter->connectaddr, iter->connectport);
|
||||
m_list_elem *iter;
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->have_reply) {
|
||||
fwd->have_reply = 1;
|
||||
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", fwd->listenport, fwd->connectaddr, fwd->connectport);
|
||||
return;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
}
|
||||
|
||||
void setup_remotetcp() {
|
||||
|
||||
struct TCPFwdList * iter = NULL;
|
||||
|
||||
m_list_elem *iter;
|
||||
TRACE(("enter setup_remotetcp"))
|
||||
|
||||
if (cli_opts.remotefwds == NULL) {
|
||||
TRACE(("cli_opts.remotefwds == NULL"))
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->listenaddr)
|
||||
{
|
||||
// we store the addresses so that we can compare them
|
||||
// when the server sends them back
|
||||
if (opts.listen_fwd_all) {
|
||||
fwd->listenaddr = m_strdup("");
|
||||
} else {
|
||||
fwd->listenaddr = m_strdup("localhost");
|
||||
}
|
||||
}
|
||||
send_msg_global_request_remotetcp(fwd->listenaddr, fwd->listenport);
|
||||
}
|
||||
|
||||
iter = cli_opts.remotefwds;
|
||||
|
||||
while (iter != NULL) {
|
||||
send_msg_global_request_remotetcp(iter->listenport);
|
||||
iter = iter->next;
|
||||
}
|
||||
TRACE(("leave setup_remotetcp"))
|
||||
}
|
||||
|
||||
static int newtcpforwarded(struct Channel * channel) {
|
||||
|
||||
char *origaddr = NULL;
|
||||
unsigned int origport;
|
||||
struct TCPFwdList * iter = NULL;
|
||||
m_list_elem * iter = NULL;
|
||||
struct TCPFwdEntry *fwd;
|
||||
char portstring[NI_MAXSERV];
|
||||
int sock;
|
||||
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
|
||||
/* We don't care what address they connected to */
|
||||
buf_eatstring(ses.payload);
|
||||
|
||||
origaddr = buf_getstring(ses.payload, NULL);
|
||||
origport = buf_getint(ses.payload);
|
||||
|
||||
/* Find which port corresponds */
|
||||
iter = cli_opts.remotefwds;
|
||||
|
||||
while (iter != NULL) {
|
||||
if (origport == iter->listenport) {
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (origport == fwd->listenport
|
||||
&& (strcmp(origaddr, fwd->listenaddr) == 0)) {
|
||||
break;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
if (iter == NULL) {
|
||||
/* We didn't request forwarding on that port */
|
||||
dropbear_log(LOG_INFO, "Server send unrequested port, from port %d",
|
||||
origport);
|
||||
cleantext(origaddr);
|
||||
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
|
||||
origaddr, origport);
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
|
||||
sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
|
||||
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;
|
||||
@@ -246,6 +244,7 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
err = SSH_OPEN_IN_PROGRESS;
|
||||
|
||||
out:
|
||||
m_free(origaddr);
|
||||
TRACE(("leave newtcpdirect: err %d", err))
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
|
||||
static int void_cipher(const unsigned char* in, unsigned char* out,
|
||||
unsigned long len, void *cipher_state) {
|
||||
memcpy(out, in, len);
|
||||
if (in != out) {
|
||||
memmove(out, in, len);
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
@@ -166,11 +168,16 @@ algo_type sshhashes[] = {
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshcompress[] = {
|
||||
#ifndef DISABLE_ZLIB
|
||||
algo_type ssh_compress[] = {
|
||||
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
|
||||
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
#endif
|
||||
|
||||
algo_type ssh_nocompress[] = {
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
@@ -187,6 +194,7 @@ algo_type sshhostkey[] = {
|
||||
|
||||
algo_type sshkex[] = {
|
||||
{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
|
||||
{"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL},
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
@@ -223,13 +231,13 @@ void crypto_init() {
|
||||
|
||||
for (i = 0; regciphers[i] != NULL; i++) {
|
||||
if (register_cipher(regciphers[i]) == -1) {
|
||||
dropbear_exit("error registering crypto");
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; reghashes[i] != NULL; i++) {
|
||||
if (register_hash(reghashes[i]) == -1) {
|
||||
dropbear_exit("error registering crypto");
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -688,7 +688,7 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
||||
TRACE(("enter recv_msg_channel_data"))
|
||||
|
||||
if (channel->recv_eof) {
|
||||
dropbear_exit("received data after eof");
|
||||
dropbear_exit("Received data after eof");
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
@@ -1006,7 +1006,7 @@ void recv_msg_channel_open_confirmation() {
|
||||
channel = getchannel();
|
||||
|
||||
if (!channel->await_open) {
|
||||
dropbear_exit("unexpected channel reply");
|
||||
dropbear_exit("Unexpected channel reply");
|
||||
}
|
||||
channel->await_open = 0;
|
||||
|
||||
@@ -1038,7 +1038,7 @@ void recv_msg_channel_open_failure() {
|
||||
channel = getchannel();
|
||||
|
||||
if (!channel->await_open) {
|
||||
dropbear_exit("unexpected channel reply");
|
||||
dropbear_exit("Unexpected channel reply");
|
||||
}
|
||||
channel->await_open = 0;
|
||||
|
||||
|
||||
202
common-kex.c
202
common-kex.c
@@ -33,9 +33,11 @@
|
||||
#include "packet.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "runopts.h"
|
||||
|
||||
/* diffie-hellman-group1-sha1 value for p */
|
||||
static const unsigned char dh_p_val[] = {
|
||||
#define DH_P_1_LEN 128
|
||||
static const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
@@ -47,8 +49,34 @@ static const unsigned char dh_p_val[] = {
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
|
||||
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
#define DH_P_LEN sizeof(dh_p_val)
|
||||
|
||||
/* diffie-hellman-group14-sha1 value for p */
|
||||
#define DH_P_14_LEN 256
|
||||
static const unsigned char dh_p_14[DH_P_14_LEN] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
|
||||
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
|
||||
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
|
||||
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
|
||||
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
|
||||
0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
|
||||
0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
|
||||
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
|
||||
0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
||||
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
|
||||
0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
|
||||
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
|
||||
0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
/* Same for group1 and group14 */
|
||||
static const int DH_G_VAL = 2;
|
||||
|
||||
static void kexinitialise();
|
||||
@@ -91,10 +119,10 @@ void send_msg_kexinit() {
|
||||
buf_put_algolist(ses.writepayload, sshhashes);
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
buf_put_algolist(ses.writepayload, sshcompress);
|
||||
buf_put_algolist(ses.writepayload, ses.compress_algos);
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
buf_put_algolist(ses.writepayload, sshcompress);
|
||||
buf_put_algolist(ses.writepayload, ses.compress_algos);
|
||||
|
||||
/* languages_client_to_server */
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
@@ -180,8 +208,16 @@ void recv_msg_newkeys() {
|
||||
|
||||
/* Set up the kex for the first time */
|
||||
void kexfirstinitialise() {
|
||||
|
||||
ses.kexstate.donefirstkex = 0;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (opts.enable_compress) {
|
||||
ses.compress_algos = ssh_compress;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
}
|
||||
kexinitialise();
|
||||
}
|
||||
|
||||
@@ -236,8 +272,8 @@ static void hashkeys(unsigned char *out, int outlen,
|
||||
}
|
||||
|
||||
/* Generate the actual encryption/integrity keys, using the results of the
|
||||
* key exchange, as specified in section 5.2 of the IETF secsh-transport
|
||||
* draft. This occurs after the DH key-exchange.
|
||||
* key exchange, as specified in section 7.2 of the transport rfc 4253.
|
||||
* This occurs after the DH key-exchange.
|
||||
*
|
||||
* ses.newkeys is the new set of keys which are generated, these are only
|
||||
* taken into use after both sides have sent a newkeys message */
|
||||
@@ -272,8 +308,8 @@ void gen_new_keys() {
|
||||
recv_IV = S2C_IV;
|
||||
trans_key = C2S_key;
|
||||
recv_key = S2C_key;
|
||||
C2S_keysize = ses.newkeys->trans_algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->recv_algo_crypt->keysize;
|
||||
C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
|
||||
mactransletter = 'E';
|
||||
macrecvletter = 'F';
|
||||
} else {
|
||||
@@ -281,8 +317,8 @@ void gen_new_keys() {
|
||||
recv_IV = C2S_IV;
|
||||
trans_key = S2C_key;
|
||||
recv_key = C2S_key;
|
||||
C2S_keysize = ses.newkeys->recv_algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->trans_algo_crypt->keysize;
|
||||
C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
|
||||
mactransletter = 'F';
|
||||
macrecvletter = 'E';
|
||||
}
|
||||
@@ -292,31 +328,33 @@ void gen_new_keys() {
|
||||
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
|
||||
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
|
||||
|
||||
recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name);
|
||||
recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0)
|
||||
dropbear_exit("crypto error");
|
||||
if (ses.newkeys->recv_crypt_mode->start(recv_cipher,
|
||||
dropbear_exit("Crypto error");
|
||||
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
|
||||
recv_IV, recv_key,
|
||||
ses.newkeys->recv_algo_crypt->keysize, 0,
|
||||
&ses.newkeys->recv_cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("crypto error");
|
||||
ses.newkeys->recv.algo_crypt->keysize, 0,
|
||||
&ses.newkeys->recv.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
|
||||
trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name);
|
||||
trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0)
|
||||
dropbear_exit("crypto error");
|
||||
if (ses.newkeys->trans_crypt_mode->start(trans_cipher,
|
||||
dropbear_exit("Crypto error");
|
||||
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
|
||||
trans_IV, trans_key,
|
||||
ses.newkeys->trans_algo_crypt->keysize, 0,
|
||||
&ses.newkeys->trans_cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("crypto error");
|
||||
ses.newkeys->trans.algo_crypt->keysize, 0,
|
||||
&ses.newkeys->trans.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
|
||||
/* MAC keys */
|
||||
hashkeys(ses.newkeys->transmackey,
|
||||
ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter);
|
||||
hashkeys(ses.newkeys->recvmackey,
|
||||
ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter);
|
||||
hashkeys(ses.newkeys->trans.mackey,
|
||||
ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
|
||||
hashkeys(ses.newkeys->recv.mackey,
|
||||
ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
|
||||
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name),
|
||||
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name),
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
gen_new_zstreams();
|
||||
@@ -334,15 +372,15 @@ void gen_new_keys() {
|
||||
#ifndef DISABLE_ZLIB
|
||||
|
||||
int is_compress_trans() {
|
||||
return ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB
|
||||
return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| (ses.authstate.authdone
|
||||
&& ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
&& ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
}
|
||||
|
||||
int is_compress_recv() {
|
||||
return ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB
|
||||
return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| (ses.authstate.authdone
|
||||
&& ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
}
|
||||
|
||||
/* Set up new zlib compression streams, close the old ones. Only
|
||||
@@ -350,47 +388,49 @@ int is_compress_recv() {
|
||||
static void gen_new_zstreams() {
|
||||
|
||||
/* create new zstreams */
|
||||
if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->recv_zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->recv_zstream->zfree = Z_NULL;
|
||||
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->recv.zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->recv.zstream->zfree = Z_NULL;
|
||||
|
||||
if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) {
|
||||
if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
} else {
|
||||
ses.newkeys->recv_zstream = NULL;
|
||||
ses.newkeys->recv.zstream = NULL;
|
||||
}
|
||||
|
||||
if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->trans_zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->trans_zstream->zfree = Z_NULL;
|
||||
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->trans.zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->trans.zstream->zfree = Z_NULL;
|
||||
|
||||
if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION)
|
||||
if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS,
|
||||
DROPBEAR_ZLIB_MEM_LEVEL, Z_DEFAULT_STRATEGY)
|
||||
!= Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
} else {
|
||||
ses.newkeys->trans_zstream = NULL;
|
||||
ses.newkeys->trans.zstream = NULL;
|
||||
}
|
||||
|
||||
/* clean up old keys */
|
||||
if (ses.keys->recv_zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv_zstream) == Z_STREAM_ERROR) {
|
||||
if (ses.keys->recv.zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("crypto error");
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
m_free(ses.keys->recv_zstream);
|
||||
m_free(ses.keys->recv.zstream);
|
||||
}
|
||||
if (ses.keys->trans_zstream != NULL) {
|
||||
if (deflateEnd(ses.keys->trans_zstream) == Z_STREAM_ERROR) {
|
||||
if (ses.keys->trans.zstream != NULL) {
|
||||
if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("crypto error");
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
m_free(ses.keys->trans_zstream);
|
||||
m_free(ses.keys->trans.zstream);
|
||||
}
|
||||
}
|
||||
#endif /* DISABLE_ZLIB */
|
||||
@@ -479,8 +519,20 @@ void recv_msg_kexinit() {
|
||||
TRACE(("leave recv_msg_kexinit"))
|
||||
}
|
||||
|
||||
static void load_dh_p(mp_int * dh_p)
|
||||
{
|
||||
switch (ses.newkeys->algo_kex) {
|
||||
case DROPBEAR_KEX_DH_GROUP1:
|
||||
bytes_to_mp(dh_p, dh_p_1, DH_P_1_LEN);
|
||||
break;
|
||||
case DROPBEAR_KEX_DH_GROUP14:
|
||||
bytes_to_mp(dh_p, dh_p_14, DH_P_14_LEN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialises and generate one side of the diffie-hellman key exchange values.
|
||||
* See the ietf-secsh-transport draft, section 6, for details */
|
||||
* See the transport rfc 4253 section 8 for details */
|
||||
/* dh_pub and dh_priv MUST be already initialised */
|
||||
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
|
||||
|
||||
@@ -493,7 +545,7 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
|
||||
m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
|
||||
|
||||
/* read the prime and generator*/
|
||||
bytes_to_mp(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN);
|
||||
load_dh_p(&dh_p);
|
||||
|
||||
if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
@@ -531,7 +583,7 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
|
||||
/* read the prime and generator*/
|
||||
m_mp_init(&dh_p);
|
||||
bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN);
|
||||
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
|
||||
@@ -666,7 +718,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo->name))
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
c2s_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
|
||||
c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
|
||||
if (c2s_comp_algo == NULL) {
|
||||
erralgo = "comp c->s";
|
||||
goto error;
|
||||
@@ -674,7 +726,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash c2s is %s", c2s_comp_algo->name))
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
s2c_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
|
||||
s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
|
||||
if (s2c_comp_algo == NULL) {
|
||||
erralgo = "comp s->c";
|
||||
goto error;
|
||||
@@ -698,36 +750,36 @@ static void read_kex_algos() {
|
||||
|
||||
/* Handle the asymmetry */
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
ses.newkeys->recv_algo_crypt =
|
||||
ses.newkeys->recv.algo_crypt =
|
||||
(struct dropbear_cipher*)s2c_cipher_algo->data;
|
||||
ses.newkeys->trans_algo_crypt =
|
||||
ses.newkeys->trans.algo_crypt =
|
||||
(struct dropbear_cipher*)c2s_cipher_algo->data;
|
||||
ses.newkeys->recv_crypt_mode =
|
||||
ses.newkeys->recv.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
|
||||
ses.newkeys->trans_crypt_mode =
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
|
||||
ses.newkeys->recv_algo_mac =
|
||||
ses.newkeys->recv.algo_mac =
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->trans_algo_mac =
|
||||
ses.newkeys->trans.algo_mac =
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->recv_algo_comp = s2c_comp_algo->val;
|
||||
ses.newkeys->trans_algo_comp = c2s_comp_algo->val;
|
||||
ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
|
||||
} else {
|
||||
/* SERVER */
|
||||
ses.newkeys->recv_algo_crypt =
|
||||
ses.newkeys->recv.algo_crypt =
|
||||
(struct dropbear_cipher*)c2s_cipher_algo->data;
|
||||
ses.newkeys->trans_algo_crypt =
|
||||
ses.newkeys->trans.algo_crypt =
|
||||
(struct dropbear_cipher*)s2c_cipher_algo->data;
|
||||
ses.newkeys->recv_crypt_mode =
|
||||
ses.newkeys->recv.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
|
||||
ses.newkeys->trans_crypt_mode =
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
|
||||
ses.newkeys->recv_algo_mac =
|
||||
ses.newkeys->recv.algo_mac =
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->trans_algo_mac =
|
||||
ses.newkeys->trans.algo_mac =
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->recv_algo_comp = c2s_comp_algo->val;
|
||||
ses.newkeys->trans_algo_comp = s2c_comp_algo->val;
|
||||
ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
|
||||
}
|
||||
|
||||
/* reserved for future extensions */
|
||||
@@ -735,5 +787,5 @@ static void read_kex_algos() {
|
||||
return;
|
||||
|
||||
error:
|
||||
dropbear_exit("no matching algo %s", erralgo);
|
||||
dropbear_exit("No matching algo %s", erralgo);
|
||||
}
|
||||
|
||||
@@ -52,12 +52,10 @@ int exitflag = 0; /* GLOBAL */
|
||||
|
||||
|
||||
/* called only at the start of a session, set up initial state */
|
||||
void common_session_init(int sock_in, int sock_out, char* remotehost) {
|
||||
void common_session_init(int sock_in, int sock_out) {
|
||||
|
||||
TRACE(("enter session_init"))
|
||||
|
||||
ses.remotehost = remotehost;
|
||||
|
||||
ses.sock_in = sock_in;
|
||||
ses.sock_out = sock_out;
|
||||
ses.maxfd = MAX(sock_in, sock_out);
|
||||
@@ -67,10 +65,13 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
|
||||
ses.last_packet_time = 0;
|
||||
|
||||
if (pipe(ses.signal_pipe) < 0) {
|
||||
dropbear_exit("signal pipe failed");
|
||||
dropbear_exit("Signal pipe failed");
|
||||
}
|
||||
setnonblocking(ses.signal_pipe[0]);
|
||||
setnonblocking(ses.signal_pipe[1]);
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
|
||||
|
||||
kexfirstinitialise(); /* initialise the kex state */
|
||||
|
||||
@@ -78,7 +79,6 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
|
||||
ses.transseq = 0;
|
||||
|
||||
ses.readbuf = NULL;
|
||||
ses.decryptreadbuf = NULL;
|
||||
ses.payload = NULL;
|
||||
ses.recvseq = 0;
|
||||
|
||||
@@ -95,22 +95,22 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
|
||||
/* set all the algos to none */
|
||||
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
ses.newkeys = NULL;
|
||||
ses.keys->recv_algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->trans_algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->recv_crypt_mode = &dropbear_mode_none;
|
||||
ses.keys->trans_crypt_mode = &dropbear_mode_none;
|
||||
ses.keys->recv.algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->trans.algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->recv.crypt_mode = &dropbear_mode_none;
|
||||
ses.keys->trans.crypt_mode = &dropbear_mode_none;
|
||||
|
||||
ses.keys->recv_algo_mac = &dropbear_nohash;
|
||||
ses.keys->trans_algo_mac = &dropbear_nohash;
|
||||
ses.keys->recv.algo_mac = &dropbear_nohash;
|
||||
ses.keys->trans.algo_mac = &dropbear_nohash;
|
||||
|
||||
ses.keys->algo_kex = -1;
|
||||
ses.keys->algo_hostkey = -1;
|
||||
ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
ses.keys->recv_zstream = NULL;
|
||||
ses.keys->trans_zstream = NULL;
|
||||
ses.keys->recv.zstream = NULL;
|
||||
ses.keys->trans.zstream = NULL;
|
||||
#endif
|
||||
|
||||
/* key exchange buffers */
|
||||
|
||||
31
configure.in
31
configure.in
@@ -82,7 +82,8 @@ AC_CHECK_DECL(__UCLIBC__,
|
||||
],,,)
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt")
|
||||
AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt")
|
||||
AC_SUBST(CRYPTLIB)
|
||||
|
||||
# Check if zlib is needed
|
||||
AC_ARG_WITH(zlib,
|
||||
@@ -145,6 +146,7 @@ AC_ARG_ENABLE(pam,
|
||||
if test "x$enableval" = "xyes"; then
|
||||
AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
|
||||
AC_MSG_NOTICE(Enabling PAM)
|
||||
AC_CHECK_FUNCS(pam_fail_delay)
|
||||
else
|
||||
AC_DEFINE(DISABLE_PAM,, Use PAM)
|
||||
AC_MSG_NOTICE(Disabling PAM)
|
||||
@@ -361,6 +363,25 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
|
||||
AC_CHECK_FUNCS(setutxent utmpxname)
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
|
||||
AC_ARG_ENABLE(bundled-libtom,
|
||||
[ --enable-bundled-libtom Use bundled libtomcrypt/libtommath even if a system version exists],
|
||||
[
|
||||
BUNDLED_LIBTOM=1
|
||||
AC_MSG_NOTICE(Forcing bundled libtom*)
|
||||
],
|
||||
[
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, , BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, , BUNDLED_LIBTOM=1)
|
||||
]
|
||||
)
|
||||
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom)
|
||||
fi
|
||||
|
||||
AC_SUBST(BUNDLED_LIBTOM)
|
||||
|
||||
dnl Added from OpenSSH 3.6.1p2's configure.ac
|
||||
|
||||
dnl allow user to disable some login recording features
|
||||
@@ -669,5 +690,13 @@ AC_CONFIG_HEADER(config.h)
|
||||
AC_OUTPUT(Makefile)
|
||||
AC_OUTPUT(libtomcrypt/Makefile)
|
||||
AC_OUTPUT(libtommath/Makefile)
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
if test $BUNDLED_LIBTOM = 1 ; then
|
||||
AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath)
|
||||
else
|
||||
AC_MSG_NOTICE(Using system libtomcrypt and libtommath)
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE(Now edit options.h to choose features.)
|
||||
|
||||
@@ -36,7 +36,7 @@ Read the identity from file
|
||||
.I idfile
|
||||
(multiple allowed).
|
||||
.TP
|
||||
.B \-L \fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Local port forwarding.
|
||||
Forward the port
|
||||
.I listenport
|
||||
@@ -45,7 +45,7 @@ on the local host through the SSH connection to port
|
||||
on the host
|
||||
.IR host .
|
||||
.TP
|
||||
.B \-R \fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
.B \-R [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Remote port forwarding.
|
||||
Forward the port
|
||||
.I listenport
|
||||
@@ -82,6 +82,11 @@ by the ssh server.
|
||||
Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the
|
||||
connection will abort as normal.
|
||||
.TP
|
||||
.B \-A
|
||||
Forward agent connections to the remote host. dbclient will use any
|
||||
OpenSSH-style agent program if available ($SSH_AUTH_SOCK will be set) for
|
||||
public key authentication. Forwarding is only enabled if -A is specified.
|
||||
.TP
|
||||
.B \-W \fIwindowsize
|
||||
Specify the per-channel receive window buffer size. Increasing this
|
||||
may improve network performance at the expense of memory use. Use -h to see the
|
||||
|
||||
148
dbutil.c
148
dbutil.c
@@ -111,7 +111,7 @@ static void generic_dropbear_exit(int exitcode, const char* format,
|
||||
}
|
||||
|
||||
void fail_assert(const char* expr, const char* file, int line) {
|
||||
dropbear_exit("failed assertion (%s:%d): `%s'", file, line, expr);
|
||||
dropbear_exit("Failed assertion (%s:%d): `%s'", file, line, expr);
|
||||
}
|
||||
|
||||
static void generic_dropbear_log(int UNUSED(priority), const char* format,
|
||||
@@ -295,6 +295,28 @@ int dropbear_listen(const char* address, const char* port,
|
||||
return nsock;
|
||||
}
|
||||
|
||||
/* Connect to a given unix socket. The socket is blocking */
|
||||
#ifdef ENABLE_CONNECT_UNIX
|
||||
int connect_unix(const char* path) {
|
||||
struct sockaddr_un addr;
|
||||
int fd = -1;
|
||||
|
||||
memset((void*)&addr, 0x0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
|
||||
fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
TRACE(("Failed to open unix socket"))
|
||||
return -1;
|
||||
}
|
||||
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
TRACE(("Failed to connect to '%s' socket", path))
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
#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 */
|
||||
@@ -341,15 +363,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
|
||||
}
|
||||
|
||||
if (nonblocking) {
|
||||
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||
close(sock);
|
||||
sock = -1;
|
||||
if (errstring != NULL && *errstring == NULL) {
|
||||
*errstring = m_strdup("Failed non-blocking");
|
||||
}
|
||||
TRACE(("Failed non-blocking: %s", strerror(errno)))
|
||||
continue;
|
||||
}
|
||||
setnonblocking(sock);
|
||||
}
|
||||
|
||||
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
@@ -441,7 +455,7 @@ int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
|
||||
(dup2(outfds[FDOUT], STDOUT_FILENO) < 0) ||
|
||||
(ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) {
|
||||
TRACE(("leave noptycommand: error redirecting FDs"))
|
||||
dropbear_exit("child dup2() failure");
|
||||
dropbear_exit("Child dup2() failure");
|
||||
}
|
||||
|
||||
close(infds[FDOUT]);
|
||||
@@ -525,14 +539,47 @@ 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() */
|
||||
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
|
||||
void getaddrstring(struct sockaddr_storage* addr,
|
||||
char **ret_host, char **ret_port,
|
||||
int host_lookup) {
|
||||
|
||||
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
||||
char *retstring = NULL;
|
||||
int ret;
|
||||
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
|
||||
@@ -550,67 +597,28 @@ unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
|
||||
sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
|
||||
serv, sizeof(serv)-1, flags);
|
||||
|
||||
if (ret != 0) {
|
||||
/* This is a fairly bad failure - it'll fallback to IP if it
|
||||
* just can't resolve */
|
||||
dropbear_exit("failed lookup (%d, %d)", ret, errno);
|
||||
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 (withport) {
|
||||
len = strlen(hbuf) + 2 + strlen(sbuf);
|
||||
retstring = (char*)m_malloc(len);
|
||||
snprintf(retstring, len, "%s:%s", hbuf, sbuf);
|
||||
} else {
|
||||
retstring = m_strdup(hbuf);
|
||||
if (ret_host) {
|
||||
*ret_host = m_strdup(host);
|
||||
}
|
||||
|
||||
return retstring;
|
||||
|
||||
}
|
||||
|
||||
/* Get the hostname corresponding to the address addr. On failure, the IP
|
||||
* address is returned. The return value is allocated with strdup() */
|
||||
char* getaddrhostname(struct sockaddr_storage * addr) {
|
||||
|
||||
char hbuf[NI_MAXHOST];
|
||||
char sbuf[NI_MAXSERV];
|
||||
int ret;
|
||||
unsigned int len;
|
||||
#ifdef DO_HOST_LOOKUP
|
||||
const int flags = NI_NUMERICSERV;
|
||||
#else
|
||||
const int flags = NI_NUMERICHOST | NI_NUMERICSERV;
|
||||
#endif
|
||||
|
||||
len = sizeof(struct sockaddr_storage);
|
||||
/* Some platforms such as Solaris 8 require that len is the length
|
||||
* of the specific structure. */
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
|
||||
if (addr->ss_family == AF_INET) {
|
||||
len = sizeof(struct sockaddr_in);
|
||||
if (ret_port) {
|
||||
*ret_port = m_strdup(serv);
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
if (addr->ss_family == AF_INET6) {
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
|
||||
sbuf, sizeof(sbuf), flags);
|
||||
|
||||
if (ret != 0) {
|
||||
/* 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. */
|
||||
return getaddrstring(addr, 0);
|
||||
}
|
||||
|
||||
return m_strdup(hbuf);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
|
||||
9
dbutil.h
9
dbutil.h
@@ -46,15 +46,20 @@ void printhex(const char * label, const unsigned char * buf, int len);
|
||||
extern int debug_trace;
|
||||
#endif
|
||||
char * stripcontrol(const char * text);
|
||||
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport);
|
||||
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);
|
||||
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);
|
||||
char* getaddrhostname(struct sockaddr_storage * addr);
|
||||
int buf_readfile(buffer* buf, const char* filename);
|
||||
int buf_getline(buffer * line, FILE * authfile);
|
||||
|
||||
|
||||
12
debian/changelog
vendored
12
debian/changelog
vendored
@@ -1,3 +1,15 @@
|
||||
dropbear (0.53.1-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 2 Mar 2011 22:54:00 +0900
|
||||
|
||||
dropbear (0.53-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 24 Feb 2011 22:54:00 +0900
|
||||
|
||||
dropbear (0.52-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
2
debug.h
2
debug.h
@@ -39,7 +39,7 @@
|
||||
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
|
||||
* since the printing may not sanitise strings etc. This will add a reasonable
|
||||
* amount to your executable size. */
|
||||
/*#define DEBUG_TRACE*/
|
||||
/*#define DEBUG_TRACE */
|
||||
|
||||
/* All functions writing to the cleartext payload buffer call
|
||||
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
|
||||
|
||||
30
dropbear.8
30
dropbear.8
@@ -7,7 +7,7 @@ dropbear \- lightweight SSH2 server
|
||||
.I banner\fR] [\-d
|
||||
.I dsskey\fR] [\-r
|
||||
.I rsakey\fR] [\-p
|
||||
.IR port ]
|
||||
.IR [address:]port ]
|
||||
.SH DESCRIPTION
|
||||
.B dropbear
|
||||
is a SSH 2 server designed to be small enough to be used in small memory
|
||||
@@ -154,6 +154,34 @@ By default the file /etc/motd will be printed for any login shell (unless
|
||||
disabled at compile-time). This can also be disabled per-user
|
||||
by creating a file ~/.hushlogin .
|
||||
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
Dropbear sets the standard variables USER, LOGNAME, HOME, SHELL, PATH, and TERM.
|
||||
|
||||
The variables below are set for sessions as appropriate.
|
||||
|
||||
.TP
|
||||
.B SSH_TTY
|
||||
This is set to the allocated TTY if a PTY was used.
|
||||
|
||||
.TP
|
||||
.B SSH_CONNECTION
|
||||
Contains "<remote_ip> <remote_port> <local_ip> <local_port>".
|
||||
|
||||
.TP
|
||||
.B DISPLAY
|
||||
Set X11 forwarding is used.
|
||||
|
||||
.TP
|
||||
.B SSH_ORIGINAL_COMMAND
|
||||
If a 'command=' authorized_keys option was used, the original command is specified
|
||||
in this variable. If a shell was requested this is set to an empty value.
|
||||
|
||||
.TP
|
||||
.B SSH_AUTH_SOCK
|
||||
Set to a forwarded ssh-agent connection.
|
||||
|
||||
|
||||
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE. */
|
||||
|
||||
/* The format of the keyfiles is basically a raw dump of the buffer. Data types
|
||||
* are specified in the transport draft - string is a 32-bit len then the
|
||||
* are specified in the transport rfc 4253 - string is a 32-bit len then the
|
||||
* non-null-terminated string, mp_int is a 32-bit len then the bignum data.
|
||||
* The actual functions are buf_put_rsa_priv_key() and buf_put_dss_priv_key()
|
||||
|
||||
|
||||
34
dss.c
34
dss.c
@@ -43,7 +43,7 @@
|
||||
* The key will have the same format as buf_put_dss_key.
|
||||
* These should be freed with dss_key_free.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
|
||||
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|
||||
|
||||
TRACE(("enter buf_get_dss_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
@@ -76,7 +76,7 @@ int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
|
||||
/* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
|
||||
* Loads a private dss key from a buffer
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_dss_priv_key(buffer* buf, dss_key *key) {
|
||||
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
@@ -99,7 +99,7 @@ int buf_get_dss_priv_key(buffer* buf, dss_key *key) {
|
||||
|
||||
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void dss_key_free(dss_key *key) {
|
||||
void dss_key_free(dropbear_dss_key *key) {
|
||||
|
||||
TRACE(("enter dsa_key_free"))
|
||||
if (key == NULL) {
|
||||
@@ -138,7 +138,7 @@ void dss_key_free(dss_key *key) {
|
||||
* mpint g
|
||||
* mpint y
|
||||
*/
|
||||
void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
|
||||
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|
||||
|
||||
dropbear_assert(key != NULL);
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
@@ -150,7 +150,7 @@ void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
|
||||
}
|
||||
|
||||
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */
|
||||
void buf_put_dss_priv_key(buffer* buf, dss_key *key) {
|
||||
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
|
||||
dropbear_assert(key != NULL);
|
||||
buf_put_dss_pub_key(buf, key);
|
||||
@@ -161,7 +161,7 @@ void buf_put_dss_priv_key(buffer* buf, dss_key *key) {
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a DSS signature (in buf) made on data by the key given.
|
||||
* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
@@ -270,7 +270,7 @@ static unsigned char* mptobytes(mp_int *mp, int *len) {
|
||||
size = mp_unsigned_bin_size(mp);
|
||||
ret = m_malloc(size);
|
||||
if (mp_to_unsigned_bin(mp, ret) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
if (len != NULL) {
|
||||
*len = size;
|
||||
@@ -292,7 +292,7 @@ static unsigned char* mptobytes(mp_int *mp, int *len) {
|
||||
*
|
||||
* Now we aren't relying on the random number generation to protect the private
|
||||
* key x, which is a long term secret */
|
||||
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
@@ -342,7 +342,7 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
m_mp_init(&dss_protok);
|
||||
bytes_to_mp(&dss_protok, proto_k, SHA512_HASH_SIZE);
|
||||
if (mp_mod(&dss_protok, key->q, &dss_k) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_protok);
|
||||
m_burn(proto_k, SHA512_HASH_SIZE);
|
||||
@@ -355,30 +355,30 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
|
||||
/* g^k mod p */
|
||||
if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
/* r = (g^k mod p) mod q */
|
||||
if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
|
||||
/* x*r mod q */
|
||||
if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
/* (SHA1(M) + xr) mod q) */
|
||||
if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
|
||||
/* (k^-1) mod q */
|
||||
if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
|
||||
/* s = (k^-1(SHA1(M) + xr)) mod q */
|
||||
if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
@@ -392,7 +392,7 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_r);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
@@ -405,7 +405,7 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_s);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
|
||||
21
dss.h
21
dss.h
@@ -32,29 +32,28 @@
|
||||
|
||||
#define DSS_SIGNATURE_SIZE 4+SSH_SIGNKEY_DSS_LEN+4+2*SHA1_HASH_SIZE
|
||||
|
||||
struct DSS_key {
|
||||
typedef struct {
|
||||
|
||||
mp_int* p;
|
||||
mp_int* q;
|
||||
mp_int* g;
|
||||
mp_int* y;
|
||||
/* x is the private part */
|
||||
mp_int* x;
|
||||
|
||||
};
|
||||
} dropbear_dss_key;
|
||||
|
||||
typedef struct DSS_key dss_key;
|
||||
|
||||
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
#endif
|
||||
int buf_get_dss_pub_key(buffer* buf, dss_key *key);
|
||||
int buf_get_dss_priv_key(buffer* buf, dss_key *key);
|
||||
void buf_put_dss_pub_key(buffer* buf, dss_key *key);
|
||||
void buf_put_dss_priv_key(buffer* buf, dss_key *key);
|
||||
void dss_key_free(dss_key *key);
|
||||
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key);
|
||||
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key);
|
||||
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key);
|
||||
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key);
|
||||
void dss_key_free(dropbear_dss_key *key);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* Taken for Dropbear from OpenSSH 5.5p1 */
|
||||
|
||||
/*
|
||||
*
|
||||
* Taken from OpenSSH 3.8.1p1
|
||||
*
|
||||
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
|
||||
* Copyright (C) 1999 WIDE Project. All rights reserved.
|
||||
*
|
||||
@@ -40,7 +39,11 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/* RCSID("$.Id: fake-rfc2553.c,v 1.5 2003/09/22 02:08:23 dtucker Exp $");*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifndef HAVE_GETNAMEINFO
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
|
||||
@@ -50,6 +53,8 @@ int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
|
||||
struct hostent *hp;
|
||||
char tmpserv[16];
|
||||
|
||||
if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET)
|
||||
return (EAI_FAMILY);
|
||||
if (serv != NULL) {
|
||||
snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
|
||||
if (strlcpy(serv, tmpserv, servlen) >= servlen)
|
||||
@@ -94,6 +99,8 @@ gai_strerror(int err)
|
||||
return ("memory allocation failure.");
|
||||
case EAI_NONAME:
|
||||
return ("nodename nor servname provided, or not known");
|
||||
case EAI_FAMILY:
|
||||
return ("ai_family not supported");
|
||||
default:
|
||||
return ("unknown/invalid error.");
|
||||
}
|
||||
@@ -158,6 +165,9 @@ getaddrinfo(const char *hostname, const char *servname,
|
||||
u_long addr;
|
||||
|
||||
port = 0;
|
||||
if (hints && hints->ai_family != AF_UNSPEC &&
|
||||
hints->ai_family != AF_INET)
|
||||
return (EAI_FAMILY);
|
||||
if (servname != NULL) {
|
||||
char *cp;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Taken from OpenSSH 3.8.1p1 */
|
||||
/* Taken for Dropbear from OpenSSH 5.5p1 */
|
||||
|
||||
/* $.Id: fake-rfc2553.h,v 1.9 2004/03/10 10:06:33 dtucker Exp $ */
|
||||
/* $Id: fake-rfc2553.h,v 1.16 2008/07/14 11:37:37 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
|
||||
@@ -43,6 +43,10 @@
|
||||
#define _FAKE_RFC2553_H
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/types.h>
|
||||
#if defined(HAVE_NETDB_H)
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* First, socket and INET6 related definitions
|
||||
@@ -75,6 +79,7 @@ struct sockaddr_in6 {
|
||||
u_int16_t sin6_port;
|
||||
u_int32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
u_int32_t sin6_scope_id;
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
|
||||
|
||||
@@ -115,9 +120,19 @@ struct sockaddr_in6 {
|
||||
#endif /* !NI_MAXHOST */
|
||||
|
||||
#ifndef EAI_NODATA
|
||||
# define EAI_NODATA 1
|
||||
# define EAI_MEMORY 2
|
||||
# define EAI_NONAME 3
|
||||
# define EAI_NODATA (INT_MAX - 1)
|
||||
#endif
|
||||
#ifndef EAI_MEMORY
|
||||
# define EAI_MEMORY (INT_MAX - 2)
|
||||
#endif
|
||||
#ifndef EAI_NONAME
|
||||
# define EAI_NONAME (INT_MAX - 3)
|
||||
#endif
|
||||
#ifndef EAI_SYSTEM
|
||||
# define EAI_SYSTEM (INT_MAX - 4)
|
||||
#endif
|
||||
#ifndef EAI_FAMILY
|
||||
# define EAI_FAMILY (INT_MAX - 5)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ADDRINFO
|
||||
@@ -143,7 +158,7 @@ int getaddrinfo(const char *, const char *,
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO)
|
||||
#define gai_strerror(a) (ssh_gai_strerror(a))
|
||||
#define gai_strerror(a) (_ssh_compat_gai_strerror(a))
|
||||
char *gai_strerror(int);
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
|
||||
48
gendss.c
48
gendss.c
@@ -37,17 +37,17 @@
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
|
||||
static void getq(dss_key *key);
|
||||
static void getp(dss_key *key, unsigned int size);
|
||||
static void getg(dss_key *key);
|
||||
static void getx(dss_key *key);
|
||||
static void gety(dss_key *key);
|
||||
static void getq(dropbear_dss_key *key);
|
||||
static void getp(dropbear_dss_key *key, unsigned int size);
|
||||
static void getg(dropbear_dss_key *key);
|
||||
static void getx(dropbear_dss_key *key);
|
||||
static void gety(dropbear_dss_key *key);
|
||||
|
||||
dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
|
||||
dss_key *key;
|
||||
dropbear_dss_key *key;
|
||||
|
||||
key = (dss_key*)m_malloc(sizeof(dss_key));
|
||||
key = m_malloc(sizeof(*key));
|
||||
|
||||
key->p = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->q = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
@@ -68,7 +68,7 @@ dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
|
||||
}
|
||||
|
||||
static void getq(dss_key *key) {
|
||||
static void getq(dropbear_dss_key *key) {
|
||||
|
||||
char buf[QSIZE];
|
||||
|
||||
@@ -81,12 +81,12 @@ static void getq(dss_key *key) {
|
||||
|
||||
/* 18 rounds are required according to HAC */
|
||||
if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void getp(dss_key *key, unsigned int size) {
|
||||
static void getp(dropbear_dss_key *key, unsigned int size) {
|
||||
|
||||
DEF_MP_INT(tempX);
|
||||
DEF_MP_INT(tempC);
|
||||
@@ -100,7 +100,7 @@ static void getp(dss_key *key, unsigned int size) {
|
||||
|
||||
/* 2*q */
|
||||
if (mp_mul_d(key->q, 2, &temp2q) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -117,25 +117,25 @@ static void getp(dss_key *key, unsigned int size) {
|
||||
|
||||
/* C = X mod 2q */
|
||||
if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* P = X - (C - 1) = X - C + 1*/
|
||||
if (mp_sub(&tempX, &tempC, &tempP) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (mp_add_d(&tempP, 1, key->p) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* now check for prime, 5 rounds is enough according to HAC */
|
||||
/* result == 1 => p is prime */
|
||||
if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
} while (!result);
|
||||
@@ -145,7 +145,7 @@ static void getp(dss_key *key, unsigned int size) {
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
static void getg(dss_key * key) {
|
||||
static void getg(dropbear_dss_key * key) {
|
||||
|
||||
DEF_MP_INT(div);
|
||||
DEF_MP_INT(h);
|
||||
@@ -155,11 +155,11 @@ static void getg(dss_key * key) {
|
||||
|
||||
/* get div=(p-1)/q */
|
||||
if (mp_sub_d(key->p, 1, &val) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (mp_div(&val, key->q, &div, NULL) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -168,12 +168,12 @@ static void getg(dss_key * key) {
|
||||
do {
|
||||
/* now keep going with g=h^div mod p, until g > 1 */
|
||||
if (mp_exptmod(&h, &div, key->p, key->g) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (mp_add_d(&h, 1, &h) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -182,15 +182,15 @@ static void getg(dss_key * key) {
|
||||
mp_clear_multi(&div, &h, &val, NULL);
|
||||
}
|
||||
|
||||
static void getx(dss_key *key) {
|
||||
static void getx(dropbear_dss_key *key) {
|
||||
|
||||
gen_random_mpint(key->q, key->x);
|
||||
}
|
||||
|
||||
static void gety(dss_key *key) {
|
||||
static void gety(dropbear_dss_key *key) {
|
||||
|
||||
if (mp_exptmod(key->g, key->x, key->p, key->y) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
2
gendss.h
2
gendss.h
@@ -29,7 +29,7 @@
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
|
||||
dss_key * gen_dss_priv_key(unsigned int size);
|
||||
dropbear_dss_key * gen_dss_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
|
||||
20
genrsa.c
20
genrsa.c
@@ -37,14 +37,14 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
mp_int* rsa_e, unsigned int size);
|
||||
|
||||
/* mostly taken from libtomcrypt's rsa key generation routine */
|
||||
rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
|
||||
rsa_key * key;
|
||||
dropbear_rsa_key * key;
|
||||
DEF_MP_INT(pminus);
|
||||
DEF_MP_INT(qminus);
|
||||
DEF_MP_INT(lcm);
|
||||
|
||||
key = (rsa_key*)m_malloc(sizeof(rsa_key));
|
||||
key = m_malloc(sizeof(*key));
|
||||
|
||||
key->e = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->n = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
@@ -58,7 +58,7 @@ rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
seedrandom();
|
||||
|
||||
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -66,20 +66,20 @@ rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
getrsaprime(key->q, &qminus, key->e, size/2);
|
||||
|
||||
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* lcm(p-1, q-1) */
|
||||
if (mp_lcm(&pminus, &qminus, &lcm) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* de = 1 mod lcm(p-1,q-1) */
|
||||
/* therefore d = (e^-1) mod lcm(p-1,q-1) */
|
||||
if (mp_invmod(key->e, &lcm, key->d) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -108,18 +108,18 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
|
||||
/* find the next integer which is prime, 8 round of miller-rabin */
|
||||
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* subtract one to get p-1 */
|
||||
if (mp_sub_d(prime, 1, primeminus) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
/* check relative primality to e */
|
||||
if (mp_gcd(primeminus, rsa_e, &temp_gcd) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
} while (mp_cmp_d(&temp_gcd, 1) != MP_EQ); /* while gcd(p-1, e) != 1 */
|
||||
|
||||
2
genrsa.h
2
genrsa.h
@@ -29,7 +29,7 @@
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
rsa_key * gen_rsa_priv_key(unsigned int size);
|
||||
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
|
||||
@@ -120,8 +120,14 @@
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
#ifdef BUNDLED_LIBTOM
|
||||
#include "libtomcrypt/src/headers/tomcrypt.h"
|
||||
#include "libtommath/tommath.h"
|
||||
#else
|
||||
#include <tomcrypt.h>
|
||||
#include <tommath.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "compat.h"
|
||||
#include "fake-rfc2553.h"
|
||||
|
||||
@@ -143,7 +143,7 @@ int mp_prime_next_prime(mp_int *a, int t, int bbs_style)
|
||||
|
||||
/* is this prime? */
|
||||
for (x = 0; x < t; x++) {
|
||||
mp_set(&b, ltm_prime_tab[t]);
|
||||
mp_set(&b, ltm_prime_tab[x]);
|
||||
if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
49
list.c
Normal file
49
list.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "options.h"
|
||||
#include "dbutil.h"
|
||||
#include "list.h"
|
||||
|
||||
void list_append(m_list *list, void *item) {
|
||||
m_list_elem *elem;
|
||||
|
||||
elem = m_malloc(sizeof(*elem));
|
||||
elem->item = item;
|
||||
elem->list = list;
|
||||
elem->next = NULL;
|
||||
if (!list->first) {
|
||||
list->first = elem;
|
||||
elem->prev = NULL;
|
||||
} else {
|
||||
elem->prev = list->last;
|
||||
list->last->next = elem;
|
||||
}
|
||||
list->last = elem;
|
||||
}
|
||||
|
||||
m_list * list_new() {
|
||||
m_list *ret = m_malloc(sizeof(m_list));
|
||||
ret->first = ret->last = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void * list_remove(m_list_elem *elem) {
|
||||
void *item = elem->item;
|
||||
m_list *list = elem->list;
|
||||
if (list->first == elem)
|
||||
{
|
||||
list->first = elem->next;
|
||||
}
|
||||
if (list->last == elem)
|
||||
{
|
||||
list->last = elem->prev;
|
||||
}
|
||||
if (elem->prev)
|
||||
{
|
||||
elem->prev->next = elem->next;
|
||||
}
|
||||
if (elem->next)
|
||||
{
|
||||
elem->next->prev = elem->prev;
|
||||
}
|
||||
m_free(elem);
|
||||
return item;
|
||||
}
|
||||
28
list.h
Normal file
28
list.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef _DROPBEAR_LIST_H
|
||||
#define _DROPBEAR_LIST_H
|
||||
|
||||
struct _m_list;
|
||||
|
||||
struct _m_list_elem {
|
||||
void *item;
|
||||
struct _m_list_elem *next;
|
||||
struct _m_list_elem *prev;
|
||||
struct _m_list *list;
|
||||
};
|
||||
|
||||
typedef struct _m_list_elem m_list_elem;
|
||||
|
||||
struct _m_list {
|
||||
m_list_elem *first;
|
||||
m_list_elem *last;
|
||||
};
|
||||
|
||||
typedef struct _m_list m_list;
|
||||
|
||||
m_list * list_new();
|
||||
void list_append(m_list *list, void *item);
|
||||
/* returns the item for the element removed */
|
||||
void * list_remove(m_list_elem *elem);
|
||||
|
||||
|
||||
#endif /* _DROPBEAR_LIST_H */
|
||||
40
options.h
40
options.h
@@ -46,9 +46,10 @@
|
||||
/*#define NO_FAST_EXPTMOD*/
|
||||
|
||||
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
|
||||
several kB in binary size, however will make the symmetrical ciphers (AES, DES
|
||||
etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
#define DROPBEAR_SMALL_CODE
|
||||
several kB in binary size however will make the symmetrical ciphers and hashes
|
||||
slower, perhaps by 50%. Recommended for small systems that aren't doing
|
||||
much traffic. */
|
||||
/*#define DROPBEAR_SMALL_CODE*/
|
||||
|
||||
/* Enable X11 Forwarding - server only */
|
||||
#define ENABLE_X11FWD
|
||||
@@ -63,8 +64,9 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
#define ENABLE_SVR_LOCALTCPFWD
|
||||
#define ENABLE_SVR_REMOTETCPFWD
|
||||
|
||||
/* Enable Authentication Agent Forwarding - server only for now */
|
||||
#define ENABLE_AGENTFWD
|
||||
/* Enable Authentication Agent Forwarding */
|
||||
#define ENABLE_SVR_AGENTFWD
|
||||
#define ENABLE_CLI_AGENTFWD
|
||||
|
||||
|
||||
/* Note: Both ENABLE_CLI_PROXYCMD and ENABLE_CLI_NETCAT must be set to
|
||||
@@ -85,7 +87,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
#define DROPBEAR_AES128
|
||||
#define DROPBEAR_3DES
|
||||
#define DROPBEAR_AES256
|
||||
#define DROPBEAR_BLOWFISH
|
||||
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
|
||||
/*#define DROPBEAR_BLOWFISH*/
|
||||
#define DROPBEAR_TWOFISH256
|
||||
#define DROPBEAR_TWOFISH128
|
||||
|
||||
@@ -125,9 +128,21 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
/* Define DSS_PROTOK to use PuTTY's method of generating the value k for dss,
|
||||
* rather than just from the random byte source. Undefining this will save you
|
||||
* ~4k in binary size with static uclibc, but your DSS hostkey could be exposed
|
||||
* if the random number source isn't good. In general this isn't required */
|
||||
* if the random number source isn't good. It happened to Sony.
|
||||
* On systems with a decent random source this isn't required. */
|
||||
/* #define DSS_PROTOK */
|
||||
|
||||
/* Control the memory/performance/compression tradeoff for zlib.
|
||||
* Set windowBits=8 for least memory usage, see your system's
|
||||
* zlib.h for full details.
|
||||
* Default settings (windowBits=15) will use 256kB for compression
|
||||
* windowBits=8 will use 129kB for compression.
|
||||
* Both modes will use ~35kB for decompression (using windowBits=15 for
|
||||
* interoperability) */
|
||||
#ifndef DROPBEAR_ZLIB_WINDOW_BITS
|
||||
#define DROPBEAR_ZLIB_WINDOW_BITS 15
|
||||
#endif
|
||||
|
||||
/* Whether to do reverse DNS lookups. */
|
||||
#define DO_HOST_LOOKUP
|
||||
|
||||
@@ -154,7 +169,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
/*#define ENABLE_SVR_PAM_AUTH*/
|
||||
#define ENABLE_SVR_PUBKEY_AUTH
|
||||
|
||||
/* Wether to ake public key options in authorized_keys file into account */
|
||||
/* Whether to take public key options in
|
||||
* authorized_keys file into account */
|
||||
#ifdef ENABLE_SVR_PUBKEY_AUTH
|
||||
#define ENABLE_SVR_PUBKEY_OPTIONS
|
||||
#endif
|
||||
@@ -220,7 +236,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
/* The command to invoke for xauth when using X11 forwarding.
|
||||
* "-q" for quiet */
|
||||
#ifndef XAUTH_COMMAND
|
||||
#define XAUTH_COMMAND "/usr/X11R6/bin/xauth -q"
|
||||
#define XAUTH_COMMAND "/usr/bin/X11/xauth -q"
|
||||
#endif
|
||||
|
||||
/* if you want to enable running an sftp server (such as the one included with
|
||||
@@ -246,13 +262,19 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
|
||||
significant difference to network performance. 24kB was empirically
|
||||
chosen for a 100mbit ethernet network. The value can be altered at
|
||||
runtime with the -W argument. */
|
||||
#ifndef DEFAULT_RECV_WINDOW
|
||||
#define DEFAULT_RECV_WINDOW 24576
|
||||
#endif
|
||||
/* Maximum size of a received SSH data packet - this _MUST_ be >= 32768
|
||||
in order to interoperate with other implementations */
|
||||
#ifndef RECV_MAX_PAYLOAD_LEN
|
||||
#define RECV_MAX_PAYLOAD_LEN 32768
|
||||
#endif
|
||||
/* Maximum size of a transmitted data packet - this can be any value,
|
||||
though increasing it may not make a significant difference. */
|
||||
#ifndef TRANS_MAX_PAYLOAD_LEN
|
||||
#define TRANS_MAX_PAYLOAD_LEN 16384
|
||||
#endif
|
||||
|
||||
/* Ensure that data is transmitted every KEEPALIVE seconds. This can
|
||||
be overridden at runtime with -K. 0 disables keepalives */
|
||||
|
||||
374
packet.c
374
packet.c
@@ -35,11 +35,13 @@
|
||||
#include "auth.h"
|
||||
#include "channel.h"
|
||||
|
||||
static void read_packet_init();
|
||||
static void writemac(buffer * outputbuffer, buffer * clearwritebuf);
|
||||
static int checkmac(buffer* hashbuf, buffer* readbuf);
|
||||
static int read_packet_init();
|
||||
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
|
||||
buffer * clear_buf, unsigned int clear_len,
|
||||
unsigned char *output_mac);
|
||||
static int checkmac();
|
||||
|
||||
#define ZLIB_COMPRESS_INCR 20 /* this is 12 bytes + 0.1% of 8000 bytes */
|
||||
#define ZLIB_COMPRESS_INCR 100
|
||||
#define ZLIB_DECOMPRESS_INCR 100
|
||||
#ifndef DISABLE_ZLIB
|
||||
static buffer* buf_decompress(buffer* buf, unsigned int len);
|
||||
@@ -51,6 +53,8 @@ void write_packet() {
|
||||
|
||||
int len, written;
|
||||
buffer * writebuf = NULL;
|
||||
time_t now;
|
||||
unsigned packet_type;
|
||||
|
||||
TRACE(("enter write_packet"))
|
||||
dropbear_assert(!isempty(&ses.writequeue));
|
||||
@@ -58,7 +62,10 @@ void write_packet() {
|
||||
/* Get the next buffer in the queue of encrypted packets to write*/
|
||||
writebuf = (buffer*)examine(&ses.writequeue);
|
||||
|
||||
len = writebuf->len - writebuf->pos;
|
||||
/* The last byte of the buffer is not to be transmitted, but is
|
||||
* a cleartext packet_type indicator */
|
||||
packet_type = writebuf->data[writebuf->len-1];
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
dropbear_assert(len > 0);
|
||||
/* Try to write as much as possible */
|
||||
written = write(ses.sock_out, buf_getptr(writebuf, len), len);
|
||||
@@ -68,12 +75,16 @@ void write_packet() {
|
||||
TRACE(("leave writepacket: EINTR"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("error writing");
|
||||
dropbear_exit("Error writing");
|
||||
}
|
||||
}
|
||||
|
||||
ses.last_trx_packet_time = time(NULL);
|
||||
ses.last_packet_time = time(NULL);
|
||||
now = time(NULL);
|
||||
ses.last_trx_packet_time = now;
|
||||
|
||||
if (packet_type != SSH_MSG_IGNORE) {
|
||||
ses.last_packet_time = now;
|
||||
}
|
||||
|
||||
if (written == 0) {
|
||||
ses.remoteclosed();
|
||||
@@ -102,18 +113,18 @@ void read_packet() {
|
||||
unsigned char blocksize;
|
||||
|
||||
TRACE(("enter read_packet"))
|
||||
blocksize = ses.keys->recv_algo_crypt->blocksize;
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
|
||||
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
|
||||
int ret;
|
||||
/* In the first blocksize of a packet */
|
||||
|
||||
/* Read the first blocksize of the packet, so we can decrypt it and
|
||||
* find the length of the whole packet */
|
||||
read_packet_init();
|
||||
ret = read_packet_init();
|
||||
|
||||
/* If we don't have the length of decryptreadbuf, we didn't read
|
||||
* a whole blocksize and should exit */
|
||||
if (ses.decryptreadbuf->len == 0) {
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
/* didn't read enough to determine the length */
|
||||
TRACE(("leave read_packet: packetinit done"))
|
||||
return;
|
||||
}
|
||||
@@ -121,7 +132,6 @@ void read_packet() {
|
||||
|
||||
/* Attempt to read the remainder of the packet, note that there
|
||||
* mightn't be any available (EAGAIN) */
|
||||
dropbear_assert(ses.readbuf != NULL);
|
||||
maxlen = ses.readbuf->len - ses.readbuf->pos;
|
||||
len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
|
||||
|
||||
@@ -134,7 +144,7 @@ void read_packet() {
|
||||
TRACE(("leave read_packet: EINTR or EAGAIN"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("error reading: %s", strerror(errno));
|
||||
dropbear_exit("Error reading: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,71 +161,75 @@ void read_packet() {
|
||||
|
||||
/* Function used to read the initial portion of a packet, and determine the
|
||||
* length. Only called during the first BLOCKSIZE of a packet. */
|
||||
static void read_packet_init() {
|
||||
/* Returns DROPBEAR_SUCCESS if the length is determined,
|
||||
* DROPBEAR_FAILURE otherwise */
|
||||
static int read_packet_init() {
|
||||
|
||||
unsigned int maxlen;
|
||||
int len;
|
||||
unsigned char blocksize;
|
||||
unsigned char macsize;
|
||||
int slen;
|
||||
unsigned int len;
|
||||
unsigned int blocksize;
|
||||
unsigned int macsize;
|
||||
|
||||
|
||||
blocksize = ses.keys->recv_algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv_algo_mac->hashsize;
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv.algo_mac->hashsize;
|
||||
|
||||
if (ses.readbuf == NULL) {
|
||||
/* start of a new packet */
|
||||
ses.readbuf = buf_new(INIT_READBUF);
|
||||
dropbear_assert(ses.decryptreadbuf == NULL);
|
||||
ses.decryptreadbuf = buf_new(blocksize);
|
||||
}
|
||||
|
||||
maxlen = blocksize - ses.readbuf->pos;
|
||||
|
||||
/* read the rest of the packet if possible */
|
||||
len = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen),
|
||||
slen = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen),
|
||||
maxlen);
|
||||
if (len == 0) {
|
||||
if (slen == 0) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
if (len < 0) {
|
||||
if (slen < 0) {
|
||||
if (errno == EINTR) {
|
||||
TRACE(("leave read_packet_init: EINTR"))
|
||||
return;
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
dropbear_exit("error reading: %s", strerror(errno));
|
||||
dropbear_exit("Error reading: %s", strerror(errno));
|
||||
}
|
||||
|
||||
buf_incrwritepos(ses.readbuf, len);
|
||||
buf_incrwritepos(ses.readbuf, slen);
|
||||
|
||||
if ((unsigned int)len != maxlen) {
|
||||
if ((unsigned int)slen != maxlen) {
|
||||
/* don't have enough bytes to determine length, get next time */
|
||||
return;
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* now we have the first block, need to get packet length, so we decrypt
|
||||
* the first block (only need first 4 bytes) */
|
||||
buf_setpos(ses.readbuf, 0);
|
||||
if (ses.keys->recv_crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
|
||||
buf_getwriteptr(ses.decryptreadbuf,blocksize),
|
||||
if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
|
||||
buf_getwriteptr(ses.readbuf, blocksize),
|
||||
blocksize,
|
||||
&ses.keys->recv_cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("error decrypting");
|
||||
&ses.keys->recv.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("Error decrypting");
|
||||
}
|
||||
buf_setlen(ses.decryptreadbuf, blocksize);
|
||||
len = buf_getint(ses.decryptreadbuf) + 4 + macsize;
|
||||
len = buf_getint(ses.readbuf) + 4 + macsize;
|
||||
|
||||
TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize))
|
||||
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
|
||||
/* check packet length */
|
||||
if ((len > RECV_MAX_PACKET_LEN) ||
|
||||
(len < MIN_PACKET_LEN + macsize) ||
|
||||
((len - macsize) % blocksize != 0)) {
|
||||
dropbear_exit("bad packet size %d", len);
|
||||
dropbear_exit("Integrity error (bad packet size %d)", len);
|
||||
}
|
||||
|
||||
buf_resize(ses.readbuf, len);
|
||||
if (len > ses.readbuf->size) {
|
||||
buf_resize(ses.readbuf, len);
|
||||
}
|
||||
buf_setlen(ses.readbuf, len);
|
||||
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* handle the received packet */
|
||||
@@ -227,69 +241,58 @@ void decrypt_packet() {
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter decrypt_packet"))
|
||||
blocksize = ses.keys->recv_algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv_algo_mac->hashsize;
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv.algo_mac->hashsize;
|
||||
|
||||
ses.kexstate.datarecv += ses.readbuf->len;
|
||||
|
||||
/* we've already decrypted the first blocksize in read_packet_init */
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
|
||||
buf_resize(ses.decryptreadbuf, ses.readbuf->len - macsize);
|
||||
buf_setlen(ses.decryptreadbuf, ses.decryptreadbuf->size);
|
||||
buf_setpos(ses.decryptreadbuf, blocksize);
|
||||
|
||||
/* decrypt it */
|
||||
while (ses.readbuf->pos < ses.readbuf->len - macsize) {
|
||||
if (ses.keys->recv_crypt_mode->decrypt(
|
||||
buf_getptr(ses.readbuf, blocksize),
|
||||
buf_getwriteptr(ses.decryptreadbuf, blocksize),
|
||||
blocksize,
|
||||
&ses.keys->recv_cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("error decrypting");
|
||||
}
|
||||
buf_incrpos(ses.readbuf, blocksize);
|
||||
buf_incrwritepos(ses.decryptreadbuf, blocksize);
|
||||
/* decrypt it in-place */
|
||||
len = ses.readbuf->len - macsize - ses.readbuf->pos;
|
||||
if (ses.keys->recv.crypt_mode->decrypt(
|
||||
buf_getptr(ses.readbuf, len),
|
||||
buf_getwriteptr(ses.readbuf, len),
|
||||
len,
|
||||
&ses.keys->recv.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("Error decrypting");
|
||||
}
|
||||
buf_incrpos(ses.readbuf, len);
|
||||
|
||||
/* check the hmac */
|
||||
buf_setpos(ses.readbuf, ses.readbuf->len - macsize);
|
||||
if (checkmac(ses.readbuf, ses.decryptreadbuf) != DROPBEAR_SUCCESS) {
|
||||
if (checkmac() != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Integrity error");
|
||||
}
|
||||
|
||||
/* readbuf no longer required */
|
||||
buf_free(ses.readbuf);
|
||||
ses.readbuf = NULL;
|
||||
|
||||
/* get padding length */
|
||||
buf_setpos(ses.decryptreadbuf, PACKET_PADDING_OFF);
|
||||
padlen = buf_getbyte(ses.decryptreadbuf);
|
||||
buf_setpos(ses.readbuf, PACKET_PADDING_OFF);
|
||||
padlen = buf_getbyte(ses.readbuf);
|
||||
|
||||
/* payload length */
|
||||
/* - 4 - 1 is for LEN and PADLEN values */
|
||||
len = ses.decryptreadbuf->len - padlen - 4 - 1;
|
||||
len = ses.readbuf->len - padlen - 4 - 1 - macsize;
|
||||
if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) {
|
||||
dropbear_exit("bad packet size");
|
||||
dropbear_exit("Bad packet size %d", len);
|
||||
}
|
||||
|
||||
buf_setpos(ses.decryptreadbuf, PACKET_PAYLOAD_OFF);
|
||||
buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (is_compress_recv()) {
|
||||
/* decompress */
|
||||
ses.payload = buf_decompress(ses.decryptreadbuf, len);
|
||||
ses.payload = buf_decompress(ses.readbuf, len);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* copy payload */
|
||||
ses.payload = buf_new(len);
|
||||
memcpy(ses.payload->data, buf_getptr(ses.decryptreadbuf, len), len);
|
||||
memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
|
||||
buf_incrlen(ses.payload, len);
|
||||
}
|
||||
|
||||
buf_free(ses.decryptreadbuf);
|
||||
ses.decryptreadbuf = NULL;
|
||||
buf_free(ses.readbuf);
|
||||
ses.readbuf = NULL;
|
||||
buf_setpos(ses.payload, 0);
|
||||
|
||||
ses.recvseq++;
|
||||
@@ -297,49 +300,22 @@ void decrypt_packet() {
|
||||
TRACE(("leave decrypt_packet"))
|
||||
}
|
||||
|
||||
/* Checks the mac in hashbuf, for the data in readbuf.
|
||||
/* Checks the mac at the end of a decrypted readbuf.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int checkmac(buffer* macbuf, buffer* sourcebuf) {
|
||||
static int checkmac() {
|
||||
|
||||
unsigned int macsize;
|
||||
hmac_state hmac;
|
||||
unsigned char tempbuf[MAX_MAC_LEN];
|
||||
unsigned long bufsize;
|
||||
unsigned int len;
|
||||
|
||||
macsize = ses.keys->recv_algo_mac->hashsize;
|
||||
if (macsize == 0) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* calculate the mac */
|
||||
if (hmac_init(&hmac,
|
||||
find_hash(ses.keys->recv_algo_mac->hashdesc->name),
|
||||
ses.keys->recvmackey,
|
||||
ses.keys->recv_algo_mac->keysize)
|
||||
!= CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
unsigned char mac_bytes[MAX_MAC_LEN];
|
||||
unsigned int mac_size, contents_len;
|
||||
|
||||
/* sequence number */
|
||||
STORE32H(ses.recvseq, tempbuf);
|
||||
if (hmac_process(&hmac, tempbuf, 4) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
mac_size = ses.keys->trans.algo_mac->hashsize;
|
||||
contents_len = ses.readbuf->len - mac_size;
|
||||
|
||||
buf_setpos(sourcebuf, 0);
|
||||
len = sourcebuf->len;
|
||||
if (hmac_process(&hmac, buf_getptr(sourcebuf, len), len) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
bufsize = sizeof(tempbuf);
|
||||
if (hmac_done(&hmac, tempbuf, &bufsize) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
buf_setpos(ses.readbuf, 0);
|
||||
make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
|
||||
|
||||
/* compare the hash */
|
||||
if (memcmp(tempbuf, buf_getptr(macbuf, macsize), macsize) != 0) {
|
||||
buf_setpos(ses.readbuf, contents_len);
|
||||
if (memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
return DROPBEAR_SUCCESS;
|
||||
@@ -354,7 +330,7 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
|
||||
buffer * ret;
|
||||
z_streamp zstream;
|
||||
|
||||
zstream = ses.keys->recv_zstream;
|
||||
zstream = ses.keys->recv.zstream;
|
||||
ret = buf_new(len);
|
||||
|
||||
zstream->avail_in = len;
|
||||
@@ -450,52 +426,69 @@ void maybe_flush_reply_queue() {
|
||||
void encrypt_packet() {
|
||||
|
||||
unsigned char padlen;
|
||||
unsigned char blocksize, macsize;
|
||||
buffer * writebuf; /* the packet which will go on the wire */
|
||||
buffer * clearwritebuf; /* unencrypted, possibly compressed */
|
||||
unsigned char type;
|
||||
unsigned int clear_len;
|
||||
unsigned char blocksize, mac_size;
|
||||
buffer * writebuf; /* the packet which will go on the wire. This is
|
||||
encrypted in-place. */
|
||||
unsigned char packet_type;
|
||||
unsigned int len, encrypt_buf_size;
|
||||
unsigned char mac_bytes[MAX_MAC_LEN];
|
||||
|
||||
type = ses.writepayload->data[0];
|
||||
TRACE(("enter encrypt_packet()"))
|
||||
TRACE(("encrypt_packet type is %d", type))
|
||||
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
packet_type = buf_getbyte(ses.writepayload);
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
|
||||
TRACE(("encrypt_packet type is %d", packet_type))
|
||||
|
||||
if (!ses.dataallowed && !packet_is_okay_kex(type)) {
|
||||
if (!ses.dataallowed && !packet_is_okay_kex(packet_type)) {
|
||||
/* During key exchange only particular packets are allowed.
|
||||
Since this type isn't OK we just enqueue it to send
|
||||
Since this packet_type isn't OK we just enqueue it to send
|
||||
after the KEX, see maybe_flush_reply_queue */
|
||||
enqueue_reply_packet();
|
||||
return;
|
||||
}
|
||||
|
||||
blocksize = ses.keys->trans_algo_crypt->blocksize;
|
||||
macsize = ses.keys->trans_algo_mac->hashsize;
|
||||
|
||||
/* Encrypted packet len is payload+5, then worst case is if we are 3 away
|
||||
* from a blocksize multiple. In which case we need to pad to the
|
||||
* multiple, then add another blocksize (or MIN_PACKET_LEN) */
|
||||
clear_len = (ses.writepayload->len+4+1) + MIN_PACKET_LEN + 3;
|
||||
blocksize = ses.keys->trans.algo_crypt->blocksize;
|
||||
mac_size = ses.keys->trans.algo_mac->hashsize;
|
||||
|
||||
/* Encrypted packet len is payload+5. We need to then make sure
|
||||
* there is enough space for padding or MIN_PACKET_LEN.
|
||||
* Add extra 3 since we need at least 4 bytes of padding */
|
||||
encrypt_buf_size = (ses.writepayload->len+4+1)
|
||||
+ MAX(MIN_PACKET_LEN, blocksize) + 3
|
||||
/* add space for the MAC at the end */
|
||||
+ mac_size
|
||||
#ifndef DISABLE_ZLIB
|
||||
clear_len += ZLIB_COMPRESS_INCR; /* bit of a kludge, but we can't know len*/
|
||||
/* some extra in case 'compression' makes it larger */
|
||||
+ ZLIB_COMPRESS_INCR
|
||||
#endif
|
||||
clearwritebuf = buf_new(clear_len);
|
||||
buf_setlen(clearwritebuf, PACKET_PAYLOAD_OFF);
|
||||
buf_setpos(clearwritebuf, PACKET_PAYLOAD_OFF);
|
||||
/* and an extra cleartext (stripped before transmission) byte for the
|
||||
* packet type */
|
||||
+ 1;
|
||||
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
writebuf = buf_new(encrypt_buf_size);
|
||||
buf_setlen(writebuf, PACKET_PAYLOAD_OFF);
|
||||
buf_setpos(writebuf, PACKET_PAYLOAD_OFF);
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* compression */
|
||||
if (is_compress_trans()) {
|
||||
buf_compress(clearwritebuf, ses.writepayload, ses.writepayload->len);
|
||||
int compress_delta;
|
||||
buf_compress(writebuf, ses.writepayload, ses.writepayload->len);
|
||||
compress_delta = (writebuf->len - PACKET_PAYLOAD_OFF) - ses.writepayload->len;
|
||||
|
||||
/* Handle the case where 'compress' increased the size. */
|
||||
if (compress_delta > ZLIB_COMPRESS_INCR) {
|
||||
buf_resize(writebuf, writebuf->size + compress_delta);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
memcpy(buf_getwriteptr(clearwritebuf, ses.writepayload->len),
|
||||
memcpy(buf_getwriteptr(writebuf, ses.writepayload->len),
|
||||
buf_getptr(ses.writepayload, ses.writepayload->len),
|
||||
ses.writepayload->len);
|
||||
buf_incrwritepos(clearwritebuf, ses.writepayload->len);
|
||||
buf_incrwritepos(writebuf, ses.writepayload->len);
|
||||
}
|
||||
|
||||
/* finished with payload */
|
||||
@@ -504,53 +497,48 @@ void encrypt_packet() {
|
||||
|
||||
/* length of padding - packet length must be a multiple of blocksize,
|
||||
* with a minimum of 4 bytes of padding */
|
||||
padlen = blocksize - (clearwritebuf->len) % blocksize;
|
||||
padlen = blocksize - (writebuf->len) % blocksize;
|
||||
if (padlen < 4) {
|
||||
padlen += blocksize;
|
||||
}
|
||||
/* check for min packet length */
|
||||
if (clearwritebuf->len + padlen < MIN_PACKET_LEN) {
|
||||
if (writebuf->len + padlen < MIN_PACKET_LEN) {
|
||||
padlen += blocksize;
|
||||
}
|
||||
|
||||
buf_setpos(clearwritebuf, 0);
|
||||
buf_setpos(writebuf, 0);
|
||||
/* packet length excluding the packetlength uint32 */
|
||||
buf_putint(clearwritebuf, clearwritebuf->len + padlen - 4);
|
||||
buf_putint(writebuf, writebuf->len + padlen - 4);
|
||||
|
||||
/* padding len */
|
||||
buf_putbyte(clearwritebuf, padlen);
|
||||
buf_putbyte(writebuf, padlen);
|
||||
/* actual padding */
|
||||
buf_setpos(clearwritebuf, clearwritebuf->len);
|
||||
buf_incrlen(clearwritebuf, padlen);
|
||||
genrandom(buf_getptr(clearwritebuf, padlen), padlen);
|
||||
buf_setpos(writebuf, writebuf->len);
|
||||
buf_incrlen(writebuf, padlen);
|
||||
genrandom(buf_getptr(writebuf, padlen), padlen);
|
||||
|
||||
/* do the actual encryption */
|
||||
buf_setpos(clearwritebuf, 0);
|
||||
/* create a new writebuffer, this is freed when it has been put on the
|
||||
* wire by writepacket() */
|
||||
writebuf = buf_new(clearwritebuf->len + macsize);
|
||||
make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
|
||||
|
||||
/* encrypt it */
|
||||
while (clearwritebuf->pos < clearwritebuf->len) {
|
||||
if (ses.keys->trans_crypt_mode->encrypt(
|
||||
buf_getptr(clearwritebuf, blocksize),
|
||||
buf_getwriteptr(writebuf, blocksize),
|
||||
blocksize,
|
||||
&ses.keys->trans_cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("error encrypting");
|
||||
}
|
||||
buf_incrpos(clearwritebuf, blocksize);
|
||||
buf_incrwritepos(writebuf, blocksize);
|
||||
/* do the actual encryption, in-place */
|
||||
buf_setpos(writebuf, 0);
|
||||
/* encrypt it in-place*/
|
||||
len = writebuf->len;
|
||||
if (ses.keys->trans.crypt_mode->encrypt(
|
||||
buf_getptr(writebuf, len),
|
||||
buf_getwriteptr(writebuf, len),
|
||||
len,
|
||||
&ses.keys->trans.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("Error encrypting");
|
||||
}
|
||||
buf_incrpos(writebuf, len);
|
||||
|
||||
/* now add a hmac and we're done */
|
||||
writemac(writebuf, clearwritebuf);
|
||||
/* stick the MAC on it */
|
||||
buf_putbytes(writebuf, mac_bytes, mac_size);
|
||||
|
||||
/* clearwritebuf is finished with */
|
||||
buf_free(clearwritebuf);
|
||||
clearwritebuf = NULL;
|
||||
|
||||
/* enqueue the packet for sending */
|
||||
/* 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);
|
||||
|
||||
@@ -563,47 +551,43 @@ void encrypt_packet() {
|
||||
|
||||
|
||||
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
|
||||
static void writemac(buffer * outputbuffer, buffer * clearwritebuf) {
|
||||
|
||||
unsigned int macsize;
|
||||
/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
|
||||
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
|
||||
buffer * clear_buf, unsigned int clear_len,
|
||||
unsigned char *output_mac) {
|
||||
unsigned char seqbuf[4];
|
||||
unsigned char tempbuf[MAX_MAC_LEN];
|
||||
unsigned long bufsize;
|
||||
hmac_state hmac;
|
||||
|
||||
TRACE(("enter writemac"))
|
||||
|
||||
macsize = ses.keys->trans_algo_mac->hashsize;
|
||||
if (macsize > 0) {
|
||||
if (key_state->algo_mac->hashsize > 0) {
|
||||
/* calculate the mac */
|
||||
if (hmac_init(&hmac,
|
||||
find_hash(ses.keys->trans_algo_mac->hashdesc->name),
|
||||
ses.keys->transmackey,
|
||||
ses.keys->trans_algo_mac->keysize) != CRYPT_OK) {
|
||||
key_state->hash_index,
|
||||
key_state->mackey,
|
||||
key_state->algo_mac->keysize) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
/* sequence number */
|
||||
STORE32H(ses.transseq, seqbuf);
|
||||
STORE32H(seqno, seqbuf);
|
||||
if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
/* the actual contents */
|
||||
buf_setpos(clearwritebuf, 0);
|
||||
buf_setpos(clear_buf, 0);
|
||||
if (hmac_process(&hmac,
|
||||
buf_getptr(clearwritebuf,
|
||||
clearwritebuf->len),
|
||||
clearwritebuf->len) != CRYPT_OK) {
|
||||
buf_getptr(clear_buf, clear_len),
|
||||
clear_len) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
bufsize = sizeof(tempbuf);
|
||||
if (hmac_done(&hmac, tempbuf, &bufsize)
|
||||
!= CRYPT_OK) {
|
||||
bufsize = MAX_MAC_LEN;
|
||||
if (hmac_done(&hmac, output_mac, &bufsize) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
buf_putbytes(outputbuffer, tempbuf, macsize);
|
||||
}
|
||||
TRACE(("leave writemac"))
|
||||
}
|
||||
@@ -620,29 +604,29 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
|
||||
while (1) {
|
||||
|
||||
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(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) {
|
||||
if (ses.keys->trans.zstream->avail_in == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
dropbear_assert(ses.keys->trans_zstream->avail_out == 0);
|
||||
dropbear_assert(ses.keys->trans.zstream->avail_out == 0);
|
||||
|
||||
/* the buffer has been filled, we must extend. This only happens in
|
||||
* unusual circumstances where the data grows in size after deflate(),
|
||||
|
||||
2
packet.h
2
packet.h
@@ -44,6 +44,6 @@ typedef struct PacketType {
|
||||
#define PACKET_PADDING_OFF 4
|
||||
#define PACKET_PAYLOAD_OFF 5
|
||||
|
||||
#define INIT_READBUF 200
|
||||
#define INIT_READBUF 128
|
||||
|
||||
#endif /* _PACKET_H_ */
|
||||
|
||||
@@ -52,6 +52,8 @@ void process_packet() {
|
||||
|
||||
ses.lastpacket = type;
|
||||
|
||||
ses.last_packet_time = time(NULL);
|
||||
|
||||
/* These packets we can receive at any time */
|
||||
switch(type) {
|
||||
|
||||
@@ -63,21 +65,19 @@ void process_packet() {
|
||||
case SSH_MSG_UNIMPLEMENTED:
|
||||
/* debugging XXX */
|
||||
TRACE(("SSH_MSG_UNIMPLEMENTED"))
|
||||
dropbear_exit("received SSH_MSG_UNIMPLEMENTED");
|
||||
dropbear_exit("Received SSH_MSG_UNIMPLEMENTED");
|
||||
|
||||
case SSH_MSG_DISCONNECT:
|
||||
/* TODO cleanup? */
|
||||
dropbear_close("Disconnect received");
|
||||
}
|
||||
|
||||
ses.last_packet_time = time(NULL);
|
||||
|
||||
/* This applies for KEX, where the spec says the next packet MUST be
|
||||
* NEWKEYS */
|
||||
if (ses.requirenext != 0) {
|
||||
if (ses.requirenext != type) {
|
||||
/* TODO send disconnect? */
|
||||
dropbear_exit("unexpected packet type %d, expected %d", type,
|
||||
dropbear_exit("Unexpected packet type %d, expected %d", type,
|
||||
ses.requirenext);
|
||||
} else {
|
||||
/* Got what we expected */
|
||||
@@ -99,7 +99,7 @@ void process_packet() {
|
||||
* NOTE: if the protocol changes and new types are added, revisit this
|
||||
* assumption */
|
||||
if ( !ses.authstate.authdone && type > MAX_UNAUTH_PACKET_TYPE ) {
|
||||
dropbear_exit("received message %d before userauth", type);
|
||||
dropbear_exit("Received message %d before userauth", type);
|
||||
}
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
|
||||
21
random.c
21
random.c
@@ -64,32 +64,23 @@ static void readrand(unsigned char* buf, unsigned int buflen) {
|
||||
#ifdef DROPBEAR_RANDOM_DEV
|
||||
readfd = open(DROPBEAR_RANDOM_DEV, O_RDONLY);
|
||||
if (readfd < 0) {
|
||||
dropbear_exit("couldn't open random device");
|
||||
dropbear_exit("Couldn't open random device");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_PRNGD_SOCKET
|
||||
memset((void*)&egdsock, 0x0, sizeof(egdsock));
|
||||
egdsock.sun_family = AF_UNIX;
|
||||
strlcpy(egdsock.sun_path, DROPBEAR_PRNGD_SOCKET,
|
||||
sizeof(egdsock.sun_path));
|
||||
readfd = connect_unix(DROPBEAR_PRNGD_SOCKET);
|
||||
|
||||
readfd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (readfd < 0) {
|
||||
dropbear_exit("couldn't open random device");
|
||||
}
|
||||
/* todo - try various common locations */
|
||||
if (connect(readfd, (struct sockaddr*)&egdsock,
|
||||
sizeof(struct sockaddr_un)) < 0) {
|
||||
dropbear_exit("couldn't open random device");
|
||||
dropbear_exit("Couldn't open random device");
|
||||
}
|
||||
|
||||
if (buflen > 255)
|
||||
dropbear_exit("can't request more than 255 bytes from egd");
|
||||
dropbear_exit("Can't request more than 255 bytes from egd");
|
||||
egdcmd[0] = 0x02; /* blocking read */
|
||||
egdcmd[1] = (unsigned char)buflen;
|
||||
if (write(readfd, egdcmd, 2) < 0)
|
||||
dropbear_exit("can't send command to egd");
|
||||
dropbear_exit("Can't send command to egd");
|
||||
#endif
|
||||
|
||||
/* read the actual random data */
|
||||
@@ -118,7 +109,7 @@ static void readrand(unsigned char* buf, unsigned int buflen) {
|
||||
if (readlen < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
dropbear_exit("error reading random source");
|
||||
dropbear_exit("Error reading random source");
|
||||
}
|
||||
readpos += readlen;
|
||||
} while (readpos < buflen);
|
||||
|
||||
34
rsa.c
34
rsa.c
@@ -38,7 +38,7 @@
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
static void rsa_pad_em(rsa_key * key,
|
||||
static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
const unsigned char * data, unsigned int len,
|
||||
mp_int * rsa_em);
|
||||
|
||||
@@ -46,7 +46,7 @@ static void rsa_pad_em(rsa_key * key,
|
||||
* The key will have the same format as buf_put_rsa_key.
|
||||
* These should be freed with rsa_key_free.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
|
||||
int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
TRACE(("enter buf_get_rsa_pub_key"))
|
||||
@@ -67,7 +67,7 @@ int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
|
||||
}
|
||||
|
||||
if (mp_count_bits(key->n) < MIN_RSA_KEYLEN) {
|
||||
dropbear_log(LOG_WARNING, "rsa key too short");
|
||||
dropbear_log(LOG_WARNING, "RSA key too short");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ out:
|
||||
/* Same as buf_get_rsa_pub_key, but reads private bits at the end.
|
||||
* Loads a private rsa key from a buffer
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_rsa_priv_key(buffer* buf, rsa_key *key) {
|
||||
int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE(("enter buf_get_rsa_priv_key"))
|
||||
@@ -137,7 +137,7 @@ out:
|
||||
|
||||
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void rsa_key_free(rsa_key *key) {
|
||||
void rsa_key_free(dropbear_rsa_key *key) {
|
||||
|
||||
TRACE(("enter rsa_key_free"))
|
||||
|
||||
@@ -175,7 +175,7 @@ void rsa_key_free(rsa_key *key) {
|
||||
* mp_int e
|
||||
* mp_int n
|
||||
*/
|
||||
void buf_put_rsa_pub_key(buffer* buf, rsa_key *key) {
|
||||
void buf_put_rsa_pub_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_rsa_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
@@ -189,7 +189,7 @@ void buf_put_rsa_pub_key(buffer* buf, rsa_key *key) {
|
||||
}
|
||||
|
||||
/* Same as buf_put_rsa_pub_key, but with the private "x" key appended */
|
||||
void buf_put_rsa_priv_key(buffer* buf, rsa_key *key) {
|
||||
void buf_put_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_rsa_priv_key"))
|
||||
|
||||
@@ -213,7 +213,7 @@ void buf_put_rsa_priv_key(buffer* buf, rsa_key *key) {
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a signature in buf, made on data by the key given.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
unsigned int slen;
|
||||
@@ -270,7 +270,7 @@ out:
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer */
|
||||
void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
unsigned int nsize, ssize;
|
||||
@@ -302,26 +302,26 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
|
||||
|
||||
/* rsa_s used as a temp var*/
|
||||
if (mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
dropbear_exit("RSA error");
|
||||
}
|
||||
if (mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
dropbear_exit("RSA error");
|
||||
}
|
||||
if (mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
dropbear_exit("RSA error");
|
||||
}
|
||||
|
||||
/* rsa_tmp2 is em' */
|
||||
/* s' = (em')^d mod n */
|
||||
if (mp_exptmod(&rsa_tmp2, key->d, key->n, &rsa_tmp1) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
dropbear_exit("RSA error");
|
||||
}
|
||||
|
||||
/* rsa_tmp1 is s' */
|
||||
/* rsa_tmp3 is r^(-1) mod n */
|
||||
/* s = (s')r^(-1) mod n */
|
||||
if (mp_mulmod(&rsa_tmp1, &rsa_tmp3, key->n, &rsa_s) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
dropbear_exit("RSA error");
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -329,7 +329,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
|
||||
/* s = em^d mod n */
|
||||
/* rsa_tmp1 is em */
|
||||
if (mp_exptmod(&rsa_tmp1, key->d, key->n, &rsa_s) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
dropbear_exit("RSA error");
|
||||
}
|
||||
|
||||
#endif /* RSA_BLINDING */
|
||||
@@ -351,7 +351,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
|
||||
}
|
||||
|
||||
if (mp_to_unsigned_bin(&rsa_s, buf_getwriteptr(buf, ssize)) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
dropbear_exit("RSA error");
|
||||
}
|
||||
buf_incrwritepos(buf, ssize);
|
||||
mp_clear(&rsa_s);
|
||||
@@ -376,7 +376,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
|
||||
*
|
||||
* rsa_em must be a pointer to an initialised mp_int.
|
||||
*/
|
||||
static void rsa_pad_em(rsa_key * key,
|
||||
static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
const unsigned char * data, unsigned int len,
|
||||
mp_int * rsa_em) {
|
||||
|
||||
|
||||
21
rsa.h
21
rsa.h
@@ -32,29 +32,28 @@
|
||||
|
||||
#define RSA_SIGNATURE_SIZE 4+7+4+40
|
||||
|
||||
struct RSA_key {
|
||||
typedef struct {
|
||||
|
||||
mp_int* n;
|
||||
mp_int* e;
|
||||
/* d, p, and q are private parts */
|
||||
mp_int* d;
|
||||
mp_int* p;
|
||||
mp_int* q;
|
||||
|
||||
};
|
||||
} dropbear_rsa_key;
|
||||
|
||||
typedef struct RSA_key rsa_key;
|
||||
|
||||
void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
#endif
|
||||
int buf_get_rsa_pub_key(buffer* buf, rsa_key *key);
|
||||
int buf_get_rsa_priv_key(buffer* buf, rsa_key *key);
|
||||
void buf_put_rsa_pub_key(buffer* buf, rsa_key *key);
|
||||
void buf_put_rsa_priv_key(buffer* buf, rsa_key *key);
|
||||
void rsa_key_free(rsa_key *key);
|
||||
int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key);
|
||||
int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key);
|
||||
void buf_put_rsa_pub_key(buffer* buf, dropbear_rsa_key *key);
|
||||
void buf_put_rsa_priv_key(buffer* buf, dropbear_rsa_key *key);
|
||||
void rsa_key_free(dropbear_rsa_key *key);
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
|
||||
26
runopts.h
26
runopts.h
@@ -37,8 +37,16 @@ typedef struct runopts {
|
||||
int listen_fwd_all;
|
||||
#endif
|
||||
unsigned int recv_window;
|
||||
unsigned int keepalive_secs;
|
||||
unsigned int idle_timeout_secs;
|
||||
time_t keepalive_secs;
|
||||
time_t idle_timeout_secs;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* 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;
|
||||
#endif
|
||||
|
||||
|
||||
} runopts;
|
||||
|
||||
@@ -112,13 +120,20 @@ typedef struct cli_runopts {
|
||||
int backgrounded;
|
||||
int is_subsystem;
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
struct SignKeyList *privkeys; /* Keys to use for public-key auth */
|
||||
m_list *privkeys; /* Keys to use for public-key auth */
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
struct TCPFwdList * remotefwds;
|
||||
m_list * remotefwds;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
struct TCPFwdList * localfwds;
|
||||
m_list * localfwds;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
int agent_fwd;
|
||||
int agent_keys_loaded; /* whether pubkeys has been populated with a
|
||||
list of keys held by the agent */
|
||||
int agent_fd; /* The agent fd is only set during authentication. Forwarded
|
||||
agent sessions have their own file descriptors */
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
@@ -128,7 +143,6 @@ typedef struct cli_runopts {
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
char *proxycmd;
|
||||
#endif
|
||||
|
||||
} cli_runopts;
|
||||
|
||||
extern cli_runopts cli_opts;
|
||||
|
||||
6
scp.c
6
scp.c
@@ -343,7 +343,7 @@ main(int argc, char **argv)
|
||||
addargs(&args, "-p%s", optarg);
|
||||
break;
|
||||
case 'B':
|
||||
addargs(&args, "-oBatchmode yes");
|
||||
fprintf(stderr, "Note: -B option is disabled in this version of scp");
|
||||
break;
|
||||
case 'l':
|
||||
speed = strtod(optarg, &endp);
|
||||
@@ -492,9 +492,13 @@ toremote(char *targ, int argc, char **argv)
|
||||
addargs(&alist, "%s", ssh_program);
|
||||
if (verbose_mode)
|
||||
addargs(&alist, "-v");
|
||||
#if 0
|
||||
// Disabled since dbclient won't understand them
|
||||
// and scp works fine without them.
|
||||
addargs(&alist, "-x");
|
||||
addargs(&alist, "-oClearAllForwardings yes");
|
||||
addargs(&alist, "-n");
|
||||
#endif
|
||||
|
||||
*src++ = 0;
|
||||
if (*src == 0)
|
||||
|
||||
71
session.h
71
session.h
@@ -41,7 +41,7 @@
|
||||
extern int sessinitdone; /* Is set to 0 somewhere */
|
||||
extern int exitflag;
|
||||
|
||||
void common_session_init(int sock_in, int sock_out, char* remotehost);
|
||||
void common_session_init(int sock_in, int sock_out);
|
||||
void session_loop(void(*loophandler)());
|
||||
void common_session_cleanup();
|
||||
void session_identification();
|
||||
@@ -51,51 +51,45 @@ const char* get_user_shell();
|
||||
void fill_passwd(const char* username);
|
||||
|
||||
/* Server */
|
||||
void svr_session(int sock, int childpipe, char *remotehost, char *addrstring);
|
||||
void svr_session(int sock, int childpipe);
|
||||
void svr_dropbear_exit(int exitcode, const char* format, va_list param);
|
||||
void svr_dropbear_log(int priority, const char* format, va_list param);
|
||||
|
||||
/* Client */
|
||||
void cli_session(int sock_in, int sock_out, char *remotehost);
|
||||
void cli_session(int sock_in, int sock_out);
|
||||
void cli_session_cleanup();
|
||||
void cleantext(unsigned char* dirtytext);
|
||||
|
||||
struct key_context {
|
||||
|
||||
const struct dropbear_cipher *recv_algo_crypt; /* NULL for none */
|
||||
const struct dropbear_cipher *trans_algo_crypt; /* NULL for none */
|
||||
const struct dropbear_cipher_mode *recv_crypt_mode;
|
||||
const struct dropbear_cipher_mode *trans_crypt_mode;
|
||||
const struct dropbear_hash *recv_algo_mac; /* NULL for none */
|
||||
const struct dropbear_hash *trans_algo_mac; /* NULL for none */
|
||||
char algo_kex;
|
||||
char algo_hostkey;
|
||||
|
||||
char recv_algo_comp; /* compression */
|
||||
char trans_algo_comp;
|
||||
int allow_compress; /* whether compression has started (useful in
|
||||
zlib@openssh.com delayed compression case) */
|
||||
/* crypto parameters that are stored individually for transmit and receive */
|
||||
struct key_context_directional {
|
||||
const struct dropbear_cipher *algo_crypt; /* NULL for none */
|
||||
const struct dropbear_cipher_mode *crypt_mode;
|
||||
const struct dropbear_hash *algo_mac; /* NULL for none */
|
||||
int hash_index; /* lookup for libtomcrypt */
|
||||
char algo_comp; /* compression */
|
||||
#ifndef DISABLE_ZLIB
|
||||
z_streamp recv_zstream;
|
||||
z_streamp trans_zstream;
|
||||
z_streamp zstream;
|
||||
#endif
|
||||
|
||||
/* actual keys */
|
||||
union {
|
||||
symmetric_CBC cbc;
|
||||
#ifdef DROPBEAR_ENABLE_CTR_MODE
|
||||
symmetric_CTR ctr;
|
||||
#endif
|
||||
} recv_cipher_state;
|
||||
union {
|
||||
symmetric_CBC cbc;
|
||||
#ifdef DROPBEAR_ENABLE_CTR_MODE
|
||||
symmetric_CTR ctr;
|
||||
#endif
|
||||
} trans_cipher_state;
|
||||
unsigned char recvmackey[MAX_MAC_KEY];
|
||||
unsigned char transmackey[MAX_MAC_KEY];
|
||||
} cipher_state;
|
||||
unsigned char mackey[MAX_MAC_KEY];
|
||||
};
|
||||
|
||||
struct key_context {
|
||||
|
||||
struct key_context_directional recv;
|
||||
struct key_context_directional trans;
|
||||
|
||||
char algo_kex;
|
||||
char algo_hostkey;
|
||||
|
||||
int allow_compress; /* whether compression has started (useful in
|
||||
zlib@openssh.com delayed compression case) */
|
||||
};
|
||||
|
||||
struct packetlist;
|
||||
@@ -116,8 +110,6 @@ struct sshsession {
|
||||
int sock_in;
|
||||
int sock_out;
|
||||
|
||||
unsigned char *remotehost; /* the peer hostname */
|
||||
|
||||
unsigned char *remoteident;
|
||||
|
||||
int maxfd; /* the maximum file descriptor to check with select() */
|
||||
@@ -128,8 +120,7 @@ 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 */
|
||||
buffer *readbuf; /* Encrypted */
|
||||
buffer *decryptreadbuf; /* Post-decryption */
|
||||
buffer *readbuf; /* From the wire, decrypted in-place */
|
||||
buffer *payload; /* Post-decompression, the actual SSH packet */
|
||||
unsigned int transseq, recvseq; /* Sequence IDs */
|
||||
|
||||
@@ -169,6 +160,9 @@ struct sshsession {
|
||||
buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
|
||||
buffer* transkexinit; /* the kexinit packet we send should be kept so we
|
||||
can add it to the hash when generating keys */
|
||||
|
||||
/* Enables/disables compression */
|
||||
algo_type *compress_algos;
|
||||
|
||||
/* a list of queued replies that should be sent after a KEX has
|
||||
concluded (ie, while dataallowed was unset)*/
|
||||
@@ -220,6 +214,13 @@ struct serversession {
|
||||
/* The numeric address they connected from, used for logging */
|
||||
char * addrstring;
|
||||
|
||||
/* The resolved remote address, used for lastlog etc */
|
||||
char *remotehost;
|
||||
|
||||
#ifdef __uClinux__
|
||||
pid_t server_pid;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@@ -268,7 +269,7 @@ struct clientsession {
|
||||
info request from the server for
|
||||
interactive auth.*/
|
||||
#endif
|
||||
struct SignKeyList *lastprivkey;
|
||||
sign_key *lastprivkey;
|
||||
|
||||
int retval; /* What the command exit status was - we emulate it */
|
||||
#if 0
|
||||
|
||||
35
signkey.c
35
signkey.c
@@ -40,8 +40,10 @@ sign_key * new_sign_key() {
|
||||
#ifdef DROPBEAR_RSA
|
||||
ret->rsakey = NULL;
|
||||
#endif
|
||||
ret->filename = NULL;
|
||||
ret->type = DROPBEAR_SIGNKEY_NONE;
|
||||
ret->source = SIGNKEY_SOURCE_INVALID;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally
|
||||
@@ -60,7 +62,7 @@ const char* signkey_name_from_type(int type, int *namelen) {
|
||||
return SSH_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
dropbear_exit("bad key type %d", type);
|
||||
dropbear_exit("Bad key type %d", type);
|
||||
return NULL; /* notreached */
|
||||
}
|
||||
|
||||
@@ -81,6 +83,8 @@ int signkey_type_from_name(const char* name, int namelen) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("signkey_type_from_name unexpected key type."))
|
||||
|
||||
return DROPBEAR_SIGNKEY_NONE;
|
||||
}
|
||||
|
||||
@@ -101,8 +105,11 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
m_free(ident);
|
||||
|
||||
if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
|
||||
TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype, type))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
TRACE(("buf_get_pub_key keytype is %d"))
|
||||
|
||||
*type = keytype;
|
||||
|
||||
@@ -112,7 +119,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
dss_key_free(key->dsskey);
|
||||
key->dsskey = (dss_key*)m_malloc(sizeof(dss_key));
|
||||
key->dsskey = m_malloc(sizeof(*key->dsskey));
|
||||
ret = buf_get_dss_pub_key(buf, key->dsskey);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(key->dsskey);
|
||||
@@ -122,7 +129,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
rsa_key_free(key->rsakey);
|
||||
key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key));
|
||||
key->rsakey = m_malloc(sizeof(*key->rsakey));
|
||||
ret = buf_get_rsa_pub_key(buf, key->rsakey);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(key->rsakey);
|
||||
@@ -165,7 +172,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
dss_key_free(key->dsskey);
|
||||
key->dsskey = (dss_key*)m_malloc(sizeof(dss_key));
|
||||
key->dsskey = m_malloc(sizeof(*key->dsskey));
|
||||
ret = buf_get_dss_priv_key(buf, key->dsskey);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(key->dsskey);
|
||||
@@ -175,7 +182,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
rsa_key_free(key->rsakey);
|
||||
key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key));
|
||||
key->rsakey = m_malloc(sizeof(*key->rsakey));
|
||||
ret = buf_get_rsa_priv_key(buf, key->rsakey);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(key->rsakey);
|
||||
@@ -208,7 +215,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
|
||||
}
|
||||
#endif
|
||||
if (pubkeys->len == 0) {
|
||||
dropbear_exit("bad key types in buf_put_pub_key");
|
||||
dropbear_exit("Bad key types in buf_put_pub_key");
|
||||
}
|
||||
|
||||
buf_setpos(pubkeys, 0);
|
||||
@@ -239,7 +246,7 @@ void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
dropbear_exit("bad key types in put pub key");
|
||||
dropbear_exit("Bad key types in put pub key");
|
||||
}
|
||||
|
||||
void sign_key_free(sign_key *key) {
|
||||
@@ -255,6 +262,8 @@ void sign_key_free(sign_key *key) {
|
||||
key->rsakey = NULL;
|
||||
#endif
|
||||
|
||||
m_free(key->filename);
|
||||
|
||||
m_free(key);
|
||||
TRACE(("leave sign_key_free"))
|
||||
}
|
||||
@@ -358,7 +367,6 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
|
||||
buffer *sigblob;
|
||||
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
@@ -372,9 +380,8 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
}
|
||||
#endif
|
||||
if (sigblob->len == 0) {
|
||||
dropbear_exit("non-matching signing type");
|
||||
dropbear_exit("Non-matching signing type");
|
||||
}
|
||||
|
||||
buf_setpos(sigblob, 0);
|
||||
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
|
||||
sigblob->len);
|
||||
@@ -405,7 +412,7 @@ int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
|
||||
memcmp(ident, SSH_SIGNKEY_DSS, identlen) == 0) {
|
||||
m_free(ident);
|
||||
if (key->dsskey == NULL) {
|
||||
dropbear_exit("no dss key to verify signature");
|
||||
dropbear_exit("No DSS key to verify signature");
|
||||
}
|
||||
return buf_dss_verify(buf, key->dsskey, data, len);
|
||||
}
|
||||
@@ -415,14 +422,14 @@ int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
|
||||
if (memcmp(ident, SSH_SIGNKEY_RSA, identlen) == 0) {
|
||||
m_free(ident);
|
||||
if (key->rsakey == NULL) {
|
||||
dropbear_exit("no rsa key to verify signature");
|
||||
dropbear_exit("No RSA key to verify signature");
|
||||
}
|
||||
return buf_rsa_verify(buf, key->rsakey, data, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_free(ident);
|
||||
dropbear_exit("non-matching signing type");
|
||||
dropbear_exit("Non-matching signing type");
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
18
signkey.h
18
signkey.h
@@ -29,13 +29,27 @@
|
||||
#include "dss.h"
|
||||
#include "rsa.h"
|
||||
|
||||
|
||||
/* Sources for signing keys */
|
||||
typedef enum {
|
||||
SIGNKEY_SOURCE_RAW_FILE,
|
||||
SIGNKEY_SOURCE_AGENT,
|
||||
SIGNKEY_SOURCE_INVALID,
|
||||
} signkey_source;
|
||||
|
||||
struct SIGN_key {
|
||||
|
||||
int type; /* The type of key (dss or rsa) */
|
||||
signkey_source source;
|
||||
char *filename;
|
||||
/* the buffer? for encrypted keys, so we can later get
|
||||
* the private key portion */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
dss_key * dsskey;
|
||||
dropbear_dss_key * dsskey;
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
rsa_key * rsakey;
|
||||
dropbear_rsa_key * rsakey;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
11
ssh.h
11
ssh.h
@@ -105,3 +105,14 @@
|
||||
#define SSH_SIGNKEY_DSS_LEN 7
|
||||
#define SSH_SIGNKEY_RSA "ssh-rsa"
|
||||
#define SSH_SIGNKEY_RSA_LEN 7
|
||||
|
||||
/* Agent commands. These aren't part of the spec, and are defined
|
||||
* only on the openssh implementation. */
|
||||
#define SSH_AGENT_FAILURE 5
|
||||
#define SSH_AGENT_SUCCESS 6
|
||||
#define SSH2_AGENTC_REQUEST_IDENTITIES 11
|
||||
#define SSH2_AGENT_IDENTITIES_ANSWER 12
|
||||
#define SSH2_AGENTC_SIGN_REQUEST 13
|
||||
#define SSH2_AGENT_SIGN_RESPONSE 14
|
||||
|
||||
#define SSH2_AGENT_FAILURE 30
|
||||
|
||||
2
sshpty.c
2
sshpty.c
@@ -234,7 +234,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
|
||||
|
||||
return 1;
|
||||
}
|
||||
dropbear_log(LOG_WARNING, "failed to open any /dev/pty?? devices");
|
||||
dropbear_log(LOG_WARNING, "Failed to open any /dev/pty?? devices");
|
||||
return 0;
|
||||
#endif /* HAVE_DEV_PTS_AND_PTC */
|
||||
#endif /* USE_DEV_PTMX */
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
|
||||
#include "agentfwd.h"
|
||||
#include "session.h"
|
||||
@@ -49,10 +49,12 @@ static void agentaccept(struct Listener * listener, int sock);
|
||||
|
||||
/* Handles client requests to start agent forwarding, sets up listening socket.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int agentreq(struct ChanSess * chansess) {
|
||||
int svr_agentreq(struct ChanSess * chansess) {
|
||||
|
||||
int fd;
|
||||
|
||||
TRACE(("enter svr_agentreq"))
|
||||
|
||||
if (!svr_pubkey_allows_agentfwd()) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
@@ -89,10 +91,12 @@ int agentreq(struct ChanSess * chansess) {
|
||||
}
|
||||
|
||||
return DROPBEAR_SUCCESS;
|
||||
TRACE(("success"))
|
||||
|
||||
fail:
|
||||
TRACE(("fail"))
|
||||
/* cleanup */
|
||||
agentcleanup(chansess);
|
||||
svr_agentcleanup(chansess);
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
@@ -118,7 +122,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 */
|
||||
void agentset(struct ChanSess * chansess) {
|
||||
void svr_agentset(struct ChanSess * chansess) {
|
||||
|
||||
char *path = NULL;
|
||||
int len;
|
||||
@@ -137,7 +141,7 @@ void agentset(struct ChanSess * chansess) {
|
||||
}
|
||||
|
||||
/* close the socket, remove the socket-file */
|
||||
void agentcleanup(struct ChanSess * chansess) {
|
||||
void svr_agentcleanup(struct ChanSess * chansess) {
|
||||
|
||||
char *path = NULL;
|
||||
uid_t uid;
|
||||
@@ -157,7 +161,7 @@ void agentcleanup(struct ChanSess * chansess) {
|
||||
gid = getgid();
|
||||
if ((setegid(ses.authstate.pw_gid)) < 0 ||
|
||||
(seteuid(ses.authstate.pw_uid)) < 0) {
|
||||
dropbear_exit("failed to set euid");
|
||||
dropbear_exit("Failed to set euid");
|
||||
}
|
||||
|
||||
/* 2 for "/" and "\0" */
|
||||
@@ -172,7 +176,7 @@ void agentcleanup(struct ChanSess * chansess) {
|
||||
|
||||
if ((seteuid(uid)) < 0 ||
|
||||
(setegid(gid)) < 0) {
|
||||
dropbear_exit("failed to revert euid");
|
||||
dropbear_exit("Failed to revert euid");
|
||||
}
|
||||
|
||||
m_free(chansess->agentfile);
|
||||
@@ -181,7 +185,7 @@ void agentcleanup(struct ChanSess * chansess) {
|
||||
|
||||
}
|
||||
|
||||
static const struct ChanType chan_agent = {
|
||||
static const struct ChanType chan_svr_agent = {
|
||||
0, /* sepfds */
|
||||
"auth-agent@openssh.com",
|
||||
NULL,
|
||||
@@ -194,7 +198,7 @@ static const struct ChanType chan_agent = {
|
||||
/* helper for accepting an agent request */
|
||||
static int send_msg_channel_open_agent(int fd) {
|
||||
|
||||
if (send_msg_channel_open_init(fd, &chan_agent) == DROPBEAR_SUCCESS) {
|
||||
if (send_msg_channel_open_init(fd, &chan_svr_agent) == DROPBEAR_SUCCESS) {
|
||||
encrypt_packet();
|
||||
return DROPBEAR_SUCCESS;
|
||||
} else {
|
||||
@@ -220,7 +224,7 @@ static int bindagent(int fd, struct ChanSess * chansess) {
|
||||
gid = getgid();
|
||||
if ((setegid(ses.authstate.pw_gid)) < 0 ||
|
||||
(seteuid(ses.authstate.pw_uid)) < 0) {
|
||||
dropbear_exit("failed to set euid");
|
||||
dropbear_exit("Failed to set euid");
|
||||
}
|
||||
|
||||
memset((void*)&addr, 0x0, sizeof(addr));
|
||||
@@ -263,7 +267,7 @@ bindsocket:
|
||||
out:
|
||||
if ((seteuid(uid)) < 0 ||
|
||||
(setegid(gid)) < 0) {
|
||||
dropbear_exit("failed to revert euid");
|
||||
dropbear_exit("Failed to revert euid");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
15
svr-auth.c
15
svr-auth.c
@@ -33,6 +33,7 @@
|
||||
#include "packet.h"
|
||||
#include "auth.h"
|
||||
#include "runopts.h"
|
||||
#include "random.h"
|
||||
|
||||
static void authclear();
|
||||
static int checkusername(unsigned char *username, unsigned int userlen);
|
||||
@@ -221,7 +222,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
strcmp(username, ses.authstate.username) != 0) {
|
||||
/* the username needs resetting */
|
||||
if (ses.authstate.username != NULL) {
|
||||
dropbear_log(LOG_WARNING, "client trying multiple usernames from %s",
|
||||
dropbear_log(LOG_WARNING, "Client trying multiple usernames from %s",
|
||||
svr_ses.addrstring);
|
||||
m_free(ses.authstate.username);
|
||||
}
|
||||
@@ -234,7 +235,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
if (!ses.authstate.pw_name) {
|
||||
TRACE(("leave checkusername: user '%s' doesn't exist", username))
|
||||
dropbear_log(LOG_WARNING,
|
||||
"login attempt for nonexistent user from %s",
|
||||
"Login attempt for nonexistent user from %s",
|
||||
svr_ses.addrstring);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
@@ -251,7 +252,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
/* check for an empty password */
|
||||
if (ses.authstate.pw_passwd[0] == '\0') {
|
||||
TRACE(("leave checkusername: empty pword"))
|
||||
dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
|
||||
dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
@@ -280,7 +281,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
/* no matching shell */
|
||||
endusershell();
|
||||
TRACE(("no matching shell"))
|
||||
dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected",
|
||||
dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
@@ -337,7 +338,11 @@ void send_msg_userauth_failure(int partial, int incrfail) {
|
||||
encrypt_packet();
|
||||
|
||||
if (incrfail) {
|
||||
usleep(300000); /* XXX improve this */
|
||||
unsigned int delay;
|
||||
genrandom((unsigned char*)&delay, sizeof(delay));
|
||||
/* We delay for 300ms +- 50ms, 0.1ms granularity */
|
||||
delay = 250000 + (delay % 1000)*100;
|
||||
usleep(delay);
|
||||
ses.authstate.failcount++;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,8 +101,9 @@ pamConvFunc(int num_msg,
|
||||
if (!(strcmp(compare_message, "password:") == 0)) {
|
||||
/* We don't recognise the prompt as asking for a password,
|
||||
so can't handle it. Add more above as required for
|
||||
different pam modules/implementations */
|
||||
dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (no echo)",
|
||||
different pam modules/implementations. If you need
|
||||
to add an entry here please mail the Dropbear developer */
|
||||
dropbear_log(LOG_NOTICE, "PAM unknown prompt '%s' (no echo)",
|
||||
compare_message);
|
||||
rc = PAM_CONV_ERR;
|
||||
break;
|
||||
@@ -123,12 +124,16 @@ pamConvFunc(int num_msg,
|
||||
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
|
||||
if (!((strcmp(compare_message, "login:" ) == 0)
|
||||
|| (strcmp(compare_message, "please enter username:") == 0))) {
|
||||
if (!(
|
||||
(strcmp(compare_message, "login:" ) == 0)
|
||||
|| (strcmp(compare_message, "please enter username:") == 0)
|
||||
|| (strcmp(compare_message, "username:") == 0)
|
||||
)) {
|
||||
/* We don't recognise the prompt as asking for a username,
|
||||
so can't handle it. Add more above as required for
|
||||
different pam modules/implementations */
|
||||
dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (with echo)",
|
||||
different pam modules/implementations. If you need
|
||||
to add an entry here please mail the Dropbear developer */
|
||||
dropbear_log(LOG_NOTICE, "PAM unknown prompt '%s' (with echo)",
|
||||
compare_message);
|
||||
rc = PAM_CONV_ERR;
|
||||
break;
|
||||
@@ -212,7 +217,10 @@ void svr_auth_pam() {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PAM_FAIL_DELAY
|
||||
/* We have our own random delay code already, disable PAM's */
|
||||
(void) pam_fail_delay(pamHandlep, 0 /* musec_delay */);
|
||||
#endif
|
||||
|
||||
/* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */
|
||||
|
||||
@@ -220,7 +228,7 @@ void svr_auth_pam() {
|
||||
dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
dropbear_log(LOG_WARNING,
|
||||
"bad PAM password attempt for '%s' from %s",
|
||||
"Bad PAM password attempt for '%s' from %s",
|
||||
ses.authstate.pw_name,
|
||||
svr_ses.addrstring);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
@@ -231,7 +239,7 @@ void svr_auth_pam() {
|
||||
dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
dropbear_log(LOG_WARNING,
|
||||
"bad PAM password attempt for '%s' from %s",
|
||||
"Bad PAM password attempt for '%s' from %s",
|
||||
ses.authstate.pw_name,
|
||||
svr_ses.addrstring);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
|
||||
@@ -64,7 +64,7 @@ void svr_auth_password() {
|
||||
* since the shadow password may differ to that tested
|
||||
* in auth.c */
|
||||
if (passwdcrypt[0] == '\0') {
|
||||
dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
|
||||
dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return;
|
||||
@@ -88,13 +88,13 @@ void svr_auth_password() {
|
||||
if (strcmp(testcrypt, passwdcrypt) == 0) {
|
||||
/* successful authentication */
|
||||
dropbear_log(LOG_NOTICE,
|
||||
"password auth succeeded for '%s' from %s",
|
||||
"Password auth succeeded for '%s' from %s",
|
||||
ses.authstate.pw_name,
|
||||
svr_ses.addrstring);
|
||||
send_msg_userauth_success();
|
||||
} else {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"bad password attempt for '%s' from %s",
|
||||
"Bad password attempt for '%s' from %s",
|
||||
ses.authstate.pw_name,
|
||||
svr_ses.addrstring);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
|
||||
@@ -135,12 +135,12 @@ void svr_auth_pubkey() {
|
||||
if (buf_verify(ses.payload, key, buf_getptr(signbuf, signbuf->len),
|
||||
signbuf->len) == DROPBEAR_SUCCESS) {
|
||||
dropbear_log(LOG_NOTICE,
|
||||
"pubkey auth succeeded for '%s' with key %s from %s",
|
||||
"Pubkey auth succeeded for '%s' with key %s from %s",
|
||||
ses.authstate.pw_name, fp, svr_ses.addrstring);
|
||||
send_msg_userauth_success();
|
||||
} else {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"pubkey auth bad signature for '%s' with key %s from %s",
|
||||
"Pubkey auth bad signature for '%s' with key %s from %s",
|
||||
ses.authstate.pw_name, fp, svr_ses.addrstring);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
}
|
||||
@@ -198,7 +198,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
|
||||
/* check that we can use the algo */
|
||||
if (have_algo(algo, algolen, sshhostkey) == DROPBEAR_FAILURE) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"pubkey auth attempt with unknown algo for '%s' from %s",
|
||||
"Pubkey auth attempt with unknown algo for '%s' from %s",
|
||||
ses.authstate.pw_name, svr_ses.addrstring);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -88,10 +88,20 @@ int svr_pubkey_allows_pty() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set chansession command to the one forced by 'command' public key option */
|
||||
/* 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->original_command = chansess->cmd;
|
||||
if (!chansess->cmd)
|
||||
{
|
||||
ses.authstate.pubkey_options->original_command = m_strdup("");
|
||||
}
|
||||
chansess->cmd = ses.authstate.pubkey_options->forced_command;
|
||||
#ifdef LOG_COMMANDS
|
||||
dropbear_log(LOG_INFO, "Command forced to '%s'", ses.authstate.pubkey_options->original_command);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Free potential public key options */
|
||||
@@ -124,7 +134,6 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
|
||||
TRACE(("enter addpubkeyoptions"))
|
||||
|
||||
ses.authstate.pubkey_options = (struct PubKeyOptions*)m_malloc(sizeof( struct PubKeyOptions ));
|
||||
memset(ses.authstate.pubkey_options, '\0', sizeof(*ses.authstate.pubkey_options));
|
||||
|
||||
buf_setpos(options_buf, 0);
|
||||
while (options_buf->pos < options_buf->len) {
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "termcodes.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
#include "utmp.h"
|
||||
#include "x11fwd.h"
|
||||
#include "agentfwd.h"
|
||||
#include "runopts.h"
|
||||
@@ -222,6 +221,7 @@ static int newchansess(struct Channel *channel) {
|
||||
|
||||
chansess = (struct ChanSess*)m_malloc(sizeof(struct ChanSess));
|
||||
chansess->cmd = NULL;
|
||||
chansess->connection_string = NULL;
|
||||
chansess->pid = 0;
|
||||
|
||||
/* pty details */
|
||||
@@ -240,7 +240,7 @@ static int newchansess(struct Channel *channel) {
|
||||
chansess->x11authcookie = NULL;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
#ifdef ENABLE_AGENTFWD
|
||||
chansess->agentlistener = NULL;
|
||||
chansess->agentfile = NULL;
|
||||
chansess->agentdir = NULL;
|
||||
@@ -250,6 +250,14 @@ static int newchansess(struct Channel *channel) {
|
||||
|
||||
}
|
||||
|
||||
static struct logininfo*
|
||||
chansess_login_alloc(struct ChanSess *chansess) {
|
||||
struct logininfo * li;
|
||||
li = login_alloc_entry(chansess->pid, ses.authstate.username,
|
||||
svr_ses.remotehost, chansess->tty);
|
||||
return li;
|
||||
}
|
||||
|
||||
/* clean a session channel */
|
||||
static void closechansess(struct Channel *channel) {
|
||||
|
||||
@@ -273,8 +281,7 @@ static void closechansess(struct Channel *channel) {
|
||||
|
||||
if (chansess->tty) {
|
||||
/* write the utmp/wtmp login record */
|
||||
li = login_alloc_entry(chansess->pid, ses.authstate.username,
|
||||
ses.remotehost, chansess->tty);
|
||||
li = chansess_login_alloc(chansess);
|
||||
login_logout(li);
|
||||
login_free_entry(li);
|
||||
|
||||
@@ -286,8 +293,8 @@ static void closechansess(struct Channel *channel) {
|
||||
x11cleanup(chansess);
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
agentcleanup(chansess);
|
||||
#ifdef ENABLE_AGENTFWD
|
||||
svr_agentcleanup(chansess);
|
||||
#endif
|
||||
|
||||
/* clear child pid entries */
|
||||
@@ -344,9 +351,9 @@ static void chansessionrequest(struct Channel *channel) {
|
||||
} else if (strcmp(type, "x11-req") == 0) {
|
||||
ret = x11req(chansess);
|
||||
#endif
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
#ifdef ENABLE_AGENTFWD
|
||||
} else if (strcmp(type, "auth-agent-req@openssh.com") == 0) {
|
||||
ret = agentreq(chansess);
|
||||
ret = svr_agentreq(chansess);
|
||||
#endif
|
||||
} else if (strcmp(type, "signal") == 0) {
|
||||
ret = sessionsignal(chansess);
|
||||
@@ -448,7 +455,7 @@ static void get_termmodes(struct ChanSess *chansess) {
|
||||
TRACE(("term mode str %d p->l %d p->p %d",
|
||||
len, ses.payload->len , ses.payload->pos));
|
||||
if (len != ses.payload->len - ses.payload->pos) {
|
||||
dropbear_exit("bad term mode string");
|
||||
dropbear_exit("Bad term mode string");
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
@@ -513,7 +520,7 @@ static void get_termmodes(struct ChanSess *chansess) {
|
||||
}
|
||||
}
|
||||
if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) {
|
||||
dropbear_log(LOG_INFO, "error setting terminal attributes");
|
||||
dropbear_log(LOG_INFO, "Error setting terminal attributes");
|
||||
}
|
||||
TRACE(("leave get_termmodes"))
|
||||
}
|
||||
@@ -543,7 +550,7 @@ static int sessionpty(struct ChanSess * chansess) {
|
||||
|
||||
/* allocate the pty */
|
||||
if (chansess->master != -1) {
|
||||
dropbear_exit("multiple pty requests");
|
||||
dropbear_exit("Multiple pty requests");
|
||||
}
|
||||
if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) {
|
||||
TRACE(("leave sessionpty: failed to allocate pty"))
|
||||
@@ -552,7 +559,7 @@ static int sessionpty(struct ChanSess * chansess) {
|
||||
|
||||
chansess->tty = (char*)m_strdup(namebuf);
|
||||
if (!chansess->tty) {
|
||||
dropbear_exit("out of memory"); /* TODO disconnect */
|
||||
dropbear_exit("Out of memory"); /* TODO disconnect */
|
||||
}
|
||||
|
||||
pw = getpwnam(ses.authstate.pw_name);
|
||||
@@ -570,6 +577,21 @@ static int sessionpty(struct ChanSess * chansess) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
static char* make_connection_string() {
|
||||
char *local_ip, *local_port, *remote_ip, *remote_port;
|
||||
size_t len;
|
||||
char *ret;
|
||||
get_socket_address(ses.sock_in, &local_ip, &local_port, &remote_ip, &remote_port, 0);
|
||||
len = strlen(local_ip) + strlen(local_port) + strlen(remote_ip) + strlen(remote_port) + 4;
|
||||
ret = m_malloc(len);
|
||||
snprintf(ret, len, "%s %s %s %s", remote_ip, remote_port, local_ip, local_port);
|
||||
m_free(local_ip);
|
||||
m_free(local_port);
|
||||
m_free(remote_ip);
|
||||
m_free(remote_port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Handle a command request from the client. This is used for both shell
|
||||
* and command-execution requests, and passes the command to
|
||||
* noptycommand or ptycommand as appropriate.
|
||||
@@ -589,9 +611,6 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* take public key option 'command' into account */
|
||||
svr_pubkey_set_forced_command(chansess);
|
||||
|
||||
if (iscmd) {
|
||||
/* "exec" */
|
||||
if (chansess->cmd == NULL) {
|
||||
@@ -616,17 +635,26 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* take public key option 'command' into account */
|
||||
svr_pubkey_set_forced_command(chansess);
|
||||
|
||||
#ifdef LOG_COMMANDS
|
||||
if (chansess->cmd) {
|
||||
dropbear_log(LOG_INFO, "user %s executing '%s'",
|
||||
dropbear_log(LOG_INFO, "User %s executing '%s'",
|
||||
ses.authstate.pw_name, chansess->cmd);
|
||||
} else {
|
||||
dropbear_log(LOG_INFO, "user %s executing login shell",
|
||||
dropbear_log(LOG_INFO, "User %s executing login shell",
|
||||
ses.authstate.pw_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* uClinux will vfork(), so there'll be a race as
|
||||
connection_string is freed below. */
|
||||
#ifndef __uClinux__
|
||||
chansess->connection_string = make_connection_string();
|
||||
#endif
|
||||
|
||||
if (chansess->term == NULL) {
|
||||
/* no pty */
|
||||
ret = noptycommand(channel, chansess);
|
||||
@@ -635,6 +663,10 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
ret = ptycommand(channel, chansess);
|
||||
}
|
||||
|
||||
#ifndef __uClinux__
|
||||
m_free(chansess->connection_string);
|
||||
#endif
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(chansess->cmd);
|
||||
}
|
||||
@@ -699,7 +731,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
|
||||
|
||||
/* we need to have a pty allocated */
|
||||
if (chansess->master == -1 || chansess->tty == NULL) {
|
||||
dropbear_log(LOG_WARNING, "no pty was allocated, couldn't execute");
|
||||
dropbear_log(LOG_WARNING, "No pty was allocated, couldn't execute");
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
@@ -736,13 +768,10 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
|
||||
|
||||
/* write the utmp/wtmp login record - must be after changing the
|
||||
* terminal used for stdout with the dup2 above */
|
||||
li= login_alloc_entry(getpid(), ses.authstate.username,
|
||||
ses.remotehost, chansess->tty);
|
||||
li = chansess_login_alloc(chansess);
|
||||
login_login(li);
|
||||
login_free_entry(li);
|
||||
|
||||
m_free(chansess->tty);
|
||||
|
||||
#ifdef DO_MOTD
|
||||
if (svr_opts.domotd) {
|
||||
/* don't show the motd if ~/.hushlogin exists */
|
||||
@@ -855,10 +884,10 @@ static void execchild(void *user_data) {
|
||||
if ((setgid(ses.authstate.pw_gid) < 0) ||
|
||||
(initgroups(ses.authstate.pw_name,
|
||||
ses.authstate.pw_gid) < 0)) {
|
||||
dropbear_exit("error changing user group");
|
||||
dropbear_exit("Error changing user group");
|
||||
}
|
||||
if (setuid(ses.authstate.pw_uid) < 0) {
|
||||
dropbear_exit("error changing user");
|
||||
dropbear_exit("Error changing user");
|
||||
}
|
||||
} else {
|
||||
/* ... but if the daemon is the same uid as the requested uid, we don't
|
||||
@@ -869,7 +898,7 @@ static void execchild(void *user_data) {
|
||||
* differing groups won't be set (as with initgroups()). The solution
|
||||
* is for the sysadmin not to give out the UID twice */
|
||||
if (getuid() != ses.authstate.pw_uid) {
|
||||
dropbear_exit("couldn't change user as non-root");
|
||||
dropbear_exit("Couldn't change user as non-root");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,25 +912,41 @@ static void execchild(void *user_data) {
|
||||
addnewvar("TERM", chansess->term);
|
||||
}
|
||||
|
||||
if (chansess->tty) {
|
||||
addnewvar("SSH_TTY", chansess->tty);
|
||||
}
|
||||
|
||||
if (chansess->connection_string) {
|
||||
addnewvar("SSH_CONNECTION", chansess->connection_string);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
if (ses.authstate.pubkey_options &&
|
||||
ses.authstate.pubkey_options->original_command) {
|
||||
addnewvar("SSH_ORIGINAL_COMMAND",
|
||||
ses.authstate.pubkey_options->original_command);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* change directory */
|
||||
if (chdir(ses.authstate.pw_dir) < 0) {
|
||||
dropbear_exit("error changing directory");
|
||||
dropbear_exit("Error changing directory");
|
||||
}
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
/* set up X11 forwarding if enabled */
|
||||
x11setauth(chansess);
|
||||
#endif
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
#ifdef ENABLE_AGENTFWD
|
||||
/* set up agent env variable */
|
||||
agentset(chansess);
|
||||
svr_agentset(chansess);
|
||||
#endif
|
||||
|
||||
usershell = m_strdup(get_user_shell());
|
||||
run_shell_command(chansess->cmd, ses.maxfd, usershell);
|
||||
|
||||
/* only reached on error */
|
||||
dropbear_exit("child failed");
|
||||
dropbear_exit("Child failed");
|
||||
}
|
||||
|
||||
const struct ChanType svrchansess = {
|
||||
|
||||
@@ -70,7 +70,7 @@ void recv_msg_kexdh_init() {
|
||||
* that, the session hash is calculated, and signed with RSA or DSS. The
|
||||
* result is sent to the client.
|
||||
*
|
||||
* See the ietf-secsh-transport draft, section 6, for details */
|
||||
* See the transport rfc 4253 section 8 for details */
|
||||
static void send_msg_kexdh_reply(mp_int *dh_e) {
|
||||
|
||||
DEF_MP_INT(dh_y);
|
||||
|
||||
53
svr-main.c
53
svr-main.c
@@ -77,22 +77,16 @@ int main(int argc, char ** argv)
|
||||
|
||||
#ifdef INETD_MODE
|
||||
static void main_inetd() {
|
||||
|
||||
struct sockaddr_storage remoteaddr;
|
||||
socklen_t remoteaddrlen;
|
||||
char * addrstring = NULL;
|
||||
char *host, *port = NULL;
|
||||
|
||||
/* Set up handlers, syslog, seed random */
|
||||
commonsetup();
|
||||
|
||||
remoteaddrlen = sizeof(remoteaddr);
|
||||
if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) {
|
||||
dropbear_exit("Unable to getpeername: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* In case our inetd was lax in logging source addresses */
|
||||
addrstring = getaddrstring(&remoteaddr, 1);
|
||||
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
|
||||
get_socket_address(0, NULL, NULL, &host, &port, 0);
|
||||
dropbear_log(LOG_INFO, "Child connection from %s:%s", host, port);
|
||||
m_free(host);
|
||||
m_free(port);
|
||||
|
||||
/* Don't check the return value - it may just fail since inetd has
|
||||
* already done setsid() after forking (xinetd on Darwin appears to do
|
||||
@@ -102,7 +96,7 @@ static void main_inetd() {
|
||||
/* Start service program
|
||||
* -1 is a dummy childpipe, just something we can close() without
|
||||
* mattering. */
|
||||
svr_session(0, -1, getaddrhostname(&remoteaddr), addrstring);
|
||||
svr_session(0, -1);
|
||||
|
||||
/* notreached */
|
||||
}
|
||||
@@ -133,7 +127,7 @@ void main_noinetd() {
|
||||
for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
|
||||
childpipes[i] = -1;
|
||||
}
|
||||
bzero(preauth_addrs, sizeof(preauth_addrs));
|
||||
memset(preauth_addrs, 0x0, sizeof(preauth_addrs));
|
||||
|
||||
/* Set up the listening sockets */
|
||||
listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock);
|
||||
@@ -218,14 +212,13 @@ void main_noinetd() {
|
||||
|
||||
/* handle each socket which has something to say */
|
||||
for (i = 0; i < listensockcount; i++) {
|
||||
|
||||
struct sockaddr_storage remoteaddr;
|
||||
socklen_t remoteaddrlen = 0;
|
||||
size_t num_unauthed_for_addr = 0;
|
||||
size_t num_unauthed_total = 0;
|
||||
char * remote_addr_str = NULL;
|
||||
char *remote_host = NULL, *remote_port = NULL;
|
||||
pid_t fork_ret = 0;
|
||||
size_t conn_idx = 0;
|
||||
struct sockaddr_storage remoteaddr;
|
||||
socklen_t remoteaddrlen;
|
||||
|
||||
if (!FD_ISSET(listensocks[i], &fds))
|
||||
continue;
|
||||
@@ -240,14 +233,14 @@ void main_noinetd() {
|
||||
}
|
||||
|
||||
/* Limit the number of unauthenticated connections per IP */
|
||||
remote_addr_str = getaddrstring(&remoteaddr, 0);
|
||||
getaddrstring(&remoteaddr, &remote_host, NULL, 0);
|
||||
|
||||
num_unauthed_for_addr = 0;
|
||||
num_unauthed_total = 0;
|
||||
for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) {
|
||||
if (childpipes[j] >= 0) {
|
||||
num_unauthed_total++;
|
||||
if (strcmp(remote_addr_str, preauth_addrs[j]) == 0) {
|
||||
if (strcmp(remote_host, preauth_addrs[j]) == 0) {
|
||||
num_unauthed_for_addr++;
|
||||
}
|
||||
} else {
|
||||
@@ -272,7 +265,7 @@ void main_noinetd() {
|
||||
fork_ret = fork();
|
||||
#endif
|
||||
if (fork_ret < 0) {
|
||||
dropbear_log(LOG_WARNING, "error forking: %s", strerror(errno));
|
||||
dropbear_log(LOG_WARNING, "Error forking: %s", strerror(errno));
|
||||
goto out;
|
||||
|
||||
} else if (fork_ret > 0) {
|
||||
@@ -280,21 +273,21 @@ void main_noinetd() {
|
||||
/* parent */
|
||||
childpipes[conn_idx] = childpipe[0];
|
||||
m_close(childpipe[1]);
|
||||
preauth_addrs[conn_idx] = remote_addr_str;
|
||||
remote_addr_str = NULL;
|
||||
preauth_addrs[conn_idx] = remote_host;
|
||||
remote_host = NULL;
|
||||
|
||||
} else {
|
||||
|
||||
/* child */
|
||||
char * addrstring = NULL;
|
||||
#ifdef DEBUG_FORKGPROF
|
||||
extern void _start(void), etext(void);
|
||||
monstartup((u_long)&_start, (u_long)&etext);
|
||||
#endif /* DEBUG_FORKGPROF */
|
||||
|
||||
m_free(remote_addr_str);
|
||||
addrstring = getaddrstring(&remoteaddr, 1);
|
||||
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
|
||||
getaddrstring(&remoteaddr, NULL, &remote_port, 0);
|
||||
dropbear_log(LOG_INFO, "Child connection from %s:%s", remote_host, remote_port);
|
||||
m_free(remote_host);
|
||||
m_free(remote_port);
|
||||
|
||||
#ifndef DEBUG_NOFORK
|
||||
if (setsid() < 0) {
|
||||
@@ -310,9 +303,7 @@ void main_noinetd() {
|
||||
m_close(childpipe[0]);
|
||||
|
||||
/* start the session */
|
||||
svr_session(childsock, childpipe[1],
|
||||
getaddrhostname(&remoteaddr),
|
||||
addrstring);
|
||||
svr_session(childsock, childpipe[1]);
|
||||
/* don't return */
|
||||
dropbear_assert(0);
|
||||
}
|
||||
@@ -320,8 +311,8 @@ void main_noinetd() {
|
||||
out:
|
||||
/* This section is important for the parent too */
|
||||
m_close(childsock);
|
||||
if (remote_addr_str) {
|
||||
m_free(remote_addr_str);
|
||||
if (remote_host) {
|
||||
m_free(remote_host);
|
||||
}
|
||||
}
|
||||
} /* for(;;) loop */
|
||||
|
||||
@@ -43,11 +43,11 @@ static void printhelp(const char * progname) {
|
||||
" before user login\n"
|
||||
" (default: none)\n"
|
||||
#ifdef DROPBEAR_DSS
|
||||
"-d dsskeyfile Use dsskeyfile for the dss host key\n"
|
||||
"-d dsskeyfile Use dsskeyfile for the DSS host key\n"
|
||||
" (default: %s)\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
"-r rsakeyfile Use rsakeyfile for the rsa host key\n"
|
||||
"-r rsakeyfile Use rsakeyfile for the RSA host key\n"
|
||||
" (default: %s)\n"
|
||||
#endif
|
||||
"-F Don't fork into background\n"
|
||||
@@ -124,6 +124,9 @@ void svr_getopts(int argc, char ** argv) {
|
||||
#endif
|
||||
#ifdef ENABLE_SVR_REMOTETCPFWD
|
||||
svr_opts.noremotetcp = 0;
|
||||
#endif
|
||||
#ifndef DISABLE_ZLIB
|
||||
opts.enable_compress = 1;
|
||||
#endif
|
||||
/* not yet
|
||||
opts.ipv4 = 1;
|
||||
@@ -296,15 +299,19 @@ void svr_getopts(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
if (keepalive_arg) {
|
||||
if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
|
||||
unsigned int val;
|
||||
if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
|
||||
}
|
||||
opts.keepalive_secs = val;
|
||||
}
|
||||
|
||||
if (idle_timeout_arg) {
|
||||
if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
|
||||
unsigned int val;
|
||||
if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
|
||||
}
|
||||
opts.idle_timeout_secs = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ void recv_msg_service_request() {
|
||||
if (len == SSH_SERVICE_CONNECTION_LEN &&
|
||||
(strncmp(SSH_SERVICE_CONNECTION, name, len) == 0)) {
|
||||
if (ses.authstate.authdone != 1) {
|
||||
dropbear_exit("request for connection before auth");
|
||||
dropbear_exit("Request for connection before auth");
|
||||
}
|
||||
|
||||
send_msg_service_accept(name, len);
|
||||
@@ -68,7 +68,7 @@ void recv_msg_service_request() {
|
||||
|
||||
m_free(name);
|
||||
/* TODO this should be a MSG_DISCONNECT */
|
||||
dropbear_exit("unrecognised SSH_MSG_SERVICE_REQUEST");
|
||||
dropbear_exit("Unrecognised SSH_MSG_SERVICE_REQUEST");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -74,23 +74,36 @@ static const struct ChanType *svr_chantypes[] = {
|
||||
NULL /* Null termination is mandatory. */
|
||||
};
|
||||
|
||||
void svr_session(int sock, int childpipe,
|
||||
char* remotehost, char *addrstring) {
|
||||
|
||||
void svr_session(int sock, int childpipe) {
|
||||
char *host, *port;
|
||||
size_t len;
|
||||
reseedrandom();
|
||||
|
||||
crypto_init();
|
||||
common_session_init(sock, sock, remotehost);
|
||||
common_session_init(sock, sock);
|
||||
|
||||
/* Initialise server specific parts of the session */
|
||||
svr_ses.childpipe = childpipe;
|
||||
svr_ses.addrstring = addrstring;
|
||||
#ifdef __uClinux__
|
||||
svr_ses.server_pid = getpid();
|
||||
#endif
|
||||
svr_authinitialise();
|
||||
chaninitialise(svr_chantypes);
|
||||
svr_chansessinitialise();
|
||||
|
||||
ses.connect_time = time(NULL);
|
||||
|
||||
/* for logging the remote address */
|
||||
get_socket_address(ses.sock_in, NULL, NULL, &host, &port, 0);
|
||||
len = strlen(host) + strlen(port) + 2;
|
||||
svr_ses.addrstring = m_malloc(len);
|
||||
snprintf(svr_ses.addrstring, len, "%s:%s", host, port);
|
||||
m_free(host);
|
||||
m_free(port);
|
||||
|
||||
get_socket_address(ses.sock_in, NULL, NULL,
|
||||
&svr_ses.remotehost, NULL, 1);
|
||||
|
||||
/* set up messages etc */
|
||||
ses.remoteclosed = svr_remoteclosed;
|
||||
|
||||
@@ -125,30 +138,39 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
if (!sessinitdone) {
|
||||
/* before session init */
|
||||
snprintf(fmtbuf, sizeof(fmtbuf),
|
||||
"premature exit: %s", format);
|
||||
"Premature exit: %s", format);
|
||||
} else if (ses.authstate.authdone) {
|
||||
/* user has authenticated */
|
||||
snprintf(fmtbuf, sizeof(fmtbuf),
|
||||
"exit after auth (%s): %s",
|
||||
"Exit (%s): %s",
|
||||
ses.authstate.pw_name, format);
|
||||
} else if (ses.authstate.pw_name) {
|
||||
/* we have a potential user */
|
||||
snprintf(fmtbuf, sizeof(fmtbuf),
|
||||
"exit before auth (user '%s', %d fails): %s",
|
||||
"Exit before auth (user '%s', %d fails): %s",
|
||||
ses.authstate.pw_name, ses.authstate.failcount, format);
|
||||
} else {
|
||||
/* before userauth */
|
||||
snprintf(fmtbuf, sizeof(fmtbuf),
|
||||
"exit before auth: %s", format);
|
||||
"Exit before auth: %s", format);
|
||||
}
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
|
||||
/* free potential public key options */
|
||||
svr_pubkey_options_cleanup();
|
||||
#ifdef __uClinux__
|
||||
/* only the main server process should cleanup - we don't want
|
||||
* forked children doing that */
|
||||
if (svr_ses.server_pid == getpid())
|
||||
#else
|
||||
if (1)
|
||||
#endif
|
||||
{
|
||||
/* free potential public key options */
|
||||
svr_pubkey_options_cleanup();
|
||||
|
||||
/* must be after we've done with username etc */
|
||||
common_session_cleanup();
|
||||
/* must be after we've done with username etc */
|
||||
common_session_cleanup();
|
||||
}
|
||||
|
||||
exit(exitcode);
|
||||
|
||||
|
||||
11
svr-tcpfwd.c
11
svr-tcpfwd.c
@@ -206,11 +206,20 @@ static int svr_remotetcpreq() {
|
||||
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
|
||||
tcpinfo->sendaddr = NULL;
|
||||
tcpinfo->sendport = 0;
|
||||
tcpinfo->listenaddr = bindaddr;
|
||||
tcpinfo->listenport = port;
|
||||
tcpinfo->chantype = &svr_chan_tcpremote;
|
||||
tcpinfo->tcp_type = forwarded;
|
||||
|
||||
if (!opts.listen_fwd_all
|
||||
|| (strcmp(tcpinfo->listenaddr, "localhost") == 0) ) {
|
||||
// NULL means "localhost only"
|
||||
tcpinfo->listenaddr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcpinfo->listenaddr = bindaddr;
|
||||
}
|
||||
|
||||
ret = listen_tcpfwd(tcpinfo);
|
||||
|
||||
out:
|
||||
|
||||
@@ -233,7 +233,7 @@ static int bindport(int fd) {
|
||||
continue;
|
||||
}
|
||||
/* otherwise it was an error we don't know about */
|
||||
dropbear_log(LOG_DEBUG, "failed to bind x11 socket");
|
||||
dropbear_log(LOG_DEBUG, "Failed to bind x11 socket");
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
|
||||
29
sysoptions.h
29
sysoptions.h
@@ -4,7 +4,7 @@
|
||||
*******************************************************************/
|
||||
|
||||
#ifndef DROPBEAR_VERSION
|
||||
#define DROPBEAR_VERSION "0.52"
|
||||
#define DROPBEAR_VERSION "0.53.1"
|
||||
#endif
|
||||
|
||||
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
|
||||
@@ -60,6 +60,7 @@
|
||||
|
||||
/* various algorithm identifiers */
|
||||
#define DROPBEAR_KEX_DH_GROUP1 0
|
||||
#define DROPBEAR_KEX_DH_GROUP14 1
|
||||
|
||||
#define DROPBEAR_SIGNKEY_ANY 0
|
||||
#define DROPBEAR_SIGNKEY_RSA 1
|
||||
@@ -98,6 +99,7 @@
|
||||
#define MAX_PROPOSED_ALGO 20
|
||||
|
||||
/* size/count limits */
|
||||
/* From transport rfc */
|
||||
#define MIN_PACKET_LEN 16
|
||||
|
||||
#define RECV_MAX_PACKET_LEN (MAX(35000, ((RECV_MAX_PAYLOAD_LEN)+100)))
|
||||
@@ -122,7 +124,7 @@
|
||||
#define MAX_PRIVKEY_SIZE 1700
|
||||
|
||||
/* The maximum size of the bignum portion of the kexhash buffer */
|
||||
/* Sect. 8 of the transport draft, K_S + e + f + K */
|
||||
/* Sect. 8 of the transport rfc 4253, K_S + e + f + K */
|
||||
#define KEXHASHBUF_MAX_INTS (1700 + 130 + 130 + 130)
|
||||
|
||||
#define DROPBEAR_MAX_SOCKS 2 /* IPv4, IPv6 are all we'll get for now. Revisit
|
||||
@@ -146,10 +148,6 @@
|
||||
#define DISABLE_X11FWD
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_AGENTFWD
|
||||
#define DISABLE_AGENTFWD
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
|
||||
#define ENABLE_CLI_ANYTCPFWD
|
||||
#endif
|
||||
@@ -160,18 +158,30 @@
|
||||
|
||||
#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) || \
|
||||
defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_SVR_LOCALTCPFWD) || \
|
||||
defined(ENABLE_AGENTFWD) || defined(ENABLE_X11FWD)
|
||||
defined(ENABLE_SVR_AGENTFWD) || defined(ENABLE_X11FWD)
|
||||
#define USING_LISTENERS
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_SVR_AGENTFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
|
||||
#define ENABLE_AGENTFWD
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CLI_NETCAT) && defined(ENABLE_CLI_PROXYCMD)
|
||||
#define ENABLE_CLI_MULTIHOP
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CLI_AGENTFWD) || defined(DROPBEAR_PRNGD_SOCKET)
|
||||
#define ENABLE_CONNECT_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH)
|
||||
#define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
|
||||
#endif
|
||||
|
||||
/* Changing this is inadvisable, it appears to have problems
|
||||
* with flushing compressed data */
|
||||
#define DROPBEAR_ZLIB_MEM_LEVEL 8
|
||||
|
||||
#if defined(ENABLE_SVR_PASSWORD_AUTH) && defined(ENABLE_SVR_PAM_AUTH)
|
||||
#error "You can't turn on PASSWORD and PAM auth both at once. Fix it in options.h"
|
||||
#endif
|
||||
@@ -202,5 +212,8 @@
|
||||
#define IS_DROPBEAR_CLIENT 1
|
||||
|
||||
#else
|
||||
#error You must compiled with either DROPBEAR_CLIENT or DROPBEAR_SERVER selected
|
||||
/* Just building key utils? */
|
||||
#define IS_DROPBEAR_SERVER 0
|
||||
#define IS_DROPBEAR_CLIENT 0
|
||||
|
||||
#endif
|
||||
|
||||
10
tcp-accept.c
10
tcp-accept.c
@@ -104,21 +104,13 @@ int listen_tcpfwd(struct TCPListener* tcpinfo) {
|
||||
struct Listener *listener = NULL;
|
||||
int nsocks;
|
||||
char* errstring = NULL;
|
||||
/* listen_spec = NULL indicates localhost */
|
||||
const char* listen_spec = NULL;
|
||||
|
||||
TRACE(("enter listen_tcpfwd"))
|
||||
|
||||
/* first we try to bind, so don't need to do so much cleanup on failure */
|
||||
snprintf(portstring, sizeof(portstring), "%d", tcpinfo->listenport);
|
||||
|
||||
/* a listenaddr of "" will indicate all interfaces */
|
||||
if (opts.listen_fwd_all
|
||||
&& (strcmp(tcpinfo->listenaddr, "localhost") != 0) ) {
|
||||
listen_spec = tcpinfo->listenaddr;
|
||||
}
|
||||
|
||||
nsocks = dropbear_listen(listen_spec, portstring, socks,
|
||||
nsocks = dropbear_listen(tcpinfo->listenaddr, portstring, socks,
|
||||
DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd);
|
||||
if (nsocks < 0) {
|
||||
dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
|
||||
|
||||
10
tcpfwd.h
10
tcpfwd.h
@@ -25,6 +25,7 @@
|
||||
#define _TCPFWD_H
|
||||
|
||||
#include "channel.h"
|
||||
#include "list.h"
|
||||
|
||||
struct TCPListener {
|
||||
|
||||
@@ -43,16 +44,14 @@ struct TCPListener {
|
||||
enum {direct, forwarded} tcp_type;
|
||||
};
|
||||
|
||||
/* A link in a list of forwards */
|
||||
struct TCPFwdList {
|
||||
|
||||
/* A forwarding entry */
|
||||
struct TCPFwdEntry {
|
||||
const unsigned char* connectaddr;
|
||||
unsigned int connectport;
|
||||
const unsigned char* listenaddr;
|
||||
unsigned int listenport;
|
||||
unsigned int have_reply; /* is set to 1 after a reply has been received
|
||||
when setting up the forwarding */
|
||||
struct TCPFwdList * next;
|
||||
|
||||
};
|
||||
|
||||
/* Server */
|
||||
@@ -70,5 +69,4 @@ void cli_recv_msg_request_failure();
|
||||
/* Common */
|
||||
int listen_tcpfwd(struct TCPListener* tcpinfo);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user