Compare commits

...

165 Commits

Author SHA1 Message Date
Matt Johnston
b42113119a Wrong date 2015-11-26 23:05:38 +08:00
Matt Johnston
722944f307 2015.70 2015-11-26 23:04:13 +08:00
Matt Johnston
e038c26963 Another attempt at test for crypt() 2015-11-26 23:01:13 +08:00
Matt Johnston
56b9388702 Backed out changeset fbcd0a20e667 2015-11-26 22:21:14 +08:00
Matt Johnston
0e438f6d5c AC_SEARCH_LIBS not AC_CHECK_LIB to find crypt() 2015-11-26 21:58:25 +08:00
Matt Johnston
9f1eb695b4 release.sh reminds how to sign 2015-11-25 23:30:56 +08:00
Matt Johnston
9fef5d1050 Added signature for changeset af074dbcb68f 2015-11-25 23:30:44 +08:00
Matt Johnston
0bb7f77a8f Added tag DROPBEAR_2015.69 for changeset 1637dbd26212 2015-11-25 23:30:36 +08:00
Matt Johnston
9e4e562cfb 2015.69 2015-11-25 23:07:47 +08:00
Matt Johnston
92ec446cb9 debian changelog 2015-11-25 23:07:18 +08:00
Matt Johnston
9097da0284 changelog 2015-11-25 23:06:55 +08:00
Matt Johnston
eedeb009ec mention dropbearkey too 2015-11-25 23:05:41 +08:00
Matt Johnston
d8bc6abcf0 Mention "dropbear -R" if no hostkeys 2015-11-25 23:05:14 +08:00
Matt Johnston
2293e3d105 check for zero K value from curve25519 2015-11-25 22:15:59 +08:00
Guilhem Moulin
550b3056fd Fix minor manpage formatting issues 2015-11-25 20:46:06 +08:00
Matt Johnston
1ba5e8052e Improve dbclient manpage 2015-11-23 23:02:03 +08:00
Matt Johnston
6f5abeff2e Fix flags after the hostname 2015-11-23 22:47:43 +08:00
Guilhem Moulin
7cbf6b131b Bundling for dbclient 2015-11-23 22:28:56 +08:00
Matt Johnston
a461298109 Increase channel limit to 1000 2015-11-19 23:53:06 +08:00
Matt Johnston
90c3a74b2a Avoid queueing into circbuffer when the channel is about to close 2015-11-19 23:52:52 +08:00
Matt Johnston
87373be960 lazy allocation of circbuffer 2015-11-19 23:52:11 +08:00
Matt Johnston
85d9672e47 Send SSH_OPEN_RESOURCE_SHORTAGE response when too many channels open
rather than SSH_OPEN_UNKNOWN_CHANNEL_TYPE
2015-11-19 22:39:32 +08:00
Matt Johnston
e0ae527190 Only clear channel_signal_pending after handling all channels,
from Andrzej Szombierski
2015-11-17 20:53:30 +08:00
Guilhem Moulin
7fb1bec84a Enable bundling 2015-11-06 23:54:24 +08:00
Matt Johnston
1f308fb2b4 S_IWUSR rather than S_IWRITE for scp 2015-11-04 23:22:58 +08:00
Guilhem Moulin
e2d36d493f Mention -y flag 2015-10-28 21:44:16 +08:00
Matt Johnston
7c43594075 Add comment about compression 2015-10-28 21:42:09 +08:00
Matt Johnston
e4827025be Warn rather than fail if flags have trailing parts 2015-10-28 21:37:35 +08:00
Matt Johnston
00798ca8cc Test for crypt() rather than crypt.h
Print a message from configure if getpass() or crypt() were missing
2015-10-21 23:08:22 +08:00
Mike Frysinger
e84cb3c3c2 fix default build when getpass() is unavailable
if the system doesn't support getpass, we still default on the options
that require it which causes a build failure.  instead, only default
enable these when getpass is available.
2015-10-21 22:48:15 +08:00
Mike Frysinger
78b9cecb52 fix default build when crypt() is unavailable
if the system doesn't support crypt.h/crypt, then ENABLE_SVR_PASSWORD_AUTH
cannot work.  rather than default this to on all the time, do so only when
support for the header is found.
2015-10-21 22:40:11 +08:00
Mike Frysinger
93c54fe6f6 avoid getpass when not used
some systems (like android's bionic) do not provide getpass.  you can
disable ENABLE_CLI_PASSWORD_AUTH & ENABLE_CLI_INTERACT_AUTH to avoid
its use (and rely on pubkey auth), but the link still fails because
the support file calls getpass.  do not define this func if both of
those auth methods are not used.
2015-10-21 22:39:55 +08:00
Mike Frysinger
5f97d0fbbc fix build when ENABLE_CLI_INTERACT_AUTH is disabled
The session.h defines clientsession.cipher_none_after_auth only when
ENABLE_CLI_INTERACT_AUTH is defined, but cli-session.c will always
try to set that member.  export cipher_none_after_auth all the time.
2015-10-21 22:39:31 +08:00
Guilhem Moulin
dc01a8edd4 Don't display the MOTD when an explicit command is run.
(possibly via authorized_keys(5) restrictions), even when a
pseudo-terminal has been allocated for the session.  In other words,
only display the MOTD when the server starts the user's default shell.
2015-10-21 22:08:47 +08:00
Matt Johnston
23cc2bfb8c don't silently ignore extra flag arguments 2015-10-21 22:05:50 +08:00
Matt Johnston
9e379835c4 avoid invalidated iterator when connection fails 2015-09-29 22:19:11 +08:00
Matt Johnston
8ccbd216c6 make sure that the test for queued packets to write occurs after
those packets might have been enqueued by set_connect_fds()
2015-09-29 21:53:27 +08:00
Matt Johnston
90f4da29d7 Added signature for changeset ef4b26364b0c 2015-08-08 22:14:30 +08:00
Matt Johnston
54dbd5bbc8 Added signature for changeset a687f835236c 2015-08-08 22:14:19 +08:00
Matt Johnston
849b8ec469 Added tag DROPBEAR_2015.68 for changeset 809feaa9408f 2015-08-08 22:14:10 +08:00
Matt Johnston
84e18f72ae changelog and version 2015.68 2015-08-08 20:35:28 +08:00
Guilhem Moulin
633b98ef28 Fix typo in dropbear(8)'s manpage 2015-08-07 23:07:16 +08:00
Guilhem Moulin
2a34a72bff Fix segfault with restricted authorized_key files without forced command 2015-08-07 23:00:08 +08:00
Matt Johnston
24bae46e42 only update keepalive timeout post-auth (when keepalives are sent) 2015-08-07 21:02:49 +08:00
Matt Johnston
7585d4606e Build with -Werror for the simplest case 2015-08-04 08:20:50 +08:00
Matt Johnston
94bff1df66 couple more changelog items 2015-08-03 23:17:50 +08:00
Matt Johnston
2e60d20a76 set timeouts to time remaining rather than timeout duration 2015-08-03 23:05:43 +08:00
Matt Johnston
ce59260ee9 Fix problem where auth timeout wasn't checked when waiting for ident 2015-08-03 21:59:40 +08:00
Matt Johnston
387ebccf36 increase MAX_CMD_LEN to 9000 2015-08-03 21:17:23 +08:00
Matt Johnston
2f618af086 remove .hgtags from release 2015-08-03 21:05:42 +08:00
Matt Johnston
0ac33d22f7 Don't try to send data on first ack packet of 3way handshake.
Cisco SSH on 15.4(3)M2 or similar can't handle it.
2015-08-03 20:53:37 +08:00
Matt Johnston
c7bd5ac77d remove extraneous semicolon from m_free #define 2015-08-03 20:46:29 +08:00
Matt Johnston
941c067765 change DROPBEAR_DEFAULT_CLI_AUTHKEY to just prepend homedir
rather than doing ~ expansion
2015-08-03 20:45:04 +08:00
Matt Johnston
839e023ed8 check ecc key return, fix null pointer crash 2015-06-23 21:48:13 +08:00
Matt Johnston
2e05a2b8c4 Merge pull request #11 from nshopik/patch-2
Prepend DROPBEAR for scp.c
2015-06-12 22:57:48 +08:00
Matt Johnston
fc2c67e61c a bit more changelog 2015-06-12 22:55:10 +08:00
Matt Johnston
9c3e9fcdad merge 2015-06-04 23:24:08 +08:00
Matt Johnston
1a4db21fe4 buf_getstring and buf_putstring now use non-unsigned char* 2015-06-04 23:08:50 +08:00
Matt Johnston
d96a52541f Merge pull request #13 from gazoo74/fix-warnings
Fix warnings
2015-06-04 23:08:50 +08:00
Matt Johnston
e7ac4c1ab3 Merge pull request #13 from gazoo74/fix-warnings
Fix warnings
2015-06-04 22:25:28 +08:00
Matt Johnston
ecd8505218 Disable twofish-ctr by default, add config option 2015-06-03 22:59:59 +08:00
Matt Johnston
1fa1c3f9db note about constant_time_strcmp and lengths 2015-06-03 22:15:12 +08:00
Matt Johnston
91df741926 Fix building when ENABLE_CLI_PUBKEY_AUTH is unset 2015-06-03 21:45:32 +08:00
Matt Johnston
2a431cab03 separate client/server fastopen options 2015-05-29 23:19:11 +08:00
Gaël PORTAY
9fdab3ced8 Merge branch 'fix-pointer-sign-warnings' into fix-warnings 2015-05-05 20:42:38 +02:00
Gaël PORTAY
6e15e75391 Turn modptr local variable into unsigned char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
1c2a1838fc Turn name and instruction local variables into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
bfd730aa4c Turn type and term local variables into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
e3c6a86b1e Turn TCPFwdEntry's connectaddr and listenaddr attributes into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
bbaeb917ff Turn banner, methods and tok local variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
20f1e49b73 Turn many local variables into char *
reqname, bindaddr, request_addr, desthost and orighost to be exhaustive.
2015-05-05 20:39:14 +02:00
Gaël PORTAY
292656d899 Turn signame local variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
05b36b484e Turn ChanSess's cmd attribute into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
be3016b8d5 Turn send_msg_service_accept()'s name argument into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
5cf43d76bf Turn checkpubkey() and send_msg_userauth_pk_ok()'s algo argument into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
6f05e810d9 Turn addr local variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
947d2697cf Turn sshsession's remoteident attribute into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
449ddae628 Turn dropbear_ecc_curve's name into const char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
6b90885d4f Turn Algo_Type's name attribute into const char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
bd6c37adb6 Turn local key_indent variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
59235276ac Turn get_response()'s return type and prompt argument into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
e5ce3fc51b Turn type local variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
9f97511356 Turn ChanSess's tty and term attributes into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
ef0aac432c Fix unused make_connection_string() warning [-Werror=unused-function]
This function is used when USE_VFORK is unset.
2015-05-05 20:39:13 +02:00
Gaël PORTAY
7928d83b02 Turn cleantext()'s dirtytext argument into char * 2015-05-05 20:39:13 +02:00
Gaël PORTAY
3e91ec07e4 Fix unused but set variable warnings [-Werror=unused-but-set-variable] 2015-05-05 20:39:13 +02:00
Gaël PORTAY
d680a9e3fb Turn username, servicename and methodname local variables into char *
Changing checkusername()'s username argument into char * as well.
2015-05-05 20:39:13 +02:00
Gaël PORTAY
6086851fc1 Fix unused parameters warnings [-Werror=unused-parameter] 2015-05-05 20:39:13 +02:00
Gaël PORTAY
61726df20c Turn sendaddr, listenaddr and request_listenaddr local variables into char * 2015-05-05 20:39:13 +02:00
Gaël PORTAY
1601a657d4 Turn send_msg_channel_open_failure()'s text and lang into const char * 2015-05-05 20:39:13 +02:00
Gaël PORTAY
50b14f696c Turn start_send_channel_request()'s type argument into char * 2015-05-05 20:39:13 +02:00
Gaël PORTAY
c239baf801 Turn addrandom()'s buf argument into unsigned char *
Data is usually represented as "unsigned char *" like genrandom().
2015-05-05 20:39:13 +02:00
Gaël PORTAY
18638859e6 Expect len to be a type of socklen_t [-Werror=pointer-sign] 2015-05-05 20:39:13 +02:00
Gaël PORTAY
224b16b247 Fix pointer differ in signess warnings [-Werror=pointer-sign] 2015-05-05 20:39:13 +02:00
Gaël PORTAY
d9d97969a3 Uses abort() instead of raising a SIGABRT signal [-Werror]
error: ‘noreturn’ function does return [-Werror]

abort() is a noreturn function while raise() is not.

And because crypt_argchk() is flagged as __attribute__(noreturn), abort()
appears to be a better condidate.

This compilation warning has probably been introduced by commit
1809f741cb.
2015-05-05 20:30:49 +02:00
Gaël PORTAY
897da4ee36 Uses k_size as an signed integer
buf_incrwritepos() and mp_to_unsigned_bin() functions use k_size as signed
integer argument.

k_size is also used in an assertion that compared it to curve_size which is
a signed long.

Only buf_getwriteptr() is using k_size as unsigned.

So it safe to use it as signed.
2015-05-05 20:30:49 +02:00
Gaël PORTAY
90f9f43335 Test struct existance against sizeof() operator
Instead of declaring an "unused-variable" or "unused-but-set-variable"
structure.

This avoid unexpected broken configurations when using something like:
$ ./configure CFLAGS="-Wall -Wextra -Werror"
It causes AC_COMPILE_IFELSE to fail and thus leading to a mismatch
configuration (because the CFLAGS are passed to the macro).
2015-05-05 20:23:54 +02:00
Matt Johnston
0e1dee828a Make sure kexfirstinitialise is called early enough 2015-05-03 00:00:35 +08:00
Matt Johnston
cbdc1f0753 fix travis more 2015-05-02 22:59:55 +08:00
Matt Johnston
7e306336d0 bad travis syntax 2015-05-02 22:55:53 +08:00
Matt Johnston
e7def4c211 add no-writev build 2015-05-02 22:51:46 +08:00
Matt Johnston
19e1afbd1c Fix no-writev fallback 2015-05-02 22:47:25 +08:00
Matt Johnston
fee32054e6 Should be AF_UNSPEC not PF_UNSPEC 2015-04-17 20:59:32 +08:00
Matt Johnston
9754fdd995 fastopen code was totally broken 2015-04-14 20:43:54 +08:00
Matt Johnston
ef20b9ff7a Avoid channel writev() when there is nothing to write 2015-03-21 22:43:08 +08:00
Matt Johnston
275611fbaa Make main socket nonblocking. Limit writequeue size. 2015-03-20 23:36:42 +08:00
Matt Johnston
a070159cc5 Fix when iov queue is large 2015-03-20 23:33:45 +08:00
Matt Johnston
20f9683ae0 avoid malloc for iovec 2015-03-20 22:53:32 +08:00
Matt Johnston
dce384668b dropbear_assert() rather than assert() 2015-03-16 21:33:01 +08:00
Nikolay Shopik
fdcd21e74b Prepend DROPBEAR for scp.c 2015-03-12 15:14:47 +03:00
Matt Johnston
67b4fa313e strdup strerror 2015-03-11 23:10:27 +08:00
Matt Johnston
5dff74109e Fix error handling for dbclient async connect 2015-03-03 20:53:00 +08:00
Matt Johnston
20d970a0e2 more changes 2015-03-02 21:40:06 +08:00
Matt Johnston
94734ad377 changes (also testing hg bookmarks) 2015-03-02 21:29:49 +08:00
Matt Johnston
14ad6a5972 merge 2015-03-01 23:27:08 +08:00
Matt Johnston
9e66b5a9b1 reword comment for clarity
--HG--
branch : nocircbuffer
2015-03-01 23:26:42 +08:00
Matt Johnston
f782cf375a Fix pubkey auth after change to reuse ses.readbuf as ses.payload
(4d7b4c5526c5)

--HG--
branch : nocircbuffer
2015-03-01 23:02:06 +08:00
Matt Johnston
3317916111 Fix some memory leaks in ecc code 2015-03-01 22:44:36 +08:00
Matt Johnston
f367273549 allocate buffer and data in a single allocation
--HG--
branch : nocircbuffer
2015-03-01 21:16:09 +08:00
Matt Johnston
91ef9b2fa9 Avoid malloc in hmac
--HG--
branch : nocircbuffer
2015-03-01 14:46:04 +08:00
Matt Johnston
579463933b A bit of a bodge to avoid memcpy if zlib is disabled
--HG--
branch : nocircbuffer
2015-03-01 00:57:21 +08:00
Matt Johnston
989c5c1436 Avoid copying data into circular buffer
--HG--
branch : nocircbuffer
2015-03-01 00:44:45 +08:00
Matt Johnston
3113932151 Better failure handling 2015-02-28 23:49:39 +08:00
Matt Johnston
125a970d71 merge tcp fastopen 2015-02-28 23:24:30 +08:00
Matt Johnston
89c0b2a6d8 Add cleanup
--HG--
branch : fastopen
2015-02-28 23:15:23 +08:00
Matt Johnston
31e379c300 merge from default
--HG--
branch : fastopen
2015-02-28 09:06:40 +08:00
Matt Johnston
843953379c EINPROGRESS for sendmsg() means it's working OK
--HG--
branch : fastopen
2015-02-27 00:02:48 +08:00
Matt Johnston
2a90c1ca7e ignore any sendmsg() errors
--HG--
branch : fastopen
2015-02-26 23:43:12 +08:00
Thorsten Horstmann
59bb1777be Use m_burn rather than memset 2015-02-24 22:48:14 +08:00
Thorsten Horstmann
c5f3c550a6 Avoid cppcheck warning 2015-02-24 22:41:26 +08:00
Matt Johnston
1809f741cb Add more ATTRIB_NORETURN annotations, from Thorsten Horstmann 2015-02-24 22:36:20 +08:00
Matt Johnston
9adfff5c1a Revert accidental commented out signal handlers 2015-02-24 22:23:32 +08:00
Matt Johnston
8008b595d3 Some additional cleanup functions 2015-02-24 22:17:04 +08:00
Matt Johnston
21bed0d21a Free memory before exiting. Based on patch from Thorsten Horstmann.
Client side is not complete.
2015-02-24 22:01:33 +08:00
Matt Johnston
4b1f5ec7c2 Use m_close() which will avoid close(-1) 2015-02-24 20:53:32 +08:00
Thorsten Horstmann
ab9439519a Fix for old compilers, variable declarations at beginning of functions
and /**/ comments
2015-02-24 20:51:18 +08:00
Thorsten Horstmann
abeb9d64a3 Some minor typo fixes, found by codespell. 2015-02-24 20:45:07 +08:00
Thorsten Horstmann
fdb7ffa864 DROPBEAR_ prefix for include guards to avoid collisions 2015-02-24 20:43:01 +08:00
Matt Johnston
46845fd3e8 get rid of some unnecessary code
--HG--
branch : fastopen
2015-02-21 00:43:32 +08:00
Matt Johnston
c53ca6ebc0 avoid some warnings
--HG--
branch : fastopen
2015-02-20 23:43:59 +08:00
Matt Johnston
f04a3a2cfa Fixes for backwards compatibility
--HG--
branch : fastopen
2015-02-20 23:38:05 +08:00
Matt Johnston
364a53577e Move generic network routines to netio.c
--HG--
branch : fastopen
2015-02-20 23:16:38 +08:00
Matt Johnston
1b1997bf2d Update priority once the socket is open
--HG--
branch : fastopen
2015-02-20 22:13:53 +08:00
Matt Johnston
34f9adb1c9 merge
--HG--
branch : fastopen
2015-02-19 22:42:30 +08:00
Matt Johnston
2e7d468b90 Add the missing second half of iov code
--HG--
branch : fastopen
2015-02-19 22:41:51 +08:00
Matt Johnston
86a717c80c fallback for old glibc and fastopen
memset rather than = {0} initialiser

--HG--
branch : fastopen
2015-02-19 22:33:51 +08:00
Matt Johnston
76a3eb393c In theory TFO should work. Needs platform cleanup and testing
--HG--
branch : fastopen
2015-02-19 00:32:00 +08:00
Matt Johnston
5f0cc969a0 generalise write iovec handling
--HG--
branch : fastopen
2015-02-18 23:02:49 +08:00
Matt Johnston
755c1458f0 async connections working
--HG--
branch : fastopen
2015-02-18 22:46:15 +08:00
Matt Johnston
8795d733ec work in progress for async connect
--HG--
branch : fastopen
2015-02-18 00:05:27 +08:00
Matt Johnston
28f61c8b3a tcp fastopen for the server
--HG--
branch : fastopen
2015-02-15 22:34:05 +08:00
Matt Johnston
9abcc7b909 connect_remote() is now always non-blocking 2015-02-14 09:56:11 +08:00
Matt Johnston
2c35f1c8fd Add envirnonment variable for debug timestamps to roughly match
network timestamps (in tshark)
2015-02-13 23:47:53 +08:00
Matt Johnston
136188259e Fix print that no longer works since we're not using fourCCs 2015-02-13 23:17:23 +08:00
Matt Johnston
02179b1218 merge 2015-02-13 23:15:12 +08:00
Matt Johnston
1e350de136 Make it compile 2015-02-13 23:13:58 +08:00
Matt Johnston
9aeda4c5bd piggyback data on acks when making connections on linux 2015-02-13 22:49:15 +08:00
Matt Johnston
8eb30c353a debug should be off by default 2015-02-13 21:45:15 +08:00
Matt Johnston
c44a78a2e6 Tighten validation of DH values. Odds of x==0 being generated are
improbable, roughly 2**-1023
Regression in 0.49
2015-02-10 21:46:19 +08:00
Matt Johnston
b6685bf806 twofish ctr modes 2015-02-04 22:12:06 +08:00
Matt Johnston
269d690e71 Added signature for changeset 1d2d81b1b7c1 2015-01-29 21:42:01 +08:00
Matt Johnston
4df268f10e sha256 2015-01-28 22:58:52 +08:00
Matt Johnston
19b3f01477 bump version 2015-01-28 22:57:33 +08:00
Matt Johnston
86811f4765 Added tag DROPBEAR_2015.67 for changeset cbd674d63cd4 2015-01-28 22:55:27 +08:00
Matt Johnston
4de876f259 Keep sha1 default 2015-01-28 22:14:07 +08:00
109 changed files with 1926 additions and 1247 deletions

View File

@@ -13,3 +13,7 @@ a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVq
96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m
caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq
2d421bc0545d1be6d59a4ebfe61606d94b124b0c 0 iEYEABECAAYFAlRJDCQACgkQjPn4sExkf7xUYACcCwVJkYWXJn5x/D5A+qMupy778lEAn0rg1oNiq96YU/4jOPsS5IMItihu
1d2d81b1b7c1b100e9c369e40b9fa5b2d491eea9 0 iEYEABECAAYFAlTKOKUACgkQjPn4sExkf7xWMACfYFozyHiRk5GaocTa5z6Ws1uyB4kAoLubxoxcnM3E7AA9mHAzc3OB5M0Y
a687f835236c7025b5cb2968fe9c4ebc4a49f0ea 0 iQIcBAABCgAGBQJVxg62AAoJEPSYMBLCC7qsC+EQAKw8YWogrVHhIFct2fx/nqybSPVrhFyKFKHhq7K/lZeVm0MGIWdSyVcQgP+Hs2jWNBWzG4AJ1BtifHWQH6IDh7W5RuwOXu5KobgPW9BsN3EVE9KIR+xe9jCAmFl9rIw0tNpy1q6R0TpYXx/sWlMilxecyEGyr2Ias2Sm19aY2mOEv8PLfh9BLfrJEKtt2NxL7TX8ScPwJXJMmVIQjN9WK4Ptx3tjcGNRivEVR/dftP5sJx2DBJx9avyDqrfloMW7Q7sPgJ88MPruCDxedOkbzH7JdHe3Humr2G4LsI0KPU7pNN6EBDjhJ+SVXuOyAgu5j/C0R+0ggGfjSrjDu8WjHyclFlwwu2MSGuHf111I1qkLtaRY3H1FZO5Y2gbLwBLQ82svA4klcBIxtP5jKAZDTh1jQMYsfKotvZdawOWrPDkNmKoUg2JXLHAtj9Dd0uGIhqfspZY3qlpzxw9uCkljWclUBD097ygotwAb2XdLoAWZ3KdvoPM+k448vIAQ7Q/aqcnm/dLQJr3Le029gpkOKoWKaQTlk0itrRGpgETHAhE2LnmWxYSKp6NYSKMgEONbfDiVNLyDTOlvpPiEb20RsOP64xA4wVDGmPenCURmMYoepQK6oJdtkNtCdth2S49KxPQAC+Dem4YZ7b+5b+cXrK5Nz7elBxZzRQWdjmZ4JDQK
ef4b26364b0cdda1084751d7de3d76c589e2d9cb 0 iQIcBAABCgAGBQJVxg7BAAoJEESTFJTynGdz9Q4P/A0Kq4H52rQqxq42PoEMFbVQIUfkFzyWjAz8eEGLmP5x5/sdpyxZDEyBSUG55uyNvOPTHE+Sd3t2h2Iieq749qwYgqggXC0P+C0zGzW3hB5Rv6dTUrKN1yCyaWE2tY488RsyVlcAs4vrp1Cum5Gv8/BUVKjzZmkZ1iq/3RyrvbLEiLoMrcLnQ+sUdaYHvfEwxDbzpOEvepg8iDJBitTrfG9xHp9otX6ucahwn1EumFvC5mvUxbiQ9jv76t4FJztjMoB24hPCH9T1FjB8uNsoM+j2Z67r81eJrGgNpJzjX0S3lY/AADZGhfGnfybTM9gFuQayIJuCJqduQibVwYkAAnPi17NmbdwPu0Rdz55oU+ft09XLVm/qkQcD1EP5bxYWnLIEMkkZQnFx7WdMpjKK9oGxZHeFYAKEgPgePCkk4TQ4PxNa+3854H19AUssQlaueGcbDLyPIRiSyqhleXawGfaJi+1jBt0DM7CNbAHAUWUE07VhQzNGWjabdEk4eXKTmDL+mZJFdHGBhyCve8sPmZBYJvM2PRgcXe8fwFh+R7gVj6kFbZJvgM9kG7EeF+4ZMEXG4yKpV/SKfMMeEPBCZjFxZhlJJ0fsZbB1Y/iLw8LXnJ0fa/5xFYv6k+iytfom/rqS4iUD7NWTjcEYHjd4EO4QlPD2Ef/AWOO8YBUBv8kA
af074dbcb68ff8670b3818e0d66d5dc6f1bd5877 0 iQIcBAABCgAGBQJWVdQfAAoJEPSYMBLCC7qs+n4P/RgZU3GsLFJN7v7Cn6NOdKdfjJBmlbCtK9KwlZZaj8fW4noqnLDcDd6a2xT4mDV3rCE6+QYialGXjNkkNCBwD9Z+gFc8spOtThrpQ54dgWzbgDlYB1y7Hp7DoWoJQIlU6Od9nWBemcSrAviOFNAX8+S6poRdEhrHgMcv2xJoqHjvT7X8gob0RnJcYxW5nLWzDaJV58QnX6QlXg4ClSB6IoCeEawdW6WzXlZ9MGsRycTtx1ool7Uo6Vo2xg48n9TaJqM/lbSsMAjHxO/fdTJMWzTId1fuZxJGFVeJbkhjSwlf7fkVXxrgDxjvIAmFDR8TSTfJo50CD82j5rPcd7KSEpQ12ImBUsntPDgOtt/mJZ3HcFds86OZ7NkPpqoJGVFFQ8yUpe//DNSB2Ovg1FrwhSKOq/9N61BBwk1INVFDp1hMq45PIa9gI9zW/99inGDeSSQlxa4iafEUEjXZTRYuX7mFjnWm5q7r134J7kyWQtN/jNUZ71F0mvhnemufgpNY/I/D7K6qkONpbDZ2nuzkhfoqugzhHYp467UePM0qmLTLdXGPPMukoGorpWeiSb2T25AEKm7N4A9NwPmdAnoFjAibjF9FAuU03sl+pu9MqFb+1ldsqjNfxhcJmoAUR5vy3pED9ailCb/OCBVTHkDPfTEhGU3waO9tPM+5x2rGB5fe

View File

@@ -46,3 +46,6 @@ e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test
0d2d39957c029adb7f4327d37fe6b4900f0736d9 DROPBEAR_2014.64
e9579816f20ea85affc6135e87f8477992808948 DROPBEAR_2014.65
735511a4c761141416ad0e6728989d2dafa55bc2 DROPBEAR_2014.66
cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
809feaa9408f036734129c77f2b3c7e779d4f099 DROPBEAR_2015.68
1637dbd262124d113e52967df46afd6c715e4fad DROPBEAR_2015.69

View File

@@ -3,7 +3,9 @@ compiler:
- gcc
script:
- autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst && make install
- autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS" --prefix=$HOME/inst
- test "$NOWRITEV" && sed -i s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h || true
- make install
- ~/inst/bin/dropbearkey -t rsa -f testrsa
- ~/inst/bin/dropbearkey -t dss -f testdss
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
@@ -15,6 +17,7 @@ before_install:
- sudo apt-get install -qq libz-dev libtomcrypt-dev libtommath-dev
env:
- BUNDLEDLIBTOM=--disable-bundled-libtom
- BUNDLEDLIBTOM=--disable-bundled-libtom WEXTRAFLAGS=-Werror
- BUNDLEDLIBTOM=--enable-bundled-libtom
- MULTI=1
- NOWRITEV=1

72
CHANGES
View File

@@ -1,3 +1,75 @@
2015.70 - 26 November 2015
- Fix server password authentication on Linux, broke in 2015.69
2015.69 - 25 November 2015
- Fix crash when forwarded TCP connections fail to connect (bug introduced in 2015.68)
- Avoid hang on session close when multiple sessions are started, affects Qt Creator
Patch from Andrzej Szombierski
- Reduce per-channel memory consumption in common case, increase default
channel limit from 100 to 1000 which should improve SOCKS forwarding for modern
webpages
- Handle multiple command line arguments in a single flag, thanks to Guilhem Moulin
- Manpage improvements from Guilhem Moulin
- Build fixes for Android from Mike Frysinger
- Don't display the MOTD when an explicit command is run from Guilhem Moulin
- Check curve25519 shared secret isn't zero
2015.68 - Saturday 8 August 2015
- Reduce local data copying for improved efficiency. Measured 30%
increase in throughput for connections to localhost
- Forwarded TCP ports connect asynchronously and try all available addresses
(IPv4, IPv6, round robin DNS)
- Fix all compile warnings, many patches from Gaël Portay
Note that configure with -Werror may not be successful on some platforms (OS X)
and some configuration options may still result in unused variable
warnings.
- Use TCP Fast Open on Linux if available. Saves a round trip at connection
to hosts that have previously been connected.
Needs a recent Linux kernel and possibly "sysctl -w net.ipv4.tcp_fastopen=3"
Client side is disabled by default pending further compatibility testing
with networks and systems.
- Increase maximum command length to 9000 bytes
- Free memory before exiting, patch from Thorsten Horstmann. Useful for
Dropbear ports to embedded systems and for checking memory leaks
with valgrind. Only partially implemented for dbclient.
This is disabled by default, enable with DROPBEAR_CLEANUP in sysoptions.h
- DROPBEAR_DEFAULT_CLI_AUTHKEY setting now always prepends home directory unless
there is a leading slash (~ isn't treated specially)
- Fix small ECC memory leaks
- Tighten validation of Diffie-Hellman parameters, from Florent Daigniere of
Matta Consulting. Odds of bad values are around 2**-512 -- improbable.
- Twofish-ctr cipher is supported though disabled by default
- Fix pre-authentication timeout when waiting for client SSH-2.0 banner, thanks
to CL Ouyang
- Fix null pointer crash with restrictions in authorized_keys without a command, patch from
Guilhem Moulin
- Ensure authentication timeout is handled while reading the initial banner,
thanks to CL Ouyang for finding it.
- Fix null pointer crash when handling bad ECC keys. Found by afl-fuzz
2015.67 - Wednesday 28 January 2015
- Call fsync() after generating private keys to ensure they aren't lost if a

View File

@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
same license:
Copyright (c) 2002-2014 Matt Johnston
Copyright (c) 2002-2015 Matt Johnston
Portions copyright (c) 2004 Mihnea Stoenescu
All rights reserved.

View File

@@ -40,12 +40,12 @@ SVROBJS=svr-kex.o svr-auth.o sshpty.o \
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-runopts.o cli-chansession.o \
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
cli-agentfwd.o list.o
cli-agentfwd.o
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
tcp-accept.o listener.o process-packet.o \
common-runopts.o circbuffer.o curve25519-donna.o
common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
KEYOBJS=dropbearkey.o
@@ -140,7 +140,7 @@ insmulti%: dropbearmulti
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
# dropbear should go in sbin, so it needs a seperate rule
# dropbear should go in sbin, so it needs a separate rule
inst_dropbear: dropbear
$(INSTALL) -d $(DESTDIR)$(sbindir)
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)

View File

@@ -21,8 +21,8 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _AGENTFWD_H_
#define _AGENTFWD_H_
#ifndef DROPBEAR_AGENTFWD_H_
#define DROPBEAR_AGENTFWD_H_
#include "includes.h"
#include "chansession.h"
@@ -60,4 +60,4 @@ void svr_agentset(struct ChanSess *chansess);
#endif /* ENABLE_SVR_AGENTFWD */
#endif /* _AGENTFWD_H_ */
#endif /* DROPBEAR_AGENTFWD_H_ */

8
algo.h
View File

@@ -22,9 +22,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _ALGO_H_
#ifndef DROPBEAR_ALGO_H_
#define _ALGO_H_
#define DROPBEAR_ALGO_H_
#include "includes.h"
#include "buffer.h"
@@ -35,7 +35,7 @@
struct Algo_Type {
const unsigned char *name; /* identifying name */
const char *name; /* identifying name */
char val; /* a value for this cipher, or -1 for invalid */
const void *data; /* algorithm specific data */
char usable; /* whether we can use this algorithm */
@@ -134,4 +134,4 @@ enum {
DROPBEAR_COMP_ZLIB_DELAY,
};
#endif /* _ALGO_H_ */
#endif /* DROPBEAR_ALGO_H_ */

8
auth.h
View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _AUTH_H_
#define _AUTH_H_
#ifndef DROPBEAR_AUTH_H_
#define DROPBEAR_AUTH_H_
#include "includes.h"
#include "signkey.h"
@@ -133,8 +133,8 @@ struct PubKeyOptions {
int no_x11_forwarding_flag;
int no_pty_flag;
/* "command=" option. */
unsigned char * forced_command;
char * forced_command;
};
#endif
#endif /* _AUTH_H_ */
#endif /* DROPBEAR_AUTH_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _BIGNUM_H_
#define _BIGNUM_H_
#ifndef DROPBEAR_BIGNUM_H_
#define DROPBEAR_BIGNUM_H_
#include "includes.h"
#include "dbutil.h"
@@ -35,4 +35,4 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
hash_state *hs, mp_int *mp);
#endif /* _BIGNUM_H_ */
#endif /* DROPBEAR_BIGNUM_H_ */

View File

@@ -46,17 +46,15 @@ buffer* buf_new(unsigned int size) {
dropbear_exit("buf->size too big");
}
buf = (buffer*)m_malloc(sizeof(buffer));
buf = (buffer*)m_malloc(sizeof(buffer)+size);
if (size > 0) {
buf->data = (unsigned char*)m_malloc(size);
buf->data = (unsigned char*)buf + sizeof(buffer);
} else {
buf->data = NULL;
}
buf->size = size;
buf->pos = 0;
buf->len = 0;
return buf;
@@ -65,7 +63,6 @@ buffer* buf_new(unsigned int size) {
/* free the buffer's data and the buffer itself */
void buf_free(buffer* buf) {
m_free(buf->data)
m_free(buf);
}
@@ -78,17 +75,18 @@ void buf_burn(buffer* buf) {
/* resize a buffer, pos and len will be repositioned if required when
* downsizing */
void buf_resize(buffer *buf, unsigned int newsize) {
buffer* buf_resize(buffer *buf, unsigned int newsize) {
if (newsize > BUF_MAX_SIZE) {
dropbear_exit("buf->size too big");
}
buf->data = m_realloc(buf->data, newsize);
buf = m_realloc(buf, sizeof(buffer)+newsize);
buf->data = (unsigned char*)buf + sizeof(buffer);
buf->size = newsize;
buf->len = MIN(newsize, buf->len);
buf->pos = MIN(newsize, buf->pos);
return buf;
}
/* Create a copy of buf, allocating required memory etc. */
@@ -99,7 +97,9 @@ buffer* buf_newcopy(buffer* buf) {
ret = buf_new(buf->len);
ret->len = buf->len;
memcpy(ret->data, buf->data, buf->len);
if (buf->len > 0) {
memcpy(ret->data, buf->data, buf->len);
}
return ret;
}
@@ -127,7 +127,7 @@ void buf_setpos(buffer* buf, unsigned int pos) {
buf->pos = pos;
}
/* increment the postion by incr, increasing the buffer length if required */
/* increment the position by incr, increasing the buffer length if required */
void buf_incrwritepos(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
dropbear_exit("Bad buf_incrwritepos");
@@ -203,10 +203,10 @@ unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
/* Return a null-terminated string, it is malloced, so must be free()ed
* Note that the string isn't checked for null bytes, hence the retlen
* may be longer than what is returned by strlen */
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
char* buf_getstring(buffer* buf, unsigned int *retlen) {
unsigned int len;
unsigned char* ret;
char* ret;
len = buf_getint(buf);
if (len > MAX_STRING_LEN) {
dropbear_exit("String too long");
@@ -225,15 +225,15 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
/* Return a string as a newly allocated buffer */
buffer * buf_getstringbuf(buffer *buf) {
buffer *ret;
unsigned char* str;
unsigned int len;
str = buf_getstring(buf, &len);
ret = m_malloc(sizeof(*ret));
ret->data = str;
ret->len = len;
ret->size = len;
ret->pos = 0;
buffer *ret = NULL;
unsigned int len = buf_getint(buf);
if (len > MAX_STRING_LEN) {
dropbear_exit("String too long");
}
ret = buf_new(len);
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
buf_incrpos(buf, len);
buf_incrlen(ret, len);
return ret;
}
@@ -262,16 +262,16 @@ void buf_putint(buffer* buf, int unsigned val) {
}
/* put a SSH style string into the buffer, increasing buffer len if required */
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
void buf_putstring(buffer* buf, const char* str, unsigned int len) {
buf_putint(buf, len);
buf_putbytes(buf, str, len);
buf_putbytes(buf, (const unsigned char*)str, len);
}
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
buf_putstring(buf, buf_str->data, buf_str->len);
buf_putstring(buf, (const char*)buf_str->data, buf_str->len);
}
/* put the set of len bytes into the buffer, incrementing the pos, increasing

View File

@@ -22,14 +22,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _BUFFER_H_
#ifndef DROPBEAR_BUFFER_H_
#define _BUFFER_H_
#define DROPBEAR_BUFFER_H_
#include "includes.h"
struct buf {
/* don't manipulate data member outside of buffer.c - it
is a pointer into the malloc holding buffer itself */
unsigned char * data;
unsigned int len; /* the used size */
unsigned int pos;
@@ -40,7 +41,8 @@ struct buf {
typedef struct buf buffer;
buffer * buf_new(unsigned int size);
void buf_resize(buffer *buf, unsigned int newsize);
/* Possibly returns a new buffer*, like realloc() */
buffer * buf_resize(buffer *buf, unsigned int newsize);
void buf_free(buffer* buf);
void buf_burn(buffer* buf);
buffer* buf_newcopy(buffer* buf);
@@ -54,15 +56,15 @@ unsigned char buf_getbool(buffer* buf);
void buf_putbyte(buffer* buf, unsigned char val);
unsigned char* buf_getptr(buffer* buf, unsigned int len);
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
char* buf_getstring(buffer* buf, unsigned int *retlen);
buffer * buf_getstringbuf(buffer *buf);
void buf_eatstring(buffer *buf);
void buf_putint(buffer* buf, unsigned int val);
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
void buf_putstring(buffer* buf, const char* str, unsigned int len);
void buf_putbufstring(buffer *buf, const buffer* buf_str);
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
void buf_putmpint(buffer* buf, mp_int * mp);
int buf_getmpint(buffer* buf, mp_int* mp);
unsigned int buf_getint(buffer* buf);
#endif /* _BUFFER_H_ */
#endif /* DROPBEAR_BUFFER_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CHANNEL_H_
#define _CHANNEL_H_
#ifndef DROPBEAR_CHANNEL_H_
#define DROPBEAR_CHANNEL_H_
#include "includes.h"
#include "buffer.h"
@@ -73,6 +73,7 @@ struct Channel {
* to ensure we don't run it twice (nor type->checkclose()). */
int close_handler_done;
struct dropbear_progress_connection *conn_pending;
int initconn; /* used for TCP forwarding, whether the channel has been
fully initialised */
@@ -92,7 +93,7 @@ struct Channel {
struct ChanType {
int sepfds; /* Whether this channel has seperate pipes for in/out or not */
int sepfds; /* Whether this channel has separate pipes for in/out or not */
char *name;
int (*inithandler)(struct Channel*);
int (*check_close)(struct Channel*);
@@ -100,9 +101,12 @@ struct ChanType {
void (*closehandler)(struct Channel*);
};
/* Callback for connect_remote */
void channel_connect_done(int result, int sock, void* user_data, const char* errstring);
void chaninitialise(const struct ChanType *chantypes[]);
void chancleanup();
void setchannelfds(fd_set *readfd, fd_set *writefd);
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads);
void channelio(fd_set *readfd, fd_set *writefd);
struct Channel* getchannel();
/* Returns an arbitrary channel that is in a ready state - not
@@ -131,10 +135,10 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type);
void recv_msg_channel_open_confirmation();
void recv_msg_channel_open_failure();
#endif
void start_send_channel_request(struct Channel *channel, unsigned char *type);
void start_send_channel_request(struct Channel *channel, char *type);
void send_msg_request_success();
void send_msg_request_failure();
#endif /* _CHANNEL_H_ */
#endif /* DROPBEAR_CHANNEL_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CHANSESSION_H_
#define _CHANSESSION_H_
#ifndef DROPBEAR_CHANSESSION_H_
#define DROPBEAR_CHANSESSION_H_
#include "loginrec.h"
#include "channel.h"
@@ -39,14 +39,14 @@ struct exitinfo {
struct ChanSess {
unsigned char * cmd; /* command to exec */
char * cmd; /* command to exec */
pid_t pid; /* child process pid */
/* pty details */
int master; /* the master terminal fd*/
int slave;
unsigned char * tty;
unsigned char * term;
char * tty;
char * term;
/* exit details */
struct exitinfo exit;
@@ -103,4 +103,4 @@ struct SigMap {
extern const struct SigMap signames[];
#endif /* _CHANSESSION_H_ */
#endif /* DROPBEAR_CHANSESSION_H_ */

View File

@@ -37,9 +37,8 @@ circbuffer * cbuf_new(unsigned int size) {
}
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
if (size > 0) {
cbuf->data = (unsigned char*)m_malloc(size);
}
/* data is malloced on first write */
cbuf->data = NULL;
cbuf->used = 0;
cbuf->readpos = 0;
cbuf->writepos = 0;
@@ -50,8 +49,10 @@ circbuffer * cbuf_new(unsigned int size) {
void cbuf_free(circbuffer * cbuf) {
m_burn(cbuf->data, cbuf->size);
m_free(cbuf->data);
if (cbuf->data) {
m_burn(cbuf->data, cbuf->size);
m_free(cbuf->data);
}
m_free(cbuf);
}
@@ -67,23 +68,6 @@ unsigned int cbuf_getavail(circbuffer * cbuf) {
}
unsigned int cbuf_readlen(circbuffer *cbuf) {
dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == 0) {
TRACE(("cbuf_readlen: unused buffer"))
return 0;
}
if (cbuf->readpos < cbuf->writepos) {
return cbuf->writepos - cbuf->readpos;
}
return cbuf->size - cbuf->readpos;
}
unsigned int cbuf_writelen(circbuffer *cbuf) {
dropbear_assert(cbuf->used <= cbuf->size);
@@ -102,12 +86,19 @@ unsigned int cbuf_writelen(circbuffer *cbuf) {
return cbuf->size - cbuf->writepos;
}
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("Bad cbuf read");
}
void cbuf_readptrs(circbuffer *cbuf,
unsigned char **p1, unsigned int *len1,
unsigned char **p2, unsigned int *len2) {
*p1 = &cbuf->data[cbuf->readpos];
*len1 = MIN(cbuf->used, cbuf->size - cbuf->readpos);
return &cbuf->data[cbuf->readpos];
if (*len1 < cbuf->used) {
*p2 = cbuf->data;
*len2 = cbuf->used - *len1;
} else {
*p2 = NULL;
*len2 = 0;
}
}
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
@@ -116,6 +107,11 @@ unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
dropbear_exit("Bad cbuf write");
}
if (!cbuf->data) {
/* lazy allocation */
cbuf->data = (unsigned char*)m_malloc(cbuf->size);
}
return &cbuf->data[cbuf->writepos];
}
@@ -131,10 +127,6 @@ void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("Bad cbuf read");
}
dropbear_assert(cbuf->used >= len);
cbuf->used -= len;
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CIRCBUFFER_H_
#define _CIRCBUFFER_H_
#ifndef DROPBEAR_CIRCBUFFER_H_
#define DROPBEAR_CIRCBUFFER_H_
struct circbuf {
unsigned int size;
@@ -40,10 +40,12 @@ void cbuf_free(circbuffer * cbuf);
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */
unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len);
/* returns pointers to the two portions of the circular buffer that can be read */
void cbuf_readptrs(circbuffer *cbuf,
unsigned char **p1, unsigned int *len1,
unsigned char **p2, unsigned int *len2);
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
void cbuf_incrread(circbuffer *cbuf, unsigned int len);

View File

@@ -155,7 +155,7 @@ static buffer * agent_request(unsigned char type, buffer *data) {
goto out;
}
buf_resize(inbuf, readlen);
inbuf = buf_resize(inbuf, readlen);
buf_setpos(inbuf, 0);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
if ((size_t)ret != readlen) {

View File

@@ -43,9 +43,9 @@ void cli_auth_getmethods() {
TRACE(("enter cli_auth_getmethods"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
buf_putstring(ses.writepayload, cli_opts.username,
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
@@ -75,7 +75,7 @@ void cli_auth_getmethods() {
void recv_msg_userauth_banner() {
unsigned char* banner = NULL;
char* banner = NULL;
unsigned int bannerlen;
unsigned int i, linecount;
@@ -151,8 +151,8 @@ void recv_msg_userauth_specific_60() {
void recv_msg_userauth_failure() {
unsigned char * methods = NULL;
unsigned char * tok = NULL;
char * methods = NULL;
char * tok = NULL;
unsigned int methlen = 0;
unsigned int partial = 0;
unsigned int i = 0;
@@ -324,6 +324,7 @@ int cli_auth_try() {
return DROPBEAR_FAILURE;
}
#if defined(ENABLE_CLI_PASSWORD_AUTH) || defined(ENABLE_CLI_INTERACT_AUTH)
/* A helper for getpass() that exits if the user cancels. The returned
* password is statically allocated by getpass() */
char* getpass_or_cancel(char* prompt)
@@ -347,3 +348,4 @@ char* getpass_or_cancel(char* prompt)
}
return password;
}
#endif

View File

@@ -31,10 +31,10 @@
#ifdef ENABLE_CLI_INTERACT_AUTH
static unsigned char* get_response(unsigned char* prompt)
static char* get_response(char* prompt)
{
FILE* tty = NULL;
unsigned char* response = NULL;
char* response = NULL;
/* not a password, but a reasonable limit */
char buf[DROPBEAR_MAX_CLI_PASS];
char* ret = NULL;
@@ -50,13 +50,13 @@ static unsigned char* get_response(unsigned char* prompt)
}
if (ret == NULL) {
response = (unsigned char*)m_strdup("");
response = m_strdup("");
} else {
unsigned int buflen = strlen(buf);
/* fgets includes newlines */
if (buflen > 0 && buf[buflen-1] == '\n')
buf[buflen-1] = '\0';
response = (unsigned char*)m_strdup(buf);
response = m_strdup(buf);
}
m_burn(buf, sizeof(buf));
@@ -66,14 +66,14 @@ static unsigned char* get_response(unsigned char* prompt)
void recv_msg_userauth_info_request() {
unsigned char *name = NULL;
unsigned char *instruction = NULL;
char *name = NULL;
char *instruction = NULL;
unsigned int num_prompts = 0;
unsigned int i;
unsigned char *prompt = NULL;
char *prompt = NULL;
unsigned int echo = 0;
unsigned char *response = NULL;
char *response = NULL;
TRACE(("enter recv_msg_recv_userauth_info_request"))
@@ -121,7 +121,7 @@ void recv_msg_userauth_info_request() {
echo = buf_getbool(ses.payload);
if (!echo) {
unsigned char* p = getpass_or_cancel(prompt);
char* p = getpass_or_cancel(prompt);
response = m_strdup(p);
m_burn(p, strlen(p));
} else {
@@ -153,7 +153,7 @@ void cli_auth_interactive() {
strlen(cli_opts.username));
/* service name */
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
/* method */

View File

@@ -143,10 +143,10 @@ void cli_auth_password() {
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN);
buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */

View File

@@ -58,7 +58,7 @@ void recv_msg_userauth_pk_ok() {
buffer* keybuf = NULL;
char* algotype = NULL;
unsigned int algolen;
int keytype;
enum signkey_type keytype;
unsigned int remotelen;
TRACE(("enter recv_msg_userauth_pk_ok"))
@@ -141,7 +141,7 @@ void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
const char *algoname = NULL;
int algolen;
unsigned int algolen;
buffer* sigbuf = NULL;
TRACE(("enter send_msg_userauth_pubkey"))
@@ -152,10 +152,10 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
AUTH_METHOD_PUBKEY_LEN);
buf_putbyte(ses.writepayload, realsign);

View File

@@ -56,7 +56,7 @@ const struct ChanType clichansess = {
static void cli_chansessreq(struct Channel *channel) {
unsigned char* type = NULL;
char* type = NULL;
int wantreply;
TRACE(("enter cli_chansessreq"))
@@ -272,7 +272,7 @@ void cli_chansess_winchange() {
static void send_chansess_pty_req(struct Channel *channel) {
unsigned char* term = NULL;
char* term = NULL;
TRACE(("enter send_chansess_pty_req"))
@@ -305,7 +305,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
static void send_chansess_shell_req(struct Channel *channel) {
unsigned char* reqtype = NULL;
char* reqtype = NULL;
TRACE(("enter send_chansess_shell_req"))
@@ -392,7 +392,7 @@ static const struct ChanType cli_chan_netcat = {
void cli_send_netcat_request() {
const unsigned char* source_host = "127.0.0.1";
const char* source_host = "127.0.0.1";
const int source_port = 22;
TRACE(("enter cli_send_netcat_request"))
@@ -403,7 +403,7 @@ void cli_send_netcat_request() {
dropbear_exit("Couldn't open initial channel");
}
buf_putstring(ses.writepayload, cli_opts.netcat_host,
buf_putstring(ses.writepayload, cli_opts.netcat_host,
strlen(cli_opts.netcat_host));
buf_putint(ses.writepayload, cli_opts.netcat_port);

View File

@@ -79,7 +79,7 @@ void send_msg_kexdh_init() {
}
cli_ses.curve25519_param = gen_kexcurve25519_param();
}
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
#endif
break;
}
@@ -322,7 +322,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
}
/* Compare hostnames */
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
if (strncmp(cli_opts.remotehost, (const char *) buf_getptr(line, hostlen),
hostlen) != 0) {
continue;
}
@@ -334,7 +334,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
continue;
}
if (strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) {
if (strncmp((const char *) buf_getptr(line, algolen), algoname, algolen) != 0) {
TRACE(("algo doesn't match"))
continue;
}
@@ -346,7 +346,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
}
/* Now we're at the interesting hostkey */
ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen,
ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algoname, algolen,
line, &fingerprint);
if (ret == DROPBEAR_SUCCESS) {
@@ -382,9 +382,9 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
buf_setpos(line, 0);
buf_setlen(line, 0);
buf_putbytes(line, cli_opts.remotehost, hostlen);
buf_putbytes(line, (const unsigned char *) cli_opts.remotehost, hostlen);
buf_putbyte(line, ' ');
buf_putbytes(line, algoname, algolen);
buf_putbytes(line, (const unsigned char *) algoname, algolen);
buf_putbyte(line, ' ');
len = line->size - line->pos;
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr

View File

@@ -30,6 +30,7 @@
#include "session.h"
#include "dbrandom.h"
#include "crypto_desc.h"
#include "netio.h"
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
static void cli_dropbear_log(int priority, const char* format, va_list param);
@@ -46,7 +47,7 @@ int main(int argc, char ** argv) {
#endif
int sock_in, sock_out;
char* error = NULL;
struct dropbear_progress_connection *progress = NULL;
_dropbear_exit = cli_dropbear_exit;
_dropbear_log = cli_dropbear_log;
@@ -72,16 +73,11 @@ int main(int argc, char ** argv) {
} else
#endif
{
int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
0, &error);
sock_in = sock_out = sock;
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport, cli_connected, &ses);
sock_in = sock_out = -1;
}
if (sock_in < 0) {
dropbear_exit("%s", error);
}
cli_session(sock_in, sock_out);
cli_session(sock_in, sock_out, progress);
/* not reached */
return -1;
@@ -91,6 +87,7 @@ int main(int argc, char ** argv) {
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
char fmtbuf[300];
char exitmsg[500];
if (!sessinitdone) {
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
@@ -102,12 +99,15 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
cli_opts.remoteport, format);
}
/* Arguments to the exit printout may be unsafe to use after session_cleanup() */
vsnprintf(exitmsg, sizeof(exitmsg), fmtbuf, param);
/* Do the cleanup first, since then the terminal will be reset */
session_cleanup();
/* Avoid printing onwards from terminal cruft */
fprintf(stderr, "\n");
_dropbear_log(LOG_INFO, fmtbuf, param);
dropbear_log(LOG_INFO, "%s", exitmsg);;
exit(exitcode);
}

View File

@@ -105,25 +105,30 @@ static void printhelp() {
void cli_getopts(int argc, char ** argv) {
unsigned int i, j;
char ** next = 0;
unsigned int cmdlen;
enum {
#ifdef ENABLE_CLI_PUBKEY_AUTH
int nextiskey = 0; /* A flag if the next argument is a keyfile */
OPT_AUTHKEY,
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
int nextislocal = 0;
OPT_LOCALTCPFWD,
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
int nextisremote = 0;
OPT_REMOTETCPFWD,
#endif
#ifdef ENABLE_CLI_NETCAT
int nextisnetcat = 0;
OPT_NETCAT,
#endif
/* a flag (no arg) if 'next' is NULL, a string-valued option otherwise */
OPT_OTHER
} opt;
unsigned int cmdlen;
char* dummy = NULL; /* Not used for anything real */
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char *host_arg = NULL;
char c;
/* see printhelp() for options */
cli_opts.progname = argv[0];
@@ -172,54 +177,23 @@ void cli_getopts(int argc, char ** argv) {
fill_own_user();
/* Iterate all the arguments */
for (i = 1; i < (unsigned int)argc; i++) {
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (nextiskey) {
/* Load a hostkey since the previous argument was "-i" */
loadidentityfile(argv[i], 1);
nextiskey = 0;
continue;
}
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
if (nextisremote) {
TRACE(("nextisremote true"))
addforward(argv[i], cli_opts.remotefwds);
nextisremote = 0;
continue;
}
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
if (nextislocal) {
TRACE(("nextislocal true"))
addforward(argv[i], cli_opts.localfwds);
nextislocal = 0;
continue;
}
#endif
#ifdef ENABLE_CLI_NETCAT
if (nextisnetcat) {
TRACE(("nextisnetcat true"))
add_netcat(argv[i]);
nextisnetcat = 0;
continue;
}
#endif
if (next) {
/* The previous flag set a value to assign */
*next = argv[i];
if (*next == NULL) {
dropbear_exit("Invalid null argument");
/* Handle non-flag arguments such as hostname or commands for the remote host */
if (argv[i][0] != '-')
{
if (host_arg == NULL) {
host_arg = argv[i];
continue;
}
next = NULL;
continue;
/* Commands to pass to the remote host. No more flag handling,
commands are consumed below */
break;
}
if (argv[i][0] == '-') {
/* A flag *waves* */
switch (argv[i][1]) {
/* Begins with '-' */
opt = OPT_OTHER;
for (j = 1; (c = argv[i][j]) != '\0' && !next && opt == OPT_OTHER; j++) {
switch (c) {
case 'y': /* always accept the remote hostkey */
if (cli_opts.always_accept_key) {
/* twice means no checking at all */
@@ -232,12 +206,7 @@ void cli_getopts(int argc, char ** argv) {
break;
#ifdef ENABLE_CLI_PUBKEY_AUTH
case 'i': /* an identityfile */
/* Keep scp happy when it changes "-i file" to "-ifile" */
if (strlen(argv[i]) > 2) {
loadidentityfile(&argv[i][2], 1);
} else {
nextiskey = 1;
}
opt = OPT_AUTHKEY;
break;
#endif
case 't': /* we want a pty */
@@ -257,7 +226,7 @@ void cli_getopts(int argc, char ** argv) {
break;
#ifdef ENABLE_CLI_LOCALTCPFWD
case 'L':
nextislocal = 1;
opt = OPT_LOCALTCPFWD;
break;
case 'g':
opts.listen_fwd_all = 1;
@@ -265,12 +234,12 @@ void cli_getopts(int argc, char ** argv) {
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
case 'R':
nextisremote = 1;
opt = OPT_REMOTETCPFWD;
break;
#endif
#ifdef ENABLE_CLI_NETCAT
case 'B':
nextisnetcat = 1;
opt = OPT_NETCAT;
break;
#endif
#ifdef ENABLE_CLI_PROXYCMD
@@ -336,50 +305,85 @@ void cli_getopts(int argc, char ** argv) {
case 'b':
next = &dummy;
default:
fprintf(stderr,
"WARNING: Ignoring unknown argument '%s'\n", argv[i]);
fprintf(stderr,
"WARNING: Ignoring unknown option -%c\n", c);
break;
} /* Switch */
/* Now we handle args where they might be "-luser" (no spaces)*/
if (next && strlen(argv[i]) > 2) {
*next = &argv[i][2];
next = NULL;
}
continue; /* next argument */
} else {
TRACE(("non-flag arg: '%s'", argv[i]))
/* Either the hostname or commands */
if (host_arg == NULL) {
host_arg = argv[i];
} else {
/* this is part of the commands to send - after this we
* don't parse any more options, and flags are sent as the
* command */
cmdlen = 0;
for (j = i; j < (unsigned int)argc; j++) {
cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
}
/* Allocate the space */
cli_opts.cmd = (char*)m_malloc(cmdlen);
cli_opts.cmd[0] = '\0';
/* Append all the bits */
for (j = i; j < (unsigned int)argc; j++) {
strlcat(cli_opts.cmd, argv[j], cmdlen);
strlcat(cli_opts.cmd, " ", cmdlen);
}
/* It'll be null-terminated here */
/* We've eaten all the options and flags */
break;
}
}
if (!next && opt == OPT_OTHER) /* got a flag */
continue;
if (c == '\0') {
i++;
j = 0;
if (!argv[i])
dropbear_exit("Missing argument");
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (opt == OPT_AUTHKEY) {
TRACE(("opt authkey"))
loadidentityfile(&argv[i][j], 1);
}
else
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
if (opt == OPT_REMOTETCPFWD) {
TRACE(("opt remotetcpfwd"))
addforward(&argv[i][j], cli_opts.remotefwds);
}
else
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
if (opt == OPT_LOCALTCPFWD) {
TRACE(("opt localtcpfwd"))
addforward(&argv[i][j], cli_opts.localfwds);
}
else
#endif
#ifdef ENABLE_CLI_NETCAT
if (opt == OPT_NETCAT) {
TRACE(("opt netcat"))
add_netcat(&argv[i][j]);
}
else
#endif
if (next) {
/* The previous flag set a value to assign */
*next = &argv[i][j];
if (*next == NULL)
dropbear_exit("Invalid null argument");
next = NULL;
}
}
/* Done with options/flags; now handle the hostname (which may not
* start with a hyphen) and optional command */
if (host_arg == NULL) { /* missing hostname */
printhelp();
exit(EXIT_FAILURE);
}
TRACE(("host is: %s", host_arg))
if (i < (unsigned int)argc) {
/* Build the command to send */
cmdlen = 0;
for (j = i; j < (unsigned int)argc; j++)
cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
/* Allocate the space */
cli_opts.cmd = (char*)m_malloc(cmdlen);
cli_opts.cmd[0] = '\0';
/* Append all the bits */
for (j = i; j < (unsigned int)argc; j++) {
strlcat(cli_opts.cmd, argv[j], cmdlen);
strlcat(cli_opts.cmd, " ", cmdlen);
}
/* It'll be null-terminated here */
TRACE(("cmd is: %s", cli_opts.cmd))
}
/* And now a few sanity checks and setup */
@@ -388,11 +392,6 @@ void cli_getopts(int argc, char ** argv) {
parse_ciphers_macs();
#endif
if (host_arg == NULL) {
printhelp();
exit(EXIT_FAILURE);
}
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
/* To match the common path of m_freeing it */
@@ -447,9 +446,9 @@ void cli_getopts(int argc, char ** argv) {
}
#endif
#ifdef DROPBEAR_DEFAULT_CLI_AUTHKEY
#if defined(DROPBEAR_DEFAULT_CLI_AUTHKEY) && defined(ENABLE_CLI_PUBKEY_AUTH)
{
char *expand_path = expand_tilde(DROPBEAR_DEFAULT_CLI_AUTHKEY);
char *expand_path = expand_homedir_path(DROPBEAR_DEFAULT_CLI_AUTHKEY);
loadidentityfile(expand_path, 0);
m_free(expand_path);
}
@@ -498,11 +497,14 @@ multihop_passthrough_args() {
m_list_elem *iter;
/* Fill out -i, -y, -W options that make sense for all
* the intermediate processes */
#ifdef ENABLE_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
len += 3 + strlen(key->filename);
}
#endif /* ENABLE_CLI_PUBKEY_AUTH */
len += 30; /* space for -W <size>, terminator. */
ret = m_malloc(len);
total = 0;
@@ -524,6 +526,7 @@ multihop_passthrough_args() {
total += written;
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
@@ -532,6 +535,7 @@ multihop_passthrough_args() {
dropbear_assert((unsigned int)written < size);
total += written;
}
#endif /* ENABLE_CLI_PUBKEY_AUTH */
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
if (total > 0)

View File

@@ -37,11 +37,12 @@
#include "chansession.h"
#include "agentfwd.h"
#include "crypto_desc.h"
#include "netio.h"
static void cli_remoteclosed();
static void cli_remoteclosed() ATTRIB_NORETURN;
static void cli_sessionloop();
static void cli_session_init();
static void cli_finished();
static void cli_finished() ATTRIB_NORETURN;
static void recv_msg_service_accept(void);
static void cli_session_cleanup(void);
static void recv_msg_global_request_cli(void);
@@ -93,21 +94,38 @@ static const struct ChanType *cli_chantypes[] = {
NULL /* Null termination */
};
void cli_session(int sock_in, int sock_out) {
void cli_connected(int result, int sock, void* userdata, const char *errstring)
{
struct sshsession *myses = userdata;
if (result == DROPBEAR_FAILURE) {
dropbear_exit("Connect failed: %s", errstring);
}
myses->sock_in = myses->sock_out = sock;
update_channel_prio();
}
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress) {
common_session_init(sock_in, sock_out);
if (progress) {
connect_set_writequeue(progress, &ses.writequeue);
}
chaninitialise(cli_chantypes);
/* Set up cli_ses vars */
cli_session_init();
/* Ready to go */
sessinitdone = 1;
/* Exchange identification */
send_session_identification();
kexfirstinitialise(); /* initialise the kex state */
send_msg_kexinit();
session_loop(cli_sessionloop);
@@ -356,10 +374,10 @@ static void cli_remoteclosed() {
/* Operates in-place turning dirty (untrusted potentially containing control
* characters) text into clean text.
* Note: this is safe only with ascii - other charsets could have problems. */
void cleantext(unsigned char* dirtytext) {
void cleantext(char* dirtytext) {
unsigned int i, j;
unsigned char c;
char c;
j = 0;
for (i = 0; dirtytext[i] != '\0'; i++) {

View File

@@ -30,6 +30,7 @@
#include "runopts.h"
#include "session.h"
#include "ssh.h"
#include "netio.h"
#ifdef ENABLE_CLI_REMOTETCPFWD
static int newtcpforwarded(struct Channel * channel);
@@ -215,7 +216,6 @@ static int newtcpforwarded(struct Channel * channel) {
m_list_elem * iter = NULL;
struct TCPFwdEntry *fwd;
char portstring[NI_MAXSERV];
int sock;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
origaddr = buf_getstring(ses.payload, NULL);
@@ -254,19 +254,7 @@ static int newtcpforwarded(struct Channel * channel) {
}
snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
sock = connect_remote(fwd->connectaddr, portstring, 1, NULL);
if (sock < 0) {
TRACE(("leave newtcpdirect: sock failed"))
err = SSH_OPEN_CONNECT_FAILED;
goto out;
}
ses.maxfd = MAX(ses.maxfd, sock);
/* We don't set readfd, that will get set after the connection's
* progress succeeds */
channel->writefd = sock;
channel->initconn = 1;
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel);
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;

View File

@@ -87,7 +87,7 @@ const struct dropbear_cipher dropbear_nocipher =
#ifdef DROPBEAR_ENABLE_CBC_MODE
const struct dropbear_cipher_mode dropbear_mode_cbc =
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
#endif // DROPBEAR_ENABLE_CBC_MODE
#endif /* DROPBEAR_ENABLE_CBC_MODE */
const struct dropbear_cipher_mode dropbear_mode_none =
{void_start, void_cipher, void_cipher};
@@ -102,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
}
const struct dropbear_cipher_mode dropbear_mode_ctr =
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
#endif // DROPBEAR_ENABLE_CTR_MODE
#endif /* DROPBEAR_ENABLE_CTR_MODE */
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
{&hash_desc, keysize, hashsize} */
@@ -144,6 +144,15 @@ algo_type sshciphers[] = {
#ifdef DROPBEAR_AES256
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_TWOFISH_CTR
/* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
#ifdef DROPBEAR_TWOFISH256
{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_TWOFISH128
{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
#endif
#endif /* DROPBEAR_TWOFISH_CTR */
#endif /* DROPBEAR_ENABLE_CTR_MODE */
#ifdef DROPBEAR_ENABLE_CBC_MODE
@@ -177,18 +186,18 @@ algo_type sshciphers[] = {
};
algo_type sshhashes[] = {
#ifdef DROPBEAR_SHA2_256_HMAC
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
#endif
#ifdef DROPBEAR_SHA1_96_HMAC
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
#endif
#ifdef DROPBEAR_SHA1_HMAC
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
#endif
#ifdef DROPBEAR_SHA2_256_HMAC
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
#endif
#ifdef DROPBEAR_MD5_HMAC
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
#endif
@@ -316,10 +325,10 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
buf_putbyte(algolist, ',');
donefirst = 1;
len = strlen(localalgos[i].name);
buf_putbytes(algolist, localalgos[i].name, len);
buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
}
}
buf_putstring(buf, algolist->data, algolist->len);
buf_putstring(buf, (const char*)algolist->data, algolist->len);
buf_free(algolist);
}
@@ -332,12 +341,12 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
enum kexguess2_used *kexguess2, int *goodguess)
{
unsigned char * algolist = NULL;
const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
char * algolist = NULL;
const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
unsigned int len;
unsigned int remotecount, localcount, clicount, servcount, i, j;
algo_type * ret = NULL;
const unsigned char **clinames, **servnames;
const char **clinames, **servnames;
if (goodguess) {
*goodguess = 0;
@@ -482,7 +491,7 @@ algolist_string(algo_type algos[])
buf_setpos(b, b->len);
buf_putbyte(b, '\0');
buf_setpos(b, 4);
ret_list = m_strdup(buf_getptr(b, b->len - b->pos));
ret_list = m_strdup((const char *) buf_getptr(b, b->len - b->pos));
buf_free(b);
return ret_list;
}

View File

@@ -35,20 +35,21 @@
#include "ssh.h"
#include "listener.h"
#include "runopts.h"
#include "netio.h"
static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
const unsigned char *text, const unsigned char *lang);
const char *text, const char *lang);
static void send_msg_channel_open_confirmation(struct Channel* channel,
unsigned int recvwindow,
unsigned int recvmaxpacket);
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf);
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *moredata, unsigned int *morelen);
static void send_msg_channel_window_adjust(struct Channel *channel,
unsigned int incr);
static void send_msg_channel_data(struct Channel *channel, int isextended);
static void send_msg_channel_eof(struct Channel *channel);
static void send_msg_channel_close(struct Channel *channel);
static void remove_channel(struct Channel *channel);
static void check_in_progress(struct Channel *channel);
static unsigned int write_pending(struct Channel * channel);
static void check_close(struct Channel *channel);
static void close_chan_fd(struct Channel *channel, int fd, int how);
@@ -99,15 +100,6 @@ void chancleanup() {
TRACE(("leave chancleanup"))
}
static void
chan_initwritebuf(struct Channel *channel)
{
dropbear_assert(channel->writebuf->size == 0 && channel->recvwindow == 0);
cbuf_free(channel->writebuf);
channel->writebuf = cbuf_new(opts.recv_window);
channel->recvwindow = opts.recv_window;
}
/* Create a new channel entry, send a reply confirm or failure */
/* If remotechan, transwindow and transmaxpacket are not know (for a new
* outgoing connection, with them to be filled on confirmation), they should
@@ -163,12 +155,11 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->writefd = FD_UNINIT;
newchan->readfd = FD_UNINIT;
newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
newchan->initconn = 0;
newchan->await_open = 0;
newchan->flushing = 0;
newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */
newchan->recvwindow = 0;
newchan->writebuf = cbuf_new(opts.recv_window);
newchan->recvwindow = opts.recv_window;
newchan->extrabuf = NULL; /* The user code can set it up */
newchan->recvdonelen = 0;
@@ -242,27 +233,20 @@ void channelio(fd_set *readfds, fd_set *writefds) {
/* write to program/pipe stdin */
if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
if (channel->initconn) {
/* XXX should this go somewhere cleaner? */
check_in_progress(channel);
continue; /* Important not to use the channel after
check_in_progress(), as it may be NULL */
}
writechannel(channel, channel->writefd, channel->writebuf);
writechannel(channel, channel->writefd, channel->writebuf, NULL, NULL);
do_check_close = 1;
}
/* stderr for client mode */
if (ERRFD_IS_WRITE(channel)
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
writechannel(channel, channel->errfd, channel->extrabuf);
writechannel(channel, channel->errfd, channel->extrabuf, NULL, NULL);
do_check_close = 1;
}
if (ses.channel_signal_pending) {
/* SIGCHLD can change channel state for server sessions */
do_check_close = 1;
ses.channel_signal_pending = 0;
}
/* handle any channel closing etc */
@@ -271,6 +255,8 @@ void channelio(fd_set *readfds, fd_set *writefds) {
}
}
ses.channel_signal_pending = 0;
#ifdef USING_LISTENERS
handle_listeners(readfds);
#endif
@@ -374,27 +360,26 @@ static void check_close(struct Channel *channel) {
* if so, set up the channel properly. Otherwise, the channel is cleaned up, so
* it is important that the channel reference isn't used after a call to this
* function */
static void check_in_progress(struct Channel *channel) {
void channel_connect_done(int result, int sock, void* user_data, const char* UNUSED(errstring)) {
int val;
socklen_t vallen = sizeof(val);
struct Channel *channel = user_data;
TRACE(("enter check_in_progress"))
TRACE(("enter channel_connect_done"))
if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen)
|| val != 0) {
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, "", "");
close(channel->writefd);
remove_channel(channel);
TRACE(("leave check_in_progress: fail"))
} else {
chan_initwritebuf(channel);
if (result == DROPBEAR_SUCCESS)
{
channel->readfd = channel->writefd = sock;
channel->conn_pending = NULL;
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
channel->readfd = channel->writefd;
channel->initconn = 0;
TRACE(("leave check_in_progress: success"))
TRACE(("leave channel_connect_done: success"))
}
else
{
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, "", "");
remove_channel(channel);
TRACE(("leave check_in_progress: fail"))
}
}
@@ -402,7 +387,7 @@ static void check_in_progress(struct Channel *channel) {
/* Send the close message and set the channel as closed */
static void send_msg_channel_close(struct Channel *channel) {
TRACE(("enter send_msg_channel_close %p", channel))
TRACE(("enter send_msg_channel_close %p", (void*)channel))
if (channel->type->closehandler
&& !channel->close_handler_done) {
channel->type->closehandler(channel);
@@ -440,35 +425,119 @@ static void send_msg_channel_eof(struct Channel *channel) {
TRACE(("leave send_msg_channel_eof"))
}
/* Called to write data out to the local side of the channel.
* Only called when we know we can write to a channel, writes as much as
* possible */
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
#ifndef HAVE_WRITEV
static int writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *UNUSED(moredata), unsigned int *morelen) {
int len, maxlen;
unsigned char *circ_p1, *circ_p2;
unsigned int circ_len1, circ_len2;
ssize_t written;
TRACE(("enter writechannel fd %d", fd))
maxlen = cbuf_readlen(cbuf);
/* Write the data out */
len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
if (len <= 0) {
TRACE(("errno %d len %d", errno, len))
if (len < 0 && errno != EINTR) {
close_chan_fd(channel, fd, SHUT_WR);
}
TRACE(("leave writechannel: len <= 0"))
return;
if (morelen) {
/* fallback doesn't consume moredata */
*morelen = 0;
}
TRACE(("writechannel wrote %d", len))
cbuf_incrread(cbuf, len);
channel->recvdonelen += len;
/* Write the first portion of the circular buffer */
cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
written = write(fd, circ_p1, circ_len1);
if (written < 0) {
if (errno != EINTR && errno != EAGAIN) {
TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
close_chan_fd(channel, fd, SHUT_WR);
return DROPBEAR_FAILURE;
}
}
cbuf_incrread(cbuf, written);
channel->recvdonelen += written;
return DROPBEAR_SUCCESS;
}
#endif /* !HAVE_WRITEV */
#ifdef HAVE_WRITEV
static int writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *moredata, unsigned int *morelen) {
struct iovec iov[3];
unsigned char *circ_p1, *circ_p2;
unsigned int circ_len1, circ_len2;
int io_count = 0;
int cbuf_written;
ssize_t written;
cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
if (circ_len1 > 0) {
TRACE(("circ1 %d", circ_len1))
iov[io_count].iov_base = circ_p1;
iov[io_count].iov_len = circ_len1;
io_count++;
}
if (circ_len2 > 0) {
TRACE(("circ2 %d", circ_len2))
iov[io_count].iov_base = circ_p2;
iov[io_count].iov_len = circ_len2;
io_count++;
}
if (morelen) {
assert(moredata);
TRACE(("more %d", *morelen))
iov[io_count].iov_base = (void*)moredata;
iov[io_count].iov_len = *morelen;
io_count++;
}
if (io_count == 0) {
/* writechannel may sometimes be called twice in a main loop iteration.
From common_recv_msg_channel_data() then channelio().
The second call may not have any data to write, so we just return. */
TRACE(("leave writechannel, no data"))
return DROPBEAR_SUCCESS;
}
if (morelen) {
/* Default return value, none consumed */
*morelen = 0;
}
written = writev(fd, iov, io_count);
if (written < 0) {
if (errno != EINTR && errno != EAGAIN) {
TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
close_chan_fd(channel, fd, SHUT_WR);
return DROPBEAR_FAILURE;
}
}
cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written);
cbuf_incrread(cbuf, cbuf_written);
if (morelen) {
*morelen = written - cbuf_written;
}
channel->recvdonelen += written;
return DROPBEAR_SUCCESS;
}
#endif /* HAVE_WRITEV */
/* Called to write data out to the local side of the channel.
Writes the circular buffer contents and also the "moredata" buffer
if not null. Will ignore EAGAIN.
Returns DROPBEAR_FAILURE if writing to fd had an error and the channel is being closed, DROPBEAR_SUCCESS otherwise */
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *moredata, unsigned int *morelen) {
int ret = DROPBEAR_SUCCESS;
TRACE(("enter writechannel fd %d", fd))
#ifdef HAVE_WRITEV
ret = writechannel_writev(channel, fd, cbuf, moredata, morelen);
#else
ret = writechannel_fallback(channel, fd, cbuf, moredata, morelen);
#endif
/* Window adjust handling */
if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
/* Set it back to max window */
send_msg_channel_window_adjust(channel, channel->recvdonelen);
channel->recvwindow += channel->recvdonelen;
channel->recvdonelen = 0;
@@ -480,11 +549,13 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
channel->recvwindow <= cbuf_getavail(channel->extrabuf));
TRACE(("leave writechannel"))
return ret;
}
/* Set the file descriptors for the main select in session.c
* This avoid channels which don't have any window available, are closed, etc*/
void setchannelfds(fd_set *readfds, fd_set *writefds) {
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads) {
unsigned int i;
struct Channel * channel;
@@ -502,7 +573,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
FD if there's the possibility of "~."" to kill an
interactive session (the read_mangler) */
if (channel->transwindow > 0
&& (ses.dataallowed || channel->read_mangler)) {
&& ((ses.dataallowed && allow_reads) || channel->read_mangler)) {
if (channel->readfd >= 0) {
FD_SET(channel->readfd, readfds);
@@ -514,8 +585,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
}
/* Stuff from the wire */
if (channel->initconn
||(channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0)) {
if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
FD_SET(channel->writefd, writefds);
}
@@ -586,11 +656,11 @@ static void remove_channel(struct Channel * channel) {
/* close the FDs in case they haven't been done
* yet (they might have been shutdown etc) */
TRACE(("CLOSE writefd %d", channel->writefd))
close(channel->writefd);
m_close(channel->writefd);
TRACE(("CLOSE readfd %d", channel->readfd))
close(channel->readfd);
m_close(channel->readfd);
TRACE(("CLOSE errfd %d", channel->errfd))
close(channel->errfd);
m_close(channel->errfd);
}
if (!channel->close_handler_done
@@ -599,6 +669,10 @@ static void remove_channel(struct Channel * channel) {
channel->close_handler_done = 1;
}
if (channel->conn_pending) {
cancel_connect(channel->conn_pending);
}
ses.channels[channel->index] = NULL;
m_free(channel);
ses.chancount--;
@@ -616,7 +690,7 @@ void recv_msg_channel_request() {
channel = getchannel();
TRACE(("enter recv_msg_channel_request %p", channel))
TRACE(("enter recv_msg_channel_request %p", (void*)channel))
if (channel->sent_close) {
TRACE(("leave recv_msg_channel_request: already closed channel"))
@@ -749,6 +823,8 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
unsigned int maxdata;
unsigned int buflen;
unsigned int len;
unsigned int consumed;
int res;
TRACE(("enter recv_msg_channel_data"))
@@ -775,25 +851,36 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
dropbear_exit("Oversized packet");
}
/* We may have to run throught twice, if the buffer wraps around. Can't
* just "leave it for next time" like with writechannel, since this
* is payload data */
len = datalen;
while (len > 0) {
buflen = cbuf_writelen(cbuf);
buflen = MIN(buflen, len);
memcpy(cbuf_writeptr(cbuf, buflen),
buf_getptr(ses.payload, buflen), buflen);
cbuf_incrwrite(cbuf, buflen);
buf_incrpos(ses.payload, buflen);
len -= buflen;
}
dropbear_assert(channel->recvwindow >= datalen);
channel->recvwindow -= datalen;
dropbear_assert(channel->recvwindow <= opts.recv_window);
/* Attempt to write the data immediately without having to put it in the circular buffer */
consumed = datalen;
res = writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed);
datalen -= consumed;
buf_incrpos(ses.payload, consumed);
/* We may have to run throught twice, if the buffer wraps around. Can't
* just "leave it for next time" like with writechannel, since this
* is payload data.
* If the writechannel() failed then remaining data is discarded */
if (res == DROPBEAR_SUCCESS) {
len = datalen;
while (len > 0) {
buflen = cbuf_writelen(cbuf);
buflen = MIN(buflen, len);
memcpy(cbuf_writeptr(cbuf, buflen),
buf_getptr(ses.payload, buflen), buflen);
cbuf_incrwrite(cbuf, buflen);
buf_incrpos(ses.payload, buflen);
len -= buflen;
}
}
TRACE(("leave recv_msg_channel_data"))
}
@@ -834,7 +921,7 @@ static void send_msg_channel_window_adjust(struct Channel* channel,
/* Handle a new channel request, performing any channel-type-specific setup */
void recv_msg_channel_open() {
unsigned char *type;
char *type;
unsigned int typelen;
unsigned int remotechan, transwindow, transmaxpacket;
struct Channel *channel;
@@ -883,6 +970,7 @@ void recv_msg_channel_open() {
if (channel == NULL) {
TRACE(("newchannel returned NULL"))
errtype = SSH_OPEN_RESOURCE_SHORTAGE;
goto failure;
}
@@ -904,8 +992,6 @@ void recv_msg_channel_open() {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
chan_initwritebuf(channel);
/* success */
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
@@ -952,7 +1038,7 @@ void send_msg_channel_success(struct Channel *channel) {
/* Send a channel open failure message, with a corresponding reason
* code (usually resource shortage or unknown chan type) */
static void send_msg_channel_open_failure(unsigned int remotechan,
int reason, const unsigned char *text, const unsigned char *lang) {
int reason, const char *text, const char *lang) {
TRACE(("enter send_msg_channel_open_failure"))
CHECKCLEARTOWRITE();
@@ -960,8 +1046,8 @@ static void send_msg_channel_open_failure(unsigned int remotechan,
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
buf_putint(ses.writepayload, remotechan);
buf_putint(ses.writepayload, reason);
buf_putstring(ses.writepayload, text, strlen((char*)text));
buf_putstring(ses.writepayload, lang, strlen((char*)lang));
buf_putstring(ses.writepayload, text, strlen(text));
buf_putstring(ses.writepayload, lang, strlen(lang));
encrypt_packet();
TRACE(("leave send_msg_channel_open_failure"))
@@ -1001,7 +1087,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
}
} else {
TRACE(("CLOSE some fd %d", fd))
close(fd);
m_close(fd);
closein = closeout = 1;
}
@@ -1024,7 +1110,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
if (channel->type->sepfds && channel->readfd == FD_CLOSED
&& channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
TRACE(("CLOSE (finally) of %d", fd))
close(fd);
m_close(fd);
}
}
@@ -1048,7 +1134,6 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
/* Outbound opened channels don't make use of in-progress connections,
* we can set it up straight away */
chan_initwritebuf(chan);
/* set fd non-blocking */
setnonblocking(fd);
@@ -1141,15 +1226,15 @@ void send_msg_request_failure() {
}
struct Channel* get_any_ready_channel() {
size_t i;
if (ses.chancount == 0) {
return NULL;
}
size_t i;
for (i = 0; i < ses.chansize; i++) {
struct Channel *chan = ses.channels[i];
if (chan
&& !(chan->sent_eof || chan->recv_eof)
&& !(chan->await_open || chan->initconn)) {
&& !(chan->await_open)) {
return chan;
}
}
@@ -1157,7 +1242,7 @@ struct Channel* get_any_ready_channel() {
}
void start_send_channel_request(struct Channel *channel,
unsigned char *type) {
char *type) {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);

View File

@@ -511,7 +511,7 @@ void recv_msg_kexinit() {
/* start the kex hash */
local_ident_len = strlen(LOCAL_IDENT);
remote_ident_len = strlen((char*)ses.remoteident);
remote_ident_len = strlen(ses.remoteident);
kexhashbuf_len = local_ident_len + remote_ident_len
+ ses.transkexinit->len + ses.payload->len
@@ -525,17 +525,18 @@ void recv_msg_kexinit() {
read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
(unsigned char*)LOCAL_IDENT, local_ident_len);
buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf,
ses.transkexinit->data, ses.transkexinit->len);
(const char*)ses.transkexinit->data, ses.transkexinit->len);
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0);
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
buf_setpos(ses.payload, ses.payload_beginning);
buf_putstring(ses.kexhashbuf,
(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
ses.payload->len-ses.payload->pos);
ses.requirenext = SSH_MSG_KEXDH_REPLY;
} else {
/* SERVER */
@@ -545,16 +546,17 @@ void recv_msg_kexinit() {
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
(unsigned char*)LOCAL_IDENT, local_ident_len);
buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0);
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
buf_setpos(ses.payload, ses.payload_beginning);
buf_putstring(ses.kexhashbuf,
(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
ses.payload->len-ses.payload->pos);
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf,
ses.transkexinit->data, ses.transkexinit->len);
(const char*)ses.transkexinit->data, ses.transkexinit->len);
ses.requirenext = SSH_MSG_KEXDH_INIT;
}
@@ -629,16 +631,20 @@ void free_kexdh_param(struct kex_dh_param *param)
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
sign_key *hostkey) {
mp_int dh_p;
DEF_MP_INT(dh_p);
DEF_MP_INT(dh_p_min1);
mp_int *dh_e = NULL, *dh_f = NULL;
/* read the prime and generator*/
m_mp_init(&dh_p);
m_mp_init_multi(&dh_p, &dh_p_min1, NULL);
load_dh_p(&dh_p);
/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
if (mp_cmp(dh_pub_them, &dh_p) != MP_LT
|| mp_cmp_d(dh_pub_them, 0) != MP_GT) {
if (mp_sub_d(&dh_p, 1, &dh_p_min1) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
/* Check that dh_pub_them (dh_e or dh_f) is in the range [2, p-2] */
if (mp_cmp(dh_pub_them, &dh_p_min1) != MP_LT
|| mp_cmp_d(dh_pub_them, 1) != MP_GT) {
dropbear_exit("Diffie-Hellman error");
}
@@ -649,7 +655,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
}
/* clear no longer needed vars */
mp_clear_multi(&dh_p, NULL);
mp_clear_multi(&dh_p, &dh_p_min1, NULL);
/* From here on, the code needs to work with the _same_ vars on each side,
* not vice-versaing for client/server */
@@ -697,6 +703,9 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
ecc_key *Q_C, *Q_S, *Q_them;
Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve);
if (Q_them == NULL) {
dropbear_exit("ECC error");
}
ses.dh_K = dropbear_ecc_shared_secret(Q_them, &param->key);
@@ -751,6 +760,7 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
unsigned char out[CURVE25519_LEN];
const unsigned char* Q_C = NULL;
const unsigned char* Q_S = NULL;
char zeroes[CURVE25519_LEN] = {0};
if (buf_pub_them->len != CURVE25519_LEN)
{
@@ -758,6 +768,11 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
}
curve25519_donna(out, param->priv, buf_pub_them->data);
if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) {
dropbear_exit("Bad curve25519");
}
m_mp_alloc_init_multi(&ses.dh_K, NULL);
bytes_to_mp(ses.dh_K, out, CURVE25519_LEN);
m_burn(out, sizeof(out));
@@ -775,9 +790,9 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
/* K_S, the host key */
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
/* Q_C, client's ephemeral public key octet string */
buf_putstring(ses.kexhashbuf, Q_C, CURVE25519_LEN);
buf_putstring(ses.kexhashbuf, (const char*)Q_C, CURVE25519_LEN);
/* Q_S, server's ephemeral public key octet string */
buf_putstring(ses.kexhashbuf, Q_S, CURVE25519_LEN);
buf_putstring(ses.kexhashbuf, (const char*)Q_S, CURVE25519_LEN);
/* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K);

View File

@@ -1,7 +1,7 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,6 +34,7 @@
#include "kex.h"
#include "channel.h"
#include "runopts.h"
#include "netio.h"
static void checktimeouts();
static long select_timeout();
@@ -53,17 +54,29 @@ int exitflag = 0; /* GLOBAL */
void common_session_init(int sock_in, int sock_out) {
time_t now;
#ifdef DEBUG_TRACE
debug_start_net();
#endif
TRACE(("enter session_init"))
ses.sock_in = sock_in;
ses.sock_out = sock_out;
ses.maxfd = MAX(sock_in, sock_out);
if (sock_in >= 0) {
setnonblocking(sock_in);
}
if (sock_out >= 0) {
setnonblocking(sock_out);
}
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
/* Sets it to lowdelay */
update_channel_prio();
now = monotonic_now();
ses.connect_time = now;
ses.last_packet_time_keepalive_recv = now;
ses.last_packet_time_idle = now;
ses.last_packet_time_any_sent = 0;
@@ -78,8 +91,6 @@ void common_session_init(int sock_in, int sock_out) {
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
kexfirstinitialise(); /* initialise the kex state */
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
ses.transseq = 0;
@@ -140,6 +151,7 @@ void session_loop(void(*loophandler)()) {
/* main loop, select()s for all sockets in use */
for(;;) {
const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
timeout.tv_sec = select_timeout();
timeout.tv_usec = 0;
@@ -147,21 +159,33 @@ void session_loop(void(*loophandler)()) {
FD_ZERO(&readfd);
dropbear_assert(ses.payload == NULL);
/* during initial setup we flush out the KEXINIT packet before
* attempting to read the remote version string, which might block */
if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
FD_SET(ses.sock_in, &readfd);
}
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
FD_SET(ses.sock_out, &writefd);
}
/* We get woken up when signal handlers write to this pipe.
SIGCHLD in svr-chansession is the only one currently. */
FD_SET(ses.signal_pipe[0], &readfd);
/* set up for channels which can be read/written */
setchannelfds(&readfd, &writefd);
setchannelfds(&readfd, &writefd, writequeue_has_space);
/* Pending connections to test */
set_connect_fds(&writefd);
/* We delay reading from the input socket during initial setup until
after we have written out our initial KEXINIT packet (empty writequeue).
This means our initial packet can be in-flight while we're doing a blocking
read for the remote ident.
We also avoid reading from the socket if the writequeue is full, that avoids
replies backing up */
if (ses.sock_in != -1
&& (ses.remoteident || isempty(&ses.writequeue))
&& writequeue_has_space) {
FD_SET(ses.sock_in, &readfd);
}
/* Ordering is important, this test must occur after any other function
might have queued packets (such as connection handlers) */
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
FD_SET(ses.sock_out, &writefd);
}
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
@@ -210,11 +234,13 @@ void session_loop(void(*loophandler)()) {
process_packet();
}
}
/* if required, flush out any queued reply packets that
were being held up during a KEX */
maybe_flush_reply_queue();
handle_connect_fds(&writefd);
/* process pipes etc for the channels, ses.dataallowed == 0
* during rekeying ) */
channelio(&readfd, &writefd);
@@ -236,6 +262,15 @@ void session_loop(void(*loophandler)()) {
/* Not reached */
}
static void cleanup_buf(buffer **buf) {
if (!*buf) {
return;
}
buf_burn(*buf);
buf_free(*buf);
*buf = NULL;
}
/* clean up a session on exit */
void session_cleanup() {
@@ -247,24 +282,47 @@ void session_cleanup() {
return;
}
/* BEWARE of changing order of functions here. */
/* Must be before extra_session_cleanup() */
chancleanup();
if (ses.extra_session_cleanup) {
ses.extra_session_cleanup();
}
chancleanup();
/* Cleaning up keys must happen after other cleanup
functions which might queue packets */
if (ses.session_id) {
buf_burn(ses.session_id);
buf_free(ses.session_id);
ses.session_id = NULL;
/* After these are freed most functions will fail */
#ifdef DROPBEAR_CLEANUP
/* listeners call cleanup functions, this should occur before
other session state is freed. */
remove_all_listeners();
remove_connect_pending();
while (!isempty(&ses.writequeue)) {
buf_free(dequeue(&ses.writequeue));
}
if (ses.hash) {
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
m_free(ses.remoteident);
m_free(ses.authstate.pw_dir);
m_free(ses.authstate.pw_name);
m_free(ses.authstate.pw_shell);
m_free(ses.authstate.pw_passwd);
m_free(ses.authstate.username);
#endif
cleanup_buf(&ses.session_id);
cleanup_buf(&ses.hash);
cleanup_buf(&ses.payload);
cleanup_buf(&ses.readbuf);
cleanup_buf(&ses.writepayload);
cleanup_buf(&ses.kexhashbuf);
cleanup_buf(&ses.transkexinit);
if (ses.dh_K) {
mp_clear(ses.dh_K);
}
m_free(ses.dh_K);
m_burn(ses.keys, sizeof(struct key_context));
m_free(ses.keys);
@@ -273,10 +331,8 @@ void session_cleanup() {
void send_session_identification() {
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
buf_putbyte(writebuf, 0x0); /* packet type */
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, writebuf);
buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
writebuf_enqueue(writebuf, 0);
}
static void read_session_identification() {
@@ -395,16 +451,16 @@ static int ident_readln(int fd, char* buf, int count) {
}
void ignore_recv_response() {
// Do nothing
/* Do nothing */
TRACE(("Ignored msg_request_response"))
}
static void send_msg_keepalive() {
CHECKCLEARTOWRITE();
time_t old_time_idle = ses.last_packet_time_idle;
struct Channel *chan = get_any_ready_channel();
CHECKCLEARTOWRITE();
if (chan) {
/* Channel requests are preferable, more implementations
handle them than SSH_MSG_GLOBAL_REQUEST */
@@ -434,6 +490,11 @@ static void checktimeouts() {
time_t now;
now = monotonic_now();
if (IS_DROPBEAR_SERVER && ses.connect_time != 0
&& now - ses.connect_time >= AUTH_TIMEOUT) {
dropbear_close("Timeout before auth");
}
/* we can't rekey if we haven't done remote ident exchange yet */
if (ses.remoteident == NULL) {
return;
@@ -474,20 +535,39 @@ static void checktimeouts() {
}
}
static void update_timeout(long limit, long now, long last_event, long * timeout) {
TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
limit, now, last_event, *timeout))
if (last_event > 0 && limit > 0) {
*timeout = MIN(*timeout, last_event+limit-now);
TRACE2(("new timeout %ld", *timeout))
}
}
static long select_timeout() {
/* determine the minimum timeout that might be required, so
as to avoid waking when unneccessary */
long ret = LONG_MAX;
if (KEX_REKEY_TIMEOUT > 0)
ret = MIN(KEX_REKEY_TIMEOUT, ret);
/* AUTH_TIMEOUT is only relevant before authdone */
if (ses.authstate.authdone != 1 && AUTH_TIMEOUT > 0)
ret = MIN(AUTH_TIMEOUT, ret);
if (opts.keepalive_secs > 0)
ret = MIN(opts.keepalive_secs, ret);
if (opts.idle_timeout_secs > 0)
ret = MIN(opts.idle_timeout_secs, ret);
return ret;
long timeout = LONG_MAX;
long now = monotonic_now();
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
if (ses.authstate.authdone != 1 && IS_DROPBEAR_SERVER) {
/* AUTH_TIMEOUT is only relevant before authdone */
update_timeout(AUTH_TIMEOUT, now, ses.connect_time, &timeout);
}
if (ses.authstate.authdone) {
update_timeout(opts.keepalive_secs, now,
MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
&timeout);
}
update_timeout(opts.idle_timeout_secs, now, ses.last_packet_time_idle,
&timeout);
/* clamp negative timeouts to zero - event has already triggered */
return MAX(timeout, 0);
}
const char* get_user_shell() {
@@ -543,6 +623,11 @@ void update_channel_prio() {
TRACE(("update_channel_prio"))
if (ses.sock_out < 0) {
TRACE(("leave update_channel_prio: no socket"))
return;
}
new_prio = DROPBEAR_PRIO_BULK;
for (i = 0; i < ses.chansize; i++) {
struct Channel *channel = ses.channels[i];
@@ -573,7 +658,7 @@ void update_channel_prio() {
}
if (new_prio != ses.socket_prio) {
TRACE(("Dropbear priority transitioning %4.4s -> %4.4s", (char*)&ses.socket_prio, (char*)&new_prio))
TRACE(("Dropbear priority transitioning %d -> %d", ses.socket_prio, new_prio))
set_sock_priority(ses.sock_out, new_prio);
ses.socket_prio = new_prio;
}

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _COMPAT_H_
#define _COMPAT_H_
#ifndef DROPBEAR_COMPAT_H_
#define DROPBEAR_COMPAT_H_
#include "includes.h"
@@ -49,8 +49,8 @@ void setusershell();
void endusershell();
#endif
#ifndef _PATH_DEVNULL
#define _PATH_DEVNULL "/dev/null"
#ifndef DROPBEAR_PATH_DEVNULL
#define DROPBEAR_PATH_DEVNULL "/dev/null"
#endif
#endif /* _COMPAT_H_ */
#endif /* DROPBEAR_COMPAT_H_ */

View File

@@ -82,9 +82,19 @@ AC_CHECK_DECL(__UCLIBC__,
AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.])
],,,)
# Checks for libraries.
AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt")
dnl We test for crypt() specially. On Linux (and others?) it resides in libcrypt
dnl but we don't want link all binaries to -lcrypt, just dropbear server.
dnl OS X doesn't need -lcrypt
AC_CHECK_FUNC(crypt, found_crypt_func=here)
AC_CHECK_LIB(crypt, crypt,
[
CRYPTLIB="-lcrypt"
found_crypt_func=here
])
AC_SUBST(CRYPTLIB)
if test "t$found_crypt_func" == there; then
AC_DEFINE(HAVE_CRYPT, 1, [crypt() function])
fi
# Check if zlib is needed
AC_ARG_WITH(zlib,
@@ -265,7 +275,7 @@ AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage
#include <sys/types.h>
#include <sys/socket.h>
]],
[[ struct sockaddr_storage s; ]])],
[[ if (sizeof(struct sockaddr_storage)) return 0 ]])],
[ ac_cv_have_struct_sockaddr_storage="yes" ],
[ ac_cv_have_struct_sockaddr_storage="no" ]
)
@@ -279,7 +289,7 @@ AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
#include <sys/types.h>
#include <netinet/in.h>
]],
[[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
[[ if (sizeof(struct sockaddr_in6)) return 0 ]])],
[ ac_cv_have_struct_sockaddr_in6="yes" ],
[ ac_cv_have_struct_sockaddr_in6="no" ]
)
@@ -293,7 +303,7 @@ AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
#include <sys/types.h>
#include <netinet/in.h>
]],
[[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
[[ if (sizeof(struct in6_addr)) return 0 ]])],
[ ac_cv_have_struct_in6_addr="yes" ],
[ ac_cv_have_struct_in6_addr="no" ]
)
@@ -308,7 +318,7 @@ AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
#include <sys/socket.h>
#include <netdb.h>
]],
[[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
[[ if (sizeof(struct addrinfo)) return 0 ]])],
[ ac_cv_have_struct_addrinfo="yes" ],
[ ac_cv_have_struct_addrinfo="no" ]
)
@@ -632,7 +642,7 @@ fi
AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
AC_CHECK_FUNCS([dup2 getpass getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
@@ -719,10 +729,21 @@ AC_OUTPUT
AC_MSG_NOTICE()
if test $BUNDLED_LIBTOM = 1 ; then
AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath)
AC_MSG_NOTICE([Using bundled libtomcrypt and libtommath])
else
AC_MSG_NOTICE(Using system libtomcrypt and libtommath)
AC_MSG_NOTICE([Using system libtomcrypt and libtommath])
fi
if test "x$ac_cv_func_getpass" != xyes; then
AC_MSG_NOTICE()
AC_MSG_NOTICE([getpass() not available, dbclient will only have public-key authentication])
fi
if test "t$found_crypt_func" != there; then
AC_MSG_NOTICE()
AC_MSG_NOTICE([crypt() not available, dropbear server will not have password authentication])
fi
AC_MSG_NOTICE()
AC_MSG_NOTICE(Now edit options.h to choose features.)
AC_MSG_NOTICE([Now edit options.h to choose features.])

View File

@@ -1,9 +1,9 @@
#ifndef _CRYPTO_DESC_H
#define _CRYPTO_DESC_H
#ifndef DROPBEAR_CRYPTO_DESC_H
#define DROPBEAR_CRYPTO_DESC_H
void crypto_init();
extern int dropbear_ltc_prng;
#endif /* _CRYPTO_DESC_H */
#endif /* DROPBEAR_CRYPTO_DESC_H */

View File

@@ -527,7 +527,7 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
memcpy(origx, x, 10 * sizeof(limb));
fsum(x, z);
fdifference(z, origx); // does x - z
fdifference(z, origx); /* does x - z */
memcpy(origxprime, xprime, sizeof(limb) * 10);
fsum(xprime, zprime);
@@ -554,7 +554,7 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
fproduct(x2, xx, zz);
freduce_degree(x2);
freduce_coefficients(x2);
fdifference(zz, xx); // does zz = xx - zz
fdifference(zz, xx); /* does zz = xx - zz */
memset(zzz + 10, 0, sizeof(limb) * 9);
fscalar_product(zzz, zz, 121665);
/* No need to call freduce_degree here:
@@ -641,9 +641,9 @@ cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
memcpy(resultz, nqz, sizeof(limb) * 10);
}
// -----------------------------------------------------------------------------
// Shamelessly copied from djb's code
// -----------------------------------------------------------------------------
/* -----------------------------------------------------------------------------
* Shamelessly copied from djb's code
* ----------------------------------------------------------------------------- */
static void
crecip(limb *out, const limb *z) {
limb z2[10];

View File

@@ -3,25 +3,32 @@
dbclient \- lightweight SSH client
.SH SYNOPSIS
.B dbclient
[\-Tt] [\-p
[\fIflag arguments\fR] [\-p
.I port\fR] [\-i
.I id\fR] [\-L
.I l\fR:\fIh\fR:\fIr\fR] [\-R
.I l\fR:\fIh\fR:\fIr\fR] [\-l
.I l\fR:\fIh\fR:\fIp\fR] [\-R
.I l\fR:\fIh\fR:\fIp\fR] [\-l
.IR user ]
.I host
.RI [ \fImore\ flags\fR ]
.RI [ command ]
.B dbclient
[
.I args ]
.I [user1]@host1[^port1],[user2]@host2[^port2],...
[\fIargs\fR]
[\fIuser1\fR]@\fIhost1\fR[^\fIport1\fR],[\fIuser2\fR]@\fIhost2\fR[^\fIport2\fR],...
.SH DESCRIPTION
.B dbclient
is a small SSH client
.SH OPTIONS
.TP
.TP
.B command
A command to run on the remote host. This will normally be run by the remote host
using the user's shell. The command begins at the first hyphen argument after the
host argument. If no command is specified an interactive terminal will be opened
(see -t and -T).
.TP
.B \-p \fIport
Connect to
.I port
@@ -35,7 +42,7 @@ Read the identity key from file
(multiple allowed). This file is created with dropbearkey(1) or converted
from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is used
.TP
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
.B \-L\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Local port forwarding.
Forward the port
.I listenport
@@ -44,7 +51,7 @@ on the local host through the SSH connection to port
on the host
.IR host .
.TP
.B \-R [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
.B \-R\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Remote port forwarding.
Forward the port
.I listenport
@@ -60,10 +67,12 @@ Login as
on the remote host.
.TP
.B \-t
Allocate a PTY.
Allocate a PTY. This is the default when no command is given, it gives a full
interactive remote session. The main effect is that keystrokes are sent remotely
immediately as opposed to local line-based editing.
.TP
.B \-T
Don't allocate a PTY.
Don't allocate a PTY. This is the default a command is given. See -t.
.TP
.B \-N
Don't request a remote shell or run any commands. Any command arguments are ignored.
@@ -129,7 +138,7 @@ Dropbear will also allow multiple "hops" to be specified, separated by commas. I
this case a connection will be made to the first host, then a TCP forwarded
connection will be made through that to the second host, and so on. Hosts other than
the final destination will not see anything other than the encrypted SSH stream.
A port for a host can be specified with a hash (eg matt@martello^44 ).
A port for a host can be specified with a caret (eg matt@martello^44 ).
This syntax can also be used with scp or rsync (specifying dbclient as the
ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg
@@ -157,6 +166,10 @@ SSH_ASKPASS should be set to the path of a program that will return a password
on standard output. This program will only be used if either DISPLAY is set and
standard input is not a TTY, or the environment variable SSH_ASKPASS_ALWAYS is
set.
.SH NOTES
If compiled with zlib support and if the server supports it, dbclient will
always use compression.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br

View File

@@ -141,7 +141,7 @@ out:
return ret;
}
void addrandom(char * buf, unsigned int len)
void addrandom(unsigned char * buf, unsigned int len)
{
hash_state hs;
@@ -306,7 +306,7 @@ void gen_random_mpint(mp_int *max, mp_int *rand) {
/* keep regenerating until we get one satisfying
* 0 < rand < max */
} while (mp_cmp(rand, max) != MP_LT);
} while (!(mp_cmp(rand, max) == MP_LT && mp_cmp_d(rand, 0) == MP_GT));
m_burn(randbuf, len);
m_free(randbuf);
}

View File

@@ -22,14 +22,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _RANDOM_H_
#define _RANDOM_H_
#ifndef DROPBEAR_RANDOM_H_
#define DROPBEAR_RANDOM_H_
#include "includes.h"
void seedrandom();
void genrandom(unsigned char* buf, unsigned int len);
void addrandom(char * buf, unsigned int len);
void addrandom(unsigned char * buf, unsigned int len);
void gen_random_mpint(mp_int *max, mp_int *rand);
#endif /* _RANDOM_H_ */
#endif /* DROPBEAR_RANDOM_H_ */

399
dbutil.c
View File

@@ -150,18 +150,44 @@ void dropbear_log(int priority, const char* format, ...) {
#ifdef DEBUG_TRACE
static double debug_start_time = -1;
void debug_start_net()
{
if (getenv("DROPBEAR_DEBUG_NET_TIMESTAMP"))
{
/* Timestamps start from first network activity */
struct timeval tv;
gettimeofday(&tv, NULL);
debug_start_time = tv.tv_sec + (tv.tv_usec / 1000000.0);
TRACE(("Resetting Dropbear TRACE timestamps"))
}
}
static double time_since_start()
{
double nowf;
struct timeval tv;
gettimeofday(&tv, NULL);
nowf = tv.tv_sec + (tv.tv_usec / 1000000.0);
if (debug_start_time < 0)
{
debug_start_time = nowf;
return 0;
}
return nowf - debug_start_time;
}
void dropbear_trace(const char* format, ...) {
va_list param;
struct timeval tv;
if (!debug_trace) {
return;
}
gettimeofday(&tv, NULL);
va_start(param, format);
fprintf(stderr, "TRACE (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
@@ -170,7 +196,6 @@ void dropbear_trace(const char* format, ...) {
void dropbear_trace2(const char* format, ...) {
static int trace_env = -1;
va_list param;
struct timeval tv;
if (trace_env == -1) {
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
@@ -180,193 +205,14 @@ void dropbear_trace2(const char* format, ...) {
return;
}
gettimeofday(&tv, NULL);
va_start(param, format);
fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
fprintf(stderr, "TRACE2 (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
}
#endif /* DEBUG_TRACE */
void set_sock_nodelay(int sock) {
int val;
/* disable nagle */
val = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
}
void set_sock_priority(int sock, enum dropbear_prio prio) {
int iptos_val = 0, so_prio_val = 0, rc;
/* Don't log ENOTSOCK errors so that this can harmlessly be called
* on a client '-J' proxy pipe */
/* set the TOS bit for either ipv4 or ipv6 */
#ifdef IPTOS_LOWDELAY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
iptos_val = IPTOS_LOWDELAY;
} else if (prio == DROPBEAR_PRIO_BULK) {
iptos_val = IPTOS_THROUGHPUT;
}
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
#endif
#ifdef SO_PRIORITY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
so_prio_val = TC_PRIO_INTERACTIVE;
} else if (prio == DROPBEAR_PRIO_BULK) {
so_prio_val = TC_PRIO_BULK;
}
/* linux specific, sets QoS class. see tc-prio(8) */
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
if (rc < 0 && errno != ENOTSOCK)
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
strerror(errno));
#endif
}
/* Listen on address:port.
* Special cases are address of "" listening on everything,
* and address of NULL listening on localhost only.
* Returns the number of sockets bound on success, or -1 on failure. On
* failure, if errstring wasn't NULL, it'll be a newly malloced error
* string.*/
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
struct addrinfo hints, *res = NULL, *res0 = NULL;
int err;
unsigned int nsock;
struct linger linger;
int val;
int sock;
TRACE(("enter dropbear_listen"))
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
hints.ai_socktype = SOCK_STREAM;
/* for calling getaddrinfo:
address == NULL and !AI_PASSIVE: local loopback
address == NULL and AI_PASSIVE: all interfaces
address != NULL: whatever the address says */
if (!address) {
TRACE(("dropbear_listen: local loopback"))
} else {
if (address[0] == '\0') {
TRACE(("dropbear_listen: all interfaces"))
address = NULL;
}
hints.ai_flags = AI_PASSIVE;
}
err = getaddrinfo(address, port, &hints, &res0);
if (err) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(gai_strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
}
if (res0) {
freeaddrinfo(res0);
res0 = NULL;
}
TRACE(("leave dropbear_listen: failed resolving"))
return -1;
}
nsock = 0;
for (res = res0; res != NULL && nsock < sockcount;
res = res->ai_next) {
/* Get a socket */
socks[nsock] = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
sock = socks[nsock]; /* For clarity */
if (sock < 0) {
err = errno;
TRACE(("socket() failed"))
continue;
}
/* Various useful socket options */
val = 1;
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
linger.l_onoff = 1;
linger.l_linger = 5;
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {
int on = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
&on, sizeof(on)) == -1) {
dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
}
}
#endif
set_sock_nodelay(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
err = errno;
close(sock);
TRACE(("bind(%s) failed", port))
continue;
}
if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
err = errno;
close(sock);
TRACE(("listen() failed"))
continue;
}
*maxfd = MAX(*maxfd, sock);
nsock++;
}
if (res0) {
freeaddrinfo(res0);
res0 = NULL;
}
if (nsock == 0) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error listening: %s", strerror(err));
}
TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
return -1;
}
TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
return nsock;
}
/* Connect to a given unix socket. The socket is blocking */
#ifdef ENABLE_CONNECT_UNIX
int connect_unix(const char* path) {
@@ -390,93 +236,6 @@ int connect_unix(const char* path) {
}
#endif
/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
* return immediately if nonblocking is set. On failure, if errstring
* wasn't null, it will be a newly malloced error message */
/* TODO: maxfd */
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring) {
struct addrinfo *res0 = NULL, *res = NULL, hints;
int sock;
int err;
TRACE(("enter connect_remote"))
if (errstring != NULL) {
*errstring = NULL;
}
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = PF_UNSPEC;
err = getaddrinfo(remotehost, remoteport, &hints, &res0);
if (err) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 100 + strlen(gai_strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error resolving '%s' port '%s'. %s",
remotehost, remoteport, gai_strerror(err));
}
TRACE(("Error resolving: %s", gai_strerror(err)))
return -1;
}
sock = -1;
err = EADDRNOTAVAIL;
for (res = res0; res; res = res->ai_next) {
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock < 0) {
err = errno;
continue;
}
if (nonblocking) {
setnonblocking(sock);
}
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
if (errno == EINPROGRESS && nonblocking) {
TRACE(("Connect in progress"))
break;
} else {
err = errno;
close(sock);
sock = -1;
continue;
}
}
break; /* Success */
}
if (sock < 0 && !(errno == EINPROGRESS && nonblocking)) {
/* Failed */
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error connecting: %s", strerror(err));
}
TRACE(("Error connecting: %s", strerror(err)))
} else {
/* Success */
set_sock_nodelay(sock);
}
freeaddrinfo(res0);
if (sock > 0 && errstring != NULL && *errstring != NULL) {
m_free(*errstring);
}
TRACE(("leave connect_remote: sock %d\n", sock))
return sock;
}
/* Sets up a pipe for a, returning three non-blocking file descriptors
* and the pid. exec_fn is the function that will actually execute the child process,
* it will be run after the child has fork()ed, and is passed exec_data.
@@ -612,88 +371,6 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
execv(usershell, argv);
}
void get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup)
{
struct sockaddr_storage addr;
socklen_t addrlen;
if (local_host || local_port) {
addrlen = sizeof(addr);
if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
dropbear_exit("Failed socket address: %s", strerror(errno));
}
getaddrstring(&addr, local_host, local_port, host_lookup);
}
if (remote_host || remote_port) {
addrlen = sizeof(addr);
if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
dropbear_exit("Failed socket address: %s", strerror(errno));
}
getaddrstring(&addr, remote_host, remote_port, host_lookup);
}
}
/* Return a string representation of the socket address passed. The return
* value is allocated with malloc() */
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port,
int host_lookup) {
char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
unsigned int len;
int ret;
int flags = NI_NUMERICSERV | NI_NUMERICHOST;
#ifndef DO_HOST_LOOKUP
host_lookup = 0;
#endif
if (host_lookup) {
flags = NI_NUMERICSERV;
}
len = sizeof(struct sockaddr_storage);
/* Some platforms such as Solaris 8 require that len is the length
* of the specific structure. Some older linux systems (glibc 2.1.3
* such as debian potato) have sockaddr_storage.__ss_family instead
* but we'll ignore them */
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
if (addr->ss_family == AF_INET) {
len = sizeof(struct sockaddr_in);
}
#ifdef AF_INET6
if (addr->ss_family == AF_INET6) {
len = sizeof(struct sockaddr_in6);
}
#endif
#endif
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
serv, sizeof(serv)-1, flags);
if (ret != 0) {
if (host_lookup) {
/* On some systems (Darwin does it) we get EINTR from getnameinfo
* somehow. Eew. So we'll just return the IP, since that doesn't seem
* to exhibit that behaviour. */
getaddrstring(addr, ret_host, ret_port, 0);
return;
} else {
/* if we can't do a numeric lookup, something's gone terribly wrong */
dropbear_exit("Failed lookup: %s", gai_strerror(ret));
}
}
if (ret_host) {
*ret_host = m_strdup(host);
}
if (ret_port) {
*ret_port = m_strdup(serv);
}
}
#ifdef DEBUG_TRACE
void printhex(const char * label, const unsigned char * buf, int len) {
@@ -827,12 +504,12 @@ out:
/* make sure that the socket closes */
void m_close(int fd) {
int val;
if (fd == -1) {
return;
}
int val;
do {
val = close(fd);
} while (val < 0 && errno == EINTR);
@@ -936,15 +613,16 @@ int m_str_to_uint(const char* str, unsigned int *val) {
}
}
/* Returns malloced path. Only expands ~ in first character */
char * expand_tilde(const char *inpath) {
/* Returns malloced path. inpath beginning with '/' is returned as-is,
otherwise home directory is prepended */
char * expand_homedir_path(const char *inpath) {
struct passwd *pw = NULL;
if (inpath[0] == '~') {
if (inpath[0] != '/') {
pw = getpwuid(getuid());
if (pw && pw->pw_dir) {
int len = strlen(inpath) + strlen(pw->pw_dir) + 1;
int len = strlen(inpath) + strlen(pw->pw_dir) + 2;
char *buf = m_malloc(len);
snprintf(buf, len, "%s/%s", pw->pw_dir, &inpath[1]);
snprintf(buf, len, "%s/%s", pw->pw_dir, inpath);
return buf;
}
}
@@ -1018,3 +696,4 @@ time_t monotonic_now() {
return time(NULL);
}

View File

@@ -22,12 +22,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _DBUTIL_H_
#ifndef DROPBEAR_DBUTIL_H_
#define _DBUTIL_H_
#define DROPBEAR_DBUTIL_H_
#include "includes.h"
#include "buffer.h"
#include "queue.h"
#ifndef DISABLE_SYSLOG
void startsyslog();
@@ -58,32 +59,18 @@ void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
void printhex(const char * label, const unsigned char * buf, int len);
void printmpint(const char *label, mp_int *mp);
void debug_start_net();
extern int debug_trace;
#endif
enum dropbear_prio {
DROPBEAR_PRIO_DEFAULT = 10,
DROPBEAR_PRIO_LOWDELAY = 11,
DROPBEAR_PRIO_BULK = 12,
};
char * stripcontrol(const char * text);
void get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup);
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port, int host_lookup);
void set_sock_nodelay(int sock);
void set_sock_priority(int sock, enum dropbear_prio prio);
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
int *writefd, int *readfd, int *errfd, pid_t *pid);
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
#ifdef ENABLE_CONNECT_UNIX
int connect_unix(const char* addr);
#endif
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring);
int buf_readfile(buffer* buf, const char* filename);
int buf_getline(buffer * line, FILE * authfile);
@@ -91,7 +78,7 @@ void m_close(int fd);
void * m_malloc(size_t size);
void * m_strdup(const char * str);
void * m_realloc(void* ptr, size_t size);
#define m_free(X) do {free(X); (X) = NULL;} while (0);
#define m_free(X) do {free(X); (X) = NULL;} while (0)
void m_burn(void* data, unsigned int len);
void setnonblocking(int fd);
void disallow_core();
@@ -110,6 +97,6 @@ int constant_time_memcmp(const void* a, const void *b, size_t n);
a real-world clock */
time_t monotonic_now();
char * expand_tilde(const char *inpath);
char * expand_homedir_path(const char *inpath);
#endif /* _DBUTIL_H_ */
#endif /* DROPBEAR_DBUTIL_H_ */

18
debian/changelog vendored
View File

@@ -1,3 +1,21 @@
dropbear (2015.70-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 26 Nov 2015 22:52:58 +0800
dropbear (2015.69-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 25 Nov 2015 22:52:58 +0800
dropbear (2015.68-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Sat, 8 Aug 2015 22:52:58 +0800
dropbear (2015.67-0.1) unstable; urgency=low
* New upstream release.

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _DEBUG_H_
#define _DEBUG_H_
#ifndef DROPBEAR_DEBUG_H_
#define DROPBEAR_DEBUG_H_
#include "includes.h"
@@ -39,7 +39,7 @@
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing may not sanitise strings etc. This will add a reasonable
* amount to your executable size. */
/* #define DEBUG_TRACE */
/*#define DEBUG_TRACE*/
/* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're

View File

@@ -3,11 +3,10 @@
dropbear \- lightweight SSH server
.SH SYNOPSIS
.B dropbear
[\-RFEmwsgjki] [\-b
[\fIflag arguments\fR] [\-b
.I banner\fR]
[\-r
.I hostkeyfile\fR] [\-p
.IR [address:]port ]
.I hostkeyfile\fR] [\-p [\fIaddress\fR:]\fIport\fR]
.SH DESCRIPTION
.B dropbear
is a small SSH server
@@ -54,7 +53,7 @@ Disable local port forwarding.
.B \-k
Disable remote port forwarding.
.TP
.B \-p \fI[address:]port
.B \-p\fR [\fIaddress\fR:]\fIport
Listen on specified
.I address
and TCP
@@ -100,7 +99,8 @@ Print the version
.TP
Authorized Keys
~/.ssh/authorized_keys can be set up to allow remote login with a RSA or DSS
~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
ECDSA, or DSS
key. Each line is of the form
.TP
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
@@ -127,7 +127,7 @@ Disable PTY allocation. Note that a user can still obtain most of the
same functionality with other means even if no-pty is set.
.TP
.B command="\fIforced_command\fR"
.B command=\fR"\fIforced_command\fR"
Disregard the command provided by the user and always run \fIforced_command\fR.
The authorized_keys file and its containing ~/.ssh directory must only be
@@ -139,7 +139,7 @@ Host Key Files
Host key files are read at startup from a standard location, by default
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
/etc/dropbear/dropbear-ecdsa_host_key
/etc/dropbear/dropbear_ecdsa_host_key
or specified on the commandline with -r. These are of the form generated
by dropbearkey. The -R option can be used to automatically generate keys
in the default location - keys will be generated after startup when the first

View File

@@ -21,24 +21,24 @@ from a private key by using
.P
Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them
first.
.SH OPTIONS
.SH ARGUMENTS
.TP
.B input type
.I input_type
Either
.I dropbear
or
.I openssh
.TP
.B output type
.I output_type
Either
.I dropbear
or
.I openssh
.TP
.B input file
.I input_file
An existing Dropbear or OpenSSH private key file
.TP
.B output file
.I output_file
The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
.SH EXAMPLE
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear

View File

@@ -9,13 +9,11 @@ dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
.I file
[\-s
.IR bits ]
[\-y]
.SH DESCRIPTION
.B dropbearkey
generates a
.I RSA
.I DSS,
or
.I ECDSA
\fIRSA\fR, \fIDSS\fR, or \fIECDSA\fR
format SSH private key, and saves it to a file for the use with the
Dropbear client or server.
Note that
@@ -33,18 +31,25 @@ or
.TP
.B \-f \fIfile
Write the secret key to the file
.IR file . For client authentication ~/.ssh/id_dropbear is loaded by default
\fIfile\fR. For client authentication ~/.ssh/id_dropbear is loaded by default
.TP
.B \-s \fIbits
Set the key size to
.I bits
bits, should be multiple of 8 (optional).
.TP
.B \-y
Just print the publickey and fingerprint for the private key in \fIfile\fR.
.SH NOTES
The program dropbearconvert(1) can be used to convert between Dropbear and OpenSSH key formats.
.P
Dropbear does not support encrypted keys.
.SH EXAMPLE
generate a host-key:
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
extract a public key suitable for authorized_keys from private key:
# dropbearkey -y -f id_rsa | grep "^ssh-rsa " >> authorized_keys
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br

6
dss.c
View File

@@ -165,7 +165,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
DEF_MP_INT(val3);
DEF_MP_INT(val4);
char * string = NULL;
int stringlen;
unsigned int stringlen;
TRACE(("enter buf_dss_verify"))
dropbear_assert(key != NULL);
@@ -186,7 +186,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
/* create the signature - s' and r' are the received signatures in buf */
/* w = (s')-1 mod q */
/* let val1 = s' */
bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, s' >= q"))
@@ -208,7 +208,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
/* u2 = ((r')w) mod q */
/* let val1 = r' */
bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE);
bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, r' >= q"))
goto out;

6
dss.h
View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _DSS_H_
#define _DSS_H_
#ifndef DROPBEAR_DSS_H_
#define DROPBEAR_DSS_H_
#include "includes.h"
#include "buffer.h"
@@ -53,4 +53,4 @@ void dss_key_free(dropbear_dss_key *key);
#endif /* DROPBEAR_DSS */
#endif /* _DSS_H_ */
#endif /* DROPBEAR_DSS_H_ */

5
ecc.c
View File

@@ -86,11 +86,6 @@ static int ecc_is_point(ecc_key *key)
{
mp_int *prime, *b, *t1, *t2;
int err;
prime = m_malloc(sizeof(mp_int));
b = m_malloc(sizeof(mp_int));
t1 = m_malloc(sizeof(mp_int));
t2 = m_malloc(sizeof(mp_int));
m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);

8
ecc.h
View File

@@ -1,5 +1,5 @@
#ifndef _DROPBEAR_ECC_H
#define _DROPBEAR_ECC_H
#ifndef DROPBEAR_DROPBEAR_ECC_H
#define DROPBEAR_DROPBEAR_ECC_H
#include "includes.h"
#include "options.h"
@@ -12,7 +12,7 @@ struct dropbear_ecc_curve {
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
const ltc_ecc_set_type *dp; /* curve domain parameters */
const struct ltc_hash_descriptor *hash_desc;
const unsigned char *name;
const char *name;
};
extern struct dropbear_ecc_curve ecc_curve_nistp256;
@@ -33,4 +33,4 @@ mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key);
#endif
#endif /* _DROPBEAR_ECC_H */
#endif /* DROPBEAR_DROPBEAR_ECC_H */

14
ecdsa.c
View File

@@ -83,9 +83,9 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
ecc_key *new_key = NULL;
/* string "ecdsa-sha2-[identifier]" */
key_ident = buf_getstring(buf, &key_ident_len);
key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
/* string "[identifier]" */
identifier = buf_getstring(buf, &identifier_len);
identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
TRACE(("Bad identifier lengths"))
@@ -140,10 +140,10 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
struct dropbear_ecc_curve *curve = NULL;
unsigned char key_ident[30];
char key_ident[30];
curve = curve_for_dp(key->dp);
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
buf_putstring(buf, key_ident, strlen(key_ident));
buf_putstring(buf, curve->name, strlen(curve->name));
buf_put_ecc_raw_pubkey_string(buf, key);
@@ -161,7 +161,7 @@ void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
hash_state hs;
unsigned char hash[64];
void *e = NULL, *p = NULL, *s = NULL, *r;
unsigned char key_ident[30];
char key_ident[30];
buffer *sigbuf = NULL;
TRACE(("buf_put_ecdsa_sign"))
@@ -222,7 +222,7 @@ void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
}
}
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
buf_putstring(buf, key_ident, strlen(key_ident));
/* enough for nistp521 */
sigbuf = buf_new(200);
@@ -409,7 +409,7 @@ int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
out:
ltc_ecc_del_point(mG);
ltc_ecc_del_point(mQ);
mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
ltc_deinit_multi(r, s, v, w, u1, u2, p, e, m, NULL);
if (mp != NULL) {
ltc_mp.montgomery_deinit(mp);
}

View File

@@ -1,5 +1,5 @@
#ifndef _ECDSA_H_
#define _ECDSA_H_
#ifndef DROPBEAR_ECDSA_H_
#define DROPBEAR_ECDSA_H_
#include "includes.h"
#include "buffer.h"
@@ -32,4 +32,4 @@ int signkey_is_ecdsa(enum signkey_type type);
#endif
#endif /* _ECDSA_H_ */
#endif /* DROPBEAR_ECDSA_H_ */

View File

@@ -39,8 +39,8 @@
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#ifndef _FAKE_RFC2553_H
#define _FAKE_RFC2553_H
#ifndef DROPBEAR_FAKE_RFC2553_H
#define DROPBEAR_FAKE_RFC2553_H
#include "includes.h"
#include <sys/types.h>

View File

@@ -67,7 +67,7 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
static void getq(dropbear_dss_key *key) {
char buf[QSIZE];
unsigned char buf[QSIZE];
/* 160 bit prime */
genrandom(buf, QSIZE);

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _GENDSS_H_
#define _GENDSS_H_
#ifndef DROPBEAR_GENDSS_H_
#define DROPBEAR_GENDSS_H_
#include "dss.h"
@@ -33,4 +33,4 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size);
#endif /* DROPBEAR_DSS */
#endif /* _GENDSS_H_ */
#endif /* DROPBEAR_GENDSS_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _GENRSA_H_
#define _GENRSA_H_
#ifndef DROPBEAR_GENRSA_H_
#define DROPBEAR_GENRSA_H_
#include "rsa.h"
@@ -33,4 +33,4 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size);
#endif /* DROPBEAR_RSA */
#endif /* _GENRSA_H_ */
#endif /* DROPBEAR_GENRSA_H_ */

View File

@@ -1,5 +1,5 @@
#ifndef _GENSIGNKEY_H
#define _GENSIGNKEY_H
#ifndef DROPBEAR_GENSIGNKEY_H
#define DROPBEAR_GENSIGNKEY_H
#include "signkey.h"

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _INCLUDES_H_
#define _INCLUDES_H_
#ifndef DROPBEAR_INCLUDES_H_
#define DROPBEAR_INCLUDES_H_
#include "config.h"
@@ -177,4 +177,4 @@ typedef u_int32_t uint32_t;
# define UNUSED(x) x
#endif
#endif /* _INCLUDES_H_ */
#endif /* DROPBEAR_INCLUDES_H_ */

6
kex.h
View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _KEX_H_
#define _KEX_H_
#ifndef DROPBEAR_KEX_H_
#define DROPBEAR_KEX_H_
#include "includes.h"
#include "algo.h"
@@ -113,4 +113,4 @@ int curve25519_donna(unsigned char *out, const unsigned char *secret, const unsi
#define MAX_KEXHASHBUF 2000
#endif /* _KEX_H_ */
#endif /* DROPBEAR_KEX_H_ */

View File

@@ -193,7 +193,7 @@ out:
static void base64_encode_fp(FILE * fp, unsigned char *data,
int datalen, int cpl)
{
char out[100];
unsigned char out[100];
int n;
unsigned long outlen;
int rawcpl;
@@ -445,7 +445,7 @@ static struct openssh_key *load_openssh_key(const char *filename)
ret->keyblob_size);
}
outlen = ret->keyblob_size - ret->keyblob_len;
if (base64_decode(buffer, len,
if (base64_decode((const unsigned char *)buffer, len,
ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
errmsg = "Error decoding base64";
goto error;
@@ -464,17 +464,16 @@ static struct openssh_key *load_openssh_key(const char *filename)
goto error;
}
memset(buffer, 0, sizeof(buffer));
m_burn(buffer, sizeof(buffer));
return ret;
error:
memset(buffer, 0, sizeof(buffer));
m_burn(buffer, sizeof(buffer));
if (ret) {
if (ret->keyblob) {
memset(ret->keyblob, 0, ret->keyblob_size);
m_burn(ret->keyblob, ret->keyblob_size);
m_free(ret->keyblob);
}
memset(&ret, 0, sizeof(ret));
m_free(ret);
}
if (fp) {
@@ -494,9 +493,8 @@ static int openssh_encrypted(const char *filename)
if (!key)
return 0;
ret = key->encrypted;
memset(key->keyblob, 0, key->keyblob_size);
m_burn(key->keyblob, key->keyblob_size);
m_free(key->keyblob);
memset(&key, 0, sizeof(key));
m_free(key);
return ret;
}
@@ -509,7 +507,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
int i, num_integers = 0;
sign_key *retval = NULL;
char *errmsg;
char *modptr = NULL;
unsigned char *modptr = NULL;
int modlen = -9999;
enum signkey_type type;
@@ -648,12 +646,12 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
*/
if (i == 1) {
/* Save the details for after we deal with number 2. */
modptr = (char *)p;
modptr = p;
modlen = len;
} else if (i >= 2 && i <= 5) {
buf_putstring(blobbuf, p, len);
buf_putstring(blobbuf, (const char*)p, len);
if (i == 2) {
buf_putstring(blobbuf, modptr, modlen);
buf_putstring(blobbuf, (const char*)modptr, modlen);
}
}
} else if (key->type == OSSH_DSA) {
@@ -661,7 +659,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
* OpenSSH key order is p, q, g, y, x,
* we want the same.
*/
buf_putstring(blobbuf, p, len);
buf_putstring(blobbuf, (const char*)p, len);
}
/* Skip past the number. */
@@ -1045,7 +1043,8 @@ static int openssh_write(const char *filename, sign_key *key,
int curve_oid_len = 0;
const void* curve_oid = NULL;
unsigned long pubkey_size = 2*curve_size+1;
unsigned int k_size;
int k_size;
int err = 0;
/* version. less than 10 bytes */
buf_incrwritepos(seq_buf,
@@ -1091,7 +1090,7 @@ static int openssh_write(const char *filename, sign_key *key,
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
buf_putbyte(seq_buf, 0);
int err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
if (err != CRYPT_OK) {
dropbear_exit("ECC error");
}

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _KEYIMPORT_H_
#define _KEYIMPORT_H_
#ifndef DROPBEAR_KEYIMPORT_H_
#define DROPBEAR_KEYIMPORT_H_
#include "includes.h"
#include "signkey.h"
@@ -39,4 +39,4 @@ int import_write(const char *filename, sign_key *key, char *passphrase,
sign_key *import_read(const char *filename, char *passphrase, int filetype);
int import_encrypted(const char* filename, int filetype);
#endif /* _KEYIMPORT_H_ */
#endif /* DROPBEAR_KEYIMPORT_H_ */

View File

@@ -122,9 +122,10 @@ static ulong32 setup_mix2(ulong32 temp)
*/
int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
{
int i, j;
int i;
ulong32 temp, *rk;
#ifndef ENCRYPT_ONLY
int j;
ulong32 *rrk;
#endif
LTC_ARGCHK(key != NULL);
@@ -148,7 +149,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
LOAD32H(rk[2], key + 8);
LOAD32H(rk[3], key + 12);
if (keylen == 16) {
#ifndef ENCRYPT_ONLY
j = 44;
#endif
for (;;) {
temp = rk[3];
rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i];
@@ -161,7 +164,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
rk += 4;
}
} else if (keylen == 24) {
#ifndef ENCRYPT_ONLY
j = 52;
#endif
LOAD32H(rk[4], key + 16);
LOAD32H(rk[5], key + 20);
for (;;) {
@@ -182,7 +187,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
rk += 6;
}
} else if (keylen == 32) {
#ifndef ENCRYPT_ONLY
j = 60;
#endif
LOAD32H(rk[4], key + 16);
LOAD32H(rk[5], key + 20);
LOAD32H(rk[6], key + 24);
@@ -728,6 +735,7 @@ int ECB_TEST(void)
*/
void ECB_DONE(symmetric_key *skey)
{
(void)skey;
}

View File

@@ -1871,6 +1871,7 @@ void des_done(symmetric_key *skey)
*/
void des3_done(symmetric_key *skey)
{
(void)skey;
}

View File

@@ -684,6 +684,7 @@ int twofish_test(void)
*/
void twofish_done(symmetric_key *skey)
{
(void)skey;
}
/**

View File

@@ -25,6 +25,7 @@
int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen)
{
#ifdef LTC_NO_FILE
(void)hash; (void)fname; (void)out; (void)outlen;
return CRYPT_NOP;
#else
FILE *in;

View File

@@ -26,6 +26,7 @@
int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen)
{
#ifdef LTC_NO_FILE
(void)hash; (void)in; (void)out; (void)outlen;
return CRYPT_NOP;
#else
hash_state md;

View File

@@ -4,8 +4,16 @@
#include <signal.h>
/* portability macros for compiler-specific code attributes */
#ifdef __GNUC__
#define ATTRIB_NORETURN __attribute__((noreturn))
#else
#define ATTRIB_NORETURN
#endif
/* this is the default LibTomCrypt macro */
void crypt_argchk(char *v, char *s, int d);
void crypt_argchk(char *v, char *s, int d) ATTRIB_NORETURN;
#define LTC_ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); }
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)

View File

@@ -28,7 +28,7 @@
*/
int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
{
unsigned char *buf, *isha;
unsigned char buf[MAXBLOCKSIZE], isha[MAXBLOCKSIZE];
unsigned long hashsize, i;
int hash, err;
@@ -44,19 +44,6 @@ int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
/* get the hash message digest size */
hashsize = hash_descriptor[hash].hashsize;
/* allocate buffers */
buf = XMALLOC(HMAC_BLOCKSIZE);
isha = XMALLOC(hashsize);
if (buf == NULL || isha == NULL) {
if (buf != NULL) {
XFREE(buf);
}
if (isha != NULL) {
XFREE(isha);
}
return CRYPT_MEM;
}
/* Get the hash of the first HMAC vector plus the data */
if ((err = hash_descriptor[hash].done(&hmac->md, isha)) != CRYPT_OK) {
goto LBL_ERR;
@@ -96,9 +83,6 @@ LBL_ERR:
zeromem(hmac, sizeof(*hmac));
#endif
XFREE(isha);
XFREE(buf);
return err;
}

View File

@@ -32,6 +32,7 @@ int hmac_file(int hash, const char *fname,
unsigned char *out, unsigned long *outlen)
{
#ifdef LTC_NO_FILE
(void)hash; (void)fname; (void)key; (void)keylen; (void)out; (void)outlen;
return CRYPT_NOP;
#else
hmac_state hmac;

View File

@@ -29,7 +29,7 @@
*/
int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen)
{
unsigned char *buf;
unsigned char buf[MAXBLOCKSIZE];
unsigned long hashsize;
unsigned long i, z;
int err;
@@ -49,16 +49,9 @@ int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned lon
return CRYPT_INVALID_KEYSIZE;
}
/* allocate ram for buf */
buf = XMALLOC(HMAC_BLOCKSIZE);
if (buf == NULL) {
return CRYPT_MEM;
}
/* allocate memory for key */
hmac->key = XMALLOC(HMAC_BLOCKSIZE);
if (hmac->key == NULL) {
XFREE(buf);
return CRYPT_MEM;
}
@@ -101,7 +94,6 @@ done:
zeromem(buf, HMAC_BLOCKSIZE);
#endif
XFREE(buf);
return err;
}

View File

@@ -21,7 +21,7 @@ void crypt_argchk(char *v, char *s, int d)
{
fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
v, d, s);
(void)raise(SIGABRT);
abort();
}
#endif

View File

@@ -40,7 +40,7 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
int i, j, err;
void *mu, *mp;
unsigned long buf;
int first, bitbuf, bitcpy, bitcnt, mode, digidx;
int bitcnt, mode, digidx;
LTC_ARGCHK(k != NULL);
LTC_ARGCHK(G != NULL);
@@ -98,8 +98,6 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
bitcnt = 1;
buf = 0;
digidx = mp_get_digit_count(k) - 1;
bitcpy = bitbuf = 0;
first = 1;
/* perform ops */
for (;;) {

6
list.h
View File

@@ -1,5 +1,5 @@
#ifndef _DROPBEAR_LIST_H
#define _DROPBEAR_LIST_H
#ifndef DROPBEAR_DROPBEAR_LIST_H
#define DROPBEAR_DROPBEAR_LIST_H
struct _m_list;
@@ -25,4 +25,4 @@ void list_append(m_list *list, void *item);
void * list_remove(m_list_elem *elem);
#endif /* _DROPBEAR_LIST_H */
#endif /* DROPBEAR_DROPBEAR_LIST_H */

View File

@@ -161,5 +161,14 @@ void remove_listener(struct Listener* listener) {
}
ses.listeners[listener->index] = NULL;
m_free(listener);
}
void remove_all_listeners(void) {
unsigned int i;
for (i = 0; i < ses.listensize; i++) {
if (ses.listeners[i]) {
remove_listener(ses.listeners[i]);
}
}
m_free(ses.listeners);
}

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _LISTENER_H
#define _LISTENER_H
#ifndef DROPBEAR_LISTENER_H
#define DROPBEAR_LISTENER_H
#define MAX_LISTENERS 20
#define LISTENER_EXTEND_SIZE 1
@@ -60,4 +60,6 @@ struct Listener * get_listener(int type, void* typedata,
void remove_listener(struct Listener* listener);
#endif /* _LISTENER_H */
void remove_all_listeners(void);
#endif /* DROPBEAR_LISTENER_H */

View File

@@ -1,5 +1,5 @@
#ifndef _HAVE_LOGINREC_H_
#define _HAVE_LOGINREC_H_
#ifndef DROPBEAR_HAVE_LOGINREC_H_
#define DROPBEAR_HAVE_LOGINREC_H_
/*
* Copyright (c) 2000 Andre Lucas. All rights reserved.
@@ -182,4 +182,4 @@ char *line_fullname(char *dst, const char *src, size_t dstsize);
char *line_stripname(char *dst, const char *src, size_t dstsize);
char *line_abbrevname(char *dst, const char *src, size_t dstsize);
#endif /* _HAVE_LOGINREC_H_ */
#endif /* DROPBEAR_HAVE_LOGINREC_H_ */

View File

@@ -1,5 +1,5 @@
#ifndef _LTC_PRNG_H_DROPBEAR
#define _LTC_PRNG_H_DROPBEAR
#ifndef DROPBEAR_LTC_PRNG_H_DROPBEAR
#define DROPBEAR_LTC_PRNG_H_DROPBEAR
#include "options.h"
#include "includes.h"
@@ -10,4 +10,4 @@ extern const struct ltc_prng_descriptor dropbear_prng_desc;
#endif /* DROPBEAR_LTC_PRNG */
#endif /* _LTC_PRNG_H_DROPBEAR */
#endif /* DROPBEAR_LTC_PRNG_H_DROPBEAR */

560
netio.c Normal file
View File

@@ -0,0 +1,560 @@
#include "netio.h"
#include "list.h"
#include "dbutil.h"
#include "session.h"
#include "debug.h"
struct dropbear_progress_connection {
struct addrinfo *res;
struct addrinfo *res_iter;
char *remotehost, *remoteport; /* For error reporting */
connect_callback cb;
void *cb_data;
struct Queue *writequeue; /* A queue of encrypted packets to send with TCP fastopen,
or NULL. */
int sock;
char* errstring;
};
/* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
Does not close sockets */
static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) {
if (c->res) {
freeaddrinfo(c->res);
}
m_free(c->remotehost);
m_free(c->remoteport);
m_free(c->errstring);
m_free(c);
if (iter) {
list_remove(iter);
}
}
static void cancel_callback(int result, int sock, void* UNUSED(data), const char* UNUSED(errstring)) {
if (result == DROPBEAR_SUCCESS)
{
m_close(sock);
}
}
void cancel_connect(struct dropbear_progress_connection *c) {
c->cb = cancel_callback;
c->cb_data = NULL;
}
static void connect_try_next(struct dropbear_progress_connection *c) {
struct addrinfo *r;
int res = 0;
int fastopen = 0;
#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
struct msghdr message;
#endif
for (r = c->res_iter; r; r = r->ai_next)
{
dropbear_assert(c->sock == -1);
c->sock = socket(c->res_iter->ai_family, c->res_iter->ai_socktype, c->res_iter->ai_protocol);
if (c->sock < 0) {
continue;
}
ses.maxfd = MAX(ses.maxfd, c->sock);
set_sock_nodelay(c->sock);
setnonblocking(c->sock);
#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
fastopen = (c->writequeue != NULL);
if (fastopen) {
memset(&message, 0x0, sizeof(message));
message.msg_name = r->ai_addr;
message.msg_namelen = r->ai_addrlen;
/* 6 is arbitrary, enough to hold initial packets */
unsigned int iovlen = 6; /* Linux msg_iovlen is a size_t */
struct iovec iov[6];
packet_queue_to_iovec(c->writequeue, iov, &iovlen);
message.msg_iov = iov;
message.msg_iovlen = iovlen;
res = sendmsg(c->sock, &message, MSG_FASTOPEN);
/* Returns EINPROGRESS if FASTOPEN wasn't available */
if (res < 0) {
if (errno != EINPROGRESS) {
m_free(c->errstring);
c->errstring = m_strdup(strerror(errno));
/* Not entirely sure which kind of errors are normal - 2.6.32 seems to
return EPIPE for any (nonblocking?) sendmsg(). just fall back */
TRACE(("sendmsg tcp_fastopen failed, falling back. %s", strerror(errno)));
/* No kernel MSG_FASTOPEN support. Fall back below */
fastopen = 0;
/* Set to NULL to avoid trying again */
c->writequeue = NULL;
}
} else {
packet_queue_consume(c->writequeue, res);
}
}
#endif
/* Normal connect(), used as fallback for TCP fastopen too */
if (!fastopen) {
res = connect(c->sock, r->ai_addr, r->ai_addrlen);
}
if (res < 0 && errno != EINPROGRESS) {
/* failure */
m_free(c->errstring);
c->errstring = m_strdup(strerror(errno));
close(c->sock);
c->sock = -1;
continue;
} else {
/* new connection was successful, wait for it to complete */
break;
}
}
if (r) {
c->res_iter = r->ai_next;
} else {
c->res_iter = NULL;
}
}
/* Connect via TCP to a host. */
struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport,
connect_callback cb, void* cb_data)
{
struct dropbear_progress_connection *c = NULL;
int err;
struct addrinfo hints;
c = m_malloc(sizeof(*c));
c->remotehost = m_strdup(remotehost);
c->remoteport = m_strdup(remoteport);
c->sock = -1;
c->cb = cb;
c->cb_data = cb_data;
list_append(&ses.conn_pending, c);
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
err = getaddrinfo(remotehost, remoteport, &hints, &c->res);
if (err) {
int len;
len = 100 + strlen(gai_strerror(err));
c->errstring = (char*)m_malloc(len);
snprintf(c->errstring, len, "Error resolving '%s' port '%s'. %s",
remotehost, remoteport, gai_strerror(err));
TRACE(("Error resolving: %s", gai_strerror(err)))
} else {
c->res_iter = c->res;
}
return c;
}
void remove_connect_pending() {
while (ses.conn_pending.first) {
struct dropbear_progress_connection *c = ses.conn_pending.first->item;
remove_connect(c, ses.conn_pending.first);
}
}
void set_connect_fds(fd_set *writefd) {
m_list_elem *iter;
TRACE(("enter set_connect_fds"))
iter = ses.conn_pending.first;
while (iter) {
m_list_elem *next_iter = iter->next;
struct dropbear_progress_connection *c = iter->item;
/* Set one going */
while (c->res_iter && c->sock < 0) {
connect_try_next(c);
}
if (c->sock >= 0) {
FD_SET(c->sock, writefd);
} else {
/* Final failure */
if (!c->errstring) {
c->errstring = m_strdup("unexpected failure");
}
c->cb(DROPBEAR_FAILURE, -1, c->cb_data, c->errstring);
remove_connect(c, iter);
}
iter = next_iter;
}
}
void handle_connect_fds(fd_set *writefd) {
m_list_elem *iter;
TRACE(("enter handle_connect_fds"))
for (iter = ses.conn_pending.first; iter; iter = iter->next) {
int val;
socklen_t vallen = sizeof(val);
struct dropbear_progress_connection *c = iter->item;
if (c->sock < 0 || !FD_ISSET(c->sock, writefd)) {
continue;
}
TRACE(("handling %s port %s socket %d", c->remotehost, c->remoteport, c->sock));
if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &val, &vallen) != 0) {
TRACE(("handle_connect_fds getsockopt(%d) SO_ERROR failed: %s", c->sock, strerror(errno)))
/* This isn't expected to happen - Unix has surprises though, continue gracefully. */
m_close(c->sock);
c->sock = -1;
} else if (val != 0) {
/* Connect failed */
TRACE(("connect to %s port %s failed.", c->remotehost, c->remoteport))
m_close(c->sock);
c->sock = -1;
m_free(c->errstring);
c->errstring = m_strdup(strerror(val));
} else {
/* New connection has been established */
c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, NULL);
remove_connect(c, iter);
TRACE(("leave handle_connect_fds - success"))
/* Must return here - remove_connect() invalidates iter */
return;
}
}
TRACE(("leave handle_connect_fds - end iter"))
}
void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) {
c->writequeue = writequeue;
}
void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count) {
struct Link *l;
unsigned int i;
int len;
buffer *writebuf;
#ifndef IOV_MAX
#define IOV_MAX UIO_MAXIOV
#endif
*iov_count = MIN(MIN(queue->count, IOV_MAX), *iov_count);
for (l = queue->head, i = 0; i < *iov_count; l = l->link, i++)
{
writebuf = (buffer*)l->item;
len = writebuf->len - 1 - writebuf->pos;
dropbear_assert(len > 0);
TRACE2(("write_packet writev #%d type %d len %d/%d", i, writebuf->data[writebuf->len-1],
len, writebuf->len-1))
iov[i].iov_base = buf_getptr(writebuf, len);
iov[i].iov_len = len;
}
}
void packet_queue_consume(struct Queue *queue, ssize_t written) {
buffer *writebuf;
int len;
while (written > 0) {
writebuf = (buffer*)examine(queue);
len = writebuf->len - 1 - writebuf->pos;
if (len > written) {
/* partial buffer write */
buf_incrpos(writebuf, written);
written = 0;
} else {
written -= len;
dequeue(queue);
buf_free(writebuf);
}
}
}
void set_sock_nodelay(int sock) {
int val;
/* disable nagle */
val = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
}
#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
void set_listen_fast_open(int sock) {
int qlen = MAX(MAX_UNAUTH_PER_IP, 5);
if (setsockopt(sock, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) != 0) {
TRACE(("set_listen_fast_open failed for socket %d: %s", sock, strerror(errno)))
}
}
#endif
void set_sock_priority(int sock, enum dropbear_prio prio) {
int rc;
#ifdef IPTOS_LOWDELAY
int iptos_val = 0;
#endif
#ifdef SO_PRIORITY
int so_prio_val = 0;
#endif
/* Don't log ENOTSOCK errors so that this can harmlessly be called
* on a client '-J' proxy pipe */
/* set the TOS bit for either ipv4 or ipv6 */
#ifdef IPTOS_LOWDELAY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
iptos_val = IPTOS_LOWDELAY;
} else if (prio == DROPBEAR_PRIO_BULK) {
iptos_val = IPTOS_THROUGHPUT;
}
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
#endif
#ifdef SO_PRIORITY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
so_prio_val = TC_PRIO_INTERACTIVE;
} else if (prio == DROPBEAR_PRIO_BULK) {
so_prio_val = TC_PRIO_BULK;
}
/* linux specific, sets QoS class. see tc-prio(8) */
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
if (rc < 0 && errno != ENOTSOCK)
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
strerror(errno));
#endif
}
/* Listen on address:port.
* Special cases are address of "" listening on everything,
* and address of NULL listening on localhost only.
* Returns the number of sockets bound on success, or -1 on failure. On
* failure, if errstring wasn't NULL, it'll be a newly malloced error
* string.*/
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
struct addrinfo hints, *res = NULL, *res0 = NULL;
int err;
unsigned int nsock;
struct linger linger;
int val;
int sock;
TRACE(("enter dropbear_listen"))
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
hints.ai_socktype = SOCK_STREAM;
/* for calling getaddrinfo:
address == NULL and !AI_PASSIVE: local loopback
address == NULL and AI_PASSIVE: all interfaces
address != NULL: whatever the address says */
if (!address) {
TRACE(("dropbear_listen: local loopback"))
} else {
if (address[0] == '\0') {
TRACE(("dropbear_listen: all interfaces"))
address = NULL;
}
hints.ai_flags = AI_PASSIVE;
}
err = getaddrinfo(address, port, &hints, &res0);
if (err) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(gai_strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
}
if (res0) {
freeaddrinfo(res0);
res0 = NULL;
}
TRACE(("leave dropbear_listen: failed resolving"))
return -1;
}
nsock = 0;
for (res = res0; res != NULL && nsock < sockcount;
res = res->ai_next) {
/* Get a socket */
socks[nsock] = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
sock = socks[nsock]; /* For clarity */
if (sock < 0) {
err = errno;
TRACE(("socket() failed"))
continue;
}
/* Various useful socket options */
val = 1;
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
linger.l_onoff = 1;
linger.l_linger = 5;
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {
int on = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
&on, sizeof(on)) == -1) {
dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
}
}
#endif
set_sock_nodelay(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
err = errno;
close(sock);
TRACE(("bind(%s) failed", port))
continue;
}
if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
err = errno;
close(sock);
TRACE(("listen() failed"))
continue;
}
*maxfd = MAX(*maxfd, sock);
nsock++;
}
if (res0) {
freeaddrinfo(res0);
res0 = NULL;
}
if (nsock == 0) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error listening: %s", strerror(err));
}
TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
return -1;
}
TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
return nsock;
}
void get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup)
{
struct sockaddr_storage addr;
socklen_t addrlen;
if (local_host || local_port) {
addrlen = sizeof(addr);
if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
dropbear_exit("Failed socket address: %s", strerror(errno));
}
getaddrstring(&addr, local_host, local_port, host_lookup);
}
if (remote_host || remote_port) {
addrlen = sizeof(addr);
if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
dropbear_exit("Failed socket address: %s", strerror(errno));
}
getaddrstring(&addr, remote_host, remote_port, host_lookup);
}
}
/* Return a string representation of the socket address passed. The return
* value is allocated with malloc() */
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port,
int host_lookup) {
char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
unsigned int len;
int ret;
int flags = NI_NUMERICSERV | NI_NUMERICHOST;
#ifndef DO_HOST_LOOKUP
host_lookup = 0;
#endif
if (host_lookup) {
flags = NI_NUMERICSERV;
}
len = sizeof(struct sockaddr_storage);
/* Some platforms such as Solaris 8 require that len is the length
* of the specific structure. Some older linux systems (glibc 2.1.3
* such as debian potato) have sockaddr_storage.__ss_family instead
* but we'll ignore them */
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
if (addr->ss_family == AF_INET) {
len = sizeof(struct sockaddr_in);
}
#ifdef AF_INET6
if (addr->ss_family == AF_INET6) {
len = sizeof(struct sockaddr_in6);
}
#endif
#endif
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
serv, sizeof(serv)-1, flags);
if (ret != 0) {
if (host_lookup) {
/* On some systems (Darwin does it) we get EINTR from getnameinfo
* somehow. Eew. So we'll just return the IP, since that doesn't seem
* to exhibit that behaviour. */
getaddrstring(addr, ret_host, ret_port, 0);
return;
} else {
/* if we can't do a numeric lookup, something's gone terribly wrong */
dropbear_exit("Failed lookup: %s", gai_strerror(ret));
}
}
if (ret_host) {
*ret_host = m_strdup(host);
}
if (ret_port) {
*ret_port = m_strdup(serv);
}
}

64
netio.h Normal file
View File

@@ -0,0 +1,64 @@
#ifndef DROPBEAR_NETIO_H
#define DROPBEAR_NETIO_H
#include "includes.h"
#include "buffer.h"
#include "queue.h"
enum dropbear_prio {
DROPBEAR_PRIO_DEFAULT = 10,
DROPBEAR_PRIO_LOWDELAY = 11,
DROPBEAR_PRIO_BULK = 12,
};
void set_sock_nodelay(int sock);
void set_sock_priority(int sock, enum dropbear_prio prio);
void get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup);
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port, int host_lookup);
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
struct dropbear_progress_connection;
/* result is DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
errstring is only set on DROPBEAR_FAILURE, returns failure message for the last attempted socket */
typedef void(*connect_callback)(int result, int sock, void* data, const char* errstring);
/* Always returns a progress connection, if it fails it will call the callback at a later point */
struct dropbear_progress_connection * connect_remote (const char* remotehost, const char* remoteport,
connect_callback cb, void *cb_data);
/* Sets up for select() */
void set_connect_fds(fd_set *writefd);
/* Handles ready sockets after select() */
void handle_connect_fds(fd_set *writefd);
/* Cleanup */
void remove_connect_pending();
/* Doesn't actually stop the connect, but adds a dummy callback instead */
void cancel_connect(struct dropbear_progress_connection *c);
void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue);
/* TODO: writev #ifdef guard */
/* Fills out iov which contains iov_count slots, returning the number filled in iov_count */
void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count);
void packet_queue_consume(struct Queue *queue, ssize_t written);
#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
/* Try for any Linux builds, will fall back if the kernel doesn't support it */
void set_listen_fast_open(int sock);
/* Define values which may be supported by the kernel even if the libc is too old */
#ifndef TCP_FASTOPEN
#define TCP_FASTOPEN 23
#endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
#endif
#endif
#endif

View File

@@ -2,8 +2,8 @@
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved. See LICENSE for the license. */
#ifndef _OPTIONS_H_
#define _OPTIONS_H_
#ifndef DROPBEAR_OPTIONS_H_
#define DROPBEAR_OPTIONS_H_
/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
* parts are to allow for commandline -DDROPBEAR_XXX options etc. */
@@ -95,18 +95,23 @@ much traffic. */
#define DROPBEAR_AES256
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
/*#define DROPBEAR_BLOWFISH*/
/*#define DROPBEAR_TWOFISH256*/
/*#define DROPBEAR_TWOFISH128*/
#define DROPBEAR_TWOFISH256
#define DROPBEAR_TWOFISH128
/* Enable CBC mode for ciphers. This has security issues though
* is the most compatible with older SSH implementations */
#define DROPBEAR_ENABLE_CBC_MODE
/* Enable "Counter Mode" for ciphers. This is more secure than normal
* CBC mode against certain attacks. This adds around 1kB to binary
* size and is recommended for most cases */
* CBC mode against certain attacks. It is recommended for security
* and forwards compatibility */
#define DROPBEAR_ENABLE_CTR_MODE
/* Twofish counter mode is disabled by default because it
has not been tested for interoperability with other SSH implementations.
If you test it please contact the Dropbear author */
/* #define DROPBEAR_TWOFISH_CTR */
/* You can compile with no encryption if you want. In some circumstances
* this could be safe security-wise, though make sure you know what
* you're doing. Anyone can see everything that goes over the wire, so
@@ -201,7 +206,10 @@ much traffic. */
* PAM challenge/response.
* You can't enable both PASSWORD and PAM. */
/* This requires crypt() */
#ifdef HAVE_CRYPT
#define ENABLE_SVR_PASSWORD_AUTH
#endif
/* PAM requires ./configure --enable-pam */
/*#define ENABLE_SVR_PAM_AUTH */
#define ENABLE_SVR_PUBKEY_AUTH
@@ -212,13 +220,16 @@ much traffic. */
#define ENABLE_SVR_PUBKEY_OPTIONS
#endif
/* This requires getpass. */
#ifdef HAVE_GETPASS
#define ENABLE_CLI_PASSWORD_AUTH
#define ENABLE_CLI_PUBKEY_AUTH
#define ENABLE_CLI_INTERACT_AUTH
#endif
#define ENABLE_CLI_PUBKEY_AUTH
/* A default argument for dbclient -i <privatekey>.
leading "~" is expanded */
#define DROPBEAR_DEFAULT_CLI_AUTHKEY "~/.ssh/id_dropbear"
Homedir is prepended unless path begins with / */
#define DROPBEAR_DEFAULT_CLI_AUTHKEY ".ssh/id_dropbear"
/* This variable can be used to set a password for client
* authentication on the commandline. Beware of platforms
@@ -289,7 +300,7 @@ much traffic. */
/* This is used by the scp binary when used as a client binary. If you're
* not using the Dropbear client, you'll need to change it */
#define _PATH_SSH_PROGRAM "/usr/bin/dbclient"
#define DROPBEAR_PATH_SSH_PROGRAM "/usr/bin/dbclient"
/* Whether to log commands executed by a client. This only logs the
* (single) command sent to the server, not what a user did in a
@@ -337,4 +348,4 @@ be overridden at runtime with -I. 0 disables idle timeouts */
* in sysoptions.h */
#include "sysoptions.h"
#endif /* _OPTIONS_H_ */
#endif /* DROPBEAR_OPTIONS_H_ */

150
packet.c
View File

@@ -34,6 +34,7 @@
#include "service.h"
#include "auth.h"
#include "channel.h"
#include "netio.h"
static int read_packet_init();
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
@@ -55,14 +56,15 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len);
/* non-blocking function writing out a current encrypted packet */
void write_packet() {
int len, written;
buffer * writebuf = NULL;
unsigned packet_type;
ssize_t written;
#ifdef HAVE_WRITEV
struct iovec *iov = NULL;
int i;
struct Link *l;
int iov_max_count;
/* 50 is somewhat arbitrary */
unsigned int iov_count = 50;
struct iovec iov[50];
#else
int len;
buffer* writebuf;
int packet_type;
#endif
TRACE2(("enter write_packet"))
@@ -70,36 +72,13 @@ void write_packet() {
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
#ifndef IOV_MAX
#define IOV_MAX UIO_MAXIOV
#endif
/* Make sure the size of the iov is below the maximum allowed by the OS. */
iov_max_count = ses.writequeue.count;
if (iov_max_count > IOV_MAX)
{
iov_max_count = IOV_MAX;
}
iov = m_malloc(sizeof(*iov) * iov_max_count);
for (l = ses.writequeue.head, i = 0; l; l = l->link, i++)
{
writebuf = (buffer*)l->item;
packet_type = writebuf->data[writebuf->len-1];
len = writebuf->len - 1 - writebuf->pos;
dropbear_assert(len > 0);
TRACE2(("write_packet writev #%d type %d len %d/%d", i, packet_type,
len, writebuf->len-1))
iov[i].iov_base = buf_getptr(writebuf, len);
iov[i].iov_len = len;
}
packet_queue_to_iovec(&ses.writequeue, iov, &iov_count);
/* This may return EAGAIN. The main loop sometimes
calls write_packet() without bothering to test with select() since
it's likely to be necessary */
written = writev(ses.sock_out, iov, iov_max_count);
written = writev(ses.sock_out, iov, iov_count);
if (written < 0) {
if (errno == EINTR || errno == EAGAIN) {
m_free(iov);
TRACE2(("leave write_packet: EINTR"))
return;
} else {
@@ -107,25 +86,13 @@ void write_packet() {
}
}
packet_queue_consume(&ses.writequeue, written);
ses.writequeue_len -= written;
if (written == 0) {
ses.remoteclosed();
}
while (written > 0) {
writebuf = (buffer*)examine(&ses.writequeue);
len = writebuf->len - 1 - writebuf->pos;
if (len > written) {
/* partial buffer write */
buf_incrpos(writebuf, written);
written = 0;
} else {
written -= len;
dequeue(&ses.writequeue);
buf_free(writebuf);
}
}
m_free(iov);
#else /* No writev () */
/* Get the next buffer in the queue of encrypted packets to write*/
writebuf = (buffer*)examine(&ses.writequeue);
@@ -134,6 +101,8 @@ void write_packet() {
* a cleartext packet_type indicator */
packet_type = writebuf->data[writebuf->len-1];
len = writebuf->len - 1 - writebuf->pos;
TRACE2(("write_packet type %d len %d/%d", packet_type,
len, writebuf->len-1))
dropbear_assert(len > 0);
/* Try to write as much as possible */
written = write(ses.sock_out, buf_getptr(writebuf, len), len);
@@ -151,6 +120,8 @@ void write_packet() {
ses.remoteclosed();
}
ses.writequeue_len -= written;
if (written == len) {
/* We've finished with the packet, free it */
dequeue(&ses.writequeue);
@@ -294,7 +265,7 @@ static int read_packet_init() {
}
if (len > ses.readbuf->size) {
buf_resize(ses.readbuf, len);
ses.readbuf = buf_resize(ses.readbuf, len);
}
buf_setlen(ses.readbuf, len);
buf_setpos(ses.readbuf, blocksize);
@@ -351,18 +322,21 @@ void decrypt_packet() {
if (is_compress_recv()) {
/* decompress */
ses.payload = buf_decompress(ses.readbuf, len);
buf_setpos(ses.payload, 0);
ses.payload_beginning = 0;
buf_free(ses.readbuf);
} else
#endif
{
ses.payload = ses.readbuf;
ses.payload_beginning = ses.payload->pos;
buf_setlen(ses.payload, ses.payload->pos + len);
/* copy payload */
ses.payload = buf_new(len);
memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
buf_incrlen(ses.payload, len);
//ses.payload = buf_new(len);
//memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
//buf_incrlen(ses.payload, len);
}
buf_free(ses.readbuf);
ses.readbuf = NULL;
buf_setpos(ses.payload, 0);
ses.recvseq++;
@@ -435,7 +409,7 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
dropbear_exit("bad packet, oversized decompressed");
}
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
buf_resize(ret, new_size);
ret = buf_resize(ret, new_size);
}
}
}
@@ -605,15 +579,12 @@ void encrypt_packet() {
/* stick the MAC on it */
buf_putbytes(writebuf, mac_bytes, mac_size);
/* The last byte of the buffer stores the cleartext packet_type. It is not
* transmitted but is used for transmit timeout purposes */
buf_putbyte(writebuf, packet_type);
/* enqueue the packet for sending. It will get freed after transmission. */
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, (void*)writebuf);
/* Update counts */
ses.kexstate.datatrans += writebuf->len;
writebuf_enqueue(writebuf, packet_type);
/* Update counts */
ses.transseq++;
now = monotonic_now();
@@ -631,6 +602,16 @@ void encrypt_packet() {
TRACE2(("leave encrypt_packet()"))
}
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type) {
/* The last byte of the buffer stores the cleartext packet_type. It is not
* transmitted but is used for transmit timeout purposes */
buf_putbyte(writebuf, packet_type);
/* enqueue the packet for sending. It will get freed after transmission. */
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, (void*)writebuf);
ses.writequeue_len += writebuf->len-1;
}
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
@@ -674,7 +655,8 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
#ifndef DISABLE_ZLIB
/* compresses len bytes from src, outputting to dest (starting from the
* respective current positions. */
* respective current positions. dest must have sufficient space,
* len+ZLIB_COMPRESS_EXPANSION */
static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
unsigned int endpos = src->pos + len;
@@ -682,38 +664,28 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
TRACE2(("enter buf_compress"))
while (1) {
dropbear_assert(dest->size - dest->pos >= len+ZLIB_COMPRESS_EXPANSION);
ses.keys->trans.zstream->avail_in = endpos - src->pos;
ses.keys->trans.zstream->next_in =
buf_getptr(src, ses.keys->trans.zstream->avail_in);
ses.keys->trans.zstream->avail_in = endpos - src->pos;
ses.keys->trans.zstream->next_in =
buf_getptr(src, ses.keys->trans.zstream->avail_in);
ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
ses.keys->trans.zstream->next_out =
buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
ses.keys->trans.zstream->next_out =
buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
buf_setpos(dest, dest->len);
if (result != Z_OK) {
dropbear_exit("zlib error");
}
if (ses.keys->trans.zstream->avail_in == 0) {
break;
}
dropbear_assert(ses.keys->trans.zstream->avail_out == 0);
/* the buffer has been filled, we must extend. This only happens in
* unusual circumstances where the data grows in size after deflate(),
* but it is possible */
buf_resize(dest, dest->size + ZLIB_COMPRESS_EXPANSION);
buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
buf_setpos(dest, dest->len);
if (result != Z_OK) {
dropbear_exit("zlib error");
}
/* fails if destination buffer wasn't large enough */
dropbear_assert(ses.keys->trans.zstream->avail_in == 0);
TRACE2(("leave buf_compress"))
}
#endif

View File

@@ -22,17 +22,21 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _PACKET_H_
#ifndef DROPBEAR_PACKET_H_
#define _PACKET_H_
#define DROPBEAR_PACKET_H_
#include "includes.h"
#include "queue.h"
#include "buffer.h"
void write_packet();
void read_packet();
void decrypt_packet();
void encrypt_packet();
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type);
void process_packet();
void maybe_flush_reply_queue();
@@ -46,4 +50,4 @@ typedef struct PacketType {
#define INIT_READBUF 128
#endif /* _PACKET_H_ */
#endif /* DROPBEAR_PACKET_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _QUEUE_H_
#define _QUEUE_H_
#ifndef DROPBEAR_QUEUE_H_
#define DROPBEAR_QUEUE_H_
struct Link {

View File

@@ -33,8 +33,13 @@ hg archive "$RELDIR" || exit 2
rm -r "$RELDIR/autom4te.cache" || exit 2
(cd $RELDIR/.. && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2
rm "$RELDIR/.hgtags"
(cd "$RELDIR/.." && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2
ls -l $ARCHIVE
openssl sha1 $ARCHIVE
echo "Done to $ARCHIVE"
openssl sha -sha256 $ARCHIVE
echo Done to
echo "$ARCHIVE"
echo Sign it with
echo gpg2 --detach-sign -a -u F29C6773 "$ARCHIVE"

6
rsa.h
View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _RSA_H_
#define _RSA_H_
#ifndef DROPBEAR_RSA_H_
#define DROPBEAR_RSA_H_
#include "includes.h"
#include "buffer.h"
@@ -55,4 +55,4 @@ void rsa_key_free(dropbear_rsa_key *key);
#endif /* DROPBEAR_RSA */
#endif /* _RSA_H_ */
#endif /* DROPBEAR_RSA_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _RUNOPTS_H_
#define _RUNOPTS_H_
#ifndef DROPBEAR_RUNOPTS_H_
#define DROPBEAR_RUNOPTS_H_
#include "includes.h"
#include "signkey.h"
@@ -170,4 +170,4 @@ void parse_ciphers_macs();
void print_version(void);
#endif /* _RUNOPTS_H_ */
#endif /* DROPBEAR_RUNOPTS_H_ */

6
scp.c
View File

@@ -96,7 +96,7 @@ int verbose_mode = 0;
int showprogress = 1;
/* This is the program to execute for the secured connection. ("ssh" or -S) */
char *ssh_program = _PATH_SSH_PROGRAM;
char *ssh_program = DROPBEAR_PATH_SSH_PROGRAM;
/* This is used to store the pid of ssh_program */
pid_t do_cmd_pid = -1;
@@ -437,7 +437,7 @@ main(int argc, char **argv)
}
/*
* Finally check the exit status of the ssh process, if one was forked
* and no error has occured yet
* and no error has occurred yet
*/
if (do_cmd_pid != -1 && errs == 0) {
if (remin != -1)
@@ -992,7 +992,7 @@ sink(int argc, char **argv)
continue;
}
omode = mode;
mode |= S_IWRITE;
mode |= S_IWUSR;
if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
bad: run_err("%s: %s", np, strerror(errno));
continue;

View File

@@ -22,9 +22,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _SERVICE_H_
#define _SERVICE_H_
#ifndef DROPBEAR_SERVICE_H_
#define DROPBEAR_SERVICE_H_
void recv_msg_service_request(); /* Server */
#endif /* _SERVICE_H_ */
#endif /* DROPBEAR_SERVICE_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _SESSION_H_
#define _SESSION_H_
#ifndef DROPBEAR_SESSION_H_
#define DROPBEAR_SESSION_H_
#include "includes.h"
#include "options.h"
@@ -38,12 +38,13 @@
#include "tcpfwd.h"
#include "chansession.h"
#include "dbutil.h"
#include "netio.h"
extern int sessinitdone; /* Is set to 0 somewhere */
extern int exitflag;
void common_session_init(int sock_in, int sock_out);
void session_loop(void(*loophandler)());
void session_loop(void(*loophandler)()) ATTRIB_NORETURN;
void session_cleanup();
void send_session_identification();
void send_msg_ignore();
@@ -55,13 +56,14 @@ const char* get_user_shell();
void fill_passwd(const char* username);
/* Server */
void svr_session(int sock, int childpipe);
void svr_session(int sock, int childpipe) ATTRIB_NORETURN;
void svr_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
void svr_dropbear_log(int priority, const char* format, va_list param);
/* Client */
void cli_session(int sock_in, int sock_out);
void cleantext(unsigned char* dirtytext);
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress) ATTRIB_NORETURN;
void cli_connected(int result, int sock, void* userdata, const char *errstring);
void cleantext(char* dirtytext);
/* crypto parameters that are stored individually for transmit and receive */
struct key_context_directional {
@@ -107,13 +109,18 @@ struct sshsession {
/* Is it a client or server? */
unsigned char isserver;
time_t connect_time; /* time the connection was established
(cleared after auth once we're not
respecting AUTH_TIMEOUT any more).
A monotonic time, not realworld */
int sock_in;
int sock_out;
/* remotehost will be initially NULL as we delay
* reading the remote version string. it will be set
* by the time any recv_() packet methods are called */
unsigned char *remoteident;
char *remoteident;
int maxfd; /* the maximum file descriptor to check with select() */
@@ -123,8 +130,13 @@ struct sshsession {
throughout the code, as handlers fill out this
buffer with the packet to send. */
struct Queue writequeue; /* A queue of encrypted packets to send */
unsigned int writequeue_len; /* Number of bytes pending to send in writequeue */
buffer *readbuf; /* From the wire, decrypted in-place */
buffer *payload; /* Post-decompression, the actual SSH packet */
buffer *payload; /* Post-decompression, the actual SSH packet.
May have extra data at the beginning, will be
passed to packet processing functions positioned past
that, see payload_beginning */
unsigned int payload_beginning;
unsigned int transseq, recvseq; /* Sequence IDs */
/* Packet-handling flags */
@@ -144,6 +156,8 @@ struct sshsession {
int signal_pipe[2]; /* stores endpoints of a self-pipe used for
race-free signal handling */
m_list conn_pending;
/* time of the last packet send/receive, for keepalive. Not real-world clock */
time_t last_packet_time_keepalive_sent;
@@ -222,11 +236,6 @@ struct serversession {
/* The resolved remote address, used for lastlog etc */
char *remotehost;
time_t connect_time; /* time the connection was established
(cleared after auth once we're not
respecting AUTH_TIMEOUT any more).
A monotonic time, not realworld */
#ifdef USE_VFORK
pid_t server_pid;
#endif
@@ -284,10 +293,9 @@ struct clientsession {
int interact_request_received; /* flag whether we've received an
info request from the server for
interactive auth.*/
#endif
int cipher_none_after_auth; /* Set to 1 if the user requested "none"
auth */
#endif
sign_key *lastprivkey;
int retval; /* What the command exit status was - we emulate it */
@@ -309,4 +317,4 @@ extern struct serversession svr_ses;
extern struct clientsession cli_ses;
#endif /* DROPBEAR_CLIENT */
#endif /* _SESSION_H_ */
#endif /* DROPBEAR_SESSION_H_ */

View File

@@ -138,9 +138,9 @@ signkey_key_ptr(sign_key *key, enum signkey_type type) {
* on return is set to the type read (useful when type = _ANY) */
int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
unsigned char* ident;
char *ident;
unsigned int len;
int keytype;
enum signkey_type keytype;
int ret = DROPBEAR_FAILURE;
TRACE2(("enter buf_get_pub_key"))
@@ -187,6 +187,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
if (eck) {
if (*eck) {
ecc_free(*eck);
m_free(*eck);
*eck = NULL;
}
*eck = buf_get_ecdsa_pub_key(buf);
@@ -208,9 +209,9 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
* on return is set to the type read (useful when type = _ANY) */
int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
unsigned char* ident;
char *ident;
unsigned int len;
int keytype;
enum signkey_type keytype;
int ret = DROPBEAR_FAILURE;
TRACE2(("enter buf_get_priv_key"))
@@ -255,6 +256,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
if (eck) {
if (*eck) {
ecc_free(*eck);
m_free(*eck);
*eck = NULL;
}
*eck = buf_get_ecdsa_priv_key(buf);
@@ -355,18 +357,21 @@ void sign_key_free(sign_key *key) {
#ifdef DROPBEAR_ECC_256
if (key->ecckey256) {
ecc_free(key->ecckey256);
m_free(key->ecckey256);
key->ecckey256 = NULL;
}
#endif
#ifdef DROPBEAR_ECC_384
if (key->ecckey384) {
ecc_free(key->ecckey384);
m_free(key->ecckey384);
key->ecckey384 = NULL;
}
#endif
#ifdef DROPBEAR_ECC_521
if (key->ecckey521) {
ecc_free(key->ecckey521);
m_free(key->ecckey521);
key->ecckey521 = NULL;
}
#endif
@@ -510,7 +515,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
* signature blob */
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
unsigned char * type_name = NULL;
char *type_name = NULL;
unsigned int type_name_len = 0;
enum signkey_type type;

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _SIGNKEY_H_
#define _SIGNKEY_H_
#ifndef DROPBEAR_SIGNKEY_H_
#define DROPBEAR_SIGNKEY_H_
#include "buffer.h"
#include "dss.h"
@@ -101,4 +101,4 @@ int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
void** signkey_key_ptr(sign_key *key, enum signkey_type type);
#endif /* _SIGNKEY_H_ */
#endif /* DROPBEAR_SIGNKEY_H_ */

View File

@@ -117,7 +117,7 @@ static void agentaccept(struct Listener *UNUSED(listener), int sock) {
}
/* set up the environment variable pointing to the socket. This is called
* just before command/shell execution, after dropping priveleges */
* just before command/shell execution, after dropping privileges */
void svr_agentset(struct ChanSess * chansess) {
char *path = NULL;

View File

@@ -36,7 +36,7 @@
#include "dbrandom.h"
static void authclear();
static int checkusername(unsigned char *username, unsigned int userlen);
static int checkusername(char *username, unsigned int userlen);
/* initialise the first time for a session, resetting all parameters */
void svr_authinitialise() {
@@ -100,7 +100,7 @@ void send_msg_userauth_banner(buffer *banner) {
* checking, and handle success or failure */
void recv_msg_userauth_request() {
unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
char *username = NULL, *servicename = NULL, *methodname = NULL;
unsigned int userlen, servicelen, methodlen;
int valid_user = 0;
@@ -227,7 +227,7 @@ out:
/* Check that the username exists and isn't disallowed (root), and has a valid shell.
* returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
static int checkusername(unsigned char *username, unsigned int userlen) {
static int checkusername(char *username, unsigned int userlen) {
char* listshell = NULL;
char* usershell = NULL;
@@ -333,14 +333,14 @@ void send_msg_userauth_failure(int partial, int incrfail) {
typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */
if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
buf_putbytes(typebuf, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
buf_putbyte(typebuf, ',');
}
}
if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
}
buf_putbufstring(ses.writepayload, typebuf);
@@ -392,7 +392,8 @@ void send_msg_userauth_success() {
/* authdone must be set after encrypt_packet() for
* delayed-zlib mode */
ses.authstate.authdone = 1;
svr_ses.connect_time = 0;
ses.connect_time = 0;
if (ses.authstate.pw_uid == 0) {
ses.allowprivport = 1;

View File

@@ -188,7 +188,7 @@ void svr_auth_pam() {
pam_handle_t* pamHandlep = NULL;
unsigned char * password = NULL;
char * password = NULL;
unsigned int passwordlen;
int rc = PAM_SUCCESS;

View File

@@ -33,6 +33,8 @@
#ifdef ENABLE_SVR_PASSWORD_AUTH
/* not constant time when strings are differing lengths.
string content isn't leaked, and crypt hashes are predictable length. */
static int constant_time_strcmp(const char* a, const char* b) {
size_t la = strlen(a);
size_t lb = strlen(b);
@@ -50,7 +52,7 @@ void svr_auth_password() {
char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
char * testcrypt = NULL; /* crypt generated from the user's password sent */
unsigned char * password;
char * password;
unsigned int passwordlen;
unsigned int changepw;
@@ -73,7 +75,7 @@ void svr_auth_password() {
password = buf_getstring(ses.payload, &passwordlen);
/* the first bytes of passwdcrypt are the salt */
testcrypt = crypt((char*)password, passwdcrypt);
testcrypt = crypt(password, passwdcrypt);
m_burn(password, passwordlen);
m_free(password);

View File

@@ -70,10 +70,10 @@
#define MIN_AUTHKEYS_LINE 10 /* "ssh-rsa AB" - short but doesn't matter */
#define MAX_AUTHKEYS_LINE 4200 /* max length of a line in authkeys */
static int checkpubkey(unsigned char* algo, unsigned int algolen,
static int checkpubkey(char* algo, unsigned int algolen,
unsigned char* keyblob, unsigned int keybloblen);
static int checkpubkeyperms();
static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
static void send_msg_userauth_pk_ok(char* algo, unsigned int algolen,
unsigned char* keyblob, unsigned int keybloblen);
static int checkfileperm(char * filename);
@@ -82,10 +82,11 @@ static int checkfileperm(char * filename);
void svr_auth_pubkey() {
unsigned char testkey; /* whether we're just checking if a key is usable */
unsigned char* algo = NULL; /* pubkey algo */
char* algo = NULL; /* pubkey algo */
unsigned int algolen;
unsigned char* keyblob = NULL;
unsigned int keybloblen;
unsigned int sign_payload_length;
buffer * signbuf = NULL;
sign_key * key = NULL;
char* fp = NULL;
@@ -125,9 +126,18 @@ void svr_auth_pubkey() {
/* create the data which has been signed - this a string containing
* session_id, concatenated with the payload packet up to the signature */
assert(ses.payload_beginning <= ses.payload->pos);
sign_payload_length = ses.payload->pos - ses.payload_beginning;
signbuf = buf_new(ses.payload->pos + 4 + ses.session_id->len);
buf_putbufstring(signbuf, ses.session_id);
buf_putbytes(signbuf, ses.payload->data, ses.payload->pos);
/* The entire contents of the payload prior. */
buf_setpos(ses.payload, ses.payload_beginning);
buf_putbytes(signbuf,
buf_getptr(ses.payload, sign_payload_length),
sign_payload_length);
buf_incrpos(ses.payload, sign_payload_length);
buf_setpos(signbuf, 0);
/* ... and finally verify the signature */
@@ -163,7 +173,7 @@ out:
/* Reply that the key is valid for auth, this is sent when the user sends
* a straight copy of their pubkey to test, to avoid having to perform
* expensive signing operations with a worthless key */
static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
static void send_msg_userauth_pk_ok(char* algo, unsigned int algolen,
unsigned char* keyblob, unsigned int keybloblen) {
TRACE(("enter send_msg_userauth_pk_ok"))
@@ -171,7 +181,7 @@ static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_PK_OK);
buf_putstring(ses.writepayload, algo, algolen);
buf_putstring(ses.writepayload, keyblob, keybloblen);
buf_putstring(ses.writepayload, (const char*)keyblob, keybloblen);
encrypt_packet();
TRACE(("leave send_msg_userauth_pk_ok"))
@@ -181,7 +191,7 @@ static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
/* Checks whether a specified publickey (and associated algorithm) is an
* acceptable key for authentication */
/* Returns DROPBEAR_SUCCESS if key is ok for auth, DROPBEAR_FAILURE otherwise */
static int checkpubkey(unsigned char* algo, unsigned int algolen,
static int checkpubkey(char* algo, unsigned int algolen,
unsigned char* keyblob, unsigned int keybloblen) {
FILE * authfile = NULL;
@@ -250,9 +260,9 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
/* check the key type - will fail if there are options */
TRACE(("a line!"))
if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) {
if (strncmp((const char *) buf_getptr(line, algolen), algo, algolen) != 0) {
int is_comment = 0;
char *options_start = NULL;
unsigned char *options_start = NULL;
int options_len = 0;
int escape, quoted;
@@ -298,7 +308,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
if (line->pos + algolen+3 > line->len) {
continue;
}
if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) {
if (strncmp((const char *) buf_getptr(line, algolen), algo, algolen) != 0) {
continue;
}
}
@@ -320,7 +330,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
TRACE(("checkpubkey: line pos = %d len = %d", line->pos, line->len))
ret = cmp_base64_key(keyblob, keybloblen, algo, algolen, line, NULL);
ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algo, algolen, line, NULL);
if (ret == DROPBEAR_SUCCESS && options_buf) {
ret = svr_add_pubkey_options(options_buf, line_num, filename);

View File

@@ -91,7 +91,7 @@ int svr_pubkey_allows_pty() {
/* Set chansession command to the one forced
* by any 'command' public key option. */
void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
if (ses.authstate.pubkey_options) {
if (ses.authstate.pubkey_options && ses.authstate.pubkey_options->forced_command) {
if (chansess->cmd) {
/* original_command takes ownership */
chansess->original_command = chansess->cmd;
@@ -120,7 +120,7 @@ static int match_option(buffer *options_buf, const char *opt_name) {
if (options_buf->len - options_buf->pos < len) {
return DROPBEAR_FAILURE;
}
if (strncasecmp(buf_getptr(options_buf, len), opt_name, len) == 0) {
if (strncasecmp((const char *) buf_getptr(options_buf, len), opt_name, len) == 0) {
buf_incrpos(options_buf, len);
return DROPBEAR_SUCCESS;
}

View File

@@ -234,7 +234,7 @@ static int newchansess(struct Channel *channel) {
struct ChanSess *chansess;
TRACE(("new chansess %p", channel))
TRACE(("new chansess %p", (void*)channel))
dropbear_assert(channel->typedata == NULL);
@@ -343,7 +343,7 @@ static void closechansess(struct Channel *channel) {
* or x11/authagent forwarding. These are passed to appropriate handlers */
static void chansessionrequest(struct Channel *channel) {
unsigned char * type = NULL;
char * type = NULL;
unsigned int typelen;
unsigned char wantreply;
int ret = 1;
@@ -406,7 +406,7 @@ out:
static int sessionsignal(struct ChanSess *chansess) {
int sig = 0;
unsigned char* signame = NULL;
char* signame = NULL;
int i;
if (chansess->pid == 0) {
@@ -557,7 +557,7 @@ static void get_termmodes(struct ChanSess *chansess) {
static int sessionpty(struct ChanSess * chansess) {
unsigned int termlen;
unsigned char namebuf[65];
char namebuf[65];
struct passwd * pw = NULL;
TRACE(("enter sessionpty"))
@@ -583,7 +583,7 @@ static int sessionpty(struct ChanSess * chansess) {
return DROPBEAR_FAILURE;
}
chansess->tty = (char*)m_strdup(namebuf);
chansess->tty = m_strdup(namebuf);
if (!chansess->tty) {
dropbear_exit("Out of memory"); /* TODO disconnect */
}
@@ -603,6 +603,7 @@ static int sessionpty(struct ChanSess * chansess) {
return DROPBEAR_SUCCESS;
}
#ifndef USE_VFORK
static void make_connection_string(struct ChanSess *chansess) {
char *local_ip, *local_port, *remote_ip, *remote_port;
size_t len;
@@ -624,6 +625,7 @@ static void make_connection_string(struct ChanSess *chansess) {
m_free(remote_ip);
m_free(remote_port);
}
#endif
/* Handle a command request from the client. This is used for both shell
* and command-execution requests, and passes the command to
@@ -812,7 +814,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
login_free_entry(li);
#ifdef DO_MOTD
if (svr_opts.domotd) {
if (svr_opts.domotd && !chansess->cmd) {
/* don't show the motd if ~/.hushlogin exists */
/* 12 == strlen("/.hushlogin\0") */

View File

@@ -247,7 +247,7 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
{
struct kex_curve25519_param *param = gen_kexcurve25519_param();
kexcurve25519_comb_key(param, ecdh_qs, svr_opts.hostkey);
buf_putstring(ses.writepayload, param->pub, CURVE25519_LEN);
buf_putstring(ses.writepayload, (const char*)param->pub, CURVE25519_LEN);
free_kexcurve25519_param(param);
}
#endif

View File

@@ -138,7 +138,6 @@ void main_noinetd() {
}
for (i = 0; i < listensockcount; i++) {
set_sock_priority(listensocks[i], DROPBEAR_PRIO_LOWDELAY);
FD_SET(listensocks[i], &fds);
}
@@ -403,9 +402,9 @@ static void commonsetup() {
}
/* Set up listening sockets for all the requested ports */
static size_t listensockets(int *sock, size_t sockcount, int *maxfd) {
unsigned int i;
static size_t listensockets(int *socks, size_t sockcount, int *maxfd) {
unsigned int i, n;
char* errstring = NULL;
size_t sockpos = 0;
int nsock;
@@ -416,7 +415,7 @@ static size_t listensockets(int *sock, size_t sockcount, int *maxfd) {
TRACE(("listening on '%s:%s'", svr_opts.addresses[i], svr_opts.ports[i]))
nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &sock[sockpos],
nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &socks[sockpos],
sockcount - sockpos,
&errstring, maxfd);
@@ -427,6 +426,14 @@ static size_t listensockets(int *sock, size_t sockcount, int *maxfd) {
continue;
}
for (n = 0; n < (unsigned int)nsock; n++) {
int sock = socks[sockpos + n];
set_sock_priority(sock, DROPBEAR_PRIO_LOWDELAY);
#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
set_listen_fast_open(sock);
#endif
}
sockpos += nsock;
}

View File

@@ -112,13 +112,14 @@ static void printhelp(const char * progname) {
void svr_getopts(int argc, char ** argv) {
unsigned int i;
unsigned int i, j;
char ** next = 0;
int nextisport = 0;
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char* keyfile = NULL;
char c;
/* see printhelp() for options */
@@ -168,28 +169,11 @@ void svr_getopts(int argc, char ** argv) {
#endif
for (i = 1; i < (unsigned int)argc; i++) {
if (nextisport) {
addportandaddress(argv[i]);
nextisport = 0;
continue;
}
if (next) {
*next = argv[i];
if (*next == NULL) {
dropbear_exit("Invalid null argument");
}
next = 0x00;
if (argv[i][0] != '-' || argv[i][1] == '\0')
dropbear_exit("Invalid argument: %s", argv[i]);
if (keyfile) {
addhostkey(keyfile);
keyfile = NULL;
}
continue;
}
if (argv[i][0] == '-') {
switch (argv[i][1]) {
for (j = 1; (c = argv[i][j]) != '\0' && !next && !nextisport; j++) {
switch (c) {
case 'b':
next = &svr_opts.bannerfile;
break;
@@ -278,12 +262,39 @@ void svr_getopts(int argc, char ** argv) {
exit(EXIT_SUCCESS);
break;
default:
fprintf(stderr, "Unknown argument %s\n", argv[i]);
fprintf(stderr, "Invalid option -%c\n", c);
printhelp(argv[0]);
exit(EXIT_FAILURE);
break;
}
}
if (!next && !nextisport)
continue;
if (c == '\0') {
i++;
j = 0;
if (!argv[i]) {
dropbear_exit("Missing argument");
}
}
if (nextisport) {
addportandaddress(&argv[i][j]);
nextisport = 0;
} else if (next) {
*next = &argv[i][j];
if (*next == NULL) {
dropbear_exit("Invalid null argument");
}
next = 0x00;
if (keyfile) {
addhostkey(keyfile);
keyfile = NULL;
}
}
}
/* Set up listening ports */
@@ -540,6 +551,6 @@ void load_all_hostkeys() {
#endif /* DROPBEAR_ECDSA */
if (!any_keys) {
dropbear_exit("No hostkeys available");
dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
}
}

Some files were not shown because too many files have changed in this diff Show More