summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore21
-rw-r--r--.hgsigs1
-rw-r--r--.hgtags1
-rw-r--r--CHANGES39
-rw-r--r--atomicio.c29
-rw-r--r--atomicio.h13
-rw-r--r--buffer.c1
-rw-r--r--cli-agentfwd.c2
-rw-r--r--cli-session.c2
-rw-r--r--cli-tcpfwd.c4
-rw-r--r--common-channel.c1
-rw-r--r--compat.c19
-rw-r--r--dbutil.c19
-rw-r--r--dbutil.h2
-rw-r--r--debian/changelog6
-rw-r--r--dropbearkey.c2
-rw-r--r--gensignkey.c39
-rw-r--r--gensignkey.h2
-rw-r--r--keyimport.c10
-rw-r--r--libtommath/bn_mp_exteuclid.c33
-rw-r--r--loginrec.c8
-rw-r--r--scpmisc.c2
-rw-r--r--scpmisc.h3
-rw-r--r--svr-authpubkey.c17
-rw-r--r--svr-authpubkeyoptions.c7
-rw-r--r--svr-chansession.c2
-rw-r--r--svr-kex.c47
-rw-r--r--svr-tcpfwd.c2
-rw-r--r--sysoptions.h2
-rw-r--r--termcodes.c24
30 files changed, 230 insertions, 130 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b81c1ea
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+*~
+*.o
+*.a
+*.da
+*.bb
+*.bbg
+*.prof
+/autom4te.cache
+/config.log
+/config.status
+/dbclient
+/dropbear
+/dropbearconvert
+/dropbearkey
+/dropbearmulti
+/scp
+/scp-progress
+Makefile
+config.h
+config.h.in
+configure
diff --git a/.hgsigs b/.hgsigs
index 65c0ce2..dbdd8b9 100644
--- a/.hgsigs
+++ b/.hgsigs
@@ -22,3 +22,4 @@ af074dbcb68ff8670b3818e0d66d5dc6f1bd5877 0 iQIcBAABCgAGBQJWVdQfAAoJEPSYMBLCC7qs+
fd1981f41c626a969f07b4823848deaefef3c8aa 0 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
diff --git a/.hgtags b/.hgtags
index 0cae712..cdaec28 100644
--- a/.hgtags
+++ b/.hgtags
@@ -54,3 +54,4 @@ cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
78b12b6549be08b0bea3da329b2578060a76ca31 DROPBEAR_2016.72
309e1c4a87682b6ca7d80b8555a1db416c3cb7ac DROPBEAR_2016.73
0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74
+c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
diff --git a/CHANGES b/CHANGES
index 95becd4..b48638e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,30 @@
+2017.75 - 18 May 2017
+
+- Security: Fix double-free in server TCP listener cleanup
+ A double-free in the server could be triggered by an authenticated user if
+ dropbear is running with -a (Allow connections to forwarded ports from any host)
+ This could potentially allow arbitrary code execution as root by an authenticated user.
+ Affects versions 2013.56 to 2016.74. Thanks to Mark Shepard for reporting the crash.
+ CVE-2017-9078 https://secure.ucc.asn.au/hg/dropbear/rev/c8114a48837c
+
+- Security: Fix information disclosure with ~/.ssh/authorized_keys symlink.
+ Dropbear parsed authorized_keys as root, even if it were a symlink. The fix
+ is to switch to user permissions when opening authorized_keys
+
+ A user could symlink their ~/.ssh/authorized_keys to a root-owned file they
+ couldn't normally read. If they managed to get that file to contain valid
+ authorized_keys with command= options it might be possible to read other
+ contents of that file.
+ This information disclosure is to an already authenticated user.
+ Thanks to Jann Horn of Google Project Zero for reporting this.
+ CVE-2017-9079 https://secure.ucc.asn.au/hg/dropbear/rev/0d889b068123
+
+- Generate hostkeys with dropbearkey atomically and flush to disk with fsync
+ Thanks to Andrei Gherzan for a patch
+
+- Fix out of tree builds with bundled libtom
+ Thanks to Henrik Nordström and Peter Krefting for patches.
+
2016.74 - 21 July 2016
- Security: Message printout was vulnerable to format string injection.
@@ -9,16 +36,24 @@
A dbclient user who can control username or host arguments could potentially
run arbitrary code as the dbclient user. This could be a problem if scripts
or webpages pass untrusted input to the dbclient program.
+ CVE-2016-7406
+ https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb
- Security: dropbearconvert import of OpenSSH keys could run arbitrary code as
the local dropbearconvert user when parsing malicious key files
+ CVE-2016-7407
+ https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e
- Security: dbclient could run arbitrary code as the local dbclient user if
particular -m or -c arguments are provided. This could be an issue where
dbclient is used in scripts.
+ CVE-2016-7408
+ https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6
- Security: dbclient or dropbear server could expose process memory to the
running user if compiled with DEBUG_TRACE and running with -v
+ CVE-2016-7409
+ https://secure.ucc.asn.au/hg/dropbear/rev/6a14b1f6dc04
The security issues were reported by an anonymous researcher working with
Beyond Security's SecuriTeam Secure Disclosure www.beyondsecurity.com/ssd.html
@@ -64,6 +99,7 @@
- Validate X11 forwarding input. Could allow bypass of authorized_keys command= restrictions,
found by github.com/tintinweb. Thanks for Damien Miller for a patch. CVE-2016-3116
+ https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff
2015.71 - 3 December 2015
@@ -342,9 +378,11 @@ kernels, from Steve Dover
- Limit the size of decompressed payloads, avoids memory exhaustion denial
of service
Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421
+ https://secure.ucc.asn.au/hg/dropbear/rev/0bf76f54de6f
- Avoid disclosing existence of valid users through inconsistent delays
Thanks to Logan Lamb for reporting. CVE-2013-4434
+ https://secure.ucc.asn.au/hg/dropbear/rev/d7784616409a
- Update config.guess and config.sub for newer architectures
@@ -447,6 +485,7 @@ though probably will be soon
This bug affects releases 0.52 onwards. Ref CVE-2012-0920.
Thanks to Danny Fullerton of Mantor Organization for reporting
the bug.
+ https://secure.ucc.asn.au/hg/dropbear/rev/818108bf7749
- Compile fix, only apply IPV6 socket options if they are available in headers
Thanks to Gustavo Zacarias for the patch
diff --git a/atomicio.c b/atomicio.c
index a061cbd..2aacf51 100644
--- a/atomicio.c
+++ b/atomicio.c
@@ -1,6 +1,8 @@
+/* $OpenBSD: atomicio.c,v 1.17 2006/04/01 05:51:34 djm Exp $ */
/*
- * Copied from OpenSSH 3.6.1p2.
+ * Copied from OpenSSH/OpenBSD.
*
+ * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
@@ -25,39 +27,32 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* RCSID("OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp "); */
+#include "includes.h"
#include "atomicio.h"
/*
- * ensure all of data on socket comes through. f==read || f==write
+ * ensure all of data on socket comes through. f==read || f==vwrite
*/
-ssize_t
-atomicio(f, fd, _s, n)
- ssize_t (*f) ();
- int fd;
- void *_s;
- size_t n;
+size_t
+atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
{
char *s = _s;
- ssize_t res;
size_t pos = 0;
+ ssize_t res;
while (n > pos) {
res = (f) (fd, s + pos, n - pos);
switch (res) {
case -1:
-#ifdef EWOULDBLOCK
- if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
-#else
if (errno == EINTR || errno == EAGAIN)
-#endif
continue;
- /* FALLTHROUGH */
+ return 0;
case 0:
- return (res);
+ errno = EPIPE;
+ return pos;
default:
- pos += res;
+ pos += (size_t)res;
}
}
return (pos);
diff --git a/atomicio.h b/atomicio.h
index 6c1f3ac..0bd019f 100644
--- a/atomicio.h
+++ b/atomicio.h
@@ -1,8 +1,7 @@
+/* $OpenBSD: atomicio.h,v 1.7 2006/03/25 22:22:42 djm Exp $ */
/*
- * Copied from OpenSSH 3.6.1p2, required for loginrec.c
- *
- * $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $
+ * Copied from OpenSSH/OpenBSD, required for loginrec.c
*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
@@ -28,9 +27,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "includes.h"
-
/*
- * Ensure all of data on socket comes through. f==read || f==write
+ * Ensure all of data on socket comes through. f==read || f==vwrite
*/
-ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
+size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
+
+#define vwrite (ssize_t (*)(int, void *, size_t))write
diff --git a/buffer.c b/buffer.c
index d646c0e..0ca50b4 100644
--- a/buffer.c
+++ b/buffer.c
@@ -109,6 +109,7 @@ void buf_setlen(buffer* buf, unsigned int len) {
dropbear_exit("Bad buf_setlen");
}
buf->len = len;
+ buf->pos = MIN(buf->pos, buf->len);
}
/* Increment the length of the buffer */
diff --git a/cli-agentfwd.c b/cli-agentfwd.c
index 5b0ea81..bdca3ea 100644
--- a/cli-agentfwd.c
+++ b/cli-agentfwd.c
@@ -130,7 +130,7 @@ static buffer * agent_request(unsigned char type, buffer *data) {
}
buf_setpos(payload, 0);
- ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len);
+ ret = atomicio(vwrite, 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;
diff --git a/cli-session.c b/cli-session.c
index d89416f..d8525ae 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -287,7 +287,7 @@ static void cli_sessionloop() {
int devnull;
/* keeping stdin open steals input from the terminal and
is confusing, though stdout/stderr could be useful. */
- devnull = open(_PATH_DEVNULL, O_RDONLY);
+ devnull = open(DROPBEAR_PATH_DEVNULL, O_RDONLY);
if (devnull < 0) {
dropbear_exit("Opening /dev/null: %d %s",
errno, strerror(errno));
diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c
index 95b2d7c..78f61f7 100644
--- a/cli-tcpfwd.c
+++ b/cli-tcpfwd.c
@@ -234,7 +234,7 @@ static int newtcpforwarded(struct Channel * channel) {
char *origaddr = NULL;
unsigned int origport;
m_list_elem * iter = NULL;
- struct TCPFwdEntry *fwd;
+ struct TCPFwdEntry *fwd = NULL;
char portstring[NI_MAXSERV];
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
@@ -265,7 +265,7 @@ static int newtcpforwarded(struct Channel * channel) {
}
- if (iter == NULL) {
+ if (iter == NULL || fwd == NULL) {
/* We didn't request forwarding on that port */
cleantext(origaddr);
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
diff --git a/common-channel.c b/common-channel.c
index 835e493..7383f47 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -32,7 +32,6 @@
#include "circbuffer.h"
#include "dbutil.h"
#include "channel.h"
-#include "ssh.h"
#include "listener.h"
#include "runopts.h"
#include "netio.h"
diff --git a/compat.c b/compat.c
index 71558a5..7a0e78a 100644
--- a/compat.c
+++ b/compat.c
@@ -114,8 +114,8 @@ size_t strlcpy(char *dst, const char *src, size_t size) {
#endif /* HAVE_STRLCPY */
#ifndef HAVE_STRLCAT
-/* taken from openbsd-compat for OpenSSH 3.6.1p1 */
-/* "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"
+/* taken from openbsd-compat for OpenSSH 7.2p2 */
+/* "$OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $"
*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
@@ -123,15 +123,12 @@ size_t strlcpy(char *dst, const char *src, size_t size) {
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
- size_t
-strlcat(dst, src, siz)
- char *dst;
- const char *src;
- size_t siz;
+size_t
+strlcat(char *dst, const char *src, size_t siz)
{
- register char *d = dst;
- register const char *s = src;
- register size_t n = siz;
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
@@ -177,7 +174,7 @@ int daemon(int nochdir, int noclose) {
if (!nochdir)
(void)chdir("/");
- if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ if (!noclose && (fd = open(DROPBEAR_PATH_DEVNULL, O_RDWR, 0)) != -1) {
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
diff --git a/dbutil.c b/dbutil.c
index ab189d2..830e8d2 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -182,7 +182,7 @@ static double time_since_start()
void dropbear_trace(const char* format, ...) {
va_list param;
- if (!ses.debug_trace) {
+ if (!debug_trace) {
return;
}
@@ -681,4 +681,21 @@ time_t monotonic_now() {
return time(NULL);
}
+void fsync_parent_dir(const char* fn) {
+#ifdef HAVE_LIBGEN_H
+ char *fn_dir = m_strdup(fn);
+ char *dir = dirname(fn_dir);
+ int dirfd = open(dir, O_RDONLY);
+ if (dirfd != -1) {
+ if (fsync(dirfd) != 0) {
+ TRACE(("fsync of directory %s failed: %s", dir, strerror(errno)))
+ }
+ m_close(dirfd);
+ } else {
+ TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
+ }
+
+ free(fn_dir);
+#endif
+}
diff --git a/dbutil.h b/dbutil.h
index 9bcc875..d83b20a 100644
--- a/dbutil.h
+++ b/dbutil.h
@@ -89,4 +89,6 @@ time_t monotonic_now(void);
char * expand_homedir_path(const char *inpath);
+void fsync_parent_dir(const char* fn);
+
#endif /* DROPBEAR_DBUTIL_H_ */
diff --git a/debian/changelog b/debian/changelog
index 87edb50..037805f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+dropbear (2017.75-0.1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Matt Johnston <matt@ucc.asn.au> Thu, 18 May 2017 22:51:57 +0800
+
dropbear (2016.74-0.1) unstable; urgency=low
* New upstream release.
diff --git a/dropbearkey.c b/dropbearkey.c
index 6ea68b4..a0d315b 100644
--- a/dropbearkey.c
+++ b/dropbearkey.c
@@ -241,7 +241,7 @@ int main(int argc, char ** argv) {
}
fprintf(stderr, "Generating key, this may take a while...\n");
- if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
+ if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE)
{
dropbear_exit("Failed to generate key.\n");
}
diff --git a/gensignkey.c b/gensignkey.c
index 55facc3..4691de0 100644
--- a/gensignkey.c
+++ b/gensignkey.c
@@ -76,10 +76,12 @@ static int get_default_bits(enum signkey_type keytype)
}
}
-int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
+/* if skip_exist is set it will silently return if the key file exists */
+int signkey_generate(enum signkey_type keytype, int bits, const char* filename, int skip_exist)
{
sign_key * key = NULL;
buffer *buf = NULL;
+ char *fn_temp = NULL;
int ret = DROPBEAR_FAILURE;
if (bits == 0)
{
@@ -126,10 +128,37 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
sign_key_free(key);
key = NULL;
buf_setpos(buf, 0);
- ret = buf_writefile(buf, filename);
- buf_burn(buf);
- buf_free(buf);
- buf = NULL;
+ fn_temp = m_malloc(strlen(filename) + 30);
+ snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
+ ret = buf_writefile(buf, fn_temp);
+
+ if (ret == DROPBEAR_FAILURE) {
+ goto out;
+ }
+
+ if (link(fn_temp, filename) < 0) {
+ /* If generating keys on connection (skipexist) it's OK to get EEXIST
+ - we probably just lost a race with another connection to generate the key */
+ if (!(skip_exist && errno == EEXIST)) {
+ dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
+ strerror(errno));
+ /* XXX fallback to non-atomic copy for some filesystems? */
+ ret = DROPBEAR_FAILURE;
+ goto out;
+ }
+ }
+
+out:
+ if (buf) {
+ buf_burn(buf);
+ buf_free(buf);
+ }
+
+ if (fn_temp) {
+ unlink(fn_temp);
+ m_free(fn_temp);
+ }
+
return ret;
}
diff --git a/gensignkey.h b/gensignkey.h
index 508eca0..1cba8d3 100644
--- a/gensignkey.h
+++ b/gensignkey.h
@@ -3,6 +3,6 @@
#include "signkey.h"
-int signkey_generate(enum signkey_type type, int bits, const char* filename);
+int signkey_generate(enum signkey_type type, int bits, const char* filename, int skip_exist);
#endif
diff --git a/keyimport.c b/keyimport.c
index d64a6f7..6aab273 100644
--- a/keyimport.c
+++ b/keyimport.c
@@ -694,7 +694,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
&id, &len, &flags);
p += ret;
/* id==4 for octet string */
- if (ret < 0 || id != 4 || len < 0 ||
+ if (ret < 0 || id != 4 || len < 0 ||
key->keyblob+key->keyblob_len-p < len) {
errmsg = "ASN.1 decoding failure";
goto error;
@@ -708,7 +708,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
&id, &len, &flags);
p += ret;
/* id==0 */
- if (ret < 0 || id != 0 || len < 0) {
+ if (ret < 0 || id != 0 || len < 0) {
errmsg = "ASN.1 decoding failure";
goto error;
}
@@ -717,7 +717,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
&id, &len, &flags);
p += ret;
/* id==6 for object */
- if (ret < 0 || id != 6 || len < 0 ||
+ if (ret < 0 || id != 6 || len < 0 ||
key->keyblob+key->keyblob_len-p < len) {
errmsg = "ASN.1 decoding failure";
goto error;
@@ -756,7 +756,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
&id, &len, &flags);
p += ret;
/* id==1 */
- if (ret < 0 || id != 1 || len < 0) {
+ if (ret < 0 || id != 1 || len < 0) {
errmsg = "ASN.1 decoding failure";
goto error;
}
@@ -765,7 +765,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
&id, &len, &flags);
p += ret;
/* id==3 for bit string */
- if (ret < 0 || id != 3 || len < 0 ||
+ if (ret < 0 || id != 3 || len < 0 ||
key->keyblob+key->keyblob_len-p < len) {
errmsg = "ASN.1 decoding failure";
goto error;
diff --git a/libtommath/bn_mp_exteuclid.c b/libtommath/bn_mp_exteuclid.c
index 25ccba9..f4f1c7b 100644
--- a/libtommath/bn_mp_exteuclid.c
+++ b/libtommath/bn_mp_exteuclid.c
@@ -29,34 +29,34 @@ int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3)
/* initialize, (u1,u2,u3) = (1,0,a) */
mp_set(&u1, 1);
- if ((err = mp_copy(a, &u3)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_copy(a, &u3)) != MP_OKAY) { goto LBL_ERR; }
/* initialize, (v1,v2,v3) = (0,1,b) */
mp_set(&v2, 1);
- if ((err = mp_copy(b, &v3)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_copy(b, &v3)) != MP_OKAY) { goto LBL_ERR; }
/* loop while v3 != 0 */
while (mp_iszero(&v3) == MP_NO) {
/* q = u3/v3 */
- if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) { goto LBL_ERR; }
/* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */
- if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) { goto _ERR; }
- if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) { goto _ERR; }
- if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) { goto _ERR; }
- if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) { goto _ERR; }
- if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) { goto _ERR; }
- if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) { goto LBL_ERR; }
+ if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) { goto LBL_ERR; }
+ if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) { goto LBL_ERR; }
+ if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) { goto LBL_ERR; }
+ if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) { goto LBL_ERR; }
+ if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) { goto LBL_ERR; }
/* (u1,u2,u3) = (v1,v2,v3) */
- if ((err = mp_copy(&v1, &u1)) != MP_OKAY) { goto _ERR; }
- if ((err = mp_copy(&v2, &u2)) != MP_OKAY) { goto _ERR; }
- if ((err = mp_copy(&v3, &u3)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_copy(&v1, &u1)) != MP_OKAY) { goto LBL_ERR; }
+ if ((err = mp_copy(&v2, &u2)) != MP_OKAY) { goto LBL_ERR; }
+ if ((err = mp_copy(&v3, &u3)) != MP_OKAY) { goto LBL_ERR; }
/* (v1,v2,v3) = (t1,t2,t3) */
- if ((err = mp_copy(&t1, &v1)) != MP_OKAY) { goto _ERR; }
- if ((err = mp_copy(&t2, &v2)) != MP_OKAY) { goto _ERR; }
- if ((err = mp_copy(&t3, &v3)) != MP_OKAY) { goto _ERR; }
+ if ((err = mp_copy(&t1, &v1)) != MP_OKAY) { goto LBL_ERR; }
+ if ((err = mp_copy(&t2, &v2)) != MP_OKAY) { goto LBL_ERR; }
+ if ((err = mp_copy(&t3, &v3)) != MP_OKAY) { goto LBL_ERR; }
}
/* make sure U3 >= 0 */
@@ -72,7 +72,8 @@ int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3)
if (U3 != NULL) { mp_exch(U3, &u3); }
err = MP_OKAY;
-_ERR: mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL);
+LBL_ERR:
+ mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL);
return err;
}
#endif
diff --git a/loginrec.c b/loginrec.c
index 1b8b143..7254cf1 100644
--- a/loginrec.c
+++ b/loginrec.c
@@ -706,7 +706,7 @@ utmp_write_direct(struct logininfo *li, struct utmp *ut)
}
(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
- if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut))
+ if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut))
dropbear_log(LOG_WARNING, "utmp_write_direct: error writing %s: %s",
UTMP_FILE, strerror(errno));
@@ -895,7 +895,7 @@ wtmp_write(struct logininfo *li, struct utmp *ut)
return 0;
}
if (fstat(fd, &buf) == 0)
- if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
+ if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
ftruncate(fd, buf.st_size);
dropbear_log(LOG_WARNING, "wtmp_write: problem writing %s: %s",
WTMP_FILE, strerror(errno));
@@ -1062,7 +1062,7 @@ wtmpx_write(struct logininfo *li, struct utmpx *utx)
}
if (fstat(fd, &buf) == 0)
- if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
+ if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
ftruncate(fd, buf.st_size);
dropbear_log(LOG_WARNING, "wtmpx_write: problem writing %s: %s",
WTMPX_FILE, strerror(errno));
@@ -1351,7 +1351,7 @@ lastlog_perform_login(struct logininfo *li)
return(0);
/* write the entry */
- if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) {
+ if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) {
close(fd);
dropbear_log(LOG_WARNING, "lastlog_write_filemode: Error writing to %s: %s",
LASTLOG_FILE, strerror(errno));
diff --git a/scpmisc.c b/scpmisc.c
index d99e358..33e1891 100644
--- a/scpmisc.c
+++ b/scpmisc.c
@@ -235,7 +235,7 @@ sanitise_stdfd(void)
{
int nullfd, dupfd;
- if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
+ if ((nullfd = dupfd = open(DROPBEAR_PATH_DEVNULL, O_RDWR)) == -1) {
fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno));
exit(1);
}
diff --git a/scpmisc.h b/scpmisc.h
index 7d0b326..f5e01d6 100644
--- a/scpmisc.h
+++ b/scpmisc.h
@@ -12,9 +12,6 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* actually from atomicio, but is only used in scp code */
-#define vwrite (ssize_t (*)(int, void *, size_t))write
-
char *chop(char *);
char *strdelim(char **);
void set_nonblock(int);
diff --git a/svr-authpubkey.c b/svr-authpubkey.c
index 90d0d2c..acc660d 100644
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
@@ -201,6 +201,8 @@ static int checkpubkey(char* algo, unsigned int algolen,
unsigned int len, pos;
buffer * options_buf = NULL;
int line_num;
+ uid_t origuid;
+ gid_t origgid;
TRACE(("enter checkpubkey"))
@@ -227,8 +229,21 @@ static int checkpubkey(char* algo, unsigned int algolen,
snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
ses.authstate.pw_dir);
- /* open the file */
+ /* open the file as the authenticating user. */
+ origuid = getuid();
+ origgid = getgid();
+ if ((setegid(ses.authstate.pw_gid)) < 0 ||
+ (seteuid(ses.authstate.pw_uid)) < 0) {
+ dropbear_exit("Failed to set euid");
+ }
+
authfile = fopen(filename, "r");
+
+ if ((seteuid(origuid)) < 0 ||
+ (setegid(origgid)) < 0) {
+ dropbear_exit("Failed to revert euid");
+ }
+
if (authfile == NULL) {
goto out;
}
diff --git a/svr-authpubkeyoptions.c b/svr-authpubkeyoptions.c
index a04426e..d08fc2c 100644
--- a/svr-authpubkeyoptions.c
+++ b/svr-authpubkeyoptions.c
@@ -95,6 +95,7 @@ void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
if (chansess->cmd) {
/* original_command takes ownership */
chansess->original_command = chansess->cmd;
+ chansess->cmd = NULL;
} else {
chansess->original_command = m_strdup("");
}
@@ -108,6 +109,9 @@ void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
/* Free potential public key options */
void svr_pubkey_options_cleanup() {
if (ses.authstate.pubkey_options) {
+ if (ses.authstate.pubkey_options->forced_command) {
+ m_free(ses.authstate.pubkey_options->forced_command);
+ }
m_free(ses.authstate.pubkey_options);
ses.authstate.pubkey_options = NULL;
}
@@ -200,8 +204,7 @@ next_option:
bad_option:
ret = DROPBEAR_FAILURE;
- m_free(ses.authstate.pubkey_options);
- ses.authstate.pubkey_options = NULL;
+ svr_pubkey_options_cleanup();
dropbear_log(LOG_WARNING, "Bad public key options at %s:%d", filename, line_num);
end:
diff --git a/svr-chansession.c b/svr-chansession.c
index 6dbc8ad..22fc954 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -634,7 +634,7 @@ static void make_connection_string(struct ChanSess *chansess) {
static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
int iscmd, int issubsys) {
- unsigned int cmdlen;
+ unsigned int cmdlen = 0;
int ret;
TRACE(("enter sessioncommand"))
diff --git a/svr-kex.c b/svr-kex.c
index fba9760..7108f64 100644
--- a/svr-kex.c
+++ b/svr-kex.c
@@ -93,29 +93,9 @@ void recv_msg_kexdh_init() {
#if DROPBEAR_DELAY_HOSTKEY
-static void fsync_parent_dir(const char* fn) {
-#ifdef HAVE_LIBGEN_H
- char *fn_dir = m_strdup(fn);
- char *dir = dirname(fn_dir);
- int dirfd = open(dir, O_RDONLY);
-
- if (dirfd != -1) {
- if (fsync(dirfd) != 0) {
- TRACE(("fsync of directory %s failed: %s", dir, strerror(errno)))
- }
- m_close(dirfd);
- } else {
- TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
- }
-
- free(fn_dir);
-#endif
-}
-
static void svr_ensure_hostkey() {
const char* fn = NULL;
- char *fn_temp = NULL;
enum signkey_type type = ses.newkeys->algo_hostkey;
void **hostkey = signkey_key_ptr(svr_opts.hostkey, type);
int ret = DROPBEAR_FAILURE;
@@ -151,28 +131,10 @@ static void svr_ensure_hostkey() {
return;
}
- fn_temp = m_malloc(strlen(fn) + 20);
- snprintf(fn_temp, strlen(fn)+20, "%s.tmp%d", fn, getpid());
-
- if (signkey_generate(type, 0, fn_temp) == DROPBEAR_FAILURE) {
+ if (signkey_generate(type, 0, fn, 1) == DROPBEAR_FAILURE) {
goto out;
}
-
- if (link(fn_temp, fn) < 0) {
- /* It's OK to get EEXIST - we probably just lost a race
- with another connection to generate the key */
- if (errno != EEXIST) {
- dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", fn,
- strerror(errno));
- /* XXX fallback to non-atomic copy for some filesystems? */
- goto out;
- }
- }
-
- /* ensure directory update is flushed to disk, otherwise we can end up
- with zero-byte hostkey files if the power goes off */
- fsync_parent_dir(fn);
-
+
ret = readhostkey(fn, svr_opts.hostkey, &type);
if (ret == DROPBEAR_SUCCESS) {
@@ -190,11 +152,6 @@ static void svr_ensure_hostkey() {
}
out:
- if (fn_temp) {
- unlink(fn_temp);
- m_free(fn_temp);
- }
-
if (ret == DROPBEAR_FAILURE)
{
dropbear_exit("Couldn't read or generate hostkey %s", fn);
diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c
index e5b6d46..207587c 100644
--- a/svr-tcpfwd.c
+++ b/svr-tcpfwd.c
@@ -199,7 +199,7 @@ static int svr_remotetcpreq() {
}
else
{
- tcpinfo->listenaddr = request_addr;
+ tcpinfo->listenaddr = m_strdup(request_addr);
}
ret = listen_tcpfwd(tcpinfo);
diff --git a/sysoptions.h b/sysoptions.h
index 1f357e7..441e3a1 100644
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -4,7 +4,7 @@
*******************************************************************/
#ifndef DROPBEAR_VERSION
-#define DROPBEAR_VERSION "2016.74"
+#define DROPBEAR_VERSION "2017.75"
#endif
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
diff --git a/termcodes.c b/termcodes.c
index 490e6ce..c5819c1 100644
--- a/termcodes.c
+++ b/termcodes.c
@@ -34,7 +34,11 @@ const struct TermCode termcodes[MAX_TERMCODE+1] = {
{VKILL, TERMCODE_CONTROLCHAR},
{VEOF, TERMCODE_CONTROLCHAR},
{VEOL, TERMCODE_CONTROLCHAR},
+#ifdef VEOL2
{VEOL2, TERMCODE_CONTROLCHAR},
+#else
+ {0, 0},
+#endif
{VSTART, TERMCODE_CONTROLCHAR},
{VSTOP, TERMCODE_CONTROLCHAR},
{VSUSP, TERMCODE_CONTROLCHAR},
@@ -51,17 +55,25 @@ const struct TermCode termcodes[MAX_TERMCODE+1] = {
#ifdef AIX
{CERASE, TERMCODE_CONTROLCHAR},
#else
+#ifdef VWERASE
{VWERASE, TERMCODE_CONTROLCHAR},
+#else
+ {0, 0},
#endif
+#endif
+#ifdef VLNEXT
{VLNEXT, TERMCODE_CONTROLCHAR},
+#else
+ {0, 0},
+#endif
#ifdef VFLUSH
{VFLUSH, TERMCODE_CONTROLCHAR},
-#else
+#else
{0, 0},
#endif
#ifdef VSWTCH
{VSWTCH, TERMCODE_CONTROLCHAR},
-#else
+#else
{0, 0},
#endif
#ifdef VSTATUS
@@ -135,8 +147,16 @@ const struct TermCode termcodes[MAX_TERMCODE+1] = {
{NOFLSH, TERMCODE_LOCAL},
{TOSTOP, TERMCODE_LOCAL},
{IEXTEN, TERMCODE_LOCAL},
+#ifdef ECHOCTL
{ECHOCTL, TERMCODE_LOCAL},
+#else
+ {0, 0},
+#endif
+#ifdef ECHOKE
{ECHOKE, TERMCODE_LOCAL},
+#else
+ {0, 0},
+#endif
#ifdef PENDIN
{PENDIN, TERMCODE_LOCAL},
#else