summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--auth.h1
-rw-r--r--cli-auth.c15
-rw-r--r--cli-authinteract.c2
-rw-r--r--cli-authpasswd.c5
-rw-r--r--cli-session.c8
-rw-r--r--common-channel.c3
-rw-r--r--common-session.c12
-rw-r--r--random.c31
-rw-r--r--random.h1
-rw-r--r--rsa.c1
-rw-r--r--scp.c32
-rw-r--r--svr-chansession.c15
-rw-r--r--svr-main.c4
-rw-r--r--svr-runopts.c8
-rw-r--r--svr-session.c6
-rw-r--r--svr-tcpfwd.c2
-rw-r--r--tcp-accept.c2
17 files changed, 119 insertions, 29 deletions
diff --git a/auth.h b/auth.h
index 7e83247..c407ad5 100644
--- a/auth.h
+++ b/auth.h
@@ -52,6 +52,7 @@ void cli_pubkeyfail();
void cli_auth_password();
int cli_auth_pubkey();
void cli_auth_interactive();
+char* getpass_or_cancel();
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
diff --git a/cli-auth.c b/cli-auth.c
index 6a6d53a..d08de9a 100644
--- a/cli-auth.c
+++ b/cli-auth.c
@@ -278,3 +278,18 @@ void cli_auth_try() {
TRACE(("leave cli_auth_try"))
}
+
+/* A helper for getpass() that exits if the user cancels. The returned
+ * password is statically allocated by getpass() */
+char* getpass_or_cancel()
+{
+ char* password = NULL;
+
+ password = getpass("Password: ");
+
+ /* 0x03 is a ctrl-c character in the buffer. */
+ if (password == NULL || strchr(password, '\3') != NULL) {
+ dropbear_close("Interrupted.");
+ }
+ return password;
+}
diff --git a/cli-authinteract.c b/cli-authinteract.c
index ef65517..5a169cb 100644
--- a/cli-authinteract.c
+++ b/cli-authinteract.c
@@ -115,7 +115,7 @@ void recv_msg_userauth_info_request() {
echo = buf_getbool(ses.payload);
if (!echo) {
- unsigned char* p = getpass(prompt);
+ unsigned char* p = getpass_or_cancel(prompt);
response = m_strdup(p);
m_burn(p, strlen(p));
} else {
diff --git a/cli-authpasswd.c b/cli-authpasswd.c
index ec290e0..5dffac4 100644
--- a/cli-authpasswd.c
+++ b/cli-authpasswd.c
@@ -125,10 +125,7 @@ void cli_auth_password() {
password = gui_getpass("Password: ");
else
#endif
- password = getpass("Password: ");
-
- if (password == NULL)
- return 0;
+ password = getpass_or_cancel("Password: ");
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
diff --git a/cli-session.c b/cli-session.c
index 0e906e6..35510fa 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -76,12 +76,14 @@ static const struct ChanType *cli_chantypes[] = {
void cli_session(int sock, char* remotehost) {
+ seedrandom();
+
crypto_init();
+
common_session_init(sock, remotehost);
chaninitialise(cli_chantypes);
-
/* Set up cli_ses vars */
cli_session_init();
@@ -91,12 +93,8 @@ void cli_session(int sock, char* remotehost) {
/* Exchange identification */
session_identification();
- seedrandom();
-
send_msg_kexinit();
- /* XXX here we do stuff differently */
-
session_loop(cli_sessionloop);
/* Not reached */
diff --git a/common-channel.c b/common-channel.c
index 7e8d428..68d2b48 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -181,7 +181,6 @@ void channelio(fd_set *readfds, fd_set *writefds) {
struct Channel *channel;
unsigned int i;
- int ret;
/* iterate through all the possible channels */
for (i = 0; i < ses.chansize; i++) {
@@ -377,7 +376,7 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
cbuf_incrread(cbuf, len);
channel->recvdonelen += len;
- if (fd == channel->writefd && len == maxlen && channel->recveof) {
+ if (fd == channel->writefd && cbuf_getused(cbuf) == 0 && channel->recveof) {
/* Check if we're closing up */
closewritefd(channel);
TRACE(("leave writechannel: recveof set"))
diff --git a/common-session.c b/common-session.c
index e8dc650..4c15391 100644
--- a/common-session.c
+++ b/common-session.c
@@ -232,10 +232,8 @@ void session_identification() {
dropbear_exit("Error writing ident string");
}
- /* We allow up to 9 lines before the actual version string, to
- * account for wrappers/cruft etc. According to the spec only the client
- * needs to handle this, but no harm in letting the server handle it too */
- for (i = 0; i < 10; i++) {
+ /* If they send more than 50 lines, something is wrong */
+ for (i = 0; i < 50; i++) {
len = ident_readln(ses.sock, linebuf, sizeof(linebuf));
if (len < 0 && errno != EINTR) {
@@ -259,6 +257,12 @@ void session_identification() {
memcpy(ses.remoteident, linebuf, len);
}
+ /* Shall assume that 2.x will be backwards compatible. */
+ if (strncmp(ses.remoteident, "SSH-2.", 6) != 0
+ && strncmp(ses.remoteident, "SSH-1.99-", 9) != 0) {
+ dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
+ }
+
TRACE(("remoteident: %s", ses.remoteident))
}
diff --git a/random.c b/random.c
index d58c8a8..cbbe016 100644
--- a/random.c
+++ b/random.c
@@ -30,8 +30,8 @@
static int donerandinit = 0;
/* this is used to generate unique output from the same hashpool */
-static unsigned int counter = 0;
-#define MAX_COUNTER 1000000/* the max value for the counter, so it won't loop */
+static uint32_t counter = 0;
+#define MAX_COUNTER 1<<31 /* the max value for the counter, so it won't loop */
static unsigned char hashpool[SHA1_HASH_SIZE];
@@ -132,7 +132,8 @@ void seedrandom() {
hash_state hs;
- /* initialise so compilers will be happy about hashing it */
+ /* initialise so that things won't warn about
+ * hashing an undefined buffer */
if (!donerandinit) {
m_burn(hashpool, sizeof(hashpool));
}
@@ -150,6 +151,30 @@ void seedrandom() {
donerandinit = 1;
}
+/* hash the current random pool with some unique identifiers
+ * for this process and point-in-time. this is used to separate
+ * the random pools for fork()ed processes. */
+void reseedrandom() {
+
+ pid_t pid;
+ struct timeval tv;
+
+ if (!donerandinit) {
+ dropbear_exit("seedrandom not done");
+ }
+
+ pid = getpid();
+ gettimeofday(&tv, NULL);
+
+ hash_state hs;
+ unsigned char hash[SHA1_HASH_SIZE];
+ sha1_init(&hs);
+ sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
+ sha1_process(&hs, (void*)&pid, sizeof(pid));
+ sha1_process(&hs, (void*)&tv, sizeof(tv));
+ sha1_done(&hs, hashpool);
+}
+
/* return len bytes of pseudo-random data */
void genrandom(unsigned char* buf, unsigned int len) {
diff --git a/random.h b/random.h
index 5ec1f24..84a0a39 100644
--- a/random.h
+++ b/random.h
@@ -28,6 +28,7 @@
struct mp_int;
void seedrandom();
+void reseedrandom();
void genrandom(unsigned char* buf, int len);
void addrandom(unsigned char* buf, int len);
void gen_random_mpint(mp_int *max, mp_int *rand);
diff --git a/rsa.c b/rsa.c
index cc16fa0..005e4ca 100644
--- a/rsa.c
+++ b/rsa.c
@@ -264,7 +264,6 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
DEF_MP_INT(rsa_tmp1);
DEF_MP_INT(rsa_tmp2);
DEF_MP_INT(rsa_tmp3);
- unsigned char *tmpbuf;
TRACE(("enter buf_put_rsa_sign"))
dropbear_assert(key != NULL);
diff --git a/scp.c b/scp.c
index ccb6c2a..ffc4deb 100644
--- a/scp.c
+++ b/scp.c
@@ -166,8 +166,22 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
close(reserved[0]);
close(reserved[1]);
+ // uClinux needs to build the args here before vforking,
+ // otherwise we do it later on.
+#ifdef __uClinux__
+ args.list[0] = ssh_program;
+ if (remuser != NULL)
+ addargs(&args, "-l%s", remuser);
+ addargs(&args, "%s", host);
+ addargs(&args, "%s", cmd);
+#endif /* __uClinux__ */
+
/* Fork a child to execute the command on the remote host using ssh. */
+#ifdef __uClinux__
+ do_cmd_pid = vfork();
+#else
do_cmd_pid = fork();
+#endif /* __uClinux__ */
if (do_cmd_pid == 0) {
/* Child. */
close(pin[1]);
@@ -177,6 +191,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
close(pin[0]);
close(pout[1]);
+#ifndef __uClinux__
args.list[0] = ssh_program;
if (remuser != NULL) {
addargs(&args, "-l");
@@ -184,6 +199,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
}
addargs(&args, "%s", host);
addargs(&args, "%s", cmd);
+#endif
execvp(ssh_program, args.list);
perror(ssh_program);
@@ -192,6 +208,22 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
fprintf(stderr, "Fatal error: fork: %s\n", strerror(errno));
exit(1);
}
+
+#ifdef __uClinux__
+ /* clean up command */
+ /* pop cmd */
+ free(args->list[--args->num]);
+ args->list[args->num]=NULL;
+ /* pop host */
+ free(args->list[--args->num-1]);
+ args->list[args->num]=NULL;
+ /* pop user */
+ if (remuser != NULL) {
+ free(args->list[--args->num-1]);
+ args->list[args->num]=NULL;
+ }
+#endif /* __uClinux__
+
/* Parent. Close the other side, and return the local side. */
close(pin[0]);
*fdout = pin[1];
diff --git a/svr-chansession.c b/svr-chansession.c
index 9a0932e..0916e7e 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -623,7 +623,12 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
if (pipe(errfds) != 0)
return DROPBEAR_FAILURE;
+#ifdef __uClinux__
+ pid = vfork();
+#else
pid = fork();
+#endif
+
if (pid < 0)
return DROPBEAR_FAILURE;
@@ -714,7 +719,11 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
return DROPBEAR_FAILURE;
}
+#ifdef __uClinux__
+ pid = vfork();
+#else
pid = fork();
+#endif
if (pid < 0)
return DROPBEAR_FAILURE;
@@ -828,12 +837,16 @@ static void execchild(struct ChanSess *chansess) {
char * baseshell = NULL;
unsigned int i;
+ /* with uClinux we'll have vfork()ed, so don't want to overwrite the
+ * hostkey. can't think of a workaround to clear it */
+#ifndef __uClinux__
/* wipe the hostkey */
sign_key_free(svr_opts.hostkey);
svr_opts.hostkey = NULL;
/* overwrite the prng state */
- seedrandom();
+ reseedrandom();
+#endif
/* close file descriptors except stdin/stdout/stderr
* Need to be sure FDs are closed here to avoid reading files as root */
diff --git a/svr-main.c b/svr-main.c
index 5b23340..e59d895 100644
--- a/svr-main.c
+++ b/svr-main.c
@@ -81,7 +81,7 @@ static void main_inetd() {
socklen_t remoteaddrlen;
char * addrstring = NULL;
- /* Set up handlers, syslog */
+ /* Set up handlers, syslog, seed random */
commonsetup();
remoteaddrlen = sizeof(remoteaddr);
@@ -385,6 +385,8 @@ static void commonsetup() {
/* Now we can setup the hostkeys - needs to be after logging is on,
* otherwise we might end up blatting error messages to the socket */
loadhostkeys();
+
+ seedrandom();
}
/* Set up listening sockets for all the requested ports */
diff --git a/svr-runopts.c b/svr-runopts.c
index 6c42fb4..8d8b8df 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -105,8 +105,12 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.inetdmode = 0;
svr_opts.portcount = 0;
svr_opts.hostkey = NULL;
+#ifdef ENABLE_SVR_LOCALTCPFWD
svr_opts.nolocaltcp = 0;
+#endif
+#ifdef ENABLE_SVR_REMOTETCPFWD
svr_opts.noremotetcp = 0;
+#endif
/* not yet
opts.ipv4 = 1;
opts.ipv6 = 1;
@@ -154,12 +158,12 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.usingsyslog = 0;
break;
#endif
-#ifndef DISABLE_LOCALTCPFWD
+#ifdef ENABLE_SVR_LOCALTCPFWD
case 'j':
svr_opts.nolocaltcp = 1;
break;
#endif
-#ifndef DISABLE_REMOTETCPFWD
+#ifdef ENABLE_SVR_REMOTETCPFWD
case 'k':
svr_opts.noremotetcp = 1;
break;
diff --git a/svr-session.c b/svr-session.c
index 408209d..70029f8 100644
--- a/svr-session.c
+++ b/svr-session.c
@@ -78,7 +78,9 @@ void svr_session(int sock, int childpipe,
char* remotehost, char *addrstring) {
struct timeval timeout;
-
+
+ reseedrandom();
+
crypto_init();
common_session_init(sock, remotehost);
@@ -110,8 +112,6 @@ void svr_session(int sock, int childpipe,
/* exchange identification, version etc */
session_identification();
- seedrandom();
-
/* start off with key exchange */
send_msg_kexinit();
diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c
index 53a115e..6391c4c 100644
--- a/svr-tcpfwd.c
+++ b/svr-tcpfwd.c
@@ -80,7 +80,7 @@ void recv_msg_global_request_remotetcp() {
reqname = buf_getstring(ses.payload, &namelen);
wantreply = buf_getbool(ses.payload);
- if (namelen > MAXNAMLEN) {
+ if (namelen > MAX_NAME_LEN) {
TRACE(("name len is wrong: %d", namelen))
goto out;
}
diff --git a/tcp-accept.c b/tcp-accept.c
index 90d72b3..ffb175e 100644
--- a/tcp-accept.c
+++ b/tcp-accept.c
@@ -47,7 +47,7 @@ static void tcp_acceptor(struct Listener *listener, int sock) {
int fd;
struct sockaddr_storage addr;
- int len;
+ socklen_t len;
char ipstring[NI_MAXHOST], portstring[NI_MAXSERV];
struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata);